Skip to content
Open
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
1 change: 1 addition & 0 deletions .azure-pipelines/pr_test_scripts.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -694,6 +694,7 @@ t1-lag-vpp:
- lldp/test_lldp.py
- lldp/test_lldp_syncd.py
- log_fidelity/test_bgp_shutdown.py
- mpls/test_mpls.py
- pc/test_po_voq.py
- pc/test_lag_member.py
- pc/test_po_update.py
Expand Down
15 changes: 15 additions & 0 deletions ansible/library/generate_golden_config_db.py
Original file line number Diff line number Diff line change
Expand Up @@ -1338,6 +1338,21 @@ def generate(self):
if self.has_otel_image():
config = self.overwrite_feature_golden_config_db_singleasic(config, "otel", "enabled", "enabled")

# Register the mpls feature on the sonic-vpp testbeds so the MPLS data-plane
# tests (tests/mpls) are not skipped by the "'mpls' not in feature_status"
# condition in tests_mark_conditions.yaml. The VPP SAI implementation
# supports MPLS (INSEG disposition/imposition).
#
# The state is deliberately "disabled": mpls is a config flag, not a
# containerized service, so there is no "mpls" docker. Registering it as
# "enabled" would make the image's monit container_checker report
# "Expected containers not running: mpls" and fail the sanity check for
# every test on this platform. The condition above only tests for the
# presence of the key, so "disabled" is enough to un-skip the tests.
if "vpp" in self.topo_name:
config = self.overwrite_feature_golden_config_db_singleasic(
config, "mpls", auto_restart="disabled", state="disabled")

