in src/iccpd/src/mlacp_sync_update.c [924:1225]
int mlacp_fsm_update_ndisc_entry(struct CSM *csm, struct NDISCMsg *ndisc_entry)
{
struct Msg *msg = NULL;
struct NDISCMsg *ndisc_msg = NULL, ndisc_data;
struct LocalInterface *local_if;
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_ndisc_flag = 0;
char mac_str[18] = "";
int my_ip_nd_flag = 0;
int vlan_count = 0;
int err = 0, ln = 0;
int permanent_neigh = 0;
int is_ack_ll = 0;
int is_link_local = 0;
uint16_t vlan_id = 0;
struct VLAN_ID vlan_key = { 0 };
int vid_intf_present = 0;
if (!csm || !ndisc_entry)
return MCLAG_ERROR;
sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", ndisc_entry->mac_addr[0], ndisc_entry->mac_addr[1], ndisc_entry->mac_addr[2],
ndisc_entry->mac_addr[3], ndisc_entry->mac_addr[4], ndisc_entry->mac_addr[5]);
ICCPD_LOG_DEBUG(__FUNCTION__,
"Received ND Info, intf[%s] Flag %x, IP[%s], MAC[%s]",
ndisc_entry->ifname, ndisc_entry->flag, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str);
if (strncmp(ndisc_entry->ifname, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0) {
sscanf (ndisc_entry->ifname, "Vlan%hu", &vlan_id);
}
if ((memcmp(show_ipv6_str((char *)ndisc_entry->ipv6_addr), "FE80", 4) == 0)
|| (memcmp(show_ipv6_str((char *)ndisc_entry->ipv6_addr), "fe80", 4) == 0))
{
is_link_local = 1;
}
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, ndisc_entry->ifname) == 0) {
ln = __LINE__;
vid_intf_present = 1;
}
if (vid_intf_present && local_if_is_l3_mode(vlan_id_list->vlan_itf)) {
if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_addr, 16) == 0)
{
my_ip_nd_flag = 1;
}
if ((my_ip_nd_flag == 0) && is_link_local)
{
if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_ll_addr, 16) == 0)
{
my_ip_nd_flag = 1;
}
}
}
ICCPD_LOG_DEBUG(__FUNCTION__,
"ND 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 NDISC info */
set_ndisc_flag = 1;
}
}
ICCPD_LOG_DEBUG(__FUNCTION__, "ND Received ln %d, vlan_count %d, set_ndisc_flag %d, my_ip %d",
ln, vlan_count, set_ndisc_flag, my_ip_nd_flag);
if (vlan_count == 0)
{
vlan_if = local_if_find_by_name(ndisc_entry->ifname);
if (vlan_if && vlan_if->is_l3_proto_enabled)
{
if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_if->ipv6_addr, 16) == 0)
{
my_ip_nd_flag = 1;
}
if ((my_ip_nd_flag == 0) && is_link_local)
{
if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_if->ipv6_ll_addr, 16) == 0)
{
my_ip_nd_flag = 1;
}
}
set_ndisc_flag = 1;
}
}
}
}
if(my_ip_nd_flag)
{
ICCPD_LOG_DEBUG(__FUNCTION__," ignoring ND sync for self ipv6 %s ", show_ipv6_str((char *)ndisc_entry->ipv6_addr));
return 0;
}
if (set_ndisc_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))
{
ln = __LINE__;
/* 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 (memcmp((char *)ndisc_entry->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_addr, 16) == 0)
{
my_ip_nd_flag = 1;
}
ICCPD_LOG_DEBUG(__FUNCTION__, "ND is learnt from intf %s, %s is the member of this vlan, my_ip %d",
vlan_id_list->vlan_itf->name, local_if->name, my_ip_nd_flag);
}
}
ICCPD_LOG_DEBUG(__FUNCTION__, "ND received PO %s, active %d, ln %d",
local_if->name, local_if->po_active, ln);
if (vlan_id_list && local_if->po_active == 1)
{
/* Any po of L3 vlan is alive, set the NDISC info */
set_ndisc_flag = 1;
break;
}
}
else
{
/* Is the ARP belong to a L3 mode MLAG itf? */
if (strcmp(local_if->name, ndisc_entry->ifname) == 0)
{
ICCPD_LOG_DEBUG(__FUNCTION__, "ND 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 NDISC info */
set_ndisc_flag = 1;
break;
}
}
else
{
ln = __LINE__;
continue;
}
}
}
}
}
if(my_ip_nd_flag)
{
ICCPD_LOG_DEBUG(__FUNCTION__," ignoring ND sync for self ipv6 %s ", show_ipv6_str((char *)ndisc_entry->ipv6_addr));
return 0;
}
/* set dynamic Ndisc */
if (set_ndisc_flag == 1)
{
if (ndisc_entry->flag & NEIGH_SYNC_FLAG_SELF_LL)
{
permanent_neigh = 1;
is_ack_ll = 1;
}
if (ndisc_entry->flag & NEIGH_SYNC_FLAG_SELF_IP)
{
permanent_neigh = 1;
}
if (ndisc_entry->op_type == NEIGH_SYNC_ADD)
{
err = iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_entry->ipv6_addr, 1, ndisc_entry->mac_addr, ndisc_entry->ifname, permanent_neigh, 10);
if (err < 0)
{
if (err != ICCP_NLE_SEQ_MISMATCH) {
ICCPD_LOG_NOTICE(__FUNCTION__, "Failed to add nd entry(%s %s %s) to kernel, status %d",
ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str, err);
return MCLAG_ERROR;
}
}
if (ndisc_entry->flag & NEIGH_SYNC_FLAG_ACK)
{
ICCPD_LOG_DEBUG(__FUNCTION__,"Sync ND on ACK ");
syn_ack_local_neigh_mac_info_to_peer(ndisc_entry->ifname, is_ack_ll);
}
}
else
{
err = iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_entry->ipv6_addr, 0, ndisc_entry->mac_addr, ndisc_entry->ifname, permanent_neigh, 11);
if (err < 0)
{
if (err != ICCP_NLE_SEQ_MISMATCH) {
ICCPD_LOG_NOTICE(__FUNCTION__, "Failed to delete nd entry(%s %s %s) from kernel status %d",
ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_addr), mac_str, err);
return MCLAG_ERROR;
}
}
}
ICCPD_LOG_DEBUG(__FUNCTION__, "NDISC update for %s %s %s", ndisc_entry->ifname, show_ipv6_str((char *)ndisc_entry->ipv6_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(ndisc_entry->ifname);
if (local_vlan_if) {
if (memcmp((char *)ndisc_entry->ipv6_addr, (char *)local_vlan_if->ipv6_addr, 16) == 0) {
ICCPD_LOG_DEBUG(__FUNCTION__, "ignore my ip %s", show_ipv6_str((char *)ndisc_entry->ipv6_addr));
return 0;
}
}
}
/* update NDISC list */
TAILQ_FOREACH(msg, &(MLACP(csm).ndisc_list), tail)
{
ndisc_msg = (struct NDISCMsg *)msg->buf;
if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)ndisc_entry->ipv6_addr, 16) == 0)
{
/* ndisc_msg->op_type = tlv->type; */
sprintf(ndisc_msg->ifname, "%s", ndisc_entry->ifname);
memcpy(ndisc_msg->mac_addr, ndisc_entry->mac_addr, ETHER_ADDR_LEN);
break;
}
}
/* delete/add NDISC list */
if (msg && ndisc_entry->op_type == NEIGH_SYNC_DEL)
{
TAILQ_REMOVE(&(MLACP(csm).ndisc_list), msg, tail);
free(msg->buf);
free(msg);
/* ICCPD_LOG_INFO(__FUNCTION__, "Del ndisc queue successfully"); */
}
else if (!msg && ndisc_entry->op_type == NEIGH_SYNC_ADD)
{
ndisc_msg = (struct NDISCMsg *)&ndisc_data;
sprintf(ndisc_msg->ifname, "%s", ndisc_entry->ifname);
memcpy((char *)ndisc_msg->ipv6_addr, (char *)ndisc_entry->ipv6_addr, 16);
ndisc_msg->op_type = ndisc_entry->op_type;
ndisc_msg->flag = 0;
ndisc_msg->learn_flag = NEIGH_REMOTE;
memcpy(ndisc_msg->mac_addr, ndisc_entry->mac_addr, ETHER_ADDR_LEN);
if (iccp_csm_init_msg(&msg, (char *)ndisc_msg, sizeof(struct NDISCMsg)) == 0)
{
mlacp_enqueue_ndisc(csm, msg);
/* ICCPD_LOG_INFO(__FUNCTION__, "Add ndisc queue successfully"); */
}
}
/* remove all NDISC msg queue, when receive peer's NDISC list at the same time */
TAILQ_FOREACH(msg, &(MLACP(csm).ndisc_msg_list), tail)
{
ndisc_msg = (struct NDISCMsg *)msg->buf;
if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)ndisc_entry->ipv6_addr, 16) == 0)
break;
}
while (msg)
{
ndisc_msg = (struct NDISCMsg *)msg->buf;
TAILQ_REMOVE(&(MLACP(csm).ndisc_msg_list), msg, tail);
free(msg->buf);
free(msg);
TAILQ_FOREACH(msg, &(MLACP(csm).ndisc_msg_list), tail)
{
ndisc_msg = (struct NDISCMsg *)msg->buf;
if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)ndisc_entry->ipv6_addr, 16) == 0)
break;
}
}
return 0;
}