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); }
static void neigh_delete(switchlink_handle_t vrf_h, switchlink_ip_addr_t *ipaddr, switchlink_handle_t intf_h) { switchlink_db_neigh_info_t neigh_info; switchlink_db_status_t status; 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) { return; } switchlink_neighbor_delete(&neigh_info); switchlink_nexthop_delete(&neigh_info); switchlink_db_neighbor_delete(&neigh_info); // delete the host route route_delete(g_default_vrf_h, ipaddr); }
void route_create(switchlink_handle_t vrf_h, switchlink_ip_addr_t *dst, switchlink_ip_addr_t *gateway, switchlink_handle_t ecmp_h, switchlink_handle_t intf_h) { if (!dst || (!gateway && !ecmp_h)) { if (ecmp_h) { ecmp_delete(ecmp_h); } return; } bool ecmp_valid = false; switchlink_handle_t nhop_h = 0; if (!ecmp_h) { switchlink_db_neigh_info_t neigh_info; memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t)); memcpy(&(neigh_info.ip_addr), gateway, sizeof(switchlink_ip_addr_t)); neigh_info.intf_h = intf_h; neigh_info.vrf_h = vrf_h; switchlink_db_status_t status; status = switchlink_db_neighbor_get_info(&neigh_info); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { nhop_h = neigh_info.nhop_h; } else { nhop_h = g_cpu_rx_nhop_h; } ecmp_valid = false; } else { ecmp_valid = true; nhop_h = ecmp_h; } // get the route from the db (if it already exists) switchlink_db_route_info_t route_info; memset(&route_info, 0, sizeof(switchlink_db_route_info_t)); route_info.vrf_h = vrf_h; memcpy(&(route_info.ip_addr), dst, sizeof(switchlink_ip_addr_t)); switchlink_db_status_t status = switchlink_db_route_get_info(&route_info); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { if ((route_info.ecmp == ecmp_valid) && (route_info.nhop_h == nhop_h)) { // no change return; } // nexthop has change, delete the current route route_delete(vrf_h, dst); } memset(&route_info, 0, sizeof(switchlink_db_route_info_t)); route_info.vrf_h = vrf_h; memcpy(&(route_info.ip_addr), dst, sizeof(switchlink_ip_addr_t)); route_info.ecmp = ecmp_valid; route_info.nhop_h = nhop_h; // add the route if (switchlink_route_create(&route_info) == -1) { if (route_info.ecmp) { ecmp_delete(route_info.nhop_h); } return; } // add the route to the db if (switchlink_db_route_add(&route_info) == SWITCHLINK_DB_STATUS_SUCCESS) { if (route_info.ecmp) { switchlink_db_ecmp_ref_inc(route_info.nhop_h); } } }
static switchlink_handle_t process_ecmp(uint8_t family, struct nlattr *attr, switchlink_handle_t vrf_h) { switchlink_db_status_t status; if ((family != AF_INET) && (family != AF_INET6)) { return 0; } switchlink_db_ecmp_info_t ecmp_info; memset(&ecmp_info, 0, sizeof(switchlink_db_ecmp_info_t)); struct rtnexthop *rnh = (struct rtnexthop *)nla_data(attr); int attrlen = nla_len(attr); while (RTNH_OK(rnh, attrlen)) { struct rtattr *rta = RTNH_DATA(rnh); if (rta->rta_type == RTA_GATEWAY) { switchlink_ip_addr_t gateway; memset(&gateway, 0, sizeof(switchlink_ip_addr_t)); gateway.family = family; if (family == AF_INET) { gateway.ip.v4addr.s_addr = ntohl(*((uint32_t *)RTA_DATA(rta))); gateway.prefix_len = 32; } else { gateway.prefix_len = 128; } switchlink_db_interface_info_t ifinfo; memset(&ifinfo, 0, sizeof(switchlink_db_interface_info_t)); status = switchlink_db_interface_get_info(rnh->rtnh_ifindex, &ifinfo); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { switchlink_db_neigh_info_t neigh_info; memset(&neigh_info, 0, sizeof(switchlink_db_neigh_info_t)); memcpy(&(neigh_info.ip_addr), &gateway, sizeof(switchlink_ip_addr_t)); neigh_info.intf_h = ifinfo.intf_h; neigh_info.vrf_h = vrf_h; status = switchlink_db_neighbor_get_info(&neigh_info); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { ecmp_info.nhops[ecmp_info.num_nhops] = neigh_info.nhop_h; } else { ecmp_info.nhops[ecmp_info.num_nhops] = g_cpu_rx_nhop_h; } ecmp_info.num_nhops++; assert(ecmp_info.num_nhops < SWITCHLINK_ECMP_NUM_MEMBERS_MAX); } } rnh = RTNH_NEXT(rnh); } if (!ecmp_info.num_nhops) { return 0; } status = switchlink_db_ecmp_get_info(&ecmp_info); if (status == SWITCHLINK_DB_STATUS_ITEM_NOT_FOUND) { switchlink_ecmp_create(&ecmp_info); switchlink_db_ecmp_add(&ecmp_info); } return ecmp_info.ecmp_h; }