Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

BMP test rework #17306

Merged
merged 7 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
233 changes: 233 additions & 0 deletions tests/topotests/bgp_bmp/bgpbmp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,233 @@
#!/usr/bin/env python
# SPDX-License-Identifier: GPL-2.0-or-later

# Copyright 2023, 6wind
import json
import os

from lib import topotest
from lib.topogen import get_topogen
from lib.topolog import logger

# remember the last sequence number of the logging messages
SEQ = 0


def bmp_reset_seq():
global SEQ
SEQ = 0


def get_bmp_messages(bmp_collector, bmp_log_file):
"""
Read the BMP logging messages.
"""
messages = []
text_output = bmp_collector.run(f"cat {bmp_log_file}")

for m in text_output.splitlines():
# some output in the bash can break the message decoding
try:
messages.append(json.loads(m))
except Exception as e:
logger.warning(str(e) + " message: {}".format(str(m)))
continue

if not messages:
logger.error("Bad BMP log format, check your BMP server")

return messages


def bmp_update_seq(bmp_collector, bmp_log_file):
global SEQ

messages = get_bmp_messages(bmp_collector, bmp_log_file)

if len(messages):
SEQ = messages[-1]["seq"]


def bmp_update_expected_files(
bmp_actual,
expected_prefixes,
bmp_log_type,
policy,
step,
bmp_client,
bmp_log_folder,
):
tgen = get_topogen()

with open(
f"{bmp_log_folder}/tmp/bmp-{bmp_log_type}-{policy}-step{step}.json", "w"
) as json_file:
json.dump(bmp_actual, json_file, indent=4)

out = bmp_client.vtysh_cmd("show bgp vrf vrf1 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 {bmp_log_folder}/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"{bmp_log_folder}/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 vrf vrf1 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"{bmp_log_folder}/tmp/show-bgp-ipv6-{bmp_log_type}-step{step}.json", "w"
) as json_file:
json.dump(filtered_out, json_file, indent=4)


def bmp_check_for_prefixes(
expected_prefixes,
bmp_log_type,
policy,
step,
bmp_collector,
bmp_log_folder,
bmp_client,
expected_json_path,
update_expected_json,
loc_rib,
):
"""
Check for the presence of the given prefixes in the BMP server logs with
the given message type and the set policy.

"""
global SEQ

bmp_log_file = f"{bmp_log_folder}/bmp.log"
# we care only about the new messages
messages = [
m
for m in sorted(
get_bmp_messages(bmp_collector, bmp_log_file), key=lambda d: d["seq"]
)
if m["seq"] > SEQ
]

# create empty initial files
# for step in $(seq 1); 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"{expected_json_path}/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:<vrf_id>.
# 0:<vrf_id> 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)
):
bmp_update_expected_files(
actual,
expected_prefixes,
bmp_log_type,
policy,
step,
bmp_client,
bmp_log_folder,
)

return topotest.json_cmp(actual, expected, exact=True)


def bmp_check_for_peer_message(
expected_peers, bmp_log_type, bmp_collector, bmp_log_file
):
"""
Check for the presence of a peer up message for the peer
"""
global SEQ

# we care only about the new messages
messages = [
m
for m in sorted(
get_bmp_messages(bmp_collector, bmp_log_file), key=lambda d: d["seq"]
)
if m["seq"] > SEQ
]

# get the list of pairs (prefix, policy, seq) for the given message type
peers = [
m["peer_ip"]
for m in messages
if "peer_ip" in m.keys() and m["bmp_log_type"] == bmp_log_type
]

# check for prefixes
for ep in expected_peers:
if ep not in peers:
msg = "The peer {} is not present in the {} log messages."
logger.debug(msg.format(ep, bmp_log_type))
return False

SEQ = messages[-1]["seq"]
return True
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
interface r1-eth0
ip address 192.0.2.1/24
!
interface r1-eth1
ip address 192.168.0.1/24
ipv6 address 192:168::1/64
!
router bgp 65501
bgp router-id 192.168.0.1
bgp log-neighbor-changes
Expand Down Expand Up @@ -41,7 +48,7 @@ router bgp 65501
exit-address-family
!
router bgp 65501 vrf vrf1
bgp router_id 192.168.0.1
bgp router-id 192.168.0.1
bgp log-neighbor-changes
address-family ipv4 unicast
label vpn export 101
Expand Down
7 changes: 0 additions & 7 deletions tests/topotests/bgp_bmp/r1/zebra.conf

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
interface r1vrf-eth0
ip address 192.0.2.1/24
!
interface r1vrf-eth1
ip address 192.168.0.1/24
ipv6 address 192:168::1/64
!
router bgp 65501 vrf vrf1
bgp router-id 192.168.0.1
bgp log-neighbor-changes
Expand All @@ -15,7 +22,6 @@ router bgp 65501 vrf vrf1
bmp monitor ipv6 unicast loc-rib
exit
!

address-family ipv4 unicast
neighbor 192.168.0.2 activate
neighbor 192.168.0.2 soft-reconfiguration inbound
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
"nexthops": [
{
"ip": "192.168.0.2",
"hostname": "r2",
"afi": "ipv4",
"used": true
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,10 @@
"nexthops": [
{
"ip": "192:168::2",
"hostname": "r2",
"afi": "ipv6",
"scope": "global"
},
{
"hostname": "r2",
"afi": "ipv6",
"scope": "link-local",
"used": true
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
interface r2-eth0
ip address 192.168.0.2/24
ipv6 address 192:168::2/64
!
interface r2-eth1
ip address 172.31.0.2/24
ipv6 address 172:31::2/64
!
router bgp 65502
bgp router-id 192.168.0.2
bgp log-neighbor-changes
Expand Down
8 changes: 0 additions & 8 deletions tests/topotests/bgp_bmp/r2/zebra.conf

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
interface r2vrf-eth0
ip address 192.168.0.2/24
ipv6 address 192:168::2/64
!
interface r2vrf-eth1
ip address 172.31.0.2/24
ipv6 address 172:31::2/64
!
router bgp 65502
bgp router-id 192.168.0.2
bgp log-neighbor-changes
Expand Down
Loading
Loading