int mlacp_fsm_update_mac_entry_from_peer()

in src/iccpd/src/mlacp_sync_update.c [216:553]


int mlacp_fsm_update_mac_entry_from_peer( struct CSM* csm, struct mLACPMACData *MacData)
{
    struct Msg* msg = NULL;
    struct MACMsg *mac_msg = NULL, *new_mac_msg = NULL;
    struct MACMsg mac_data, mac_find;
    struct LocalInterface* local_if = NULL;
    uint8_t from_mclag_intf = 0;/*0: orphan port, 1: MCLAG port*/
    memset(&mac_data, 0, sizeof(struct MACMsg));
    memset(&mac_find, 0, sizeof(struct MACMsg));
    uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

    ICCPD_LOG_INFO("ICCP_FDB",
        "Received MAC Info, interface=[%s] vid[%d] MAC[%s] OperType[%s] MacType[%d] ",
        MacData->ifname, ntohs(MacData->vid), mac_addr_to_str(MacData->mac_addr),
        MacData->type == MAC_SYNC_ADD ? "add" : "del", MacData->mac_type);

    if (memcmp(MacData->mac_addr, null_mac, ETHER_ADDR_LEN) == 0)
    {
        ICCPD_LOG_ERR(__FUNCTION__, "Invalid MAC address from peer do not add.");
        return 0;
    }


    /*Find the interface in MCLAG interface list*/
    LIST_FOREACH(local_if, &(MLACP(csm).lif_list), mlacp_next)
    {
        if (local_if->type == IF_T_PORT_CHANNEL && strcmp(local_if->name, MacData->ifname) == 0)
        {
            from_mclag_intf = 1;
            break;
        }
    }

    mac_find.vid = ntohs(MacData->vid);
    memcpy(&mac_find.mac_addr, MacData->mac_addr, ETHER_ADDR_LEN);
    mac_msg = RB_FIND(mac_rb_tree, &MLACP(csm).mac_rb ,&mac_find);

    /*Same MAC is exist in local switch, this may be mac move*/
    //if (strcmp(mac_msg->mac_str, MacData->mac_str) == 0 && mac_msg->vid == ntohs(MacData->vid))
    if (mac_msg)
    {
        ICCPD_LOG_DEBUG("ICCP_FDB", "Recv MAC update from peer RB_FIND success, existing MAC age flag:%d interface %s, "
            "MAC %s vlan-id %d, fdb_type: %d, op_type %s", mac_msg->age_flag, mac_msg->ifname,
            mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->fdb_type,
            (mac_msg->op_type == MAC_SYNC_ADD) ? "add":"del");

        if (MacData->type == MAC_SYNC_ADD)
        {
            mac_msg->age_flag &= ~MAC_AGE_PEER;

            if (from_mclag_intf && mac_msg->pending_local_del)
            {
                mac_msg->pending_local_del = 0;

                mac_msg->age_flag = MAC_AGE_LOCAL;

                // AS MAC was learned locally and in pending state due to IF is down,
                // send del to peer when MAC add received from peer
                mac_msg->op_type = MAC_SYNC_DEL;
                if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail))
                {
                    TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), mac_msg, tail);
                }
            }

            ICCPD_LOG_DEBUG("ICCP_FDB", "Recv ADD, Remove peer age flag:%d interface %s, "
                "MAC %s vlan-id %d, op_type %s, from_mclag_intf: %d ", mac_msg->age_flag, mac_msg->ifname,
                mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid,
                (mac_msg->op_type == MAC_SYNC_ADD) ? "add":"del", from_mclag_intf);

            /*mac_msg->fdb_type = tlv->fdb_type;*/
            /*The port ifname is different to the local item*/
            if (strcmp(mac_msg->ifname, MacData->ifname) != 0 || strcmp(mac_msg->origin_ifname, MacData->ifname) != 0)
            {
                if (mac_msg->fdb_type != MAC_TYPE_STATIC)
                {
                    /*Update local item*/
                    memcpy(&mac_msg->origin_ifname, MacData->ifname, MAX_L_PORT_NAME);
                }
                else
                {
                    ICCPD_LOG_DEBUG("ICCP_FDB", "Ignore Recv MAC ADD, Local static present,"
                        " interface  %s, MAC %s vlan-id %d ", mac_msg->ifname,
                        mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
                    //set back the peer age flag
                    mac_msg->age_flag |= MAC_AGE_PEER;
                    return 0;
                }

                /*If the MAC is learned from orphan port, or from MCLAG port but the local port is down*/
                if (from_mclag_intf == 0 || local_if->state == PORT_STATE_DOWN )
                {
                    /*Set MAC_AGE_LOCAL flag*/
                    mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1, 1);

                    if (strlen(csm->peer_itf_name) != 0)
                    {
                        if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0)
                        {
                            /*This MAC is already point to peer-link*/
                            ICCPD_LOG_NOTICE("ICCP_FDB", "Remote MAC ADD local IF down, MAC already points to Peer_link done processing "
                                " interface  %s, MAC %s vlan-id %d ", mac_msg->ifname,
                                mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
                            return 0;
                        }

                        if (csm->peer_link_if && (csm->peer_link_if->state == PORT_STATE_UP))
                        {
                            /*Redirect the mac to peer-link*/
                            memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME);

                            /*Send mac add message to mclagsyncd*/
                            add_mac_to_chip(mac_msg, mac_msg->fdb_type);

                            ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD , local mac exist move to peer link up "
                                " interface  %s, MAC %s vlan-id %d ", mac_msg->ifname,
                                mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);

                        }
                        else
                        {
                            /*Redirect the mac to peer-link, if peerlink is down FdbOrch deletes MAC*/
                            memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME);

                            add_mac_to_chip(mac_msg, mac_msg->fdb_type);

                            ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD , local mac exist move to peer link down "
                                    " interface  %s, MAC %s vlan-id %d ", mac_msg->ifname,
                                    mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
                        }
                    }
                    else
                    {
                        /*must redirect but no peerlink, del mac from ASIC*/
                        del_mac_from_chip(mac_msg);

                        /*Update local item*/
                        memcpy(&mac_msg->ifname, MacData->ifname, MAX_L_PORT_NAME);

                        /*if orphan port mac but no peerlink, don't keep this mac*/
                        if (from_mclag_intf == 0)
                        {
                            MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg);

                            // free only if not in change list to be send to peer node,
                            // else free is taken care after sending the update to peer
                            if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail))
                            {
                                free(mac_msg);
                            }

                            ICCPD_LOG_ERR(__FUNCTION__, "Ignore Recv MAC ADD "
                                "MAC %s vlan %d interface %s peer link not available ",
                                mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname);
                            return 0;
                        }
                    }
                }
                else
                {
                    /*Update local item*/
                    memcpy(&mac_msg->ifname, MacData->ifname, MAX_L_PORT_NAME);

                    /*from MCLAG port and the local port is up, add mac to ASIC to update port*/
                    add_mac_to_chip(mac_msg, mac_msg->fdb_type);
                }
            }
	    else if(!from_mclag_intf && (strcmp(mac_msg->ifname, MacData->ifname) == 0))
            {
                // local to remote MAC move on Orphan port.
                if (strlen(csm->peer_itf_name) != 0)
                {
                    if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0)
                    {
                        /*This MAC is already point to peer-link*/
                        ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD learn on Orphan port ,MAC already points to Peer_link"
                            " interface  %s, MAC %s vlan-id %d ", mac_msg->ifname,
                            mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
                        return 0;
                    }

                    if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP)
                    {
                        /*Redirect the mac to peer-link*/
                        memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME);

                        ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD learn on Orphan port ,point MAC address to Peer_link"
                            "interface  %s, MAC %s vlan-id %d ", mac_msg->ifname,
                            mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
                        /*Send mac add message to mclagsyncd*/
                        add_mac_to_chip(mac_msg, mac_msg->fdb_type);
                    }
                    else
                    {
                        /*Redirect the mac to peer-link*/
                         /*must redirect but if peerlink is down FdbOrch will delete MAC */
                        memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME);
                        add_mac_to_chip(mac_msg, mac_msg->fdb_type);

                        ICCPD_LOG_DEBUG("ICCP_FDB", "Remote MAC ADD learn on Orphan port ,point MAC address to Peer_link"
                            " peer link is down, delete the MAC, interface  %s, MAC %s vlan-id %d ", mac_msg->ifname,
                            mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
                    }
                }
            }

            // Code to exchange MAC_SYNC_ACK notifications can be enabled in future, if MAC SYNC issues observed.
            #if 0
            mac_msg->op_type = MAC_SYNC_ACK;
            if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, sizeof(struct MACMsg)) == 0)
            {
                /*Reply mac ack message to peer, peer will clean MAC_AGE_PEER flag*/
                TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail);
                ICCPD_LOG_DEBUG(__FUNCTION__, "Recv ADD, MAC-msg-list enqueue: %s, "
                    "add %s vlan-id %d, op_type %d", mac_msg->ifname,
                    mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->op_type);
            }
            #endif
        }
        // Code to exchange MAC_SYNC_ACK notifications can be enabled in future, if MAC SYNC issues observed.
        #if 0
        else if (tlv->type == MAC_SYNC_ACK)
        {
            /*Clean the MAC_AGE_PEER flag*/
            mac_msg->age_flag &= ~MAC_AGE_PEER;
            ICCPD_LOG_DEBUG(__FUNCTION__, "Recv ACK, Remove peer age flag:%d ifname  %s, "
                "add %s vlan-id %d, op_type %d", mac_msg->age_flag, mac_msg->ifname,
                mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->op_type);
        }
        #endif

    }

    /* delete/add MAC list*/
    if (mac_msg && (MacData->type == MAC_SYNC_DEL))
    {
        mac_msg->age_flag |= MAC_AGE_PEER;
        ICCPD_LOG_DEBUG("ICCP_FDB", "Recv MAC DEL from peer: Add peer age flag: %d interface %s, "
            "MAC %s vlan %d, op_type %s", mac_msg->age_flag, mac_msg->ifname,
            mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid,
            (mac_msg->op_type == MAC_SYNC_ADD) ? "add":"del");

        if (mac_msg->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER))
        {
            /*send mac del message to mclagsyncd.*/
            del_mac_from_chip(mac_msg);

            /*If local and peer both aged, del the mac*/
            MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_msg);

            // free only if not in change list to be send to peer node,
            // else free is taken care after sending the update to peer
            if (!MAC_IN_MSG_LIST(&(MLACP(csm).mac_msg_list), mac_msg, tail))
            {
                free(mac_msg);
            }
        }
        else
        {
            return 0;
        }
    }
    else if (!mac_msg && (MacData->type == MAC_SYNC_ADD))
    {
        mac_msg = (struct MACMsg*)&mac_data;
        mac_msg->fdb_type = MacData->mac_type;
        mac_msg->vid = ntohs(MacData->vid);
        memcpy(mac_msg->mac_addr, MacData->mac_addr, ETHER_ADDR_LEN);
        sprintf(mac_msg->ifname, "%s", MacData->ifname);
        sprintf(mac_msg->origin_ifname, "%s", MacData->ifname);
        mac_msg->age_flag = 0;

        /*Set MAC_AGE_LOCAL flag*/
        mac_msg->age_flag = set_mac_local_age_flag(csm, mac_msg, 1, 0);

        /*If the MAC is learned from orphan port, or from MCLAG port but the local port is down*/
        if (from_mclag_intf == 0 || local_if->state == PORT_STATE_DOWN)
        {

            if (strlen(csm->peer_itf_name) == 0)
            {
                /*if orphan port mac but no peerlink, don't keep this mac*/
                //MAC to be saved and program when peer_link is configured..? TBD
                if (from_mclag_intf == 0)
                {
                    ICCPD_LOG_DEBUG("ICCP_FDB", "Recv MAC ADD from peer: Ignore MAC learn on orphan port "
                        "peer-link is not configured interface %s, MAC %s vlan-id %d, "
                        " op_type %d", from_mclag_intf, mac_msg->ifname,
                        mac_addr_to_str(mac_msg->mac_addr),
                        mac_msg->vid, mac_msg->op_type);
                    return 0;
                }
            }
            else
            {
                /*Redirect the mac to peer-link*/
                memcpy(&mac_msg->ifname, csm->peer_itf_name, MAX_L_PORT_NAME);

                ICCPD_LOG_DEBUG("ICCP_FDB", "Recv MAC ADD from peer: Redirect to peerlink for orphan port or portchannel is down,"
                    " age flag: %d interface %s, MAC %s vlan %d, op_type %d",
                    mac_msg->age_flag, mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr),
                    mac_msg->vid, mac_msg->op_type);
            }
        }

        if (iccp_csm_init_mac_msg(&new_mac_msg, (char*)mac_msg, sizeof(struct MACMsg)) == 0)
        {
            /*ICCPD_LOG_INFO(__FUNCTION__, "add mac queue successfully");*/
            RB_INSERT(mac_rb_tree, &MLACP(csm).mac_rb, new_mac_msg);

            /*If the mac is from orphan port, or from MCLAG port but the local port is down*/
            if (strcmp(mac_msg->ifname, csm->peer_itf_name) == 0)
            {
                /*Send mac add message to mclagsyncd*/
                if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP)
                    add_mac_to_chip(mac_msg, mac_msg->fdb_type);
            }
            else if(local_if->state != PORT_STATE_DOWN)
            {
                /*from MCLAG port and the local port is up*/
                add_mac_to_chip(mac_msg, mac_msg->fdb_type);
            }
            // Code to exchange MAC_SYNC_ACK notifications can be enabled in future, if MAC SYNC issues observed.
            #if 0
            mac_msg->op_type = MAC_SYNC_ACK;
            if (iccp_csm_init_msg(&msg_send, (char*)mac_msg, sizeof(struct MACMsg)) == 0)
            {
                /*Reply mac ack message to peer, peer will clean MAC_AGE_PEER flag*/
                TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), msg_send, tail);
                ICCPD_LOG_DEBUG(__FUNCTION__, "MAC-msg-list enqueue: %s, add %s vlan-id %d, op_type %d",
                    mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->op_type);
            }
            #endif
        }
    }

    return 0;
}