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.

Reply via email to