On Tue, May 18, 2021 at 05:35:01PM +0200, Claudio Jeker wrote:
> bgpd(8) will soon support ADD-PATH (RFC7911) and enhanced route refresh
> (RFC7313). This is the frist step toward this.
> It add the capability parsers, extends the capability struct and adds the
> capability negotiation bits. The route refresh parser and generator are
> extended to support the BoRR and EoRR message and last but not least
> bgpctl is adjusted to print the new capabilities.
>
> Now since the system has no way of enabling the two new capabilities.
> bgpctl will only show if the peer sends the capability but there should
> be no other effect.
>
> The RDE bits for enahnced route refresh are almost ready, add-path will
> take a bit more since the RDE needs to grow an extra indirection.
>
> I decided to split this work up to simplify review. Lets see if this
> works :)
Since this does not change any behaviour I consider to commit this soon
unles someone objects.
--
:wq Claudio
Index: bgpctl/bgpctl.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/bgpctl.c,v
retrieving revision 1.267
diff -u -p -r1.267 bgpctl.c
--- bgpctl/bgpctl.c 3 May 2021 14:01:56 -0000 1.267
+++ bgpctl/bgpctl.c 18 May 2021 08:49:34 -0000
@@ -1351,6 +1351,13 @@ print_capability(u_int8_t capa_code, u_c
} else
printf("bad length");
break;
+ case CAPA_ADD_PATH:
+ printf("add-path capability");
+ /* XXX there is more needed here */
+ break;
+ case CAPA_ENHANCED_RR:
+ printf("enhanced route refresh capability");
+ break;
default:
printf("unknown capability %u length %u", capa_code, len);
break;
Index: bgpctl/output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
retrieving revision 1.16
diff -u -p -r1.16 output.c
--- bgpctl/output.c 26 Apr 2021 18:23:20 -0000 1.16
+++ bgpctl/output.c 18 May 2021 15:17:39 -0000
@@ -147,6 +147,34 @@ show_neighbor_capa_mp(struct capabilitie
}
static void
+show_neighbor_capa_add_path(struct capabilities *capa)
+{
+ const char *mode;
+ int comma;
+ u_int8_t i;
+
+ printf(" Add-path: ");
+ for (i = 0, comma = 0; i < AID_MAX; i++) {
+ switch (capa->add_path[i]) {
+ case 0:
+ default:
+ continue;
+ case CAPA_AP_RECV:
+ mode = "recv";
+ break;
+ case CAPA_AP_SEND:
+ mode = "send";
+ break;
+ case CAPA_AP_BIDIR:
+ mode = "bidir";
+ }
+ printf("%s%s %s", comma ? ", " : "", aid2str(i), mode);
+ comma = 1;
+ }
+ printf("\n");
+}
+
+static void
show_neighbor_capa_restart(struct capabilities *capa)
{
int comma;
@@ -202,6 +230,13 @@ show_neighbor_msgstats(struct peer *p)
p->stats.prefix_sent_withdraw, p->stats.prefix_rcvd_withdraw);
printf(" %-15s %10llu %10llu\n", "End-of-Rib",
p->stats.prefix_sent_eor, p->stats.prefix_rcvd_eor);
+ printf(" Route Refresh statistics:\n");
+ printf(" %-15s %10llu %10llu\n", "Request",
+ p->stats.refresh_sent_req, p->stats.refresh_rcvd_req);
+ printf(" %-15s %10llu %10llu\n", "Begin-of-RR",
+ p->stats.refresh_sent_borr, p->stats.refresh_rcvd_borr);
+ printf(" %-15s %10llu %10llu\n", "End-of-RR",
+ p->stats.refresh_sent_eorr, p->stats.refresh_rcvd_eorr);
}
static void
@@ -210,7 +245,7 @@ show_neighbor_full(struct peer *p, struc
const char *errstr;
struct in_addr ina;
char *s;
- int hascapamp = 0;
+ int hascapamp, hascapaap;
u_int8_t i;
if ((p->conf.remote_addr.aid == AID_INET &&
@@ -279,35 +314,57 @@ show_neighbor_full(struct peer *p, struc
fmt_monotime(p->stats.last_read),
p->holdtime, p->holdtime/3);
printf(" Last write %s\n", fmt_monotime(p->stats.last_write));
- for (i = 0; i < AID_MAX; i++)
+
+ hascapamp = 0;
+ hascapaap = 0;
+ for (i = AID_MIN; i < AID_MAX; i++) {
if (p->capa.peer.mp[i])
hascapamp = 1;
- if (hascapamp || p->capa.peer.refresh ||
- p->capa.peer.grestart.restart || p->capa.peer.as4byte) {
+ if (p->capa.peer.add_path[i])
+ hascapaap = 1;
+ }
+ if (hascapamp || hascapaap || p->capa.peer.grestart.restart ||
+ p->capa.peer.refresh || p->capa.peer.enhanced_rr ||
+ p->capa.peer.as4byte) {
printf(" Neighbor capabilities:\n");
if (hascapamp)
show_neighbor_capa_mp(&p->capa.peer);
+ if (p->capa.peer.as4byte)
+ printf(" 4-byte AS numbers\n");
if (p->capa.peer.refresh)
printf(" Route Refresh\n");
+ if (p->capa.peer.enhanced_rr)
+ printf(" Enhanced Route Refresh\n");
if (p->capa.peer.grestart.restart)
show_neighbor_capa_restart(&p->capa.peer);
- if (p->capa.peer.as4byte)
- printf(" 4-byte AS numbers\n");
+ if (hascapaap)
+ show_neighbor_capa_add_path(&p->capa.peer);
}
- for (i = 0; i < AID_MAX; i++)
+
+ hascapamp = 0;
+ hascapaap = 0;
+ for (i = AID_MIN; i < AID_MAX; i++) {
if (p->capa.neg.mp[i])
hascapamp = 1;
- if (hascapamp || p->capa.neg.refresh ||
- p->capa.neg.grestart.restart || p->capa.neg.as4byte) {
+ if (p->capa.neg.add_path[i])
+ hascapaap = 1;
+ }
+ if (hascapamp || hascapaap || p->capa.neg.grestart.restart ||
+ p->capa.neg.refresh || p->capa.neg.enhanced_rr ||
+ p->capa.neg.as4byte) {
printf(" Negotiated capabilities:\n");
if (hascapamp)
show_neighbor_capa_mp(&p->capa.neg);
+ if (p->capa.neg.as4byte)
+ printf(" 4-byte AS numbers\n");
if (p->capa.neg.refresh)
printf(" Route Refresh\n");
+ if (p->capa.neg.enhanced_rr)
+ printf(" Enhanced Route Refresh\n");
if (p->capa.neg.grestart.restart)
show_neighbor_capa_restart(&p->capa.neg);
- if (p->capa.neg.as4byte)
- printf(" 4-byte AS numbers\n");
+ if (hascapaap)
+ show_neighbor_capa_add_path(&p->capa.neg);
}
printf("\n");
Index: bgpctl/output_json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v
retrieving revision 1.10
diff -u -p -r1.10 output_json.c
--- bgpctl/output_json.c 3 May 2021 14:01:56 -0000 1.10
+++ bgpctl/output_json.c 18 May 2021 15:22:56 -0000
@@ -40,19 +40,23 @@ json_head(struct parse_result *res)
static void
json_neighbor_capabilities(struct capabilities *capa)
{
- int hascapamp;
+ int hascapamp = 0, hascapaap = 0;
uint8_t i;
- for (i = 0; i < AID_MAX; i++)
+ for (i = 0; i < AID_MAX; i++) {
if (capa->mp[i])
hascapamp = 1;
- if (!hascapamp && !capa->refresh && !capa->grestart.restart &&
- !capa->as4byte)
+ if (capa->add_path[i])
+ hascapaap = 1;
+ }
+ if (!hascapamp && !hascapaap && !capa->grestart.restart &&
+ !capa->refresh && !capa->enhanced_rr && !capa->as4byte)
return;
json_do_object("capabilities");
json_do_bool("as4byte", capa->as4byte);
json_do_bool("refresh", capa->refresh);
+ json_do_bool("enhanced_refresh", capa->enhanced_rr);
if (hascapamp) {
json_do_array("multiprotocol");
@@ -95,6 +99,31 @@ json_neighbor_capabilities(struct capabi
json_do_end();
}
+ if (hascapaap) {
+ json_do_array("add-path");
+ for (i = 0; i < AID_MAX; i++)
+ if (capa->add_path[i]) {
+ json_do_object("add-path-elm");
+ json_do_printf("family", "%s", aid2str(i));
+ switch (capa->add_path[i]) {
+ case CAPA_AP_RECV:
+ json_do_printf("mode", "recv");
+ break;
+ case CAPA_AP_SEND:
+ json_do_printf("mode", "send");
+ break;
+ case CAPA_AP_BIDIR:
+ json_do_printf("mode", "bidir");
+ break;
+ default:
+ json_do_printf("mode", "unknown %d",
+ capa->add_path[i]);
+ break;
+ }
+ json_do_end();
+ }
+ json_do_end();
+ }
json_do_end();
}
@@ -153,6 +182,22 @@ json_neighbor_stats(struct peer *p)
json_do_uint("updates", p->stats.prefix_rcvd_update);
json_do_uint("withdraws", p->stats.prefix_rcvd_withdraw);
json_do_uint("eor", p->stats.prefix_rcvd_eor);
+ json_do_end();
+
+ json_do_end();
+
+ json_do_object("route-refresh");
+
+ json_do_object("sent");
+ json_do_uint("request", p->stats.refresh_sent_req);
+ json_do_uint("borr", p->stats.refresh_sent_borr);
+ json_do_uint("eorr", p->stats.refresh_sent_eorr);
+ json_do_end();
+
+ json_do_object("received");
+ json_do_uint("request", p->stats.refresh_rcvd_req);
+ json_do_uint("borr", p->stats.refresh_rcvd_borr);
+ json_do_uint("eorr", p->stats.refresh_rcvd_eorr);
json_do_end();
json_do_end();
Index: bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
retrieving revision 1.413
diff -u -p -r1.413 bgpd.h
--- bgpd/bgpd.h 2 Mar 2021 09:45:07 -0000 1.413
+++ bgpd/bgpd.h 18 May 2021 08:41:54 -0000
@@ -352,17 +352,24 @@ struct capabilities {
int8_t mp[AID_MAX]; /* multiprotocol extensions, RFC 4760 */
int8_t refresh; /* route refresh, RFC 2918 */
int8_t as4byte; /* 4-byte ASnum, RFC 4893 */
+ int8_t enhanced_rr; /* enhanced route refresh, RFC 7313 */
+ int8_t add_path[AID_MAX]; /* ADD_PATH, RFC 7911 */
};
+/* flags for RFC4724 - graceful restart */
#define CAPA_GR_PRESENT 0x01
#define CAPA_GR_RESTART 0x02
#define CAPA_GR_FORWARD 0x04
#define CAPA_GR_RESTARTING 0x08
-
#define CAPA_GR_TIMEMASK 0x0fff
#define CAPA_GR_R_FLAG 0x8000
#define CAPA_GR_F_FLAG 0x80
+/* flags for RFC7911 - enhanced router refresh */
+#define CAPA_AP_RECV 0x01
+#define CAPA_AP_SEND 0x02
+#define CAPA_AP_BIDIR 0x03
+
struct peer_config {
struct bgpd_addr remote_addr;
struct bgpd_addr local_addr_v4;
@@ -595,7 +602,8 @@ enum err_codes {
ERR_UPDATE,
ERR_HOLDTIMEREXPIRED,
ERR_FSM,
- ERR_CEASE
+ ERR_CEASE,
+ ERR_RREFRESH
};
enum suberr_update {
@@ -626,6 +634,10 @@ enum suberr_cease {
ERR_CEASE_MAX_SENT_PREFIX
};
+enum suberr_rrefresh {
+ ERR_RR_INV_LEN = 1
+};
+
struct kroute_node;
struct kroute6_node;
struct knexthop_node;
@@ -713,6 +725,14 @@ struct session_up {
u_int16_t short_as;
};
+struct route_refresh {
+ u_int8_t aid;
+ u_int8_t subtype;
+};
+#define ROUTE_REFRESH_REQUEST 0
+#define ROUTE_REFRESH_BEGIN_RR 1
+#define ROUTE_REFRESH_END_RR 2
+
struct pftable_msg {
struct bgpd_addr addr;
char pftable[PFTABLE_LEN];
@@ -1457,7 +1477,8 @@ static const char * const errnames[] = {
"error in UPDATE message",
"HoldTimer expired",
"Finite State Machine error",
- "Cease"
+ "Cease",
+ "error in ROUTE-REFRESH message"
};
static const char * const suberr_header_names[] = {
@@ -1514,6 +1535,11 @@ static const char * const suberr_cease_n
"resource exhaustion",
"hard reset",
"sent max-prefix exceeded"
+};
+
+static const char * const suberr_rrefresh_names[] = {
+ "none",
+ "invalid message length"
};
static const char * const ctl_res_strerror[] = {
Index: bgpd/logmsg.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/logmsg.c,v
retrieving revision 1.4
diff -u -p -r1.4 logmsg.c
--- bgpd/logmsg.c 18 Feb 2019 09:43:57 -0000 1.4
+++ bgpd/logmsg.c 18 May 2021 08:41:54 -0000
@@ -176,6 +176,12 @@ log_notification(const struct peer *peer
else
suberrname = suberr_fsm_names[subcode];
break;
+ case ERR_RREFRESH:
+ if (subcode >= sizeof(suberr_rrefresh_names)/sizeof(char *))
+ uk = 1;
+ else
+ suberrname = suberr_rrefresh_names[subcode];
+ break;
default:
logit(LOG_ERR, "%s: %s notification, unknown errcode "
"%u, subcode %u", p, dir, errcode, subcode);
Index: bgpd/session.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.c,v
retrieving revision 1.415
diff -u -p -r1.415 session.c
--- bgpd/session.c 16 May 2021 09:09:11 -0000 1.415
+++ bgpd/session.c 18 May 2021 09:34:52 -0000
@@ -68,7 +68,7 @@ void session_tcp_established(struct peer
void session_capa_ann_none(struct peer *);
int session_capa_add(struct ibuf *, u_int8_t, u_int8_t);
int session_capa_add_mp(struct ibuf *, u_int8_t);
-int session_capa_add_gr(struct peer *, struct ibuf *, u_int8_t);
+int session_capa_add_afi(struct peer *, struct ibuf *, u_int8_t, u_int8_t);
struct bgp_msg *session_newmsg(enum msg_type, u_int16_t);
int session_sendmsg(struct bgp_msg *, struct peer *);
void session_open(struct peer *);
@@ -76,7 +76,7 @@ void session_keepalive(struct peer *);
void session_update(u_int32_t, void *, size_t);
void session_notification(struct peer *, u_int8_t, u_int8_t, void *,
ssize_t);
-void session_rrefresh(struct peer *, u_int8_t);
+void session_rrefresh(struct peer *, u_int8_t, u_int8_t);
int session_graceful_restart(struct peer *);
int session_graceful_stop(struct peer *);
int session_dispatch_msg(struct pollfd *, struct peer *);
@@ -84,7 +84,7 @@ void session_process_msg(struct peer *);
int parse_header(struct peer *, u_char *, u_int16_t *, u_int8_t *);
int parse_open(struct peer *);
int parse_update(struct peer *);
-int parse_refresh(struct peer *);
+int parse_rrefresh(struct peer *);
int parse_notification(struct peer *);
int parse_capabilities(struct peer *, u_char *, u_int16_t, u_int32_t *);
int capa_neg_calc(struct peer *);
@@ -1329,20 +1329,17 @@ session_capa_add_mp(struct ibuf *buf, u_
}
int
-session_capa_add_gr(struct peer *p, struct ibuf *b, u_int8_t aid)
+session_capa_add_afi(struct peer *p, struct ibuf *b, u_int8_t aid,
+ u_int8_t flags)
{
u_int errs = 0;
u_int16_t afi;
- u_int8_t flags, safi;
+ u_int8_t safi;
if (aid2afi(aid, &afi, &safi)) {
- log_warn("session_capa_add_gr: bad AID");
+ log_warn("session_capa_add_afi: bad AID");
return (1);
}
- if (p->capa.neg.grestart.flags[aid] & CAPA_GR_RESTARTING)
- flags = CAPA_GR_F_FLAG;
- else
- flags = 0;
afi = htons(afi);
errs += ibuf_add(b, &afi, sizeof(afi));
@@ -1445,6 +1442,7 @@ session_open(struct peer *p)
int rst = 0;
u_int16_t hdr;
u_int8_t grlen;
+ u_int8_t flags;
if (mpcapa) {
grlen = 2 + 4 * mpcapa;
@@ -1472,15 +1470,25 @@ session_open(struct peer *p)
if (mpcapa) {
for (i = 0; i < AID_MAX; i++) {
if (p->capa.ann.mp[i]) {
- errs += session_capa_add_gr(p, opb, i);
+ if (p->capa.neg.grestart.flags[i] &
+ CAPA_GR_RESTARTING)
+ flags = CAPA_GR_F_FLAG;
+ else
+ flags = 0;
+ errs += session_capa_add_afi(p, opb,
+ i, flags);
}
}
} else { /* AID_INET */
- errs += session_capa_add_gr(p, opb, AID_INET);
+ if (p->capa.neg.grestart.flags[i] & CAPA_GR_RESTARTING)
+ flags = CAPA_GR_F_FLAG;
+ else
+ flags = 0;
+ errs += session_capa_add_afi(p, opb, AID_INET, flags);
}
}
- /* 4-bytes AS numbers, draft-ietf-idr-as4bytes-13 */
+ /* 4-bytes AS numbers, RFC6793 */
if (p->capa.ann.as4byte) { /* 4 bytes data */
u_int32_t nas;
@@ -1489,6 +1497,32 @@ session_open(struct peer *p)
errs += ibuf_add(opb, &nas, sizeof(nas));
}
+ /* advertisement of multiple paths, RFC7911 */
+ if (p->capa.ann.add_path[0]) { /* variable */
+ u_int8_t aplen;
+
+ if (mpcapa)
+ aplen = 2 + 4 * mpcapa;
+ else /* AID_INET */
+ aplen = 2 + 4;
+ errs += session_capa_add(opb, CAPA_ADD_PATH, aplen);
+ if (mpcapa) {
+ for (i = AID_MIN; i < AID_MAX; i++) {
+ if (p->capa.ann.mp[i]) {
+ errs += session_capa_add_afi(p, opb,
+ i, p->capa.ann.add_path[i]);
+ }
+ }
+ } else { /* AID_INET */
+ errs += session_capa_add_afi(p, opb, AID_INET,
+ p->capa.ann.add_path[AID_INET]);
+ }
+ }
+
+ /* enhanced route-refresh, RFC6793 */
+ if (p->capa.ann.enhanced_rr) /* no data */
+ errs += session_capa_add(opb, CAPA_ENHANCED_RR, 0);
+
if (ibuf_size(opb))
optparamlen = ibuf_size(opb) + sizeof(op_type) +
sizeof(optparamlen);
@@ -1602,6 +1636,13 @@ session_notification(struct peer *p, u_i
log_notification(p, errcode, subcode, data, datalen, "sending");
+ /* cap to maximum size */
+ if (datalen > MAX_PKTSIZE - MSGSIZE_NOTIFICATION_MIN) {
+ log_peer_warnx(&p->conf,
+ "oversized notification, data trunkated");
+ datalen = MAX_PKTSIZE - MSGSIZE_NOTIFICATION_MIN;
+ }
+
if ((buf = session_newmsg(NOTIFICATION,
MSGSIZE_NOTIFICATION_MIN + datalen)) == NULL) {
bgp_fsm(p, EVNT_CON_FATAL);
@@ -1636,24 +1677,42 @@ session_neighbor_rrefresh(struct peer *p
{
u_int8_t i;
- if (!p->capa.neg.refresh)
+ if (!p->capa.neg.refresh && !p->capa.peer.enhanced_rr)
return (-1);
for (i = 0; i < AID_MAX; i++) {
if (p->capa.peer.mp[i] != 0)
- session_rrefresh(p, i);
+ session_rrefresh(p, i, ROUTE_REFRESH_REQUEST);
}
return (0);
}
void
-session_rrefresh(struct peer *p, u_int8_t aid)
+session_rrefresh(struct peer *p, u_int8_t aid, u_int8_t subtype)
{
struct bgp_msg *buf;
int errs = 0;
u_int16_t afi;
- u_int8_t safi, null8 = 0;
+ u_int8_t safi;
+
+ switch (subtype) {
+ case ROUTE_REFRESH_REQUEST:
+ p->stats.refresh_sent_req++;
+ break;
+ case ROUTE_REFRESH_BEGIN_RR:
+ case ROUTE_REFRESH_END_RR:
+ /* requires enhanced route refresh */
+ if (!p->capa.neg.enhanced_rr)
+ return;
+ if (subtype == ROUTE_REFRESH_BEGIN_RR)
+ p->stats.refresh_sent_borr++;
+ else
+ p->stats.refresh_sent_eorr++;
+ break;
+ default:
+ fatalx("session_rrefresh: bad subtype %d", subtype);
+ }
if (aid2afi(aid, &afi, &safi) == -1)
fatalx("session_rrefresh: bad afi/safi pair");
@@ -1665,7 +1724,7 @@ session_rrefresh(struct peer *p, u_int8_
afi = htons(afi);
errs += ibuf_add(buf->buf, &afi, sizeof(afi));
- errs += ibuf_add(buf->buf, &null8, sizeof(null8));
+ errs += ibuf_add(buf->buf, &subtype, sizeof(subtype));
errs += ibuf_add(buf->buf, &safi, sizeof(safi));
if (errs) {
@@ -1886,7 +1945,7 @@ session_process_msg(struct peer *p)
p->stats.msg_rcvd_keepalive++;
break;
case RREFRESH:
- parse_refresh(p);
+ parse_rrefresh(p);
p->stats.msg_rcvd_rrefresh++;
break;
default: /* cannot happen */
@@ -1987,7 +2046,7 @@ parse_header(struct peer *peer, u_char *
}
break;
case RREFRESH:
- if (*len != MSGSIZE_RREFRESH) {
+ if (*len < MSGSIZE_RREFRESH_MIN) {
log_peer_warnx(&peer->conf,
"received RREFRESH: illegal len: %u byte", *len);
session_notification(peer, ERR_HEADER, ERR_HDR_LEN,
@@ -2227,11 +2286,16 @@ parse_update(struct peer *peer)
}
int
-parse_refresh(struct peer *peer)
+parse_rrefresh(struct peer *peer)
{
- u_char *p;
- u_int16_t afi;
- u_int8_t aid, safi;
+ u_int16_t afi, datalen;
+ u_int8_t aid, safi, subtype;
+ u_char *p;
+
+ p = peer->rbuf->rptr;
+ p += MSGSIZE_HEADER_MARKER;
+ memcpy(&datalen, p, sizeof(datalen));
+ datalen = ntohs(datalen);
p = peer->rbuf->rptr;
p += MSGSIZE_HEADER; /* header is already checked */
@@ -2245,10 +2309,59 @@ parse_refresh(struct peer *peer)
memcpy(&afi, p, sizeof(afi));
afi = ntohs(afi);
p += 2;
- /* reserved, 1 byte */
+ /* subtype, 1 byte */
+ subtype = *p;
p += 1;
/* safi, 1 byte */
- memcpy(&safi, p, sizeof(safi));
+ safi = *p;
+
+ /* check subtype if peer announced enhanced route refresh */
+ if (peer->capa.neg.enhanced_rr) {
+ switch (subtype) {
+ case ROUTE_REFRESH_REQUEST:
+ /* no ORF support, so no oversized RREFRESH msgs */
+ if (datalen != MSGSIZE_RREFRESH) {
+ log_peer_warnx(&peer->conf,
+ "received RREFRESH: illegal len: %u byte",
+ datalen);
+ datalen = htons(datalen);
+ session_notification(peer, ERR_HEADER,
+ ERR_HDR_LEN, &datalen, sizeof(datalen));
+ bgp_fsm(peer, EVNT_CON_FATAL);
+ return (-1);
+ }
+ peer->stats.refresh_rcvd_req++;
+ break;
+ case ROUTE_REFRESH_BEGIN_RR:
+ case ROUTE_REFRESH_END_RR:
+ /* special handling for RFC7313 */
+ if (datalen != MSGSIZE_RREFRESH) {
+ log_peer_warnx(&peer->conf,
+ "received RREFRESH: illegal len: %u byte",
+ datalen);
+ p = peer->rbuf->rptr;
+ p += MSGSIZE_HEADER;
+ datalen -= MSGSIZE_HEADER;
+ session_notification(peer, ERR_RREFRESH,
+ ERR_RR_INV_LEN, p, datalen);
+ bgp_fsm(peer, EVNT_CON_FATAL);
+ return (-1);
+ }
+ if (subtype == ROUTE_REFRESH_BEGIN_RR)
+ peer->stats.refresh_rcvd_borr++;
+ else
+ peer->stats.refresh_rcvd_eorr++;
+ break;
+ default:
+ log_peer_warnx(&peer->conf, "peer sent bad refresh, "
+ "bad subtype %d", subtype);
+ return (0);
+ }
+ } else {
+ /* force subtype to default */
+ subtype = ROUTE_REFRESH_REQUEST;
+ peer->stats.refresh_rcvd_req++;
+ }
/* afi/safi unchecked - unrecognized values will be ignored anyway */
if (afi2aid(afi, safi, &aid) == -1) {
@@ -2257,7 +2370,7 @@ parse_refresh(struct peer *peer)
return (0);
}
- if (!peer->capa.neg.refresh) {
+ if (!peer->capa.neg.refresh && !peer->capa.neg.enhanced_rr) {
log_peer_warnx(&peer->conf, "peer sent unexpected refresh");
return (0);
}
@@ -2355,6 +2468,18 @@ parse_notification(struct peer *peer)
log_peer_warnx(&peer->conf,
"disabling 4-byte AS num capability");
break;
+ case CAPA_ADD_PATH:
+ memset(peer->capa.ann.add_path, 0,
+ sizeof(peer->capa.ann.add_path));
+ log_peer_warnx(&peer->conf,
+ "disabling ADD-PATH capability");
+ break;
+ case CAPA_ENHANCED_RR:
+ peer->capa.ann.enhanced_rr = 0;
+ log_peer_warnx(&peer->conf,
+ "disabling enhanced route refresh "
+ "capability");
+ break;
default: /* should not happen... */
log_peer_warnx(&peer->conf, "received "
"\"unsupported capability\" notification "
@@ -2413,7 +2538,7 @@ parse_capabilities(struct peer *peer, u_
u_int16_t gr_header;
u_int8_t safi;
u_int8_t aid;
- u_int8_t gr_flags;
+ u_int8_t flags;
u_int8_t capa_code;
u_int8_t capa_len;
u_int8_t i;
@@ -2497,7 +2622,8 @@ parse_capabilities(struct peer *peer, u_
for (i = 2; i <= capa_len - 4; i += 4) {
memcpy(&afi, capa_val + i, sizeof(afi));
afi = ntohs(afi);
- memcpy(&safi, capa_val + i + 2, sizeof(safi));
+ safi = capa_val[i + 2];
+ flags = capa_val[i + 3];
if (afi2aid(afi, safi, &aid) == -1) {
log_peer_warnx(&peer->conf,
"Received graceful restart capa: "
@@ -2505,11 +2631,9 @@ parse_capabilities(struct peer *peer, u_
afi, safi);
continue;
}
- memcpy(&gr_flags, capa_val + i + 3,
- sizeof(gr_flags));
peer->capa.peer.grestart.flags[aid] |=
CAPA_GR_PRESENT;
- if (gr_flags & CAPA_GR_F_FLAG)
+ if (flags & CAPA_GR_F_FLAG)
peer->capa.peer.grestart.flags[aid] |=
CAPA_GR_FORWARD;
if (gr_header & CAPA_GR_R_FLAG)
@@ -2538,6 +2662,43 @@ parse_capabilities(struct peer *peer, u_
}
peer->capa.peer.as4byte = 1;
break;
+ case CAPA_ADD_PATH:
+ if (capa_len % 4 != 0) {
+ log_peer_warnx(&peer->conf,
+ "Bad ADD-PATH capability length: "
+ "%u", capa_len);
+ memset(peer->capa.peer.add_path, 0,
+ sizeof(peer->capa.peer.add_path));
+ break;
+ }
+ for (i = 0; i <= capa_len - 4; i += 4) {
+ memcpy(&afi, capa_val + i, sizeof(afi));
+ afi = ntohs(afi);
+ safi = capa_val[i + 2];
+ flags = capa_val[i + 3];
+ if (afi2aid(afi, safi, &aid) == -1) {
+ log_peer_warnx(&peer->conf,
+ "Received ADD-PATH capa: "
+ " unknown AFI %u, safi %u pair",
+ afi, safi);
+ memset(peer->capa.peer.add_path, 0,
+ sizeof(peer->capa.peer.add_path));
+ break;
+ }
+ if (flags & ~CAPA_AP_BIDIR) {
+ log_peer_warnx(&peer->conf,
+ "Received ADD-PATH capa: "
+ " bad flags %x", flags);
+ memset(peer->capa.peer.add_path, 0,
+ sizeof(peer->capa.peer.add_path));
+ break;
+ }
+ peer->capa.peer.add_path[aid] = flags;
+ }
+ break;
+ case CAPA_ENHANCED_RR:
+ peer->capa.peer.enhanced_rr = 1;
+ break;
default:
break;
}
@@ -2555,6 +2716,8 @@ capa_neg_calc(struct peer *p)
p->capa.neg.refresh =
(p->capa.ann.refresh && p->capa.peer.refresh) != 0;
+ p->capa.neg.enhanced_rr =
+ (p->capa.ann.enhanced_rr && p->capa.peer.enhanced_rr) != 0;
p->capa.neg.as4byte =
(p->capa.ann.as4byte && p->capa.peer.as4byte) != 0;
@@ -2585,30 +2748,49 @@ capa_neg_calc(struct peer *p)
int8_t negflags;
/* disable GR if the AFI/SAFI is not present */
- if (p->capa.ann.grestart.restart == 0 ||
- (p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT &&
+ if ((p->capa.peer.grestart.flags[i] & CAPA_GR_PRESENT &&
p->capa.neg.mp[i] == 0))
p->capa.peer.grestart.flags[i] = 0; /* disable */
/* look at current GR state and decide what to do */
negflags = p->capa.neg.grestart.flags[i];
p->capa.neg.grestart.flags[i] = p->capa.peer.grestart.flags[i];
if (negflags & CAPA_GR_RESTARTING) {
- if (!(p->capa.peer.grestart.flags[i] &
- CAPA_GR_FORWARD)) {
+ if (p->capa.ann.grestart.restart != 0 &&
+ p->capa.peer.grestart.flags[i] & CAPA_GR_FORWARD) {
+ p->capa.neg.grestart.flags[i] |=
+ CAPA_GR_RESTARTING;
+ } else {
if (imsg_rde(IMSG_SESSION_FLUSH, p->conf.id,
&i, sizeof(i)) == -1)
return (-1);
log_peer_warnx(&p->conf, "graceful restart of "
"%s, not restarted, flushing", aid2str(i));
- } else
- p->capa.neg.grestart.flags[i] |=
- CAPA_GR_RESTARTING;
+ }
}
}
p->capa.neg.grestart.timeout = p->capa.peer.grestart.timeout;
p->capa.neg.grestart.restart = p->capa.peer.grestart.restart;
if (p->capa.ann.grestart.restart == 0)
p->capa.neg.grestart.restart = 0;
+
+
+ /*
+ * ADD-PATH: set only those bits where both sides agree.
+ * For this compare our send bit with the recv bit from the peer
+ * and vice versa.
+ * The flags are stored from this systems view point.
+ */
+ memset(p->capa.neg.add_path, 0, sizeof(p->capa.neg.add_path));
+ if (p->capa.ann.add_path[0]) {
+ for (i = AID_MIN; i < AID_MAX; i++) {
+ if ((p->capa.ann.add_path[i] & CAPA_AP_RECV) &&
+ (p->capa.peer.add_path[i] & CAPA_AP_SEND))
+ p->capa.neg.add_path[i] |= CAPA_AP_RECV;
+ if ((p->capa.ann.add_path[i] & CAPA_AP_SEND) &&
+ (p->capa.peer.add_path[i] & CAPA_AP_RECV))
+ p->capa.neg.add_path[i] |= CAPA_AP_SEND;
+ }
+ }
return (0);
}
Index: bgpd/session.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.h,v
retrieving revision 1.150
diff -u -p -r1.150 session.h
--- bgpd/session.h 16 Feb 2021 08:29:16 -0000 1.150
+++ bgpd/session.h 18 May 2021 08:41:54 -0000
@@ -34,7 +34,8 @@
#define MSGSIZE_OPEN_MIN 29
#define MSGSIZE_UPDATE_MIN 23
#define MSGSIZE_KEEPALIVE MSGSIZE_HEADER
-#define MSGSIZE_RREFRESH MSGSIZE_HEADER + 4
+#define MSGSIZE_RREFRESH (MSGSIZE_HEADER + 4)
+#define MSGSIZE_RREFRESH_MIN MSGSIZE_RREFRESH
#define MSG_PROCESS_LIMIT 25
#define SESSION_CLEAR_DELAY 5
@@ -106,11 +107,13 @@ enum opt_params {
};
enum capa_codes {
- CAPA_NONE,
- CAPA_MP,
- CAPA_REFRESH,
+ CAPA_NONE = 0,
+ CAPA_MP = 1,
+ CAPA_REFRESH = 2,
CAPA_RESTART = 64,
- CAPA_AS4BYTE = 65
+ CAPA_AS4BYTE = 65,
+ CAPA_ADD_PATH = 69,
+ CAPA_ENHANCED_RR = 70,
};
struct bgp_msg {
@@ -158,6 +161,12 @@ struct peer_stats {
unsigned long long msg_sent_notification;
unsigned long long msg_sent_keepalive;
unsigned long long msg_sent_rrefresh;
+ unsigned long long refresh_rcvd_req;
+ unsigned long long refresh_rcvd_borr;
+ unsigned long long refresh_rcvd_eorr;
+ unsigned long long refresh_sent_req;
+ unsigned long long refresh_sent_borr;
+ unsigned long long refresh_sent_eorr;
unsigned long long prefix_rcvd_update;
unsigned long long prefix_rcvd_withdraw;
unsigned long long prefix_rcvd_eor;