Here is the inital support for OpenBGPD to understand BFD messages.
With this, when BFD detects failure, it sets the nexthop for that
neighbor to Invalid. Conversely, when BFD sets the state to up, it
removes that flag, setting the nexthop to Valid.
# when BFD state to 203.0.113.9 is Up
$ bgpctl show rib
flags: * = Valid, > = Selected, I = via IBGP, A = Announced, S = Stale
origin: i = IGP, e = EGP, ? = Incomplete
flags destination gateway lpref med aspath origin
I*> 192.0.2.1/32 203.0.113.1 100 0 i
AI* 192.0.2.1/32 0.0.0.0 100 0 i
I*> 192.0.2.9/32 203.0.113.9 100 0 i
I*> 198.51.100.9/32 203.0.113.9 100 0 i
I*> 203.0.113.0/24 203.0.113.9 100 0 i
# when BFD state to 203.0.113.9 is Down
$ bgpctl show rib
flags: * = Valid, > = Selected, I = via IBGP, A = Announced, S = Stale
origin: i = IGP, e = EGP, ? = Incomplete
flags destination gateway lpref med aspath origin
I*> 192.0.2.1/32 203.0.113.1 100 0 i
AI* 192.0.2.1/32 0.0.0.0 100 0 i
I 192.0.2.9/32 203.0.113.9 100 0 i
I 198.51.100.9/32 203.0.113.9 100 0 i
I 203.0.113.0/24 203.0.113.9 100 0 i
Index: bgpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
retrieving revision 1.188
diff -u -p -u -p -r1.188 bgpd.c
--- bgpd.c 24 Jan 2017 04:22:42 -0000 1.188
+++ bgpd.c 25 Jan 2017 09:47:10 -0000
@@ -778,6 +778,12 @@ send_network(int type, struct network_co
int
bgpd_filternexthop(struct kroute *kr, struct kroute6 *kr6)
{
+ /* BFD routes are special */
+ if (kr && kr->flags & F_BFDDOWN && kr->prefixlen != 0)
+ return (1);
+ if (kr6 && kr6->flags & F_BFDDOWN && kr6->prefixlen != 0)
+ return (1);
+
/* kernel routes are never filtered */
if (kr && kr->flags & F_KERNEL && kr->prefixlen != 0)
return (0);
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.300
diff -u -p -u -p -r1.300 bgpd.h
--- bgpd.h 25 Jan 2017 00:11:07 -0000 1.300
+++ bgpd.h 25 Jan 2017 09:47:10 -0000
@@ -85,6 +85,8 @@
#define F_CTL_ADJ_OUT 0x4000
#define F_CTL_ACTIVE 0x8000
#define F_RTLABEL 0x10000
+#define F_BFD 0x20000
+#define F_BFDDOWN 0x40000
/*
* Limit the number of control messages generated by the RDE and queued in
@@ -522,7 +524,7 @@ struct kroute {
struct in_addr prefix;
struct in_addr nexthop;
u_int32_t mplslabel;
- u_int16_t flags;
+ u_int32_t flags;
u_int16_t labelid;
u_short ifindex;
u_int8_t prefixlen;
@@ -532,7 +534,7 @@ struct kroute {
struct kroute6 {
struct in6_addr prefix;
struct in6_addr nexthop;
- u_int16_t flags;
+ u_int32_t flags;
u_int16_t labelid;
u_short ifindex;
u_int8_t prefixlen;
Index: kroute.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/kroute.c,v
retrieving revision 1.211
diff -u -p -u -p -r1.211 kroute.c
--- kroute.c 24 Jan 2017 04:22:42 -0000 1.211
+++ kroute.c 25 Jan 2017 09:47:10 -0000
@@ -27,6 +27,7 @@
#include <net/if_dl.h>
#include <net/route.h>
#include <netmpls/mpls.h>
+#include <net/bfd.h>
#include <err.h>
#include <errno.h>
#include <fcntl.h>
@@ -163,6 +164,7 @@ u_int8_t mask2prefixlen6(struct sockaddr
void get_rtaddrs(int, struct sockaddr *, struct sockaddr **);
void if_change(u_short, int, struct if_data *);
void if_announce(void *);
+void bfd_msg(void *, struct sockaddr *);
int send_rtmsg(int, int, struct ktable *, struct kroute *,
u_int8_t);
@@ -2093,7 +2095,7 @@ kroute_validate(struct kroute *kr)
{
struct kif_node *kif;
- if (kr->flags & (F_REJECT | F_BLACKHOLE))
+ if (kr->flags & (F_REJECT | F_BLACKHOLE | F_BFDDOWN))
return (0);
if ((kif = kif_find(kr->ifindex)) == NULL) {
@@ -2113,7 +2115,7 @@ kroute6_validate(struct kroute6 *kr)
{
struct kif_node *kif;
- if (kr->flags & (F_REJECT | F_BLACKHOLE))
+ if (kr->flags & (F_REJECT | F_BLACKHOLE | F_BFDDOWN))
return (0);
if ((kif = kif_find(kr->ifindex)) == NULL) {
@@ -2510,6 +2512,80 @@ if_change(u_short ifindex, int flags, st
}
void
+bfd_msg(void *msg, struct sockaddr *sa)
+{
+ struct bfd_msghdr *bfd;
+ struct ktable *kt;
+ struct knexthop_node *kn;
+ struct kroute_node *kr;
+ struct kroute6_node *kr6;
+ struct bgpd_addr prefix;
+ u_int rtableid = 0; /* XXX */
+ int state = -1;
+
+ bfd = msg;
+ bzero(&prefix, sizeof(prefix));
+
+ sa2addr(sa, &prefix);
+ if ((kt = ktable_get(rtableid)) == NULL) {
+ log_warnx("kr_nexthop_add: non-existent rtableid %d", rtableid);
+ return;
+ }
+
+ if ((kn = knexthop_find(kt, &prefix)) == NULL)
+ return;
+
+ switch (kn->nexthop.aid) {
+ case AID_INET:
+ kr = kn->kroute;
+ state = kr->r.flags & F_BFDDOWN;
+ break;
+ case AID_INET6:
+ kr6 = kn->kroute;
+ state = kr6->r.flags & F_BFDDOWN;
+ break;
+ }
+
+ switch (bfd->bm_sa.bs_state) {
+ case BFD_STATE_UP:
+ if (state) {
+ switch (kn->nexthop.aid) {
+ case AID_INET:
+ kr = kn->kroute;
+ kr->r.flags &= ~F_BFDDOWN;
+ break;
+ case AID_INET6:
+ kr6 = kn->kroute;
+ kr6->r.flags &= ~F_BFDDOWN;
+ break;
+ }
+ log_warnx("BFD was up, setting down");
+ knexthop_send_update(kn);
+ }
+ break;
+ case BFD_STATE_DOWN:
+ case BFD_STATE_ADMINDOWN:
+ if (!state) {
+ switch (kn->nexthop.aid) {
+ case AID_INET:
+ kr = kn->kroute;
+ kr->r.flags |= F_BFDDOWN;
+ break;
+ case AID_INET6:
+ kr6 = kn->kroute;
+ kr6->r.flags |= F_BFDDOWN;
+ break;
+ }
+ log_warnx("BFD was down, setting up");
+ knexthop_send_update(kn);
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+void
if_announce(void *msg)
{
struct if_announcemsghdr *ifan;
@@ -3120,6 +3196,12 @@ dispatch_rtmsg(void)
break;
case RTM_IFANNOUNCE:
if_announce(next);
+ break;
+ case RTM_BFD:
+ sa = (struct sockaddr *)(next + rtm->rtm_hdrlen);
+ get_rtaddrs(rtm->rtm_addrs, sa, rti_info);
+ if (rti_info[RTAX_DST])
+ bfd_msg(next, rti_info[RTAX_DST]);
break;
default:
/* ignore for now */
--
Larkinson's Law:
All laws are basically false.