tests: Added NSIM plugin tests
Type: test Change-Id: Id621a806b853688ced7c6a38e1a9e5f298d2b97e Signed-off-by: adrianvillin <avillin@cisco.com>
This commit is contained in:
parent
87a8826d17
commit
6160f2ddb2
267
test/test_nsim.py
Normal file
267
test/test_nsim.py
Normal file
@ -0,0 +1,267 @@
|
||||
from framework import VppTestCase
|
||||
from asfframework import VppTestRunner
|
||||
from config import config
|
||||
import unittest
|
||||
import re
|
||||
|
||||
from scapy.layers.l2 import Ether
|
||||
from scapy.layers.inet import IP, UDP
|
||||
from scapy.packet import Raw
|
||||
from random import randint
|
||||
from util import ppp
|
||||
|
||||
|
||||
def create_stream(self, src_if, dst_if, count):
|
||||
packets = []
|
||||
for i in range(count):
|
||||
# create packet info stored in the test case instance
|
||||
info = self.create_packet_info(src_if, dst_if)
|
||||
# convert the info into packet payload
|
||||
payload = self.info_to_payload(info)
|
||||
# create the packet itself
|
||||
p = (
|
||||
Ether(dst=src_if.local_mac, src=src_if.remote_mac)
|
||||
/ IP(src=src_if.remote_ip4, dst=dst_if.remote_ip4)
|
||||
/ UDP(sport=randint(49152, 65535), dport=5678)
|
||||
/ Raw(payload)
|
||||
)
|
||||
# store a copy of the packet in the packet info
|
||||
info.data = p.copy()
|
||||
# append the packet to the list
|
||||
packets.append(p)
|
||||
|
||||
# return the created packet list
|
||||
return packets
|
||||
|
||||
|
||||
def verify_capture(self, src_if, dst_if, capture, reply):
|
||||
packet_info = None
|
||||
for packet in capture:
|
||||
try:
|
||||
ip = packet[IP]
|
||||
udp = packet[UDP]
|
||||
# convert the payload to packet info object
|
||||
payload_info = self.payload_to_info(packet[Raw])
|
||||
# make sure the indexes match
|
||||
self.assert_equal(
|
||||
payload_info.src, src_if.sw_if_index, "source sw_if_index"
|
||||
)
|
||||
self.assert_equal(
|
||||
payload_info.dst, dst_if.sw_if_index, "destination sw_if_index"
|
||||
)
|
||||
packet_info = self.get_next_packet_info_for_interface2(
|
||||
src_if.sw_if_index, dst_if.sw_if_index, packet_info
|
||||
)
|
||||
# make sure we didn't run out of saved packets
|
||||
self.assertIsNotNone(packet_info)
|
||||
self.assert_equal(
|
||||
payload_info.index, packet_info.index, "packet info index"
|
||||
)
|
||||
saved_packet = packet_info.data # fetch the saved packet
|
||||
# assert the values match
|
||||
self.assert_equal(ip.src, saved_packet[IP].src, "IP source address")
|
||||
# ... more assertions here
|
||||
self.assert_equal(udp.sport, saved_packet[UDP].sport, "UDP source port")
|
||||
except Exception:
|
||||
self.logger.error(ppp("Unexpected or invalid packet:", packet))
|
||||
raise
|
||||
remaining_packet = self.get_next_packet_info_for_interface2(
|
||||
src_if.sw_if_index, dst_if.sw_if_index, packet_info
|
||||
)
|
||||
self.assertIsNone(
|
||||
remaining_packet,
|
||||
"Interface %s: Packet expected from interface "
|
||||
"%s didn't arrive" % (dst_if.name, src_if.name),
|
||||
)
|
||||
|
||||
# find timestamps and get actual delay
|
||||
pattern = r"\d{2}:\d{2}:\d{2}:\d{6}"
|
||||
timestamps = re.findall(pattern, reply)
|
||||
actual_delay = int(timestamps[2][9:]) - int(timestamps[0][9:])
|
||||
self.assertTrue(
|
||||
actual_delay >= 100000, f"Delay is lower than expected: {actual_delay} < 100000"
|
||||
)
|
||||
|
||||
|
||||
@unittest.skipIf("nsim" in config.excluded_plugins, "Exclude NSIM plugin tests")
|
||||
class TestNsimCli(VppTestCase):
|
||||
"""NSIM plugin tests [CLI]"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestNsimCli, cls).setUpClass()
|
||||
try:
|
||||
cls.create_pg_interfaces(range(2))
|
||||
for i in cls.pg_interfaces:
|
||||
i.config_ip4()
|
||||
i.resolve_arp()
|
||||
i.admin_up()
|
||||
except Exception:
|
||||
cls.tearDownClass()
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.vapi.cli("nsim cross-connect enable-disable pg0 pg1 disable")
|
||||
cls.vapi.cli("nsim output-feature enable-disable pg0 disable")
|
||||
for i in cls.pg_interfaces:
|
||||
i.unconfig_ip4()
|
||||
i.admin_down()
|
||||
super(TestNsimCli, cls).tearDownClass()
|
||||
|
||||
def test_nsim_delay(self):
|
||||
"""Add 100ms delay"""
|
||||
packets = create_stream(self, self.pg0, self.pg1, 5)
|
||||
self.pg0.add_stream(packets)
|
||||
self.pg0.enable_capture()
|
||||
self.pg1.enable_capture()
|
||||
|
||||
self.vapi.cli(
|
||||
"set nsim delay 100.0 ms bandwidth 1 gbit packet-size 128 drop-fraction 0.0"
|
||||
)
|
||||
self.vapi.cli("nsim cross-connect enable-disable pg0 pg1")
|
||||
self.vapi.cli("nsim output-feature enable-disable pg0")
|
||||
|
||||
self.pg_start()
|
||||
capture = self.pg1.get_capture()
|
||||
self.pg0.assert_nothing_captured()
|
||||
reply = self.vapi.cli("show trace")
|
||||
verify_capture(self, self.pg0, self.pg1, capture, reply)
|
||||
self.assertIn("nsim", reply)
|
||||
reply = self.vapi.cli("show nsim")
|
||||
self.assertIn("delay: 100.0 ms", reply)
|
||||
|
||||
def test_nsim_drop(self):
|
||||
"""Drop all packets"""
|
||||
packets = create_stream(self, self.pg0, self.pg1, 5)
|
||||
self.pg0.add_stream(packets)
|
||||
self.vapi.cli("clear trace")
|
||||
# test fails if running test-debug and no delay is set ("invalid delay 0.00")
|
||||
self.vapi.cli(
|
||||
"set nsim delay 1 us bandwidth 1 gbit packet-size 128 drop-fraction 1.0 packets-per-drop 0"
|
||||
)
|
||||
|
||||
self.pg_start()
|
||||
self.pg1.assert_nothing_captured()
|
||||
reply = self.vapi.cli("show nsim")
|
||||
self.assertIn("drop fraction: 1.0", reply)
|
||||
reply = self.vapi.cli("show trace")
|
||||
self.assertIn("sw_if_index -1", reply)
|
||||
|
||||
|
||||
@unittest.skipIf("nsim" in config.excluded_plugins, "Exclude NSIM plugin tests")
|
||||
class TestNsimApi(VppTestCase):
|
||||
"""NSIM plugin tests [API]"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestNsimApi, cls).setUpClass()
|
||||
try:
|
||||
cls.create_pg_interfaces(range(2))
|
||||
for i in cls.pg_interfaces:
|
||||
i.config_ip4()
|
||||
i.resolve_arp()
|
||||
i.admin_up()
|
||||
except Exception:
|
||||
cls.tearDownClass()
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.vapi.nsim_cross_connect_enable_disable(
|
||||
enable_disable=False, sw_if_index0=1, sw_if_index1=2
|
||||
)
|
||||
cls.vapi.nsim_output_feature_enable_disable(enable_disable=False, sw_if_index=1)
|
||||
for i in cls.pg_interfaces:
|
||||
i.unconfig_ip4()
|
||||
i.admin_down()
|
||||
super(TestNsimApi, cls).tearDownClass()
|
||||
|
||||
def test_nsim_delay(self):
|
||||
"""Add 100ms delay"""
|
||||
packets = create_stream(self, self.pg0, self.pg1, 5)
|
||||
self.pg0.add_stream(packets)
|
||||
self.pg0.enable_capture()
|
||||
self.pg1.enable_capture()
|
||||
|
||||
# "show nsim" shows 99.9ms if delay is exactly 100000
|
||||
self.vapi.nsim_configure2(
|
||||
delay_in_usec=100001,
|
||||
average_packet_size=128,
|
||||
bandwidth_in_bits_per_second=100000000000,
|
||||
packets_per_drop=0,
|
||||
packets_per_reorder=0,
|
||||
)
|
||||
self.vapi.nsim_cross_connect_enable_disable(
|
||||
enable_disable=True, sw_if_index0=1, sw_if_index1=2
|
||||
)
|
||||
self.vapi.nsim_output_feature_enable_disable(enable_disable=True, sw_if_index=1)
|
||||
self.pg_start()
|
||||
capture = self.pg1.get_capture()
|
||||
reply = self.vapi.cli("show trace")
|
||||
verify_capture(self, self.pg0, self.pg1, capture, reply)
|
||||
self.assertIn("nsim", reply)
|
||||
reply = self.vapi.cli("show nsim")
|
||||
self.assertIn("delay: 100.0 ms", reply)
|
||||
|
||||
|
||||
# has to be separated, otherwise we get "VPP API client: read failed"
|
||||
# when configuring NSIM (nsim_configure2) and then VPP crashes on teardown
|
||||
@unittest.skipIf("nsim" in config.excluded_plugins, "Exclude NSIM plugin tests")
|
||||
class TestNsimApi2(VppTestCase):
|
||||
"""NSIM plugin tests [API]"""
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
super(TestNsimApi2, cls).setUpClass()
|
||||
try:
|
||||
cls.create_pg_interfaces(range(2))
|
||||
for i in cls.pg_interfaces:
|
||||
i.config_ip4()
|
||||
i.resolve_arp()
|
||||
i.admin_up()
|
||||
except Exception:
|
||||
cls.tearDownClass()
|
||||
raise
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
cls.vapi.nsim_cross_connect_enable_disable(
|
||||
enable_disable=False, sw_if_index0=1, sw_if_index1=2
|
||||
)
|
||||
cls.vapi.nsim_output_feature_enable_disable(enable_disable=False, sw_if_index=1)
|
||||
for i in cls.pg_interfaces:
|
||||
i.unconfig_ip4()
|
||||
i.admin_down()
|
||||
super(TestNsimApi2, cls).tearDownClass()
|
||||
|
||||
def test_nsim_drop(self):
|
||||
"""Drop all packets"""
|
||||
packets = create_stream(self, self.pg0, self.pg1, 5)
|
||||
self.pg0.add_stream(packets)
|
||||
self.pg0.enable_capture()
|
||||
self.pg1.enable_capture()
|
||||
self.vapi.cli("clear trace")
|
||||
|
||||
self.vapi.nsim_configure2(
|
||||
delay_in_usec=10,
|
||||
average_packet_size=128,
|
||||
bandwidth_in_bits_per_second=100000000,
|
||||
packets_per_drop=1,
|
||||
packets_per_reorder=0,
|
||||
)
|
||||
self.vapi.nsim_cross_connect_enable_disable(
|
||||
enable_disable=True, sw_if_index0=1, sw_if_index1=2
|
||||
)
|
||||
self.vapi.nsim_output_feature_enable_disable(enable_disable=True, sw_if_index=1)
|
||||
|
||||
self.pg_start()
|
||||
self.pg1.assert_nothing_captured()
|
||||
reply = self.vapi.cli("show nsim")
|
||||
self.assertIn("drop fraction: 1.0", reply)
|
||||
reply = self.vapi.cli("show trace")
|
||||
self.assertIn("sw_if_index -1", reply)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
unittest.main(testRunner=VppTestRunner)
|
Loading…
x
Reference in New Issue
Block a user