in src/iccpd/src/iccp_ifm.c [116:373]
static void do_arp_learn_from_kernel(struct ndmsg *ndm, struct rtattr *tb[], int msgtype, int is_del)
{
struct System *sys = NULL;
struct CSM *csm = NULL;
struct Msg *msg = NULL;
struct ARPMsg *arp_msg = NULL, *arp_info = NULL;
struct VLAN_ID *vlan_id_list = NULL;
struct Msg *msg_send = NULL;
uint16_t vid = 0;
int entry_exists = 0;
struct LocalInterface *peer_link_if = NULL;
int ln = 0;
uint16_t vlan_id = 0;
struct VLAN_ID vlan_key = { 0 };
char buf[MAX_BUFSIZE] = { 0 };
size_t msg_len = 0;
struct LocalInterface *lif_po = NULL, *arp_lif = NULL;
int verify_arp = 0;
int arp_update = 0;
if (!(sys = system_get_instance()))
return;
/* Find local itf*/
if (!(arp_lif = local_if_find_by_ifindex(ndm->ndm_ifindex)))
return;
/* create ARP msg*/
msg_len = sizeof(struct ARPMsg);
arp_msg = (struct ARPMsg *)&buf;
arp_msg->op_type = NEIGH_SYNC_LIF;
sprintf(arp_msg->ifname, "%s", arp_lif->name);
if (tb[NDA_DST])
memcpy(&arp_msg->ipv4_addr, RTA_DATA(tb[NDA_DST]), RTA_PAYLOAD(tb[NDA_DST]));
if (!is_del && tb[NDA_LLADDR])
memcpy(arp_msg->mac_addr, RTA_DATA(tb[NDA_LLADDR]), RTA_PAYLOAD(tb[NDA_LLADDR]));
arp_msg->ipv4_addr = arp_msg->ipv4_addr;
ICCPD_LOG_NOTICE(__FUNCTION__, "ARP type %s, state (%04X)(%d) ifindex [%d] (%s) ip %s, mac [%02X:%02X:%02X:%02X:%02X:%02X]",
msgtype == RTM_NEWNEIGH ? "New":"Del", ndm->ndm_state, fwd_neigh_state_valid(ndm->ndm_state),
ndm->ndm_ifindex, arp_lif->name,
show_ip_str(arp_msg->ipv4_addr),
arp_msg->mac_addr[0], arp_msg->mac_addr[1], arp_msg->mac_addr[2], arp_msg->mac_addr[3], arp_msg->mac_addr[4],
arp_msg->mac_addr[5]);
if (msgtype != RTM_DELNEIGH) {
if (arp_lif->ipv4_addr == 0) {
ICCPD_LOG_DEBUG(__FUNCTION__, "IP not configured on %s, ignore ARP", arp_lif->name);
return;
}
}
uint8_t bcast_mac[ETHER_ADDR_LEN] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
if (memcmp(arp_msg->mac_addr, bcast_mac, ETHER_ADDR_LEN) == 0)
{
ICCPD_LOG_DEBUG(__FUNCTION__, "Ignoring neighbor entry due to bcast lladdr");
msgtype = RTM_DELNEIGH;
}
if ((strncmp(arp_msg->ifname, VLAN_PREFIX, strlen(VLAN_PREFIX)) == 0)) {
sscanf (arp_msg->ifname, "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;
ln = __LINE__;
LIST_FOREACH(lif_po, &(MLACP(csm).lif_list), mlacp_next)
{
if (lif_po->type != IF_T_PORT_CHANNEL) {
ln = __LINE__;
continue;
}
if (!local_if_is_l3_mode(lif_po))
{
vid = 0;
/* 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 != ndm->ndm_ifindex) {
ln = __LINE__;
continue;
}
vid = vlan_id_list->vid;
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled member port of vlan %d", vid);
}
else
{
/* Is the ARP belong to a L3 mode MLAG itf?*/
if (ndm->ndm_ifindex != lif_po->ifindex) {
ln = __LINE__;
continue;
}
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from mclag enabled intf %s", lif_po->name);
}
verify_arp = 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 == ndm->ndm_ifindex) {
vid = vlan_id_list->vid;
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP is from peer link vlan %d", vid);
verify_arp = 1;
lif_po = peer_link_if;
break;
}
}
}
}
}
if (!(csm && lif_po)) {
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received no PO ln %d", ln);
return;
}
if (!verify_arp) {
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP received no verify_arp ln %d", ln);
return;
}
if (vid != 0) {
if (vid && vlan_id_list && vlan_id_list->vlan_itf) {
if (arp_msg->ipv4_addr == vlan_id_list->vlan_itf->ipv4_addr) {
ICCPD_LOG_DEBUG(__FUNCTION__, "Ignore My ip %s", show_ip_str(arp_msg->ipv4_addr));
return;
}
}
}
/* update lif ARP*/
TAILQ_FOREACH(msg, &MLACP(csm).arp_list, tail)
{
arp_info = (struct ARPMsg *)msg->buf;
if (arp_info->ipv4_addr != arp_msg->ipv4_addr)
continue;
entry_exists = 1;
if (msgtype == RTM_DELNEIGH)
{
/* delete ARP*/
TAILQ_REMOVE(&MLACP(csm).arp_list, msg, tail);
free(msg->buf);
free(msg);
msg = NULL;
ICCPD_LOG_DEBUG(__FUNCTION__, "Delete ARP %s", show_ip_str(arp_msg->ipv4_addr));
}
else
{
/* update ARP*/
if (arp_info->op_type != arp_msg->op_type
|| strcmp(arp_info->ifname, arp_msg->ifname) != 0
|| memcmp(arp_info->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN) != 0)
{
arp_update = 1;
arp_info->op_type = arp_msg->op_type;
sprintf(arp_info->ifname, "%s", arp_msg->ifname);
memcpy(arp_info->mac_addr, arp_msg->mac_addr, ETHER_ADDR_LEN);
ICCPD_LOG_DEBUG(__FUNCTION__, "Update ARP for %s", show_ip_str(arp_msg->ipv4_addr));
}
}
break;
}
if (msg && !arp_update)
return;
if (msgtype != RTM_DELNEIGH)
{
/* enquene lif_msg (add)*/
if (!msg)
{
arp_msg->op_type = NEIGH_SYNC_LIF;
arp_msg->learn_flag = NEIGH_LOCAL;
if (iccp_csm_init_msg(&msg, (char *)arp_msg, msg_len) == 0)
{
mlacp_enqueue_arp(csm, msg);
/*ICCPD_LOG_DEBUG(__FUNCTION__, "ARP-list enqueue: %s, add %s",
arp_msg->ifname, show_ip_str((arp_msg->ipv4_addr));*/
}
else
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP-list: %s, add %s",
arp_msg->ifname, show_ip_str(arp_msg->ipv4_addr));
}
/* enqueue iccp_msg (add)*/
if (MLACP(csm).current_state == MLACP_STATE_EXCHANGE)
{
arp_msg->op_type = NEIGH_SYNC_ADD;
arp_msg->flag = 0;
if (iccp_csm_init_msg(&msg_send, (char *)arp_msg, msg_len) == 0)
{
TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail);
/*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[ADD] message for %s",
show_ip_str(arp_msg->ipv4_addr));*/
}
else
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[ADD] message for %s",
show_ip_str(arp_msg->ipv4_addr));
}
}
else
{
/* enqueue iccp_msg (delete)*/
if ((MLACP(csm).current_state == MLACP_STATE_EXCHANGE) && entry_exists)
{
arp_msg->op_type = NEIGH_SYNC_DEL;
arp_msg->flag = 0;
if (iccp_csm_init_msg(&msg_send, (char *)arp_msg, msg_len) == 0)
{
TAILQ_INSERT_TAIL(&(MLACP(csm).arp_msg_list), msg_send, tail);
/*ICCPD_LOG_DEBUG(__FUNCTION__, "Enqueue ARP[DEL] message for %s",
show_ip_str(arp_msg->ipv4_addr));*/
}
else
ICCPD_LOG_WARN(__FUNCTION__, "Failed to enqueue ARP[DEL] message for %s",
show_ip_str(arp_msg->ipv4_addr));
} else {
ICCPD_LOG_DEBUG(__FUNCTION__, "ARP[DEL] message for %s skipped. entry_exists %d",
show_ip_str(arp_msg->ipv4_addr), entry_exists);
}
}
return;
}