summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/bgpd/bgpd.conf.515
-rw-r--r--usr.sbin/bgpd/bgpd.h6
-rw-r--r--usr.sbin/bgpd/parse.y18
-rw-r--r--usr.sbin/bgpd/rde.c179
-rw-r--r--usr.sbin/bgpd/rde.h14
-rw-r--r--usr.sbin/bgpd/rde_decide.c9
-rw-r--r--usr.sbin/bgpd/rde_peer.c14
-rw-r--r--usr.sbin/bgpd/rde_rib.c44
-rw-r--r--usr.sbin/bgpd/rde_update.c11
9 files changed, 229 insertions, 81 deletions
diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5
index 65672160ebd..6ee7bc244b3 100644
--- a/usr.sbin/bgpd/bgpd.conf.5
+++ b/usr.sbin/bgpd/bgpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.conf.5,v 1.212 2021/07/13 08:44:18 claudio Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.213 2021/08/09 08:15:34 claudio Exp $
.\"
.\" Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
.\" Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -16,7 +16,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: July 13 2021 $
+.Dd $Mdocdate: August 9 2021 $
.Dt BGPD.CONF 5
.Os
.Sh NAME
@@ -809,6 +809,17 @@ The default is
for the same address family of the session.
.Pp
.It Xo
+.Ic announce add-path recv
+.Pq Ic yes Ns | Ns Ic no
+.Xc
+If set to
+.Ic yes ,
+the receive add-path capability is announced which allows reception of multiple
+paths per prefix.
+The default is
+.Ic no .
+.Pp
+.It Xo
.Ic announce as-4byte
.Pq Ic yes Ns | Ns Ic no
.Xc
diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h
index 4c0952d5829..e897e077c36 100644
--- a/usr.sbin/bgpd/bgpd.h
+++ b/usr.sbin/bgpd/bgpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: bgpd.h,v 1.416 2021/07/27 07:32:08 claudio Exp $ */
+/* $OpenBSD: bgpd.h,v 1.417 2021/08/09 08:15:34 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -95,6 +95,7 @@
#define F_CTL_OVS_INVALID 0x100000
#define F_CTL_OVS_NOTFOUND 0x200000
#define F_CTL_NEIGHBORS 0x400000 /* only used by bgpctl */
+#define F_CTL_HAS_PATHID 0x800000 /* only set on requests */
#define CTASSERT(x) extern char _ctassert[(x) ? 1 : -1 ] \
__attribute__((__unused__))
@@ -891,9 +892,10 @@ struct ctl_show_rib_request {
struct filter_as as;
struct community community;
u_int32_t flags;
- u_int8_t validation_state;
+ u_int32_t path_id;
pid_t pid;
enum imsg_type type;
+ u_int8_t validation_state;
u_int8_t prefixlen;
u_int8_t aid;
};
diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y
index 82ea2289875..37f1862c922 100644
--- a/usr.sbin/bgpd/parse.y
+++ b/usr.sbin/bgpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.417 2021/06/17 16:05:26 claudio Exp $ */
+/* $OpenBSD: parse.y,v 1.418 2021/08/09 08:15:34 claudio Exp $ */
/*
* Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -204,7 +204,8 @@ typedef struct {
%token GROUP NEIGHBOR NETWORK
%token EBGP IBGP
%token LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART
-%token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY ENHANCED
+%token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY ENHANCED ADDPATH
+%token SEND RECV
%token DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN
%token DUMP IN OUT SOCKET RESTRICTED
%token LOG TRANSPARENT
@@ -1455,6 +1456,16 @@ peeropts : REMOTEAS as4number {
| ANNOUNCE AS4BYTE yesno {
curpeer->conf.capabilities.as4byte = $3;
}
+ | ANNOUNCE ADDPATH RECV yesno {
+ int8_t *ap = curpeer->conf.capabilities.add_path;
+ u_int8_t i;
+
+ for (i = 0; i < AID_MAX; i++)
+ if ($4)
+ *ap++ |= CAPA_AP_RECV;
+ else
+ *ap++ &= ~CAPA_AP_RECV;
+ }
| EXPORT NONE {
curpeer->conf.export_type = EXPORT_NONE;
}
@@ -2878,6 +2889,7 @@ lookup(char *s)
{ "AS", AS},
{ "IPv4", IPV4},
{ "IPv6", IPV6},
+ { "add-path", ADDPATH},
{ "ah", AH},
{ "allow", ALLOW},
{ "announce", ANNOUNCE},
@@ -2965,6 +2977,7 @@ lookup(char *s)
{ "quick", QUICK},
{ "rd", RD},
{ "rde", RDE},
+ { "recv", RECV},
{ "refresh", REFRESH },
{ "reject", REJECT},
{ "remote-as", REMOTEAS},
@@ -2978,6 +2991,7 @@ lookup(char *s)
{ "rtlabel", RTLABEL},
{ "rtr", RTR},
{ "self", SELF},
+ { "send", SEND},
{ "set", SET},
{ "socket", SOCKET },
{ "source-as", SOURCEAS},
diff --git a/usr.sbin/bgpd/rde.c b/usr.sbin/bgpd/rde.c
index 24dc6716f65..65696e253e2 100644
--- a/usr.sbin/bgpd/rde.c
+++ b/usr.sbin/bgpd/rde.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.c,v 1.531 2021/07/27 07:50:01 claudio Exp $ */
+/* $OpenBSD: rde.c,v 1.532 2021/08/09 08:15:34 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -50,10 +50,10 @@ void rde_dispatch_imsg_parent(struct imsgbuf *);
void rde_dispatch_imsg_rtr(struct imsgbuf *);
void rde_dispatch_imsg_peer(struct rde_peer *, void *);
void rde_update_dispatch(struct rde_peer *, struct imsg *);
-int rde_update_update(struct rde_peer *, struct filterstate *,
+int rde_update_update(struct rde_peer *, u_int32_t,
+ struct filterstate *, struct bgpd_addr *, u_int8_t);
+void rde_update_withdraw(struct rde_peer *, u_int32_t,
struct bgpd_addr *, u_int8_t);
-void rde_update_withdraw(struct rde_peer *, struct bgpd_addr *,
- u_int8_t);
int rde_attr_parse(u_char *, u_int16_t, struct rde_peer *,
struct filterstate *, struct mpattr *);
int rde_attr_add(struct filterstate *, u_char *, u_int16_t);
@@ -1183,7 +1183,7 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
u_int16_t attrpath_len;
u_int16_t nlri_len;
u_int8_t aid, prefixlen, safi, subtype;
- u_int32_t fas;
+ u_int32_t fas, pathid;
p = imsg->data;
@@ -1288,6 +1288,21 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
goto done;
}
+ if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
+ if (len <= sizeof(pathid)) {
+ log_peer_warnx(&peer->conf,
+ "bad withdraw prefix");
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_NETWORK, NULL, 0);
+ goto done;
+ }
+ memcpy(&pathid, p, sizeof(pathid));
+ pathid = ntohl(pathid);
+ p += sizeof(pathid);
+ len -= sizeof(pathid);
+ } else
+ pathid = 0;
+
if ((pos = nlri_get_prefix(p, len, &prefix,
&prefixlen)) == -1) {
/*
@@ -1302,7 +1317,7 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
p += pos;
len -= pos;
- rde_update_withdraw(peer, &prefix, prefixlen);
+ rde_update_withdraw(peer, pathid, &prefix, prefixlen);
}
/* withdraw MP_UNREACH_NLRI if available */
@@ -1339,6 +1354,23 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
}
while (mplen > 0) {
+ if (peer_has_add_path(peer, aid, CAPA_AP_RECV)) {
+ if (mplen <= sizeof(pathid)) {
+ log_peer_warnx(&peer->conf,
+ "bad %s withdraw prefix",
+ aid2str(aid));
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpa.unreach, mpa.unreach_len);
+ goto done;
+ }
+ memcpy(&pathid, mpp, sizeof(pathid));
+ pathid = ntohl(pathid);
+ mpp += sizeof(pathid);
+ mplen -= sizeof(pathid);
+ } else
+ pathid = 0;
+
switch (aid) {
case AID_INET6:
if ((pos = nlri_get_prefix6(mpp, mplen,
@@ -1381,7 +1413,7 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
mpp += pos;
mplen -= pos;
- rde_update_withdraw(peer, &prefix, prefixlen);
+ rde_update_withdraw(peer, pathid, &prefix, prefixlen);
}
if ((state.aspath.flags & ~F_ATTR_MP_UNREACH) == 0)
@@ -1401,6 +1433,21 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
goto done;
}
+ if (peer_has_add_path(peer, AID_INET, CAPA_AP_RECV)) {
+ if (nlri_len <= sizeof(pathid)) {
+ log_peer_warnx(&peer->conf,
+ "bad nlri prefix");
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_NETWORK, NULL, 0);
+ goto done;
+ }
+ memcpy(&pathid, p, sizeof(pathid));
+ pathid = ntohl(pathid);
+ p += sizeof(pathid);
+ nlri_len -= sizeof(pathid);
+ } else
+ pathid = 0;
+
if ((pos = nlri_get_prefix(p, nlri_len, &prefix,
&prefixlen)) == -1) {
log_peer_warnx(&peer->conf, "bad nlri prefix");
@@ -1411,7 +1458,8 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
p += pos;
nlri_len -= pos;
- if (rde_update_update(peer, &state, &prefix, prefixlen) == -1)
+ if (rde_update_update(peer, pathid, &state,
+ &prefix, prefixlen) == -1)
goto done;
}
@@ -1456,6 +1504,22 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
mplen -= pos;
while (mplen > 0) {
+ if (peer_has_add_path(peer, aid, CAPA_AP_RECV)) {
+ if (mplen <= sizeof(pathid)) {
+ log_peer_warnx(&peer->conf,
+ "bad %s nlri prefix", aid2str(aid));
+ rde_update_err(peer, ERR_UPDATE,
+ ERR_UPD_OPTATTR,
+ mpa.reach, mpa.reach_len);
+ goto done;
+ }
+ memcpy(&pathid, mpp, sizeof(pathid));
+ pathid = ntohl(pathid);
+ mpp += sizeof(pathid);
+ mplen -= sizeof(pathid);
+ } else
+ pathid = 0;
+
switch (aid) {
case AID_INET6:
if ((pos = nlri_get_prefix6(mpp, mplen,
@@ -1498,7 +1562,7 @@ rde_update_dispatch(struct rde_peer *peer, struct imsg *imsg)
mpp += pos;
mplen -= pos;
- if (rde_update_update(peer, &state,
+ if (rde_update_update(peer, pathid, &state,
&prefix, prefixlen) == -1)
goto done;
}
@@ -1509,8 +1573,8 @@ done:
}
int
-rde_update_update(struct rde_peer *peer, struct filterstate *in,
- struct bgpd_addr *prefix, u_int8_t prefixlen)
+rde_update_update(struct rde_peer *peer, u_int32_t path_id,
+ struct filterstate *in, struct bgpd_addr *prefix, u_int8_t prefixlen)
{
struct filterstate state;
enum filter_actions action;
@@ -1523,8 +1587,8 @@ rde_update_update(struct rde_peer *peer, struct filterstate *in,
aspath_origin(in->aspath.aspath));
/* add original path to the Adj-RIB-In */
- if (prefix_update(rib_byid(RIB_ADJ_IN), peer, in, prefix, prefixlen,
- vstate) == 1)
+ if (prefix_update(rib_byid(RIB_ADJ_IN), peer, path_id, in,
+ prefix, prefixlen, vstate) == 1)
peer->prefix_cnt++;
/* max prefix checker */
@@ -1552,9 +1616,9 @@ rde_update_update(struct rde_peer *peer, struct filterstate *in,
rde_update_log("update", i, peer,
&state.nexthop->exit_nexthop, prefix,
prefixlen);
- prefix_update(rib, peer, &state, prefix,
+ prefix_update(rib, peer, path_id, &state, prefix,
prefixlen, vstate);
- } else if (prefix_withdraw(rib, peer, prefix,
+ } else if (prefix_withdraw(rib, peer, path_id, prefix,
prefixlen)) {
rde_update_log(wmsg, i, peer,
NULL, prefix, prefixlen);
@@ -1567,8 +1631,8 @@ rde_update_update(struct rde_peer *peer, struct filterstate *in,
}
void
-rde_update_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix,
- u_int8_t prefixlen)
+rde_update_withdraw(struct rde_peer *peer, u_int32_t path_id,
+ struct bgpd_addr *prefix, u_int8_t prefixlen)
{
u_int16_t i;
@@ -1576,13 +1640,14 @@ rde_update_withdraw(struct rde_peer *peer, struct bgpd_addr *prefix,
struct rib *rib = rib_byid(i);
if (rib == NULL)
continue;
- if (prefix_withdraw(rib, peer, prefix, prefixlen))
+ if (prefix_withdraw(rib, peer, path_id, prefix, prefixlen))
rde_update_log("withdraw", i, peer, NULL, prefix,
prefixlen);
}
/* remove original path form the Adj-RIB-In */
- if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peer, prefix, prefixlen))
+ if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peer, path_id,
+ prefix, prefixlen))
peer->prefix_cnt--;
peer->prefix_rcvd_withdraw++;
@@ -2292,28 +2357,31 @@ rde_reflector(struct rde_peer *peer, struct rde_aspath *asp)
* control specific functions
*/
static void
-rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
+rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags,
+ int adjout)
{
struct ctl_show_rib rib;
struct ibuf *wbuf;
struct attr *a;
struct nexthop *nexthop;
struct rib_entry *re;
+ struct rde_peer *peer;
void *bp;
time_t staletime;
size_t aslen;
u_int8_t l;
nexthop = prefix_nexthop(p);
+ peer = prefix_peer(p);
bzero(&rib, sizeof(rib));
rib.age = getmonotime() - p->lastchange;
rib.local_pref = asp->lpref;
rib.med = asp->med;
rib.weight = asp->weight;
- strlcpy(rib.descr, prefix_peer(p)->conf.descr, sizeof(rib.descr));
- memcpy(&rib.remote_addr, &prefix_peer(p)->remote_addr,
+ strlcpy(rib.descr, peer->conf.descr, sizeof(rib.descr));
+ memcpy(&rib.remote_addr, &peer->remote_addr,
sizeof(rib.remote_addr));
- rib.remote_id = prefix_peer(p)->remote_bgpid;
+ rib.remote_id = peer->remote_bgpid;
if (nexthop != NULL) {
memcpy(&rib.true_nexthop, &nexthop->true_nexthop,
sizeof(rib.true_nexthop));
@@ -2334,7 +2402,7 @@ rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
re = prefix_re(p);
if (re != NULL && re->active == p)
rib.flags |= F_PREF_ACTIVE;
- if (!prefix_peer(p)->conf.ebgp)
+ if (!peer->conf.ebgp)
rib.flags |= F_PREF_INTERNAL;
if (asp->flags & F_PREFIX_ANNOUNCED)
rib.flags |= F_PREF_ANNOUNCE;
@@ -2344,9 +2412,20 @@ rde_dump_rib_as(struct prefix *p, struct rde_aspath *asp, pid_t pid, int flags)
rib.flags &= ~F_PREF_ELIGIBLE;
if (asp->flags & F_ATTR_PARSE_ERR)
rib.flags |= F_PREF_INVALID;
- staletime = prefix_peer(p)->staletime[p->pt->aid];
+ staletime = peer->staletime[p->pt->aid];
if (staletime && p->lastchange <= staletime)
rib.flags |= F_PREF_STALE;
+ if (!adjout) {
+ if (peer_has_add_path(peer, p->pt->aid, CAPA_AP_RECV)) {
+ rib.path_id = p->path_id;
+ rib.flags |= F_PREF_PATH_ID;
+ }
+ } else {
+ if (peer_has_add_path(peer, p->pt->aid, CAPA_AP_SEND)) {
+ rib.path_id = 0; /* XXX add-path send */
+ rib.flags |= F_PREF_PATH_ID;
+ }
+ }
aslen = aspath_length(asp->aspath);
if ((wbuf = imsg_create(ibuf_se_ctl, IMSG_CTL_SHOW_RIB, 0, pid,
@@ -2411,7 +2490,7 @@ rde_match_peer(struct rde_peer *p, struct ctl_neighbor *n)
}
static void
-rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
+rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req, int adjout)
{
struct rde_aspath *asp;
struct rib_entry *re;
@@ -2428,6 +2507,12 @@ rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
if ((req->flags & F_CTL_INVALID) &&
(asp->flags & F_ATTR_PARSE_ERR) == 0)
return;
+ /*
+ * XXX handle out specially since then we want to match against our
+ * path ids.
+ */
+ if ((req->flags & F_CTL_HAS_PATHID) && req->path_id != p->path_id)
+ return;
if (req->as.type != AS_UNDEF &&
!aspath_match(asp->aspath, &req->as, 0))
return;
@@ -2438,7 +2523,7 @@ rde_dump_filter(struct prefix *p, struct ctl_show_rib_request *req)
}
if (!ovs_match(p, req->flags))
return;
- rde_dump_rib_as(p, asp, req->pid, req->flags);
+ rde_dump_rib_as(p, asp, req->pid, req->flags, adjout);
}
static void
@@ -2448,7 +2533,7 @@ rde_dump_upcall(struct rib_entry *re, void *ptr)
struct prefix *p;
LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
- rde_dump_filter(p, &ctx->req);
+ rde_dump_filter(p, &ctx->req, 0);
}
static void
@@ -2469,14 +2554,14 @@ rde_dump_prefix_upcall(struct rib_entry *re, void *ptr)
if (!prefix_compare(&ctx->req.prefix, &addr,
ctx->req.prefixlen))
LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
- rde_dump_filter(p, &ctx->req);
+ rde_dump_filter(p, &ctx->req, 0);
} else {
if (ctx->req.prefixlen < pt->prefixlen)
return;
if (!prefix_compare(&addr, &ctx->req.prefix,
pt->prefixlen))
LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
- rde_dump_filter(p, &ctx->req);
+ rde_dump_filter(p, &ctx->req, 0);
}
}
@@ -2487,7 +2572,7 @@ rde_dump_adjout_upcall(struct prefix *p, void *ptr)
if (p->flags & (PREFIX_FLAG_WITHDRAW | PREFIX_FLAG_DEAD))
return;
- rde_dump_filter(p, &ctx->req);
+ rde_dump_filter(p, &ctx->req, 1);
}
static void
@@ -2507,13 +2592,13 @@ rde_dump_adjout_prefix_upcall(struct prefix *p, void *ptr)
return;
if (!prefix_compare(&ctx->req.prefix, &addr,
ctx->req.prefixlen))
- rde_dump_filter(p, &ctx->req);
+ rde_dump_filter(p, &ctx->req, 1);
} else {
if (ctx->req.prefixlen < p->pt->prefixlen)
return;
if (!prefix_compare(&addr, &ctx->req.prefix,
p->pt->prefixlen))
- rde_dump_filter(p, &ctx->req);
+ rde_dump_filter(p, &ctx->req, 1);
}
}
@@ -3580,11 +3665,12 @@ rde_softreconfig_in(struct rib_entry *re, void *bula)
if (action == ACTION_ALLOW) {
/* update Local-RIB */
- prefix_update(rib, peer, &state, &prefix,
- pt->prefixlen, p->validation_state);
+ prefix_update(rib, peer, p->path_id, &state,
+ &prefix, pt->prefixlen,
+ p->validation_state);
} else if (action == ACTION_DENY) {
/* remove from Local-RIB */
- prefix_withdraw(rib, peer, &prefix,
+ prefix_withdraw(rib, peer, p->path_id, &prefix,
pt->prefixlen);
}
@@ -3724,11 +3810,12 @@ rde_roa_softreload(struct rib_entry *re, void *bula)
if (action == ACTION_ALLOW) {
/* update Local-RIB */
- prefix_update(rib, peer, &state, &prefix,
- pt->prefixlen, p->validation_state);
+ prefix_update(rib, peer, p->path_id, &state,
+ &prefix, pt->prefixlen,
+ p->validation_state);
} else if (action == ACTION_DENY) {
/* remove from Local-RIB */
- prefix_withdraw(rib, peer, &prefix,
+ prefix_withdraw(rib, peer, p->path_id, &prefix,
pt->prefixlen);
}
@@ -3952,7 +4039,7 @@ network_add(struct network_config *nc, struct filterstate *state)
vstate = rde_roa_validity(&rde_roa, &nc->prefix,
nc->prefixlen, aspath_origin(state->aspath.aspath));
- if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, state, &nc->prefix,
+ if (prefix_update(rib_byid(RIB_ADJ_IN), peerself, 0, state, &nc->prefix,
nc->prefixlen, vstate) == 1)
peerself->prefix_cnt++;
for (i = RIB_LOC_START; i < rib_size; i++) {
@@ -3962,7 +4049,7 @@ network_add(struct network_config *nc, struct filterstate *state)
rde_update_log("announce", i, peerself,
state->nexthop ? &state->nexthop->exit_nexthop : NULL,
&nc->prefix, nc->prefixlen);
- prefix_update(rib, peerself, state, &nc->prefix,
+ prefix_update(rib, peerself, 0, state, &nc->prefix,
nc->prefixlen, vstate);
}
filterset_free(&nc->attrset);
@@ -4022,12 +4109,12 @@ network_delete(struct network_config *nc)
struct rib *rib = rib_byid(i);
if (rib == NULL)
continue;
- if (prefix_withdraw(rib, peerself, &nc->prefix,
+ if (prefix_withdraw(rib, peerself, 0, &nc->prefix,
nc->prefixlen))
rde_update_log("withdraw announce", i, peerself,
NULL, &nc->prefix, nc->prefixlen);
}
- if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, &nc->prefix,
+ if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, 0, &nc->prefix,
nc->prefixlen))
peerself->prefix_cnt--;
}
@@ -4074,7 +4161,7 @@ network_flush_upcall(struct rib_entry *re, void *ptr)
u_int32_t i;
u_int8_t prefixlen;
- p = prefix_bypeer(re, peerself);
+ p = prefix_bypeer(re, peerself, 0);
if (p == NULL)
return;
if ((prefix_aspath(p)->flags & F_ANN_DYNAMIC) != F_ANN_DYNAMIC)
@@ -4087,12 +4174,12 @@ network_flush_upcall(struct rib_entry *re, void *ptr)
struct rib *rib = rib_byid(i);
if (rib == NULL)
continue;
- if (prefix_withdraw(rib, peerself, &addr, prefixlen) == 1)
+ if (prefix_withdraw(rib, peerself, 0, &addr, prefixlen) == 1)
rde_update_log("flush announce", i, peerself,
NULL, &addr, prefixlen);
}
- if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, &addr,
+ if (prefix_withdraw(rib_byid(RIB_ADJ_IN), peerself, 0, &addr,
prefixlen) == 1)
peerself->prefix_cnt--;
}
diff --git a/usr.sbin/bgpd/rde.h b/usr.sbin/bgpd/rde.h
index 6088026030f..54f718d2b73 100644
--- a/usr.sbin/bgpd/rde.h
+++ b/usr.sbin/bgpd/rde.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde.h,v 1.241 2021/07/27 07:50:02 claudio Exp $ */
+/* $OpenBSD: rde.h,v 1.242 2021/08/09 08:15:34 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org> and
@@ -329,6 +329,8 @@ struct prefix {
struct rde_peer *peer;
struct nexthop *nexthop; /* may be NULL */
time_t lastchange;
+ u_int32_t path_id;
+ u_int32_t path_id_tx;
u_int8_t validation_state;
u_int8_t nhflags;
u_int8_t eor;
@@ -386,6 +388,7 @@ int rde_match_peer(struct rde_peer *, struct ctl_neighbor *);
/* rde_peer.c */
int peer_has_as4byte(struct rde_peer *);
+int peer_has_add_path(struct rde_peer *, u_int8_t, int);
int peer_accept_no_as_set(struct rde_peer *);
void peer_init(u_int32_t);
void peer_shutdown(void);
@@ -577,13 +580,13 @@ void path_clean(struct rde_aspath *);
void path_put(struct rde_aspath *);
#define PREFIX_SIZE(x) (((x) + 7) / 8 + 1)
-struct prefix *prefix_get(struct rib *, struct rde_peer *,
+struct prefix *prefix_get(struct rib *, struct rde_peer *, u_int32_t,
struct bgpd_addr *, int);
struct prefix *prefix_lookup(struct rde_peer *, struct bgpd_addr *, int);
struct prefix *prefix_match(struct rde_peer *, struct bgpd_addr *);
-int prefix_update(struct rib *, struct rde_peer *,
+int prefix_update(struct rib *, struct rde_peer *, u_int32_t,
struct filterstate *, struct bgpd_addr *, int, u_int8_t);
-int prefix_withdraw(struct rib *, struct rde_peer *,
+int prefix_withdraw(struct rib *, struct rde_peer *, u_int32_t,
struct bgpd_addr *, int);
void prefix_add_eor(struct rde_peer *, u_int8_t);
int prefix_adjout_update(struct rde_peer *, struct filterstate *,
@@ -598,7 +601,8 @@ int prefix_dump_new(struct rde_peer *, u_int8_t, unsigned int,
void (*)(void *, u_int8_t), int (*)(void *));
int prefix_write(u_char *, int, struct bgpd_addr *, u_int8_t, int);
int prefix_writebuf(struct ibuf *, struct bgpd_addr *, u_int8_t);
-struct prefix *prefix_bypeer(struct rib_entry *, struct rde_peer *);
+struct prefix *prefix_bypeer(struct rib_entry *, struct rde_peer *,
+ u_int32_t);
void prefix_destroy(struct prefix *);
void prefix_relink(struct prefix *, struct rde_aspath *, int);
diff --git a/usr.sbin/bgpd/rde_decide.c b/usr.sbin/bgpd/rde_decide.c
index d071beb83bc..f77f615030a 100644
--- a/usr.sbin/bgpd/rde_decide.c
+++ b/usr.sbin/bgpd/rde_decide.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_decide.c,v 1.85 2021/05/04 09:21:05 claudio Exp $ */
+/* $OpenBSD: rde_decide.c,v 1.86 2021/08/09 08:15:34 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -281,6 +281,13 @@ prefix_cmp(struct prefix *p1, struct prefix *p2, int *testall)
if (i > 0)
return -1;
+ /* XXX RFC7911 does not specify this but it is needed. */
+ /* 13. lowest path identifier wins */
+ if (p1->path_id < p2->path_id)
+ return 1;
+ if (p1->path_id > p2->path_id)
+ return -1;
+
fatalx("Uh, oh a politician in the decision process");
}
diff --git a/usr.sbin/bgpd/rde_peer.c b/usr.sbin/bgpd/rde_peer.c
index 502826ddf4c..fafc1c8f6df 100644
--- a/usr.sbin/bgpd/rde_peer.c
+++ b/usr.sbin/bgpd/rde_peer.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_peer.c,v 1.11 2021/06/17 16:05:26 claudio Exp $ */
+/* $OpenBSD: rde_peer.c,v 1.12 2021/08/09 08:15:35 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
@@ -54,6 +54,14 @@ peer_has_as4byte(struct rde_peer *peer)
}
int
+peer_has_add_path(struct rde_peer *peer, u_int8_t aid, int mode)
+{
+ if (aid > AID_MAX)
+ return 0;
+ return (peer->capa.add_path[aid] & mode);
+}
+
+int
peer_accept_no_as_set(struct rde_peer *peer)
{
return (peer->flags & PEERFLAG_NO_AS_SET);
@@ -250,7 +258,8 @@ peer_flush_upcall(struct rib_entry *re, void *arg)
struct rib *rib = rib_byid(i);
if (rib == NULL)
continue;
- rp = prefix_get(rib, peer, &addr, prefixlen);
+ rp = prefix_get(rib, peer, p->path_id,
+ &addr, prefixlen);
if (rp) {
asp = prefix_aspath(rp);
if (asp && asp->pftableid)
@@ -264,7 +273,6 @@ peer_flush_upcall(struct rib_entry *re, void *arg)
prefix_destroy(p);
peer->prefix_cnt--;
- break; /* optimization, only one match per peer possible */
}
}
diff --git a/usr.sbin/bgpd/rde_rib.c b/usr.sbin/bgpd/rde_rib.c
index dc852519549..9cca822a94f 100644
--- a/usr.sbin/bgpd/rde_rib.c
+++ b/usr.sbin/bgpd/rde_rib.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_rib.c,v 1.223 2021/07/27 07:50:02 claudio Exp $ */
+/* $OpenBSD: rde_rib.c,v 1.224 2021/08/09 08:15:35 claudio Exp $ */
/*
* Copyright (c) 2003, 2004 Claudio Jeker <claudio@openbsd.org>
@@ -842,7 +842,7 @@ path_put(struct rde_aspath *asp)
/* prefix specific functions */
static int prefix_add(struct bgpd_addr *, int, struct rib *,
- struct rde_peer *, struct rde_aspath *,
+ struct rde_peer *, u_int32_t, struct rde_aspath *,
struct rde_community *, struct nexthop *,
u_int8_t, u_int8_t);
static int prefix_move(struct prefix *, struct rde_peer *,
@@ -850,7 +850,7 @@ static int prefix_move(struct prefix *, struct rde_peer *,
struct nexthop *, u_int8_t, u_int8_t);
static void prefix_link(struct prefix *, struct rib_entry *,
- struct rde_peer *, struct rde_aspath *,
+ struct rde_peer *, u_int32_t, struct rde_aspath *,
struct rde_community *, struct nexthop *,
u_int8_t, u_int8_t);
static void prefix_unlink(struct prefix *);
@@ -876,12 +876,14 @@ prefix_cmp(struct prefix *a, struct prefix *b)
return (a->nexthop > b->nexthop ? 1 : -1);
if (a->nhflags != b->nhflags)
return (a->nhflags > b->nhflags ? 1 : -1);
+ /* XXX path_id ??? */
return pt_prefix_cmp(a->pt, b->pt);
}
static inline int
prefix_index_cmp(struct prefix *a, struct prefix *b)
{
+ /* XXX path_id ??? */
return pt_prefix_cmp(a->pt, b->pt);
}
@@ -892,15 +894,15 @@ RB_GENERATE_STATIC(prefix_index, prefix, entry.tree.index, prefix_index_cmp)
* search for specified prefix of a peer. Returns NULL if not found.
*/
struct prefix *
-prefix_get(struct rib *rib, struct rde_peer *peer, struct bgpd_addr *prefix,
- int prefixlen)
+prefix_get(struct rib *rib, struct rde_peer *peer, u_int32_t path_id,
+ struct bgpd_addr *prefix, int prefixlen)
{
struct rib_entry *re;
re = rib_get(rib, prefix, prefixlen);
if (re == NULL)
return (NULL);
- return (prefix_bypeer(re, peer));
+ return (prefix_bypeer(re, peer, path_id));
}
/*
@@ -954,8 +956,9 @@ prefix_match(struct rde_peer *peer, struct bgpd_addr *addr)
* Return 1 if prefix was newly added, 0 if it was just changed.
*/
int
-prefix_update(struct rib *rib, struct rde_peer *peer, struct filterstate *state,
- struct bgpd_addr *prefix, int prefixlen, u_int8_t vstate)
+prefix_update(struct rib *rib, struct rde_peer *peer, u_int32_t path_id,
+ struct filterstate *state, struct bgpd_addr *prefix, int prefixlen,
+ u_int8_t vstate)
{
struct rde_aspath *asp, *nasp = &state->aspath;
struct rde_community *comm, *ncomm = &state->communities;
@@ -964,7 +967,7 @@ prefix_update(struct rib *rib, struct rde_peer *peer, struct filterstate *state,
/*
* First try to find a prefix in the specified RIB.
*/
- if ((p = prefix_get(rib, peer, prefix, prefixlen)) != NULL) {
+ if ((p = prefix_get(rib, peer, path_id, prefix, prefixlen)) != NULL) {
if (prefix_nexthop(p) == state->nexthop &&
prefix_nhflags(p) == state->nhflags &&
communities_equal(ncomm, prefix_communities(p)) &&
@@ -997,8 +1000,8 @@ prefix_update(struct rib *rib, struct rde_peer *peer, struct filterstate *state,
return (prefix_move(p, peer, asp, comm, state->nexthop,
state->nhflags, vstate));
else
- return (prefix_add(prefix, prefixlen, rib, peer, asp, comm,
- state->nexthop, state->nhflags, vstate));
+ return (prefix_add(prefix, prefixlen, rib, peer, path_id, asp,
+ comm, state->nexthop, state->nhflags, vstate));
}
/*
@@ -1006,8 +1009,9 @@ prefix_update(struct rib *rib, struct rde_peer *peer, struct filterstate *state,
*/
static int
prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
- struct rde_peer *peer, struct rde_aspath *asp, struct rde_community *comm,
- struct nexthop *nexthop, u_int8_t nhflags, u_int8_t vstate)
+ struct rde_peer *peer, u_int32_t path_id, struct rde_aspath *asp,
+ struct rde_community *comm, struct nexthop *nexthop, u_int8_t nhflags,
+ u_int8_t vstate)
{
struct prefix *p;
struct rib_entry *re;
@@ -1017,7 +1021,7 @@ prefix_add(struct bgpd_addr *prefix, int prefixlen, struct rib *rib,
re = rib_add(rib, prefix, prefixlen);
p = prefix_alloc();
- prefix_link(p, re, peer, asp, comm, nexthop, nhflags, vstate);
+ prefix_link(p, re, peer, path_id, asp, comm, nexthop, nhflags, vstate);
return (1);
}
@@ -1045,6 +1049,7 @@ prefix_move(struct prefix *p, struct rde_peer *peer,
np->peer = peer;
np->entry.list.re = prefix_re(p);
np->pt = p->pt; /* skip refcnt update since ref is moved */
+ np->path_id = p->path_id;
np->validation_state = vstate;
np->nhflags = nhflags;
np->nexthop = nexthop_ref(nexthop);
@@ -1086,13 +1091,13 @@ prefix_move(struct prefix *p, struct rde_peer *peer,
* or pt_entry -- become empty remove them too.
*/
int
-prefix_withdraw(struct rib *rib, struct rde_peer *peer,
+prefix_withdraw(struct rib *rib, struct rde_peer *peer, u_int32_t path_id,
struct bgpd_addr *prefix, int prefixlen)
{
struct prefix *p;
struct rde_aspath *asp;
- p = prefix_get(rib, peer, prefix, prefixlen);
+ p = prefix_get(rib, peer, path_id, prefix, prefixlen);
if (p == NULL) /* Got a dummy withdrawn request. */
return (0);
@@ -1487,12 +1492,12 @@ prefix_writebuf(struct ibuf *buf, struct bgpd_addr *prefix, u_int8_t plen)
* belonging to the peer peer. Returns NULL if no match found.
*/
struct prefix *
-prefix_bypeer(struct rib_entry *re, struct rde_peer *peer)
+prefix_bypeer(struct rib_entry *re, struct rde_peer *peer, u_int32_t path_id)
{
struct prefix *p;
LIST_FOREACH(p, &re->prefix_h, entry.list.rib)
- if (prefix_peer(p) == peer)
+ if (prefix_peer(p) == peer && p->path_id == path_id)
return (p);
return (NULL);
}
@@ -1544,7 +1549,7 @@ prefix_destroy(struct prefix *p)
*/
static void
prefix_link(struct prefix *p, struct rib_entry *re, struct rde_peer *peer,
- struct rde_aspath *asp, struct rde_community *comm,
+ u_int32_t path_id, struct rde_aspath *asp, struct rde_community *comm,
struct nexthop *nexthop, u_int8_t nhflags, u_int8_t vstate)
{
if (p->flags & PREFIX_FLAG_ADJOUT)
@@ -1555,6 +1560,7 @@ prefix_link(struct prefix *p, struct rib_entry *re, struct rde_peer *peer,
p->communities = communities_ref(comm);
p->peer = peer;
p->pt = pt_ref(re->prefix);
+ p->path_id = path_id;
p->validation_state = vstate;
p->nhflags = nhflags;
p->nexthop = nexthop_ref(nexthop);
diff --git a/usr.sbin/bgpd/rde_update.c b/usr.sbin/bgpd/rde_update.c
index 3296227bb39..3c4c8b04dec 100644
--- a/usr.sbin/bgpd/rde_update.c
+++ b/usr.sbin/bgpd/rde_update.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: rde_update.c,v 1.130 2021/06/17 08:14:50 claudio Exp $ */
+/* $OpenBSD: rde_update.c,v 1.131 2021/08/09 08:15:35 claudio Exp $ */
/*
* Copyright (c) 2004 Claudio Jeker <claudio@openbsd.org>
@@ -625,9 +625,18 @@ up_dump_prefix(u_char *buf, int len, struct prefix_tree *prefix_head,
{
struct prefix *p, *np;
struct bgpd_addr addr;
+ u_int32_t pathid;
int r, wpos = 0, done = 0;
RB_FOREACH_SAFE(p, prefix_tree, prefix_head, np) {
+ if (peer_has_add_path(peer, p->pt->aid, CAPA_AP_SEND)) {
+ if (len <= wpos + (int)sizeof(pathid))
+ break;
+ /* XXX add-path send side */
+ pathid = 0;
+ memcpy(buf + wpos, &pathid, sizeof(pathid));
+ wpos += sizeof(pathid);
+ }
pt_getaddr(p->pt, &addr);
if ((r = prefix_write(buf + wpos, len - wpos,
&addr, p->pt->prefixlen, withdraw)) == -1)