Add 'min-version' RTR config option and default to RTR version 1 by default.
authorclaudio <claudio@openbsd.org>
Mon, 12 Aug 2024 09:04:23 +0000 (09:04 +0000)
committerclaudio <claudio@openbsd.org>
Mon, 12 Aug 2024 09:04:23 +0000 (09:04 +0000)
The min-version pins a minimal required version for rtr session. This is
needed if specific PDUs are required and it ensures that the session is
not suddenly downgraded. This is important for ASPA where a minimum
version of 2 is required. Only then the ASPA PDUs are transmitted.

By default a RTR version of 1 is used but setting min-version to 2
will enable draft-ietf-sidrops-8210bis-14 support and enforce it
at the same time. Right now defaulting to version 2 is not possible
since draft-ietf-sidrops-8210bis failed to progress for a too long
time resulting in split eco system with various incompatible RTR
version 2 implementations.

OK tb@

usr.sbin/bgpd/bgpd.c
usr.sbin/bgpd/bgpd.conf.5
usr.sbin/bgpd/bgpd.h
usr.sbin/bgpd/parse.y
usr.sbin/bgpd/rtr.c
usr.sbin/bgpd/rtr_proto.c
usr.sbin/bgpd/session.h

index 5987713..8b6e1bc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bgpd.c,v 1.264 2024/05/15 09:09:38 job Exp $ */
+/*     $OpenBSD: bgpd.c,v 1.265 2024/08/12 09:04:23 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -738,8 +738,12 @@ send_config(struct bgpd_config *conf)
        }
        free_aspatree(&conf->aspa);
        SIMPLEQ_FOREACH(rtr, &conf->rtrs, entry) {
+               struct rtr_config_msg rtrconf = { 0 };
+
+               strlcpy(rtrconf.descr, rtr->descr, sizeof(rtrconf.descr));
+               rtrconf.min_version = rtr->min_version;
                if (imsg_compose(ibuf_rtr, IMSG_RECONF_RTR_CONFIG, rtr->id,
-                   0, -1, rtr->descr, sizeof(rtr->descr)) == -1)
+                   0, -1, &rtrconf, sizeof(rtrconf)) == -1)
                        return (-1);
        }
 
index a554e51..e01abf8 100644 (file)
@@ -1,4 +1,4 @@
-.\" $OpenBSD: bgpd.conf.5,v 1.240 2024/04/24 10:41:34 claudio Exp $
+.\" $OpenBSD: bgpd.conf.5,v 1.241 2024/08/12 09:04:23 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: April 24 2024 $
+.Dd $Mdocdate: August 12 2024 $
 .Dt BGPD.CONF 5
 .Os
 .Sh NAME
@@ -579,6 +579,12 @@ Bind to the specific IP address before opening the TCP connection to the
 .Em rtr
 server.
 .Pp
+.Ic min-version Ar number
+Require a minimal RTR version of
+.Ar number .
+To ensure that ASPA records are synchronised over RTR a minimal version
+of 2 is required.
+.Pp
 .It Ic port Ar number
 Specify the TCP destination port for the
 .Em rtr
index e0ba711..a4d2a10 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: bgpd.h,v 1.493 2024/05/18 11:17:30 jsg Exp $ */
+/*     $OpenBSD: bgpd.h,v 1.494 2024/08/12 09:04:23 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -33,6 +33,8 @@
 #include <imsg.h>
 
 #define        BGP_VERSION                     4
+#define        RTR_MAX_VERSION                 2
+#define        RTR_DEFAULT_VERSION             1
 #define        BGP_PORT                        179
 #define        RTR_PORT                        323
 #define        CONFFILE                        "/etc/bgpd.conf"
@@ -570,11 +572,19 @@ struct rtr_config {
        struct bgpd_addr                local_addr;
        uint32_t                        id;
        uint16_t                        remote_port;
+       uint8_t                         min_version;
+};
+
+struct rtr_config_msg {
+       char                            descr[PEER_DESCR_LEN];
+       uint8_t                         min_version;
 };
 
 struct ctl_show_rtr {
        char                    descr[PEER_DESCR_LEN];
        char                    state[PEER_DESCR_LEN];
+       char                    last_sent_msg[REASON_LEN];
+       char                    last_recv_msg[REASON_LEN];
        struct bgpd_addr        remote_addr;
        struct bgpd_addr        local_addr;
        uint32_t                serial;
@@ -582,12 +592,11 @@ struct ctl_show_rtr {
        uint32_t                retry;
        uint32_t                expire;
        int                     session_id;
-       uint16_t                remote_port;
-       uint8_t                 version;
        enum rtr_error          last_sent_error;
        enum rtr_error          last_recv_error;
-       char                    last_sent_msg[REASON_LEN];
-       char                    last_recv_msg[REASON_LEN];
+       uint16_t                remote_port;
+       uint8_t                 version;
+       uint8_t                 min_version;
 };
 
 enum imsg_type {
index fa8047d..bffd409 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: parse.y,v 1.463 2024/05/22 08:41:14 claudio Exp $ */
+/*     $OpenBSD: parse.y,v 1.464 2024/08/12 09:04:23 claudio Exp $ */
 
 /*
  * Copyright (c) 2002, 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -241,7 +241,7 @@ typedef struct {
 
 %token AS ROUTERID HOLDTIME YMIN LISTEN ON FIBUPDATE FIBPRIORITY RTABLE
 %token NONE UNICAST VPN RD EXPORT EXPORTTRGT IMPORTTRGT DEFAULTROUTE
-%token RDE RIB EVALUATE IGNORE COMPARE RTR PORT
+%token RDE RIB EVALUATE IGNORE COMPARE RTR PORT MINVERSION
 %token GROUP NEIGHBOR NETWORK
 %token EBGP IBGP
 %token FLOWSPEC PROTO FLAGS FRAGMENT TOS LENGTH ICMPTYPE CODE
@@ -724,6 +724,14 @@ rtropt             : DESCR STRING          {
                | PORT port {
                        currtr->remote_port = $2;
                }
+               | MINVERSION NUMBER {
+                       if ($2 < 0 || $2 > RTR_MAX_VERSION) {
+                               yyerror("min-version must be between %u and %u",
+                                   0, RTR_MAX_VERSION);
+                               YYERROR;
+                       }
+                       currtr->min_version = $2;
+               }
                ;
 
 conf_main      : AS as4number          {
@@ -3578,6 +3586,7 @@ lookup(char *s)
                { "med",                MED},
                { "metric",             METRIC},
                { "min",                YMIN},
+               { "min-version",        MINVERSION},
                { "multihop",           MULTIHOP},
                { "neighbor",           NEIGHBOR},
                { "neighbor-as",        NEIGHBORAS},
index 43b4712..4ea5aa9 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rtr.c,v 1.21 2024/04/09 12:05:07 claudio Exp $ */
+/*     $OpenBSD: rtr.c,v 1.22 2024/08/12 09:04:23 claudio Exp $ */
 
 /*
  * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
@@ -309,7 +309,7 @@ rtr_dispatch_imsg_parent(struct imsgbuf *imsgbuf)
        struct imsg              imsg;
        struct bgpd_config       tconf;
        struct roa               roa;
-       char                     descr[PEER_DESCR_LEN];
+       struct rtr_config_msg    rtrconf;
        struct rtr_session      *rs;
        uint32_t                 rtrid;
        int                      n, fd;
@@ -395,13 +395,14 @@ rtr_dispatch_imsg_parent(struct imsgbuf *imsgbuf)
                        aspa = NULL;
                        break;
                case IMSG_RECONF_RTR_CONFIG:
-                       if (imsg_get_data(&imsg, descr, sizeof(descr)) == -1)
+                       if (imsg_get_data(&imsg, &rtrconf,
+                           sizeof(rtrconf)) == -1)
                                fatal("imsg_get_data");
                        rs = rtr_get(rtrid);
                        if (rs == NULL)
-                               rtr_new(rtrid, descr);
+                               rtr_new(rtrid, &rtrconf);
                        else
-                               rtr_config_keep(rs);
+                               rtr_config_keep(rs, &rtrconf);
                        break;
                case IMSG_RECONF_DRAIN:
                        imsg_compose(ibuf_main, IMSG_RECONF_DRAIN, 0, 0,
index 9619f1f..3b09fa3 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: rtr_proto.c,v 1.37 2024/08/09 14:00:48 claudio Exp $ */
+/*     $OpenBSD: rtr_proto.c,v 1.38 2024/08/12 09:04:23 claudio Exp $ */
 
 /*
  * Copyright (c) 2020 Claudio Jeker <claudio@openbsd.org>
@@ -42,7 +42,6 @@ struct rtr_header {
        uint32_t        length;
 } __packed;
 
-#define RTR_MAX_VERSION                2
 #define RTR_MAX_PDU_SIZE       49152   /* XXX < IBUF_READ_SIZE */
 #define RTR_MAX_PDU_ERROR_SIZE 256
 #define RTR_DEFAULT_REFRESH    3600
