diff -Naur bird-1.5.0/proto/static/config.Y bird/proto/static/config.Y --- bird-1.5.0/proto/static/config.Y 2015-06-08 11:11:21.000000000 +0000 +++ bird/proto/static/config.Y 2015-06-22 15:49:30.000000000 +0000 @@ -17,7 +17,7 @@ CF_DECLS -CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK) +CF_KEYWORDS(STATIC, ROUTE, VIA, DROP, REJECT, PROHIBIT, PREFERENCE, CHECK, LINK, BFD) CF_KEYWORDS(MULTIPATH, WEIGHT, RECURSIVE, IGP, TABLE, BLACKHOLE, UNREACHABLE) @@ -60,6 +60,9 @@ this_srt_nh->masklen = $3 - 1; /* really */ if (($3<1) || ($3>256)) cf_error("Weight must be in range 1-256"); } + | stat_multipath1 BFD expr { + this_srt_nh->use_bfd = $3; ; cf_check_bfd($3); + } ; stat_multipath: @@ -73,6 +76,12 @@ this_srt->via = $3; this_srt->via_if = $4; } + | stat_route0 VIA ipa ipa_scope BFD bool { + this_srt->dest = RTD_ROUTER; + this_srt->via = $3; + this_srt->via_if = $4; + this_srt->use_bfd = $6; cf_check_bfd($6); + } | stat_route0 VIA TEXT { this_srt->dest = RTD_DEVICE; this_srt->if_name = $3; @@ -86,7 +95,6 @@ this_srt->dest = RTDX_RECURSIVE; this_srt->via = $3; } - | stat_route0 DROP { this_srt->dest = RTD_BLACKHOLE; } | stat_route0 REJECT { this_srt->dest = RTD_UNREACHABLE; } | stat_route0 BLACKHOLE { this_srt->dest = RTD_BLACKHOLE; } @@ -94,6 +102,7 @@ | stat_route0 PROHIBIT { this_srt->dest = RTD_PROHIBIT; } ; + CF_CLI(SHOW STATIC, optsym, [], [[Show details of static protocol]]) { static_show(proto_get_named($3, &proto_static)); } ; diff -Naur bird-1.5.0/proto/static/static.c bird/proto/static/static.c --- bird-1.5.0/proto/static/static.c 2015-06-08 11:11:21.000000000 +0000 +++ bird/proto/static/static.c 2015-06-23 07:59:24.000000000 +0000 @@ -47,6 +47,12 @@ #include "static.h" +#ifdef HACK_BFD_IN +#include "nest/bfd.h" +#endif + +void static_bfd_notify(struct bfd_request *req); + static inline rtable * p_igp_table(struct proto *p) { @@ -54,6 +60,33 @@ return cf->igp_table ? cf->igp_table->table : p->table; } +#ifdef HACK_BFD_IN +static void +static_add_route_to_bfd(struct proto *p, struct static_route *r) +{ + struct iface * iface = NULL; + if(r->via_if) + iface = r->via_if; + else + if ((r->neigh) && (r->neigh->iface)) + iface = r->neigh->iface; + + + + if ((iface) && (r->use_bfd) && (r->bfd_req == NULL)) + { +log(L_ERR "Installing BFD for via %I Interface %s (dest type %d)\n", r->via, iface->name, r->dest); + r->bfd_req = bfd_request_session(p->pool, r->via, iface->addr->ip, iface, static_bfd_notify, p); + } + + if ((!r->use_bfd) && (r->bfd_req != NULL)) + { +log(L_ERR "Freeing BFD session for via %I (dest type %d)\n", r->via, r->dest); + rfree(r->bfd_req); + r->bfd_req = NULL; + } +} +#endif static void static_install(struct proto *p, struct static_route *r, struct iface *ifa) @@ -64,7 +97,7 @@ if (r->installed > 0) return; - + log(L_ERR "Installing static route %I/%d, rtd=%d\n", r->net, r->masklen, r->dest); DBG("Installing static route %I/%d, rtd=%d\n", r->net, r->masklen, r->dest); bzero(&a, sizeof(a)); a.src = p->main_source; @@ -115,6 +148,24 @@ e->pflags = 0; rte_update(p, n, e); r->installed = 1; + +#ifdef HACK_BFD_IN + // Register BFD + if (a.nexthops) + { + // Multiple via mode + struct static_route *r2; + for (r2 = r->mp_next; r2; r2 = r2->mp_next) + { + static_add_route_to_bfd(p, r2); + } + } + else + { + // Single via mode + static_add_route_to_bfd(p, r); + } +#endif } static void @@ -275,13 +326,13 @@ case RTD_NONE: /* a part of multipath route */ { + struct static_route *r1, *r2; + int count = 0; 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; @@ -300,6 +351,132 @@ } } +#ifdef HACK_BFD_IN +static struct static_route * check_route_for_bfd_req_pr(struct static_route **master, struct static_route * r, struct bfd_request *req) +{ + *master = NULL; + if (r->dest == RTD_MULTIPATH) + { + struct static_route * r2; + for (r2 = r->mp_next; r2; r2 = r2->mp_next) + { + if(r2->bfd_req == req) + { + *master = r; + return(r2); + } + } + } + else + { + if(r->bfd_req == req) + return(r); + } + return(NULL); +} + +static struct static_route * locate_route_with_bfd_req(struct static_route **master, struct proto *p, struct bfd_request *req) +{ + struct static_route *r; + struct static_config *c = (void *) p->cf; + struct static_route *result; + *master = NULL; + + WALK_LIST(r, c->iface_routes) + { + result = check_route_for_bfd_req_pr(master, r, req); + if(result != NULL) + return(result); + } + WALK_LIST(r, c->other_routes) + { + result = check_route_for_bfd_req_pr(master, r, req); + if(result != NULL) + return(result); + } + return(NULL); +} + + +void static_bfd_notify(struct bfd_request *req) +{ + struct proto *p = req->data; + struct static_route * r; + struct static_route * master; + struct iface * iface = NULL; + char stateUp = 0; + char * state = "DOWN"; + +// Not sure if this is the best detection mechanisum, appears to be up at startup + if (req->down) + { + stateUp = 0; + state = "DOWN"; + } + else + { + stateUp = 1; + state = "UP"; + } + + + r = locate_route_with_bfd_req(&master, p, req); + if(r == NULL) + { + log(L_ERR "BFD Update : BFD Request NOT found"); + return; + } + else + { + log(L_ERR "BFD Update : BFD Request found"); + } + +// Not sure if this is the correct way + if(r->via_if) + iface = r->via_if; + else + if ((r->neigh) && (r->neigh->iface)) + iface = r->neigh->iface; + + log(L_ERR "BFD Update : for route via %I desttype %d - %s", r->via, r->dest, state); + + switch (r->dest) + { + case RTD_ROUTER: + if (stateUp) + static_install(p, r, iface); + else + static_remove(p, r); + break; + + case RTD_NONE: /* a part of multipath route */ + { + struct static_route *r2; + if(master) + { + int count = 0; + if (stateUp == r->installed) + break; /* no change */ + r->installed = stateUp; + + for (r2 = master->mp_next; r2; r2 = r2->mp_next) + count += r2->installed; + + if (count) + { + /* Set of nexthops changed - force reinstall */ + master->installed = 0; + static_install(p, master, NULL); + } + else + static_remove(p, master); + } + break; + } + } +} +#endif + static void static_dump_rt(struct static_route *r) { @@ -544,6 +721,7 @@ static void static_show_rt(struct static_route *r) { + struct static_route *r2; byte via[STD_ADDRESS_P_LENGTH + 16]; switch (r->dest) @@ -559,7 +737,6 @@ } cli_msg(-1009, "%I/%d %s%s", r->net, r->masklen, via, 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 */ diff -Naur bird-1.5.0/proto/static/static.h bird/proto/static/static.h --- bird-1.5.0/proto/static/static.h 2015-06-08 11:11:21.000000000 +0000 +++ bird/proto/static/static.h 2015-06-22 16:18:28.000000000 +0000 @@ -9,6 +9,8 @@ #ifndef _BIRD_STATIC_H_ #define _BIRD_STATIC_H_ +#define HACK_BFD_IN 1 + struct static_config { struct proto_config c; list iface_routes; /* Routes to search on interface events */ @@ -32,6 +34,10 @@ byte *if_name; /* Name for RTD_DEVICE routes */ struct static_route *mp_next; /* Nexthops for RTD_MULTIPATH routes */ int installed; /* Installed in rt table, -1 for reinstall */ +#ifdef HACK_BFD_IN + int use_bfd; /* Use BFD to check availablity */ + struct bfd_request *bfd_req; /* BFD request, if BFD is used */ +#endif }; /* Dummy nodes (parts of multipath route) abuses masklen field for weight