void do_mac_update_from_syncd()

in src/iccpd/src/mlacp_link_handler.c [2642:3044]


void do_mac_update_from_syncd(uint8_t mac_addr[ETHER_ADDR_LEN], uint16_t vid, char *ifname, uint8_t fdb_type, uint8_t op_type)
{
    struct System *sys = NULL;
    struct CSM *csm = NULL;
    struct Msg *msg = NULL;
    struct MACMsg *mac_msg = NULL, *mac_info = NULL, *new_mac_msg = NULL;
    struct MACMsg mac_find;
    uint8_t mac_exist = 0;
    char buf[MAX_BUFSIZE];
    size_t msg_len = 0;
    uint8_t from_mclag_intf = 0;/*0: orphan port, 1: MCLAG port*/
    struct CSM *first_csm = NULL;
    uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };

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

    if (!(sys = system_get_instance()))
    {
        ICCPD_LOG_ERR(__FUNCTION__, "Invalid system instance");
        return;
    }

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

    /* create MAC msg*/
    memset(buf, 0, MAX_BUFSIZE);
    msg_len = sizeof(struct MACMsg);
    mac_msg = (struct MACMsg*)buf;
    mac_msg->op_type = op_type;
    mac_msg->fdb_type = fdb_type;
    memcpy(mac_msg->mac_addr, mac_addr, ETHER_ADDR_LEN);
    mac_msg->vid = vid;

    mac_msg->age_flag = 0;
    mac_msg->pending_local_del = 0;

    ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: vid %d mac %s port %s type: %d optype %s  ",
            vid, mac_addr_to_str(mac_addr), ifname, fdb_type, op_type == MAC_SYNC_ADD ? "add" : "del");
    /*Debug*/
    #if 0
    /* dump receive MAC info*/
    fprintf(stderr, "\n======== MAC Update==========\n");
    fprintf(stderr, "  MAC    =  %s \n", mac_addr_to_str(mac_addr));
    fprintf(stderr, "  vlan id = %d\n", vid);
    fprintf(stderr, "  fdb type = %s\n", fdb_type == MAC_TYPE_STATIC ? "static" : "dynamic");
    fprintf(stderr, "  op type = %s\n", op_type == MAC_SYNC_ADD ? "add" : "del");
    fprintf(stderr, "==============================\n");
    #endif

    /* Find MLACP itf, may be mclag enabled port-channel*/
    LIST_FOREACH(csm, &(sys->csm_list), next)
    {
        if (csm && !first_csm)
        {
            /*Record the first CSM, only one CSM in the system currently*/
            first_csm = csm;
        }

        /*If MAC is from peer-link, break; peer-link is not in MLACP(csm).lif_list*/
        if (strcmp(ifname, csm->peer_itf_name) == 0)
            break;

        LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
        {
            if (lif_po->type != IF_T_PORT_CHANNEL)
                continue;

            if (strcmp(lif_po->name, ifname) == 0)
            {
                from_mclag_intf = 1;
                break;
            }
        }

        if (from_mclag_intf == 1)
            break;
    }

    if (!first_csm)
        return;

    /*If support multiple CSM, the MAC list of orphan port must be moved to sys->mac_rb*/
    csm = first_csm;

    struct PeerInterface* pif = NULL;
    pif = peer_if_find_by_name(csm, ifname);

    memset(&mac_find, 0, sizeof(struct MACMsg));
    mac_find.vid = vid;
    memcpy(mac_find.mac_addr,mac_addr, ETHER_ADDR_LEN);

    mac_info = RB_FIND(mac_rb_tree, &MLACP(csm).mac_rb ,&mac_find);
    if(mac_info)
    {
        mac_exist = 1;
        ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: RB_FIND success for the MAC entry : %s, "
            " vid: %d , ifname %s, type: %d, age flag: %d", mac_addr_to_str(mac_info->mac_addr),
            mac_info->vid, mac_info->ifname, mac_info->fdb_type, mac_info->age_flag );
    }

    /*handle mac add*/
    if (op_type == MAC_SYNC_ADD)
    {
        /* Find local itf*/
        if (!(mac_lif = local_if_find_by_name(ifname)))
        {
            ICCPD_LOG_ERR(__FUNCTION__, " interface %s not present failed "
                "to add MAC %s vlan %d", ifname, mac_addr_to_str(mac_addr), vid);
            return;
        }

        sprintf(mac_msg->ifname, "%s", ifname);
        sprintf(mac_msg->origin_ifname, "%s", ifname);

        /*If the recv mac port is peer-link, no need to handle*/
        if (strcmp(csm->peer_itf_name, mac_msg->ifname) == 0)
        {
            ICCPD_LOG_DEBUG("ICCP_FDB", "MAC learn received on peer_link %s ignore MAC %s vlan %d",
                mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
            return;
        }

        /*same MAC exist*/
        if (mac_exist)
        {
            /*If the current mac port is peer-link, it will handle by port up event*/
            /*if(strcmp(csm->peer_itf_name, mac_info->ifname) == 0)
               {
                return;
               }*/
            if (mac_lif->state == PORT_STATE_DOWN)
            {
                ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: MAC add received, "
                    "MAC exists interface %s down, MAC %s vlan %d, is mclag interface : %s ",
                    mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid,
                    from_mclag_intf ? "true":"false" );

                // if from mclag intf update mac to point to peer_link.
                //else ignore mac.
                if (from_mclag_intf  && pif && (pif->state == PORT_STATE_UP))
                {
                    ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: MAC add received, "
                        "MAC exists interface %s down, point to peer link MAC %s, vlan %d, is pending local del : %s ",
                        mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid,
                        mac_info->pending_local_del ? "true":"false" );

                    mac_info->pending_local_del = 1;
                    mac_info->fdb_type = mac_msg->fdb_type;
                    memcpy(&mac_info->origin_ifname, mac_msg->ifname, MAX_L_PORT_NAME);

                    //existing mac must be pointing to peer_link, else update if info and send to syncd
                    if (strcmp(mac_info->ifname, csm->peer_itf_name) == 0)
                    {
                        add_mac_to_chip(mac_info, mac_msg->fdb_type);
                    }
                    else
                    {
                        // this for the case of MAC move , existing mac may point to different interface.
                        // need to update the ifname and update to syncd.
                        memcpy(&mac_info->ifname, csm->peer_itf_name, MAX_L_PORT_NAME);
                        add_mac_to_chip(mac_info, mac_msg->fdb_type);
                    }

                    return;
                }

                //else
                //Update the MAC
            }

            /* update MAC*/
            if (mac_info->fdb_type != mac_msg->fdb_type
                || strcmp(mac_info->ifname, mac_msg->ifname) != 0
                || strcmp(mac_info->origin_ifname, mac_msg->ifname) != 0)
            {
                mac_info->fdb_type = mac_msg->fdb_type;
                sprintf(mac_info->ifname, "%s", mac_msg->ifname);
                sprintf(mac_info->origin_ifname, "%s", mac_msg->ifname);

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

                ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Update MAC %s, vlan %d ifname %s",
                    mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname);
                // MAC is local now Del entry from MCLAG_FDB_TABLE if peer not aged.
                if (!(mac_msg->age_flag & MAC_AGE_PEER))
                {
                    ICCPD_LOG_DEBUG("ICCP_FDB", " MAC update from mclagsyncd: MAC move Update MAC remote to local %s, vlan %d"
                            " ifname %s, del entry from MCLAG_FDB_TABLE",
                            mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname);
		    mac_info->age_flag = MAC_AGE_PEER;
                    del_mac_from_chip(mac_msg);
                }
            }
            else
            {
                /*All info are the same, Remove MAC_AGE_LOCAL flag, then return*/
                /*In theory, this will be happened that mac age and then learn*/
                mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 0, 1);
                ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Duplicate update MAC %s, vlan %d ifname %s",
                        mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname);
                // MAC is local now Del entry from MCLAG_FDB_TABLE if peer not aged.
                if (!(mac_msg->age_flag & MAC_AGE_PEER))
                {
                    ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Update MAC remote to local %s, vlan %d"
                            " ifname %s, del entry from MCLAG_FDB_TABLE",
                            mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid, mac_msg->ifname);
                    del_mac_from_chip(mac_msg);
                }
                return;
            }
        }
        else/*same MAC not exist*/
        {
            /*If the port the mac learn is change to down before the mac
               sync to iccp, this mac must be deleted */
#if 0
            if ((mac_lif->state == PORT_STATE_DOWN))
            {
                if ((!from_mclag_intf) && (mac_msg->fdb_type != MAC_TYPE_STATIC))
                {
                    //ignore mac add
                    ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: mclag interface %s down, MAC %s,"
                       " vlan %d ignore mac add.", ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
                    return;
                }
            }
#endif

            // If both local and remote MCLAG interfaces are down, ignore MAC and send delete to HW.
            if (from_mclag_intf && (mac_lif->state == PORT_STATE_DOWN) && pif && (pif->state == PORT_STATE_DOWN))
            {
                ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: mclag interface %s down on local and remote ignore MAC %s,"
                    " vlan %d ", ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
                del_mac_from_chip(mac_msg);
                return;
            }
            /*set MAC_AGE_PEER flag before send this item to peer*/
            mac_msg->age_flag |= MAC_AGE_PEER;
            ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Add peer age flag, age %d interface %s, "
                "MAC %s vlan-id %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;

            /*enqueue mac to mac-list*/
            if (iccp_csm_init_mac_msg(&new_mac_msg, (char*)mac_msg, msg_len) == 0)
            {
                RB_INSERT(mac_rb_tree, &MLACP(csm).mac_rb, new_mac_msg);

                ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: MAC-list enqueue interface %s, "
                        "MAC %s vlan-id %d", mac_msg->ifname,
                        mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);

                //if port is down do not sync the MAC.
                // For MAC learned on MCLAG interface point to peer_link.
                // MAC learned on orphan port save MAC, when Orphan port is UP sync MAC
                if (mac_lif->state == PORT_STATE_DOWN)
                {
                    if (from_mclag_intf && pif && (pif->state == PORT_STATE_UP))
                    {
                        mac_msg->pending_local_del = 1;
                        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", "MAC update from mclagsyncd: mclag interface %s down, MAC %s,"
                           " vlan %d point to peer link %s", ifname, mac_addr_to_str(mac_msg->mac_addr),
                           mac_msg->vid, mac_msg->ifname);
                    }
                    return;
                }

                if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE))
                {
                    TAILQ_INSERT_TAIL(&(MLACP(csm).mac_msg_list), new_mac_msg, tail);

                    ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: MAC-msg-list enqueue interface %s, "
                        "MAC %s vlan-id %d, age_flag %d", new_mac_msg->ifname,
                        mac_addr_to_str(new_mac_msg->mac_addr), new_mac_msg->vid, new_mac_msg->age_flag);
                }
            }
            else
                ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Failed to enqueue interface %s, MAC %s vlan-id %d",
                    mac_msg->ifname, mac_addr_to_str(mac_msg->mac_addr), mac_msg->vid);
        }
    }
    else/*handle mac del*/
    {
        /*same MAC exist*/
        if (mac_exist)
        {
            /*orphan port mac or origin from_mclag_intf but state is down*/
            if (strcmp(mac_info->ifname, csm->peer_itf_name) == 0)
            {
                if (mac_info->pending_local_del)
                {
                    //do not delete the MAC.
                    ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: do not del pending MAC on %s(peer-link), "
                        "MAC %s vlan-id %d", mac_info->ifname,
                        mac_addr_to_str(mac_info->mac_addr), mac_info->vid);
                    return;
                }
                /*Set MAC_AGE_LOCAL flag*/
                mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 1, 1);

                if (mac_info->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER))
                {
                    ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s(peer-link), "
                        "MAC %s vlan-id %d", mac_info->ifname,
                        mac_addr_to_str(mac_info->mac_addr), mac_info->vid);

                    if (mac_info->add_to_syncd)
                    {
                        del_mac_from_chip(mac_info);
                    }

                    /*If peer link is down, del the mac*/
                    MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_info);

                    // 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_info, tail))
                    {
                        free(mac_info);
                    }
                }
                else if (csm->peer_link_if && csm->peer_link_if->state != PORT_STATE_DOWN)
                {
                    /*peer-link learn mac is control by iccpd, ignore the chip del info*/
                    add_mac_to_chip(mac_info, mac_info->fdb_type);

                    ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s(peer-link is up), "
                        "add back MAC %s vlan-id %d", mac_info->ifname,
                        mac_addr_to_str(mac_info->mac_addr), mac_info->vid);
                }

                return;
            }

            /*Add MAC_AGE_LOCAL flag*/
            mac_info->age_flag = set_mac_local_age_flag(csm, mac_info, 1, 1);

            if (mac_info->age_flag == (MAC_AGE_LOCAL | MAC_AGE_PEER))
            {
                ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s, "
                    "MAC %s vlan-id %d", mac_info->ifname,
                    mac_addr_to_str(mac_info->mac_addr), mac_info->vid);

                //before removing the MAC send del to syncd if added before.
                if (mac_info->add_to_syncd)
                {
                    del_mac_from_chip(mac_info);
                }
                /*If local and peer both aged, del the mac (local orphan mac is here)*/
                MAC_RB_REMOVE(mac_rb_tree, &MLACP(csm).mac_rb, mac_info);

                // 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_info, tail))
                {
                    free(mac_info);
                }
            }
            else
            {
                ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s, "
                    "MAC %s vlan-id %d, peer is not age, add back to chip",
                    mac_info->ifname, mac_addr_to_str(mac_info->mac_addr), mac_info->vid);

                if (from_mclag_intf && lif_po && lif_po->state == PORT_STATE_DOWN)
                {
                    /*If local if is down, redirect the mac to peer-link*/
                    if (strlen(csm->peer_itf_name) != 0)
                    {
                        memcpy(&mac_info->ifname, csm->peer_itf_name, MAX_L_PORT_NAME);

                        if (csm->peer_link_if && csm->peer_link_if->state == PORT_STATE_UP)
                        {
                            add_mac_to_chip(mac_info, mac_info->fdb_type);
                            ICCPD_LOG_DEBUG("ICCP_FDB", "MAC update from mclagsyncd: Recv MAC del interface %s(down), "
                                "MAC %s vlan-id %d, redirect to peer-link",
                                mac_info->ifname, mac_addr_to_str(mac_info->mac_addr), mac_info->vid);
                        }
                    }

                    return;
                }

                /*If local is aged but peer is not aged, Send mac add message to mclagsyncd*/
                /*it is from_mclag_intf and port state is up, local orphan mac can not be here*/
                /* Find local itf*/
                if (!(mac_lif = local_if_find_by_name(mac_info->ifname)))
                    return;
                if (mac_lif->state == PORT_STATE_UP)
                    add_mac_to_chip(mac_info, mac_info->fdb_type);
            }
        }
    }

    return;
}