Static: Support for BFD controlled static routes
This commit is contained in:
parent
1321e12ac4
commit
538264cf1a
4 changed files with 141 additions and 37 deletions
|
@ -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
|
#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);
|
struct bfd_request * bfd_request_session(pool *p, ip_addr addr, ip_addr local, struct iface *iface, void (*hook)(struct bfd_request *), void *data);
|
||||||
|
|
|
@ -16,10 +16,22 @@ CF_DEFINES
|
||||||
static struct static_route *this_srt, *this_srt_nh, *last_srt_nh;
|
static struct static_route *this_srt, *this_srt_nh, *last_srt_nh;
|
||||||
static struct f_inst **this_srt_last_cmd;
|
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_DECLS
|
||||||
|
|
||||||
CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK)
|
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
|
CF_GRAMMAR
|
||||||
|
@ -37,7 +49,7 @@ static_proto:
|
||||||
| static_proto proto_item ';'
|
| static_proto proto_item ';'
|
||||||
| static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; }
|
| static_proto CHECK LINK bool ';' { STATIC_CFG->check_link = $4; }
|
||||||
| static_proto IGP TABLE rtable ';' { STATIC_CFG->igp_table = $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 {
|
stat_route0: ROUTE prefix {
|
||||||
|
@ -57,11 +69,15 @@ stat_multipath1:
|
||||||
this_srt_nh->via = $2;
|
this_srt_nh->via = $2;
|
||||||
this_srt_nh->via_if = $3;
|
this_srt_nh->via_if = $3;
|
||||||
this_srt_nh->if_name = (void *) this_srt; /* really */
|
this_srt_nh->if_name = (void *) this_srt; /* really */
|
||||||
|
this_srt_nh->use_bfd = -1; /* undefined */
|
||||||
}
|
}
|
||||||
| stat_multipath1 WEIGHT expr {
|
| stat_multipath1 WEIGHT expr {
|
||||||
this_srt_nh->masklen = $3 - 1; /* really */
|
this_srt_nh->masklen = $3 - 1; /* really */
|
||||||
if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256");
|
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:
|
stat_multipath:
|
||||||
|
@ -98,6 +114,7 @@ stat_route:
|
||||||
|
|
||||||
stat_route_item:
|
stat_route_item:
|
||||||
cmd { *this_srt_last_cmd = $1; this_srt_last_cmd = &($1->next); }
|
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:
|
stat_route_opts:
|
||||||
|
|
|
@ -141,6 +141,29 @@ static_remove(struct proto *p, struct static_route *r)
|
||||||
r->installed = 0;
|
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 int
|
||||||
static_decide(struct static_config *cf, struct static_route *r)
|
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))
|
if (cf->check_link && !(r->neigh->iface->flags & IF_LINK_UP))
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
|
if (r->bfd_req && r->bfd_req->state != BFD_STATE_UP)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -171,6 +197,8 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
|
||||||
r->chain = n->data;
|
r->chain = n->data;
|
||||||
n->data = r;
|
n->data = r;
|
||||||
r->neigh = n;
|
r->neigh = n;
|
||||||
|
|
||||||
|
static_update_bfd(p, r);
|
||||||
if (static_decide(cf, r))
|
if (static_decide(cf, r))
|
||||||
static_install(p, r, n->iface);
|
static_install(p, r, n->iface);
|
||||||
else
|
else
|
||||||
|
@ -200,6 +228,8 @@ static_add(struct proto *p, struct static_config *cf, struct static_route *r)
|
||||||
r2->chain = n->data;
|
r2->chain = n->data;
|
||||||
n->data = r2;
|
n->data = r2;
|
||||||
r2->neigh = n;
|
r2->neigh = n;
|
||||||
|
|
||||||
|
static_update_bfd(p, r2);
|
||||||
r2->installed = static_decide(cf, r2);
|
r2->installed = static_decide(cf, r2);
|
||||||
count += r2->installed;
|
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 int
|
||||||
static_start(struct proto *p)
|
static_start(struct proto *p)
|
||||||
{
|
{
|
||||||
|
@ -254,7 +304,10 @@ static_shutdown(struct proto *p)
|
||||||
WALK_LIST(r, cf->iface_routes)
|
WALK_LIST(r, cf->iface_routes)
|
||||||
r->installed = 0;
|
r->installed = 0;
|
||||||
WALK_LIST(r, cf->other_routes)
|
WALK_LIST(r, cf->other_routes)
|
||||||
|
{
|
||||||
|
static_rte_cleanup(p, r);
|
||||||
r->installed = 0;
|
r->installed = 0;
|
||||||
|
}
|
||||||
|
|
||||||
return PS_DOWN;
|
return PS_DOWN;
|
||||||
}
|
}
|
||||||
|
@ -268,6 +321,44 @@ static_cleanup(struct proto *p)
|
||||||
rt_unlock_table(cf->igp_table->table);
|
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 void
|
||||||
static_neigh_notify(struct neighbor *n)
|
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);
|
DBG("Static: neighbor notify for %I: iface %p\n", n->addr, n->iface);
|
||||||
for(r=n->data; r; r=r->chain)
|
for(r=n->data; r; r=r->chain)
|
||||||
switch (r->dest)
|
{
|
||||||
{
|
static_update_bfd(p, r);
|
||||||
case RTD_ROUTER:
|
static_update_rte(p, r);
|
||||||
if (static_decide((struct static_config *) p->cf, r))
|
}
|
||||||
static_install(p, r, n->iface);
|
}
|
||||||
else
|
|
||||||
static_remove(p, r);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case RTD_NONE: /* a part of multipath route */
|
static void
|
||||||
{
|
static_bfd_notify(struct bfd_request *req)
|
||||||
int decision = static_decide((struct static_config *) p->cf, r);
|
{
|
||||||
if (decision == r->installed)
|
struct static_route *r = req->data;
|
||||||
break; /* no change */
|
struct proto *p = r->neigh->proto;
|
||||||
r->installed = decision;
|
|
||||||
|
|
||||||
struct static_route *r1, *r2;
|
// if (req->down) TRACE(D_EVENTS, "BFD session down for nbr %I on %s", XXXX);
|
||||||
int count = 0;
|
|
||||||
r1 = (void *) r->if_name; /* really */
|
|
||||||
for (r2 = r1->mp_next; r2; r2 = r2->mp_next)
|
|
||||||
count += r2->installed;
|
|
||||||
|
|
||||||
if (count)
|
static_update_rte(p, r);
|
||||||
{
|
|
||||||
/* Set of nexthops changed - force reinstall */
|
|
||||||
r1->installed = 0;
|
|
||||||
static_install(p, r1, NULL);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
static_remove(p, r1);
|
|
||||||
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
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;
|
for (x = x->mp_next, y = y->mp_next;
|
||||||
x && y;
|
x && y;
|
||||||
x = x->mp_next, y = y->mp_next)
|
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 0;
|
||||||
return !x && !y;
|
return !x && !y;
|
||||||
|
|
||||||
|
@ -499,6 +571,9 @@ static_reconfigure(struct proto *p, struct proto_config *new)
|
||||||
WALK_LIST(r, n->other_routes)
|
WALK_LIST(r, n->other_routes)
|
||||||
static_add(p, n, r);
|
static_add(p, n, r);
|
||||||
|
|
||||||
|
WALK_LIST(r, o->other_routes)
|
||||||
|
static_rte_cleanup(p, r);
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -584,13 +659,14 @@ static_show_rt(struct static_route *r)
|
||||||
case RTDX_RECURSIVE: bsprintf(via, "recursive %I", r->via); break;
|
case RTDX_RECURSIVE: bsprintf(via, "recursive %I", r->via); break;
|
||||||
default: bsprintf(via, "???");
|
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;
|
struct static_route *r2;
|
||||||
if (r->dest == RTD_MULTIPATH)
|
if (r->dest == RTD_MULTIPATH)
|
||||||
for (r2 = r->mp_next; r2; r2 = r2->mp_next)
|
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 */
|
cli_msg(-1009, "\tvia %I%J weight %d%s%s", r2->via, r2->via_if, r2->masklen + 1, /* really */
|
||||||
r2->installed ? "" : " (dormant)");
|
r2->bfd_req ? " (bfd)" : "", r2->installed ? "" : " (dormant)");
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -9,6 +9,9 @@
|
||||||
#ifndef _BIRD_STATIC_H_
|
#ifndef _BIRD_STATIC_H_
|
||||||
#define _BIRD_STATIC_H_
|
#define _BIRD_STATIC_H_
|
||||||
|
|
||||||
|
#include "nest/route.h"
|
||||||
|
#include "nest/bfd.h"
|
||||||
|
|
||||||
struct static_config {
|
struct static_config {
|
||||||
struct proto_config c;
|
struct proto_config c;
|
||||||
list iface_routes; /* Routes to search on interface events */
|
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 static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */
|
||||||
struct f_inst *cmds; /* List of commands for setting attributes */
|
struct f_inst *cmds; /* List of commands for setting attributes */
|
||||||
int installed; /* Installed in rt table, -1 for reinstall */
|
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
|
/* Dummy nodes (parts of multipath route) abuses masklen field for weight
|
||||||
|
|
Loading…
Reference in a new issue