in src/iccpd/src/mlacp_sync_update.c [626:903]
int mlacp_fsm_update_arp_entry(struct CSM* csm, struct ARPMsg *arp_entry)
{
struct Msg* msg = NULL;
struct ARPMsg *arp_msg = NULL, arp_data;
struct LocalInterface *local_if = NULL;
struct LocalInterface *vlan_if = NULL;
struct LocalInterface *peer_link_if = NULL;
struct LocalInterface *local_vlan_if = NULL;
struct VLAN_ID *vlan_id_list = NULL;
int set_arp_flag = 0;
int my_ip_arp_flag = 0;
int vlan_count = 0;
char mac_str[18] = "";
int err = 0, ln = 0;
int permanent_neigh = 0;
uint16_t vlan_id = 0;
struct VLAN_ID vlan_key = { 0 };
int vid_intf_present = 0;
if (!csm || !arp_entry)
return MCLAG_ERROR;
#if 0
ICCPD_LOG_INFO(__FUNCTION__,
"Received ARP Info, intf[%s] IP[%s], MAC[%02x:%02x:%02x:%02x:%02x:%02x]",
arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr),
arp_entry->mac_addr[0], arp_entry->mac_addr[1], arp_entry->mac_addr[2],
arp_entry->mac_addr[3], arp_entry->mac_addr[4], arp_entry->mac_addr[5]);
#endif
sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", arp_entry->mac_addr[0], arp_entry->mac_addr[1], arp_entry->mac_addr[2],
arp_entry->mac_addr[3], arp_entry->mac_addr[4], arp_entry->mac_addr[5]);
ICCPD_LOG_DEBUG(__FUNCTION__, "Received ARP Info, Flag %x, intf[%s] IP[%s], MAC[%s]", arp_entry->flag, arp_entry->ifname,
show_ip_str(arp_entry->ipv4_addr), mac_str);
if (strncmp(arp_entry->ifname, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0) {
sscanf (arp_entry->ifname, "Vlan%hu", &vlan_id);
}
if (vlan_id)
{
memset(&vlan_key, 0, sizeof(struct VLAN_ID));
vlan_key.vid = vlan_id;
peer_link_if = local_if_find_by_name(csm->peer_itf_name);
if (peer_link_if && !local_if_is_l3_mode(peer_link_if))
{
ln = __LINE__;
/* Is peer-linlk itf belong to a vlan the same as peer?*/
vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key);
if (vlan_id_list)
{
vlan_count++;
if (vlan_id_list->vlan_itf) {
if (strcmp(vlan_id_list->vlan_itf->name, arp_entry->ifname) == 0) {
ln = __LINE__;
vid_intf_present = 1;
}
if (vid_intf_present && local_if_is_l3_mode(vlan_id_list->vlan_itf)) {
if (arp_entry->ipv4_addr == vlan_id_list->vlan_itf->ipv4_addr) {
my_ip_arp_flag = 1;
}
}
ICCPD_LOG_DEBUG(__FUNCTION__,
"ARP is learnt from intf %s, peer-link %s is the member of this vlan",
vlan_id_list->vlan_itf->name, peer_link_if->name);
/* Peer-link belong to L3 vlan is alive, set the ARP info*/
set_arp_flag = 1;
}
}
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP Received ln %d, vlan_count %d, set_arp_flag %d, my_ip %d",
ln, vlan_count, set_arp_flag, my_ip_arp_flag);
if (vlan_count == 0)
{
vlan_if = local_if_find_by_name(arp_entry->ifname);
if (vlan_if && vlan_if->is_l3_proto_enabled)
{
if (arp_entry->ipv4_addr == vlan_if->ipv4_addr) {
my_ip_arp_flag = 1;
}
set_arp_flag = 1;
}
}
}
}
if(my_ip_arp_flag)
{
ICCPD_LOG_DEBUG(__FUNCTION__," ignoring ARP sync for self ip %s ", show_ip_str(arp_entry->ipv4_addr));
return 0;
}
if (set_arp_flag == 0)
{
LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next)
{
if (local_if->type == IF_T_PORT_CHANNEL)
{
if (!local_if_is_l3_mode(local_if))
{
/* Is the L2 MLAG itf belong to a vlan the same as peer?*/
if (vlan_id) {
vlan_id_list = RB_FIND(vlan_rb_tree, &(local_if->vlan_tree), &vlan_key);
if (vlan_id_list && vlan_id_list->vlan_itf) {
if (arp_entry->ipv4_addr == vlan_id_list->vlan_itf->ipv4_addr) {
my_ip_arp_flag = 1;
}
ICCPD_LOG_DEBUG(__FUNCTION__,
"ARP is learnt from intf %s, mclag %s is the member of this vlan",
vlan_id_list->vlan_itf->name, local_if->name);
}
}
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received PO %s, active %d, my_ip %d, ln %d",
local_if->name, local_if->po_active, my_ip_arp_flag, ln);
if (vlan_id_list && local_if->po_active == 1)
{
/* Any po of L3 vlan is alive, set the ARP info*/
set_arp_flag = 1;
break;
}
}
else
{
/* Is the ARP belong to a L3 mode MLAG itf?*/
if (strcmp(local_if->name, arp_entry->ifname) == 0)
{
ICCPD_LOG_DEBUG(__FUNCTION__,
"ARP is learnt from mclag L3 intf %s, active %d",
local_if->name, local_if->po_active);
if (local_if->po_active == 1)
{
/* po is alive, set the ARP info*/
set_arp_flag = 1;
break;
}
}
else
{
ln = __LINE__;
continue;
}
}
}
}
}
if(my_ip_arp_flag)
{
ICCPD_LOG_DEBUG(__FUNCTION__," ignoring ARP sync for self ip %s ", show_ip_str(arp_entry->ipv4_addr));
return 0;
}
/* set dynamic ARP*/
if (set_arp_flag == 1)
{
if (arp_entry->flag & NEIGH_SYNC_FLAG_SELF_IP)
{
permanent_neigh = 1;
}
if (arp_entry->op_type == NEIGH_SYNC_ADD)
{
err = iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_entry->ipv4_addr, 1, arp_entry->mac_addr, arp_entry->ifname, permanent_neigh, 8);
if (err < 0)
{
if (err != ICCP_NLE_SEQ_MISMATCH) {
ICCPD_LOG_ERR(__FUNCTION__, "ARP add failure for %s %s %s, status %d",
arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str, err);
return MCLAG_ERROR;
}
}
if (arp_entry->flag & NEIGH_SYNC_FLAG_ACK)
{
ICCPD_LOG_DEBUG(__FUNCTION__,"Sync ARP on ACK ");
syn_ack_local_neigh_mac_info_to_peer(arp_entry->ifname, 0);
}
}
else
{
err = iccp_netlink_neighbor_request(AF_INET, (uint8_t *)&arp_entry->ipv4_addr, 0, arp_entry->mac_addr, arp_entry->ifname, permanent_neigh, 9);
if (err < 0)
{
if (err != ICCP_NLE_SEQ_MISMATCH) {
ICCPD_LOG_ERR(__FUNCTION__, "ARP delete failure for %s %s %s, status %d",
arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str, err);
return MCLAG_ERROR;
}
}
}
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP update for %s %s %s",
arp_entry->ifname, show_ip_str(arp_entry->ipv4_addr), mac_str);
}
else
{
ICCPD_LOG_NOTICE(__FUNCTION__, "Failure: port-channel is not alive, ln %d", ln);
/*TODO Set static route through peer-link or just skip it?*/
local_vlan_if = local_if_find_by_name(arp_entry->ifname);
if (local_vlan_if) {
if (arp_entry->ipv4_addr == local_vlan_if->ipv4_addr) {
ICCPD_LOG_DEBUG(__FUNCTION__, "ignore my ip %s", show_ip_str(arp_entry->ipv4_addr));
return 0;
}
}
}
/* update ARP list*/
TAILQ_FOREACH(msg, &(MLACP(csm).arp_list), tail)
{
arp_msg = (struct ARPMsg*)msg->buf;
if (arp_msg->ipv4_addr == arp_entry->ipv4_addr)
{
/*arp_msg->op_type = tlv->type;*/
sprintf(arp_msg->ifname, "%s", arp_entry->ifname);
memcpy(arp_msg->mac_addr, arp_entry->mac_addr, ETHER_ADDR_LEN);
break;
}
}
/* delete/add ARP list*/
if (msg && arp_entry->op_type == NEIGH_SYNC_DEL)
{
TAILQ_REMOVE(&(MLACP(csm).arp_list), msg, tail);
free(msg->buf);
free(msg);
/*ICCPD_LOG_INFO(__FUNCTION__, "Del arp queue successfully");*/
}
else if (!msg && arp_entry->op_type == NEIGH_SYNC_ADD)
{
arp_msg = (struct ARPMsg*)&arp_data;
sprintf(arp_msg->ifname, "%s", arp_entry->ifname);
arp_msg->ipv4_addr = arp_entry->ipv4_addr;
arp_msg->op_type = arp_entry->op_type;
arp_msg->flag = 0;
arp_msg->learn_flag = NEIGH_REMOTE;
memcpy(arp_msg->mac_addr, arp_entry->mac_addr, ETHER_ADDR_LEN);
if (iccp_csm_init_msg(&msg, (char*)arp_msg, sizeof(struct ARPMsg)) == 0)
{
mlacp_enqueue_arp(csm, msg);
/*ICCPD_LOG_INFO(__FUNCTION__, "Add arp queue successfully");*/
}
}
/* remove all ARP msg queue, when receive peer's ARP list at the same time*/
TAILQ_FOREACH(msg, &(MLACP(csm).arp_msg_list), tail)
{
arp_msg = (struct ARPMsg*)msg->buf;
if (arp_msg->ipv4_addr == arp_entry->ipv4_addr)
break;
}
while (msg)
{
arp_msg = (struct ARPMsg*)msg->buf;
TAILQ_REMOVE(&(MLACP(csm).arp_msg_list), msg, tail);
free(msg->buf);
free(msg);
TAILQ_FOREACH(msg, &(MLACP(csm).arp_msg_list), tail)
{
arp_msg = (struct ARPMsg*)msg->buf;
if (arp_msg->ipv4_addr == arp_entry->ipv4_addr)
break;
}
}
return 0;
}