void neigh_create(switchlink_handle_t vrf_h, switchlink_ip_addr_t *ipaddr, switchlink_mac_addr_t mac_addr, switchlink_handle_t intf_h) { switchlink_db_status_t status; switchlink_db_neigh_info_t neigh_info; if ((ipaddr->family == AF_INET6) && IN6_IS_ADDR_MULTICAST(&(ipaddr->ip.v6addr))) { return; } memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t)); neigh_info.vrf_h = vrf_h; neigh_info.intf_h = intf_h; memcpy(&(neigh_info.ip_addr), ipaddr, sizeof(switchlink_ip_addr_t)); status = switchlink_db_neighbor_get_info(&neigh_info); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { if (memcmp(neigh_info.mac_addr, mac_addr, sizeof(switchlink_mac_addr_t)) == 0) { // no change return; } // update, currently handled as a delete followed by add neigh_delete(vrf_h, ipaddr, intf_h); } memcpy(neigh_info.mac_addr, mac_addr, sizeof(switchlink_mac_addr_t)); if (switchlink_nexthop_create(&neigh_info) == -1) { return; } if (switchlink_neighbor_create(&neigh_info) == -1) { switchlink_nexthop_delete(&neigh_info); return; } switchlink_db_neighbor_add(&neigh_info); // add a host route route_create(g_default_vrf_h, ipaddr, ipaddr, 0, intf_h); }
void process_neigh_msg(struct nlmsghdr *nlmsg, int type) { int hdrlen, attrlen; struct nlattr *attr; struct ndmsg *nbh; switchlink_mac_addr_t mac_addr; bool mac_addr_valid = false; bool ipaddr_valid = false; switchlink_ip_addr_t ipaddr; assert((type == RTM_NEWNEIGH) || (type == RTM_DELNEIGH)); nbh = nlmsg_data(nlmsg); hdrlen = sizeof(struct ndmsg); NL_LOG_DEBUG(("%sneigh: family = %d, ifindex = %d, state = 0x%x, " "flags = 0x%x, type = %d\n", ((type == RTM_NEWNEIGH) ? "new" : "del"), nbh->ndm_family, nbh->ndm_ifindex, nbh->ndm_state, nbh->ndm_flags, nbh->ndm_type)); switchlink_db_interface_info_t ifinfo; if (switchlink_db_interface_get_info(nbh->ndm_ifindex, &ifinfo) != SWITCHLINK_DB_STATUS_SUCCESS) { NL_LOG_DEBUG(("neigh: switchlink_db_interface_get_info failed\n")); return; } if (strncmp(ifinfo.ifname, SWITCHLINK_CPU_INTERFACE_NAME, SWITCHLINK_INTERFACE_NAME_LEN_MAX) == 0) { NL_LOG_DEBUG(("neigh: skipping neighbor on CPU interface\n")); return; } memset(&ipaddr, 0, sizeof(switchlink_ip_addr_t)); attrlen = nlmsg_attrlen(nlmsg, hdrlen); attr = nlmsg_attrdata(nlmsg, hdrlen); while (nla_ok(attr, attrlen)) { int attr_type = nla_type(attr); switch (attr_type) { case NDA_DST: ipaddr_valid = true; ipaddr.family = nbh->ndm_family; if (nbh->ndm_family == AF_INET) { ipaddr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); ipaddr.prefix_len = 32; } else { memcpy(&(ipaddr.ip.v6addr), nla_data(attr), nla_len(attr)); ipaddr.prefix_len = 128; } break; case NDA_LLADDR: { uint64_t lladdr; mac_addr_valid = true; lladdr = nla_get_u64(attr); memcpy(mac_addr, &lladdr, 6); break; } default: NL_LOG_DEBUG(("neigh: skipping attr(%d)\n", attr_type)); break; } attr = nla_next(attr, &attrlen); } switchlink_handle_t intf_h = ifinfo.intf_h; switchlink_handle_t bridge_h = 0; if (ifinfo.intf_type == SWITCHLINK_INTF_TYPE_L2_ACCESS) { bridge_h = ifinfo.bridge_h; assert(bridge_h); } if (type == RTM_NEWNEIGH) { if (bridge_h && mac_addr_valid) { mac_create(mac_addr, bridge_h, intf_h); } if (ipaddr_valid) { if (mac_addr_valid) { neigh_create(g_default_vrf_h, &ipaddr, mac_addr, intf_h); } else { // mac address is not valid, remove the neighbor entry neigh_delete(g_default_vrf_h, &ipaddr, intf_h); } } } else { if (bridge_h && mac_addr_valid) { mac_delete(mac_addr, bridge_h); } if (ipaddr_valid) { neigh_delete(g_default_vrf_h, &ipaddr, intf_h); } } }
static void netlink_neigh(struct ufpd_thread *thread, struct nlmsghdr *nlh) { struct ndmsg *neigh_entry; struct rtattr *route_attr; struct neigh_table *neigh; int route_attr_len; int ifindex; int family; uint8_t dst_addr[16] = {}; uint8_t dst_mac[ETH_ALEN] = {}; int i, port_index = -1; neigh_entry = (struct ndmsg *)NLMSG_DATA(nlh); family = neigh_entry->ndm_family; ifindex = neigh_entry->ndm_ifindex; port_index = -1; for(i = 0; i < thread->num_ports; i++){ if(ufp_tun_index(thread->plane, i) == ifindex){ port_index = i; break; } } if(port_index < 0) goto out; route_attr = (struct rtattr *)RTM_RTA(neigh_entry); route_attr_len = RTM_PAYLOAD(nlh); while(RTA_OK(route_attr, route_attr_len)){ switch(route_attr->rta_type){ case NDA_DST: memcpy(dst_addr, RTA_DATA(route_attr), RTA_PAYLOAD(route_attr)); break; case NDA_LLADDR: memcpy(dst_mac, RTA_DATA(route_attr), RTA_PAYLOAD(route_attr)); break; default: break; } route_attr = RTA_NEXT(route_attr, route_attr_len); } switch(family){ case AF_INET: neigh = thread->neigh_inet[port_index]; break; case AF_INET6: neigh = thread->neigh_inet6[port_index]; break; default: goto out; break; } switch(nlh->nlmsg_type){ case RTM_NEWNEIGH: neigh_add(neigh, family, dst_addr, dst_mac, thread->mpool); break; case RTM_DELNEIGH: neigh_delete(neigh, family, dst_addr); break; default: break; } out: return; }