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 sharp_remove_routes_helper(struct prefix *p, vrf_id_t vrf_id, uint8_t instance, uint32_t routes) { uint32_t temp, i; bool v4 = false; zlog_debug("Removing %u routes", routes); if (p->family == AF_INET) { v4 = true; temp = ntohl(p->u.prefix4.s_addr); } else temp = ntohl(p->u.val32[3]); monotime(&sg.r.t_start); for (i = 0; i < routes; i++) { route_delete(p, vrf_id, (uint8_t)instance); if (v4) p->u.prefix4.s_addr = htonl(++temp); else p->u.val32[3] = htonl(++temp); } }
int main(int argc, char *argv[]) { const char rtnet_dev[] = "/dev/rtnet"; if (argc == 1) print_routes(); if ((strcmp(argv[1], "--help") == 0) || (argc < 3)) help(); f = open(rtnet_dev, O_RDWR); if (f < 0) { perror(rtnet_dev); exit(1); } /* add host routes from file? */ if (strcmp(argv[1], "-f") == 0) route_listadd(argv[2]); /* second argument is now always an IP address */ if (!inet_aton(argv[2], &addr)) help(); if (strcmp(argv[1], "solicit") == 0) route_solicit(argc, argv); if (strcmp(argv[1], "add") == 0) route_add(argc, argv); if (strcmp(argv[1], "del") == 0) route_delete(argc, argv); help(); return 0; }
void process_address_msg(struct nlmsghdr *nlmsg, int type) { int hdrlen, attrlen; struct nlattr *attr; struct ifaddrmsg *addrmsg; bool addr_valid = false; switchlink_ip_addr_t addr; assert((type == RTM_NEWADDR) || (type == RTM_DELADDR)); addrmsg = nlmsg_data(nlmsg); hdrlen = sizeof(struct ifaddrmsg); NL_LOG_DEBUG(("%saddr: family = %d, prefixlen = %d, flags = 0x%x, " "scope = 0x%x ifindex = %d\n", ((type == RTM_NEWADDR) ? "new" : "del"), addrmsg->ifa_family, addrmsg->ifa_prefixlen, addrmsg->ifa_flags, addrmsg->ifa_scope, addrmsg->ifa_index)); if ((addrmsg->ifa_family != AF_INET) && (addrmsg->ifa_family != AF_INET6)) { // an address family that we are not interested in, skip return; } switchlink_db_status_t status; switchlink_intf_type_t intf_type = SWITCHLINK_INTF_TYPE_NONE; switchlink_handle_t intf_h = 0; bool create_l3vi = false; switchlink_db_interface_info_t ifinfo; status = switchlink_db_interface_get_info(addrmsg->ifa_index, &ifinfo); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { intf_type = ifinfo.intf_type; intf_h = ifinfo.intf_h; } else { switchlink_db_bridge_info_t brinfo; status = switchlink_db_bridge_get_info(addrmsg->ifa_index, &brinfo); if (status == SWITCHLINK_DB_STATUS_SUCCESS) { create_l3vi = true; } else { // an interface that we are not interested in, skip return; } } if (strcmp(ifinfo.ifname, SWITCHLINK_CPU_INTERFACE_NAME) == 0) { // address on CPU interface, skip return; } 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 IFA_ADDRESS: addr_valid = true; memset(&addr, 0, sizeof(switchlink_ip_addr_t)); addr.family = addrmsg->ifa_family; addr.prefix_len = addrmsg->ifa_prefixlen; if (addrmsg->ifa_family == AF_INET) { addr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); } else { memcpy(&(addr.ip.v6addr), nla_data(attr), nla_len(attr)); } break; default: NL_LOG_DEBUG(("addr: skipping attr(%d)\n", attr_type)); break; } attr = nla_next(attr, &attrlen); } if (type == RTM_NEWADDR) { if ((addrmsg->ifa_family == AF_INET) || ((addrmsg->ifa_family == AF_INET6) && !IN6_IS_ADDR_LINKLOCAL(&(addr.ip.v6addr)))) { if (create_l3vi) { interface_create_l3vi(addrmsg->ifa_index); status = switchlink_db_interface_get_info(addrmsg->ifa_index, &ifinfo); assert(status == SWITCHLINK_DB_STATUS_SUCCESS); intf_h = ifinfo.intf_h; } else { if (intf_type == SWITCHLINK_INTF_TYPE_L2_ACCESS) { interface_change_type(addrmsg->ifa_index, SWITCHLINK_INTF_TYPE_L3); } } } if (addr_valid) { switchlink_ip_addr_t null_gateway; memset(&null_gateway, 0, sizeof(null_gateway)); null_gateway.family = addr.family; // add the subnet route route_create(g_default_vrf_h, &addr, &null_gateway, 0, intf_h); // add the interface route if (addrmsg->ifa_family == AF_INET) { addr.prefix_len = 32; } else { addr.prefix_len = 128; } route_create(g_default_vrf_h, &addr, &null_gateway, 0, intf_h); } } else { if (addr_valid) { // remove the subnet route route_delete(g_default_vrf_h, &addr); // remove the interface route if (addrmsg->ifa_family == AF_INET) { addr.prefix_len = 32; } else { addr.prefix_len = 128; } route_delete(g_default_vrf_h, &addr); } } }
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); } } }
void process_route_msg(struct nlmsghdr *nlmsg, int type) { int hdrlen, attrlen; struct nlattr *attr; struct rtmsg *rmsg; bool src_valid = false; bool dst_valid = false; bool gateway_valid = false; switchlink_handle_t ecmp_h = 0; switchlink_ip_addr_t src_addr; switchlink_ip_addr_t dst_addr; switchlink_ip_addr_t gateway_addr; switchlink_db_interface_info_t ifinfo; uint8_t af = AF_UNSPEC; bool oif_valid = false; uint32_t oif = 0; switchlink_handle_t oifl_h = 0; bool ip_multicast = false; bool iif_valid = false; uint32_t iif = 0; assert((type == RTM_NEWROUTE) || (type == RTM_DELROUTE)); rmsg = nlmsg_data(nlmsg); hdrlen = sizeof(struct rtmsg); NL_LOG_DEBUG(("%sroute: family = %d, dst_len = %d, src_len = %d, tos = %d, " "table = %d, proto = %d, scope = %d, type = %d, " "flags = 0x%x\n", ((type == RTM_NEWROUTE) ? "new" : "del"), rmsg->rtm_family, rmsg->rtm_dst_len, rmsg->rtm_src_len, rmsg->rtm_tos, rmsg->rtm_table, rmsg->rtm_protocol, rmsg->rtm_scope, rmsg->rtm_type, rmsg->rtm_flags)); if (rmsg->rtm_family > AF_MAX) { assert(rmsg->rtm_type == RTN_MULTICAST); if (rmsg->rtm_family == RTNL_FAMILY_IPMR) { af = AF_INET; } else if (rmsg->rtm_family == RTNL_FAMILY_IP6MR) { af = AF_INET6; } ip_multicast = true; } else { af = rmsg->rtm_family; } if ((af != AF_INET) && (af != AF_INET6)) { return; } memset(&dst_addr, 0, sizeof(switchlink_ip_addr_t)); memset(&gateway_addr, 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 RTA_SRC: src_valid = true; memset(&src_addr, 0, sizeof(switchlink_ip_addr_t)); src_addr.family = af; src_addr.prefix_len = rmsg->rtm_src_len; if (src_addr.family == AF_INET) { src_addr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); } else { memcpy(&(src_addr.ip.v6addr), nla_data(attr), nla_len(attr)); } break; case RTA_DST: dst_valid = true; memset(&dst_addr, 0, sizeof(switchlink_ip_addr_t)); dst_addr.family = af; dst_addr.prefix_len = rmsg->rtm_dst_len; if (dst_addr.family == AF_INET) { dst_addr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); } else { memcpy(&(dst_addr.ip.v6addr), nla_data(attr), nla_len(attr)); } break; case RTA_GATEWAY: gateway_valid = true; memset(&gateway_addr, 0, sizeof(switchlink_ip_addr_t)); gateway_addr.family = rmsg->rtm_family; if (rmsg->rtm_family == AF_INET) { gateway_addr.ip.v4addr.s_addr = ntohl(nla_get_u32(attr)); gateway_addr.prefix_len = 32; } else { memcpy(&(gateway_addr.ip.v6addr), nla_data(attr), nla_len(attr)); gateway_addr.prefix_len = 128; } break; case RTA_MULTIPATH: if (ip_multicast) { oifl_h = process_oif_list(attr, g_default_vrf_h); } else { ecmp_h = process_ecmp(af, attr, g_default_vrf_h); } break; case RTA_OIF: oif_valid = true; oif = nla_get_u32(attr); break; case RTA_IIF: iif_valid = true; iif = nla_get_u32(attr); break; default: NL_LOG_DEBUG(("route: skipping attr(%d)\n", attr_type)); break; } attr = nla_next(attr, &attrlen); } if (rmsg->rtm_dst_len == 0) { dst_valid = true; memset(&dst_addr, 0, sizeof(switchlink_ip_addr_t)); dst_addr.family = af; dst_addr.prefix_len = 0; } if (!ip_multicast) { if (type == RTM_NEWROUTE) { memset(&ifinfo, 0, sizeof(ifinfo)); if (oif_valid) { switchlink_db_status_t status; status = switchlink_db_interface_get_info(oif, &ifinfo); if (status != SWITCHLINK_DB_STATUS_SUCCESS) { NL_LOG_DEBUG(("route: switchlink_db_interface_get_info " "(unicast) failed\n")); return; } } route_create(g_default_vrf_h, (dst_valid ? &dst_addr : NULL), (gateway_valid ? &gateway_addr : NULL), ecmp_h, ifinfo.intf_h); } else { route_delete(g_default_vrf_h, (dst_valid ? &dst_addr : NULL)); } } else { if (rmsg->rtm_src_len == 0) { src_valid = true; memset(&src_addr, 0, sizeof(switchlink_ip_addr_t)); src_addr.family = af; src_addr.prefix_len = 0; } if (type == RTM_NEWROUTE) { if (!iif_valid || !oifl_h) { // multicast route cache is not resolved yet return; } switchlink_db_status_t status; status = switchlink_db_interface_get_info(iif, &ifinfo); if (status != SWITCHLINK_DB_STATUS_SUCCESS) { NL_LOG_DEBUG(("route: switchlink_db_interface_get_info " "(multicast) failed\n")); return; } mroute_create(g_default_vrf_h, (src_valid ? &src_addr : NULL), (dst_valid ? &dst_addr : NULL), ifinfo.intf_h, oifl_h); } else { mroute_delete(g_default_vrf_h, (src_valid ? &src_addr : NULL), (dst_valid ? &dst_addr : NULL)); } } }