Skip to content
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
12 changes: 12 additions & 0 deletions tests/common/plugins/conditional_mark/tests_mark_conditions.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -1884,6 +1884,18 @@ srv6/test_srv6_basic_sanity.py:
conditions:
- topo_name not in ["ciscovs-7nodes", "ciscovs-5nodes"]

srv6/test_srv6_dataplane.py:
skip:
reason: "Only target mellanox platform with 202412 image at this time"
conditions:
- "asic_type not in ['mellanox', 'broadcom'] or release not in ['202412']"

srv6/test_srv6_static_config.py:
skip:
reason: "Requires particular image support, skip in PR testing"
conditions:
- "release not in ['202412']"

#######################################
##### ssh #####
#######################################
Expand Down
3 changes: 2 additions & 1 deletion tests/common/plugins/ptfadapter/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -168,7 +168,8 @@ def check_if_use_minigraph_from_tbinfo(tbinfo):
return False
return True

with PtfTestAdapter(tbinfo['ptf_ip'], ptf_nn_agent_port, 0, list(ifaces_map.keys()), ptfhost) as adapter:
with PtfTestAdapter(tbinfo['ptf_ip'], tbinfo['ptf_ipv6'],
ptf_nn_agent_port, 0, list(ifaces_map.keys()), ptfhost) as adapter:
if not request.config.option.keep_payload:
override_ptf_functions()
node_id = request.module.__name__
Expand Down
12 changes: 8 additions & 4 deletions tests/common/plugins/ptfadapter/ptfadapter.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,10 @@ class PtfTestAdapter(BaseTest):
# the number of currently established connections
NN_STAT_CURRENT_CONNECTIONS = 201

def __init__(self, ptf_ip, ptf_nn_port, device_num, ptf_port_set, ptfhost):
def __init__(self, ptf_ip, ptf_ipv6, ptf_nn_port, device_num, ptf_port_set, ptfhost):
""" initialize PtfTestAdapter
:param ptf_ip: PTF host IP
:param ptf_ipv6: PTF host IPv6 address
:param ptf_nn_port: PTF nanomessage agent port
:param device_num: device number
:param ptf_port_set: PTF ports
Expand All @@ -43,7 +44,7 @@ def __init__(self, ptf_ip, ptf_nn_port, device_num, ptf_port_set, ptfhost):
self.payload_pattern = ""
self.connected = False
self.ptfhost = ptfhost
self._init_ptf_dataplane(ptf_ip, ptf_nn_port, device_num, ptf_port_set)
self._init_ptf_dataplane(ptf_ip, ptf_ipv6, ptf_nn_port, device_num, ptf_port_set)

def __enter__(self):
""" enter in 'with' block """
Expand All @@ -64,17 +65,19 @@ def _check_ptf_nn_agent_availability(self, socket_addr):
finally:
sock.close()

def _init_ptf_dataplane(self, ptf_ip, ptf_nn_port, device_num, ptf_port_set, ptf_config=None):
def _init_ptf_dataplane(self, ptf_ip, ptf_ipv6, ptf_nn_port, device_num, ptf_port_set, ptf_config=None):
"""
initialize ptf framework and establish connection to ptf_nn_agent
running on PTF host
:param ptf_ip: PTF host IP
:param ptf_ipv6: PTF host IPv6 address
:param ptf_nn_port: PTF nanomessage agent port
:param device_num: device number
:param ptf_port_set: PTF ports
:return:
"""
self.ptf_ip = ptf_ip
self.ptf_ipv6 = ptf_ipv6
self.ptf_nn_port = ptf_nn_port
self.device_num = device_num
self.ptf_port_set = ptf_port_set
Expand Down Expand Up @@ -137,7 +140,8 @@ def reinit(self, ptf_config=None):
self.ptfhost.command('supervisorctl update')
self.ptfhost.command('supervisorctl restart ptf_nn_agent')

self._init_ptf_dataplane(self.ptf_ip, self.ptf_nn_port, self.device_num, self.ptf_port_set, ptf_config)
self._init_ptf_dataplane(self.ptf_ip, self.ptf_ipv6, self.ptf_nn_port,
self.device_num, self.ptf_port_set, ptf_config)

def update_payload(self, pkt):
"""Update the payload of packet to the default pattern when certain conditions are met.
Expand Down
4 changes: 3 additions & 1 deletion tests/srv6/srv6_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,11 +128,13 @@ def runSendReceive(pkt, src_port, exp_pkt, dst_ports, pkt_expected, ptfadapter):
# Send the packet and poll on destination ports
testutils.send(ptfadapter, src_port, pkt, 1)
logger.debug("Sent packet: " + pkt.summary())

