From 538264cf1a7690d90b2953aebff21958c2b55c44 Mon Sep 17 00:00:00 2001 From: Ondrej Zajicek Date: Fri, 24 Jul 2015 18:02:07 +0200 Subject: [PATCH] Static: Support for BFD controlled static routes --- nest/bfd.h | 6 ++ proto/static/config.Y | 21 +++++- proto/static/static.c | 146 ++++++++++++++++++++++++++++++++---------- proto/static/static.h | 5 ++ 4 files changed, 141 insertions(+), 37 deletions(-) diff --git a/nest/bfd.h b/nest/bfd.h index 79c3c921..f1e95cb2 100644 --- a/nest/bfd.h +++ b/nest/bfd.h @@ -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); diff --git a/proto/static/config.Y b/proto/static/config.Y index d1b62af9..182721b3 100644 --- a/proto/static/config.Y +++ b/proto/static/config.Y @@ -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: diff --git a/proto/static/static.c b/proto/static/static.c index 57c44885..be808593 100644 --- a/proto/static/static.c +++ b/proto/static/static.c @@ -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; +static void +static_bfd_notify(struct bfd_request *req) +{ + struct static_route *r = req->data; + struct proto *p = r->neigh->proto; - 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 (req->down) TRACE(D_EVENTS, "BFD session down for nbr %I on %s", XXXX); - if (count) - { - /* Set of nexthops changed - force reinstall */ - r1->installed = 0; - static_install(p, r1, NULL); - } - else - static_remove(p, r1); - - break; - } - } + 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 diff --git a/proto/static/static.h b/proto/static/static.h index f197d352..6b047234 100644 --- a/proto/static/static.h +++ b/proto/static/static.h @@ -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