Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pluggable packet module proposal #147

Merged
merged 9 commits into from
Nov 30, 2021
89 changes: 48 additions & 41 deletions ptf
Original file line number Diff line number Diff line change
Expand Up @@ -50,61 +50,65 @@ DEBUG_LEVELS = {
# The default configuration dictionary for PTF
config_default = {
# Miscellaneous options
"list" : False,
"list_test_names" : False,
"allow_user" : False,
"list" : False,
sborkows marked this conversation as resolved.
Show resolved Hide resolved
"list_test_names" : False,
"allow_user" : False,

# Test selection options
"test_spec" : "",
"test_file" : None,
"test_dir" : None,
"test_order" : "default",
"test_order_seed" : 0xaba,
"test_spec" : "",
"test_file" : None,
"test_dir" : None,
"test_order" : "default",
"test_order_seed" : 0xaba,

# Switch connection options
"platform" : "eth",
"platform_args" : None,
"platform_dir" : None,
"interfaces" : [],
"port_info" : {},
"device_sockets" : [], # when using nanomsg
"platform" : "eth",
"platform_args" : None,
"platform_dir" : None,
"interfaces" : [],
"port_info" : {},
"device_sockets" : [], # when using nanomsg

# Logging options
"log_file" : "ptf.log",
"log_dir" : None,
"debug" : "verbose",
"profile" : False,
"profile_file" : "profile.out",
"xunit" : False,
"xunit_dir" : "xunit",
"log_file" : "ptf.log",
"log_dir" : None,
"debug" : "verbose",
"profile" : False,
"profile_file" : "profile.out",
"xunit" : False,
"xunit_dir" : "xunit",

# Test behavior options
"relax" : False,
"test_params" : None,
"failfast" : False,
"fail_skipped" : False,
"default_timeout" : 2.0,
"default_negative_timeout" : 0.1,
"minsize" : 0,
"random_seed" : None,
"disable_ipv6" : False,
"disable_vxlan" : False,
"disable_erspan" : False,
"disable_geneve" : False,
"disable_mpls" : False,
"disable_nvgre" : False,
"disable_igmp" : False,
"disable_rocev2" : False,
"qlen" : 100,
"test_case_timeout" : None,
"relax" : False,
"test_params" : None,
"failfast" : False,
"fail_skipped" : False,
"default_timeout" : 2.0,
"default_negative_timeout" : 0.1,
"minsize" : 0,
"random_seed" : None,
"disable_ipv6" : False,
"disable_vxlan" : False,
"disable_erspan" : False,
"disable_geneve" : False,
"disable_mpls" : False,
"disable_nvgre" : False,
"disable_igmp" : False,
"disable_rocev2" : False,
"qlen" : 100,
"test_case_timeout" : None,

# Socket options
"socket_recv_size" : 4096,
"socket_recv_size" : 4096,

# Packet manipulation provider module
"packet_manipulation_module": "ptf.packet_scapy",

# Other configuration
"port_map" : None,
"port_map" : None,
}


def config_setup():
"""
Set up the configuration including parsing the arguments
Expand Down Expand Up @@ -231,6 +235,9 @@ be subtracted from the result by prefixing them with the '^' character. """

parser.add_argument("--pypath", dest="pypath", action="append")

parser.add_argument("--packet-manipulation-module", type=str,
sborkows marked this conversation as resolved.
Show resolved Hide resolved
help="Provide packet manipulation module which should be used as a 'packet' one for other PTF modules")

group = parser.add_argument_group("Test selection options")
group.add_argument("-f", "--test-file", help="File of tests to run, one per line")
group.add_argument("--test-dir", type=str, action=ActionTestDir,
Expand Down
156 changes: 15 additions & 141 deletions src/ptf/packet.py
Original file line number Diff line number Diff line change
@@ -1,146 +1,20 @@
# Distributed under the OpenFlow Software License (see LICENSE)
# Copyright (c) 2010 The Board of Trustees of The Leland Stanford Junior University
# Copyright (c) 2012, 2013 Big Switch Networks, Inc.
"""
Wrap scapy to satisfy pylint
""" A pluggable packet module
sborkows marked this conversation as resolved.
Show resolved Hide resolved

This module dynamically imports definitions from packet manipulation module,
specified in config or provided as an agrument.
The default one is Scapy, but one can develop its own packet manipulation framework and
then, create an implementation of packet module for it (for Scapy it is packet_scapy.py)
"""
import ptf
from ptf import config
import sys
import logging

try:
import scapy.config
import scapy.route
import scapy.layers.l2
import scapy.layers.inet
import scapy.layers.dhcp
import scapy.layers.vxlan
import scapy.packet
import scapy.main
import scapy.fields

if not config.get("disable_ipv6", False):
import scapy.route6
import scapy.layers.inet6
except ImportError:
sys.exit("Need to install scapy for packet parsing")

Ether = scapy.layers.l2.Ether
LLC = scapy.layers.l2.LLC
SNAP = scapy.layers.l2.SNAP
Dot1Q = scapy.layers.l2.Dot1Q
GRE = scapy.layers.l2.GRE
IP = scapy.layers.inet.IP
IPOption = scapy.layers.inet.IPOption
try:
ARP = scapy.layers.inet.ARP
except AttributeError:
# Works with more recent versions of Scapy
ARP = scapy.layers.l2.ARP
TCP = scapy.layers.inet.TCP
UDP = scapy.layers.inet.UDP
ICMP = scapy.layers.inet.ICMP
DHCP = scapy.layers.dhcp.DHCP
BOOTP = scapy.layers.dhcp.BOOTP
PADDING = scapy.packet.Padding
VXLAN = scapy.layers.vxlan.VXLAN

BTH = None
if not config.get("disable_rocev2", False):
try:
ptf.disable_logging()
scapy.main.load_contrib("roce")
BTH = scapy.contrib.roce.BTH
ptf.enable_logging()
logging.info("ROCEv2 support found in Scapy")
except:
ptf.enable_logging()
logging.warn("ROCEv2 support not found in Scapy")
pass

if not config.get("disable_ipv6", False):
IPv6 = scapy.layers.inet6.IPv6
IPv6ExtHdrRouting = scapy.layers.inet6.IPv6ExtHdrRouting
ICMPv6Unknown = scapy.layers.inet6.ICMPv6Unknown
ICMPv6EchoRequest = scapy.layers.inet6.ICMPv6EchoRequest
ICMPv6MLReport = scapy.layers.inet6.ICMPv6MLReport

ERSPAN = None
ERSPAN_III = None
PlatformSpecific = None
if not config.get("disable_erspan", False):
try:
ptf.disable_logging()
scapy.main.load_contrib("erspan")
ERSPAN = scapy.contrib.erspan.ERSPAN
ERSPAN_III = scapy.contrib.erspan.ERSPAN_III
PlatformSpecific = scapy.contrib.erspan.ERSPAN_PlatformSpecific
ptf.enable_logging()
logging.info("ERSPAN support found in Scapy")
except:
ptf.enable_logging()
logging.warn("ERSPAN support not found in Scapy")
pass

GENEVE = None
if not config.get("disable_geneve", False):
try:
ptf.disable_logging()
scapy.main.load_contrib("geneve")
GENEVE = scapy.contrib.geneve.GENEVE
ptf.enable_logging()
logging.info("GENEVE support found in Scapy")
except:
ptf.enable_logging()
logging.warn("GENEVE support not found in Scapy")
pass

MPLS = None
if not config.get("disable_mpls", False):
try:
ptf.disable_logging()
scapy.main.load_contrib("mpls")
MPLS = scapy.contrib.mpls.MPLS
ptf.enable_logging()
logging.info("MPLS support found in Scapy")
except:
ptf.enable_logging()
logging.warn("MPLS support not found in Scapy")
pass

NVGRE = None
if not config.get("disable_nvgre", False):

class NVGRE(scapy.packet.Packet):
name = "NVGRE"
fields_desc = [
scapy.fields.BitField("chksum_present", 0, 1),
scapy.fields.BitField("routing_present", 0, 1),
scapy.fields.BitField("key_present", 1, 1),
scapy.fields.BitField("seqnum_present", 0, 1),
scapy.fields.BitField("reserved", 0, 9),
scapy.fields.BitField("version", 0, 3),
scapy.fields.XShortField("proto", 0x6558),
scapy.fields.ThreeBytesField("vsid", 0),
scapy.fields.XByteField("flowid", 0),
]

def mysummary(self):
return self.sprintf("NVGRE (vni=%NVGRE.vsid%)")
__module = __import__(config.get("packet_manipulation_module"), fromlist=["*"])
sborkows marked this conversation as resolved.
Show resolved Hide resolved
__keys = []

scapy.packet.bind_layers(IP, NVGRE, proto=47)
scapy.packet.bind_layers(NVGRE, Ether)
# import logic - everything from __all__ if provided, otherwise everything not starting
# with underscore
if "__all__" in __module.__dict__:
__keys = __module.__dict__["__all__"]
else:
__keys = [k for k in __module.__dict__ if not k.startswith("_")]

IGMP = None
if not config.get("disable_igmp", False):
try:
ptf.disable_logging()
scapy.main.load_contrib("igmp")
IGMP = scapy.contrib.igmp.IGMP
ptf.enable_logging()
logging.info("IGMP support found in Scapy")
except:
ptf.enable_logging()
logging.warn("IGMP support not found in Scapy")
pass
locals().update({k: getattr(__module, k) for k in __keys})
Loading