summaryrefslogtreecommitdiffstats
path: root/test/vpp_pg_interface.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/vpp_pg_interface.py')
-rw-r--r--test/vpp_pg_interface.py256
1 files changed, 144 insertions, 112 deletions
diff --git a/test/vpp_pg_interface.py b/test/vpp_pg_interface.py
index 779eb0be6d9..2682774caab 100644
--- a/test/vpp_pg_interface.py
+++ b/test/vpp_pg_interface.py
@@ -13,20 +13,28 @@ from vpp_interface import VppInterface
from vpp_papi import VppEnum
from scapy.layers.l2 import Ether, ARP
-from scapy.layers.inet6 import IPv6, ICMPv6ND_NS, ICMPv6ND_NA,\
- ICMPv6NDOptSrcLLAddr, ICMPv6NDOptDstLLAddr, ICMPv6ND_RA, RouterAlert, \
- IPv6ExtHdrHopByHop
+from scapy.layers.inet6 import (
+ IPv6,
+ ICMPv6ND_NS,
+ ICMPv6ND_NA,
+ ICMPv6NDOptSrcLLAddr,
+ ICMPv6NDOptDstLLAddr,
+ ICMPv6ND_RA,
+ RouterAlert,
+ IPv6ExtHdrHopByHop,
+)
from util import ppp, ppc, UnexpectedPacketError
from scapy.utils6 import in6_getnsma, in6_getnsmac, in6_ismaddr
class CaptureTimeoutError(Exception):
- """ Exception raised if capture or packet doesn't appear within timeout """
+ """Exception raised if capture or packet doesn't appear within timeout"""
+
pass
def is_ipv6_misc(p):
- """ Is packet one of uninteresting IPv6 broadcasts? """
+ """Is packet one of uninteresting IPv6 broadcasts?"""
if p.haslayer(ICMPv6ND_RA):
if in6_ismaddr(p[IPv6].dst):
return True
@@ -72,10 +80,9 @@ class VppPGInterface(VppInterface):
return self._out_path
def get_in_path(self, worker):
- """ pcap file path - injected packets"""
+ """pcap file path - injected packets"""
if worker is not None:
- return "%s/pg%u_wrk%u_in.pcap" % (self.test.tempdir, self.pg_index,
- worker)
+ return "%s/pg%u_wrk%u_in.pcap" % (self.test.tempdir, self.pg_index, worker)
return "%s/pg%u_in.pcap" % (self.test.tempdir, self.pg_index)
@property
@@ -92,7 +99,10 @@ class VppPGInterface(VppInterface):
def get_input_cli(self, nb_replays=None, worker=None):
"""return CLI string to load the injected packets"""
input_cli = "packet-generator new pcap %s source pg%u name %s" % (
- self.get_in_path(worker), self.pg_index, self.get_cap_name(worker))
+ self.get_in_path(worker),
+ self.pg_index,
+ self.get_cap_name(worker),
+ )
if nb_replays is not None:
return "%s limit %d" % (input_cli, nb_replays)
if worker is not None:
@@ -114,7 +124,7 @@ class VppPGInterface(VppInterface):
return v
def __init__(self, test, pg_index, gso, gso_size, mode):
- """ Create VPP packet-generator interface """
+ """Create VPP packet-generator interface"""
super().__init__(test)
r = test.vapi.pg_create_interface_v2(pg_index, gso, gso_size, mode)
@@ -130,9 +140,10 @@ class VppPGInterface(VppInterface):
self._out_file = "pg%u_out.pcap" % self.pg_index
self._out_path = self.test.tempdir + "/" + self._out_file
self._capture_cli = "packet-generator capture pg%u pcap %s" % (
- self.pg_index, self.out_path)
- self._cap_name = "pcap%u-sw_if_index-%s" % (
- self.pg_index, self.sw_if_index)
+ self.pg_index,
+ self.out_path,
+ )
+ self._cap_name = "pcap%u-sw_if_index-%s" % (self.pg_index, self.sw_if_index)
def handle_old_pcap_file(self, path, counter):
filename = os.path.basename(path)
@@ -149,22 +160,22 @@ class VppPGInterface(VppInterface):
try:
if os.path.isfile(path):
- name = "%s/history.[timestamp:%f].[%s-counter:%04d].%s" % \
- (self.test.tempdir,
- time.time(),
- self.name,
- counter,
- filename)
+ name = "%s/history.[timestamp:%f].[%s-counter:%04d].%s" % (
+ self.test.tempdir,
+ time.time(),
+ self.name,
+ counter,
+ filename,
+ )
self.test.logger.debug("Renaming %s->%s" % (path, name))
os.rename(path, name)
except OSError:
- self.test.logger.debug("OSError: Could not rename %s %s" %
- (path, filename))
+ self.test.logger.debug("OSError: Could not rename %s %s" % (path, filename))
def enable_capture(self):
- """ Enable capture on this packet-generator interface
- of at most n packets.
- If n < 0, this is no limit
+ """Enable capture on this packet-generator interface
+ of at most n packets.
+ If n < 0, this is no limit
"""
# disable the capture to flush the capture
self.disable_capture()
@@ -177,16 +188,14 @@ class VppPGInterface(VppInterface):
self.test.vapi.cli("%s disable" % self.capture_cli)
def coalesce_enable(self):
- """ Enable packet coalesce on this packet-generator interface"""
+ """Enable packet coalesce on this packet-generator interface"""
self._coalesce_enabled = 1
- self.test.vapi.pg_interface_enable_disable_coalesce(self.sw_if_index,
- 1)
+ self.test.vapi.pg_interface_enable_disable_coalesce(self.sw_if_index, 1)
def coalesce_disable(self):
- """ Disable packet coalesce on this packet-generator interface"""
+ """Disable packet coalesce on this packet-generator interface"""
self._coalesce_enabled = 0
- self.test.vapi.pg_interface_enable_disable_coalesce(self.sw_if_index,
- 0)
+ self.test.vapi.pg_interface_enable_disable_coalesce(self.sw_if_index, 0)
def add_stream(self, pkts, nb_replays=None, worker=None):
"""
@@ -201,31 +210,31 @@ class VppPGInterface(VppInterface):
self.test.vapi.cli(self.get_input_cli(nb_replays, worker))
def generate_debug_aid(self, kind):
- """ Create a hardlink to the out file with a counter and a file
+ """Create a hardlink to the out file with a counter and a file
containing stack trace to ease debugging in case of multiple capture
- files present. """
- self.test.logger.debug("Generating debug aid for %s on %s" %
- (kind, self._name))
- link_path, stack_path = ["%s/debug_%s_%s_%s.%s" %
- (self.test.tempdir, self._name,
- self._out_assert_counter, kind, suffix)
- for suffix in ["pcap", "stack"]
- ]
+ files present."""
+ self.test.logger.debug("Generating debug aid for %s on %s" % (kind, self._name))
+ link_path, stack_path = [
+ "%s/debug_%s_%s_%s.%s"
+ % (self.test.tempdir, self._name, self._out_assert_counter, kind, suffix)
+ for suffix in ["pcap", "stack"]
+ ]
os.link(self.out_path, link_path)
with open(stack_path, "w") as f:
f.writelines(format_stack())
self._out_assert_counter += 1
def _get_capture(self, timeout, filter_out_fn=is_ipv6_misc):
- """ Helper method to get capture and filter it """
+ """Helper method to get capture and filter it"""
try:
if not self.wait_for_capture_file(timeout):
return None
output = rdpcap(self.out_path)
self.test.logger.debug("Capture has %s packets" % len(output.res))
except:
- self.test.logger.debug("Exception in scapy.rdpcap (%s): %s" %
- (self.out_path, format_exc()))
+ self.test.logger.debug(
+ "Exception in scapy.rdpcap (%s): %s" % (self.out_path, format_exc())
+ )
return None
before = len(output.res)
if filter_out_fn:
@@ -233,13 +242,15 @@ class VppPGInterface(VppInterface):
removed = before - len(output.res)
if removed:
self.test.logger.debug(
- "Filtered out %s packets from capture (returning %s)" %
- (removed, len(output.res)))
+ "Filtered out %s packets from capture (returning %s)"
+ % (removed, len(output.res))
+ )
return output
- def get_capture(self, expected_count=None, remark=None, timeout=1,
- filter_out_fn=is_ipv6_misc):
- """ Get captured packets
+ def get_capture(
+ self, expected_count=None, remark=None, timeout=1, filter_out_fn=is_ipv6_misc
+ ):
+ """Get captured packets
:param expected_count: expected number of packets to capture, if None,
then self.test.packet_count_for_dst_pg_idx is
@@ -255,15 +266,16 @@ class VppPGInterface(VppInterface):
name = self.name if remark is None else "%s (%s)" % (self.name, remark)
based_on = "based on provided argument"
if expected_count is None:
- expected_count = \
- self.test.get_packet_count_for_if_idx(self.sw_if_index)
+ expected_count = self.test.get_packet_count_for_if_idx(self.sw_if_index)
based_on = "based on stored packet_infos"
if expected_count == 0:
raise Exception(
- "Internal error, expected packet count for %s is 0!" %
- name)
- self.test.logger.debug("Expecting to capture %s (%s) packets on %s" % (
- expected_count, based_on, name))
+ "Internal error, expected packet count for %s is 0!" % name
+ )
+ self.test.logger.debug(
+ "Expecting to capture %s (%s) packets on %s"
+ % (expected_count, based_on, name)
+ )
while remaining_time > 0:
before = time.time()
capture = self._get_capture(remaining_time, filter_out_fn)
@@ -273,14 +285,14 @@ class VppPGInterface(VppInterface):
# bingo, got the packets we expected
return capture
elif len(capture.res) > expected_count:
- self.test.logger.error(
- ppc("Unexpected packets captured:", capture))
+ self.test.logger.error(ppc("Unexpected packets captured:", capture))
break
else:
- self.test.logger.debug("Partial capture containing %s "
- "packets doesn't match expected "
- "count %s (yet?)" %
- (len(capture.res), expected_count))
+ self.test.logger.debug(
+ "Partial capture containing %s "
+ "packets doesn't match expected "
+ "count %s (yet?)" % (len(capture.res), expected_count)
+ )
elif expected_count == 0:
# bingo, got None as we expected - return empty capture
return PacketList()
@@ -290,26 +302,29 @@ class VppPGInterface(VppInterface):
if len(capture) > 0 and 0 == expected_count:
rem = f"\n{remark}" if remark else ""
raise UnexpectedPacketError(
- capture[0],
- f"\n({len(capture)} packets captured in total){rem}")
- raise Exception("Captured packets mismatch, captured %s packets, "
- "expected %s packets on %s" %
- (len(capture.res), expected_count, name))
+ capture[0], f"\n({len(capture)} packets captured in total){rem}"
+ )
+ raise Exception(
+ "Captured packets mismatch, captured %s packets, "
+ "expected %s packets on %s" % (len(capture.res), expected_count, name)
+ )
else:
if 0 == expected_count:
return
raise Exception("No packets captured on %s" % name)
- def assert_nothing_captured(self, timeout=1, remark=None,
- filter_out_fn=is_ipv6_misc):
- """ Assert that nothing unfiltered was captured on interface
+ def assert_nothing_captured(
+ self, timeout=1, remark=None, filter_out_fn=is_ipv6_misc
+ ):
+ """Assert that nothing unfiltered was captured on interface
:param remark: remark printed into debug logs
:param filter_out_fn: filter applied to each packet, packets for which
the filter returns True are removed from capture
"""
- capture = self.get_capture(0, timeout=timeout, remark=remark,
- filter_out_fn=filter_out_fn)
+ capture = self.get_capture(
+ 0, timeout=timeout, remark=remark, filter_out_fn=filter_out_fn
+ )
if not capture or len(capture.res) == 0:
# junk filtered out, we're good
return
@@ -322,7 +337,7 @@ class VppPGInterface(VppInterface):
#
# also have a 5-minute timeout just in case things go terribly wrong...
deadline = time.time() + 300
- while self.test.vapi.cli('show packet-generator').find("Yes") != -1:
+ while self.test.vapi.cli("show packet-generator").find("Yes") != -1:
self._test.sleep(0.01) # yield
if time.time() > deadline:
self.test.logger.debug("Timeout waiting for pg to stop")
@@ -339,19 +354,21 @@ class VppPGInterface(VppInterface):
self.wait_for_pg_stop()
deadline = time.time() + timeout
if not os.path.isfile(self.out_path):
- self.test.logger.debug("Waiting for capture file %s to appear, "
- "timeout is %ss" % (self.out_path, timeout))
+ self.test.logger.debug(
+ "Waiting for capture file %s to appear, "
+ "timeout is %ss" % (self.out_path, timeout)
+ )
else:
- self.test.logger.debug("Capture file %s already exists" %
- self.out_path)
+ self.test.logger.debug("Capture file %s already exists" % self.out_path)
return True
while time.time() < deadline:
if os.path.isfile(self.out_path):
break
self._test.sleep(0) # yield
if os.path.isfile(self.out_path):
- self.test.logger.debug("Capture file appeared after %fs" %
- (time.time() - (deadline - timeout)))
+ self.test.logger.debug(
+ "Capture file appeared after %fs" % (time.time() - (deadline - timeout))
+ )
else:
self.test.logger.debug("Timeout - capture file still nowhere")
return False
@@ -374,7 +391,8 @@ class VppPGInterface(VppInterface):
if len(hdr) == packet_header_size:
# parse the capture length - caplen
sec, usec, caplen, wirelen = struct.unpack(
- self._pcap_reader.endian + "IIII", hdr)
+ self._pcap_reader.endian + "IIII", hdr
+ )
self._pcap_reader.f.seek(0, 2) # seek to end of file
end_pos = self._pcap_reader.f.tell() # get position at end
if end_pos >= orig_pos + len(hdr) + caplen:
@@ -394,19 +412,22 @@ class VppPGInterface(VppInterface):
deadline = time.time() + timeout
if self._pcap_reader is None:
if not self.wait_for_capture_file(timeout):
- raise CaptureTimeoutError("Capture file %s did not appear "
- "within timeout" % self.out_path)
+ raise CaptureTimeoutError(
+ "Capture file %s did not appear within timeout" % self.out_path
+ )
while time.time() < deadline:
try:
self._pcap_reader = PcapReader(self.out_path)
break
except:
self.test.logger.debug(
- "Exception in scapy.PcapReader(%s): %s" %
- (self.out_path, format_exc()))
+ "Exception in scapy.PcapReader(%s): %s"
+ % (self.out_path, format_exc())
+ )
if not self._pcap_reader:
- raise CaptureTimeoutError("Capture file %s did not appear within "
- "timeout" % self.out_path)
+ raise CaptureTimeoutError(
+ "Capture file %s did not appear within timeout" % self.out_path
+ )
poll = False
if timeout > 0:
@@ -423,12 +444,14 @@ class VppPGInterface(VppInterface):
if p is not None:
if filter_out_fn is not None and filter_out_fn(p):
self.test.logger.debug(
- "Packet received after %ss was filtered out" %
- (time.time() - (deadline - timeout)))
+ "Packet received after %ss was filtered out"
+ % (time.time() - (deadline - timeout))
+ )
else:
self.test.logger.debug(
- "Packet received after %fs" %
- (time.time() - (deadline - timeout)))
+ "Packet received after %fs"
+ % (time.time() - (deadline - timeout))
+ )
return p
self._test.sleep(0) # yield
poll = False
@@ -437,9 +460,12 @@ class VppPGInterface(VppInterface):
def create_arp_req(self):
"""Create ARP request applicable for this interface"""
- return (Ether(dst="ff:ff:ff:ff:ff:ff", src=self.remote_mac) /
- ARP(op=ARP.who_has, pdst=self.local_ip4,
- psrc=self.remote_ip4, hwsrc=self.remote_mac))
+ return Ether(dst="ff:ff:ff:ff:ff:ff", src=self.remote_mac) / ARP(
+ op=ARP.who_has,
+ pdst=self.local_ip4,
+ psrc=self.remote_ip4,
+ hwsrc=self.remote_mac,
+ )
def create_ndp_req(self, addr=None):
"""Create NDP - NS applicable for this interface"""
@@ -448,10 +474,12 @@ class VppPGInterface(VppInterface):
nsma = in6_getnsma(inet_pton(socket.AF_INET6, addr))
d = inet_ntop(socket.AF_INET6, nsma)
- return (Ether(dst=in6_getnsmac(nsma)) /
- IPv6(dst=d, src=self.remote_ip6) /
- ICMPv6ND_NS(tgt=addr) /
- ICMPv6NDOptSrcLLAddr(lladdr=self.remote_mac))
+ return (
+ Ether(dst=in6_getnsmac(nsma))
+ / IPv6(dst=d, src=self.remote_ip6)
+ / ICMPv6ND_NS(tgt=addr)
+ / ICMPv6NDOptSrcLLAddr(lladdr=self.remote_mac)
+ )
def resolve_arp(self, pg_interface=None):
"""Resolve ARP using provided packet-generator interface
@@ -462,8 +490,10 @@ class VppPGInterface(VppInterface):
"""
if pg_interface is None:
pg_interface = self
- self.test.logger.info("Sending ARP request for %s on port %s" %
- (self.local_ip4, pg_interface.name))
+ self.test.logger.info(
+ "Sending ARP request for %s on port %s"
+ % (self.local_ip4, pg_interface.name)
+ )
arp_req = self.create_arp_req()
pg_interface.add_stream(arp_req)
pg_interface.enable_capture()
@@ -472,21 +502,21 @@ class VppPGInterface(VppInterface):
try:
captured_packet = pg_interface.wait_for_packet(1)
except:
- self.test.logger.info("No ARP received on port %s" %
- pg_interface.name)
+ self.test.logger.info("No ARP received on port %s" % pg_interface.name)
return
arp_reply = captured_packet.copy() # keep original for exception
try:
if arp_reply[ARP].op == ARP.is_at:
- self.test.logger.info("VPP %s MAC address is %s " %
- (self.name, arp_reply[ARP].hwsrc))
+ self.test.logger.info(
+ "VPP %s MAC address is %s " % (self.name, arp_reply[ARP].hwsrc)
+ )
self._local_mac = arp_reply[ARP].hwsrc
else:
- self.test.logger.info("No ARP received on port %s" %
- pg_interface.name)
+ self.test.logger.info("No ARP received on port %s" % pg_interface.name)
except:
self.test.logger.error(
- ppp("Unexpected response to ARP request:", captured_packet))
+ ppp("Unexpected response to ARP request:", captured_packet)
+ )
raise
def resolve_ndp(self, pg_interface=None, timeout=1, link_layer=False):
@@ -502,8 +532,9 @@ class VppPGInterface(VppInterface):
if pg_interface is None:
pg_interface = self
addr = self.local_ip6_ll if link_layer else self.local_ip6
- self.test.logger.info("Sending NDP request for %s on port %s" %
- (addr, pg_interface.name))
+ self.test.logger.info(
+ "Sending NDP request for %s on port %s" % (addr, pg_interface.name)
+ )
ndp_req = self.create_ndp_req(addr)
pg_interface.add_stream(ndp_req)
pg_interface.enable_capture()
@@ -516,25 +547,26 @@ class VppPGInterface(VppInterface):
while now < deadline:
try:
captured_packet = pg_interface.wait_for_packet(
- deadline - now, filter_out_fn=None)
+ deadline - now, filter_out_fn=None
+ )
except:
- self.test.logger.error(
- "Timeout while waiting for NDP response")
+ self.test.logger.error("Timeout while waiting for NDP response")
raise
ndp_reply = captured_packet.copy() # keep original for exception
try:
ndp_na = ndp_reply[ICMPv6ND_NA]
opt = ndp_na[ICMPv6NDOptDstLLAddr]
- self.test.logger.info("VPP %s MAC address is %s " %
- (self.name, opt.lladdr))
+ self.test.logger.info(
+ "VPP %s MAC address is %s " % (self.name, opt.lladdr)
+ )
self._local_mac = opt.lladdr
self.test.logger.debug(self.test.vapi.cli("show trace"))
# we now have the MAC we've been after
return
except:
self.test.logger.info(
- ppp("Unexpected response to NDP request:",
- captured_packet))
+ ppp("Unexpected response to NDP request:", captured_packet)
+ )
now = time.time()
self.test.logger.debug(self.test.vapi.cli("show trace"))