From b46ccdf582946f30d80735345c533c23a7f035c0 Mon Sep 17 00:00:00 2001 From: Ethan Jackson Date: Sun, 30 Jan 2011 17:52:19 -0800 Subject: [PATCH] lib: route-table improvements. This commit makes several changes to the route_table code used to populate tunnel_egress_iface. - It removes name_table code from netdev-vport and puts it into route-table. - It no longer attempts to build the name_table dynamically by listening to rtnetlink-link notifications. Instead it dumps the entire table, and uses rtnetlink-link notifications to indicate a re-dump is required. - It forces rtnetlink-link notifications to re-dump the routing table. This fixes an issue where bringing an interface down or removing it altogether would not have the expected effect on related tunnel_egress_ifaces. --- lib/netdev-vport.c | 147 ++------------------------------------------- lib/route-table.c | 147 ++++++++++++++++++++++++++++++++++++++++++++- lib/route-table.h | 2 + 3 files changed, 151 insertions(+), 145 deletions(-) diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c index 4da44da1..ae043c26 100644 --- a/lib/netdev-vport.c +++ b/lib/netdev-vport.c @@ -39,23 +39,12 @@ #include "packets.h" #include "route-table.h" #include "rtnetlink.h" -#include "rtnetlink-link.h" #include "shash.h" #include "socket-util.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(netdev_vport); -static struct hmap name_map; -static struct rtnetlink_notifier netdev_vport_link_notifier; - -struct name_node { - struct hmap_node node; /* Node in name_map. */ - uint32_t ifi_index; /* Kernel interface index. */ - - char ifname[IFNAMSIZ]; /* Interface name. */ -}; - struct netdev_vport_notifier { struct netdev_notifier notifier; struct list list_node; @@ -93,9 +82,6 @@ static int tnl_port_config_from_nlattr(const struct nlattr *options, size_t options_len, struct nlattr *a[ODP_TUNNEL_ATTR_MAX + 1]); -static void netdev_vport_tnl_iface_init(void); -static void netdev_vport_link_change(const struct rtnetlink_link_change *, - void *); static const char *netdev_vport_get_tnl_iface(const struct netdev *netdev); static bool @@ -189,13 +175,6 @@ netdev_vport_get_netdev_type(const struct dpif_linux_vport *vport) return "unknown"; } -static int -netdev_vport_init(void) -{ - netdev_vport_tnl_iface_init(); - return 0; -} - static int netdev_vport_create(const struct netdev_class *netdev_class, const char *name, const struct shash *args, @@ -563,136 +542,23 @@ netdev_vport_poll_remove(struct netdev_notifier *notifier_) static void netdev_vport_run(void) { - rtnetlink_link_notifier_run(); route_table_run(); } static void netdev_vport_wait(void) { - rtnetlink_link_notifier_wait(); route_table_wait(); } /* get_tnl_iface() implementation. */ - -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; -} - -/* Queries the kernel for fresh data to populate the name map with. */ -static int -netdev_vport_reset_names(void) -{ - int error; - struct nl_dump dump; - struct rtgenmsg *rtmsg; - struct ofpbuf request, reply; - static struct nl_sock *rtnl_sock; - struct name_node *nn, *nn_next; - - HMAP_FOR_EACH_SAFE(nn, nn_next, node, &name_map) { - hmap_remove(&name_map, &nn->node); - free(nn); - } - - error = nl_sock_create(NETLINK_ROUTE, &rtnl_sock); - if (error) { - VLOG_WARN_RL(&rl, "Failed to create NETLINK_ROUTE socket"); - return error; - } - - ofpbuf_init(&request, 0); - - nl_msg_put_nlmsghdr(&request, sizeof *rtmsg, RTM_GETLINK, 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)) { - struct rtnetlink_link_change change; - - if (rtnetlink_link_parse(&reply, &change)) { - netdev_vport_link_change(&change, NULL); - } - } - nl_sock_destroy(rtnl_sock); - - return nl_dump_done(&dump); -} - -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); - } - - } 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); - - rtnetlink_link_notifier_register(&netdev_vport_link_notifier, - netdev_vport_link_change, NULL); - - netdev_vport_reset_names(); - tnl_iface_is_init = true; - } -} - static const char * netdev_vport_get_tnl_iface(const struct netdev *netdev) { struct nlattr *a[ODP_TUNNEL_ATTR_MAX + 1]; - int ifindex; uint32_t route; struct netdev_dev_vport *ndv; + static char name[IFNAMSIZ]; ndv = netdev_dev_vport_cast(netdev_get_dev(netdev)); if (tnl_port_config_from_nlattr(ndv->options->data, ndv->options->size, @@ -701,13 +567,8 @@ netdev_vport_get_tnl_iface(const struct netdev *netdev) } route = nl_attr_get_be32(a[ODP_TUNNEL_ATTR_DST_IPV4]); - if (route_table_get_ifindex(route, &ifindex)) { - struct name_node *nn; - HMAP_FOR_EACH_WITH_HASH(nn, node, hash_int(ifindex, 0), &name_map) { - if (nn->ifi_index == ifindex) { - return nn->ifname; - } - } + if (route_table_get_name(route, name)) { + return name; } return NULL; @@ -1046,7 +907,7 @@ unparse_patch_config(const char *name OVS_UNUSED, const char *type OVS_UNUSED, } #define VPORT_FUNCTIONS(GET_STATUS) \ - netdev_vport_init, \ + NULL, \ netdev_vport_run, \ netdev_vport_wait, \ \ diff --git a/lib/route-table.c b/lib/route-table.c index 83a666ef..29d81bb3 100644 --- a/lib/route-table.c +++ b/lib/route-table.c @@ -30,6 +30,7 @@ #include "netlink-socket.h" #include "ofpbuf.h" #include "rtnetlink.h" +#include "rtnetlink-link.h" #include "vlog.h" VLOG_DEFINE_THIS_MODULE(route_table); @@ -56,15 +57,25 @@ struct route_node { struct route_data rd; /* Data associated with this node. */ }; +struct name_node { + struct hmap_node node; /* Node in name_map. */ + uint32_t ifi_index; /* Kernel interface index. */ + + char ifname[IFNAMSIZ]; /* Interface name. */ +}; + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 20); static unsigned int register_count = 0; static struct rtnetlink *rtn = NULL; static struct route_table_msg rtmsg; -static struct rtnetlink_notifier notifier; +static struct rtnetlink_notifier route_notifier; +static struct rtnetlink_notifier name_notifier; static bool route_table_valid = false; +static bool name_table_valid = false; static struct hmap route_map; +static struct hmap name_map; static int route_table_reset(void); static void route_table_handle_msg(const struct route_table_msg *); @@ -75,6 +86,39 @@ static struct route_node *route_node_lookup_by_ip(uint32_t ip); static void route_map_clear(void); static uint32_t hash_route_data(const struct route_data *); +static void name_table_init(void); +static void name_table_uninit(void); +static int name_table_reset(void); +static void name_table_change(const struct rtnetlink_link_change *, void *); +static void name_map_clear(void); +static struct name_node *name_node_lookup(int ifi_index); + +/* Populates 'name' with the name of the interface traffic destined for 'ip' + * is likely to egress out of (see route_table_get_ifindex). + * + * Returns true if successful, otherwise false. */ +bool +route_table_get_name(ovs_be32 ip, char name[IFNAMSIZ]) +{ + int ifindex; + + if (!name_table_valid) { + name_table_reset(); + } + + if (route_table_get_ifindex(ip, &ifindex)) { + struct name_node *nn; + + nn = name_node_lookup(ifindex); + if (nn) { + strncpy(name, nn->ifname, IFNAMSIZ); + return true; + } + } + + return false; +} + /* Populates 'ifindex' with the interface index traffic destined for 'ip' is * likely to egress. There is no hard guarantee that traffic destined for 'ip' * will egress out the specified interface. 'ifindex' may refer to an @@ -126,10 +170,11 @@ route_table_register(void) nf = (rtnetlink_notify_func *) route_table_change; rtn = rtnetlink_create(RTNLGRP_IPV4_ROUTE, pf, &rtmsg); - rtnetlink_notifier_register(rtn, ¬ifier, nf, NULL); + rtnetlink_notifier_register(rtn, &route_notifier, nf, NULL); hmap_init(&route_map); route_table_reset(); + name_table_init(); } register_count++; @@ -149,6 +194,7 @@ route_table_unregister(void) route_map_clear(); hmap_destroy(&route_map); + name_table_uninit(); } } @@ -157,6 +203,7 @@ void route_table_run(void) { if (rtn) { + rtnetlink_link_notifier_run(); rtnetlink_notifier_run(rtn); } } @@ -166,6 +213,7 @@ void route_table_wait(void) { if (rtn) { + rtnetlink_link_notifier_wait(); rtnetlink_notifier_wait(rtn); } } @@ -345,3 +393,98 @@ hash_route_data(const struct route_data *rd) { return hash_bytes(rd, sizeof *rd, 0); } + +/* name_table . */ + +static void +name_table_init(void) +{ + hmap_init(&name_map); + rtnetlink_link_notifier_register(&name_notifier, name_table_change, NULL); + name_table_valid = false; +} + +static void +name_table_uninit(void) +{ + rtnetlink_link_notifier_unregister(&name_notifier); + name_map_clear(); + hmap_destroy(&name_map); +} + +static int +name_table_reset(void) +{ + int error; + struct nl_dump dump; + struct rtgenmsg *rtmsg; + struct ofpbuf request, reply; + static struct nl_sock *rtnl_sock; + + name_table_valid = true; + name_map_clear(); + error = nl_sock_create(NETLINK_ROUTE, &rtnl_sock); + if (error) { + VLOG_WARN_RL(&rl, "failed to create NETLINK_ROUTE socket"); + return error; + } + + ofpbuf_init(&request, 0); + nl_msg_put_nlmsghdr(&request, sizeof *rtmsg, RTM_GETLINK, 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)) { + struct rtnetlink_link_change change; + + if (rtnetlink_link_parse(&reply, &change) + && change.nlmsg_type == RTM_NEWLINK + && !name_node_lookup(change.ifi_index)) { + struct name_node *nn; + + nn = xzalloc(sizeof *nn); + nn->ifi_index = change.ifi_index; + strncpy(nn->ifname, change.ifname, IFNAMSIZ); + nn->ifname[IFNAMSIZ] = '\0'; + hmap_insert(&name_map, &nn->node, hash_int(nn->ifi_index, 0)); + } + } + nl_sock_destroy(rtnl_sock); + return nl_dump_done(&dump); +} + +static void +name_table_change(const struct rtnetlink_link_change *change OVS_UNUSED, + void *aux OVS_UNUSED) +{ + /* Changes to interface status can cause routing table changes that some + * versions of the linux kernel do not advertise for some reason. */ + route_table_valid = false; + name_table_valid = false; +} + +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 void +name_map_clear(void) +{ + struct name_node *nn, *nn_next; + + HMAP_FOR_EACH_SAFE(nn, nn_next, node, &name_map) { + hmap_remove(&name_map, &nn->node); + free(nn); + } +} diff --git a/lib/route-table.h b/lib/route-table.h index e7e1921a..534350c8 100644 --- a/lib/route-table.h +++ b/lib/route-table.h @@ -17,12 +17,14 @@ #ifndef ROUTE_TABLE_H #define ROUTE_TABLE_H 1 +#include #include #include #include "openvswitch/types.h" bool route_table_get_ifindex(ovs_be32 ip, int *ifindex); +bool route_table_get_name(ovs_be32 ip, char name[IFNAMSIZ]); void route_table_register(void); void route_table_unregister(void); void route_table_run(void); -- 2.30.2