From c0c94bcc90e3255b6b801f859100bc72e8760e5e Mon Sep 17 00:00:00 2001 From: claudio Date: Wed, 4 Jan 2023 14:33:30 +0000 Subject: [PATCH] Add a per eBGP session role to the config. This somewhat replaces the RFC 9234 open policy role. This is done because ASPA requires the same role to be present to properly validate paths. For iBGP sessions the role is forced to ROLE_NONE. If no role is set on an ebgp session then 'announce policy' is forced to 'no'. Also make sure the the role capability is only added if the role is set. OK tb@ --- usr.sbin/bgpd/bgpd.conf.5 | 34 +++++++++++------- usr.sbin/bgpd/bgpd.h | 18 +++++++--- usr.sbin/bgpd/parse.y | 57 +++++++++++++++++-------------- usr.sbin/bgpd/printconf.c | 10 +++--- usr.sbin/bgpd/session.c | 72 +++++++++++++++++++++++++++++++-------- usr.sbin/bgpd/util.c | 14 ++++---- 6 files changed, 137 insertions(+), 68 deletions(-) diff --git a/usr.sbin/bgpd/bgpd.conf.5 b/usr.sbin/bgpd/bgpd.conf.5 index 4baeaaf0b14..edd429a6862 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.227 2022/12/22 19:53:24 kn Exp $ +.\" $OpenBSD: bgpd.conf.5,v 1.228 2023/01/04 14:33:30 claudio Exp $ .\" .\" Copyright (c) 2004 Claudio Jeker .\" Copyright (c) 2003, 2004 Henning Brauer @@ -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: December 22 2022 $ +.Dd $Mdocdate: January 4 2023 $ .Dt BGPD.CONF 5 .Os .Sh NAME @@ -933,19 +933,11 @@ The default is .Pp .It Xo .Ic announce policy -.Pq Ic no Ns | Ns Ar role -.Op Ic enforce +.Pq Ic yes Ns | Ns Ic no Ns | Ns Ic enforce .Xc If set to -.Ic no , -do not add the open policy role capability. -The role can be one of -.Ar provider , -.Ar customer , -.Ar rs , -.Ar rs-client , -or -.Ar peer . +.Ic yes , +add the open policy role capability. If the role of the neighbor does not correspond to the expected role then the session will be closed. If @@ -1311,6 +1303,22 @@ setting. .It Ic rib Ar name Bind the neighbor to the specified RIB. .Pp +.It Ic role Ar role +Set the local role for this eBGP session. +The role can be one of +.Ar none , +.Ar provider , +.Ar customer , +.Ar rs , +.Ar rs-client , +or +.Ar peer . +If the role is set to +.Ar none +the +.Ic announce Ic policy +will also be disabled. +.Pp .It Ic route-reflector Op Ar address Act as an RFC 4456 .Em route-reflector diff --git a/usr.sbin/bgpd/bgpd.h b/usr.sbin/bgpd/bgpd.h index 75a8cc9e440..c9818b7aac0 100644 --- a/usr.sbin/bgpd/bgpd.h +++ b/usr.sbin/bgpd/bgpd.h @@ -1,4 +1,4 @@ -/* $OpenBSD: bgpd.h,v 1.455 2022/11/18 10:17:23 claudio Exp $ */ +/* $OpenBSD: bgpd.h,v 1.456 2023/01/04 14:33:30 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -333,6 +333,15 @@ enum enforce_as { ENFORCE_AS_ON }; +enum role { + ROLE_NONE, + ROLE_CUSTOMER, + ROLE_PROVIDER, + ROLE_RS, + ROLE_RS_CLIENT, + ROLE_PEER, +}; + enum auth_method { AUTH_NONE, AUTH_MD5SIG, @@ -380,12 +389,12 @@ struct capabilities { int8_t flags[AID_MAX]; /* graceful restart per AID flags */ int8_t restart; /* graceful restart, RFC 4724 */ } grestart; + enum role role; /* Open Policy, RFC 9234 */ int8_t mp[AID_MAX]; /* multiprotocol extensions, RFC 4760 */ + int8_t add_path[AID_MAX]; /* ADD_PATH, RFC 7911 */ 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 */ - uint8_t role; /* Open Policy, RFC 9234 */ int8_t role_ena; /* 1 for enable, 2 for enforce */ }; @@ -432,6 +441,7 @@ struct peer_config { enum export_type export_type; enum enforce_as enforce_as; enum enforce_as enforce_local_as; + enum role role; uint16_t max_prefix_restart; uint16_t max_out_prefix_restart; uint16_t holdtime; @@ -1417,7 +1427,7 @@ const char *log_rd(uint64_t); const char *log_ext_subtype(int, uint8_t); const char *log_reason(const char *); const char *log_rtr_error(enum rtr_error); -const char *log_policy(uint8_t); +const char *log_policy(enum role); int aspath_snprint(char *, size_t, void *, uint16_t); int aspath_asprint(char **, void *, uint16_t); size_t aspath_strlen(void *, uint16_t); diff --git a/usr.sbin/bgpd/parse.y b/usr.sbin/bgpd/parse.y index a52ebdfaf72..5d3d002e885 100644 --- a/usr.sbin/bgpd/parse.y +++ b/usr.sbin/bgpd/parse.y @@ -1,4 +1,4 @@ -/* $OpenBSD: parse.y,v 1.437 2022/11/18 10:17:23 claudio Exp $ */ +/* $OpenBSD: parse.y,v 1.438 2023/01/04 14:33:30 claudio Exp $ */ /* * Copyright (c) 2002, 2003, 2004 Henning Brauer @@ -219,7 +219,7 @@ typedef struct { %token EBGP IBGP %token LOCALAS REMOTEAS DESCR LOCALADDR MULTIHOP PASSIVE MAXPREFIX RESTART %token ANNOUNCE CAPABILITIES REFRESH AS4BYTE CONNECTRETRY ENHANCED ADDPATH -%token SEND RECV PLUS POLICY +%token SEND RECV PLUS POLICY ROLE %token DEMOTE ENFORCE NEIGHBORAS ASOVERRIDE REFLECTOR DEPEND DOWN %token DUMP IN OUT SOCKET RESTRICTED %token LOG TRANSPARENT @@ -1640,32 +1640,30 @@ peeropts : REMOTEAS as4number { curpeer->conf.eval.extrapaths = $5; curpeer->conf.eval.maxpaths = $6; } - | ANNOUNCE POLICY STRING enforce { - curpeer->conf.capabilities.role_ena = $4; - if (strcmp($3, "no") == 0) { - curpeer->conf.capabilities.role_ena = 0; - } else if (strcmp($3, "provider") == 0) { - curpeer->conf.capabilities.role = - CAPA_ROLE_PROVIDER; - } else if (strcmp($3, "rs") == 0) { - curpeer->conf.capabilities.role = - CAPA_ROLE_RS; - } else if (strcmp($3, "rs-client") == 0) { - curpeer->conf.capabilities.role = - CAPA_ROLE_RS_CLIENT; - } else if (strcmp($3, "customer") == 0) { - curpeer->conf.capabilities.role = - CAPA_ROLE_CUSTOMER; - } else if (strcmp($3, "peer") == 0) { - curpeer->conf.capabilities.role = - CAPA_ROLE_PEER; + | ANNOUNCE POLICY enforce { + curpeer->conf.capabilities.role_ena = $3; + } + | ROLE STRING { + if (strcmp($2, "provider") == 0) { + curpeer->conf.role = ROLE_PROVIDER; + } else if (strcmp($2, "rs") == 0) { + curpeer->conf.role = ROLE_RS; + } else if (strcmp($2, "rs-client") == 0) { + curpeer->conf.role = ROLE_RS_CLIENT; + } else if (strcmp($2, "customer") == 0) { + curpeer->conf.role = ROLE_CUSTOMER; + } else if (strcmp($2, "peer") == 0) { + curpeer->conf.role = ROLE_PEER; } else { - yyerror("syntax error, one of no, provider, " + yyerror("syntax error, one of none, provider, " "rs, rs-client, customer, peer expected"); - free($3); + free($2); YYERROR; } - free($3); + free($2); + } + | ROLE NONE { + curpeer->conf.role = ROLE_NONE; } | EXPORT NONE { curpeer->conf.export_type = EXPORT_NONE; @@ -2742,7 +2740,7 @@ delete : /* empty */ { $$ = 0; } | DELETE { $$ = 1; } ; -enforce : /* empty */ { $$ = 1; } +enforce : yesno { $$ = $1; } | ENFORCE { $$ = 2; } ; @@ -3248,6 +3246,7 @@ lookup(char *s) { "restricted", RESTRICTED}, { "rib", RIB}, { "roa-set", ROASET }, + { "role", ROLE}, { "route-reflector", REFLECTOR}, { "router-id", ROUTERID}, { "rtable", RTABLE}, @@ -4711,6 +4710,14 @@ neighbor_consistent(struct peer *p) return (-1); } + /* BGP role and RFC 9234 role are only valid for EBGP neighbors */ + if (p->conf.ebgp) { + if (p->conf.role == ROLE_NONE) + p->conf.capabilities.role_ena = 0; + p->conf.capabilities.role = p->conf.role; + } else + p->conf.role = ROLE_NONE; + /* check for duplicate peer definitions */ RB_FOREACH(xp, peer_head, new_peers) if (xp->conf.remote_masklen == diff --git a/usr.sbin/bgpd/printconf.c b/usr.sbin/bgpd/printconf.c index 461a3c46d08..cdb408f5934 100644 --- a/usr.sbin/bgpd/printconf.c +++ b/usr.sbin/bgpd/printconf.c @@ -1,4 +1,4 @@ -/* $OpenBSD: printconf.c,v 1.160 2022/11/18 10:17:23 claudio Exp $ */ +/* $OpenBSD: printconf.c,v 1.161 2023/01/04 14:33:30 claudio Exp $ */ /* * Copyright (c) 2003, 2004 Henning Brauer @@ -671,6 +671,8 @@ print_peer(struct peer_config *p, struct bgpd_config *conf, const char *c) log_addr(&p->local_addr_v6)); if (p->remote_port != BGP_PORT) printf("%s\tport %hu\n", c, p->remote_port); + if (p->role != ROLE_NONE) + printf("%s\trole %s\n", c, log_policy(p->role)); if (p->max_prefix) { printf("%s\tmax-prefix %u", c, p->max_prefix); if (p->max_prefix_restart) @@ -847,11 +849,9 @@ print_announce(struct peer_config *p, const char *c) printf("\n"); } if (p->capabilities.role_ena) { - printf("%s\tannounce policy %s%s\n", c, - log_policy(p->capabilities.role), - p->capabilities.role_ena == 2 ? " enforce" : ""); + printf("%s\tannounce policy %s\n", c, + p->capabilities.role_ena == 2 ? "enforce" : "yes"); } - } void diff --git a/usr.sbin/bgpd/session.c b/usr.sbin/bgpd/session.c index 88a0f84bb7a..d388b83cdd2 100644 --- a/usr.sbin/bgpd/session.c +++ b/usr.sbin/bgpd/session.c @@ -1,4 +1,4 @@ -/* $OpenBSD: session.c,v 1.438 2022/12/28 21:30:16 jmc Exp $ */ +/* $OpenBSD: session.c,v 1.439 2023/01/04 14:33:30 claudio Exp $ */ /* * Copyright (c) 2003, 2004, 2005 Henning Brauer @@ -1412,6 +1412,47 @@ session_sendmsg(struct bgp_msg *msg, struct peer *p) return (0); } +/* + * Translate between internal roles and the value expected by RFC 9234. + */ +static uint8_t +role2capa(enum role role) +{ + switch (role) { + case ROLE_CUSTOMER: + return CAPA_ROLE_CUSTOMER; + case ROLE_PROVIDER: + return CAPA_ROLE_PROVIDER; + case ROLE_RS: + return CAPA_ROLE_RS; + case ROLE_RS_CLIENT: + return CAPA_ROLE_RS_CLIENT; + case ROLE_PEER: + return CAPA_ROLE_PEER; + default: + fatalx("Unsupported role for role capability"); + } +} + +static enum role +capa2role(uint8_t val) +{ + switch (val) { + case CAPA_ROLE_PROVIDER: + return ROLE_PROVIDER; + case CAPA_ROLE_RS: + return ROLE_RS; + case CAPA_ROLE_RS_CLIENT: + return ROLE_RS_CLIENT; + case CAPA_ROLE_CUSTOMER: + return ROLE_CUSTOMER; + case CAPA_ROLE_PEER: + return ROLE_PEER; + default: + return ROLE_NONE; + } +} + void session_open(struct peer *p) { @@ -1442,9 +1483,12 @@ session_open(struct peer *p) errs += session_capa_add(opb, CAPA_REFRESH, 0); /* BGP open policy, RFC 9234, only for ebgp sessions */ - if (p->capa.ann.role_ena && p->conf.ebgp) { + if (p->conf.ebgp && p->capa.ann.role_ena && + p->capa.ann.role != ROLE_NONE) { + uint8_t val; + val = role2capa(p->capa.ann.role); errs += session_capa_add(opb, CAPA_ROLE, 1); - errs += ibuf_add(opb, &p->capa.ann.role, 1); + errs += ibuf_add(opb, &val, 1); } /* graceful restart and End-of-RIB marker, RFC 4724 */ @@ -2628,7 +2672,7 @@ parse_capabilities(struct peer *peer, u_char *d, uint16_t dlen, uint32_t *as) log_peer_warnx(&peer->conf, "Received role capability on iBGP session"); peer->capa.peer.role_ena = 1; - peer->capa.peer.role = *capa_val; + peer->capa.peer.role = capa2role(*capa_val); break; case CAPA_RESTART: if (capa_len == 2) { @@ -2847,24 +2891,24 @@ capa_neg_calc(struct peer *p, uint8_t *suberr) if (p->capa.ann.role_ena != 0 && p->capa.peer.role_ena != 0 && p->conf.ebgp) { switch (p->capa.ann.role) { - case CAPA_ROLE_PROVIDER: - if (p->capa.peer.role != CAPA_ROLE_CUSTOMER) + case ROLE_PROVIDER: + if (p->capa.peer.role != ROLE_CUSTOMER) goto fail; break; - case CAPA_ROLE_RS: - if (p->capa.peer.role != CAPA_ROLE_RS_CLIENT) + case ROLE_RS: + if (p->capa.peer.role != ROLE_RS_CLIENT) goto fail; break; - case CAPA_ROLE_RS_CLIENT: - if (p->capa.peer.role != CAPA_ROLE_RS) + case ROLE_RS_CLIENT: + if (p->capa.peer.role != ROLE_RS) goto fail; break; - case CAPA_ROLE_CUSTOMER: - if (p->capa.peer.role != CAPA_ROLE_PROVIDER) + case ROLE_CUSTOMER: + if (p->capa.peer.role != ROLE_PROVIDER) goto fail; break; - case CAPA_ROLE_PEER: - if (p->capa.peer.role != CAPA_ROLE_PEER) + case ROLE_PEER: + if (p->capa.peer.role != ROLE_PEER) goto fail; break; default: diff --git a/usr.sbin/bgpd/util.c b/usr.sbin/bgpd/util.c index 1922f058312..2163fb18439 100644 --- a/usr.sbin/bgpd/util.c +++ b/usr.sbin/bgpd/util.c @@ -1,4 +1,4 @@ -/* $OpenBSD: util.c,v 1.73 2022/11/09 14:23:53 claudio Exp $ */ +/* $OpenBSD: util.c,v 1.74 2023/01/04 14:33:30 claudio Exp $ */ /* * Copyright (c) 2006 Claudio Jeker @@ -198,18 +198,18 @@ log_rtr_error(enum rtr_error err) } const char * -log_policy(uint8_t role) +log_policy(enum role role) { switch (role) { - case CAPA_ROLE_PROVIDER: + case ROLE_PROVIDER: return "provider"; - case CAPA_ROLE_RS: + case ROLE_RS: return "rs"; - case CAPA_ROLE_RS_CLIENT: + case ROLE_RS_CLIENT: return "rs-client"; - case CAPA_ROLE_CUSTOMER: + case ROLE_CUSTOMER: return "customer"; - case CAPA_ROLE_PEER: + case ROLE_PEER: return "peer"; default: return "unknown"; -- 2.20.1