On Thu, May 27, 2021 at 06:24:06PM +0200, Claudio Jeker wrote:
> Implement RFC 7313 enhanced route refresh.
> 
> While there also change when graceful restart EoR markers are sent.
> In short the graceful restart marker should only be sent initally. After
> that the End of Route Refresh message should be sent instead.
> Because of this track if an EoR marker was received or should be sent in
> the peer config.
> 
> For now this setting is off by default but that may be changed at a later
> state.
> 
> Please try this out and tell me if it works for you. The message and
> prefix/rrefresh counters in bgpctl show nei output help a lot to see what
> is going on.

Ping.

-- 
:wq Claudio

Index: bgpd.8
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.8,v
retrieving revision 1.67
diff -u -p -r1.67 bgpd.8
--- bgpd.8      25 May 2021 14:18:44 -0000      1.67
+++ bgpd.8      27 May 2021 16:03:30 -0000
@@ -380,6 +380,15 @@ has been started.
 .Re
 .Pp
 .Rs
+.%A K. Patel
+.%A E. Chen
+.%A B. Venkatachalapathy
+.%D July 2014
+.%R RFC 7313
+.%T Enhanced Route Refresh Capability for BGP-4
+.Re
+.Pp
+.Rs
 .%A W. Kumari
 .%A R. Bush
 .%A H. Schiller
Index: bgpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
retrieving revision 1.210
diff -u -p -r1.210 bgpd.conf.5
--- bgpd.conf.5 6 May 2021 09:21:35 -0000       1.210
+++ bgpd.conf.5 27 May 2021 16:03:30 -0000
@@ -831,6 +831,16 @@ The default is
 .Ic yes .
 .Pp
 .It Xo
+.Ic announce enhanced refresh
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+If set to
+.Ic yes ,
+the enhanced route refresh capability is announced.
+The default is
+.Ic no .
+.Pp
+.It Xo
 .Ic announce refresh
 .Pq Ic yes Ns | Ns Ic no
 .Xc
Index: bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.414
diff -u -p -r1.414 bgpd.h
--- bgpd.h      27 May 2021 08:27:48 -0000      1.414
+++ bgpd.h      27 May 2021 16:03:30 -0000
@@ -159,7 +159,7 @@ extern const struct aid aid_vals[];
 #define        AID_INET6       2
 #define        AID_VPN_IPv4    3
 #define        AID_VPN_IPv6    4
-#define        AID_MAX         5
+#define        AID_MAX         5       /* check rde_peer.recv_eor when max 
reaches 7 */
 #define        AID_MIN         1       /* skip AID_UNSPEC since that is a 
dummy */
 
 #define AID_VALS       {                                       \
