Commit 9d3fc306 authored by Ondrej Zajicek (work)'s avatar Ondrej Zajicek (work)
Browse files

BFD: Allow per-request session options

BFD session options are configured per interface in BFD protocol. This
patch allows to specify them also per-request in protocols requesting
sessions (currently limited to BGP).
parent fc1e3211
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ CF_HDR
#include "nest/protocol.h"
#include "nest/iface.h"
#include "nest/route.h"
#include "nest/bfd.h"
#include "nest/cli.h"
#include "filter/filter.h"

@@ -78,6 +79,7 @@ CF_DECLS
  struct f_trie *trie;
  struct f_val v;
  struct password_item *p;
  struct bfd_options *bo;
  struct rt_show_data *ra;
  struct sym_show_data *sd;
  struct lsadb_show_data *ld;
+20 −2
Original line number Diff line number Diff line
@@ -9,9 +9,20 @@

#include "lib/lists.h"
#include "lib/resource.h"
#include "conf/conf.h"

struct bfd_session;

struct bfd_options {
  u32 min_rx_int;
  u32 min_tx_int;
  u32 idle_tx_int;
  u8 multiplier;
  u8 passive;
  u8 passive_set;
  u8 mode;
};

struct bfd_request {
  resource r;
  node n;
@@ -20,6 +31,7 @@ struct bfd_request {
  ip_addr local;
  struct iface *iface;
  struct iface *vrf;
  struct bfd_options opts;

  void (*hook)(struct bfd_request *);
  void *data;
@@ -32,6 +44,7 @@ struct bfd_request {
  u8 down;
};

#define BGP_BFD_GRACEFUL	2	/* BFD down triggers graceful restart */

#define BFD_STATE_ADMIN_DOWN	0
#define BFD_STATE_DOWN		1
@@ -39,15 +52,20 @@ struct bfd_request {
#define BFD_STATE_UP		3


static inline struct bfd_options * bfd_new_options(void)
{ return cfg_allocz(sizeof(struct bfd_options)); }

#ifdef CONFIG_BFD

struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data);
struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, struct iface *vrf, void (*hook)(struct bfd_request *), void *data, const struct bfd_options *opts);
void bfd_update_request(struct bfd_request *req, const struct bfd_options *opts);

static inline void cf_check_bfd(int use UNUSED) { }

#else

static inline struct bfd_request * bfd_request_session(pool *p UNUSED, ip_addr addr UNUSED, ip_addr local UNUSED, struct iface *iface UNUSED, struct iface *vrf UNUSED, void (*hook)(struct bfd_request *) UNUSED, void *data UNUSED) { return NULL; }
static inline struct bfd_request * bfd_request_session(pool *p UNUSED, ip_addr addr UNUSED, ip_addr local UNUSED, struct iface *iface UNUSED, struct iface *vrf UNUSED, void (*hook)(struct bfd_request *) UNUSED, void *data UNUSED, const struct bfd_options *opts UNUSED) { return NULL; }
static inline void bfd_update_request(struct bfd_request *req UNUSED, const struct bfd_options *opts UNUSED) { };

static inline void cf_check_bfd(int use) { if (use) cf_error("BFD not available"); }

+25 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ static struct iface_patt_node *this_ipn;
static list *this_p_list;
static struct password_item *this_p_item;
static int password_id;
static struct bfd_options *this_bfd_opts;

static void
iface_patt_check(void)
@@ -75,6 +76,7 @@ CF_KEYWORDS(BGP, PASSWORDS, DESCRIPTION, SORTED)
CF_KEYWORDS(RELOAD, IN, OUT, MRTDUMP, MESSAGES, RESTRICT, MEMORY, IGP_METRIC, CLASS, DSCP)
CF_KEYWORDS(TIMEFORMAT, ISO, SHORT, LONG, ROUTE, PROTOCOL, BASE, LOG, S, MS, US)
CF_KEYWORDS(GRACEFUL, RESTART, WAIT, MAX, FLUSH, AS)
CF_KEYWORDS(MIN, IDLE, RX, TX, INTERVAL, MULTIPLIER, PASSIVE)
CF_KEYWORDS(CHECK, LINK)

/* For r_args_channel */
@@ -97,6 +99,7 @@ CF_ENUM_PX(T_ENUM_AF, AF_, AFI_, IPV4, IPV6)
%type <ps> proto_patt proto_patt2
%type <cc> channel_start proto_channel
%type <cl> limit_spec
%type <bo> bfd_opts
%type <net> r_args_for_val
%type <net_ptr> r_args_for
%type <t> r_args_channel
@@ -497,6 +500,28 @@ password_algorithm:
 | HMAC SHA512	{ $$ = ALG_HMAC_SHA512; }
 ;


/* BFD options */

bfd_item:
   INTERVAL expr_us { this_bfd_opts->min_rx_int = this_bfd_opts->min_tx_int = $2; }
 | MIN RX INTERVAL expr_us { this_bfd_opts->min_rx_int = $4; }
 | MIN TX INTERVAL expr_us { this_bfd_opts->min_tx_int = $4; }
 | IDLE TX INTERVAL expr_us { this_bfd_opts->idle_tx_int = $4; }
 | MULTIPLIER expr { this_bfd_opts->multiplier = $2; }
 | PASSIVE bool { this_bfd_opts->passive = $2; this_bfd_opts->passive_set = 1; }
 | GRACEFUL { this_bfd_opts->mode = BGP_BFD_GRACEFUL; }
 ;

bfd_items:
   /* empty */
 | bfd_items bfd_item ';'
 ;

bfd_opts:
 '{' { this_bfd_opts = bfd_new_options(); } bfd_items '}' { $$ = this_bfd_opts; this_bfd_opts = NULL; }
 ;

/* Core commands */
CF_CLI_HELP(SHOW, ..., [[Show status information]])

+51 −16
Original line number Diff line number Diff line
@@ -128,6 +128,18 @@ static inline void bfd_notify_kick(struct bfd_proto *p);
 *	BFD sessions
 */

static inline struct bfd_session_config
bfd_merge_options(const struct bfd_iface_config *cf, const struct bfd_options *opts)
{
  return (struct bfd_session_config) {
    .min_rx_int = opts->min_rx_int ?: cf->min_rx_int,
    .min_tx_int = opts->min_tx_int ?: cf->min_tx_int,
    .idle_tx_int = opts->idle_tx_int ?: cf->idle_tx_int,
    .multiplier = opts->multiplier ?: cf->multiplier,
    .passive = opts->passive_set ? opts->passive : cf->passive
  };
}

static void
bfd_session_update_state(struct bfd_session *s, uint state, uint diag)
{
@@ -152,10 +164,10 @@ bfd_session_update_state(struct bfd_session *s, uint state, uint diag)
  bfd_unlock_sessions(p);

  if (state == BFD_STATE_UP)
    bfd_session_set_min_tx(s, s->ifa->cf->min_tx_int);
    bfd_session_set_min_tx(s, s->cf.min_tx_int);

  if (old_state == BFD_STATE_UP)
    bfd_session_set_min_tx(s, s->ifa->cf->idle_tx_int);
    bfd_session_set_min_tx(s, s->cf.idle_tx_int);

  if (notify)
    bfd_notify_kick(p);
@@ -405,7 +417,7 @@ bfd_get_free_id(struct bfd_proto *p)
}

static struct bfd_session *
bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *iface)
bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *iface, struct bfd_options *opts)
{
  birdloop_enter(p->loop);

@@ -421,15 +433,16 @@ bfd_add_session(struct bfd_proto *p, ip_addr addr, ip_addr local, struct iface *
  HASH_INSERT(p->session_hash_id, HASH_ID, s);
  HASH_INSERT(p->session_hash_ip, HASH_IP, s);

  s->cf = bfd_merge_options(ifa->cf, opts);

  /* Initialization of state variables - see RFC 5880 6.8.1 */
  s->loc_state = BFD_STATE_DOWN;
  s->rem_state = BFD_STATE_DOWN;
  s->des_min_tx_int = s->des_min_tx_new = ifa->cf->idle_tx_int;
  s->req_min_rx_int = s->req_min_rx_new = ifa->cf->min_rx_int;
  s->des_min_tx_int = s->des_min_tx_new = s->cf.idle_tx_int;
  s->req_min_rx_int = s->req_min_rx_new = s->cf.min_rx_int;
  s->rem_min_rx_int = 1;
  s->detect_mult = ifa->cf->multiplier;
  s->passive = ifa->cf->passive;
  s->detect_mult = s->cf.multiplier;
  s->passive = s->cf.passive;
  s->tx_csn = random_u32();

  s->tx_timer = tm_new_init(p->tpool, bfd_tx_timer_hook, s, 0, 0);
@@ -506,15 +519,19 @@ bfd_remove_session(struct bfd_proto *p, struct bfd_session *s)
static void
bfd_reconfigure_session(struct bfd_proto *p, struct bfd_session *s)
{
  if (EMPTY_LIST(s->request_list))
    return;

  birdloop_enter(p->loop);

  struct bfd_iface_config *cf = s->ifa->cf;
  struct bfd_request *req = SKIP_BACK(struct bfd_request, n, HEAD(s->request_list));
  s->cf = bfd_merge_options(s->ifa->cf, &req->opts);

  u32 tx = (s->loc_state == BFD_STATE_UP) ? cf->min_tx_int : cf->idle_tx_int;
  u32 tx = (s->loc_state == BFD_STATE_UP) ? s->cf.min_tx_int : s->cf.idle_tx_int;
  bfd_session_set_min_tx(s, tx);
  bfd_session_set_min_rx(s, cf->min_rx_int);
  s->detect_mult = cf->multiplier;
  s->passive = cf->passive;
  bfd_session_set_min_rx(s, s->cf.min_rx_int);
  s->detect_mult = s->cf.multiplier;
  s->passive = s->cf.passive;

  bfd_session_control_tx_timer(s, 0);

@@ -639,7 +656,7 @@ bfd_add_request(struct bfd_proto *p, struct bfd_request *req)
  u8 state, diag;

  if (!s)
    s = bfd_add_session(p, req->addr, req->local, req->iface);
    s = bfd_add_session(p, req->addr, req->local, req->iface, &req->opts);

  rem_node(&req->n);
  add_tail(&s->request_list, &req->n);
@@ -698,7 +715,8 @@ static struct resclass bfd_request_class;
struct bfd_request *
bfd_request_session(pool *p, ip_addr addr, ip_addr local,
		    struct iface *iface, struct iface *vrf,
		    void (*hook)(struct bfd_request *), void *data)
		    void (*hook)(struct bfd_request *), void *data,
		    const struct bfd_options *opts)
{
  struct bfd_request *req = ralloc(p, &bfd_request_class);

@@ -710,6 +728,9 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local,
  req->iface = iface;
  req->vrf = vrf;

  if (opts)
    req->opts = *opts;

  bfd_submit_request(req);

  req->hook = hook;
@@ -718,6 +739,20 @@ bfd_request_session(pool *p, ip_addr addr, ip_addr local,
  return req;
}

void
bfd_update_request(struct bfd_request *req, const struct bfd_options *opts)
{
  struct bfd_session *s = req->session;

  if (!memcmp(opts, &req->opts, sizeof(const struct bfd_options)))
    return;

  req->opts = *opts;

  if (s)
    bfd_reconfigure_session(s->ifa->bfd, s);
}

static void
bfd_request_free(resource *r)
{
@@ -767,7 +802,7 @@ bfd_neigh_notify(struct neighbor *nb)
  if ((nb->scope > 0) && !n->req)
  {
    ip_addr local = ipa_nonzero(n->local) ? n->local : nb->ifa->ip;
    n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL);
    n->req = bfd_request_session(p->p.pool, n->addr, local, nb->iface, p->p.vrf, NULL, NULL, NULL);
  }

  if ((nb->scope <= 0) && n->req)
@@ -784,7 +819,7 @@ bfd_start_neighbor(struct bfd_proto *p, struct bfd_neighbor *n)

  if (n->multihop)
  {
    n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL);
    n->req = bfd_request_session(p->p.pool, n->addr, n->local, NULL, p->p.vrf, NULL, NULL, NULL);
    return;
  }

+12 −0
Original line number Diff line number Diff line
@@ -61,6 +61,15 @@ struct bfd_iface_config
  list *passwords;			/* Passwords for authentication */
};

struct bfd_session_config
{
  u32 min_rx_int;
  u32 min_tx_int;
  u32 idle_tx_int;
  u8 multiplier;
  u8 passive;
};

struct bfd_neighbor
{
  node n;
@@ -130,6 +139,9 @@ struct bfd_session
  u8 rem_diag;
  u32 loc_id;				/* Local session ID (local discriminator) */
  u32 rem_id;				/* Remote session ID (remote discriminator) */

  struct bfd_session_config cf;		/* Static configuration parameters */

  u32 des_min_tx_int;			/* Desired min rx interval, local option */
  u32 des_min_tx_new;			/* Used for des_min_tx_int change */
  u32 req_min_rx_int;			/* Required min tx interval, local option */
Loading