time.sleep(1)
(index, rcv_pkt) = testutils.verify_packet_any_port(ptfadapter, exp_pkt, dst_ports)
received = False
if rcv_pkt:
received = True
pytest_assert(received is True)
pytest_assert(received == pkt_expected)
logger.debug('index=%s, received=%s' % (str(index), str(received)))
if received:
logger.debug("Received packet: " + scapy.Ether(rcv_pkt).summary())
Expand Down
179 changes: 179 additions & 0 deletions tests/srv6/test_srv6_dataplane.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,179 @@
import pytest
import time
import random
import logging
from scapy.layers.inet6 import IPv6, ICMPv6EchoRequest
from scapy.layers.l2 import Ether

from srv6_utils import runSendReceive
from common.helpers.voq_helpers import get_neighbor_info
from ptf.testutils import simple_ipv6_sr_packet

logger = logging.getLogger(__name__)

pytestmark = [
pytest.mark.asic("mellanox", "broadcom"),
pytest.mark.topology("t0", "t1")
]


def get_ptf_src_port_and_dut_port_and_neighbor(dut, tbinfo):
"""Get the PTF port mapping for the duthost or an asic of the duthost"""
dut_mg_facts = dut.get_extended_minigraph_facts(tbinfo)
ports_map = dut_mg_facts["minigraph_ptf_indices"]
if len(ports_map) == 0:
pytest.skip("No PTF ports found for {}".format(dut))

lldp_table = dut.command("show lldp table")['stdout'].split("\n")[3:]
neighbor_table = [line.split() for line in lldp_table]
for entry in neighbor_table:
intf = entry[0]
if intf in ports_map:
return intf, ports_map[intf], entry[1] # local intf, ptf_src_port, neighbor hostname

dut_port, ptf_src_port = random.choice(ports_map)
return dut_port, ptf_src_port, None


@pytest.mark.parametrize("with_srh", [True, False])
def test_srv6_uN_forwarding(duthosts, enum_frontend_dut_hostname, enum_frontend_asic_index,
ptfadapter, tbinfo, nbrhosts, with_srh):
duthost = duthosts[enum_frontend_dut_hostname]
asic_index = enum_frontend_asic_index

if duthost.is_multi_asic:
cli_options = " -n " + duthost.get_namespace_from_asic_id(asic_index)
dut_asic = duthost.asic_instance[asic_index]
dut_mac = dut_asic.get_router_mac()
dut_port, ptf_src_port, neighbor = get_ptf_src_port_and_dut_port_and_neighbor(dut_asic, tbinfo)
else:
cli_options = ''
dut_mac = duthost._get_router_mac()
dut_port, ptf_src_port, neighbor = get_ptf_src_port_and_dut_port_and_neighbor(duthost, tbinfo)

logger.info("Doing test on DUT port {} | PTF port {}".format(dut_port, ptf_src_port))

# get neighbor IP
lines = duthost.command("show ipv6 bgp sum")['stdout'].split("\n")
for line in lines:
if neighbor in line:
neighbor_ip = line.split()[0]
assert neighbor_ip

# use DUT portchannel if applicable
pc_info = duthost.command("show int portchannel")['stdout']
if dut_port in pc_info:
lines = pc_info.split("\n")
for line in lines:
if dut_port in line:
dut_port = line.split()[1]

sonic_db_cli = "sonic-db-cli" + cli_options

# add a locator configuration entry
duthost.command(sonic_db_cli + " CONFIG_DB HSET SRV6_MY_LOCATORS\\|loc1 prefix fcbb:bbbb:1::")
# add a uN sid configuration entry
duthost.command(sonic_db_cli +
" CONFIG_DB HSET SRV6_MY_SIDS\\|loc1\\|fcbb:bbbb:1::/48 action uN decap_dscp_mode pipe")
# add the static route for IPv6 forwarding towards PTF's uSID
duthost.command(sonic_db_cli + " CONFIG_DB HSET STATIC_ROUTE\\|default\\|fcbb:bbbb:2::/48 nexthop {} ifname {}"
.format(neighbor_ip, dut_port))
time.sleep(5)

for i in range(0, 10):
if with_srh:
injected_pkt = simple_ipv6_sr_packet(
eth_dst=dut_mac,
eth_src=ptfadapter.dataplane.get_mac(0, ptf_src_port).decode(),
ipv6_src=ptfadapter.ptf_ipv6,
ipv6_dst="fcbb:bbbb:1:2::",
srh_seg_left=1,
srh_nh=41,
inner_frame=IPv6()/ICMPv6EchoRequest(seq=i)
)
else:
injected_pkt = Ether(dst=dut_mac, src=ptfadapter.dataplane.get_mac(0, ptf_src_port).decode()) \
/ IPv6(src=ptfadapter.ptf_ipv6, dst="fcbb:bbbb:1:2::") \
/ IPv6() / ICMPv6EchoRequest(seq=i)

