static void do_arp_learn_from_kernel()

in src/iccpd/src/iccp_ifm.c [116:373]


static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int msgtype, int is_del)
{
    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;
    int entry_exists = 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;
    int arp_update = 0;

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

    /* Find local itf*/
    if (!(arp_lif = local_if_find_by_ifindex(ndm->ndm_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);
    if (tb[NDA_DST])
        memcpy(&arp_msg->ipv4_addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
    if (!is_del && tb[NDA_LLADDR])
        memcpy(arp_msg->mac_addr, RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR]));

    arp_msg->ipv4_addr = arp_msg->ipv4_addr;

    ICCPD_LOG_NOTICE(__FUNCTION__, "ARP type %s, state (%04X)(%d) ifindex [%d] (%s) ip %s, mac [%02X:%02X:%02X:%02X:%02X:%02X]",
                    msgtype == RTM_NEWNEIGH ? "New":"Del", ndm->ndm_state, fwd_neigh_state_valid(ndm->ndm_state),
                    ndm->ndm_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 (msgtype != RTM_DELNEIGH) {
        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");
        msgtype = RTM_DELNEIGH;
    }

    if ((strncmp(arp_msg->ifname, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0)) {
        sscanf (arp_msg->ifname, "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;
            }

            if (!local_if_is_l3_mode(lif_po))
            {
                vid = 0;
                /* 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 != ndm->ndm_ifindex) {
                    ln = __LINE__;
                    continue;
                }

                vid = vlan_id_list->vid;
                ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled member port of vlan %d", vid);
            }
            else
            {
                /* Is the ARP belong to a L3 mode MLAG itf?*/
                if (ndm->ndm_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 == ndm->ndm_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 (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;

        entry_exists = 1;
        if (msgtype == RTM_DELNEIGH)
        {
            /* delete ARP*/
            TAILQ_REMOVE(&MLACP(csm).arp_list, msg, tail);
            free(msg->buf);
            free(msg);
            msg = NULL;
            ICCPD_LOG_DEBUG(__FUNCTION__, "Delete ARP %s", show_ip_str(arp_msg->ipv4_addr));
        }
        else
        {
            /* 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_update = 1;
                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;
    }

    if (msg && !arp_update)
        return;

    if (msgtype != RTM_DELNEIGH)
    {
        /* 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] message 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));
        }
    }
    else
    {
        /* enqueue iccp_msg (delete)*/
        if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE) && entry_exists)
        {
            arp_msg->op_type = NEIGH_SYNC_DEL;
            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[DEL] message for %s",
                                show_ip_str(arp_msg->ipv4_addr));*/
            }
            else
                ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[DEL] message for %s",
                                show_ip_str(arp_msg->ipv4_addr));
        } else {
            ICCPD_LOG_DEBUG(__FUNCTION__, "ARP[DEL] message for %s skipped. entry_exists %d",
                                show_ip_str(arp_msg->ipv4_addr), entry_exists);
        }
    }

    return;
}