-.\" $OpenBSD: bgpd.8,v 1.68 2021/06/16 16:24:12 job Exp $
+.\" $OpenBSD: bgpd.8,v 1.69 2021/06/17 16:05:25 claudio Exp $
.\"
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
.\"
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: June 16 2021 $
+.Dd $Mdocdate: June 17 2021 $
.Dt BGPD 8
.Os
.Sh NAME
.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
-.\" $OpenBSD: bgpd.conf.5,v 1.210 2021/05/06 09:21:35 claudio Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.211 2021/06/17 16:05:25 claudio Exp $
.\"
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: May 6 2021 $
+.Dd $Mdocdate: June 17 2021 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
.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
-/* $OpenBSD: bgpd.h,v 1.414 2021/05/27 08:27:48 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.415 2021/06/17 16:05:26 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
#define F_CTL_OVS_NOTFOUND 0x200000
#define F_CTL_NEIGHBORS 0x400000 /* only used by bgpctl */
+#define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \
+ __attribute__((__unused__))
+
/*
* Note that these numeric assignments differ from the numbers commonly
* used in route origin validation context.
-/* $OpenBSD: parse.y,v 1.416 2021/05/20 10:06:20 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.417 2021/06/17 16:05:26 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
%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
| 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;
}
{ "dump", DUMP},
{ "ebgp", EBGP},
{ "enforce", ENFORCE},
+ { "enhanced", ENHANCED },
{ "esp", ESP},
{ "evaluate", EVALUATE},
{ "export", EXPORT},
-/* $OpenBSD: rde.c,v 1.526 2021/06/17 10:28:36 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.527 2021/06/17 16:05:26 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
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;
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;
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;
__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);
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);
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.
u_int8_t safi;
peer->prefix_sent_eor++;
+ peer->sent_eor |= 1 << aid;
if (aid == AID_INET) {
u_char null[4];
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");
+}
+
/*
* network announcement stuff
*/
-/* $OpenBSD: rde.h,v 1.239 2021/05/27 14:32:08 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.240 2021/06/17 16:05:26 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
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;
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 */
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 *);
-/* $OpenBSD: rde_peer.c,v 1.10 2021/06/17 08:45:37 claudio Exp $ */
+/* $OpenBSD: rde_peer.c,v 1.11 2021/06/17 16:05:26 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
struct rde_peer_head peerlist;
struct rde_peer *peerself;
+CTASSERT(sizeof(peerself->recv_eor) * 8 > AID_MAX);
+CTASSERT(sizeof(peerself->sent_eor) * 8 > AID_MAX);
+
struct iq {
SIMPLEQ_ENTRY(iq) entry;
struct imsg imsg;
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++) {
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)
}
}
+/*
+ * 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);
+}
+
/*
* move an imsg from src to dst, disconnecting any dynamic memory from src.
*/
-/* $OpenBSD: session.c,v 1.420 2021/05/27 09:15:51 claudio Exp $ */
+/* $OpenBSD: session.c,v 1.421 2021/06/17 16:05:26 claudio Exp $ */
/*
* Copyright (c) 2003, 2004, 2005 Henning Brauer <henning@openbsd.org>
int
parse_rrefresh(struct peer *peer)
{
+ struct route_refresh rr;
u_int16_t afi, datalen;
u_int8_t aid, safi, subtype;
u_char *p;
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);
{
struct imsg imsg;
struct mrt xmrt;
+ struct route_refresh rr;
struct mrt *mrt;
struct imsgbuf *i;
struct peer *p;
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)
fatalx("update request not from RDE");