Skip to content

Commit

Permalink
[bgp] Add bgp router id test (#17211)
Browse files Browse the repository at this point in the history
How did you do it?
Test in default config, bgp router id should be aligned with Loopback IPv4 address
Test when bgp_router_id and Loopback IPv4 address both exist in running config, bgp router id should be aligned with bgp_router_id in running config. And Loopback IPv4 address should be advertised to neighbor
Test when bgp_router_id configured but Loopback IPv4 address missing, bgp could work well.

How did you verify/test it?
Run test in m0/t0/t1/dualtor/dualtor-aa testbed, all passed
  • Loading branch information
yaqiangz committed Mar 3, 2025
1 parent e73f31f commit f69c7d2
Show file tree
Hide file tree
Showing 4 changed files with 148 additions and 5 deletions.
6 changes: 2 additions & 4 deletions tests/bgp/test_bgp_fact.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,9 @@
]


def run_bgp_facts(duthosts, enum_frontend_dut_hostname, enum_asic_index):
def run_bgp_facts(duthost, enum_asic_index):
"""compare the bgp facts between observed states and target state"""

duthost = duthosts[enum_frontend_dut_hostname]

bgp_facts = duthost.bgp_facts(instance_id=enum_asic_index)['ansible_facts']
namespace = duthost.get_namespace_from_asic_id(enum_asic_index)
config_facts = duthost.config_facts(host=duthost.hostname, source="running", namespace=namespace)['ansible_facts']
Expand Down Expand Up @@ -43,4 +41,4 @@ def run_bgp_facts(duthosts, enum_frontend_dut_hostname, enum_asic_index):


def test_bgp_facts(duthosts, enum_frontend_dut_hostname, enum_asic_index):
run_bgp_facts(duthosts, enum_frontend_dut_hostname, enum_asic_index)
run_bgp_facts(duthosts[enum_frontend_dut_hostname], enum_asic_index)
139 changes: 139 additions & 0 deletions tests/bgp/test_bgp_router_id.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
import pytest
import logging
import re

from tests.common.helpers.assertions import pytest_require, pytest_assert
from tests.bgp.test_bgp_fact import run_bgp_facts
from tests.common.utilities import wait_until


pytestmark = [
pytest.mark.topology('any')
]

logger = logging.getLogger(__name__)

CUSTOMIZED_BGP_ROUTER_ID = "8.8.8.8"


def verify_bgp(enum_asic_index, duthost, expected_bgp_router_id, neighbor_type, nbrhosts):
output = duthost.shell("show ip bgp summary", module_ignore_errors=True)["stdout"]

# Verify router id from DUT itself
pattern = r"BGP router identifier (\d+\.\d+\.\d+\.\d+)"
match = re.search(pattern, output)
pytest_assert(match, "Cannot get actual BGP router id from [{}]".format(output))
pytest_assert(match.group(1) == expected_bgp_router_id,
"BGP router id unexpected, expected: {}, actual: {}".format(expected_bgp_router_id, match.group(1)))

# Verify BGP sessions are established
run_bgp_facts(duthost, enum_asic_index)

# Verify from peer device side to check
if neighbor_type not in ["sonic", "eos"]:
logger.warning("Unsupport neighbor type for neighbor bgp check: {}".format(neighbor_type))
local_ip_map = {}
cfg_facts = duthost.config_facts(host=duthost.hostname, source="running")['ansible_facts']
for _, item in cfg_facts.get("BGP_NEIGHBOR", {}).items():
if "." in item["local_addr"]:
local_ip_map[item["name"]] = item["local_addr"]

for neighbor_name, nbrhost in nbrhosts.items():
pytest_assert(neighbor_name in local_ip_map, "Cannot find local ip for {}".format(neighbor_name))
if neighbor_type == "sonic":
cmd = "show ip neighbors {}".format(local_ip_map[neighbor_name])
elif neighbor_type == "eos":
cmd = "/usr/bin/Cli -c \"show ip bgp neighbors {}\"".format(local_ip_map[neighbor_name])
output = nbrhost["host"].shell(cmd, module_ignore_errors=True)['stdout']
pattern = r"BGP version 4, remote router ID (\d+\.\d+\.\d+\.\d+)"
match = re.search(pattern, output)
pytest_assert(match, "Cannot get remote BGP router id from [{}]".format(output))
pytest_assert(match.group(1) == expected_bgp_router_id,
"BGP router id is unexpected, local: {}, fetch from remote: {}"
.format(expected_bgp_router_id, match.group(1)))


@pytest.fixture()
def loopback_ip(duthosts, enum_frontend_dut_hostname):
duthost = duthosts[enum_frontend_dut_hostname]
cfg_facts = duthost.config_facts(host=duthost.hostname, source="running")['ansible_facts']
loopback_ip = None
loopback_table = cfg_facts.get("LOOPBACK_INTERFACE", {})
for key in loopback_table.get("Loopback0", {}).keys():
if "." in key:
loopback_ip = key.split("/")[0]
pytest_require(loopback_ip is not None, "Cannot get IPv4 address of Loopback0")
yield loopback_ip


def restart_bgp(duthost):
duthost.reset_service("bgp")
duthost.restart_service("bgp")
pytest_assert(wait_until(100, 10, 10, duthost.is_service_fully_started_per_asic_or_host, "bgp"), "BGP not started.")
pytest_assert(wait_until(100, 10, 10, duthost.check_default_route, "bgp"), "Default route not ready")


