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