route-table: Handle route updates more robustly.
authorEthan Jackson <ethan@nicira.com>
Fri, 14 Jan 2011 00:29:31 +0000 (16:29 -0800)
committerEthan Jackson <ethan@nicira.com>
Fri, 14 Jan 2011 19:24:32 +0000 (11:24 -0800)
The kernel does not broadcast rtnetlink route messages in all cases
one would expect.  This can cause stale entires to end up in the
route table which may cause incorrect results for
route_table_get_ifindex() queries.  This commit causes rtnetlink
route messages to dump the entire route table on the next
route_table_get_ifindex() query.

lib/route-table.c

index 440db8fd48ac02c9a4b7451c02775792b5d74b08..e21e80c2d3d93da6b4e3a3cfaa9614dc2f183d04 100644 (file)
@@ -62,9 +62,12 @@ static unsigned int register_count = 0;
 static struct rtnetlink *rtn = NULL;
 static struct route_table_msg rtmsg;
 static struct rtnetlink_notifier notifier;
+
+static bool route_table_valid = false;
 static struct hmap route_map;
 
 static int route_table_reset(void);
+static void route_table_handle_msg(const struct route_table_msg *);
 static bool route_table_parse(struct ofpbuf *, struct route_table_msg *);
 static void route_table_change(const struct route_table_msg *, void *);
 static struct route_node *route_node_lookup(const struct route_data *);
@@ -86,6 +89,10 @@ route_table_get_ifindex(ovs_be32 ip_, int *ifindex)
 
     *ifindex = 0;
 
+    if (!route_table_valid) {
+        route_table_reset();
+    }
+
     rn = route_node_lookup_by_ip(ip);
 
     if (rn) {
@@ -173,6 +180,7 @@ route_table_reset(void)
     static struct nl_sock *rtnl_sock;
 
     route_map_clear();
+    route_table_valid = true;
 
     error = nl_sock_create(NETLINK_ROUTE, 0, 0, 0, &rtnl_sock);
     if (error) {
@@ -194,7 +202,7 @@ route_table_reset(void)
         struct route_table_msg msg;
 
         if (route_table_parse(&reply, &msg)) {
-            route_table_change(&msg, NULL);
+            route_table_handle_msg(&msg);
         }
     }
 
@@ -260,35 +268,23 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
 }
 
 static void
-route_table_change(const struct route_table_msg *change, void *aux OVS_UNUSED)
+route_table_change(const struct route_table_msg *change OVS_UNUSED,
+                   void *aux OVS_UNUSED)
 {
-    if (!change) {
-        VLOG_DBG_RL(&rl, "received NULL change message");
-        route_table_reset();
-    } else if (!change->relevant) {
-        VLOG_DBG_RL(&rl, "ignoring irrelevant change message");
-    } else if (change->nlmsg_type == RTM_NEWROUTE) {
-        if (!route_node_lookup(&change->rd)) {
-            struct route_node *rn;
-
-            rn = xzalloc(sizeof *rn);
-            memcpy(&rn->rd, &change->rd, sizeof change->rd);
-
-            hmap_insert(&route_map, &rn->node, hash_route_data(&rn->rd));
-        } else {
-            VLOG_DBG_RL(&rl, "skipping insertion of duplicate route entry");
-        }
-    } else if (change->nlmsg_type == RTM_DELROUTE) {
+    route_table_valid = false;
+}
+
+static void
+route_table_handle_msg(const struct route_table_msg *change)
+{
+    if (change->relevant && change->nlmsg_type == RTM_NEWROUTE &&
+        !route_node_lookup(&change->rd)) {
         struct route_node *rn;
 
-        rn = route_node_lookup(&change->rd);
+        rn = xzalloc(sizeof *rn);
+        memcpy(&rn->rd, &change->rd, sizeof change->rd);
 
-        if (rn) {
-            hmap_remove(&route_map, &rn->node);
-            free(rn);
-        } else {
-            VLOG_DBG_RL(&rl, "skipping deletion of non-existent route entry");
-        }
+        hmap_insert(&route_map, &rn->node, hash_route_data(&rn->rd));
     }
 }