Merge pull request #10105 from ton31337/feature/rfc9072

bgpd: Implement rfc9072
This commit is contained in:
Russ White 2021-11-29 10:46:58 -05:00 committed by GitHub
commit 5c24a442d9
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
14 changed files with 349 additions and 54 deletions

View File

@ -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;
}

View File

@ -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 */

View File

@ -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;

View File

@ -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);

View File

@ -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[] = {

View File

@ -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];

View File

@ -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

View File

@ -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
----

View File

@ -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
!

View File

@ -0,0 +1,4 @@
!
int r1-eth0
ip address 192.168.1.1/24
!

View File

@ -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
!

View File

@ -0,0 +1,7 @@
!
int lo
ip address 172.16.16.1/32
!
int r2-eth0
ip address 192.168.1.2/24
!

View File

@ -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))