]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Static: Support for BFD controlled static routes
authorOndrej Zajicek <santiago@crfreenet.org>
Fri, 24 Jul 2015 16:02:07 +0000 (18:02 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Fri, 24 Jul 2015 16:02:07 +0000 (18:02 +0200)
nest/bfd.h
proto/static/config.Y
proto/static/static.c
proto/static/static.h

index 79c3c921e5f1fe3c9b94f228fcfda7e90557e1c4..f1e95cb2346609eb276fa0f5e475448b177debda 100644 (file)
@@ -32,6 +32,12 @@ struct bfd_request {
 };
 
 
+#define BFD_STATE_ADMIN_DOWN   0
+#define BFD_STATE_DOWN         1
+#define BFD_STATE_INIT         2
+#define BFD_STATE_UP           3
+
+
 #ifdef CONFIG_BFD
 
 struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, void (*hook)(struct bfd_request *), void *data);
index d1b62af972ec2a168bd167b30694850db5419094..182721b3a5ad761a8ec5fa0d9639019732de026a 100644 (file)
@@ -16,10 +16,22 @@ CF_DEFINES
 static struct static_route *this_srt, *this_srt_nh, *last_srt_nh;
 static struct f_inst **this_srt_last_cmd;
 
+static void
+static_route_finish(void)
+{
+  struct static_route *r;
+
+  /* Update undefined use_bfd entries in multipath nexthops */
+  if (this_srt->dest == RTD_MULTIPATH)
+    for (r = this_srt->mp_next; r; r = r->mp_next)
+      if (r->use_bfd < 0)
+        r->use_bfd = this_srt->use_bfd;
+}
+
 CF_DECLS
 
 CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
-CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE)
+CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE, BFD)
 
 
 CF_GRAMMAR
@@ -37,7 +49,7 @@ static_proto:
  | static_proto proto_item ';'
  | static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; }
  | static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $4; }
- | static_proto stat_route stat_route_opt_list ';'
+ | static_proto stat_route stat_route_opt_list ';' { static_route_finish(); }
  ;
 
 stat_route0: ROUTE prefix {
@@ -57,11 +69,15 @@ stat_multipath1:
      this_srt_nh->via = $2;
      this_srt_nh->via_if = $3;
      this_srt_nh->if_name = (void *) this_srt; /* really */
+     this_srt_nh->use_bfd = -1; /* undefined */
    }
  | stat_multipath1 WEIGHT expr {
      this_srt_nh->masklen = $3 - 1; /* really */
      if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); 
    }
+ | stat_multipath1 BFD bool {
+     this_srt_nh->use_bfd = $3; cf_check_bfd($3);
+   }
  ;
 
 stat_multipath:
@@ -98,6 +114,7 @@ stat_route:
 
 stat_route_item:
    cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
+ | BFD bool ';' { this_srt->use_bfd = $2; cf_check_bfd($2); }
  ;
 
 stat_route_opts:
index 57c44885631864406dd78cece935c6d20372ab98..be808593c622a5581527cb48c54bdd58096b3102 100644 (file)
@@ -141,6 +141,29 @@ static_remove(struct proto *p, struct static_route *r)
   r->installed = 0;
 }
 
+static void
+static_bfd_notify(struct bfd_request *req);
+
+static void
+static_update_bfd(struct proto *p, struct static_route *r)
+{
+  struct neighbor *nb = r->neigh;
+  int bfd_up = (nb->scope > 0) && r->use_bfd;
+
+  if (bfd_up && !r->bfd_req)
+  {
+    // ip_addr local = ipa_nonzero(r->local) ? r->local : nb->ifa->ip;
+    r->bfd_req = bfd_request_session(p->pool, r->via, nb->ifa->ip, nb->iface,
+                                    static_bfd_notify, r);
+  }
+
+  if (!bfd_up && r->bfd_req)
+  {
+    rfree(r->bfd_req);
+    r->bfd_req = NULL;
+  }
+}
+
 static int
 static_decide(struct static_config *cf, struct static_route *r)
 {
@@ -153,6 +176,9 @@ static_decide(struct static_config *cf, struct static_route *r)
   if (cf->check_link && !(r->neigh->iface->flags & IF_LINK_UP))
     return 0;
 
+  if (r->bfd_req && r->bfd_req->state != BFD_STATE_UP)
+    return 0;
+
   return 1;
 }
 
@@ -171,6 +197,8 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
            r->chain = n->data;
            n->data = r;
            r->neigh = n;
+
+           static_update_bfd(p, r);
            if (static_decide(cf, r))
              static_install(p, r, n->iface);
            else
@@ -200,6 +228,8 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
                r2->chain = n->data;
                n->data = r2;
                r2->neigh = n;
+
+               static_update_bfd(p, r2);
                r2->installed = static_decide(cf, r2);
                count += r2->installed;
              }
@@ -222,6 +252,26 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
     }
 }
 
+static void
+static_rte_cleanup(struct proto *p, struct static_route *r)
+{
+  struct static_route *r2;
+
+  if (r->bfd_req)
+  {
+    rfree(r->bfd_req);
+    r->bfd_req = NULL;
+  }
+
+  if (r->dest == RTD_MULTIPATH)
+    for (r2 = r->mp_next; r2; r2 = r2->mp_next)
+      if (r2->bfd_req)
+      {
+       rfree(r2->bfd_req);
+       r2->bfd_req = NULL;
+      }
+}
+
 static int
 static_start(struct proto *p)
 {
@@ -254,7 +304,10 @@ static_shutdown(struct proto *p)
   WALK_LIST(r, cf->iface_routes)
     r->installed = 0;
   WALK_LIST(r, cf->other_routes)
+  {
+    static_rte_cleanup(p, r);
     r->installed = 0;
+  }
 
   return PS_DOWN;
 }
