From 44c6f579c34d65dfc9c2041753c1dc7494af63f4 Mon Sep 17 00:00:00 2001 From: Louis Scalbert Date: Wed, 23 Oct 2024 15:17:00 +0200 Subject: [PATCH] tests: rework bgp_bmp The BGP BMP topotest is difficult to debug. It does not say which prefix is not received by BGP or BMP when it fails. Rework the test to convert the actual BMP logs to JSON and compare the BGP table and BMP server logs output to expected reference JSON files. Signed-off-by: Louis Scalbert --- .../bmp1/bmp-update-loc-rib-step1.json | 34 ++ .../bmp1/bmp-update-loc-rib-step2.json | 43 +++ .../bmp1/bmp-update-post-policy-step1.json | 36 ++ .../bmp1/bmp-update-post-policy-step2.json | 45 +++ .../bmp1/bmp-update-pre-policy-step1.json | 36 ++ .../bmp1/bmp-update-pre-policy-step2.json | 45 +++ .../bmp1/bmp-withdraw-loc-rib-step1.json | 28 ++ .../bmp1/bmp-withdraw-loc-rib-step2.json | 34 ++ .../bmp1/bmp-withdraw-post-policy-step1.json | 30 ++ .../bmp1/bmp-withdraw-post-policy-step2.json | 36 ++ .../bmp1/bmp-withdraw-pre-policy-step1.json | 30 ++ .../bmp1/bmp-withdraw-pre-policy-step2.json | 36 ++ .../r1/show-bgp-ipv4-update-step1.json | 21 ++ .../r1/show-bgp-ipv4-update-step2.json | 25 ++ .../r1/show-bgp-ipv4-withdraw-step1.json | 6 + .../r1/show-bgp-ipv4-withdraw-step2.json | 10 + .../r1/show-bgp-ipv6-update-step1.json | 27 ++ .../r1/show-bgp-ipv6-update-step2.json | 25 ++ .../r1/show-bgp-ipv6-withdraw-step1.json | 6 + .../r1/show-bgp-ipv6-withdraw-step2.json | 10 + tests/topotests/bgp_bmp/test_bgp_bmp.py | 310 +++++++++++++++--- 21 files changed, 827 insertions(+), 46 deletions(-) create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-update-loc-rib-step1.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-update-loc-rib-step2.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-update-post-policy-step1.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-update-post-policy-step2.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-update-pre-policy-step1.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-update-pre-policy-step2.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-withdraw-loc-rib-step1.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-withdraw-loc-rib-step2.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-withdraw-post-policy-step1.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-withdraw-post-policy-step2.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-withdraw-pre-policy-step1.json create mode 100644 tests/topotests/bgp_bmp/bmp1/bmp-withdraw-pre-policy-step2.json create mode 100644 tests/topotests/bgp_bmp/r1/show-bgp-ipv4-update-step1.json create mode 100644 tests/topotests/bgp_bmp/r1/show-bgp-ipv4-update-step2.json create mode 100644 tests/topotests/bgp_bmp/r1/show-bgp-ipv4-withdraw-step1.json create mode 100644 tests/topotests/bgp_bmp/r1/show-bgp-ipv4-withdraw-step2.json create mode 100644 tests/topotests/bgp_bmp/r1/show-bgp-ipv6-update-step1.json create mode 100644 tests/topotests/bgp_bmp/r1/show-bgp-ipv6-update-step2.json create mode 100644 tests/topotests/bgp_bmp/r1/show-bgp-ipv6-withdraw-step1.json create mode 100644 tests/topotests/bgp_bmp/r1/show-bgp-ipv6-withdraw-step2.json 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"]] - ) - ) - ] - - # 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 - - SEQ = messages[-1]["seq"] - return True + # 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 + + ref_file = f"{CWD}/bmp1/bmp-{bmp_log_type}-{policy}-step{step}.json" + expected = json.loads(open(ref_file).read()) + + # 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(): -- 2.39.5