-
-static struct name_node *
-name_node_lookup(int ifi_index)
-{
- struct name_node *nn;
-
- HMAP_FOR_EACH_WITH_HASH(nn, node, hash_int(ifi_index, 0), &name_map) {
- if (nn->ifi_index == ifi_index) {
- return nn;
- }
- }
-
- return NULL;
-}
-
-static struct route_node *
-route_node_lookup(int rta_oif, uint32_t rta_dst, unsigned char rtm_dst_len)
-{
- uint32_t hash;
- struct route_node *rn;
-
- hash = hash_3words(rta_oif, rta_dst, rtm_dst_len);
- HMAP_FOR_EACH_WITH_HASH(rn, node, hash, &route_map) {
- if (rn->rta_oif == rn->rta_oif &&
- rn->rta_dst == rn->rta_dst &&
- rn->rtm_dst_len == rn->rtm_dst_len) {
- return rn;
- }
- }
-
- return NULL;
-}
-
-/* Resets the name or route map depending on the value of 'is_name'. Clears
- * the appropriate map, makes an rtnetlink dump request, and calls the change
- * callback for each reply from the kernel. One should probably use
- * netdev_vport_reset_routes or netdev_vport_reset_names instead. */
-static int
-netdev_vport_reset_name_else_route(bool is_name)
-{
- int error;
- int nlmsg_type;
- struct nl_dump dump;
- struct rtgenmsg *rtmsg;
- struct ofpbuf request, reply;
- static struct nl_sock *rtnl_sock;
-
- if (is_name) {
- struct name_node *nn, *nn_next;
-
- HMAP_FOR_EACH_SAFE(nn, nn_next, node, &name_map) {
- hmap_remove(&name_map, &nn->node);
- free(nn);
- }
- } else {
- struct route_node *rn, *rn_next;
-
- HMAP_FOR_EACH_SAFE(rn, rn_next, node, &route_map) {
- hmap_remove(&route_map, &rn->node);
- free(rn);
- }
- }
-
- error = nl_sock_create(NETLINK_ROUTE, 0, 0, 0, &rtnl_sock);
- if (error) {
- VLOG_WARN_RL(&rl, "Failed to create NETLINK_ROUTE socket");
- return error;
- }
-
- ofpbuf_init(&request, 0);
-
- nlmsg_type = is_name ? RTM_GETLINK : RTM_GETROUTE;
- nl_msg_put_nlmsghdr(&request, sizeof *rtmsg, nlmsg_type, NLM_F_REQUEST);
-
- rtmsg = ofpbuf_put_zeros(&request, sizeof *rtmsg);
- rtmsg->rtgen_family = AF_INET;
-
- nl_dump_start(&dump, rtnl_sock, &request);
-
- while (nl_dump_next(&dump, &reply)) {
- if (is_name) {
- struct rtnetlink_link_change change;
-
- if (rtnetlink_link_parse(&reply, &change)) {
- netdev_vport_link_change(&change, NULL);
- }
- } else {
- struct rtnetlink_route_change change;
-
- if (rtnetlink_route_parse(&reply, &change)) {
- netdev_vport_route_change(&change, NULL);
- }
- }
- }
-
- error = nl_dump_done(&dump);
- nl_sock_destroy(rtnl_sock);
-
- return error;
-}
-
-static int
-netdev_vport_reset_routes(void)
-{
- return netdev_vport_reset_name_else_route(false);
-}
-
-static int
-netdev_vport_reset_names(void)
-{
- return netdev_vport_reset_name_else_route(true);
-}
-
-static void
-netdev_vport_route_change(const struct rtnetlink_route_change *change,
- void *aux OVS_UNUSED)
-{
-
- if (!change) {
- netdev_vport_reset_routes();
- } else if (change->nlmsg_type == RTM_NEWROUTE) {
- uint32_t hash;
- struct route_node *rn;
-
- if (route_node_lookup(change->rta_oif, change->rta_dst,
- change->rtm_dst_len)) {
- return;
- }
-
- rn = xzalloc(sizeof *rn);
- rn->rta_oif = change->rta_oif;
- rn->rta_dst = change->rta_dst;
- rn->rtm_dst_len = change->rtm_dst_len;
-
- hash = hash_3words(rn->rta_oif, rn->rta_dst, rn->rtm_dst_len);
- hmap_insert(&route_map, &rn->node, hash);
- } else if (change->nlmsg_type == RTM_DELROUTE) {
- struct route_node *rn;
-
- rn = route_node_lookup(change->rta_oif, change->rta_dst,
- change->rtm_dst_len);
-
- if (rn) {
- hmap_remove(&route_map, &rn->node);
- free(rn);
- }
- } else {
- VLOG_WARN_RL(&rl, "Received unexpected rtnetlink message type %d",
- change->nlmsg_type);
- }
-}
-
-static void
-netdev_vport_link_change(const struct rtnetlink_link_change *change,
- void *aux OVS_UNUSED)
-{
-
- if (!change) {
- netdev_vport_reset_names();
- } else if (change->nlmsg_type == RTM_NEWLINK) {
- struct name_node *nn;
-
- if (name_node_lookup(change->ifi_index)) {
- return;
- }
-
- nn = xzalloc(sizeof *nn);
- nn->ifi_index = change->ifi_index;
-
- strncpy(nn->ifname, change->ifname, IFNAMSIZ);
- nn->ifname[IFNAMSIZ - 1] = '\0';
-
- hmap_insert(&name_map, &nn->node, hash_int(nn->ifi_index, 0));
- } else if (change->nlmsg_type == RTM_DELLINK) {
- struct name_node *nn;
-
- nn = name_node_lookup(change->ifi_index);
-
- if (nn) {
- hmap_remove(&name_map, &nn->node);
- free(nn);
- }
-
- /* Link deletions do not result in all of the RTM_DELROUTE messages one
- * would expect. For now, go ahead and reset route_map whenever a link
- * is deleted. */
- netdev_vport_reset_routes();
- } else {
- VLOG_WARN_RL(&rl, "Received unexpected rtnetlink message type %d",
- change->nlmsg_type);
- }
-}
-
-static void
-netdev_vport_tnl_iface_init(void)
-{
- static bool tnl_iface_is_init = false;
-
- if (!tnl_iface_is_init) {
- hmap_init(&name_map);
- hmap_init(&route_map);
-
- rtnetlink_link_notifier_register(&netdev_vport_link_notifier,
- netdev_vport_link_change, NULL);
-
- rtnetlink_route_notifier_register(&netdev_vport_route_notifier,
- netdev_vport_route_change, NULL);
-
- netdev_vport_reset_names();
- netdev_vport_reset_routes();
- tnl_iface_is_init = true;
- }
-}
-