mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-04-28 15:36:25 +00:00
Merge pull request #12727 from opensourcerouting/feature/bgp_software_version_capability
bgpd: Software Version Capability
This commit is contained in:
commit
a15b0b1024
@ -297,6 +297,15 @@ static struct peer *peer_xfer_conn(struct peer *from_peer)
|
||||
from_peer->domainname = NULL;
|
||||
}
|
||||
|
||||
if (peer->soft_version) {
|
||||
XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
|
||||
peer->soft_version = NULL;
|
||||
}
|
||||
if (from_peer->soft_version) {
|
||||
peer->soft_version = from_peer->soft_version;
|
||||
from_peer->soft_version = NULL;
|
||||
}
|
||||
|
||||
FOREACH_AFI_SAFI (afi, safi) {
|
||||
peer->af_sflags[afi][safi] = from_peer->af_sflags[afi][safi];
|
||||
peer->af_cap[afi][safi] = from_peer->af_cap[afi][safi];
|
||||
|
@ -139,3 +139,5 @@ DEFINE_MTYPE(BGPD, BGP_SRV6_FUNCTION, "BGP srv6 function");
|
||||
DEFINE_MTYPE(BGPD, EVPN_REMOTE_IP, "BGP EVPN Remote IP hash entry");
|
||||
|
||||
DEFINE_MTYPE(BGPD, BGP_NOTIFICATION, "BGP Notification Message");
|
||||
|
||||
DEFINE_MTYPE(BGPD, BGP_SOFT_VERSION, "Software Version");
|
||||
|
@ -138,4 +138,6 @@ DECLARE_MTYPE(EVPN_REMOTE_IP);
|
||||
|
||||
DECLARE_MTYPE(BGP_NOTIFICATION);
|
||||
|
||||
DECLARE_MTYPE(BGP_SOFT_VERSION);
|
||||
|
||||
#endif /* _QUAGGA_BGP_MEMORY_H */
|
||||
|
@ -59,6 +59,7 @@ static const struct message capcode_str[] = {
|
||||
{CAPABILITY_CODE_EXT_MESSAGE, "BGP Extended Message"},
|
||||
{CAPABILITY_CODE_LLGR, "Long-lived BGP Graceful Restart"},
|
||||
{CAPABILITY_CODE_ROLE, "Role"},
|
||||
{CAPABILITY_CODE_SOFT_VERSION, "Software Version"},
|
||||
{0}};
|
||||
|
||||
/* Minimum sizes for length field of each cap (so not inc. the header) */
|
||||
@ -79,6 +80,7 @@ static const size_t cap_minsizes[] = {
|
||||
[CAPABILITY_CODE_EXT_MESSAGE] = CAPABILITY_CODE_EXT_MESSAGE_LEN,
|
||||
[CAPABILITY_CODE_LLGR] = CAPABILITY_CODE_LLGR_LEN,
|
||||
[CAPABILITY_CODE_ROLE] = CAPABILITY_CODE_ROLE_LEN,
|
||||
[CAPABILITY_CODE_SOFT_VERSION] = CAPABILITY_CODE_SOFT_VERSION_LEN,
|
||||
};
|
||||
|
||||
/* value the capability must be a multiple of.
|
||||
@ -103,6 +105,7 @@ static const size_t cap_modsizes[] = {
|
||||
[CAPABILITY_CODE_EXT_MESSAGE] = 1,
|
||||
[CAPABILITY_CODE_LLGR] = 1,
|
||||
[CAPABILITY_CODE_ROLE] = 1,
|
||||
[CAPABILITY_CODE_SOFT_VERSION] = 1,
|
||||
};
|
||||
|
||||
/* BGP-4 Multiprotocol Extentions lead us to the complex world. We can
|
||||
@ -921,6 +924,41 @@ static int bgp_capability_role(struct peer *peer, struct capability_header *hdr)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int bgp_capability_software_version(struct peer *peer,
|
||||
struct capability_header *hdr)
|
||||
{
|
||||
struct stream *s = BGP_INPUT(peer);
|
||||
char str[BGP_MAX_SOFT_VERSION + 1];
|
||||
size_t end = stream_get_getp(s) + hdr->length;
|
||||
uint8_t len;
|
||||
|
||||
SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_RCV);
|
||||
|
||||
len = stream_getc(s);
|
||||
if (stream_get_getp(s) + len > end) {
|
||||
flog_warn(
|
||||
EC_BGP_CAPABILITY_INVALID_DATA,
|
||||
"%s: Received malformed Software Version capability from peer %s",
|
||||
__func__, peer->host);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (len) {
|
||||
stream_get(str, s, len);
|
||||
str[len] = '\0';
|
||||
|
||||
XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
|
||||
|
||||
peer->soft_version = XSTRDUP(MTYPE_BGP_SOFT_VERSION, str);
|
||||
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%s sent Software Version: %s", peer->host,
|
||||
peer->soft_version);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse given capability.
|
||||
* XXX: This is reading into a stream, but not using stream API
|
||||
@ -989,6 +1027,7 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
|
||||
case CAPABILITY_CODE_ENHANCED_RR:
|
||||
case CAPABILITY_CODE_EXT_MESSAGE:
|
||||
case CAPABILITY_CODE_ROLE:
|
||||
case CAPABILITY_CODE_SOFT_VERSION:
|
||||
/* Check length. */
|
||||
if (caphdr.length < cap_minsizes[caphdr.code]) {
|
||||
zlog_info(
|
||||
@ -1089,6 +1128,9 @@ static int bgp_capability_parse(struct peer *peer, size_t length,
|
||||
case CAPABILITY_CODE_ROLE:
|
||||
ret = bgp_capability_role(peer, &caphdr);
|
||||
break;
|
||||
case CAPABILITY_CODE_SOFT_VERSION:
|
||||
ret = bgp_capability_software_version(peer, &caphdr);
|
||||
break;
|
||||
default:
|
||||
if (caphdr.code > 128) {
|
||||
/* We don't send Notification for unknown vendor
|
||||
@ -1928,6 +1970,50 @@ uint16_t bgp_open_capability(struct stream *s, struct peer *peer,
|
||||
bgp_peer_send_gr_capability(s, peer, ext_opt_params);
|
||||
bgp_peer_send_llgr_capability(s, peer, ext_opt_params);
|
||||
|
||||
/* Software Version capability
|
||||
* An implementation is REQUIRED Extended Optional Parameters
|
||||
* Length for BGP OPEN Message support as defined in [RFC9072].
|
||||
* The inclusion of the Software Version Capability is OPTIONAL.
|
||||
* If an implementation supports the inclusion of the capability,
|
||||
* the implementation MUST include a configuration switch to enable
|
||||
* or disable its use, and that switch MUST be off by default.
|
||||
*/
|
||||
if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION) ||
|
||||
peer->sort == BGP_PEER_IBGP) {
|
||||
SET_FLAG(peer->cap, PEER_CAP_SOFT_VERSION_ADV);
|
||||
stream_putc(s, BGP_OPEN_OPT_CAP);
|
||||
rcapp = stream_get_endp(s);
|
||||
ext_opt_params ? stream_putw(s, 0)
|
||||
: stream_putc(s, 0); /* Capability Length */
|
||||
stream_putc(s, CAPABILITY_CODE_SOFT_VERSION);
|
||||
capp = stream_get_endp(s);
|
||||
stream_putc(s, 0); /* dummy placeholder len */
|
||||
|
||||
/* The Capability Length SHOULD be no greater than 64.
|
||||
* This is the limit to allow other capabilities as much
|
||||
* space as they require.
|
||||
*/
|
||||
len = strlen(cmd_software_version_get());
|
||||
if (len > BGP_MAX_SOFT_VERSION)
|
||||
len = BGP_MAX_SOFT_VERSION;
|
||||
|
||||
stream_putc(s, len);
|
||||
stream_put(s, cmd_software_version_get(), len);
|
||||
|
||||
/* Software Version capability Len. */
|
||||
len = stream_get_endp(s) - rcapp - 1;
|
||||
ext_opt_params ? stream_putw_at(s, rcapp, len - 1)
|
||||
: stream_putc_at(s, rcapp, len);
|
||||
|
||||
/* Total Capability Len. */
|
||||
len = stream_get_endp(s) - capp - 1;
|
||||
stream_putc_at(s, capp, len);
|
||||
|
||||
if (bgp_debug_neighbor_events(peer))
|
||||
zlog_debug("%s Sending Software Version cap, value: %s",
|
||||
peer->host, cmd_software_version_get());
|
||||
}
|
||||
|
||||
/* Total Opt Parm Len. */
|
||||
len = stream_get_endp(s) - cp - 1;
|
||||
|
||||
|
@ -52,6 +52,7 @@ struct graceful_restart_af {
|
||||
#define CAPABILITY_CODE_ENHANCED_RR 70 /* Enhanced Route Refresh capability */
|
||||
#define CAPABILITY_CODE_LLGR 71 /* Long-lived Graceful Restart */
|
||||
#define CAPABILITY_CODE_FQDN 73 /* Advertise hostname capability */
|
||||
#define CAPABILITY_CODE_SOFT_VERSION 75 /* Software Version capability */
|
||||
#define CAPABILITY_CODE_ENHE 5 /* Extended Next Hop Encoding */
|
||||
#define CAPABILITY_CODE_REFRESH_OLD 128 /* Route Refresh Capability(cisco) */
|
||||
#define CAPABILITY_CODE_ORF_OLD 130 /* Cooperative Route Filtering Capability(cisco) */
|
||||
@ -72,6 +73,7 @@ struct graceful_restart_af {
|
||||
#define CAPABILITY_CODE_ORF_LEN 5
|
||||
#define CAPABILITY_CODE_EXT_MESSAGE_LEN 0 /* Extended Message Support */
|
||||
#define CAPABILITY_CODE_ROLE_LEN 1
|
||||
#define CAPABILITY_CODE_SOFT_VERSION_LEN 1
|
||||
|
||||
/* Cooperative Route Filtering Capability. */
|
||||
|
||||
|
@ -1685,6 +1685,13 @@ static int bgp_open_receive(struct peer *peer, bgp_size_t size)
|
||||
peer->v_keepalive = peer->bgp->default_keepalive;
|
||||
}
|
||||
|
||||
/* If another side disabled sending Software Version capability,
|
||||
* we MUST drop the previous from showing in the outputs to avoid
|
||||
* stale information and due to security reasons.
|
||||
*/
|
||||
if (peer->soft_version)
|
||||
XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
|
||||
|
||||
/* Open option part parse. */
|
||||
if (optlen != 0) {
|
||||
if (bgp_open_option_parse(peer, optlen, &mp_capability) < 0)
|
||||
|
@ -5575,6 +5575,30 @@ DEFUN (no_neighbor_capability_enhe,
|
||||
PEER_FLAG_CAPABILITY_ENHE);
|
||||
}
|
||||
|
||||
/* neighbor capability software-version */
|
||||
DEFPY(neighbor_capability_software_version,
|
||||
neighbor_capability_software_version_cmd,
|
||||
"[no$no] neighbor <A.B.C.D|X:X::X:X|WORD>$neighbor capability software-version",
|
||||
NO_STR
|
||||
NEIGHBOR_STR
|
||||
NEIGHBOR_ADDR_STR2
|
||||
"Advertise capability to the peer\n"
|
||||
"Advertise Software Version capability to the peer\n")
|
||||
{
|
||||
struct peer *peer;
|
||||
|
||||
peer = peer_and_group_lookup_vty(vty, neighbor);
|
||||
if (peer && peer->conf_if)
|
||||
return CMD_SUCCESS;
|
||||
|
||||
if (no)
|
||||
return peer_flag_unset_vty(vty, neighbor,
|
||||
PEER_FLAG_CAPABILITY_SOFT_VERSION);
|
||||
else
|
||||
return peer_flag_set_vty(vty, neighbor,
|
||||
PEER_FLAG_CAPABILITY_SOFT_VERSION);
|
||||
}
|
||||
|
||||
static int peer_af_flag_modify_vty(struct vty *vty, const char *peer_str,
|
||||
afi_t afi, safi_t safi, uint32_t flag,
|
||||
int set)
|
||||
@ -10833,6 +10857,9 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
|
||||
peer_down_str[(int)peer->last_reset]);
|
||||
json_object_int_add(json_peer, "lastResetCode",
|
||||
peer->last_reset);
|
||||
json_object_string_add(json_peer, "softwareVersion",
|
||||
peer->soft_version ? peer->soft_version
|
||||
: "n/a");
|
||||
} else {
|
||||
if (peer->last_reset == PEER_DOWN_NOTIFY_SEND
|
||||
|| peer->last_reset == PEER_DOWN_NOTIFY_RECEIVED) {
|
||||
@ -10851,8 +10878,10 @@ static void bgp_show_peer_reset(struct vty * vty, struct peer *peer,
|
||||
BGP_NOTIFY_CEASE_HARD_RESET)
|
||||
: "");
|
||||
} else {
|
||||
vty_out(vty, " %s\n",
|
||||
peer_down_str[(int)peer->last_reset]);
|
||||
vty_out(vty, " %s (%s)\n",
|
||||
peer_down_str[(int)peer->last_reset],
|
||||
peer->soft_version ? peer->soft_version
|
||||
: "n/a");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -13852,6 +13881,27 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
|
||||
json_object_object_add(json_cap, "hostName",
|
||||
json_hname);
|
||||
|
||||
/* Software Version capability */
|
||||
json_object *json_soft_version = NULL;
|
||||
|
||||
json_soft_version = json_object_new_object();
|
||||
|
||||
if (CHECK_FLAG(p->cap, PEER_CAP_SOFT_VERSION_ADV))
|
||||
json_object_string_add(
|
||||
json_soft_version,
|
||||
"advertisedSoftwareVersion",
|
||||
cmd_software_version_get());
|
||||
|
||||
if (CHECK_FLAG(p->cap, PEER_CAP_SOFT_VERSION_RCV))
|
||||
json_object_string_add(
|
||||
json_soft_version,
|
||||
"receivedSoftwareVersion",
|
||||
p->soft_version ? p->soft_version
|
||||
: "n/a");
|
||||
|
||||
json_object_object_add(json_cap, "softwareVersion",
|
||||
json_soft_version);
|
||||
|
||||
/* Graceful Restart */
|
||||
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) ||
|
||||
CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) {
|
||||
@ -14227,6 +14277,25 @@ static void bgp_show_peer(struct vty *vty, struct peer *p, bool use_json,
|
||||
|
||||
vty_out(vty, "\n");
|
||||
|
||||
/* Software Version capability */
|
||||
vty_out(vty, " Version Capability:");
|
||||
|
||||
if (CHECK_FLAG(p->cap, PEER_CAP_SOFT_VERSION_ADV)) {
|
||||
vty_out(vty,
|
||||
" advertised software version (%s)",
|
||||
cmd_software_version_get());
|
||||
} else
|
||||
vty_out(vty, " not advertised");
|
||||
|
||||
if (CHECK_FLAG(p->cap, PEER_CAP_SOFT_VERSION_RCV)) {
|
||||
vty_out(vty, " received software version (%s)",
|
||||
p->soft_version ? p->soft_version
|
||||
: "n/a");
|
||||
} else
|
||||
vty_out(vty, " not received");
|
||||
|
||||
vty_out(vty, "\n");
|
||||
|
||||
/* Graceful Restart */
|
||||
if (CHECK_FLAG(p->cap, PEER_CAP_RESTART_RCV) ||
|
||||
CHECK_FLAG(p->cap, PEER_CAP_RESTART_ADV)) {
|
||||
@ -16967,7 +17036,7 @@ static void bgp_config_write_redistribute(struct vty *vty, struct bgp *bgp,
|
||||
|
||||
/* peer-group helpers for config-write */
|
||||
|
||||
static bool peergroup_flag_check(struct peer *peer, uint64_t flag)
|
||||
bool peergroup_flag_check(struct peer *peer, uint64_t flag)
|
||||
{
|
||||
if (!peer_group_active(peer)) {
|
||||
if (CHECK_FLAG(peer->flags_invert, flag))
|
||||
@ -17507,6 +17576,11 @@ static void bgp_config_write_peer_global(struct vty *vty, struct bgp *bgp,
|
||||
addr);
|
||||
}
|
||||
|
||||
/* capability software-version */
|
||||
if (peergroup_flag_check(peer, PEER_FLAG_CAPABILITY_SOFT_VERSION))
|
||||
vty_out(vty, " neighbor %s capability software-version\n",
|
||||
addr);
|
||||
|
||||
/* dont-capability-negotiation */
|
||||
if (peergroup_flag_check(peer, PEER_FLAG_DONT_CAPABILITY))
|
||||
vty_out(vty, " neighbor %s dont-capability-negotiate\n", addr);
|
||||
@ -19677,6 +19751,9 @@ void bgp_vty_init(void)
|
||||
install_element(BGP_NODE, &neighbor_capability_enhe_cmd);
|
||||
install_element(BGP_NODE, &no_neighbor_capability_enhe_cmd);
|
||||
|
||||
/* "neighbor capability software-version" commands.*/
|
||||
install_element(BGP_NODE, &neighbor_capability_software_version_cmd);
|
||||
|
||||
/* "neighbor capability orf prefix-list" commands.*/
|
||||
install_element(BGP_NODE, &neighbor_capability_orf_prefix_hidden_cmd);
|
||||
install_element(BGP_NODE,
|
||||
|
@ -181,5 +181,6 @@ int bgp_vty_find_and_parse_bgp(struct vty *vty, struct cmd_token **argv,
|
||||
extern int bgp_show_summary_vty(struct vty *vty, const char *name, afi_t afi,
|
||||
safi_t safi, const char *neighbor, int as_type,
|
||||
as_t as, uint16_t show_flags);
|
||||
extern bool peergroup_flag_check(struct peer *peer, uint64_t flag);
|
||||
|
||||
#endif /* _QUAGGA_BGP_VTY_H */
|
||||
|
11
bgpd/bgpd.c
11
bgpd/bgpd.c
@ -1178,6 +1178,8 @@ static void peer_free(struct peer *peer)
|
||||
|
||||
XFREE(MTYPE_PEER_CONF_IF, peer->conf_if);
|
||||
|
||||
XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
|
||||
|
||||
/* Remove BFD configuration. */
|
||||
if (peer->bfd_config)
|
||||
bgp_peer_remove_bfd_config(peer);
|
||||
@ -2631,6 +2633,7 @@ int peer_delete(struct peer *peer)
|
||||
|
||||
XFREE(MTYPE_BGP_PEER_HOST, peer->hostname);
|
||||
XFREE(MTYPE_BGP_PEER_HOST, peer->domainname);
|
||||
XFREE(MTYPE_BGP_SOFT_VERSION, peer->soft_version);
|
||||
|
||||
peer_unlock(peer); /* initial reference */
|
||||
|
||||
@ -2774,6 +2777,13 @@ static void peer_group2peer_config_copy(struct peer_group *group,
|
||||
if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_ENHE))
|
||||
SET_FLAG(peer->flags, PEER_FLAG_CAPABILITY_ENHE);
|
||||
|
||||
/* capability software-version apply */
|
||||
if (!CHECK_FLAG(peer->flags_override,
|
||||
PEER_FLAG_CAPABILITY_SOFT_VERSION))
|
||||
if (CHECK_FLAG(conf->flags, PEER_FLAG_CAPABILITY_SOFT_VERSION))
|
||||
SET_FLAG(peer->flags,
|
||||
PEER_FLAG_CAPABILITY_SOFT_VERSION);
|
||||
|
||||
/* password apply */
|
||||
if (!CHECK_FLAG(peer->flags_override, PEER_FLAG_PASSWORD))
|
||||
PEER_STR_ATTR_INHERIT(peer, group, password,
|
||||
@ -4386,6 +4396,7 @@ static const struct peer_flag_action peer_flag_action_list[] = {
|
||||
{PEER_FLAG_PORT, 0, peer_change_reset},
|
||||
{PEER_FLAG_AIGP, 0, peer_change_none},
|
||||
{PEER_FLAG_GRACEFUL_SHUTDOWN, 0, peer_change_none},
|
||||
{PEER_FLAG_CAPABILITY_SOFT_VERSION, 0, peer_change_reset},
|
||||
{0, 0, 0}};
|
||||
|
||||
static const struct peer_flag_action peer_af_flag_action_list[] = {
|
||||
|
@ -1250,6 +1250,8 @@ struct peer {
|
||||
#define PEER_CAP_GRACEFUL_RESTART_N_BIT_RCV (1U << 24)
|
||||
#define PEER_CAP_ROLE_ADV (1U << 25) /* role advertised */
|
||||
#define PEER_CAP_ROLE_RCV (1U << 26) /* role received */
|
||||
#define PEER_CAP_SOFT_VERSION_ADV (1U << 27)
|
||||
#define PEER_CAP_SOFT_VERSION_RCV (1U << 28)
|
||||
|
||||
/* Capability flags (reset in bgp_stop) */
|
||||
uint32_t af_cap[AFI_MAX][SAFI_MAX];
|
||||
@ -1376,6 +1378,7 @@ struct peer {
|
||||
#define PEER_FLAG_PORT (1ULL << 33)
|
||||
#define PEER_FLAG_AIGP (1ULL << 34)
|
||||
#define PEER_FLAG_GRACEFUL_SHUTDOWN (1ULL << 35)
|
||||
#define PEER_FLAG_CAPABILITY_SOFT_VERSION (1ULL << 36)
|
||||
|
||||
/*
|
||||
*GR-Disabled mode means unset PEER_FLAG_GRACEFUL_RESTART
|
||||
@ -1771,6 +1774,10 @@ struct peer {
|
||||
/* Path attributes treat-as-withdraw */
|
||||
bool withdraw_attrs[BGP_ATTR_MAX];
|
||||
|
||||
/* BGP Software Version Capability */
|
||||
#define BGP_MAX_SOFT_VERSION 64
|
||||
char *soft_version;
|
||||
|
||||
QOBJ_FIELDS;
|
||||
};
|
||||
DECLARE_QOBJ_TYPE(peer);
|
||||
|
@ -2020,10 +2020,17 @@ Capability Negotiation
|
||||
|
||||
.. clicmd:: neighbor PEER override-capability
|
||||
|
||||
|
||||
Override the result of Capability Negotiation with local configuration.
|
||||
Ignore remote peer's capability value.
|
||||
|
||||
.. clicmd:: neighbor PEER capability software-version
|
||||
|
||||
Send the software version in the BGP OPEN message to the neighbor. This is
|
||||
very useful in environments with a large amount of peers with different
|
||||
versions of FRR or any other vendor.
|
||||
|
||||
Disabled by default.
|
||||
|
||||
.. _bgp-as-path-access-lists:
|
||||
|
||||
AS Path Access Lists
|
||||
|
@ -127,6 +127,11 @@ bool cmd_allow_reserved_ranges_get(void)
|
||||
return host.allow_reserved_ranges;
|
||||
}
|
||||
|
||||
const char *cmd_software_version_get(void)
|
||||
{
|
||||
return FRR_FULL_NAME "/" FRR_VERSION;
|
||||
}
|
||||
|
||||
static int root_on_exit(struct vty *vty);
|
||||
|
||||
/* Standard command node structures. */
|
||||
|
@ -606,6 +606,7 @@ extern const char *cmd_domainname_get(void);
|
||||
extern const char *cmd_system_get(void);
|
||||
extern const char *cmd_release_get(void);
|
||||
extern const char *cmd_version_get(void);
|
||||
extern const char *cmd_software_version_get(void);
|
||||
extern bool cmd_allow_reserved_ranges_get(void);
|
||||
|
||||
/* NOT safe for general use; call this only if DEV_BUILD! */
|
||||
|
@ -176,9 +176,9 @@ struct test_peer_attr {
|
||||
|
||||
enum test_peer_attr_type type;
|
||||
union {
|
||||
uint32_t flag;
|
||||
uint64_t flag;
|
||||
struct {
|
||||
uint32_t flag;
|
||||
uint64_t flag;
|
||||
size_t direct;
|
||||
} filter;
|
||||
} u;
|
||||
@ -281,6 +281,18 @@ static struct test_peer_attr test_peer_attrs[] = {
|
||||
.o.invert_peer = true,
|
||||
.o.use_iface_peer = true,
|
||||
},
|
||||
{
|
||||
.cmd = "capability software-version",
|
||||
.u.flag = PEER_FLAG_CAPABILITY_SOFT_VERSION,
|
||||
.type = PEER_AT_GLOBAL_FLAG,
|
||||
},
|
||||
{
|
||||
.cmd = "capability software-version",
|
||||
.u.flag = PEER_FLAG_CAPABILITY_SOFT_VERSION,
|
||||
.type = PEER_AT_GLOBAL_FLAG,
|
||||
.o.invert_peer = true,
|
||||
.o.use_iface_peer = true,
|
||||
},
|
||||
{
|
||||
.cmd = "description",
|
||||
.peer_cmd = "description FRR Peer",
|
||||
|
0
tests/topotests/bgp_software_version/__init__.py
Normal file
0
tests/topotests/bgp_software_version/__init__.py
Normal file
8
tests/topotests/bgp_software_version/r1/bgpd.conf
Normal file
8
tests/topotests/bgp_software_version/r1/bgpd.conf
Normal file
@ -0,0 +1,8 @@
|
||||
!
|
||||
router bgp 65001
|
||||
no bgp ebgp-requires-policy
|
||||
neighbor 192.168.1.2 remote-as external
|
||||
neighbor 192.168.1.2 timers 1 3
|
||||
neighbor 192.168.1.2 timers connect 1
|
||||
neighbor 192.168.1.2 capability software-version
|
||||
!
|
4
tests/topotests/bgp_software_version/r1/zebra.conf
Normal file
4
tests/topotests/bgp_software_version/r1/zebra.conf
Normal file
@ -0,0 +1,4 @@
|
||||
!
|
||||
int r1-eth0
|
||||
ip address 192.168.1.1/24
|
||||
!
|
7
tests/topotests/bgp_software_version/r2/bgpd.conf
Normal file
7
tests/topotests/bgp_software_version/r2/bgpd.conf
Normal file
@ -0,0 +1,7 @@
|
||||
router bgp 65002
|
||||
no bgp ebgp-requires-policy
|
||||
neighbor 192.168.1.1 remote-as external
|
||||
neighbor 192.168.1.1 timers 1 3
|
||||
neighbor 192.168.1.1 timers connect 1
|
||||
neighbor 192.168.1.1 capability software-version
|
||||
!
|
4
tests/topotests/bgp_software_version/r2/zebra.conf
Normal file
4
tests/topotests/bgp_software_version/r2/zebra.conf
Normal file
@ -0,0 +1,4 @@
|
||||
!
|
||||
int r2-eth0
|
||||
ip address 192.168.1.2/24
|
||||
!
|
@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2022 by
|
||||
# Donatas Abraitis <donatas@opensourcerouting.org>
|
||||
#
|
||||
# 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 Software Version capability works if forced with a knob.
|
||||
Reference: https://datatracker.ietf.org/doc/html/draft-abraitis-bgp-version-capability
|
||||
"""
|
||||
|
||||
import os
|
||||
import re
|
||||
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_software_version():
|
||||
tgen = get_topogen()
|
||||
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
r1 = tgen.gears["r1"]
|
||||
|
||||
def _bgp_converge():
|
||||
output = json.loads(r1.vtysh_cmd("show bgp summary json"))
|
||||
expected = {"ipv4Unicast": {"peers": {"192.168.1.2": {"state": "Established"}}}}
|
||||
return topotest.json_cmp(output, expected)
|
||||
|
||||
test_func = functools.partial(
|
||||
_bgp_converge,
|
||||
)
|
||||
_, result = topotest.run_and_expect(test_func, None, count=60, wait=0.5)
|
||||
assert result is None, "Can't converge"
|
||||
|
||||
def _bgp_check_software_version():
|
||||
output = json.loads(r1.vtysh_cmd("show bgp neighbor 192.168.1.2 json"))
|
||||
|
||||
try:
|
||||
versions = output["192.168.1.2"]["neighborCapabilities"]["softwareVersion"]
|
||||
adv = versions["advertisedSoftwareVersion"]
|
||||
rcv = versions["receivedSoftwareVersion"]
|
||||
|
||||
if not adv and not rcv:
|
||||
return False
|
||||
|
||||
pattern = "^FRRouting/\\d.+"
|
||||
if re.search(pattern, adv) and re.search(pattern, rcv):
|
||||
return True
|
||||
except:
|
||||
return False
|
||||
|
||||
return False
|
||||
|
||||
assert _bgp_check_software_version(), "Neighbor's software version is n/a"
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
Loading…
Reference in New Issue
Block a user