Index | Thread | Search

From:
Claudio Jeker <cjeker@diehard.n-r-g.com>
Subject:
bgpd: introduce min-version for rtr and default to version 1
To:
tech@openbsd.org
Date:
Fri, 9 Aug 2024 22:28:20 +0200

Download raw body.

Thread
This diff introduces a 'min-version' config option for rtr sessions.
The session can only be established if the negotiated version with the
cache is larger or equal to min-version. The default is 0 which is the old
RFC6810 spec.

Now on top of this introduce RTR_DEFAULT_VERSION which is not set to 1 for
RFC8210. If people want to try ASPA and the draft-8210bis code you need to
set min-version 2. Then the code will negotiate and require version 2
which includes the ASPA PDU.

I lightly tested this and it seems to work fine. There is currently no
support to clear a RTR session to pick up the new config. I will add
something for that later.

IMO defaulting to version 1 is currently the best option until the dust of
RTRv2 settled.
-- 
:wq Claudio

Index: bgpctl/output.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output.c,v
diff -u -p -r1.51 output.c
--- bgpctl/output.c	22 May 2024 08:42:34 -0000	1.51
+++ bgpctl/output.c	28 May 2024 15:39:24 -0000
@@ -1128,8 +1128,9 @@ show_rtr(struct ctl_show_rtr *rtr)
 	if (rtr->local_addr.aid != AID_UNSPEC)
 		printf(" Local Address: %s\n", log_addr(&rtr->local_addr));
 	if (rtr->session_id != -1)
-		printf(" Version: %u Session ID: %d Serial #: %u\n",
-		    rtr->version, rtr->session_id, rtr->serial);
+		printf(" Version: %u min %u Session ID: %d Serial #: %u\n",
+		    rtr->version, rtr->min_version, rtr->session_id,
+		    rtr->serial);
 	printf(" Refresh: %u, Retry: %u, Expire: %u\n",
 	    rtr->refresh, rtr->retry, rtr->expire);
 
Index: bgpctl/output_json.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpctl/output_json.c,v
diff -u -p -r1.44 output_json.c
--- bgpctl/output_json.c	22 May 2024 08:42:34 -0000	1.44
+++ bgpctl/output_json.c	28 May 2024 15:39:24 -0000
@@ -963,6 +963,7 @@ json_rtr(struct ctl_show_rtr *rtr)
 
 	if (rtr->session_id != -1) {
 		json_do_uint("version", rtr->version);
+		json_do_uint("minimal_version", rtr->min_version);
 		json_do_uint("session_id", rtr->session_id);
 		json_do_uint("serial", rtr->serial);
 	}
Index: bgpd/bgpd.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.c,v
diff -u -p -r1.264 bgpd.c
--- bgpd/bgpd.c	15 May 2024 09:09:38 -0000	1.264
+++ bgpd/bgpd.c	9 Aug 2024 14:15:36 -0000
@@ -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: bgpd/bgpd.conf.5
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.conf.5,v
diff -u -p -r1.240 bgpd.conf.5
--- bgpd/bgpd.conf.5	24 Apr 2024 10:41:34 -0000	1.240
+++ bgpd/bgpd.conf.5	15 May 2024 08:50:55 -0000
@@ -579,6 +579,12 @@ Bind to the specific IP address before o
 .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: bgpd/bgpd.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/bgpd.h,v
diff -u -p -r1.493 bgpd.h
--- bgpd/bgpd.h	18 May 2024 11:17:30 -0000	1.493
+++ bgpd/bgpd.h	9 Aug 2024 14:04:08 -0000
@@ -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: bgpd/parse.y
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/parse.y,v
diff -u -p -r1.463 parse.y
--- bgpd/parse.y	22 May 2024 08:41:14 -0000	1.463
+++ bgpd/parse.y	28 May 2024 15:39:25 -0000
@@ -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: bgpd/rtr.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rtr.c,v
diff -u -p -r1.21 rtr.c
--- bgpd/rtr.c	9 Apr 2024 12:05:07 -0000	1.21
+++ bgpd/rtr.c	9 Aug 2024 14:20:46 -0000
@@ -309,7 +309,7 @@ rtr_dispatch_imsg_parent(struct 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 
 			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: bgpd/rtr_proto.c
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/rtr_proto.c,v
diff -u -p -r1.37 rtr_proto.c
--- bgpd/rtr_proto.c	9 Aug 2024 14:00:48 -0000	1.37
+++ bgpd/rtr_proto.c	9 Aug 2024 14:22:35 -0000
@@ -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
 
 	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
 			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
 		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, siz
 }
 
 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 p
 
 	/* 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: bgpd/session.h
===================================================================
RCS file: /cvs/src/usr.sbin/bgpd/session.h,v
diff -u -p -r1.170 session.h
--- bgpd/session.h	18 May 2024 11:17:30 -0000	1.170
+++ bgpd/session.h	22 May 2024 08:37:14 -0000
@@ -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);