int mlacp_fsm_update_arp_entry()

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;
}