Commit 538264cf authored by Ondrej Zajicek's avatar Ondrej Zajicek
Browse files

Static: Support for BFD controlled static routes

parent 1321e12a
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -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);
+19 −2
Original line number Diff line number Diff line
@@ -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:
+112 −36
Original line number Diff line number Diff line
@@ -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,20 +321,14 @@ static_cleanup(struct proto *p)
    rt_unlock_table(cf->igp_table->table);
}


static void
static_neigh_notify(struct neighbor *n)
static_update_rte(struct proto *p, struct static_route *r)
{
  struct proto *p = n->proto;
  struct static_route *r;

  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);
      static_install(p, r, r->neigh->iface);
    else
      static_remove(p, r);
    break;
@@ -313,6 +360,31 @@ static_neigh_notify(struct neighbor *n)
  }
}

static void
static_neigh_notify(struct neighbor *n)
{
  struct proto *p = n->proto;
  struct static_route *r;

  DBG("Static: neighbor notify for %I: iface %p\n", n->addr, n->iface);
  for(r=n->data; r; r=r->chain)
  {
    static_update_bfd(p, r);
    static_update_rte(p, r);
  }
}

static void
static_bfd_notify(struct bfd_request *req)
{
  struct static_route *r = req->data;
  struct proto *p = r->neigh->proto;

  // if (req->down) TRACE(D_EVENTS, "BFD session down for nbr %I on %s", XXXX);

  static_update_rte(p, r);
}

static void
static_dump_rt(struct static_route *r)
{
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -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