@@ -213,6 +212,9 @@ struct rtr_session {
        char                            last_recv_msg[REASON_LEN];
        uint8_t                         version;
        uint8_t                         prev_version;
+       uint8_t                         min_version;
+       uint8_t                         errored;
+
 };
 
 TAILQ_HEAD(, rtr_session) rtrs = TAILQ_HEAD_INITIALIZER(rtrs);
@@ -259,6 +261,14 @@ log_rtr_type(enum rtr_pdu_type type)
        }
 };
 
+static uint8_t
+rtr_max_session_version(struct rtr_session *rs)
+{
+       if (rs->min_version > RTR_DEFAULT_VERSION)
+               return rs->min_version;
+       return RTR_DEFAULT_VERSION;
+}
+
 static void
 rtr_reset_cache(struct rtr_session *rs)
 {
@@ -1084,13 +1094,14 @@ rtr_fsm(struct rtr_session *rs, enum rtr_event event)
 
        switch (event) {
        case RTR_EVNT_UNSUPP_PROTO_VERSION:
-               if (rs->prev_version == rs->version) {
+               if (rs->prev_version == rs->version ||
+                   rs->version < rs->min_version) {
                        /*
                         * Can't downgrade anymore, fail connection.
                         * RFC requires sending the error with the
                         * highest supported version number.
                         */
-                       rs->version = RTR_MAX_VERSION;
+                       rs->version = rtr_max_session_version(rs);
                        rtr_send_error(rs, NULL, UNSUPP_PROTOCOL_VERS,
                            "negotiation failed");
                        return;
@@ -1114,8 +1125,13 @@ rtr_fsm(struct rtr_session *rs, enum rtr_event event)
                        rs->fd = -1;
                }
                /* try to reopen session */
-               timer_set(&rs->timers, Timer_Rtr_Retry,
-                   arc4random_uniform(10));
+               if (!rs->errored)
+                       timer_set(&rs->timers, Timer_Rtr_Retry,
+                           arc4random_uniform(10));
+               else
+                       timer_set(&rs->timers, Timer_Rtr_Retry, rs->retry);
+
+               rs->errored = 1;
                /*
                 * A close event during version negotiation needs to remain
                 * in the negotiation state else the same error will happen
@@ -1190,6 +1206,7 @@ rtr_fsm(struct rtr_session *rs, enum rtr_event event)
                rtr_sem_release(rs->active_lock);
                rtr_recalc();
                rs->active_lock = 0;
+               rs->errored = 0;
                /* clear the last errors */
                rs->last_sent_error = NO_ERROR;
                rs->last_recv_error = NO_ERROR;
@@ -1371,12 +1388,12 @@ rtr_poll_events(struct pollfd *pfds, size_t npfds, time_t *timeout)
 }
 
 struct rtr_session *
-rtr_new(uint32_t id, char *descr)
+rtr_new(uint32_t id, struct rtr_config_msg *conf)
 {
        struct rtr_session *rs;
 
        if ((rs = calloc(1, sizeof(*rs))) == NULL)
-               fatal("RTR session %s", descr);
+               fatal("RTR session %s", conf->descr);
 
        RB_INIT(&rs->roa_set);
        RB_INIT(&rs->aspa);
@@ -1384,11 +1401,12 @@ rtr_new(uint32_t id, char *descr)
        TAILQ_INIT(&rs->timers);
        msgbuf_init(&rs->w);
 
-       strlcpy(rs->descr, descr, sizeof(rs->descr));
+       strlcpy(rs->descr, conf->descr, sizeof(rs->descr));
        rs->id = id;
        rs->session_id = -1;
-       rs->version = RTR_MAX_VERSION;
-       rs->prev_version = RTR_MAX_VERSION;
+       rs->min_version = conf->min_version;    /* must be set before version */
+       rs->version = rtr_max_session_version(rs);
+       rs->prev_version = rtr_max_session_version(rs);
        rs->refresh = RTR_DEFAULT_REFRESH;
        rs->retry = RTR_DEFAULT_RETRY;
        rs->expire = RTR_DEFAULT_EXPIRE;
@@ -1441,8 +1459,8 @@ rtr_open(struct rtr_session *rs, int fd)
        }
 
        if (rs->state == RTR_STATE_CLOSED) {
-               rs->version = RTR_MAX_VERSION;
-               rs->prev_version = RTR_MAX_VERSION;
+               rs->version = rtr_max_session_version(rs);
+               rs->prev_version = rtr_max_session_version(rs);
        }
 
        rs->fd = rs->w.fd = fd;
@@ -1471,8 +1489,10 @@ rtr_config_merge(void)
 }
 
 void
-rtr_config_keep(struct rtr_session *rs)
+rtr_config_keep(struct rtr_session *rs, struct rtr_config_msg *conf)
 {
+       strlcpy(rs->descr, conf->descr, sizeof(rs->descr));
+       rs->min_version = conf->min_version;
        rs->reconf_action = RECONF_KEEP;
 }
 
@@ -1523,6 +1543,7 @@ rtr_show(struct rtr_session *rs, pid_t pid)
 
        /* descr, remote_addr, local_addr and remote_port set by parent */
        msg.version = rs->version;
+       msg.min_version = rs->min_version;
        msg.serial = rs->serial;
        msg.refresh = rs->refresh;
        msg.retry = rs->retry;
index 815b124..a6f4a53 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: session.h,v 1.170 2024/05/18 11:17:30 jsg Exp $ */
+/*     $OpenBSD: session.h,v 1.171 2024/08/12 09:04:23 claudio Exp $ */
 
 /*
  * Copyright (c) 2003, 2004 Henning Brauer <henning@openbsd.org>
@@ -296,13 +296,14 @@ struct rtr_session;
 size_t                  rtr_count(void);
 void                    rtr_check_events(struct pollfd *, size_t);
 size_t                  rtr_poll_events(struct pollfd *, size_t, time_t *);
-struct rtr_session     *rtr_new(uint32_t, char *);
+struct rtr_session     *rtr_new(uint32_t, struct rtr_config_msg *);
 struct rtr_session     *rtr_get(uint32_t);
 void                    rtr_free(struct rtr_session *);
 void                    rtr_open(struct rtr_session *, int);
 void                    rtr_config_prep(void);
 void                    rtr_config_merge(void);
-void                    rtr_config_keep(struct rtr_session *);
+void                    rtr_config_keep(struct rtr_session *,
+                            struct rtr_config_msg *);
 void                    rtr_roa_merge(struct roa_tree *);
 void                    rtr_aspa_merge(struct aspa_tree *);
 void                    rtr_shutdown(void);