in src/iccpd/src/iccp_ifm.c [1018:1258]
void do_ndisc_update_from_reply_packet(unsigned int ifindex, char *ipv6_addr, uint8_t mac_addr[ETHER_ADDR_LEN])
{
struct System *sys = NULL;
struct CSM *csm = NULL;
struct Msg *msg = NULL;
struct NDISCMsg *ndisc_msg = NULL, *ndisc_info = NULL;
struct VLAN_ID *vlan_id_list = NULL;
struct Msg *msg_send = NULL;
char mac_str[18] = "";
uint8_t null_mac[] = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
uint16_t vid = 0;
int err = 0, ln = 0;
struct LocalInterface *peer_link_if = NULL;
int is_link_local = 0;
char buf[MAX_BUFSIZE] = { 0 };
size_t msg_len = 0;
char addr_null[16] = { 0 };
uint16_t vlan_id = 0;
struct VLAN_ID vlan_key = { 0 };
struct LocalInterface *lif_po = NULL, *ndisc_lif = NULL;
int verify_ndisc = 0;
if (!(sys = system_get_instance()))
return;
/* Find local itf */
if (!(ndisc_lif = local_if_find_by_ifindex(ifindex)))
return;
sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", mac_addr[0], mac_addr[1], mac_addr[2], mac_addr[3], mac_addr[4], mac_addr[5]);
/* create Ndisc msg */
msg_len = sizeof(struct NDISCMsg);
ndisc_msg = (struct NDISCMsg *)&buf;
ndisc_msg->op_type = NEIGH_SYNC_LIF;
sprintf(ndisc_msg->ifname, "%s", ndisc_lif->name);
memcpy((char *)ndisc_msg->ipv6_addr, ipv6_addr, 16);
memcpy(ndisc_msg->mac_addr, mac_addr, ETHER_ADDR_LEN);
ICCPD_LOG_DEBUG(__FUNCTION__, "nd ifindex [%d] (%s) ip %s mac %s", ifindex, ndisc_lif->name, show_ipv6_str(ipv6_addr), mac_str);
if (memcmp(ndisc_lif->ipv6_addr, addr_null, 16) == 0) {
ICCPD_LOG_DEBUG(__FUNCTION__, "IPv6 address not configured on %s, ignore ND", ndisc_lif->name);
return;
}
uint8_t bcast_mac[ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (memcmp(ndisc_msg->mac_addr, bcast_mac, ETHER_ADDR_LEN) == 0)
{
ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry due to bcast lladdr");
return;
}
if ((strncmp(ndisc_lif->name, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0)) {
sscanf (ndisc_lif->name, "Vlan%hu", &vlan_id);
}
if (vlan_id) {
memset(&vlan_key, 0, sizeof(struct VLAN_ID));
vlan_key.vid = vlan_id;
}
/* Find MLACP itf, member of port-channel */
LIST_FOREACH(csm, &(sys->csm_list), next)
{
vid = 0;
LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
{
if (lif_po->type != IF_T_PORT_CHANNEL) {
ln = __LINE__;
continue;
}
vid = 0;
if (!local_if_is_l3_mode(lif_po))
{
/* Is the L2 MLAG itf belong to a vlan?*/
vlan_id_list = RB_FIND(vlan_rb_tree, &(lif_po->vlan_tree), &vlan_key);
if (!vlan_id_list) {
ln = __LINE__;
continue;
}
if (!vlan_id_list->vlan_itf) {
ln = __LINE__;
continue;
}
if (vlan_id_list->vlan_itf->ifindex != ifindex) {
ln = __LINE__;
continue;
}
vid = vlan_id_list->vid;
}
else
{
/* Is the ND belong to a L3 mode MLAG itf? */
if (ifindex != lif_po->ifindex) {
ln = __LINE__;
continue;
}
ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from intf %s", lif_po->name);
}
verify_ndisc = 1;
break;
}
if (lif_po) {
break;
} else if (csm->peer_link_if) {
peer_link_if = csm->peer_link_if;
if (!local_if_is_l3_mode(peer_link_if)) {
vid = 0;
vlan_id_list = RB_FIND(vlan_rb_tree, &(peer_link_if->vlan_tree), &vlan_key);
if (vlan_id_list && vlan_id_list->vlan_itf) {
if (vlan_id_list->vlan_itf->ifindex == ifindex) {
vid = vlan_id_list->vid;
ICCPD_LOG_DEBUG(__FUNCTION__, "ND is from peer link vlan %d", vid);
verify_ndisc = 1;
lif_po = peer_link_if;
break;
}
}
}
}
}
if (!(csm && lif_po)) {
ICCPD_LOG_DEBUG(__FUNCTION__, "ND received no PO ln %d", ln);
return;
}
if (!verify_ndisc) {
ICCPD_LOG_DEBUG(__FUNCTION__, "ND received no verify_ndisc ln %d", ln);
return;
}
if ((memcmp(show_ipv6_str((char *)ndisc_msg->ipv6_addr), "FE80", 4) == 0)
|| (memcmp(show_ipv6_str((char *)ndisc_msg->ipv6_addr), "fe80", 4) == 0))
{
is_link_local = 1;
}
if (vid && vlan_id_list && vlan_id_list->vlan_itf) {
if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_addr, 16) == 0)
{
ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry for My Ip %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr));
return;
}
if (is_link_local)
{
if (memcmp((char *)ndisc_msg->ipv6_addr, (char *)vlan_id_list->vlan_itf->ipv6_ll_addr, 16) == 0)
{
ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry for My Ip %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr));
return;
}
}
}
/* update lif ND */
TAILQ_FOREACH(msg, &MLACP(csm).ndisc_list, tail)
{
ndisc_info = (struct NDISCMsg *)msg->buf;
if (memcmp((char *)ndisc_info->ipv6_addr, (char *)ndisc_msg->ipv6_addr, 16) != 0)
continue;
/* If MAC addr is NULL, use the old one */
if (memcmp(mac_addr, null_mac, ETHER_ADDR_LEN) == 0)
{
memcpy(ndisc_msg->mac_addr, ndisc_info->mac_addr, ETHER_ADDR_LEN);
sprintf(mac_str, "%02x:%02x:%02x:%02x:%02x:%02x", ndisc_info->mac_addr[0], ndisc_info->mac_addr[1],
ndisc_info->mac_addr[2], ndisc_info->mac_addr[3], ndisc_info->mac_addr[4], ndisc_info->mac_addr[5]);
}
/* update ND */
if (ndisc_info->op_type != ndisc_msg->op_type
|| strcmp(ndisc_info->ifname, ndisc_msg->ifname) != 0 || memcmp(ndisc_info->mac_addr, ndisc_msg->mac_addr, ETHER_ADDR_LEN) != 0)
{
ndisc_info->op_type = ndisc_msg->op_type;
sprintf(ndisc_info->ifname, "%s", ndisc_msg->ifname);
memcpy(ndisc_info->mac_addr, ndisc_msg->mac_addr, ETHER_ADDR_LEN);
ICCPD_LOG_DEBUG(__FUNCTION__, "Update ND for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr));
}
break;
}
/* enquene lif_msg (add) */
if (!msg)
{
/* If MAC addr is NULL, and same ipv6 item is not exist in ndisc_list */
if (memcmp(mac_addr, null_mac, ETHER_ADDR_LEN) == 0)
{
return;
}
ndisc_msg->op_type = NEIGH_SYNC_LIF;
ndisc_msg->learn_flag = NEIGH_LOCAL;
if (iccp_csm_init_msg(&msg, (char *)ndisc_msg, msg_len) == 0)
{
mlacp_enqueue_ndisc(csm, msg);
/* ICCPD_LOG_DEBUG(__FUNCTION__, "NDISC-list enqueue: %s, add %s", ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr)); */
}
else
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue NDISC-list: %s, add %s", ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr));
}
ICCPD_LOG_DEBUG(__FUNCTION__, "add nd entry(%s, %s, %s) to kernel",
ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr), mac_str);
if ((err = iccp_netlink_neighbor_request(AF_INET6, (uint8_t *)ndisc_msg->ipv6_addr, 1, ndisc_msg->mac_addr, ndisc_msg->ifname, 0, 3)) < 0)
{
if (err != ICCP_NLE_SEQ_MISMATCH) {
ICCPD_LOG_NOTICE(__FUNCTION__, "Failed to add nd entry(%s, %s, %s) to kernel, status %d",
ndisc_msg->ifname, show_ipv6_str((char *)ndisc_msg->ipv6_addr), mac_str, err);
return;
}
}
/* enqueue iccp_msg (add) */
if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
{
ndisc_msg->op_type = NEIGH_SYNC_ADD;
ndisc_msg->flag = 0;
if (iccp_csm_init_msg(&msg_send, (char *)ndisc_msg, msg_len) == 0)
{
TAILQ_INSERT_TAIL(&(MLACP(csm).ndisc_msg_list), msg_send, tail);
/* ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ND[ADD] for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr)); */
}
else
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ND[ADD] message for %s", show_ipv6_str((char *)ndisc_msg->ipv6_addr));
}
return;
}