@pytest.fixture()
def router_id_setup_and_teardown(duthosts, enum_frontend_dut_hostname):
duthost = duthosts[enum_frontend_dut_hostname]
duthost.shell("sonic-db-cli CONFIG_DB hset \"DEVICE_METADATA|localhost\" \"bgp_router_id\" \"{}\""
.format(CUSTOMIZED_BGP_ROUTER_ID), module_ignore_errors=True)
restart_bgp(duthost)

yield

duthost.shell("sonic-db-cli CONFIG_DB hdel \"DEVICE_METADATA|localhost\" \"bgp_router_id\"",
module_ignore_errors=True)
restart_bgp(duthost)


@pytest.fixture(scope="function")
def router_id_loopback_setup_and_teardown(duthosts, enum_frontend_dut_hostname, loopback_ip):
duthost = duthosts[enum_frontend_dut_hostname]
duthost.shell("sonic-db-cli CONFIG_DB hset \"DEVICE_METADATA|localhost\" \"bgp_router_id\" \"{}\""
.format(CUSTOMIZED_BGP_ROUTER_ID), module_ignore_errors=True)
duthost.shell("sonic-db-cli CONFIG_DB del \"LOOPBACK_INTERFACE|Loopback0|{}/32\"".format(loopback_ip))
restart_bgp(duthost)

yield

duthost.shell("sonic-db-cli CONFIG_DB hdel \"DEVICE_METADATA|localhost\" \"bgp_router_id\"",
module_ignore_errors=True)
duthost.shell("sonic-db-cli CONFIG_DB hset \"LOOPBACK_INTERFACE|Loopback0|{}/32\" \"NULL\" \"NULL\""
.format(loopback_ip), module_ignore_errors=True)
restart_bgp(duthost)


def test_bgp_router_id_default(duthosts, enum_frontend_dut_hostname, enum_asic_index, nbrhosts, request, loopback_ip):
# Test in default config, the BGP router id should be aligned with Loopback IPv4 address
duthost = duthosts[enum_frontend_dut_hostname]
neighbor_type = request.config.getoption("neighbor_type")
verify_bgp(enum_asic_index, duthost, loopback_ip, neighbor_type, nbrhosts)


def test_bgp_router_id_set(duthosts, enum_frontend_dut_hostname, enum_asic_index, nbrhosts, request, loopback_ip,
router_id_setup_and_teardown):
# Test in the scenario that bgp_router_id and Loopback IPv4 address both exist in CONFIG_DB, the actual BGP router
# ID should be aligned with bgp_router_id in CONFIG_DB. And the Loopback IPv4 address should be advertised to BGP
# neighbor
duthost = duthosts[enum_frontend_dut_hostname]
neighbor_type = request.config.getoption("neighbor_type")
verify_bgp(enum_asic_index, duthost, CUSTOMIZED_BGP_ROUTER_ID, neighbor_type, nbrhosts)
# Verify Loopback ip has been advertised to neighbor
cfg_facts = duthost.config_facts(host=duthost.hostname, source="running")['ansible_facts']
for remote_ip in cfg_facts.get("BGP_NEIGHBOR", {}).keys():
if "." not in remote_ip:
continue
output = duthost.shell("show ip bgp neighbor {} advertised-routes| grep {}".format(remote_ip, loopback_ip),
module_ignore_errors=True)
pytest_assert(output["rc"] == 0, "Failed to check whether Loopback ipv4 address has been advertised")
pytest_assert(loopback_ip in output["stdout"], "Router advertised unexpected: {}".format(output["stdout"]))


def test_bgp_router_id_set_without_loopback(duthosts, enum_frontend_dut_hostname, enum_asic_index, nbrhosts, request,
router_id_loopback_setup_and_teardown):
# Test in the scenario that bgp_router_id specified but Loopback IPv4 address not set, BGP could work well and the
# actual BGP router id should be aligned with CONFIG_DB
duthost = duthosts[enum_frontend_dut_hostname]
neighbor_type = request.config.getoption("neighbor_type")
verify_bgp(enum_asic_index, duthost, CUSTOMIZED_BGP_ROUTER_ID, neighbor_type, nbrhosts)
Original file line number Diff line number Diff line change
Expand Up @@ -143,6 +143,12 @@ bgp/test_bgp_queue.py:
conditions:
- "topo_type in ['m0', 'mx']"

bgp/test_bgp_router_id.py:
skip:
reason: "Not supported on multi-asic"
conditions:
- "is_multi_asic==True"

bgp/test_bgp_slb.py:
skip:
reason: "Skip over topologies which doesn't support slb."
Expand Down
2 changes: 1 addition & 1 deletion tests/ip/test_mgmt_ipv6_only.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def test_bgp_facts_ipv6_only(duthosts, enum_frontend_dut_hostname, enum_asic_ind
convert_and_restore_config_db_to_ipv6_only): # noqa F811
# Add a temporary debug log to see if DUTs are reachable via IPv6 mgmt-ip. Will remove later
log_eth0_interface_info(duthosts)
run_bgp_facts(duthosts, enum_frontend_dut_hostname, enum_asic_index)
run_bgp_facts(duthosts[enum_frontend_dut_hostname], enum_asic_index)


def test_show_features_ipv6_only(duthosts, enum_dut_hostname, convert_and_restore_config_db_to_ipv6_only): # noqa F811
Expand Down

0 comments on commit f69c7d2

Please sign in to comment.