mirror of
https://git.proxmox.com/git/mirror_frr
synced 2025-08-05 15:10:38 +00:00
Merge pull request #17639 from pguibert6WIND/bmp_import_vrf_view
Ability to import BMP information from a separate BGP instance
This commit is contained in:
commit
b4619da938
803
bgpd/bgp_bmp.c
803
bgpd/bgp_bmp.c
File diff suppressed because it is too large
Load Diff
@ -92,7 +92,7 @@ struct bmp_mirrorq {
|
||||
uint8_t data[0];
|
||||
};
|
||||
|
||||
enum {
|
||||
enum bmp_afi_state {
|
||||
BMP_AFI_INACTIVE = 0,
|
||||
BMP_AFI_NEEDSYNC,
|
||||
BMP_AFI_SYNC,
|
||||
@ -148,6 +148,7 @@ struct bmp {
|
||||
uint64_t syncpeerid;
|
||||
afi_t syncafi;
|
||||
safi_t syncsafi;
|
||||
struct bgp *sync_bgp;
|
||||
};
|
||||
|
||||
/* config & state for an active outbound connection. When the connection
|
||||
@ -195,6 +196,9 @@ struct bmp_listener {
|
||||
int sock;
|
||||
};
|
||||
|
||||
/* config for imported bgp instances */
|
||||
PREDECL_SORTLIST_UNIQ(bmp_imported_bgps);
|
||||
|
||||
/* bmp_targets - plural since it may contain multiple bmp_listener &
|
||||
* bmp_active items. If they have the same config, BMP session should be
|
||||
* put in the same targets since that's a bit more effective.
|
||||
@ -206,6 +210,7 @@ struct bmp_targets {
|
||||
|
||||
struct bmp_bgp *bmpbgp;
|
||||
struct bgp *bgp;
|
||||
bool bgp_request_sync[AFI_MAX][SAFI_MAX];
|
||||
char *name;
|
||||
|
||||
struct bmp_listeners_head listeners;
|
||||
@ -238,6 +243,8 @@ struct bmp_targets {
|
||||
struct bmp_qhash_head locupdhash;
|
||||
struct bmp_qlist_head locupdlist;
|
||||
|
||||
struct bmp_imported_bgps_head imported_bgps;
|
||||
|
||||
uint64_t cnt_accept, cnt_aclrefused;
|
||||
|
||||
bool stats_send_experimental;
|
||||
@ -274,6 +281,14 @@ enum bmp_vrf_state {
|
||||
vrf_state_up = 1,
|
||||
};
|
||||
|
||||
struct bmp_imported_bgp {
|
||||
struct bmp_imported_bgps_item bib;
|
||||
struct bmp_targets *targets;
|
||||
char *name;
|
||||
enum bmp_vrf_state vrf_state;
|
||||
bool bgp_request_sync[AFI_MAX][SAFI_MAX];
|
||||
};
|
||||
|
||||
struct bmp_bgp {
|
||||
struct bmp_bgph_item bbi;
|
||||
|
||||
@ -289,7 +304,8 @@ struct bmp_bgp {
|
||||
size_t mirror_qsizelimit;
|
||||
};
|
||||
|
||||
extern bool bmp_bgp_update_vrf_status(struct bmp_bgp *bmpbgp, enum bmp_vrf_state force);
|
||||
extern bool bmp_bgp_update_vrf_status(enum bmp_vrf_state *vrf_state, struct bgp *bgp,
|
||||
enum bmp_vrf_state force);
|
||||
|
||||
enum {
|
||||
/* RFC7854 - 10.8 */
|
||||
|
@ -135,12 +135,13 @@ TRACEPOINT_LOGLEVEL(frr_bgp, bmp_mirror_packet, TRACE_INFO)
|
||||
TRACEPOINT_EVENT(
|
||||
frr_bgp,
|
||||
bmp_eor,
|
||||
TP_ARGS(afi_t, afi, safi_t, safi, uint8_t, flags, uint8_t, peer_type_flag),
|
||||
TP_ARGS(afi_t, afi, safi_t, safi, uint8_t, flags, uint8_t, peer_type_flag, bgp),
|
||||
TP_FIELDS(
|
||||
ctf_integer(afi_t, afi, afi)
|
||||
ctf_integer(safi_t, safi, safi)
|
||||
ctf_integer(uint8_t, flags, flags)
|
||||
ctf_integer(uint8_t, peer_type_flag, peer_type_flag)
|
||||
ctf_string(bgp, bgp->name_pretty)
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -171,3 +171,8 @@ associated with a particular ``bmp targets``:
|
||||
|
||||
All BGP neighbors are included in Route Mirroring. Options to select
|
||||
a subset of BGP sessions may be added in the future.
|
||||
|
||||
.. clicmd:: bmp import-vrf-view VRF_OR_VIEW_NAME
|
||||
|
||||
Perform Route Mirroring and Route Monitoring from an other BGP
|
||||
instance.
|
||||
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"loc-rib": {
|
||||
"update": {
|
||||
"172.31.0.77/32": {
|
||||
"as_path": "",
|
||||
"bgp_nexthop": "192.168.1.3",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"is_filtered": false,
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.0.1",
|
||||
"peer_distinguisher": "444:1",
|
||||
"peer_type": "loc-rib instance",
|
||||
"policy": "loc-rib"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"as_path": "",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"is_filtered": false,
|
||||
"nxhp_ip": "192:167::3",
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.0.1",
|
||||
"peer_distinguisher": "555:1",
|
||||
"peer_type": "loc-rib instance",
|
||||
"policy": "loc-rib",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"loc-rib": {
|
||||
"update": {
|
||||
"172.31.0.77/32": {
|
||||
"as_path": "",
|
||||
"bgp_nexthop": "192.168.1.3",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"is_filtered": false,
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.0.1",
|
||||
"peer_distinguisher": "666:22",
|
||||
"peer_type": "loc-rib instance",
|
||||
"policy": "loc-rib"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"as_path": "",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"is_filtered": false,
|
||||
"nxhp_ip": "192:167::3",
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.0.1",
|
||||
"peer_distinguisher": "666:22",
|
||||
"peer_type": "loc-rib instance",
|
||||
"policy": "loc-rib",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"post-policy": {
|
||||
"update": {
|
||||
"172.31.0.77/32": {
|
||||
"as_path": "",
|
||||
"bgp_nexthop": "192.168.1.3",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"ipv6": false,
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "444:1",
|
||||
"peer_ip": "192.168.1.3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "post-policy"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"as_path": "",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"ipv6": true,
|
||||
"nxhp_ip": "192:167::3",
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "555:1",
|
||||
"peer_ip": "192:167::3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "post-policy",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"post-policy": {
|
||||
"update": {
|
||||
"172.31.0.77/32": {
|
||||
"as_path": "",
|
||||
"bgp_nexthop": "192.168.1.3",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"ipv6": false,
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "666:22",
|
||||
"peer_ip": "192.168.1.3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "post-policy"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"as_path": "",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"ipv6": true,
|
||||
"nxhp_ip": "192:167::3",
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "666:22",
|
||||
"peer_ip": "192:167::3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "post-policy",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"pre-policy": {
|
||||
"update": {
|
||||
"172.31.0.77/32": {
|
||||
"as_path": "",
|
||||
"bgp_nexthop": "192.168.1.3",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"ipv6": false,
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "444:1",
|
||||
"peer_ip": "192.168.1.3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "pre-policy"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"as_path": "",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"ipv6": true,
|
||||
"nxhp_ip": "192:167::3",
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "555:1",
|
||||
"peer_ip": "192:167::3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "pre-policy",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
{
|
||||
"pre-policy": {
|
||||
"update": {
|
||||
"172.31.0.77/32": {
|
||||
"as_path": "",
|
||||
"bgp_nexthop": "192.168.1.3",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"ipv6": false,
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "666:22",
|
||||
"peer_ip": "192.168.1.3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "pre-policy"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"as_path": "",
|
||||
"bmp_log_type": "update",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"ipv6": true,
|
||||
"nxhp_ip": "192:167::3",
|
||||
"origin": "IGP",
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "666:22",
|
||||
"peer_ip": "192:167::3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "pre-policy",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,28 @@
|
||||
{
|
||||
"loc-rib": {
|
||||
"withdraw": {
|
||||
"172.31.0.77/32": {
|
||||
"bmp_log_type": "withdraw",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"is_filtered": false,
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.0.1",
|
||||
"peer_distinguisher": "444:1",
|
||||
"peer_type": "loc-rib instance",
|
||||
"policy": "loc-rib"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"bmp_log_type": "withdraw",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"is_filtered": false,
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.0.1",
|
||||
"peer_distinguisher": "555:1",
|
||||
"peer_type": "loc-rib instance",
|
||||
"policy": "loc-rib",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"loc-rib": {
|
||||
"withdraw": {
|
||||
"172.31.0.15/32": {
|
||||
"afi": 1,
|
||||
"bmp_log_type": "withdraw",
|
||||
"ip_prefix": "172.31.0.15/32",
|
||||
"is_filtered": false,
|
||||
"label": 0,
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.0.1",
|
||||
"peer_distinguisher": "0:0",
|
||||
"peer_type": "loc-rib instance",
|
||||
"policy": "loc-rib",
|
||||
"rd": "444:2",
|
||||
"safi": 128
|
||||
},
|
||||
"2001::1111/128": {
|
||||
"afi": 2,
|
||||
"bmp_log_type": "withdraw",
|
||||
"ip_prefix": "2001::1111/128",
|
||||
"is_filtered": false,
|
||||
"label": 0,
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.0.1",
|
||||
"peer_distinguisher": "0:0",
|
||||
"peer_type": "loc-rib instance",
|
||||
"policy": "loc-rib",
|
||||
"rd": "555:2",
|
||||
"safi": 128
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
{
|
||||
"post-policy": {
|
||||
"withdraw": {
|
||||
"172.31.0.77/32": {
|
||||
"bmp_log_type": "withdraw",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"ipv6": false,
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "444:1",
|
||||
"peer_ip": "192.168.1.3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "post-policy"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"bmp_log_type": "withdraw",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"ipv6": true,
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "555:1",
|
||||
"peer_ip": "192:167::3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "post-policy",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
{
|
||||
"pre-policy": {
|
||||
"withdraw": {
|
||||
"172.31.0.77/32": {
|
||||
"bmp_log_type": "withdraw",
|
||||
"ip_prefix": "172.31.0.77/32",
|
||||
"ipv6": false,
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "444:1",
|
||||
"peer_ip": "192.168.1.3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "pre-policy"
|
||||
},
|
||||
"2001::1125/128": {
|
||||
"afi": 2,
|
||||
"bmp_log_type": "withdraw",
|
||||
"ip_prefix": "2001::1125/128",
|
||||
"ipv6": true,
|
||||
"peer_asn": 65501,
|
||||
"peer_bgp_id": "192.168.1.3",
|
||||
"peer_distinguisher": "555:1",
|
||||
"peer_ip": "192:167::3",
|
||||
"peer_type": "route distinguisher instance",
|
||||
"policy": "pre-policy",
|
||||
"safi": 1
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
73
tests/topotests/bgp_bmp/r1import/frr.conf
Normal file
73
tests/topotests/bgp_bmp/r1import/frr.conf
Normal file
@ -0,0 +1,73 @@
|
||||
interface r1import-eth0
|
||||
ip address 192.0.2.1/24
|
||||
!
|
||||
interface r1import-eth1
|
||||
ip address 192.168.0.1/24
|
||||
ipv6 address 192:168::1/64
|
||||
!
|
||||
interface r1import-eth2
|
||||
ip address 192.168.1.1/24
|
||||
ipv6 address 192:167::1/64
|
||||
!
|
||||
router bgp 65501
|
||||
bgp router-id 192.168.0.1
|
||||
bgp log-neighbor-changes
|
||||
no bgp ebgp-requires-policy
|
||||
neighbor 192.168.0.2 remote-as 65502
|
||||
neighbor 192:168::2 remote-as 65502
|
||||
!
|
||||
bmp targets bmp1
|
||||
bmp connect 192.0.2.10 port 1789 min-retry 100 max-retry 10000
|
||||
bmp monitor ipv4 unicast pre-policy
|
||||
bmp monitor ipv6 unicast pre-policy
|
||||
bmp monitor ipv4 unicast post-policy
|
||||
bmp monitor ipv6 unicast post-policy
|
||||
bmp monitor ipv4 unicast loc-rib
|
||||
bmp monitor ipv6 unicast loc-rib
|
||||
bmp import-vrf-view vrf1
|
||||
exit
|
||||
!
|
||||
address-family ipv4 vpn
|
||||
neighbor 192.168.0.2 activate
|
||||
neighbor 192.168.0.2 soft-reconfiguration inbound
|
||||
exit-address-family
|
||||
address-family ipv6 vpn
|
||||
neighbor 192:168::2 activate
|
||||
neighbor 192:168::2 soft-reconfiguration inbound
|
||||
exit-address-family
|
||||
address-family ipv4 unicast
|
||||
neighbor 192.168.0.2 activate
|
||||
neighbor 192.168.0.2 soft-reconfiguration inbound
|
||||
no neighbor 192:168::2 activate
|
||||
exit-address-family
|
||||
!
|
||||
address-family ipv6 unicast
|
||||
neighbor 192:168::2 activate
|
||||
neighbor 192:168::2 soft-reconfiguration inbound
|
||||
exit-address-family
|
||||
!
|
||||
router bgp 65501 vrf vrf1
|
||||
bgp router-id 192.168.0.1
|
||||
bgp log-neighbor-changes
|
||||
neighbor 192.168.1.3 remote-as 65501
|
||||
neighbor 192:167::3 remote-as 65501
|
||||
address-family ipv4 unicast
|
||||
neighbor 192.168.1.3 activate
|
||||
neighbor 192.168.1.3 soft-reconfiguration inbound
|
||||
no neighbor 192:167::3 activate
|
||||
label vpn export 101
|
||||
rd vpn export 444:1
|
||||
rt vpn both 52:100
|
||||
export vpn
|
||||
import vpn
|
||||
exit-address-family
|
||||
address-family ipv6 unicast
|
||||
neighbor 192:167::3 activate
|
||||
neighbor 192:167::3 soft-reconfiguration inbound
|
||||
label vpn export 103
|
||||
rd vpn export 555:1
|
||||
rt vpn both 54:200
|
||||
export vpn
|
||||
import vpn
|
||||
exit-address-family
|
||||
exit
|
@ -0,0 +1,21 @@
|
||||
{
|
||||
"routes": {
|
||||
"172.31.0.77/32": [
|
||||
{
|
||||
"bestpath": true,
|
||||
"pathFrom": "internal",
|
||||
"path": "",
|
||||
"origin": "IGP",
|
||||
"nexthops": [
|
||||
{
|
||||
"ip": "192.168.1.3",
|
||||
"hostname": "r3",
|
||||
"afi": "ipv4",
|
||||
"used": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"routes": {
|
||||
"172.31.0.77/32": null
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,27 @@
|
||||
{
|
||||
"routes": {
|
||||
"2001::1125/128": [
|
||||
{
|
||||
"bestpath": true,
|
||||
"pathFrom": "internal",
|
||||
"path": "",
|
||||
"origin": "IGP",
|
||||
"nexthops": [
|
||||
{
|
||||
"ip": "192:167::3",
|
||||
"hostname": "r3",
|
||||
"afi": "ipv6",
|
||||
"scope": "global"
|
||||
},
|
||||
{
|
||||
"hostname": "r3",
|
||||
"afi": "ipv6",
|
||||
"scope": "link-local",
|
||||
"used": true
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,6 @@
|
||||
{
|
||||
"routes": {
|
||||
"2001::1125/128": null
|
||||
}
|
||||
}
|
||||
|
18
tests/topotests/bgp_bmp/r3/frr.conf
Normal file
18
tests/topotests/bgp_bmp/r3/frr.conf
Normal file
@ -0,0 +1,18 @@
|
||||
interface r3-eth0
|
||||
ip address 192.168.1.3/24
|
||||
ipv6 address 192:167::3/64
|
||||
!
|
||||
router bgp 65501
|
||||
bgp router-id 192.168.1.3
|
||||
bgp log-neighbor-changes
|
||||
no bgp network import-check
|
||||
neighbor 192.168.1.1 remote-as 65501
|
||||
neighbor 192:167::1 remote-as 65501
|
||||
address-family ipv4 unicast
|
||||
neighbor 192.168.1.1 activate
|
||||
no neighbor 192:167::1 activate
|
||||
exit-address-family
|
||||
address-family ipv6 unicast
|
||||
neighbor 192:167::1 activate
|
||||
exit-address-family
|
||||
exit
|
567
tests/topotests/bgp_bmp/test_bgp_bmp_3.py
Normal file
567
tests/topotests/bgp_bmp/test_bgp_bmp_3.py
Normal file
@ -0,0 +1,567 @@
|
||||
#!/usr/bin/env python
|
||||
# SPDX-License-Identifier: ISC
|
||||
|
||||
# Copyright 2024 6WIND S.A.
|
||||
#
|
||||
|
||||
"""
|
||||
test_bgp_bmp.py_3: Test BGP BMP functionalities
|
||||
|
||||
+------+ +------+ +------+
|
||||
| | | | | |
|
||||
| BMP1 |------------| R1 |---------------| R2 |
|
||||
| | | | | |
|
||||
+------+ +--+---+ +------+
|
||||
|
|
||||
+--+---+
|
||||
| |
|
||||
| R3 |
|
||||
| |
|
||||
+------+
|
||||
|
||||
Setup two routers R1 and R2 with one link configured with IPv4 and
|
||||
IPv6 addresses.
|
||||
Configure BGP in R1 and R2 to exchange prefixes from
|
||||
the latter to the first router.
|
||||
Setup a link between R1 and the BMP server, activate the BMP feature in R1
|
||||
and ensure the monitored BGP sessions logs are well present on the BMP server.
|
||||
"""
|
||||
|
||||
from functools import partial
|
||||
import json
|
||||
import os
|
||||
import pytest
|
||||
import sys
|
||||
|
||||
# Save the Current Working Directory to find configuration files.
|
||||
CWD = os.path.dirname(os.path.realpath(__file__))
|
||||
sys.path.append(os.path.join("../"))
|
||||
sys.path.append(os.path.join("../lib/"))
|
||||
|
||||
# pylint: disable=C0413
|
||||
# Import topogen and topotest helpers
|
||||
from lib import topotest
|
||||
from lib.bgp import verify_bgp_convergence_from_running_config
|
||||
from lib.bgp import bgp_configure_prefixes
|
||||
from .bgpbmp import (
|
||||
bmp_check_for_prefixes,
|
||||
bmp_check_for_peer_message,
|
||||
bmp_update_seq,
|
||||
bmp_reset_seq,
|
||||
)
|
||||
from lib.topogen import Topogen, TopoRouter, get_topogen
|
||||
from lib.topolog import logger
|
||||
|
||||
pytestmark = [pytest.mark.bgpd]
|
||||
|
||||
PRE_POLICY = "pre-policy"
|
||||
POST_POLICY = "post-policy"
|
||||
LOC_RIB = "loc-rib"
|
||||
|
||||
UPDATE_EXPECTED_JSON = False
|
||||
DEBUG_PCAP = False
|
||||
|
||||
|
||||
def build_topo(tgen):
|
||||
tgen.add_router("r1import")
|
||||
tgen.add_router("r2")
|
||||
tgen.add_router("r3") # CPE behind r1
|
||||
|
||||
tgen.add_bmp_server("bmp1import", ip="192.0.2.10", defaultRoute="via 192.0.2.1")
|
||||
|
||||
switch = tgen.add_switch("s1")
|
||||
switch.add_link(tgen.gears["r1import"])
|
||||
switch.add_link(tgen.gears["bmp1import"])
|
||||
|
||||
tgen.add_link(tgen.gears["r1import"], tgen.gears["r2"], "r1import-eth1", "r2-eth0")
|
||||
tgen.add_link(tgen.gears["r1import"], tgen.gears["r3"], "r1import-eth2", "r3-eth0")
|
||||
|
||||
|
||||
def setup_module(mod):
|
||||
tgen = Topogen(build_topo, mod.__name__)
|
||||
tgen.start_topology()
|
||||
|
||||
tgen.net["r1import"].cmd(
|
||||
"""
|
||||
ip link add vrf1 type vrf table 10
|
||||
ip link set vrf1 up
|
||||
ip link set r1import-eth2 master vrf1
|
||||
"""
|
||||
)
|
||||
|
||||
bmp_reset_seq()
|
||||
if DEBUG_PCAP:
|
||||
tgen.gears["r1import"].run("rm /tmp/bmp.pcap")
|
||||
tgen.gears["r1import"].run(
|
||||
"tcpdump -nni r1import-eth0 -s 0 -w /tmp/bmp.pcap &", stdout=None
|
||||
)
|
||||
|
||||
for rname, router in tgen.routers().items():
|
||||
logger.info("Loading router %s" % rname)
|
||||
router.load_frr_config(
|
||||
os.path.join(CWD, "{}/frr.conf".format(rname)),
|
||||
[(TopoRouter.RD_ZEBRA, None), (TopoRouter.RD_BGP, "-M bmp")],
|
||||
)
|
||||
|
||||
tgen.start_router()
|
||||
|
||||
logger.info("starting BMP servers")
|
||||
for bmp_name, server in tgen.get_bmp_servers().items():
|
||||
server.start(log_file=os.path.join(tgen.logdir, bmp_name, "bmp.log"))
|
||||
|
||||
|
||||
def teardown_module(_mod):
|
||||
tgen = get_topogen()
|
||||
tgen.stop_topology()
|
||||
|
||||
|
||||
def test_bgp_convergence():
|
||||
tgen = get_topogen()
|
||||
if tgen.routers_have_failure():
|
||||
pytest.skip(tgen.errors)
|
||||
|
||||
result = verify_bgp_convergence_from_running_config(tgen, dut="r1import")
|
||||
assert result is True, "BGP is not converging"
|
||||
|
||||
|
||||
def _test_prefixes_syncro(policy, vrf=None, step=1):
|
||||
"""
|
||||
Check that the given policy has syncronised the previously received BGP
|
||||
updates.
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
prefixes = ["172.31.0.77/32", "2001::1125/128"]
|
||||
# check
|
||||
test_func = partial(
|
||||
bmp_check_for_prefixes,
|
||||
prefixes,
|
||||
"update",
|
||||
policy,
|
||||
step,
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import"),
|
||||
tgen.gears["r1import"],
|
||||
f"{CWD}/bmp1import",
|
||||
UPDATE_EXPECTED_JSON,
|
||||
LOC_RIB,
|
||||
)
|
||||
success, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||
assert success, "Checking the updated prefixes has failed ! %s" % res
|
||||
|
||||
|
||||
def _test_prefixes(policy, vrf=None, step=0):
|
||||
"""
|
||||
Setup the BMP monitor policy, Add and withdraw ipv4/v6 prefixes.
|
||||
Check if the previous actions are logged in the BMP server with the right
|
||||
message type and the right policy.
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
safi = "vpn" if vrf else "unicast"
|
||||
|
||||
prefixes = ["172.31.0.77/32", "2001::1125/128"]
|
||||
|
||||
for type in ("update", "withdraw"):
|
||||
bmp_update_seq(
|
||||
tgen.gears["bmp1import"], os.path.join(tgen.logdir, "bmp1import", "bmp.log")
|
||||
)
|
||||
|
||||
bgp_configure_prefixes(
|
||||
tgen.gears["r3"],
|
||||
65501,
|
||||
"unicast",
|
||||
prefixes,
|
||||
vrf=None,
|
||||
update=(type == "update"),
|
||||
)
|
||||
|
||||
logger.info(f"checking for prefixes {type}")
|
||||
|
||||
for ipver in [4, 6]:
|
||||
if UPDATE_EXPECTED_JSON:
|
||||
continue
|
||||
ref_file = "{}/r1import/show-bgp-{}-ipv{}-{}-step{}.json".format(
|
||||
CWD, vrf, ipver, type, step
|
||||
)
|
||||
expected = json.loads(open(ref_file).read())
|
||||
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp,
|
||||
tgen.gears["r1import"],
|
||||
f"show bgp vrf {vrf} ipv{ipver} json",
|
||||
expected,
|
||||
)
|
||||
_, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||
assertmsg = f"r1: BGP IPv{ipver} convergence failed"
|
||||
assert res is None, assertmsg
|
||||
|
||||
# check
|
||||
test_func = partial(
|
||||
bmp_check_for_prefixes,
|
||||
prefixes,
|
||||
type,
|
||||
policy,
|
||||
step,
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import"),
|
||||
tgen.gears["r1import"],
|
||||
f"{CWD}/bmp1import",
|
||||
UPDATE_EXPECTED_JSON,
|
||||
LOC_RIB,
|
||||
)
|
||||
success, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||
assert success, "Checking the updated prefixes has failed ! %s" % res
|
||||
|
||||
|
||||
def _test_peer_up(check_locrib=True):
|
||||
"""
|
||||
Checking for BMP peers up messages
|
||||
"""
|
||||
|
||||
tgen = get_topogen()
|
||||
if check_locrib:
|
||||
peers = ["0.0.0.0", "192.168.1.3", "192:167::3"]
|
||||
else:
|
||||
peers = ["192.168.1.3", "192:167::3"]
|
||||
|
||||
logger.info("checking for BMP peers up messages")
|
||||
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer up",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
is_rd_instance=True,
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert success, "Checking the updated prefixes has been failed !."
|
||||
|
||||
|
||||
def test_bmp_server_logging():
|
||||
"""
|
||||
Assert the logging of the bmp server.
|
||||
"""
|
||||
|
||||
def check_for_log_file():
|
||||
tgen = get_topogen()
|
||||
output = tgen.gears["bmp1import"].run(
|
||||
"ls {}".format(os.path.join(tgen.logdir, "bmp1import"))
|
||||
)
|
||||
if "bmp.log" not in output:
|
||||
return False
|
||||
return True
|
||||
|
||||
success, _ = topotest.run_and_expect(check_for_log_file, True, count=30, wait=1)
|
||||
assert success, "The BMP server is not logging"
|
||||
|
||||
|
||||
def test_bmp_peer_up_start():
|
||||
_test_peer_up()
|
||||
|
||||
|
||||
def test_bmp_bgp_unicast():
|
||||
"""
|
||||
Add/withdraw bgp unicast prefixes and check the bmp logs.
|
||||
"""
|
||||
logger.info("*** Unicast prefixes pre-policy logging ***")
|
||||
_test_prefixes(PRE_POLICY, vrf="vrf1", step=1)
|
||||
logger.info("*** Unicast prefixes post-policy logging ***")
|
||||
_test_prefixes(POST_POLICY, vrf="vrf1", step=1)
|
||||
logger.info("*** Unicast prefixes loc-rib logging ***")
|
||||
_test_prefixes(LOC_RIB, vrf="vrf1", step=1)
|
||||
|
||||
|
||||
def test_peer_down():
|
||||
"""
|
||||
Checking for BMP peers down messages
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
tgen.gears["r3"].vtysh_cmd("clear bgp *")
|
||||
|
||||
peers = ["192.168.1.3", "192:167::3"]
|
||||
|
||||
logger.info("checking for BMP peers down messages")
|
||||
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer down",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert success, "Checking the updated prefixes has been failed !."
|
||||
|
||||
|
||||
def test_reconfigure_prefixes():
|
||||
"""
|
||||
Reconfigured BGP networks from R3. Check for BGP VRF update messages
|
||||
"""
|
||||
|
||||
tgen = get_topogen()
|
||||
|
||||
prefixes = ["172.31.0.77/32", "2001::1125/128"]
|
||||
bgp_configure_prefixes(
|
||||
tgen.gears["r3"],
|
||||
65501,
|
||||
"unicast",
|
||||
prefixes,
|
||||
vrf=None,
|
||||
update=True,
|
||||
)
|
||||
|
||||
for ipver in [4, 6]:
|
||||
ref_file = "{}/r1import/show-bgp-{}-ipv{}-{}-step{}.json".format(
|
||||
CWD, "vrf1", ipver, "update", 1
|
||||
)
|
||||
expected = json.loads(open(ref_file).read())
|
||||
|
||||
test_func = partial(
|
||||
topotest.router_json_cmp,
|
||||
tgen.gears["r1import"],
|
||||
f"show bgp vrf vrf1 ipv{ipver} json",
|
||||
expected,
|
||||
)
|
||||
_, res = topotest.run_and_expect(test_func, None, count=30, wait=1)
|
||||
assertmsg = f"r1: BGP IPv{ipver} convergence failed"
|
||||
assert res is None, assertmsg
|
||||
|
||||
|
||||
def test_monitor_syncro():
|
||||
"""
|
||||
Checking for BMP peers down messages
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
tgen.gears["r1import"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
router bgp 65501
|
||||
bmp targets bmp1
|
||||
bmp import-vrf-view vrf1
|
||||
"""
|
||||
)
|
||||
|
||||
logger.info("*** Unicast prefixes pre-policy logging ***")
|
||||
_test_prefixes_syncro(PRE_POLICY, vrf="vrf1")
|
||||
logger.info("*** Unicast prefixes post-policy logging ***")
|
||||
_test_prefixes_syncro(POST_POLICY, vrf="vrf1")
|
||||
logger.info("*** Unicast prefixes loc-rib logging ***")
|
||||
_test_prefixes_syncro(LOC_RIB, vrf="vrf1")
|
||||
|
||||
|
||||
def test_reconfigure_route_distinguisher_vrf1():
|
||||
"""
|
||||
Checking for BMP peers down messages
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
bmp_update_seq(
|
||||
tgen.gears["bmp1import"], os.path.join(tgen.logdir, "bmp1import", "bmp.log")
|
||||
)
|
||||
peers = ["0.0.0.0"]
|
||||
|
||||
tgen.gears["r1import"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
router bgp 65501 vrf vrf1
|
||||
address-family ipv4 unicast
|
||||
rd vpn export 666:22
|
||||
exit-address-family
|
||||
address-family ipv6 unicast
|
||||
rd vpn export 666:22
|
||||
"""
|
||||
)
|
||||
logger.info(
|
||||
"Checking for BMP peer down LOC-RIB message with route-distinguisher set to 444:1"
|
||||
)
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer down",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
is_rd_instance=True,
|
||||
peer_distinguisher="444:1",
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert (
|
||||
success
|
||||
), "Checking the BMP peer down LOC-RIB message with route-distinguisher set to 444:1 failed !."
|
||||
|
||||
logger.info(
|
||||
"Checking for BMP peer up LOC-RIB messages with route-distinguisher set to 666:22"
|
||||
)
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer up",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
is_rd_instance=True,
|
||||
peer_distinguisher="666:22",
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert (
|
||||
success
|
||||
), "Checking the BMP peer up LOC-RIB message with route-distinguisher set to 666:22 failed !."
|
||||
|
||||
logger.info(
|
||||
"Checking for BMP peer up messages with route-distinguisher set to 666:22"
|
||||
)
|
||||
peers = ["192.168.1.3", "192:167::3"]
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer up",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
is_rd_instance=True,
|
||||
peer_distinguisher="666:22",
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert (
|
||||
success
|
||||
), "Checking the BMP peer up messages with route-distinguisher set to 666:22 failed !."
|
||||
|
||||
logger.info("*** Unicast prefixes pre-policy logging ***")
|
||||
_test_prefixes_syncro(PRE_POLICY, vrf="vrf1", step=2)
|
||||
logger.info("*** Unicast prefixes post-policy logging ***")
|
||||
_test_prefixes_syncro(POST_POLICY, vrf="vrf1", step=2)
|
||||
logger.info("*** Unicast prefixes loc-rib logging ***")
|
||||
_test_prefixes_syncro(LOC_RIB, vrf="vrf1", step=2)
|
||||
|
||||
|
||||
def test_bgp_routerid_changed():
|
||||
"""
|
||||
Checking for BGP loc-rib up messages with new router-id
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
tgen.gears["r1import"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
router bgp 65501 vrf vrf1
|
||||
bgp router-id 192.168.1.77
|
||||
"""
|
||||
)
|
||||
|
||||
peers = ["0.0.0.0"]
|
||||
|
||||
logger.info(
|
||||
"checking for BMP peer down LOC-RIB message with router-id set to 192.168.0.1."
|
||||
)
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer down",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
is_rd_instance=True,
|
||||
peer_bgp_id="192.168.0.1",
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert (
|
||||
success
|
||||
), "Checking the BMP peer down LOC-RIB message with router-id set to 192.168.0.1 failed !."
|
||||
|
||||
logger.info(
|
||||
"checking for BMP peer up LOC-RIB message with router-id set to 192.168.1.77."
|
||||
)
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer up",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
is_rd_instance=True,
|
||||
peer_bgp_id="192.168.1.77",
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert (
|
||||
success
|
||||
), "Checking the BMP peer up LOC-RIB message with router-id set to 192.168.1.77 failed !."
|
||||
|
||||
|
||||
def test_bgp_instance_flapping():
|
||||
"""
|
||||
Checking for BGP loc-rib up messages
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
# create flapping at BMP
|
||||
# note: only peer up are handled at BMP level today
|
||||
tgen.net["r1import"].cmd("ip link set dev vrf1 down")
|
||||
|
||||
peers = ["0.0.0.0"]
|
||||
|
||||
logger.info("checking for BMP peer down LOC-RIB message.")
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer down",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
is_rd_instance=True,
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert success, "Checking the BMP peer down LOC-RIB message failed !."
|
||||
|
||||
tgen.net["r1import"].cmd("ip link set dev vrf1 up")
|
||||
|
||||
logger.info("checking for BMP peer up LOC-RIB message.")
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer up",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
is_rd_instance=True,
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert success, "Checking the BMP peer up LOC-RIB message failed !."
|
||||
|
||||
|
||||
def test_peer_up_after_flush():
|
||||
"""
|
||||
Checking for BMP peers down messages
|
||||
"""
|
||||
_test_peer_up(check_locrib=False)
|
||||
|
||||
|
||||
def test_peer_down_locrib():
|
||||
"""
|
||||
Checking for BMP peers down loc-rib messages
|
||||
"""
|
||||
tgen = get_topogen()
|
||||
|
||||
tgen.gears["r1import"].vtysh_cmd(
|
||||
"""
|
||||
configure terminal
|
||||
router bgp 65501
|
||||
bmp targets bmp1
|
||||
no bmp import-vrf-view vrf1
|
||||
"""
|
||||
)
|
||||
|
||||
peers = ["0.0.0.0"]
|
||||
|
||||
logger.info("checking for BMP peers down messages")
|
||||
|
||||
test_func = partial(
|
||||
bmp_check_for_peer_message,
|
||||
peers,
|
||||
"peer down",
|
||||
tgen.gears["bmp1import"],
|
||||
os.path.join(tgen.logdir, "bmp1import", "bmp.log"),
|
||||
)
|
||||
success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1)
|
||||
assert success, "Checking the BMP peer down message has failed !."
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
args = ["-s"] + sys.argv[1:]
|
||||
sys.exit(pytest.main(args))
|
Loading…
Reference in New Issue
Block a user