Add a per eBGP session role to the config.
authorclaudio <claudio@openbsd.org>
Wed, 4 Jan 2023 14:33:30 +0000 (14:33 +0000)
committerclaudio <claudio@openbsd.org>
Wed, 4 Jan 2023 14:33:30 +0000 (14:33 +0000)
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
usr.sbin/bgpd/bgpd.h
usr.sbin/bgpd/parse.y
usr.sbin/bgpd/printconf.c
usr.sbin/bgpd/session.c
usr.sbin/bgpd/util.c

index 4baeaaf..edd429a 100644 (file)
@@ -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 <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: 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
index 75a8cc9..c9818b7 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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);
index a52ebdf..5d3d002 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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 ==
index 461a3c4..cdb408f 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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
index 88a0f84..d388b83 100644 (file)
@@ -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 <henning@openbsd.org>
@@ -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:
index 1922f05..2163fb1 100644 (file)
@@ -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 <claudio@openbsd.org>
@@ -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";