@@ -268,6 +321,44 @@ static_cleanup(struct proto *p)
     rt_unlock_table(cf->igp_table->table);
 }
 
+static void
+static_update_rte(struct proto *p, struct static_route *r)
+{
+  switch (r->dest)
+  {
+  case RTD_ROUTER:
+    if (static_decide((struct static_config *) p->cf, r))
+      static_install(p, r, r->neigh->iface);
+    else
+      static_remove(p, r);
+    break;
+
+  case RTD_NONE: /* a part of multipath route */
+  {
+    int decision = static_decide((struct static_config *) p->cf, r);
+    if (decision == r->installed)
+      break; /* no change */
+    r->installed = decision;
+
+    struct static_route *r1, *r2;
+    int count = 0;
+    r1 = (void *) r->if_name; /* really */
+    for (r2 = r1->mp_next; r2; r2 = r2->mp_next)
+      count += r2->installed;
+
+    if (count)
+    {
+      /* Set of nexthops changed - force reinstall */
+      r1->installed = 0;
+      static_install(p, r1, NULL);
+    }
+    else
+      static_remove(p, r1);
+
+    break;
+  }
+  }
+}
 
 static void
 static_neigh_notify(struct neighbor *n)
@@ -277,40 +368,21 @@ static_neigh_notify(struct neighbor *n)
 
   DBG("Static: neighbor notify for %I: iface %p\n", n->addr, n->iface);
   for(r=n->data; r; r=r->chain)
-    switch (r->dest)
-      {
-      case RTD_ROUTER:
-       if (static_decide((struct static_config *) p->cf, r))
-         static_install(p, r, n->iface);
-       else
-         static_remove(p, r);
-       break;
+  {
+    static_update_bfd(p, r);
+    static_update_rte(p, r);
+  }
+}
 
-      case RTD_NONE: /* a part of multipath route */
-       {
-         int decision = static_decide((struct static_config *) p->cf, r);
-         if (decision == r->installed)
-           break; /* no change */
-         r->installed = decision;
-
-         struct static_route *r1, *r2;
-         int count = 0;
-         r1 = (void *) r->if_name; /* really */
-         for (r2 = r1->mp_next; r2; r2 = r2->mp_next)
-           count += r2->installed;
-
-         if (count)
-           {
-             /* Set of nexthops changed - force reinstall */
-             r1->installed = 0;
-             static_install(p, r1, NULL);
-           }
-         else
-           static_remove(p, r1);
+static void
+static_bfd_notify(struct bfd_request *req)
+{
+  struct static_route *r = req->data;
+  struct proto *p = r->neigh->proto;
 
-         break;
-       }
-      }
+  // if (req->down) TRACE(D_EVENTS, "BFD session down for nbr %I on %s", XXXX);
+
+  static_update_rte(p, r);
 }
 
 static void
@@ -414,7 +486,7 @@ static_same_dest(struct static_route *x, struct static_route *y)
       for (x = x->mp_next, y = y->mp_next;
           x && y;
           x = x->mp_next, y = y->mp_next)
-       if (!ipa_equal(x->via, y->via) || (x->via_if != y->via_if))
+       if (!ipa_equal(x->via, y->via) || (x->via_if != y->via_if) || (x->use_bfd != y->use_bfd))
          return 0;
       return !x && !y;
 
@@ -499,6 +571,9 @@ static_reconfigure(struct proto *p, struct proto_config *new)
   WALK_LIST(r, n->other_routes)
     static_add(p, n, r);
 
+  WALK_LIST(r, o->other_routes)
+    static_rte_cleanup(p, r);
+
   return 1;
 }
 
@@ -584,13 +659,14 @@ static_show_rt(struct static_route *r)
     case RTDX_RECURSIVE: bsprintf(via, "recursive %I", r->via); break;
     default:           bsprintf(via, "???");
     }
-  cli_msg(-1009, "%I/%d %s%s", r->net, r->masklen, via, r->installed ? "" : " (dormant)");
+  cli_msg(-1009, "%I/%d %s%s%s", r->net, r->masklen, via,
+         r->bfd_req ? " (bfd)" : "", r->installed ? "" : " (dormant)");
 
   struct static_route *r2;
   if (r->dest == RTD_MULTIPATH)
     for (r2 = r->mp_next; r2; r2 = r2->mp_next)
-      cli_msg(-1009, "\tvia %I%J weight %d%s", r2->via, r2->via_if, r2->masklen + 1, /* really */
-             r2->installed ? "" : " (dormant)");
+      cli_msg(-1009, "\tvia %I%J weight %d%s%s", r2->via, r2->via_if, r2->masklen + 1, /* really */
+             r2->bfd_req ? " (bfd)" : "", r2->installed ? "" : " (dormant)");
 }
 
 void
index f197d3520586480a5bb42dacc519796296dfa42a..6b0472346c5bf78970b94c67907d9b64056231aa 100644 (file)
@@ -9,6 +9,9 @@
 #ifndef _BIRD_STATIC_H_
 #define _BIRD_STATIC_H_
 
+#include "nest/route.h"
+#include "nest/bfd.h"
+
 struct static_config {
   struct proto_config c;
   list iface_routes;           /* Routes to search on interface events */
@@ -33,6 +36,8 @@ struct static_route {
   struct static_route *mp_next;                /* Nexthops for RTD_MULTIPATH routes */
   struct f_inst *cmds;                 /* List of commands for setting attributes */
   int installed;                       /* Installed in rt table, -1 for reinstall */
+  int use_bfd;                         /* Configured to use BFD */
+  struct bfd_request *bfd_req;         /* BFD request, if BFD is used */
 };
 
 /* Dummy nodes (parts of multipath route) abuses masklen field for weight