From: https://github.com/FRRouting/frr/commit/d08c0c8077fbb3e100ed2e87927edec1a09d224b
Reviewed-by: Aron Xu <aron@debian.org>

From d08c0c8077fbb3e100ed2e87927edec1a09d224b Mon Sep 17 00:00:00 2001
From: Donatas Abraitis <donatas.abraitis@gmail.com>
Date: Sat, 20 Nov 2021 22:00:23 +0200
Subject: [PATCH] bgpd: Implement rfc9072

Related: https://datatracker.ietf.org/doc/html/rfc9072

Signed-off-by: Donatas Abraitis <donatas.abraitis@gmail.com>
---
 bgpd/bgp_open.c   | 140 ++++++++++++++++++++++++++++++++--------------
 bgpd/bgp_open.h   |  15 ++++-
 bgpd/bgp_packet.c |  53 +++++++++++++++---
 bgpd/bgp_vty.c    |  47 ++++++++++++++++
 bgpd/bgpd.c       |   1 +
 bgpd/bgpd.h       |   4 ++
 6 files changed, 207 insertions(+), 53 deletions(-)

Index: frr-7.5.1/bgpd/bgp_open.c
===================================================================
--- frr-7.5.1.orig/bgpd/bgp_open.c
+++ frr-7.5.1/bgpd/bgp_open.c
@@ -1016,7 +1016,7 @@ static bool strict_capability_same(struc
 /* peek into option, stores ASN to *as4 if the AS4 capability was found.
  * Returns  0 if no as4 found, as4cap value otherwise.
  */
-as_t peek_for_as4_capability(struct peer *peer, uint8_t length)
+as_t peek_for_as4_capability(struct peer *peer, uint16_t length)
 {
 	struct stream *s = BGP_INPUT(peer);
 	size_t orig_getp = stream_get_getp(s);
@@ -1032,7 +1032,7 @@ as_t peek_for_as4_capability(struct peer
 	 */
 	while (stream_get_getp(s) < end) {
 		uint8_t opt_type;
-		uint8_t opt_length;
+		uint16_t opt_length;
 
 		/* Check the length. */
 		if (stream_get_getp(s) + 2 > end)
@@ -1040,7 +1040,9 @@ as_t peek_for_as4_capability(struct peer
 
 		/* Fetch option type and length. */
 		opt_type = stream_getc(s);
-		opt_length = stream_getc(s);
+		opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
+				     ? stream_getw(s)
+				     : stream_getc(s);
 
 		/* Option length check. */
 		if (stream_get_getp(s) + opt_length > end)
@@ -1088,7 +1090,8 @@ end:
  *
  * @param[out] mp_capability @see bgp_capability_parse() for semantics.
  */
-int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
+int bgp_open_option_parse(struct peer *peer, uint16_t length,
+			  int *mp_capability)
 {
 	int ret = 0;
 	uint8_t *error;
@@ -1107,7 +1110,7 @@ int bgp_open_option_parse(struct peer *p
 
 	while (stream_get_getp(s) < end) {
 		uint8_t opt_type;
-		uint8_t opt_length;
+		uint16_t opt_length;
 
 		/* Must have at least an OPEN option header */
 		if (STREAM_READABLE(s) < 2) {
@@ -1119,11 +1122,14 @@ int bgp_open_option_parse(struct peer *p
 
 		/* Fetch option type and length. */
 		opt_type = stream_getc(s);
-		opt_length = stream_getc(s);
+		opt_length = BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)
+				     ? stream_getw(s)
+				     : stream_getc(s);
 
 		/* Option length check. */
 		if (STREAM_READABLE(s) < opt_length) {
-			zlog_info("%s Option length error", peer->host);
+			zlog_info("%s Option length error (%d)", peer->host,
+				  opt_length);
 			bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
 					BGP_NOTIFY_OPEN_MALFORMED_ATTR);
 			return -1;
@@ -1220,9 +1226,10 @@ int bgp_open_option_parse(struct peer *p
 }
 
 static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
-				    afi_t afi, safi_t safi, uint8_t code)
+				    afi_t afi, safi_t safi, uint8_t code,
+				    bool ext_opt_params)
 {
-	uint8_t cap_len;
+	uint16_t cap_len;
 	uint8_t orf_len;
 	unsigned long capp;
 	unsigned long orfp;
@@ -1236,7 +1243,8 @@ static void bgp_open_capability_orf(stru
 
 	stream_putc(s, BGP_OPEN_OPT_CAP);
 	capp = stream_get_endp(s); /* Set Capability Len Pointer */
-	stream_putc(s, 0);	 /* Capability Length */
+	ext_opt_params ? stream_putw(s, 0)
+		       : stream_putc(s, 0); /* Capability Length */
 	stream_putc(s, code);      /* Capability Code */
 	orfp = stream_get_endp(s); /* Set ORF Len Pointer */
 	stream_putc(s, 0);	 /* ORF Length */
@@ -1284,11 +1292,12 @@ static void bgp_open_capability_orf(stru
 
 	/* Total Capability Len. */
 	cap_len = stream_get_endp(s) - capp - 1;
-	stream_putc_at(s, capp, cap_len);
+	ext_opt_params ? stream_putw_at(s, capp, cap_len)
+		       : stream_putc_at(s, capp, cap_len);
 }
 
 static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
-					unsigned long cp)
+					bool ext_opt_params)
 {
 	int len;
 	iana_afi_t pkt_afi;
@@ -1310,7 +1319,8 @@ static void bgp_peer_send_gr_capability(
 	SET_FLAG(peer->cap, PEER_CAP_RESTART_ADV);
 	stream_putc(s, BGP_OPEN_OPT_CAP);
 	capp = stream_get_endp(s); /* Set Capability Len Pointer */
-	stream_putc(s, 0);	 /* Capability Length */
+	ext_opt_params ? stream_putw(s, 0)
+		       : stream_putc(s, 0); /* Capability Length */
 	stream_putc(s, CAPABILITY_CODE_RESTART);
 	/* Set Restart Capability Len Pointer */
 	rcapp = stream_get_endp(s);
@@ -1365,14 +1375,16 @@ static void bgp_peer_send_gr_capability(
 
 	/* Total Capability Len. */
 	len = stream_get_endp(s) - capp - 1;
-	stream_putc_at(s, capp, len);
+	ext_opt_params ? stream_putw_at(s, capp, len - 1)
+		       : stream_putc_at(s, capp, len);
 }
 
 /* Fill in capability open option to the packet. */
-void bgp_open_capability(struct stream *s, struct peer *peer)
+uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
+			     bool ext_opt_params)
 {
-	uint8_t len;
-	unsigned long cp, capp, rcapp;
+	uint16_t len;
+	unsigned long cp, capp, rcapp, eopl = 0;
 	iana_afi_t pkt_afi;
 	afi_t afi;
 	safi_t safi;
@@ -1381,16 +1393,26 @@ void bgp_open_capability(struct stream *
 	uint8_t afi_safi_count = 0;
 	int adv_addpath_tx = 0;
 
-	/* Remember current pointer for Opt Parm Len. */
+	/* Non-Ext OP Len. */
 	cp = stream_get_endp(s);
-
-	/* Opt Parm Len. */
 	stream_putc(s, 0);
 
+	if (ext_opt_params) {
+		/* Non-Ext OP Len. */
+		stream_putc_at(s, cp, BGP_OPEN_NON_EXT_OPT_LEN);
+
+		/* Non-Ext OP Type */
+		stream_putc(s, BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH);
+
+		/* Extended Opt. Parm. Length */
+		eopl = stream_get_endp(s);
+		stream_putw(s, 0);
+	}
+
 	/* Do not send capability. */
 	if (!CHECK_FLAG(peer->sflags, PEER_STATUS_CAPABILITY_OPEN)
 	    || CHECK_FLAG(peer->flags, PEER_FLAG_DONT_CAPABILITY))
-		return;
+		return 0;
 
 	/* MP capability for configured AFI, SAFI */
 	FOREACH_AFI_SAFI (afi, safi) {
@@ -1401,7 +1423,9 @@ void bgp_open_capability(struct stream *
 
 			peer->afc_adv[afi][safi] = 1;
 			stream_putc(s, BGP_OPEN_OPT_CAP);
-			stream_putc(s, CAPABILITY_CODE_MP_LEN + 2);
+			ext_opt_params
+				? stream_putw(s, CAPABILITY_CODE_MP_LEN + 2)
+				: stream_putc(s, CAPABILITY_CODE_MP_LEN + 2);
 			stream_putc(s, CAPABILITY_CODE_MP);
 			stream_putc(s, CAPABILITY_CODE_MP_LEN);
 			stream_putw(s, pkt_afi);
@@ -1421,7 +1445,13 @@ void bgp_open_capability(struct stream *
 				 */
 				SET_FLAG(peer->cap, PEER_CAP_ENHE_ADV);
 				stream_putc(s, BGP_OPEN_OPT_CAP);
-				stream_putc(s, CAPABILITY_CODE_ENHE_LEN + 2);
+				ext_opt_params
+					? stream_putw(s,
+						      CAPABILITY_CODE_ENHE_LEN
+							      + 2)
+					: stream_putc(s,
+						      CAPABILITY_CODE_ENHE_LEN
+							      + 2);
 				stream_putc(s, CAPABILITY_CODE_ENHE);
 				stream_putc(s, CAPABILITY_CODE_ENHE_LEN);
 
@@ -1442,18 +1472,21 @@ void bgp_open_capability(struct stream *
 	/* Route refresh. */
 	SET_FLAG(peer->cap, PEER_CAP_REFRESH_ADV);
 	stream_putc(s, BGP_OPEN_OPT_CAP);
-	stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2);
+	ext_opt_params ? stream_putw(s, CAPABILITY_CODE_REFRESH_LEN + 2)
+		       : stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2);
 	stream_putc(s, CAPABILITY_CODE_REFRESH_OLD);
 	stream_putc(s, CAPABILITY_CODE_REFRESH_LEN);
 	stream_putc(s, BGP_OPEN_OPT_CAP);
-	stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2);
+	ext_opt_params ? stream_putw(s, CAPABILITY_CODE_REFRESH_LEN + 2)
+		       : stream_putc(s, CAPABILITY_CODE_REFRESH_LEN + 2);
 	stream_putc(s, CAPABILITY_CODE_REFRESH);
 	stream_putc(s, CAPABILITY_CODE_REFRESH_LEN);
 
 	/* AS4 */
 	SET_FLAG(peer->cap, PEER_CAP_AS4_ADV);
 	stream_putc(s, BGP_OPEN_OPT_CAP);
-	stream_putc(s, CAPABILITY_CODE_AS4_LEN + 2);
+	ext_opt_params ? stream_putw(s, CAPABILITY_CODE_AS4_LEN + 2)
+		       : stream_putc(s, CAPABILITY_CODE_AS4_LEN + 2);
 	stream_putc(s, CAPABILITY_CODE_AS4);
 	stream_putc(s, CAPABILITY_CODE_AS4_LEN);
 	if (peer->change_local_as)
@@ -1477,7 +1510,11 @@ void bgp_open_capability(struct stream *
 
 	SET_FLAG(peer->cap, PEER_CAP_ADDPATH_ADV);
 	stream_putc(s, BGP_OPEN_OPT_CAP);
-	stream_putc(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count) + 2);
+	ext_opt_params
+		? stream_putw(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count)
+					 + 2)
+		: stream_putc(s, (CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count)
+					 + 2);
 	stream_putc(s, CAPABILITY_CODE_ADDPATH);
 	stream_putc(s, CAPABILITY_CODE_ADDPATH_LEN * afi_safi_count);
 
@@ -1513,9 +1550,11 @@ void bgp_open_capability(struct stream *
 		    || CHECK_FLAG(peer->af_flags[afi][safi],
 				  PEER_FLAG_ORF_PREFIX_RM)) {
 			bgp_open_capability_orf(s, peer, afi, safi,
-						CAPABILITY_CODE_ORF_OLD);
+						CAPABILITY_CODE_ORF_OLD,
+						ext_opt_params);
 			bgp_open_capability_orf(s, peer, afi, safi,
-						CAPABILITY_CODE_ORF);
+						CAPABILITY_CODE_ORF,
+						ext_opt_params);
 		}
 	}
 
@@ -1523,11 +1562,15 @@ void bgp_open_capability(struct stream *
 	if (CHECK_FLAG(peer->flags, PEER_FLAG_DYNAMIC_CAPABILITY)) {
 		SET_FLAG(peer->cap, PEER_CAP_DYNAMIC_ADV);
 		stream_putc(s, BGP_OPEN_OPT_CAP);
-		stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
+		ext_opt_params
+			? stream_putw(s, CAPABILITY_CODE_DYNAMIC_LEN + 2)
+			: stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
 		stream_putc(s, CAPABILITY_CODE_DYNAMIC_OLD);
 		stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN);
 		stream_putc(s, BGP_OPEN_OPT_CAP);
-		stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
+		ext_opt_params
+			? stream_putw(s, CAPABILITY_CODE_DYNAMIC_LEN + 2)
+			: stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN + 2);
 		stream_putc(s, CAPABILITY_CODE_DYNAMIC);
 		stream_putc(s, CAPABILITY_CODE_DYNAMIC_LEN);
 	}
@@ -1537,7 +1580,8 @@ void bgp_open_capability(struct stream *
 		SET_FLAG(peer->cap, PEER_CAP_HOSTNAME_ADV);
 		stream_putc(s, BGP_OPEN_OPT_CAP);
 		rcapp = stream_get_endp(s); /* Ptr to length placeholder */
-		stream_putc(s, 0);	  /* dummy len for now */
+		ext_opt_params ? stream_putw(s, 0)
+			       : stream_putc(s, 0); /* Capability Length */
 		stream_putc(s, CAPABILITY_CODE_FQDN);
 		capp = stream_get_endp(s);
 		stream_putc(s, 0); /* dummy len for now */
@@ -1559,7 +1603,9 @@ void bgp_open_capability(struct stream *
 
 		/* Set the lengths straight */
 		len = stream_get_endp(s) - rcapp - 1;
-		stream_putc_at(s, rcapp, len);
+		ext_opt_params ? stream_putw_at(s, rcapp, len - 1)
+			       : stream_putc_at(s, rcapp, len);
+
 		len = stream_get_endp(s) - capp - 1;
 		stream_putc_at(s, capp, len);
 
@@ -1570,9 +1616,18 @@ void bgp_open_capability(struct stream *
 				cmd_domainname_get());
 	}
 
-	bgp_peer_send_gr_capability(s, peer, cp);
+	bgp_peer_send_gr_capability(s, peer, ext_opt_params);
 
 	/* Total Opt Parm Len. */
 	len = stream_get_endp(s) - cp - 1;
 	stream_putc_at(s, cp, len);
+
+	if (ext_opt_params) {
+		len = stream_get_endp(s) - eopl - 2;
+		stream_putw_at(s, eopl, len);
+	} else {
+		stream_putc_at(s, cp, len);
+	}
+
+	return len;
 }
Index: frr-7.5.1/bgpd/bgp_open.h
===================================================================
--- frr-7.5.1.orig/bgpd/bgp_open.h
+++ frr-7.5.1/bgpd/bgp_open.h
@@ -84,10 +84,19 @@ struct graceful_restart_af {
 #define RESTART_R_BIT              0x8000
 #define RESTART_F_BIT              0x80
 
-extern int bgp_open_option_parse(struct peer *, uint8_t, int *);
-extern void bgp_open_capability(struct stream *, struct peer *);
+/* Optional Parameters */
+#define BGP_OPEN_NON_EXT_OPT_LEN 255		      /* Non-Ext OP Len. */
+#define BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH 255 /* Non-Ext OP Type */
+#define BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(peer)                                  \
+	(CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)                \
+	 || CHECK_FLAG(peer->sflags, PEER_STATUS_EXT_OPT_PARAMS_LENGTH))
+
+extern int bgp_open_option_parse(struct peer *peer, uint16_t length,
+				 int *mp_capability);
+extern uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
+				    bool ext_opt_params);
 extern void bgp_capability_vty_out(struct vty *vty, struct peer *peer,
 				   bool use_json, json_object *json_neigh);
-extern as_t peek_for_as4_capability(struct peer *, uint8_t);
+extern as_t peek_for_as4_capability(struct peer *peer, uint16_t length);
 
 #endif /* _QUAGGA_BGP_OPEN_H */
Index: frr-7.5.1/bgpd/bgp_packet.c
===================================================================
--- frr-7.5.1.orig/bgpd/bgp_packet.c
+++ frr-7.5.1/bgpd/bgp_packet.c
@@ -559,8 +559,22 @@ void bgp_open_send(struct peer *peer)
 	stream_putw(s, send_holdtime);		/* Hold Time */
 	stream_put_in_addr(s, &peer->local_id); /* BGP Identifier */
 
-	/* Set capability code. */
-	bgp_open_capability(s, peer);
+	/* Set capabilities */
+	if (CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) {
+		(void)bgp_open_capability(s, peer, true);
+	} else {
+		struct stream *tmp = stream_new(STREAM_SIZE(s));
+
+		stream_copy(tmp, s);
+		if (bgp_open_capability(tmp, peer, false)
+		    > BGP_OPEN_NON_EXT_OPT_LEN) {
+			stream_free(tmp);
+			(void)bgp_open_capability(s, peer, true);
+		} else {
+			stream_copy(s, tmp);
+			stream_free(tmp);
+		}
+	}
 
 	/* Set BGP packet length. */
 	(void)bgp_packet_set_size(s);
@@ -1092,7 +1106,7 @@ static int bgp_open_receive(struct peer
 {
 	int ret;
 	uint8_t version;
-	uint8_t optlen;
+	uint16_t optlen;
 	uint16_t holdtime;
 	uint16_t send_holdtime;
 	as_t remote_as;
@@ -1113,20 +1127,41 @@ static int bgp_open_receive(struct peer
 	memcpy(notify_data_remote_id, stream_pnt(peer->curr), 4);
 	remote_id.s_addr = stream_get_ipv4(peer->curr);
 
-	/* Receive OPEN message log  */
-	if (bgp_debug_neighbor_events(peer))
-		zlog_debug(
-			"%s rcv OPEN, version %d, remote-as (in open) %u, holdtime %d, id %s",
-			peer->host, version, remote_as, holdtime,
-			inet_ntoa(remote_id));
 
 	/* BEGIN to read the capability here, but dont do it yet */
 	mp_capability = 0;
 	optlen = stream_getc(peer->curr);
 
+	/* Extended Optional Parameters Length for BGP OPEN Message */
+	if (optlen == BGP_OPEN_NON_EXT_OPT_LEN
+	    || CHECK_FLAG(peer->flags, PEER_FLAG_EXTENDED_OPT_PARAMS)) {
+		uint8_t opttype;
+
+		opttype = stream_getc(peer->curr);
+		if (opttype == BGP_OPEN_NON_EXT_OPT_TYPE_EXTENDED_LENGTH) {
+			optlen = stream_getw(peer->curr);
+			SET_FLAG(peer->sflags,
+				 PEER_STATUS_EXT_OPT_PARAMS_LENGTH);
+		}
+	}
+
+	/* Receive OPEN message log  */
+	if (bgp_debug_neighbor_events(peer))
+		zlog_debug(
+			"%s rcv OPEN%s, version %d, remote-as (in open) %u, holdtime %d, id %pI4",
+			peer->host,
+			CHECK_FLAG(peer->sflags,
+				   PEER_STATUS_EXT_OPT_PARAMS_LENGTH)
+				? " (Extended)"
+				: "",
+			version, remote_as, holdtime, &remote_id);
+
 	if (optlen != 0) {
 		/* If not enough bytes, it is an error. */
 		if (STREAM_READABLE(peer->curr) < optlen) {
+			flog_err(EC_BGP_PKT_OPEN,
+				 "%s: stream has not enough bytes (%u)",
+				 peer->host, optlen);
 			bgp_notify_send(peer, BGP_NOTIFY_OPEN_ERR,
 					BGP_NOTIFY_OPEN_MALFORMED_ATTR);
 			return BGP_Stop;
Index: frr-7.5.1/bgpd/bgp_vty.c
===================================================================
--- frr-7.5.1.orig/bgpd/bgp_vty.c
+++ frr-7.5.1/bgpd/bgp_vty.c
@@ -5750,6 +5750,30 @@ DEFUN (no_neighbor_disable_connected_che
 				   PEER_FLAG_DISABLE_CONNECTED_CHECK);
 }
 
+/* extended-optional-parameters */
+DEFUN(neighbor_extended_optional_parameters,
+      neighbor_extended_optional_parameters_cmd,
+      "neighbor <A.B.C.D|X:X::X:X|WORD> extended-optional-parameters",
+      NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+      "Force the extended optional parameters format for OPEN messages\n")
+{
+	int idx_peer = 1;
+
+	return peer_flag_set_vty(vty, argv[idx_peer]->arg,
+				 PEER_FLAG_EXTENDED_OPT_PARAMS);
+}
+
+DEFUN(no_neighbor_extended_optional_parameters,
+      no_neighbor_extended_optional_parameters_cmd,
+      "no neighbor <A.B.C.D|X:X::X:X|WORD> extended-optional-parameters",
+      NO_STR NEIGHBOR_STR NEIGHBOR_ADDR_STR2
+      "Force the extended optional parameters format for OPEN messages\n")
+{
+	int idx_peer = 2;
+
+	return peer_flag_unset_vty(vty, argv[idx_peer]->arg,
+				   PEER_FLAG_EXTENDED_OPT_PARAMS);
+}
 
 /* enforce-first-as */
 DEFUN (neighbor_enforce_first_as,
@@ -11270,6 +11294,14 @@ static void bgp_show_peer(struct vty *vt
 				"bgpTimerConfiguredKeepAliveIntervalMsecs",
 				bgp->default_keepalive);
 		}
+
+		/* Extended Optional Parameters Length for BGP OPEN Message */
+		if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p))
+			json_object_boolean_true_add(
+				json_neigh, "extendedOptionalParametersLength");
+		else
+			json_object_boolean_false_add(
+				json_neigh, "extendedOptionalParametersLength");
 	} else {
 		/* Administrative shutdown. */
 		if (CHECK_FLAG(p->flags, PEER_FLAG_SHUTDOWN)
@@ -11331,6 +11363,11 @@ static void bgp_show_peer(struct vty *vt
 			vty_out(vty, ", keepalive interval is %d seconds\n",
 				bgp->default_keepalive);
 		}
+
+		/* Extended Optional Parameters Length for BGP OPEN Message */
+		if (BGP_OPEN_EXT_OPT_PARAMS_CAPABLE(p))
+			vty_out(vty,
+				"  Extended Optional Parameters Length is enabled\n");
 	}
 	/* Capability. */
 	if (p->status == Established) {
@@ -15047,6 +15084,11 @@ static void bgp_config_write_peer_global
 	if (peergroup_flag_check(peer, PEER_FLAG_DISABLE_CONNECTED_CHECK))
 		vty_out(vty, " neighbor %s disable-connected-check\n", addr);
 
+	/* extended-optional-parameters */
+	if (peergroup_flag_check(peer, PEER_FLAG_EXTENDED_OPT_PARAMS))
+		vty_out(vty, " neighbor %s extended-optional-parameters\n",
+			addr);
+
 	/* enforce-first-as */
 	if (peergroup_flag_check(peer, PEER_FLAG_ENFORCE_FIRST_AS))
 		vty_out(vty, " neighbor %s enforce-first-as\n", addr);
@@ -16841,6 +16883,11 @@ void bgp_vty_init(void)
 	install_element(BGP_NODE, &neighbor_disable_connected_check_cmd);
 	install_element(BGP_NODE, &no_neighbor_disable_connected_check_cmd);
 
+	/* "neighbor extended-optional-parameters" commands.  */
+	install_element(BGP_NODE, &neighbor_extended_optional_parameters_cmd);
+	install_element(BGP_NODE,
+			&no_neighbor_extended_optional_parameters_cmd);
+
 	/* "neighbor enforce-first-as" commands. */
 	install_element(BGP_NODE, &neighbor_enforce_first_as_cmd);
 	install_element(BGP_NODE, &no_neighbor_enforce_first_as_cmd);
Index: frr-7.5.1/bgpd/bgpd.c
===================================================================
--- frr-7.5.1.orig/bgpd/bgpd.c
+++ frr-7.5.1/bgpd/bgpd.c
@@ -3910,6 +3910,7 @@ static const struct peer_flag_action pee
 	{PEER_FLAG_LOCAL_AS_NO_PREPEND, 0, peer_change_none},
 	{PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_none},
 	{PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
+	{PEER_FLAG_EXTENDED_OPT_PARAMS, 0, peer_change_reset},
 	{0, 0, 0}};
 
 static const struct peer_flag_action peer_af_flag_action_list[] = {
Index: frr-7.5.1/bgpd/bgpd.h
===================================================================
--- frr-7.5.1.orig/bgpd/bgpd.h
+++ frr-7.5.1/bgpd/bgpd.h
@@ -1166,6 +1166,8 @@ struct peer {
 #define PEER_FLAG_GRACEFUL_RESTART          (1U << 24) /* Graceful Restart */
 #define PEER_FLAG_GRACEFUL_RESTART_GLOBAL_INHERIT (1U << 25) /* Global-Inherit */
 #define PEER_FLAG_RTT_SHUTDOWN (1U << 26) /* shutdown rtt */
+/* force the extended format for Optional Parameters in OPEN message */
+#define PEER_FLAG_EXTENDED_OPT_PARAMS (1U << 30)
 
 	/*
 	 *GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
@@ -1251,6 +1253,8 @@ struct peer {
 #define PEER_STATUS_GROUP             (1U << 4) /* peer-group conf */
 #define PEER_STATUS_NSF_MODE          (1U << 5) /* NSF aware peer */
 #define PEER_STATUS_NSF_WAIT          (1U << 6) /* wait comeback peer */
+/* received extended format encoding for OPEN message */
+#define PEER_STATUS_EXT_OPT_PARAMS_LENGTH (1U << 7)
 
 	/* Peer status af flags (reset in bgp_stop) */
 	uint16_t af_sflags[AFI_MAX][SAFI_MAX];