expected_pkt = injected_pkt.copy()
expected_pkt['Ether'].dst = get_neighbor_info(neighbor_ip, nbrhosts)['mac']
expected_pkt['Ether'].src = dut_mac
expected_pkt['IPv6'].dst = "fcbb:bbbb:2::"
expected_pkt['IPv6'].hlim -= 1
logger.debug("Expected packet #{}: {}".format(i, expected_pkt.summary()))
runSendReceive(injected_pkt, ptf_src_port, expected_pkt, [ptf_src_port], True, ptfadapter)

# delete the SRv6 configuration
duthost.command(sonic_db_cli + " CONFIG_DB DEL SRV6_MY_LOCATORS\\|loc1")
duthost.command(sonic_db_cli + " CONFIG_DB DEL SRV6_MY_SIDS\\|loc1\\|fcbb:bbbb:1::/48")
duthost.command(sonic_db_cli + " CONFIG_DB DEL STATIC_ROUTE\\|default\\|fcbb:bbbb:2::/48")


@pytest.mark.parametrize("with_srh", [True, False])
def test_srv6_uN_decap_pipe_mode(duthosts, enum_frontend_dut_hostname, enum_frontend_asic_index,
ptfadapter, tbinfo, nbrhosts, with_srh):
duthost = duthosts[enum_frontend_dut_hostname]
asic_index = enum_frontend_asic_index

if duthost.is_multi_asic:
cli_options = " -n " + duthost.get_namespace_from_asic_id(asic_index)
dut_asic = duthost.asic_instance[asic_index]
dut_mac = dut_asic.get_router_mac()
dut_port, ptf_src_port, neighbor = get_ptf_src_port_and_dut_port_and_neighbor(dut_asic, tbinfo)
else:
cli_options = ''
dut_mac = duthost._get_router_mac()
dut_port, ptf_src_port, neighbor = get_ptf_src_port_and_dut_port_and_neighbor(duthost, tbinfo)

logger.info("Doing test on DUT port {} | PTF port {}".format(dut_port, ptf_src_port))

# get neighbor IP
lines = duthost.command("show ipv6 bgp sum")['stdout'].split("\n")
for line in lines:
if neighbor in line:
neighbor_ip = line.split()[0]
assert neighbor_ip

# use DUT portchannel if applicable
pc_info = duthost.command("show int portchannel")['stdout']
if dut_port in pc_info:
lines = pc_info.split("\n")
for line in lines:
if dut_port in line:
dut_port = line.split()[1]

sonic_db_cli = "sonic-db-cli" + cli_options

# add a locator configuration entry
duthost.command(sonic_db_cli + " CONFIG_DB HSET SRV6_MY_LOCATORS\\|loc1 prefix fcbb:bbbb:1::")
# add a uN sid configuration entry
duthost.command(sonic_db_cli +
" CONFIG_DB HSET SRV6_MY_SIDS\\|loc1\\|fcbb:bbbb:1::/48 action uN decap_dscp_mode pipe")

time.sleep(5)

for i in range(0, 10):
if with_srh:
injected_pkt = simple_ipv6_sr_packet(
eth_dst=dut_mac,
eth_src=ptfadapter.dataplane.get_mac(0, ptf_src_port).decode(),
ipv6_src=ptfadapter.ptf_ipv6,
ipv6_dst="fcbb:bbbb:1::",
srh_seg_left=1,
srh_nh=41,
inner_frame=IPv6(dst=neighbor_ip, src=ptfadapter.ptf_ipv6)/ICMPv6EchoRequest(seq=i)
)
else:
injected_pkt = Ether(dst=dut_mac, src=ptfadapter.dataplane.get_mac(0, ptf_src_port).decode()) \
/ IPv6(src=ptfadapter.ptf_ipv6, dst="fcbb:bbbb:1::") \
/ IPv6(dst=neighbor_ip, src=ptfadapter.ptf_ipv6) / ICMPv6EchoRequest(seq=i)

expected_pkt = Ether(dst=get_neighbor_info(neighbor_ip, nbrhosts)['mac'], src=dut_mac) / \
IPv6(dst=neighbor_ip, src=ptfadapter.ptf_ipv6)/ICMPv6EchoRequest(seq=i)
logger.debug("Expected packet #{}: {}".format(i, expected_pkt.summary()))
runSendReceive(injected_pkt, ptf_src_port, expected_pkt, [ptf_src_port], True, ptfadapter)

# delete the SRv6 configuration
duthost.command(sonic_db_cli + " CONFIG_DB DEL SRV6_MY_LOCATORS\\|loc1")
duthost.command(sonic_db_cli + " CONFIG_DB DEL SRV6_MY_SIDS\\|loc1\\|fcbb:bbbb:1::/48")