ofpbuf: New function ofpbuf_clone_data_with_headroom().
[openvswitch] / lib / route-table.c
index dd215f75fb9226a1be90974e4e247214df1e7536..e21e80c2d3d93da6b4e3a3cfaa9614dc2f183d04 100644 (file)
@@ -46,6 +46,7 @@ struct route_data {
 /* A digested version of a route message sent down by the kernel to indicate
  * that a route has changed. */
 struct route_table_msg {
+    bool relevant;        /* Should this message be processed? */
     int nlmsg_type;       /* e.g. RTM_NEWROUTE, RTM_DELROUTE. */
     struct route_data rd; /* Data parsed from this message. */
 };
@@ -61,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 *);
@@ -85,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) {
@@ -172,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) {
@@ -193,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);
         }
     }
 
@@ -232,6 +241,16 @@ route_table_parse(struct ofpbuf *buf, struct route_table_msg *change)
         }
 
         memset(change, 0, sizeof *change);
+        change->relevant = true;
+
+        if (rtm->rtm_scope == RT_SCOPE_NOWHERE) {
+            change->relevant = false;
+        }
+
+        if (rtm->rtm_type != RTN_UNICAST &&
+            rtm->rtm_type != RTN_LOCAL) {
+            change->relevant = false;
+        }
 
         change->nlmsg_type     = nlmsg->nlmsg_type;
         change->rd.rtm_dst_len = rtm->rtm_dst_len;
@@ -249,33 +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->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);
+    route_table_valid = false;
+}
 
-            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) {
+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));
     }
 }