void do_arp_update_from_reply_packet()

in src/iccpd/src/iccp_ifm.c [802:1016]


void do_arp_update_from_reply_packet(unsigned int ifindex, unsigned int addr, uint8_t mac_addr[ETHER_ADDR_LEN])
{
    struct System *sys = NULL;
    struct CSM *csm = NULL;
    struct Msg *msg = NULL;
    struct ARPMsg *arp_msg = NULL, *arp_info = NULL;
    struct VLAN_ID *vlan_id_list = NULL;
    struct Msg *msg_send = NULL;
    uint16_t vid = 0;
    struct LocalInterface *peer_link_if = NULL;
    int ln = 0;
    uint16_t vlan_id = 0;
    struct VLAN_ID vlan_key = { 0 };

    char buf[MAX_BUFSIZE] = { 0 };
    size_t msg_len = 0;

    struct LocalInterface *lif_po = NULL, *arp_lif = NULL;

    int verify_arp = 0;

    if (!(sys = system_get_instance()))
        return;

    /* Find local itf*/
    if (!(arp_lif = local_if_find_by_ifindex(ifindex)))
        return;

    /* create ARP msg*/
    msg_len = sizeof(struct ARPMsg);
    arp_msg = (struct ARPMsg*)&buf;
    arp_msg->op_type = NEIGH_SYNC_LIF;
    sprintf(arp_msg->ifname, "%s", arp_lif->name);
    memcpy(&arp_msg->ipv4_addr, &addr, 4);
    memcpy(arp_msg->mac_addr, mac_addr, 6);

    ICCPD_LOG_DEBUG(__FUNCTION__, "ARP ifindex [%d] (%s) ip %s mac [%02X:%02X:%02X:%02X:%02X:%02X]",
                    ifindex, arp_lif->name,
                    show_ip_str(arp_msg->ipv4_addr),
                    arp_msg->mac_addr[0], arp_msg->mac_addr[1], arp_msg->mac_addr[2], arp_msg->mac_addr[3], arp_msg->mac_addr[4],
                    arp_msg->mac_addr[5]);

    if (arp_lif->ipv4_addr == 0) {
        ICCPD_LOG_DEBUG(__FUNCTION__, "IP not configured on %s, ignore ARP", arp_lif->name);
        return;
    }

    uint8_t bcast_mac[ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
    if (memcmp(arp_msg->mac_addr, bcast_mac, ETHER_ADDR_LEN) == 0)
    {
        ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry due to bcast lladdr");
        return;
    }

    if ((strncmp(arp_lif->name, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0)) {
        sscanf (arp_lif->name, "Vlan%hu", &vlan_id);
    }

    if (vlan_id) {
        memset(&vlan_key, 0, sizeof(struct VLAN_ID));
        vlan_key.vid = vlan_id;
    }
    /* Find MLACP itf, member of port-channel*/
    LIST_FOREACH(csm, &(sys->csm_list), next)
    {
        vid = 0;
        ln = __LINE__;
        LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
        {
            if (lif_po->type != IF_T_PORT_CHANNEL) {
                ln = __LINE__;
                continue;
            }

            vid = 0;
            if (!local_if_is_l3_mode(lif_po))
            {
                /* Is the L2 MLAG itf belong to a vlan?*/
                vlan_id_list = RB_FIND(vlan_rb_tree, &(lif_po->vlan_tree), &vlan_key);

                if (!vlan_id_list) {
                    ln = __LINE__;
                    continue;
                }

                if (!vlan_id_list->vlan_itf) {
                    ln = __LINE__;
                    continue;
                }

                if (vlan_id_list->vlan_itf->ifindex != ifindex) {
                    ln = __LINE__;
                    continue;
                }

                vid = vlan_id_list->vid;
                ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled port %s of vlan %d",
                                              lif_po->name, vid);
            }
            else
            {
                /* Is the ARP belong to a L3 mode MLAG itf?*/
                if (ifindex != lif_po->ifindex) {
                    ln = __LINE__;
                    continue;
                }
                ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled intf %s", lif_po->name);
            }

            verify_arp = 1;

            break;
        }

        if (lif_po) {
            break;
        } else if (csm->peer_link_if){
           peer_link_if = csm->peer_link_if;
           if (!local_if_is_l3_mode(peer_link_if)) {
               vid = 0;
               vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key);

               if (vlan_id_list && vlan_id_list->vlan_itf) {
                   if (vlan_id_list->vlan_itf->ifindex == ifindex) {
                       vid = vlan_id_list->vid;
                       ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from peer link vlan %d", vid);
                       verify_arp = 1;
                       lif_po = peer_link_if;
                       break;
                   }
               }
           }
        }
    }

    if (!(csm && lif_po)) {
        ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received no PO ln %d", ln);
        return;
    }
    if (!verify_arp) {
        ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received no verify_arp ln %d", ln);
        return;
    }

    if (vid == 0) {
        if (iccp_check_if_addr_from_netlink(AF_INET, (uint8_t *)&addr, arp_lif))
        {
            ICCPD_LOG_DEBUG(__FUNCTION__, "ARP %s is identical with the ip address of interface %s",
                                          show_ip_str(arp_msg->ipv4_addr), arp_lif->name);
            return;
        }
    } else {
        if (vid && vlan_id_list && vlan_id_list->vlan_itf) {
            if (arp_msg->ipv4_addr == vlan_id_list->vlan_itf->ipv4_addr) {
                ICCPD_LOG_DEBUG(__FUNCTION__, "Ignore My ip %s", show_ip_str(arp_msg->ipv4_addr));
                return;
            }
        }
    }

    /* update lif ARP*/
    TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail)
    {
        arp_info = (struct ARPMsg*)msg->buf;
        if (arp_info->ipv4_addr != arp_msg->ipv4_addr)
            continue;

        /* update ARP*/
        if (arp_info->op_type != arp_msg->op_type
            || strcmp(arp_info->ifname, arp_msg->ifname) != 0
            || memcmp(arp_info->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN) != 0)
        {
            arp_info->op_type = arp_msg->op_type;
            sprintf(arp_info->ifname, "%s", arp_msg->ifname);
            memcpy(arp_info->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN);
            ICCPD_LOG_DEBUG(__FUNCTION__, "Update ARP for %s",
                            show_ip_str(arp_msg->ipv4_addr));
        }
        break;
    }

    /* enquene lif_msg (add)*/
    if (!msg)
    {
        arp_msg->op_type = NEIGH_SYNC_LIF;
        arp_msg->learn_flag = NEIGH_LOCAL;
        if (iccp_csm_init_msg(&msg, (char*)arp_msg, msg_len) == 0)
        {
            mlacp_enqueue_arp(csm, msg);
            /*ICCPD_LOG_DEBUG(__FUNCTION__, "ARP-list enqueue: %s, add %s",
                            arp_msg->ifname, show_ip_str(arp_msg->ipv4_addr));*/
        }
        else
            ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP-list: %s, add %s",
                            arp_msg->ifname, show_ip_str(arp_msg->ipv4_addr));
    }

    /* enqueue iccp_msg (add)*/
    if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
    {
        arp_msg->op_type = NEIGH_SYNC_ADD;
        arp_msg->flag = 0;
        if (iccp_csm_init_msg(&msg_send, (char*)arp_msg, msg_len) == 0)
        {
            TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail);
            /*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[ADD] for %s",
                            show_ip_str(arp_msg->ipv4_addr));*/
        }
        else
            ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[ADD] message for %s",
                            show_ip_str(arp_msg->ipv4_addr));
    }

    return;
}