summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--bgpd/bgp_open.c140
-rw-r--r--bgpd/bgp_open.h15
-rw-r--r--bgpd/bgp_packet.c53
-rw-r--r--bgpd/bgp_vty.c47
-rw-r--r--bgpd/bgpd.c1
-rw-r--r--bgpd/bgpd.h4
-rw-r--r--doc/user/bgp.rst9
-rw-r--r--doc/user/overview.rst3
-rw-r--r--tests/topotests/bgp_extended_optional_parameters_length/__init__.py0
-rw-r--r--tests/topotests/bgp_extended_optional_parameters_length/r1/bgpd.conf6
-rw-r--r--tests/topotests/bgp_extended_optional_parameters_length/r1/zebra.conf4
-rw-r--r--tests/topotests/bgp_extended_optional_parameters_length/r2/bgpd.conf8
-rw-r--r--tests/topotests/bgp_extended_optional_parameters_length/r2/zebra.conf7
-rw-r--r--tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py106
14 files changed, 349 insertions, 54 deletions
diff --git a/bgpd/bgp_open.c b/bgpd/bgp_open.c
index 523e6cdf97..a05921e7b6 100644
--- a/bgpd/bgp_open.c
+++ b/bgpd/bgp_open.c
@@ -1091,7 +1091,7 @@ static bool strict_capability_same(struct peer *peer)
/* 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);
@@ -1107,7 +1107,7 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length)
*/
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)
@@ -1115,7 +1115,9 @@ as_t peek_for_as4_capability(struct peer *peer, uint8_t length)
/* 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)
@@ -1163,7 +1165,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;
@@ -1182,7 +1185,7 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
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) {
@@ -1194,11 +1197,14 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
/* 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;
@@ -1302,9 +1308,10 @@ int bgp_open_option_parse(struct peer *peer, uint8_t length, int *mp_capability)
}
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;
@@ -1318,7 +1325,8 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
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 */
@@ -1366,11 +1374,12 @@ static void bgp_open_capability_orf(struct stream *s, struct peer *peer,
/* 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;
@@ -1392,7 +1401,8 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
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);
@@ -1447,11 +1457,12 @@ static void bgp_peer_send_gr_capability(struct stream *s, struct peer *peer,
/* 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);
}
static void bgp_peer_send_llgr_capability(struct stream *s, struct peer *peer,
- unsigned long cp)
+ bool ext_opt_params)
{
int len;
iana_afi_t pkt_afi;
@@ -1468,7 +1479,8 @@ static void bgp_peer_send_llgr_capability(struct stream *s, struct peer *peer,
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_LLGR);
rcapp = stream_get_endp(s);
@@ -1494,14 +1506,16 @@ static void bgp_peer_send_llgr_capability(struct stream *s, struct peer *peer,
/* 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;
@@ -1510,16 +1524,26 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
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) {
@@ -1530,7 +1554,9 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
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);
@@ -1550,7 +1576,13 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
*/
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);
@@ -1571,25 +1603,29 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
/* 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);
/* Enhanced Route Refresh. */
SET_FLAG(peer->cap, PEER_CAP_ENHANCED_RR_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2);
+ ext_opt_params ? stream_putw(s, CAPABILITY_CODE_ENHANCED_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_ENHANCED_LEN + 2);
stream_putc(s, CAPABILITY_CODE_ENHANCED_RR);
stream_putc(s, CAPABILITY_CODE_ENHANCED_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)
@@ -1601,7 +1637,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
/* Extended Message Support */
SET_FLAG(peer->cap, PEER_CAP_EXTENDED_MESSAGE_ADV);
stream_putc(s, BGP_OPEN_OPT_CAP);
- stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2);
+ ext_opt_params ? stream_putw(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2)
+ : stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN + 2);
stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE);
stream_putc(s, CAPABILITY_CODE_EXT_MESSAGE_LEN);
@@ -1620,7 +1657,11 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
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);
@@ -1667,9 +1708,11 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
|| 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);
}
}
@@ -1677,11 +1720,15 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
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);
}
@@ -1691,7 +1738,8 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
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 */
@@ -1713,7 +1761,9 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
/* 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);
@@ -1724,10 +1774,18 @@ void bgp_open_capability(struct stream *s, struct peer *peer)
cmd_domainname_get());
}
- bgp_peer_send_gr_capability(s, peer, cp);
- bgp_peer_send_llgr_capability(s, peer, cp);
+ bgp_peer_send_gr_capability(s, peer, ext_opt_params);
+ bgp_peer_send_llgr_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;
}
diff --git a/bgpd/bgp_open.h b/bgpd/bgp_open.h
index 0d616926a2..c04816c006 100644
--- a/bgpd/bgp_open.h
+++ b/bgpd/bgp_open.h
@@ -93,10 +93,19 @@ struct graceful_restart_af {
/* Long-lived Graceful Restart */
#define LLGR_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 */
diff --git a/bgpd/bgp_packet.c b/bgpd/bgp_packet.c
index de9a89523b..319213ef76 100644
--- a/bgpd/bgp_packet.c
+++ b/bgpd/bgp_packet.c
@@ -608,8 +608,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);
@@ -1136,7 +1150,7 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
{
int ret;
uint8_t version;
- uint8_t optlen;
+ uint16_t optlen;
uint16_t holdtime;
uint16_t send_holdtime;
as_t remote_as;
@@ -1157,19 +1171,40 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
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 %pI4",
- peer->host, version, remote_as, holdtime, &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;
diff --git a/bgpd/bgp_vty.c b/bgpd/bgp_vty.c
index d1a28876eb..8a63030181 100644
--- a/bgpd/bgp_vty.c
+++ b/bgpd/bgp_vty.c
@@ -6302,6 +6302,30 @@ DEFUN(no_neighbor_disable_link_bw_encoding_ieee,
PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE);
}
+/* 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,
@@ -12497,6 +12521,14 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
"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)
@@ -12569,6 +12601,11 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
vty_out(vty, " Configured tcp-mss is %d", p->tcp_mss);
vty_out(vty, ", synced tcp-mss is %d\n", sync_tcp_mss);
}
+
+ /* 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 (peer_established(p)) {
@@ -16636,6 +16673,11 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
vty_out(vty, " neighbor %s disable-link-bw-encoding-ieee\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);
@@ -18593,6 +18635,11 @@ void bgp_vty_init(void)
install_element(BGP_NODE,
&no_neighbor_disable_link_bw_encoding_ieee_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);
diff --git a/bgpd/bgpd.c b/bgpd/bgpd.c
index 877585cec1..5cc5feba3a 100644
--- a/bgpd/bgpd.c
+++ b/bgpd/bgpd.c
@@ -4181,6 +4181,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
{PEER_FLAG_LOCAL_AS_REPLACE_AS, 0, peer_change_none},
{PEER_FLAG_UPDATE_SOURCE, 0, peer_change_none},
{PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE, 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[] = {
diff --git a/bgpd/bgpd.h b/bgpd/bgpd.h
index 29775bccce..7c91065601 100644
--- a/bgpd/bgpd.h
+++ b/bgpd/bgpd.h
@@ -1298,6 +1298,8 @@ struct peer {
* extended communities.
*/
#define PEER_FLAG_DISABLE_LINK_BW_ENCODING_IEEE (1U << 29)
+/* 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
@@ -1384,6 +1386,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];
diff --git a/doc/user/bgp.rst b/doc/user/bgp.rst
index 4e996aa69c..2f8c5c01da 100644
--- a/doc/user/bgp.rst
+++ b/doc/user/bgp.rst
@@ -1423,6 +1423,15 @@ Configuring Peers
value is carried encoded as uint32. To enable backward compatibility we
need to disable IEEE floating-point encoding option per-peer.
+.. clicmd:: neighbor PEER extended-optional-parameters
+
+ Force Extended Optional Parameters Length format to be used for OPEN messages.
+
+ By default, it's disabled. If the standard optional parameters length is
+ higher than one-octet (255), then extended format is enabled automatically.
+
+ For testing purposes, extended format can be enabled with this command.
+
.. clicmd:: neighbor PEER ebgp-multihop
Specifying ``ebgp-multihop`` allows sessions with eBGP neighbors to
diff --git a/doc/user/overview.rst b/doc/user/overview.rst
index efe64b72f0..acae3eb27b 100644
--- a/doc/user/overview.rst
+++ b/doc/user/overview.rst
@@ -371,7 +371,8 @@ BGP
:t:`Using BGP to Bind MPLS Labels to Address Prefixes. E. Rosen. October 2017`
- :rfc:`8654`
:t:`Extended Message Support for BGP. R. Bush, K. Patel, D. Ward. October 2019`
-
+- :rfc:`9072`
+ :t:`Extended Optional Parameters Length for BGP OPEN Message. E. Chen, J. Scudder. July 2021`
OSPF
----
diff --git a/tests/topotests/bgp_extended_optional_parameters_length/__init__.py b/tests/topotests/bgp_extended_optional_parameters_length/__init__.py
new file mode 100644
index 0000000000..e69de29bb2
--- /dev/null
+++ b/tests/topotests/bgp_extended_optional_parameters_length/__init__.py
diff --git a/tests/topotests/bgp_extended_optional_parameters_length/r1/bgpd.conf b/tests/topotests/bgp_extended_optional_parameters_length/r1/bgpd.conf
new file mode 100644
index 0000000000..d83013ca99
--- /dev/null
+++ b/tests/topotests/bgp_extended_optional_parameters_length/r1/bgpd.conf
@@ -0,0 +1,6 @@
+!
+router bgp 65001
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.2 remote-as external
+ neighbor 192.168.1.2 extended-optional-parameters
+!
diff --git a/tests/topotests/bgp_extended_optional_parameters_length/r1/zebra.conf b/tests/topotests/bgp_extended_optional_parameters_length/r1/zebra.conf
new file mode 100644
index 0000000000..b29940f46a
--- /dev/null
+++ b/tests/topotests/bgp_extended_optional_parameters_length/r1/zebra.conf
@@ -0,0 +1,4 @@
+!
+int r1-eth0
+ ip address 192.168.1.1/24
+!
diff --git a/tests/topotests/bgp_extended_optional_parameters_length/r2/bgpd.conf b/tests/topotests/bgp_extended_optional_parameters_length/r2/bgpd.conf
new file mode 100644
index 0000000000..e390d6ed8d
--- /dev/null
+++ b/tests/topotests/bgp_extended_optional_parameters_length/r2/bgpd.conf
@@ -0,0 +1,8 @@
+router bgp 65002
+ no bgp ebgp-requires-policy
+ neighbor 192.168.1.1 remote-as external
+ neighbor 192.168.1.1 extended-optional-parameters
+ address-family ipv4 unicast
+ redistribute connected
+ exit-address-family
+!
diff --git a/tests/topotests/bgp_extended_optional_parameters_length/r2/zebra.conf b/tests/topotests/bgp_extended_optional_parameters_length/r2/zebra.conf
new file mode 100644
index 0000000000..dc15cf756a
--- /dev/null
+++ b/tests/topotests/bgp_extended_optional_parameters_length/r2/zebra.conf
@@ -0,0 +1,7 @@
+!
+int lo
+ ip address 172.16.16.1/32
+!
+int r2-eth0
+ ip address 192.168.1.2/24
+!
diff --git a/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py
new file mode 100644
index 0000000000..e677dc6ff6
--- /dev/null
+++ b/tests/topotests/bgp_extended_optional_parameters_length/test_bgp_extended_optional_parameters_length.py
@@ -0,0 +1,106 @@
+#!/usr/bin/env python
+
+# Copyright (c) 2021 by
+# Donatas Abraitis <donatas.abraitis@gmail.com>
+#
+# Permission to use, copy, modify, and/or distribute this software
+# for any purpose with or without fee is hereby granted, provided
+# that the above copyright notice and this permission notice appear
+# in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND NETDEF DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL NETDEF BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY
+# DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
+# WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
+# ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE
+# OF THIS SOFTWARE.
+#
+
+"""
+Test if Extended Optional Parameters Length encoding format works
+if forced with a knob.
+https://datatracker.ietf.org/doc/html/rfc9072
+"""
+
+import os
+import sys
+import json
+import pytest
+import functools
+
+pytestmark = pytest.mark.bgpd
+
+CWD = os.path.dirname(os.path.realpath(__file__))
+sys.path.append(os.path.join(CWD, "../"))
+
+# pylint: disable=C0413
+from lib import topotest
+from lib.topogen import Topogen, TopoRouter, get_topogen
+
+pytestmark = [pytest.mark.bgpd]
+
+
+def setup_module(mod):
+ topodef = {"s1": ("r1", "r2")}
+ tgen = Topogen(topodef, mod.__name__)
+ tgen.start_topology()
+
+ router_list = tgen.routers()
+
+ for i, (rname, router) in enumerate(router_list.items(), 1):
+ router.load_config(
+ TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname))
+ )
+ router.load_config(
+ TopoRouter.RD_BGP, os.path.join(CWD, "{}/bgpd.conf".format(rname))
+ )
+
+ tgen.start_router()
+
+
+def teardown_module(mod):
+ tgen = get_topogen()
+ tgen.stop_topology()
+
+
+def test_bgp_extended_optional_parameters_length():
+ tgen = get_topogen()
+
+ if tgen.routers_have_failure():
+ pytest.skip(tgen.errors)
+
+ router = tgen.gears["r1"]
+
+ def _bgp_converge(router):
+ output = json.loads(router.vtysh_cmd("show bgp ipv4 unicast summary json"))
+ expected = {
+ "peers": {
+ "192.168.1.2": {
+ "pfxRcd": 2,
+ "pfxSnt": 2,
+ "state": "Established",
+ "peerState": "OK",
+ }
+ }
+ }
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_converge, router)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't converge with extended-optional-parameters"
+
+ def _bgp_extended_optional_parameters_length(router):
+ output = json.loads(router.vtysh_cmd("show bgp neighbor 192.168.1.2 json"))
+ expected = {"192.168.1.2": {"extendedOptionalParametersLength": True}}
+ return topotest.json_cmp(output, expected)
+
+ test_func = functools.partial(_bgp_extended_optional_parameters_length, router)
+ _, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
+ assert result is None, "Can't see Extended Optional Parameters Length to be used"
+
+
+if __name__ == "__main__":
+ args = ["-s"] + sys.argv[1:]
+ sys.exit(pytest.main(args))