[PATCH 3/7] Babel: Rework handling of retractions.

Toke Høiland-Jørgensen toke at toke.dk
Mon May 2 19:07:51 CEST 2016


An update with wildcard AE and infinite metric should be treated as a
global retraction of all prefixes announced by that neighbour, per
section 4.4.9 of the RFC. In addition, router ID and seqno in retraction
updates should be ignored. This reworks the handling of retractions and
adjusts the parser to handle all this correctly.

Signed-off-by: Toke Høiland-Jørgensen <toke at toke.dk>
---
 proto/babel/babel.c   | 72 +++++++++++++++++++++++++++++++++++----------------
 proto/babel/packets.c | 22 +++++++++++-----
 2 files changed, 65 insertions(+), 29 deletions(-)

diff --git a/proto/babel/babel.c b/proto/babel/babel.c
index 4b28f69..e982abb 100644
--- a/proto/babel/babel.c
+++ b/proto/babel/babel.c
@@ -1040,17 +1040,18 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
   struct babel_proto *p = ifa->proto;
   struct babel_msg_update *msg = &m->update;
 
-  struct babel_neighbor *n;
+  struct babel_neighbor *nbr;
   struct babel_entry *e;
   struct babel_source *s;
   struct babel_route *r;
+  node *n;
   int feasible;
 
   TRACE(D_PACKETS, "Handling update for %I/%d with seqno %d metric %d",
 	msg->prefix, msg->plen, msg->seqno, msg->metric);
 
-  n = babel_find_neighbor(ifa, msg->sender);
-  if (!n)
+  nbr = babel_find_neighbor(ifa, msg->sender);
+  if (!nbr)
   {
     DBG("Babel: Haven't heard from neighbor %I; ignoring update.\n", msg->sender);
     return;
@@ -1095,27 +1096,54 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
    *   of the Interval value included in the update.
    */
 
-  if (msg->metric == BABEL_INFINITY)
-    e = babel_find_entry(p, msg->prefix, msg->plen);
-  else
-    e = babel_get_entry(p, msg->prefix, msg->plen);
+  if (msg->metric == BABEL_INFINITY) /* Retraction */
+  {
+    if (msg->ae == BABEL_AE_WILDCARD)
+    {
+      /* Special case: This is a retraction of all prefixes announced by this
+         neighbour (see second-to-last paragraph of section 4.4.9 in the
+         RFC). */
+      WALK_LIST(n, nbr->routes)
+      {
+	r = SKIP_BACK(struct babel_route, neigh_route, n);
+        r->metric = BABEL_INFINITY;
+        babel_select_route(r->e);
+      }
+    }
+    else
+    {
 
-  if (!e)
-    return;
+      e = babel_find_entry(p, msg->prefix, msg->plen);
+
+      if (!e)
+	return;
+
+      r = babel_find_route(e, nbr); /* the route entry indexed by neighbour */
 
+      if(!r)
+	return;
+
+      r->metric = BABEL_INFINITY;
+      babel_select_route(e);
+    }
+
+    return; /* Done with retractions */
+  }
+
+  e = babel_get_entry(p, msg->prefix, msg->plen);
+  r = babel_find_route(e, nbr); /* the route entry indexed by neighbour */
   s = babel_find_source(e, msg->router_id); /* for feasibility */
-  r = babel_find_route(e, n); /* the route entry indexed by neighbour */
   feasible = babel_is_feasible(s, msg->seqno, msg->metric);
 
   if (!r)
   {
-    if (!feasible || (msg->metric == BABEL_INFINITY))
+    if (!feasible)
       return;
 
-    r = babel_get_route(e, n);
+    r = babel_get_route(e, nbr);
     r->advert_metric = msg->metric;
     r->router_id = msg->router_id;
-    r->metric = babel_compute_metric(n, msg->metric);
+    r->metric = babel_compute_metric(nbr, msg->metric);
     r->next_hop = msg->next_hop;
     r->seqno = msg->seqno;
   }
@@ -1126,24 +1154,22 @@ babel_handle_update(union babel_msg *m, struct babel_iface *ifa)
     babel_unicast_seqno_request(r);
 
     if (msg->router_id == r->router_id) return;
-    r->metric = BABEL_INFINITY; /* retraction */
+    r->metric = BABEL_INFINITY; /* treat as retraction */
   }
   else
   {
     /* Last paragraph above - update the entry */
     r->advert_metric = msg->metric;
-    r->metric = babel_compute_metric(n, msg->metric);
-    r->router_id = msg->router_id;
+    r->metric = babel_compute_metric(nbr, msg->metric);
     r->next_hop = msg->next_hop;
+
+    r->router_id = msg->router_id;
     r->seqno = msg->seqno;
 
-    if (msg->metric != BABEL_INFINITY)
-    {
-      r->expiry_interval = BABEL_ROUTE_EXPIRY_FACTOR(msg->interval);
-      r->expires = now + r->expiry_interval;
-      if (r->expiry_interval > BABEL_ROUTE_REFRESH_INTERVAL)
-        r->refresh_time = now + r->expiry_interval - BABEL_ROUTE_REFRESH_INTERVAL;
-    }
+    r->expiry_interval = BABEL_ROUTE_EXPIRY_FACTOR(msg->interval);
+    r->expires = now + r->expiry_interval;
+    if (r->expiry_interval > BABEL_ROUTE_REFRESH_INTERVAL)
+      r->refresh_time = now + r->expiry_interval - BABEL_ROUTE_REFRESH_INTERVAL;
 
     /* If the route is not feasible at this point, it means it is from another
        neighbour than the one currently selected; so send a unicast seqno
diff --git a/proto/babel/packets.c b/proto/babel/packets.c
index be47aa7..60b9cd3 100644
--- a/proto/babel/packets.c
+++ b/proto/babel/packets.c
@@ -484,6 +484,13 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
     break;
 
   case BABEL_AE_IP4:
+    if (tlv->flags & BABEL_FLAG_ROUTER_ID)
+    {
+      /* spec doesn't specify how to treat updates with the router ID flag set
+       * for an IPv4 address. We consider them an error. */
+      DBG("Received update with FLAG_ROUTER_ID set for an IPv4 address.\n");
+      return PARSE_ERROR;
+    }
     /* TODO */
     return PARSE_IGNORE;
 
@@ -508,11 +515,6 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
       state->def_ip6_prefix_seen = 1;
     }
 
-    if (tlv->flags & BABEL_FLAG_ROUTER_ID)
-    {
-      state->router_id = ((u64) _I2(msg->prefix)) << 32 | _I3(msg->prefix);
-      state->router_id_seen = 1;
-    }
     break;
 
   case BABEL_AE_IP6_LL:
@@ -523,7 +525,15 @@ babel_read_update(struct babel_tlv *hdr, union babel_msg *m,
     return PARSE_IGNORE;
   }
 
-  if (!state->router_id_seen)
+  if (tlv->flags & BABEL_FLAG_ROUTER_ID)
+  {
+    state->router_id = ((u64) _I2(msg->prefix)) << 32 | _I3(msg->prefix);
+    state->router_id_seen = 1;
+  }
+
+  /* Updates with no router ID are allowed for retractions (RFC section
+   * 4.4.9). */
+  if (!state->router_id_seen && msg->metric != BABEL_INFINITY)
   {
     DBG("Babel: No router ID seen before update\n");
     return PARSE_ERROR;
-- 
2.8.0



More information about the Bird-users mailing list