Index: parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
retrieving revision 1.416
diff -u -p -r1.416 parse.y
--- parse.y     20 May 2021 10:06:20 -0000      1.416
+++ parse.y     27 May 2021 16:03:30 -0000
@@ -204,7 +204,7 @@ typedef struct {
 %token GROUP NEIGHBOR NETWORK
 %token EBGP IBGP
 %token LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
-%token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY
+%token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY ENHANCED
 %token DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN
 %token DUMP IN OUT SOCKET RESTRICTED
 %token LOG TRANSPARENT
@@ -1446,6 +1446,9 @@ peeropts  : REMOTEAS as4number    {
                | ANNOUNCE REFRESH yesno {
                        curpeer->conf.capabilities.refresh = $3;
                }
+               | ANNOUNCE ENHANCED REFRESH yesno {
+                       curpeer->conf.capabilities.enhanced_rr = $4;
+               }
                | ANNOUNCE RESTART yesno {
                        curpeer->conf.capabilities.grestart.restart = $3;
                }
@@ -2898,6 +2901,7 @@ lookup(char *s)
                { "dump",               DUMP},
                { "ebgp",               EBGP},
                { "enforce",            ENFORCE},
+               { "enhanced",           ENHANCED },
                { "esp",                ESP},
                { "evaluate",           EVALUATE},
                { "export",             EXPORT},
Index: rde.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.c,v
retrieving revision 1.524
diff -u -p -r1.524 rde.c
--- rde.c       27 May 2021 16:32:13 -0000      1.524
+++ rde.c       2 Jun 2021 10:09:23 -0000
@@ -1068,6 +1068,7 @@ rde_dispatch_imsg_rtr(struct imsgbuf *ib
 void
 rde_dispatch_imsg_peer(struct rde_peer *peer, void *bula)
 {
+       struct route_refresh rr;
        struct session_up sup;
        struct imsg imsg;
        u_int8_t aid;
@@ -1097,7 +1098,6 @@ rde_dispatch_imsg_peer(struct rde_peer *
        case IMSG_SESSION_STALE:
        case IMSG_SESSION_FLUSH:
        case IMSG_SESSION_RESTARTED:
-       case IMSG_REFRESH:
                if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(aid)) {
                        log_warnx("%s: wrong imsg len", __func__);
                        break;
@@ -1119,8 +1119,44 @@ rde_dispatch_imsg_peer(struct rde_peer *
                        if (peer->staletime[aid])
                                peer_flush(peer, aid, peer->staletime[aid]);
                        break;
-               case IMSG_REFRESH:
-                       peer_dump(peer, aid);
+               }
+               break;
+       case IMSG_REFRESH:
+               if (imsg.hdr.len - IMSG_HEADER_SIZE != sizeof(rr)) {
+                       log_warnx("%s: wrong imsg len", __func__);
+                       break;
+               }
+               memcpy(&rr, imsg.data, sizeof(rr));
+               if (rr.aid >= AID_MAX) {
+                       log_warnx("%s: bad AID", __func__);
+                       break;
+               }
+               switch (rr.subtype) {
+               case ROUTE_REFRESH_REQUEST:
+                       peer_dump(peer, rr.aid);
+                       break;
+               case ROUTE_REFRESH_BEGIN_RR:
+                       /* check if graceful restart EOR was received */
+                       if ((peer->recv_eor & (1 << rr.aid)) == 0) {
+                               log_peer_warnx(&peer->conf,
+                                   "received %s BoRR before EoR",
+                                   aid2str(rr.aid));
+                               break;
+                       }
+                       peer_begin_rrefresh(peer, rr.aid);
+                       break;
+               case ROUTE_REFRESH_END_RR:
+                       if ((peer->recv_eor & (1 << rr.aid)) != 0 &&
+                           peer->staletime[rr.aid])
+                               peer_flush(peer, rr.aid,
+                                   peer->staletime[rr.aid]);
+                       else
+                               log_peer_warnx(&peer->conf,
+                                   "received unexpected %s EoRR",
+                                   aid2str(rr.aid));
+                       break;
+               default:
+                       log_warnx("%s: bad subtype %d", __func__, rr.subtype);
                        break;
                }
                break;
@@ -3004,8 +3040,14 @@ rde_update_queue_runner(void)
                                            __func__, __LINE__);
                                sent++;
                        }
-                       if (eor)
-                               rde_peer_send_eor(peer, AID_INET);
+                       if (eor) {
+                               int sent_eor = peer->sent_eor & (1 << AID_INET);
+                               if (peer->capa.grestart.restart && !sent_eor)
+                                       rde_peer_send_eor(peer, AID_INET);
+                               if (peer->capa.enhanced_rr && sent_eor)
+                                       rde_peer_send_rrefresh(peer, AID_INET,
+                                           ROUTE_REFRESH_END_RR);
+                       }
                }
                max -= sent;
        } while (sent != 0 && max > 0);
@@ -3055,7 +3097,12 @@ rde_update6_queue_runner(u_int8_t aid)
                                continue;
                        len = sizeof(queue_buf) - MSGSIZE_HEADER;
                        if (up_is_eor(peer, aid)) {
-                               rde_peer_send_eor(peer, aid);
+                               int sent_eor = peer->sent_eor & (1 << aid);
+                               if (peer->capa.grestart.restart && !sent_eor)
+                                       rde_peer_send_eor(peer, aid);
+                               if (peer->capa.enhanced_rr && sent_eor)
+                                       rde_peer_send_rrefresh(peer, aid,
+                                           ROUTE_REFRESH_END_RR);
                                continue;
                        }
                        r = up_dump_mp_reach(queue_buf, len, peer, aid);
@@ -3747,6 +3794,7 @@ static void
 rde_peer_recv_eor(struct rde_peer *peer, u_int8_t aid)
 {
        peer->prefix_rcvd_eor++;
+       peer->recv_eor |= 1 << aid;
 
        /*
         * First notify SE to avert a possible race with the restart timeout.
@@ -3771,6 +3819,7 @@ rde_peer_send_eor(struct rde_peer *peer,
        u_int8_t        safi;
 
        peer->prefix_sent_eor++;
+       peer->sent_eor |= 1 << aid;
 
        if (aid == AID_INET) {
                u_char null[4];
@@ -3805,6 +3854,33 @@ rde_peer_send_eor(struct rde_peer *peer,
 
        log_peer_info(&peer->conf, "sending %s EOR marker",
            aid2str(aid));
+}
+
+void
+rde_peer_send_rrefresh(struct rde_peer *peer, u_int8_t aid, u_int8_t subtype)
+{
+       struct route_refresh rr;
+
+       /* not strickly needed, the SE checks as well */
+        if (peer->capa.enhanced_rr == 0)
+               return;
+
+       switch (subtype) {
+       case ROUTE_REFRESH_END_RR:
+       case ROUTE_REFRESH_BEGIN_RR:
+               break;
+       default:
+               fatalx("%s unexpected subtype %d", __func__, subtype);
+       }
+
+       rr.aid = aid;
+       rr.subtype = subtype;
+
+       if (imsg_compose(ibuf_se, IMSG_REFRESH, peer->conf.id, 0, -1,
+           &rr, sizeof(rr)) == -1)
+
+       log_peer_info(&peer->conf, "sending %s %s marker",
+           aid2str(aid), subtype == ROUTE_REFRESH_END_RR ? "EoRR" : "BoRR");
 }
 
 /*
Index: rde.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde.h,v
retrieving revision 1.239
diff -u -p -r1.239 rde.h
--- rde.h       27 May 2021 14:32:08 -0000      1.239
+++ rde.h       27 May 2021 16:03:30 -0000
@@ -107,6 +107,8 @@ struct rde_peer {
        u_int16_t                        loc_rib_id;
        u_int16_t                        short_as;
        u_int16_t                        mrt_idx;
+       u_int8_t                         recv_eor;      /* bitfield per AID */
+       u_int8_t                         sent_eor;      /* bitfield per AID */
        u_int8_t                         reconf_out;    /* out filter changed */
        u_int8_t                         reconf_rib;    /* rib changed */
        u_int8_t                         throttled;
@@ -378,6 +380,7 @@ void                rde_generate_updates(struct rib *,
                    struct prefix *, int);
 u_int32_t      rde_local_as(void);
 int            rde_decisionflags(void);
+void           rde_peer_send_rrefresh(struct rde_peer *, u_int8_t, u_int8_t);
 int            rde_match_peer(struct rde_peer *, struct ctl_neighbor *);
 
 /* rde_peer.c */
@@ -395,6 +398,7 @@ void                 peer_down(struct rde_peer *, void
 void            peer_flush(struct rde_peer *, u_int8_t, time_t);
 void            peer_stale(struct rde_peer *, u_int8_t);
 void            peer_dump(struct rde_peer *, u_int8_t);
+void            peer_begin_rrefresh(struct rde_peer *, u_int8_t);
 
 void            peer_imsg_push(struct rde_peer *, struct imsg *);
 int             peer_imsg_pop(struct rde_peer *, struct imsg *);
Index: rde_peer.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rde_peer.c,v
retrieving revision 1.9
diff -u -p -r1.9 rde_peer.c
--- rde_peer.c  27 May 2021 14:32:08 -0000      1.9
+++ rde_peer.c  27 May 2021 16:03:30 -0000
@@ -345,6 +345,15 @@ peer_up(struct rde_peer *peer, struct se
        peer->local_v6_addr = sup->local_v6_addr;
        memcpy(&peer->capa, &sup->capa, sizeof(peer->capa));
 
+       /* clear eor markers depending on GR flags */
+       if (peer->capa.grestart.restart) {
+               peer->sent_eor = 0;
+               peer->recv_eor = 0;
+       } else {
+               /* no EOR expected */
+               peer->sent_eor = ~0;
+               peer->recv_eor = ~0;
+       }
        peer->state = PEER_UP;
 
        for (i = 0; i < AID_MAX; i++) {
@@ -443,6 +452,9 @@ peer_stale(struct rde_peer *peer, u_int8
 void
 peer_dump(struct rde_peer *peer, u_int8_t aid)
 {
+       if (peer->capa.enhanced_rr && (peer->sent_eor & (1 << aid)))
+               rde_peer_send_rrefresh(peer, aid, ROUTE_REFRESH_BEGIN_RR);
+
        if (peer->export_type == EXPORT_NONE) {
                /* nothing to send apart from the marker */
                if (peer->capa.grestart.restart)
@@ -457,6 +469,27 @@ peer_dump(struct rde_peer *peer, u_int8_
                /* throttle peer until dump is done */
                peer->throttled = 1;
        }
+}
+
+/*
+ * Start of an enhanced route refresh. Mark all routes as stale.
+ * Once the route refresh ends a End of Route Refresh message is sent
+ * which calls peer_flush() to remove all stale routes.
+ */
+void
+peer_begin_rrefresh(struct rde_peer *peer, u_int8_t aid)
+{
+       time_t now;
+
+       /* flush the now even staler routes out */
+       if (peer->staletime[aid])
+               peer_flush(peer, aid, peer->staletime[aid]);
+
+       peer->staletime[aid] = now = getmonotime();
+
+       /* make sure new prefixes start on a higher timestamp */
+       while (now >= getmonotime())
+               sleep(1);
 }
 
 /*
Index: session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.420
diff -u -p -r1.420 session.c
--- session.c   27 May 2021 09:15:51 -0000      1.420
+++ session.c   27 May 2021 16:03:30 -0000
@@ -2256,6 +2256,7 @@ parse_update(struct peer *peer)
 int
 parse_rrefresh(struct peer *peer)
 {
+       struct route_refresh rr;
        u_int16_t afi, datalen;
        u_int8_t aid, safi, subtype;
        u_char *p;
@@ -2343,7 +2344,10 @@ parse_rrefresh(struct peer *peer)
                return (0);
        }
 
-       if (imsg_rde(IMSG_REFRESH, peer->conf.id, &aid, sizeof(aid)) == -1)
+       rr.aid = aid;
+       rr.subtype = subtype;
+
+       if (imsg_rde(IMSG_REFRESH, peer->conf.id, &rr, sizeof(rr)) == -1)
                return (-1);
 
        return (0);
@@ -2768,6 +2772,7 @@ session_dispatch_imsg(struct imsgbuf *ib
 {
        struct imsg              imsg;
        struct mrt               xmrt;
+       struct route_refresh     rr;
        struct mrt              *mrt;
        struct imsgbuf          *i;
        struct peer             *p;
@@ -3094,6 +3099,23 @@ session_dispatch_imsg(struct imsgbuf *ib
                                bgp_fsm(p, EVNT_CON_FATAL);
                                break;
                        }
+                       break;
+               case IMSG_REFRESH:
+                       if (idx != PFD_PIPE_ROUTE)
+                               fatalx("route refresh request not from RDE");
+                       if (imsg.hdr.len < IMSG_HEADER_SIZE + sizeof(rr)) {
+                               log_warnx("RDE sent invalid refresh msg");
+                               break;
+                       }
+                       if ((p = getpeerbyid(conf, imsg.hdr.peerid)) == NULL) {
+                               log_warnx("no such peer: id=%u",
+                                   imsg.hdr.peerid);
+                               break;
+                       }
+                       memcpy(&rr, imsg.data, sizeof(rr));
+                       if (rr.aid >= AID_MAX)
+                               fatalx("IMSG_REFRESH: bad AID");
+                       session_rrefresh(p, rr.aid, rr.subtype);
                        break;
                case IMSG_SESSION_RESTARTED:
                        if (idx != PFD_PIPE_ROUTE)

Reply via email to