diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-update-loc-rib-step1.json b/tests/topotests/bgp_bmp/bmp1/bmp-update-loc-rib-step1.json new file mode 100644 index 0000000000..ae5e921779 --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-update-loc-rib-step1.json @@ -0,0 +1,34 @@ +{ + "loc-rib": { + "update": { + "172.31.0.15/32": { + "as_path": "65501 65502", + "bgp_nexthop": "192.168.0.2", + "bmp_log_type": "update", + "ip_prefix": "172.31.0.15/32", + "is_filtered": false, + "origin": "IGP", + "peer_asn": 65501, + "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "0:0", + "peer_type": "loc-rib instance", + "policy": "loc-rib" + }, + "2111::1111/128": { + "afi": 2, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "2111::1111/128", + "is_filtered": false, + "nxhp_ip": "192:168::2", + "origin": "IGP", + "peer_asn": 65501, + "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "0:0", + "peer_type": "loc-rib instance", + "policy": "loc-rib", + "safi": 1 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-update-loc-rib-step2.json b/tests/topotests/bgp_bmp/bmp1/bmp-update-loc-rib-step2.json new file mode 100644 index 0000000000..3e07369a79 --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-update-loc-rib-step2.json @@ -0,0 +1,43 @@ +{ + "loc-rib": { + "update": { + "2001::2222/128": { + "afi": 2, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "2001::2222/128", + "is_filtered": false, + "label": 105, + "nxhp_ip": "192:168::2", + "nxhp_rd1": "0:0", + "nxhp_rd2": "0:0", + "origin": "IGP", + "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 + }, + "172.31.10.1/32": { + "afi": 1, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "172.31.10.1/32", + "is_filtered": false, + "label": 102, + "nxhp_ip": "192.168.0.2", + "nxhp_rd": "0:0", + "origin": "IGP", + "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 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-update-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1/bmp-update-post-policy-step1.json new file mode 100644 index 0000000000..d5d9d65182 --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-update-post-policy-step1.json @@ -0,0 +1,36 @@ +{ + "post-policy": { + "update": { + "172.31.0.15/32": { + "as_path": "65501 65502", + "bgp_nexthop": "192.168.0.2", + "bmp_log_type": "update", + "ip_prefix": "172.31.0.15/32", + "ipv6": false, + "origin": "IGP", + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192.168.0.2", + "peer_type": "global instance", + "policy": "post-policy" + }, + "2111::1111/128": { + "afi": 2, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "2111::1111/128", + "ipv6": true, + "nxhp_ip": "192:168::2", + "origin": "IGP", + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192:168::2", + "peer_type": "global instance", + "policy": "post-policy", + "safi": 1 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-update-post-policy-step2.json b/tests/topotests/bgp_bmp/bmp1/bmp-update-post-policy-step2.json new file mode 100644 index 0000000000..4b49b249f0 --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-update-post-policy-step2.json @@ -0,0 +1,45 @@ +{ + "post-policy": { + "update": { + "172.31.10.1/32": { + "afi": 1, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "172.31.10.1/32", + "ipv6": false, + "label": 102, + "nxhp_ip": "192.168.0.2", + "nxhp_rd": "0:0", + "origin": "IGP", + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192.168.0.2", + "peer_type": "global instance", + "policy": "post-policy", + "rd": "444:2", + "safi": 128 + }, + "2001::2222/128": { + "afi": 2, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "2001::2222/128", + "ipv6": true, + "label": 105, + "nxhp_ip": "192:168::2", + "nxhp_rd1": "0:0", + "nxhp_rd2": "0:0", + "origin": "IGP", + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192:168::2", + "peer_type": "global instance", + "policy": "post-policy", + "rd": "555:2", + "safi": 128 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-update-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1/bmp-update-pre-policy-step1.json new file mode 100644 index 0000000000..e11badc040 --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-update-pre-policy-step1.json @@ -0,0 +1,36 @@ +{ + "pre-policy": { + "update": { + "172.31.0.15/32": { + "as_path": "65501 65502", + "bgp_nexthop": "192.168.0.2", + "bmp_log_type": "update", + "ip_prefix": "172.31.0.15/32", + "ipv6": false, + "origin": "IGP", + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192.168.0.2", + "peer_type": "global instance", + "policy": "pre-policy" + }, + "2111::1111/128": { + "afi": 2, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "2111::1111/128", + "ipv6": true, + "nxhp_ip": "192:168::2", + "origin": "IGP", + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192:168::2", + "peer_type": "global instance", + "policy": "pre-policy", + "safi": 1 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-update-pre-policy-step2.json b/tests/topotests/bgp_bmp/bmp1/bmp-update-pre-policy-step2.json new file mode 100644 index 0000000000..4cd0c03b3b --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-update-pre-policy-step2.json @@ -0,0 +1,45 @@ +{ + "pre-policy": { + "update": { + "172.31.10.1/32": { + "afi": 1, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "172.31.10.1/32", + "ipv6": false, + "label": 102, + "nxhp_ip": "192.168.0.2", + "nxhp_rd": "0:0", + "origin": "IGP", + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192.168.0.2", + "peer_type": "global instance", + "policy": "pre-policy", + "rd": "444:2", + "safi": 128 + }, + "2001::2222/128": { + "afi": 2, + "as_path": "65501 65502", + "bmp_log_type": "update", + "ip_prefix": "2001::2222/128", + "ipv6": true, + "label": 105, + "nxhp_ip": "192:168::2", + "nxhp_rd1": "0:0", + "nxhp_rd2": "0:0", + "origin": "IGP", + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192:168::2", + "peer_type": "global instance", + "policy": "pre-policy", + "rd": "555:2", + "safi": 128 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-loc-rib-step1.json b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-loc-rib-step1.json new file mode 100644 index 0000000000..345b52d4bf --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-loc-rib-step1.json @@ -0,0 +1,28 @@ +{ + "loc-rib": { + "withdraw": { + "172.31.0.15/32": { + "bmp_log_type": "withdraw", + "ip_prefix": "172.31.0.15/32", + "is_filtered": false, + "peer_asn": 65501, + "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "0:0", + "peer_type": "loc-rib instance", + "policy": "loc-rib" + }, + "2111::1111/128": { + "afi": 2, + "bmp_log_type": "withdraw", + "ip_prefix": "2111::1111/128", + "is_filtered": false, + "peer_asn": 65501, + "peer_bgp_id": "192.168.0.1", + "peer_distinguisher": "0:0", + "peer_type": "loc-rib instance", + "policy": "loc-rib", + "safi": 1 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-loc-rib-step2.json b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-loc-rib-step2.json new file mode 100644 index 0000000000..63f48533c7 --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-loc-rib-step2.json @@ -0,0 +1,34 @@ +{ + "loc-rib": { + "withdraw": { + "172.31.10.1/32": { + "afi": 1, + "bmp_log_type": "withdraw", + "ip_prefix": "172.31.10.1/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::2222/128": { + "afi": 2, + "bmp_log_type": "withdraw", + "ip_prefix": "2001::2222/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 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-post-policy-step1.json b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-post-policy-step1.json new file mode 100644 index 0000000000..de84307a4e --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-post-policy-step1.json @@ -0,0 +1,30 @@ +{ + "post-policy": { + "withdraw": { + "172.31.0.15/32": { + "bmp_log_type": "withdraw", + "ip_prefix": "172.31.0.15/32", + "ipv6": false, + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192.168.0.2", + "peer_type": "global instance", + "policy": "post-policy" + }, + "2111::1111/128": { + "afi": 2, + "bmp_log_type": "withdraw", + "ip_prefix": "2111::1111/128", + "ipv6": true, + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192:168::2", + "peer_type": "global instance", + "policy": "post-policy", + "safi": 1 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-post-policy-step2.json b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-post-policy-step2.json new file mode 100644 index 0000000000..4e1afcda22 --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-post-policy-step2.json @@ -0,0 +1,36 @@ +{ + "post-policy": { + "withdraw": { + "2001::2222/128": { + "afi": 2, + "bmp_log_type": "withdraw", + "ip_prefix": "2001::2222/128", + "ipv6": true, + "label": 0, + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192:168::2", + "peer_type": "global instance", + "policy": "post-policy", + "rd": "555:2", + "safi": 128 + }, + "172.31.10.1/32": { + "afi": 1, + "bmp_log_type": "withdraw", + "ip_prefix": "172.31.10.1/32", + "ipv6": false, + "label": 0, + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192.168.0.2", + "peer_type": "global instance", + "policy": "post-policy", + "rd": "444:2", + "safi": 128 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-pre-policy-step1.json b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-pre-policy-step1.json new file mode 100644 index 0000000000..1c34498b7a --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-pre-policy-step1.json @@ -0,0 +1,30 @@ +{ + "pre-policy": { + "withdraw": { + "172.31.0.15/32": { + "bmp_log_type": "withdraw", + "ip_prefix": "172.31.0.15/32", + "ipv6": false, + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192.168.0.2", + "peer_type": "global instance", + "policy": "pre-policy" + }, + "2111::1111/128": { + "afi": 2, + "bmp_log_type": "withdraw", + "ip_prefix": "2111::1111/128", + "ipv6": true, + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192:168::2", + "peer_type": "global instance", + "policy": "pre-policy", + "safi": 1 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-pre-policy-step2.json b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-pre-policy-step2.json new file mode 100644 index 0000000000..0a4a6404ad --- /dev/null +++ b/tests/topotests/bgp_bmp/bmp1/bmp-withdraw-pre-policy-step2.json @@ -0,0 +1,36 @@ +{ + "pre-policy": { + "withdraw": { + "2001::2222/128": { + "afi": 2, + "bmp_log_type": "withdraw", + "ip_prefix": "2001::2222/128", + "ipv6": true, + "label": 0, + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192:168::2", + "peer_type": "global instance", + "policy": "pre-policy", + "rd": "555:2", + "safi": 128 + }, + "172.31.10.1/32": { + "afi": 1, + "bmp_log_type": "withdraw", + "ip_prefix": "172.31.10.1/32", + "ipv6": false, + "label": 0, + "peer_asn": 65502, + "peer_bgp_id": "192.168.0.2", + "peer_distinguisher": "0:0", + "peer_ip": "192.168.0.2", + "peer_type": "global instance", + "policy": "pre-policy", + "rd": "444:2", + "safi": 128 + } + } + } +} diff --git a/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-update-step1.json b/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-update-step1.json new file mode 100644 index 0000000000..038c87ca9d --- /dev/null +++ b/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-update-step1.json @@ -0,0 +1,21 @@ +{ + "routes": { + "172.31.0.15/32": [ + { + "bestpath": true, + "pathFrom": "external", + "path": "65502", + "origin": "IGP", + "nexthops": [ + { + "ip": "192.168.0.2", + "hostname": "r2", + "afi": "ipv4", + "used": true + } + ] + } + ] + } +} + diff --git a/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-update-step2.json b/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-update-step2.json new file mode 100644 index 0000000000..e0eb712eff --- /dev/null +++ b/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-update-step2.json @@ -0,0 +1,25 @@ +{ + "routes": { + "routeDistinguishers": { + "444:2": { + "172.31.10.1/32": [ + { + "bestpath": true, + "pathFrom": "external", + "path": "65502", + "origin": "IGP", + "nexthops": [ + { + "ip": "192.168.0.2", + "hostname": "r2", + "afi": "ipv4", + "used": true + } + ] + } + ] + } + } + } +} + diff --git a/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-withdraw-step1.json b/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-withdraw-step1.json new file mode 100644 index 0000000000..6a77813776 --- /dev/null +++ b/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-withdraw-step1.json @@ -0,0 +1,6 @@ +{ + "routes": { + "172.31.0.15/32": null + } +} + diff --git a/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-withdraw-step2.json b/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-withdraw-step2.json new file mode 100644 index 0000000000..1c94a1a722 --- /dev/null +++ b/tests/topotests/bgp_bmp/r1/show-bgp-ipv4-withdraw-step2.json @@ -0,0 +1,10 @@ +{ + "routes": { + "routeDistinguishers": { + "444:2": { + "172.31.10.1/32": null + } + } + } +} + diff --git a/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-update-step1.json b/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-update-step1.json new file mode 100644 index 0000000000..db34220149 --- /dev/null +++ b/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-update-step1.json @@ -0,0 +1,27 @@ +{ + "routes": { + "2111::1111/128": [ + { + "bestpath": true, + "pathFrom": "external", + "path": "65502", + "origin": "IGP", + "nexthops": [ + { + "ip": "192:168::2", + "hostname": "r2", + "afi": "ipv6", + "scope": "global" + }, + { + "hostname": "r2", + "afi": "ipv6", + "scope": "link-local", + "used": true + } + ] + } + ] + } +} + diff --git a/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-update-step2.json b/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-update-step2.json new file mode 100644 index 0000000000..ada2c26baf --- /dev/null +++ b/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-update-step2.json @@ -0,0 +1,25 @@ +{ + "routes": { + "routeDistinguishers": { + "555:2": { + "2001::2222/128": [ + { + "bestpath": true, + "pathFrom": "external", + "path": "65502", + "origin": "IGP", + "nexthops": [ + { + "ip": "192:168::2", + "hostname": "r2", + "afi": "ipv6", + "used": true + } + ] + } + ] + } + } + } +} + diff --git a/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-withdraw-step1.json b/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-withdraw-step1.json new file mode 100644 index 0000000000..93f4a75e8c --- /dev/null +++ b/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-withdraw-step1.json @@ -0,0 +1,6 @@ +{ + "routes": { + "2111::1111/128": null + } +} + diff --git a/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-withdraw-step2.json b/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-withdraw-step2.json new file mode 100644 index 0000000000..9703a269d5 --- /dev/null +++ b/tests/topotests/bgp_bmp/r1/show-bgp-ipv6-withdraw-step2.json @@ -0,0 +1,10 @@ +{ + "routes": { + "routeDistinguishers": { + "555:2": { + "2001::2222/128": null + } + } + } +} + diff --git a/tests/topotests/bgp_bmp/test_bgp_bmp.py b/tests/topotests/bgp_bmp/test_bgp_bmp.py index e02221c2eb..a6344a6c0a 100644 --- a/tests/topotests/bgp_bmp/test_bgp_bmp.py +++ b/tests/topotests/bgp_bmp/test_bgp_bmp.py @@ -50,6 +50,9 @@ 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("r1") @@ -67,6 +70,12 @@ def setup_module(mod): tgen = Topogen(build_topo, mod.__name__) tgen.start_topology() + if DEBUG_PCAP: + tgen.gears["r1"].run("rm /tmp/bmp.pcap") + tgen.gears["r1"].run( + "tcpdump -nni r1-eth0 -s 0 -w /tmp/bmp.pcap &", stdout=None + ) + for rname, router in tgen.routers().items(): router.load_config( TopoRouter.RD_ZEBRA, os.path.join(CWD, "{}/zebra.conf".format(rname)) @@ -122,42 +131,181 @@ def get_bmp_messages(): return messages -def check_for_prefixes(expected_prefixes, bmp_log_type, policy, labels=None): +def update_seq(): + global SEQ + + messages = get_bmp_messages() + + if len(messages): + SEQ = messages[-1]["seq"] + + +def update_expected_files(bmp_actual, expected_prefixes, bmp_log_type, policy, step): + tgen = get_topogen() + + with open(f"/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w") as json_file: + json.dump(bmp_actual, json_file, indent=4) + + if step == 2: # vpn + rd = "444:2" + out = tgen.gears["r1"].vtysh_cmd("show bgp ipv4 vpn json", isjson=True) + filtered_out = { + "routes": { + "routeDistinguishers": { + rd: { + prefix: route_info + for prefix, route_info in out["routes"] + .get("routeDistinguishers", {}) + .get(rd, {}) + .items() + if prefix in expected_prefixes + } + } + } + } + if bmp_log_type == "withdraw": + for pfx in expected_prefixes: + if "::" in pfx: + continue + filtered_out["routes"]["routeDistinguishers"][rd][pfx] = None + + # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done + with open( + f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w" + ) as json_file: + json.dump(filtered_out, json_file, indent=4) + + rd = "555:2" + out = tgen.gears["r1"].vtysh_cmd("show bgp ipv6 vpn json", isjson=True) + filtered_out = { + "routes": { + "routeDistinguishers": { + rd: { + prefix: route_info + for prefix, route_info in out["routes"] + .get("routeDistinguishers", {}) + .get(rd, {}) + .items() + if prefix in expected_prefixes + } + } + } + } + if bmp_log_type == "withdraw": + for pfx in expected_prefixes: + if "::" not in pfx: + continue + filtered_out["routes"]["routeDistinguishers"][rd][pfx] = None + with open( + f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w" + ) as json_file: + json.dump(filtered_out, json_file, indent=4) + + return + + out = tgen.gears["r1"].vtysh_cmd("show bgp ipv4 json", isjson=True) + filtered_out = { + "routes": { + prefix: route_info + for prefix, route_info in out["routes"].items() + if prefix in expected_prefixes + } + } + if bmp_log_type == "withdraw": + for pfx in expected_prefixes: + if "::" in pfx: + continue + filtered_out["routes"][pfx] = None + + # ls /tmp/show*json | while read file; do egrep -v 'prefix|network|metric|ocPrf|version|weight|peerId|vrf|Version|valid|Reason|fe80' $file >$(basename $file); echo >> $(basename $file); done + with open(f"/tmp/show-bgp-ipv4-{bmp_log_type}-step{step}.json", "w") as json_file: + json.dump(filtered_out, json_file, indent=4) + + out = tgen.gears["r1"].vtysh_cmd("show bgp ipv6 json", isjson=True) + filtered_out = { + "routes": { + prefix: route_info + for prefix, route_info in out["routes"].items() + if prefix in expected_prefixes + } + } + if bmp_log_type == "withdraw": + for pfx in expected_prefixes: + if "::" not in pfx: + continue + filtered_out["routes"][pfx] = None + with open(f"/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w") as json_file: + json.dump(filtered_out, json_file, indent=4) + + +def check_for_prefixes(expected_prefixes, bmp_log_type, policy, step): """ Check for the presence of the given prefixes in the BMP server logs with the given message type and the set policy. + """ global SEQ + # we care only about the new messages messages = [ m for m in sorted(get_bmp_messages(), key=lambda d: d["seq"]) if m["seq"] > SEQ ] - # get the list of pairs (prefix, policy, seq) for the given message type - prefixes = [ - m["ip_prefix"] - for m in messages - if "ip_prefix" in m.keys() - and "bmp_log_type" in m.keys() - and m["bmp_log_type"] == bmp_log_type - and m["policy"] == policy - and ( - labels is None - or ( - m["ip_prefix"] in labels.keys() and m["label"] == labels[m["ip_prefix"]] - ) - ) - ] + # create empty initial files + # for step in $(seq 2); do + # for i in "update" "withdraw"; do + # for j in "pre-policy" "post-policy" "loc-rib"; do + # echo '{"null": {}}'> bmp-$i-$j-step$step.json + # done + # done + # done - # check for prefixes - for ep in expected_prefixes: - if ep not in prefixes: - msg = "The prefix {} is not present in the {} log messages." - logger.debug(msg.format(ep, bmp_log_type)) - return False + ref_file = f"{CWD}/bmp1/bmp-{bmp_log_type}-{policy}-step{step}.json" + expected = json.loads(open(ref_file).read()) - SEQ = messages[-1]["seq"] - return True + # Build actual json from logs + actual = {} + for m in messages: + if ( + "bmp_log_type" in m.keys() + and "ip_prefix" in m.keys() + and m["ip_prefix"] in expected_prefixes + and m["bmp_log_type"] == bmp_log_type + and m["policy"] == policy + ): + policy_dict = actual.setdefault(m["policy"], {}) + bmp_log_type_dict = policy_dict.setdefault(m["bmp_log_type"], {}) + + # Add or update the ip_prefix dictionary with filtered key-value pairs + bmp_log_type_dict[m["ip_prefix"]] = { + k: v + for k, v in sorted(m.items()) + # filter out variable keys + if k not in ["timestamp", "seq", "nxhp_link-local"] + and ( + # When policy is loc-rib, the peer-distinguisher is 0:0 + # for the default VRF or the RD if any or the 0:. + # 0: is used to distinguished. RFC7854 says: "If the + # peer is a "Local Instance Peer", it is set to a unique, + # locally defined value." The value is not tested because it + # is variable. + k != "peer_distinguisher" + or policy != LOC_RIB + or v == "0:0" + or not v.startswith("0:") + ) + } + + # build expected JSON files + if ( + UPDATE_EXPECTED_JSON + and actual + and set(actual.get(policy, {}).get(bmp_log_type, {}).keys()) + == set(expected_prefixes) + ): + update_expected_files(actual, expected_prefixes, bmp_log_type, policy, step) + + return topotest.json_cmp(actual, expected, exact=True) def check_for_peer_message(expected_peers, bmp_log_type): @@ -230,25 +378,63 @@ def unicast_prefixes(policy): message type and the right policy. """ tgen = get_topogen() + set_bmp_policy(tgen, "r1", 65501, "bmp1", "unicast", policy) + update_seq() + prefixes = ["172.31.0.15/32", "2111::1111/128"] # add prefixes configure_prefixes(tgen, "r2", 65502, "unicast", prefixes) + for ipver in [4, 6]: + if UPDATE_EXPECTED_JSON: + continue + ref_file = "{}/r1/show-bgp-ipv{}-update-step1.json".format(CWD, ipver) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + f"show bgp 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 + logger.info("checking for updated prefixes") # check - test_func = partial(check_for_prefixes, prefixes, "update", policy) - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." + test_func = partial(check_for_prefixes, prefixes, "update", policy, 1) + success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !. %s" % res + + update_seq() # withdraw prefixes configure_prefixes(tgen, "r2", 65502, "unicast", prefixes, update=False) - logger.info("checking for withdrawed prefxies") + logger.info("checking for withdrawn prefixes") + + for ipver in [4, 6]: + if UPDATE_EXPECTED_JSON: + continue + ref_file = "{}/r1/show-bgp-ipv{}-withdraw-step1.json".format(CWD, ipver) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + f"show bgp 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(check_for_prefixes, prefixes, "withdraw", policy) - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the withdrawed prefixes has been failed !." + test_func = partial(check_for_prefixes, prefixes, "withdraw", policy, 1) + success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert success, "Checking the withdrawn prefixes has been failed !. %s" % res def vpn_prefixes(policy): @@ -258,32 +444,64 @@ def vpn_prefixes(policy): message type and the right policy. """ tgen = get_topogen() + set_bmp_policy(tgen, "r1", 65501, "bmp1", "vpn", policy) - prefixes = ["172.31.10.1/32", "2001::2222/128"] + update_seq() - # "label vpn export" value in r2/bgpd.conf - labels = { - "172.31.10.1/32": 102, - "2001::2222/128": 105, - } + prefixes = ["172.31.10.1/32", "2001::2222/128"] # add prefixes configure_prefixes(tgen, "r2", 65502, "unicast", prefixes, vrf="vrf1") + for ipver in [4, 6]: + if UPDATE_EXPECTED_JSON: + continue + ref_file = "{}/r1/show-bgp-ipv{}-update-step2.json".format(CWD, ipver) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + f"show bgp ipv{ipver} vpn 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 + logger.info("checking for updated prefixes") # check - test_func = partial(check_for_prefixes, prefixes, "update", policy, labels=labels) - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the updated prefixes has been failed !." + test_func = partial(check_for_prefixes, prefixes, "update", policy, 2) + success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert success, "Checking the updated prefixes has been failed !. %s" % res + + update_seq() # withdraw prefixes configure_prefixes(tgen, "r2", 65502, "unicast", prefixes, vrf="vrf1", update=False) - logger.info("checking for withdrawed prefixes") + logger.info("checking for withdrawn prefixes") + + for ipver in [4, 6]: + if UPDATE_EXPECTED_JSON: + continue + ref_file = "{}/r1/show-bgp-ipv{}-withdraw-step2.json".format(CWD, ipver) + expected = json.loads(open(ref_file).read()) + + test_func = partial( + topotest.router_json_cmp, + tgen.gears["r1"], + f"show bgp ipv{ipver} vpn 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(check_for_prefixes, prefixes, "withdraw", policy) - success, _ = topotest.run_and_expect(test_func, True, count=30, wait=1) - assert success, "Checking the withdrawed prefixes has been failed !." + test_func = partial(check_for_prefixes, prefixes, "withdraw", policy, 2) + success, res = topotest.run_and_expect(test_func, None, count=30, wait=1) + assert success, "Checking the withdrawn prefixes has been failed !. %s" % res def test_bmp_server_logging():