# Disable dash-ha feature for all multi-asic platforms
if multi_asic.is_multi_asic():
config = self.overwrite_feature_golden_config_db_multiasic(config, "dash-ha", feature_data={
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -401,10 +401,12 @@ memory_checker/test_memory_checker.py::test_monit_reset_counter_failure:
#######################################
##### MPLS #####
#######################################
mpls/test_mpls.py:
mpls/test_mpls.py::TestBasicMpls::test_push_label:
skip:
reason: >
Unsupported
MPLS push is not testable here: the test injects the push route
directly into ROUTE_TABLE and orchagent does not install that route
into ASIC_DB, so it never reaches the SAI backend.
conditions_logical_operator: or
conditions:
- "asic_type in ['vpp']"
Expand Down
50 changes: 44 additions & 6 deletions tests/mpls/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,22 @@
LABEL_DEL_ROUTES = 'label_del_routes'


def _resolve_ptf_port_ids(dut_port, mg_facts):
"""Resolve a DUT L3 interface to its PTF port indices.

On t1-lag the spine/tor facing interfaces can be PortChannels, which are not
present in minigraph_port_indices. Resolve such a PortChannel to the PTF port
indices of its physical member ports. A physical interface resolves to a
single-element list.
"""
portchannels = mg_facts.get('minigraph_portchannels', {})
if dut_port in portchannels:
members = portchannels[dut_port]['members']
else:
members = [dut_port]
return [mg_facts['minigraph_port_indices'][member] for member in members]


@pytest.fixture(scope='module')
def setup(duthost, tbinfo, ptfadapter):
"""
Expand All @@ -22,9 +38,24 @@ def setup(duthost, tbinfo, ptfadapter):
:param tbinfo: fixture provides information about testbed
:return: dictionary with all test required information
"""
if tbinfo['topo']['name'] not in ('t1'):
if tbinfo['topo']['type'] != 't1':
pytest.skip('Unsupported topology')

# Enabling MPLS on an interface makes intfmgrd run
# "sysctl -w net.mpls.conf.<intf>.input=1", which needs the mpls_router kernel
# module. The module ships in the image but nothing loads it, so without this
# the sysctl fails and is logged as an ERR. sonic-swss's own MPLS test loads it
# the same way. Left loaded on teardown: modprobe is idempotent and unloading
# could disrupt anything else using MPLS.
if duthost.facts['asic_type'] == 'vpp':
result = duthost.shell('modprobe mpls_router', module_ignore_errors=True)
if result['rc'] != 0:
# Not fatal here: let the test itself fail on the resulting syslog
# error rather than hiding a genuine loss of kernel MPLS support
# behind a setup failure.
logger.warning('Failed to load mpls_router: %s. Enabling MPLS on an '
'interface will log a setIntfMpls error.', result['stderr'])

# gather ansible facts
mg_facts = duthost.minigraph_facts(host=duthost.hostname)['ansible_facts']
host_facts = duthost.setup()['ansible_facts']
Expand Down Expand Up @@ -60,15 +91,20 @@ def setup(duthost, tbinfo, ptfadapter):
logger.info('spine_ports: {}'.format(spine_ports))
logger.info('tor_addr: {}'.format(tor_addr))

# The test needs both a T2-facing ingress and a T0-facing egress interface.
# Some t1 variants (e.g. t1-backend, whose neighbors are all BT0) have no T2
# peer at all, so bail out cleanly instead of failing later in random.choice().
if not spine_ports or not tor_ports:
pytest.skip('Topology has no T2-facing ({}) or T0-facing ({}) interface'
.format(len(spine_ports), len(tor_ports)))

for dut_port in tor_ports:
port_id = mg_facts['minigraph_port_indices'][dut_port]
tor_ports_ids[dut_port] = port_id
tor_ports_ids[dut_port] = _resolve_ptf_port_ids(dut_port, mg_facts)
ansible_port = 'ansible_'+dut_port
tor_mac[dut_port] = host_facts[ansible_port]['macaddress']

for dut_port in spine_ports:
port_id = mg_facts['minigraph_port_indices'][dut_port]
spine_ports_ids[dut_port] = port_id
spine_ports_ids[dut_port] = _resolve_ptf_port_ids(dut_port, mg_facts)
ansible_port = 'ansible_'+dut_port
spine_mac[dut_port] = host_facts[ansible_port]['macaddress']

Expand All @@ -78,8 +114,10 @@ def setup(duthost, tbinfo, ptfadapter):
src_port = random.choice(spine_ports)
dst_port = random.choice(tor_ports)

# dst_pid is the list of egress PortChannel member PTF ports (verify on any member).
# src_pid is a single ingress member PTF port used to inject the test packet.
dst_pid = tor_ports_ids[dst_port]
src_pid = spine_ports_ids[src_port]
src_pid = spine_ports_ids[src_port][0]

dst_mac = tor_mac[dst_port]
src_mac = spine_mac[src_port]
Expand Down
9 changes: 4 additions & 5 deletions tests/mpls/test_mpls.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,6 @@ def expected_mask_ip_packet(self, pkt):
exp_pkt['Ethernet'].remove_payload()
exp_pkt /= pkt1
exp_pkt = mask.Mask(exp_pkt)
exp_pkt = mask.Mask(exp_pkt)
exp_pkt.set_do_not_care_scapy(packet.Ether, 'dst')
exp_pkt.set_do_not_care_scapy(packet.Ether, 'src')
exp_pkt.set_do_not_care_scapy(packet.IP, 'chksum')
Expand Down Expand Up @@ -198,7 +197,7 @@ def test_pop_label(self, setup, ptfadapter):
ptfadapter.dataplane.flush()
testutils.send(ptfadapter, src_pid, pkt)
try:
res = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=[dst_pid])
res = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=dst_pid)
logger.info(res)
except Exception as e:
self.teardown_labels(setup)
Expand All @@ -222,7 +221,7 @@ def test_swap_label(self, setup, ptfadapter):
ptfadapter.dataplane.flush()
testutils.send(ptfadapter, src_pid, pkt)
try:
res = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=[dst_pid])
res = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=dst_pid)
logger.info(res)
except Exception as e:
self.teardown_labels(setup)
Expand Down Expand Up @@ -255,7 +254,7 @@ def test_push_label(self, setup, ptfadapter):
testutils.send(ptfadapter, src_pid, pkt)

try:
res = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=[dst_pid])
res = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=dst_pid)
logger.info(res)
except Exception as e:
self.teardown_labels(setup)
Expand All @@ -280,7 +279,7 @@ def test_swap_labelstack(self, setup, ptfadapter):
testutils.send(ptfadapter, src_pid, pkt)

try:
res = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=[dst_pid])
res = testutils.verify_packet_any_port(ptfadapter, exp_pkt, ports=dst_pid)
logger.info(res)
except Exception as e:
self.teardown_labels(setup)
Expand Down
Loading