test suite reviews and discussions
 help / color / mirror / Atom feed
* [dts] [dts 0/4] add unified packet type module and test suite
@ 2015-09-17  1:13 Yufen Mo
  2015-09-17  1:13 ` [dts] [dts 1/4] " Yufen Mo
                   ` (3 more replies)
  0 siblings, 4 replies; 6+ messages in thread
From: Yufen Mo @ 2015-09-17  1:13 UTC (permalink / raw)
  To: dts

From: yufengmx <yufengx.mo@intel.com>

yufengmx (4):
  fix some issue of the test plan for unified packet type
  Add packet module for unified network packet function
  Add test suite for unified packet type     This suite validate unified
    packet type flag feature on different NICs. For     more details,
    please reference to test plan.
  Update lldp and nvgre layer module

 dep/lldp.py                      | 242 +++++++++++++++
 framework/packet.py              | 642 +++++++++++++++++++++++++++++++++++++++
 test_plans/uni_pkt_test_plan.rst |  30 +-
 tests/TestSuite_uni_pkt.py       | 364 ++++++++++++++++++++++
 4 files changed, 1262 insertions(+), 16 deletions(-)
 create mode 100644 dep/lldp.py
 create mode 100755 framework/packet.py
 create mode 100644 tests/TestSuite_uni_pkt.py

-- 
1.9.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dts] [dts 1/4] add unified packet type module and test suite
  2015-09-17  1:13 [dts] [dts 0/4] add unified packet type module and test suite Yufen Mo
@ 2015-09-17  1:13 ` Yufen Mo
  2015-09-17  1:13 ` [dts] [dts 2/4] " Yufen Mo
                   ` (2 subsequent siblings)
  3 siblings, 0 replies; 6+ messages in thread
From: Yufen Mo @ 2015-09-17  1:13 UTC (permalink / raw)
  To: dts

From: yufengmx <yufengx.mo@intel.com>

fix some issue of the test plan for unified packet type

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 test_plans/uni_pkt_test_plan.rst | 30 ++++++++++++++----------------
 1 file changed, 14 insertions(+), 16 deletions(-)

diff --git a/test_plans/uni_pkt_test_plan.rst b/test_plans/uni_pkt_test_plan.rst
index c42308b..5ef661c 100644
--- a/test_plans/uni_pkt_test_plan.rst
+++ b/test_plans/uni_pkt_test_plan.rst
@@ -68,14 +68,14 @@ Send time sync packet from tester::
 
 Check below message dumped by testpmd::
     (outer) L2 type: ETHER_Timesync
-    
+
 Send ARP packet from tester::
     sendp([Ether(dst='FF:FF:FF:FF:FF:FF')/ARP()],
         iface=txItf)
 
 Check below message dumped by testpmd::
     (outer) L2 type: ETHER_ARP
-        
+
 Send LLDP packet from tester::
     sendp([Ether()/LLDP()/LLDPManagementAddress()], iface=txItf)
 
@@ -85,13 +85,12 @@ Check below message dumped by testpmd::
 Test Case: IPv4&L4 packet type detect
 =====================================
 This case checked that whether L3 and L4 packet can be normally detected.
-Niantic and i350 will shown that L2 type is MAC.
 Only Fortville can detect icmp packet.
 Only niantic and i350 can detect ipv4 extension packet.
-Fortville did not detect whether packet contian ipv4 header options, so L3
+Fortville did not detect whether packet contain ipv4 header options, so L3
 type will be shown as IPV4_EXT_UNKNOWN.
 Fortville will identify all unrecognized L4 packet as L4_NONFRAG.
-Only Fortville can inentify L4 fragement packet.
+Only Fortville can identify L4 fragment packet.
 
 Send IP only packet and verify L2/L3/L4 corrected::
     sendp([Ether()/IP()/Raw('\0'*60)], iface=txItf)
@@ -142,11 +141,10 @@ Send IP extension+SCTP packet and verify L2/L3/L4 corrected(Niantic,i350)::
 Test Case: IPv6&L4 packet type detect
 =====================================
 This case checked that whether IPv6 and L4 packet can be normally detected.
-Niantic and i350 will shown that L2 type is MAC.
-Fortville did not detect whether packet contian ipv6 extension options, so L3
+Fortville did not detect whether packet contain ipv6 extension options, so L3
 type will be shown as IPV6_EXT_UNKNOWN.
 Fortville will identify all unrecognized L4 packet as L4_NONFRAG.
-Only Fortville can inentify L4 fragement packet.
+Only Fortville can identify L4 fragment packet.
 
 Send IPv6 only packet and verify L2/L3/L4 corrected::
     sendp([Ether()/IPv6()/Raw('\0'*60)], iface=txItf)
@@ -214,7 +212,7 @@ Send IPv4+IPv4+SCTP packet and verify inner and outer L2/L3/L4 corrected::
     Inner L4 type: SCTP
 
 Send IPv4+IPv4+ICMP packet and verify inner and outer L2/L3/L4 corrected::
-    sendp([Ether()/IP()/IP()/SCTP()/Raw('\0'*40)],iface=txItf)
+    sendp([Ether()/IP()/IP()/ICMP()/Raw('\0'*40)],iface=txItf)
 
     Inner L4 type: ICMP
     
@@ -257,7 +255,7 @@ detected by Niantic and i350.
 Send IPv4+IPv6 packet and verify inner and outer L2/L3/L4 corrected::
     sendp([Ether()/IP()/IPv6()/Raw('\0'*40)], iface=txItf)
 
-    (outer) L2 type: MAC
+    (outer) L2 type: ETHER
     (outer) L3 type: IPV4
     (outer) L4 type: Unknown
     Tunnel type: IP
@@ -332,7 +330,7 @@ Send IPv4+IPv4+SCTP packet and verify inner and outer L2/L3/L4 corrected::
     Inner L4 type: SCTP
 
 Send IPv4+IPv4+ICMP packet and verify inner and outer L2/L3/L4 corrected::
-    sendp([Ether()/IP()/IP()/SCTP()/Raw('\0'*40)],iface=txItf)
+    sendp([Ether()/IP()/IP()/ICMP()/Raw('\0'*40)],iface=txItf)
     
     Inner L4 type: ICMP
     
@@ -501,7 +499,7 @@ Send IPV6+NVGRE+MAC packet and verify inner and outer L2/L3/L4 corrected::
     (outer) L4 type: Unknown
     Tunnel type: GRENAT
     Inner L2 type: ETHER
-    Inner L3 type: Unkown
+    Inner L3 type: Unknown
     Inner L4 type: Unknown
     
 Send IPV6+NVGRE+MAC+IPv4 fragment packet and verify inner and outer L2/L3/L4
@@ -722,7 +720,7 @@ Send IPv4+GRE+IPv4+ICMP packet and verify inner and outer L2/L3/L4 corrected::
 Send IPv4+GRE packet and verify inner and outer L2/L3/L4 corrected::
     sendp([Ether()/IP()/GRE()/Raw('x'*40)], iface=txItf)
 
-    Inner L3 type: Unkown
+    Inner L3 type: Unknown
     Inner L4 type: Unknown
 
 Test Case: Vxlan tunnel packet type detect
@@ -732,7 +730,7 @@ Fortville.
 Fortville did not distinguish GRE/Teredo/Vxlan packets, all those types
 will be displayed as GRENAT.
 
-Add vxlan tunnle port filter on receive port::
+Add vxlan tunnel port filter on receive port::
     rx_vxlan_port add 4789 0
 Send IPv4+Vxlan+MAC+IPv4 fragment packet and verify inner and outer L2/L3/L4
 corrected::
@@ -820,7 +818,7 @@ corrected::
     
 Send IPv4+Vxlan+MAC+IPv6+ICMP packet and verify inner and outer L2/L3/L4
 corrected::
-    sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IPv6(nh=28)/ICMP()/
+    sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/IPv6(nh=58)/ICMP()/
     Raw('\0'*40)], iface=txItf)
 
     Inner L4 type: ICMP
@@ -828,5 +826,5 @@ corrected::
 Send IPv4+Vxlan+MAC packet and verify inner and outer L2/L3/L4 corrected::
     sendp([Ether()/IP()/UDP()/Vxlan()/Ether()/Raw('\0'*40)], iface=txItf)
     
-    Inner L3 type: Unkown
+    Inner L3 type: Unknown
     Inner L4 type: Unknown
-- 
1.9.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dts] [dts 2/4] add unified packet type module and test suite
  2015-09-17  1:13 [dts] [dts 0/4] add unified packet type module and test suite Yufen Mo
  2015-09-17  1:13 ` [dts] [dts 1/4] " Yufen Mo
@ 2015-09-17  1:13 ` Yufen Mo
  2015-09-17  1:13 ` [dts] [dts 3/4] " Yufen Mo
  2015-09-17  1:13 ` [dts] [dts 4/4] " Yufen Mo
  3 siblings, 0 replies; 6+ messages in thread
From: Yufen Mo @ 2015-09-17  1:13 UTC (permalink / raw)
  To: dts

From: yufengmx <yufengx.mo@intel.com>

This module based on scapy module function to handle packet generate and
analyse. Also based on tcpdump tool to sniff packets.

In this module, define some basic type packets which can simple used by name.
For example, "pkt=Packet(pkt_type='UDP')" will prepare default UDP packet.
After "pkt.send_pkt(tx_port='eth0')", the UDP packet will be sent out from
port "eth0".

For those tunnel packets, this module will seperate the packet type and strip
that what layers combine to this packet. For example,
"MAC_IPv6_NVGRE_MAC_IPFRAG_PKT" mean this is nvgre tunnle packet and combined
with Ether/IPv6/Nvgre/Ether/IP_frag/Raw data.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 framework/packet.py | 642 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 642 insertions(+)
 create mode 100755 framework/packet.py

diff --git a/framework/packet.py b/framework/packet.py
new file mode 100755
index 0000000..0a3f330
--- /dev/null
+++ b/framework/packet.py
@@ -0,0 +1,642 @@
+#!/usr/bin/python
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#   * Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
+#     distribution.
+#   * Neither the name of Intel Corporation nor the names of its
+#     contributors may be used to endorse or promote products derived
+#     from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+Generic packet create, transmit and analyze module
+Base on scapy(python program for packet manipulation)
+"""
+
+import os
+import time
+import signal
+import sys
+import re
+import signal
+import random
+import subprocess
+from uuid import uuid4
+from settings import FOLDERS
+
+from scapy.config import conf
+conf.use_pcap = True
+
+from scapy.all import conf
+from scapy.utils import struct, socket, wrpcap, rdpcap
+from scapy.layers.inet import Ether, IP, TCP, UDP, ICMP
+from scapy.layers.inet6 import IPv6, IPv6ExtHdrRouting, IPv6ExtHdrFragment
+from scapy.layers.l2 import Dot1Q, ARP, GRE
+from scapy.layers.sctp import SCTP, SCTPChunkData
+from scapy.sendrecv import sniff
+from scapy.route import *
+from scapy.packet import bind_layers, Raw
+from scapy.sendrecv import sendp
+
+
+sys.path.append(FOLDERS['Depends'])
+# load extension layers
+from vxlan import Vxlan
+bind_layers(UDP, Vxlan, dport=4789)
+bind_layers(Vxlan, Ether)
+from nvgre import NVGRE, IPPROTO_NVGRE
+bind_layers(IP, NVGRE, proto=IPPROTO_NVGRE)
+bind_layers(NVGRE, Ether)
+from lldp import LLDP, LLDPManagementAddress
+bind_layers(Ether, LLDP, type=0x88cc)
+
+# packet generator type should be configured later
+PACKETGEN = "scapy"
+
+LayersTypes = {
+    "L2": ['ether', 'dot1q', '1588', 'arp', 'lldp'],
+    # ipv4_ext_unknown, ipv6_ext_unknown
+    "L3": ['ipv4','ipv4ihl', 'ipv6', 'ipv4_ext', 'ipv6_ext','ipv6_ext2', 'ipv6_frag'],
+    "L4": ['tcp', 'udp', 'frag', 'sctp', 'icmp', 'nofrag'],
+    "TUNNEL": ['ip', 'gre', 'vxlan', 'nvgre', 'geneve', 'grenat'],
+    "INNER L2": ['inner_mac', 'inner_mac&vlan'],
+    # inner_ipv4_unknown, inner_ipv6_unknown
+    "INNER L3": ['inner_ipv4', 'inner_ipv4_ext', 'inner_ipv6', 'inner_ipv6_ext'],
+    "INNER L4": ['inner_tcp', 'inner_udp', 'inner_frag', 'inner_sctp', 'inner_icmp', 'inner_nofrag'],
+    "PAYLOAD": ['raw']
+}
+
+# Saved back groud sniff process id
+SNIFF_PIDS = {}
+
+# Saved packet generator process id
+# used in pktgen or tgen
+PKTGEN_PIDS = {}
+
+
+class scapy(object):
+    SCAPY_LAYERS = {
+        'ether': Ether(dst="ff:ff:ff:ff:ff:ff"),
+        'dot1q': Dot1Q(),
+        '1588': Ether(type=0x88f7),
+        'arp': ARP(),
+        'ipv4': IP(),
+        'ipv4ihl': IP(ihl=10),
+        'ipv4_ext': IP(frag=5),
+        'ipv6': IPv6(src="::1"),
+        'ipv6_ext': IPv6(src="::1", nh=43)/IPv6ExtHdrRouting(),
+        'ipv6_ext2': IPv6()/IPv6ExtHdrRouting(),
+        'udp': UDP(),
+        'tcp': TCP(),
+        'sctp': SCTP(),
+        'icmp': ICMP(),
+        'gre': GRE(),
+        'raw': Raw(),
+        'vxlan': Vxlan(),
+
+        'inner_mac': Ether(),
+        'inner_mac&vlan': Ether() / Dot1Q(),
+        'inner_ipv4': IP(),
+        'inner_ipv4_ext': IP(),
+        'inner_ipv6': IPv6(src="::1"),
+        'inner_ipv6_ext': IPv6(src="::1"),
+
+        'inner_tcp': TCP(),
+        'inner_udp': UDP(),
+        'inner_sctp': SCTP(),
+        'inner_icmp': ICMP(),
+
+        'lldp': LLDP()/LLDPManagementAddress(),
+        'ip_frag': IP(frag=5),
+        'ipv6_frag': IPv6(src="::1")/IPv6ExtHdrFragment(),
+        'ip_in_ip': IP()/IP(),
+        'ip_in_ip_frag': IP()/IP(frag=5),
+        'ipv6_in_ip': IP()/IPv6(src="::1"),
+        'ipv6_frag_in_ip': IP()/IPv6(src="::1", nh=44)/IPv6ExtHdrFragment(),
+        'nvgre': NVGRE(),
+        'geneve': "Not Implement",
+    }
+
+    def __init__(self):
+        self.pkt = None
+        pass
+
+    def assign_pkt(self, pkt):
+        self.pkt = pkt
+
+    def add_layers(self, layers):
+        self.pkt = None
+        for layer in layers:
+            if self.pkt is not None:
+                self.pkt = self.pkt / self.SCAPY_LAYERS[layer]
+            else:
+                self.pkt = self.SCAPY_LAYERS[layer]
+
+    def ether(self, dst="ff:ff:ff:ff:ff:ff", src="00:00:20:00:00:00", type=None):
+        self.pkt[Ether].dst = dst
+        self.pkt[Ether].src = src
+        if type is not None:
+            self.pkt[Ether].type = type
+
+    def dot1q(self, vlan, prio=0, type=None):
+        self.pkt[Dot1Q].vlan = int(vlan)
+        self.pkt[Dot1Q].prio = prio
+        if type is not None:
+            self.pkt[Dot1Q].type = type
+
+    def strip_dot1q(self, element):
+        value = None
+
+        if self.pkt.haslayer('Dot1Q') is 0:
+            return None
+
+        if element == 'vlan':
+            value = int(str(self.pkt[Dot1Q].vlan))
+        return value
+
+    def ipv4(self, frag=0, src="127.0.0.1", proto=None, tos=0, dst="127.0.0.1", chksum=None, len=None, version=4, flags=None, ihl=None, ttl=64, id=1, options=None):
+        self.pkt[IP].frag = frag
+        self.pkt[IP].src = src
+        if proto is not None:
+            self.pkt[IP].proto = proto
+        self.pkt[IP].tos = tos
+        self.pkt[IP].dst = dst
+        if chksum is not None:
+            self.pkt[IP].chksum = chksum
+        if len is not None:
+            self.pkt[IP].len = len
+        self.pkt[IP].version = version
+        if flags is not None:
+            self.pkt[IP].flags = flags
+        if ihl is not None:
+            self.pkt[IP].ihl = ihl
+        self.pkt[IP].ttl = ttl
+        self.pkt[IP].id = id
+        if options is not None:
+            self.pkt[IP].options = options
+
+    def ipv6(self, version=6, tc=0, fl=0, plen=0, nh=0, hlim=64, src="::1", dst="::1"):
+        """
+        Configure IPv6 protocal.
+        """
+        self.pkt[IPv6].version = version
+        self.pkt[IPv6].tc = tc
+        self.pkt[IPv6].fl = fl
+        if plen:
+            self.pkt[IPv6].plen = plen
+        if nh:
+            self.pkt[IPv6].nh = nh
+        self.pkt[IPv6].src = src
+        self.pkt[IPv6].dst = dst
+
+    def inner_ipv6(self, version=6, tc=0, fl=0, plen=0, nh=0, hlim=64, src="::1", dst="::1"):
+        """
+        Configure IPv6 protocal.
+        """
+        self.pkt[IPv6][Ether][IPv6].version = version
+        self.pkt[IPv6][Ether][IPv6].tc = tc
+        self.pkt[IPv6][Ether][IPv6].fl = fl
+        if plen:
+            self.pkt[IPv6][Ether][IPv6].plen = plen
+        if nh:
+            self.pkt[IPv6][Ether][IPv6].nh = nh
+        self.pkt[IPv6][Ether][IPv6].src = src
+        self.pkt[IPv6][Ether][IPv6].dst = dst
+
+    def udp(self, src=53, dst=53, len=None, chksum=None):
+        self.pkt[UDP].sport = src
+        self.pkt[UDP].dport = dst
+        if len is not None:
+            self.pkt[UDP].len = len
+        if chksum is not None:
+            self.pkt[UDP].chksum = chksum
+
+    def raw(self, payload=None):
+        if payload is not None:
+            self.pkt[Raw].load = ''
+            for load in payload:
+                self.pkt[Raw].load += '%c' % int(load, 16)
+
+    def vxlan(self, vni=0):
+        self.pkt[Vxlan].vni = vni
+
+    def read_pcap(self, file):
+        pcap_pkts = []
+        try:
+            pcap_pkts = rdpcap(file)
+        except:
+            pass
+
+        return pcap_pkts
+
+    def write_pcap(self, file):
+        try:
+            wrpcap(file, self.pkt)
+        except:
+            pass
+
+    def send_pcap_pkt(self, crb=None, file='', intf=''):
+        if intf == '' or file == '' or crb is None:
+            print "Invalid option for send packet by scapy"
+            return
+
+        content = 'pkts=rdpcap(\"%s\");sendp(pkts, iface=\"%s\");exit()' % (file, intf)
+        cmd_file = '/tmp/scapy_%s.cmd' % intf
+
+        crb.create_file(content, cmd_file)
+        crb.send_expect("scapy -c scapy_%s.cmd &" % intf, "# ")
+
+    def print_summary(self):
+        print "Send out pkt %s" % self.pkt.summary()
+
+    def send_pkt(self, intf=''):
+        self.print_summary()
+        if intf != '':
+            sendp(self.pkt, iface=intf)
+
+
+class Packet(object):
+    """
+    Module for config/create packet
+    Based on scapy module
+    Usage: assign_layers([layers list])
+           config_layer('layername', {layer config})
+           ...
+    """
+    def_packet = {
+        'TIMESYNC': {'layers': ['ether', 'raw'], 'cfgload': False},
+        'ARP': {'layers': ['ether', 'arp'], 'cfgload': False},
+        'LLDP': {'layers': ['ether', 'lldp'], 'cfgload': False},
+        'TCP': {'layers': ['ether', 'ipv4', 'tcp', 'raw'], 'cfgload': True},
+        'UDP': {'layers': ['ether', 'ipv4', 'udp', 'raw'], 'cfgload': True},
+        'SCTP': {'layers': ['ether', 'ipv4', 'sctp', 'raw'], 'cfgload': True},
+        'IPv6_TCP': {'layers': ['ether', 'ipv6', 'tcp', 'raw'], 'cfgload': True},
+        'IPv6_UDP': {'layers': ['ether', 'ipv6', 'udp', 'raw'], 'cfgload': True},
+        'IPv6_SCTP': {'layers': ['ether', 'ipv6', 'sctp', 'raw'], 'cfgload': True},
+    }
+
+    def __init__(self, **options):
+        """
+        pkt_type: description of packet type
+                  defined in def_packet
+        options: special option for Packet module
+                 pkt_len: length of network packet
+                 ran_payload: whether payload of packet is random
+                 pkt_file:
+                 pkt_gen: packet generator type
+                          now only support scapy
+        """
+        self.pkt_layers = []
+        self.pkt_len = 64
+        self.pkt_opts = options
+
+        self.pkt_type = "UDP"
+
+        if 'pkt_type' in self.pkt_opts.keys():
+            self.pkt_type = self.pkt_opts['pkt_type']
+
+        if self.pkt_type in self.def_packet.keys():
+            self.pkt_layers = self.def_packet[self.pkt_type]['layers']
+            self.pkt_cfgload = self.def_packet[self.pkt_type]['cfgload']
+            if "IPv6" in self.pkt_type:
+                self.pkt_len = 128
+        else:
+            self._load_pkt_layers()
+            
+        if 'pkt_len' in self.pkt_opts.keys():
+            self.pkt_len = self.pkt_opts['pkt_len']
+
+        if 'pkt_file' in self.pkt_opts.keys():
+            self.uni_name = self.pkt_opts['pkt_file']
+        else:
+            self.uni_name = '/tmp/' + str(uuid4()) + '.pcap'
+
+        if 'pkt_gen' in self.pkt_opts.keys():
+            if self.pkt_opts['pkt_gen'] == 'scapy':
+                self.pktgen = scapy()
+            else:
+                print "Not support other pktgen yet!!!"
+        else:
+            self.pktgen = scapy()
+
+    def send_pkt(self, crb=None, tx_port='', auto_cfg=True):
+        if tx_port == '':
+            print "Invalid Tx interface"
+            return
+
+        self.tx_port = tx_port
+
+        # assign layer
+        self.assign_layers()
+
+        # config special layer
+        if auto_cfg is True:
+            self.config_def_layers()
+
+        # handle packet options
+        payload_len = self.pkt_len - len(self.pktgen.pkt) - 4
+
+        # if raw data has not been configured and payload should configured
+        if hasattr(self, 'configured_layer_raw') is False and self.pkt_cfgload is True:
+            payload = []
+            raw_confs = {}
+            if 'ran_payload' in self.pkt_opts.keys():
+                for loop in range(payload_len):
+                    payload.append("%02x" % random.randrange(0, 255))
+            else:
+                for loop in range(payload_len):
+                    payload.append('58')  # 'X'
+
+            raw_confs['payload'] = payload
+            self._config_layer_raw(raw_confs)
+
+        # check with port type
+        if 'ixia' in self.tx_port:
+            print "Not Support Yet"
+
+        if crb is not None:
+            self.pktgen.write_pcap(self.uni_name)
+            crb.session.copy_file_to(self.uni_name)
+            pcap_file = self.uni_name.split('/')[2]
+            self.pktgen.send_pcap_pkt(crb=crb, file=pcap_file, intf=self.tx_port)
+        else:
+            self.pktgen.send_pkt(intf=self.tx_port)
+
+    def check_layer_config(self, layer, config):
+        """
+        check the format of layer configuration
+        every layer should has different check function
+        """
+        pass
+
+    def assign_layers(self, layers=None):
+        """
+        assign layer for this packet
+        maybe need add check layer function
+        """
+        if layers is not None:
+            self.pkt_layers = layers
+
+        for layer in self.pkt_layers:
+            found = False
+            l_type = layer.lower()
+
+            for types in LayersTypes.values():
+                if l_type in types:
+                    found = True
+                    break
+
+            if found is False:
+                self.pkt_layers.remove(l_type)
+                print "INVAILD LAYER TYPE [%s]" % l_type.upper()
+
+        self.pktgen.add_layers(self.pkt_layers)
+
+    def _load_pkt_layers(self):
+        name2type = {
+            'MAC': 'ether',
+            'VLAN': 'dot1q',
+            'IP': 'ipv4',
+            'IPihl': 'ipv4ihl',
+            'IPFRAG': 'ipv4_ext',
+            'IPv6': 'ipv6',
+            'IPv6FRAG': 'ipv6_frag',
+            'IPv6EXT': 'ipv6_ext',
+            'IPv6EXT2': 'ipv6_ext2',
+            'TCP': 'tcp',
+            'UDP': 'udp',
+            'SCTP': 'sctp',
+            'ICMP': 'icmp',
+            'NVGRE': 'nvgre',
+            'GRE': 'gre',
+            'VXLAN': 'vxlan',
+            'PKT': 'raw',
+        }
+
+        layers = self.pkt_type.split('_')
+        self.pkt_layers = []
+        self.pkt_cfgload = True
+        for layer in layers:
+            if layer in name2type.keys():
+                self.pkt_layers.append(name2type[layer])
+        
+    def config_def_layers(self):
+        """
+        Handel config packet layers by default
+        """
+        if self.pkt_type == "TIMESYNC":
+            self.config_layer('ether', {'dst': 'FF:FF:FF:FF:FF:FF',
+                                        'type': 0x88f7})
+            self.config_layer('raw', {'payload': ['00', '02']})
+
+        if self.pkt_type == "ARP":
+            self.config_layer('ether', {'dst': 'FF:FF:FF:FF:FF:FF'})
+
+        if self.pkt_type == "IPv6_SCTP":
+            self.config_layer('ipv6', {'nh': 132})
+
+        if "IPv6_NVGRE" in self.pkt_type:
+            self.config_layer('ipv6', {'nh': 47})
+            if "IPv6_SCTP" in self.pkt_type:
+                self.config_layer('inner_ipv6', {'nh': 132})
+            if "IPv6_ICMP" in self.pkt_type:
+                self.config_layer('inner_ipv6', {'nh': 58})
+            if "IPFRAG" in self.pkt_type:
+                self.config_layer('raw', {'payload': ['00'] * 40})
+            else:
+                self.config_layer('raw', {'payload': ['00'] * 18})
+
+        if "MAC_IP_IPv6" in self.pkt_type or\
+           "MAC_IP_NVGRE" in self.pkt_type or \
+           "MAC_IP_UDP_VXLAN" in self.pkt_type:
+            if "IPv6_SCTP" in self.pkt_type:
+                self.config_layer('ipv6', {'nh': 132})
+            if "IPv6_ICMP" in self.pkt_type:
+                self.config_layer('ipv6', {'nh': 58})
+            if "IPFRAG" in self.pkt_type:
+                self.config_layer('raw', {'payload': ['00'] * 40})
+            else:
+                self.config_layer('raw', {'payload': ['00'] * 18})
+        
+    def config_layer(self, layer, config={}):
+        """
+        Configure packet assgined layer
+        return the status of configure result
+        """
+        try:
+            # if inner in layer mean same layer in outer
+            if 'inner' in layer:
+                dup_layer = layer[6:]
+                if self.pkt_layers.count(dup_layer) != 2:
+                    raise
+            else:
+                idx = self.pkt_layers.index(layer)
+        except Exception as e:
+            print "INVALID LAYER ID %s" % layer
+            return -1
+
+        if self.check_layer_config(layer, config) is False:
+            return -1
+
+        layer_conf = getattr(self, "_config_layer_%s" % layer)
+        setattr(self, 'configured_layer_%s' % layer, True)
+
+        return layer_conf(config)
+
+    def _config_layer_ether(self, config):
+        return self.pktgen.ether(**config)
+
+    def _config_layer_dot1q(self, config):
+        return self.pktgen.dot1q(**config)
+
+    def _config_layer_ipv4(self, config):
+        return self.pktgen.ipv4(**config)
+
+    def _config_layer_ipv6(self, config):
+        return self.pktgen.ipv6(**config)
+
+    def _config_layer_inner_ipv6(self, config):
+        return self.pktgen.inner_ipv6(**config)
+
+    def _config_layer_udp(self, config):
+        return self.pktgen.udp(**config)
+
+    def _config_layer_raw(self, config):
+        return self.pktgen.raw(**config)
+
+    def _config_layer_vxlan(self, config):
+        return self.pktgen.vxlan(**config)
+
+    def strip_layer_element(self, layer, element):
+        """
+        Strip packet layer elements
+        return the status of configure result
+        """
+        strip_element = getattr(self, "strip_element_%s" % layer)
+
+        return strip_element(element)
+
+    def strip_element_dot1q(self, element):
+        return self.pktgen.strip_dot1q(element)
+
+
+def increment_ip_address(self, addr):
+    """
+    Returns the IP address from a given one, like
+    192.168.1.1 ->192.168.1.2
+    If disable ip hw chksum, csum routine will increase ip
+    """
+    ip2int = lambda ipstr: struct.unpack('!I', socket.inet_aton(ipstr))[0]
+    x = ip2int(addr)
+    int2ip = lambda n: socket.inet_ntoa(struct.pack('!I', n))
+    return int2ip(x + 1)
+
+
+def increment_ipv6_address(self, addr):
+    """
+    Returns the IP address from a given one, like
+    FE80:0:0:0:0:0:0:0 -> FE80::1
+    csum routine will increase ip
+    """
+    ipv6addr = struct.unpack('!8H', socket.inet_pton(AF_INET6, addr))
+    addr = list(ipv6addr)
+    addr[7] += 1
+    ipv6 = socket.inet_ntop(AF_INET6, struct.pack(
+        '!8H', addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]))
+    return ipv6
+
+
+def sniff_packets(intf, count=0, timeout=5):
+    """
+    sniff all packets for certain port in certain seconds
+    """
+    sniff_cmd = 'tcpdump -i %(INTF)s -w %(FILE)s'
+    options = {'INTF': intf, 'COUNT': count,
+               'FILE': '/tmp/sniff_%s.pcap' % intf}
+    if count:
+        sniff_cmd += ' -c %(COUNT)d'
+        cmd = sniff_cmd % options
+    else:
+        cmd = sniff_cmd % options
+
+    args = cmd.split()
+    pipe = subprocess.Popen(args)
+    index = str(time.time())
+    SNIFF_PIDS[index] = (pipe, intf, timeout)
+    return index
+
+
+def load_sniff_packets(index=''):
+    pkts = []
+    child_exit = False
+    if index in SNIFF_PIDS.keys():
+        pipe, intf, timeout = SNIFF_PIDS[index]
+        time_elapse = int(time.time() - float(index))
+        while time_elapse < timeout:
+            if pipe.poll() is not None:
+                child_exit = True
+                break
+
+            time.sleep(1)
+            time_elapse += 1
+
+        if not child_exit:
+            pipe.kill()
+
+        # wait pcap file ready
+        time.sleep(0.5)
+        try:
+            cap_pkts = rdpcap("/tmp/sniff_%s.pcap" % intf)
+            for pkt in cap_pkts:
+                # packet gen should be scapy
+                packet = Packet(tx_port=intf)
+                packet.pktgen.assign_pkt(pkt)
+                pkts.append(packet)
+        except:
+            pass
+
+    return pkts
+
+############################################################################################################
+############################################################################################################
+if __name__ == "__main__":
+    inst = sniff_packets("lo", timeout=5)
+    time.sleep(3)
+    pkts = load_sniff_packets(inst)
+
+    pkt = Packet(pkt_type='UDP', pkt_len=1500, ran_payload=True)
+    pkt.send_pkt(tx_port='lo')
+    pkt = Packet(pkt_type='IPv6_TCP')
+    pkt.send_pkt(tx_port='lo')
+    pkt = Packet(pkt_type='IPv6_SCTP')
+    pkt.send_pkt(tx_port='lo')
+
+    pkt = Packet()
+    pkt.assign_layers(['ether', 'dot1q', 'ipv4', 'udp', 'vxlan', 'inner_mac', 'inner_ipv4', 'inner_udp', 'raw'])
+    pkt.config_layer('ether', {'dst': '00:11:22:33:44:55'})
+    pkt.config_layer('dot1q', {'vlan': 2})
+    pkt.config_layer('ipv4', {'dst': '1.1.1.1'})
+    pkt.config_layer('udp', {'src': 4789, 'dst': 4789, 'chksum': 0x1111})
+    pkt.config_layer('vxlan', {'vni': 2})
+    pkt.config_layer('raw', {'payload': ['58']*18})
-- 
1.9.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dts] [dts 3/4] add unified packet type module and test suite
  2015-09-17  1:13 [dts] [dts 0/4] add unified packet type module and test suite Yufen Mo
  2015-09-17  1:13 ` [dts] [dts 1/4] " Yufen Mo
  2015-09-17  1:13 ` [dts] [dts 2/4] " Yufen Mo
@ 2015-09-17  1:13 ` Yufen Mo
  2015-09-17  1:13 ` [dts] [dts 4/4] " Yufen Mo
  3 siblings, 0 replies; 6+ messages in thread
From: Yufen Mo @ 2015-09-17  1:13 UTC (permalink / raw)
  To: dts

From: yufengmx <yufengx.mo@intel.com>

 unified packet type flag feature on different NICs. For more details, please
 reference to test plan.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 tests/TestSuite_uni_pkt.py | 364 +++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 364 insertions(+)
 create mode 100644 tests/TestSuite_uni_pkt.py

diff --git a/tests/TestSuite_uni_pkt.py b/tests/TestSuite_uni_pkt.py
new file mode 100644
index 0000000..ca72e75
--- /dev/null
+++ b/tests/TestSuite_uni_pkt.py
@@ -0,0 +1,364 @@
+# BSD LICENSE
+#
+# Copyright(c) 2010-2014 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#   * Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
+#     distribution.
+#   * Neither the name of Intel Corporation nor the names of its
+#     contributors may be used to endorse or promote products derived
+#     from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+"""
+DPDK Test suite.
+
+Unified packet type flag is supposed to recognize packet types and support all
+possible PMDs.
+
+This 32 bits of packet_type can be divided into several sub fields to
+indicate different packet type information of a packet. The initial design
+is to divide those bits into fields for L2 types, L3 types, L4 types, tunnel
+types, inner L2 types, inner L3 types and inner L4 types. All PMDs should
+translate the offloaded packet types into these 7 fields of information, for
+user applications
+"""
+
+import dts
+from test_case import TestCase
+from exception import VerifyFailure
+from packet import Packet
+import time
+
+
+class TestUniPacket(TestCase):
+
+    def set_up_all(self):
+        """
+        Run at the start of each test suite.
+        """
+        ports = self.dut.get_ports()
+        self.verify(len(ports) >= 2, "Insufficient ports for testing")
+        valports = [_ for _ in ports if self.tester.get_local_port(_) != -1]
+        # start testpmd
+        self.dut_port = valports[0]
+        tester_port = self.tester.get_local_port(self.dut_port)
+        self.tester_iface = self.tester.get_interface(tester_port)
+        self.dut.send_expect(
+            "./%s/app/testpmd -c f -n 4 -- -i --txqflags=0x0" % self.target, "testpmd>", 20)
+        self.dut.send_expect("set fwd rxonly", "testpmd>")
+        self.dut.send_expect("set verbose 1", "testpmd>")
+        self.dut.send_expect("start", "testpmd>")
+
+    def set_up(self):
+        """
+        Run before each test case.
+        Nothing to do.
+        """
+        pass
+
+    def run_test(self, pkt_types):
+        time.sleep(1)
+        for pkt_type in pkt_types.keys():
+            pkt_names = pkt_types[pkt_type]
+            pkt = Packet(pkt_type=pkt_type)
+            pkt.send_pkt(tx_port=self.tester_iface)
+            out = self.dut.get_session_output(timeout=2)
+            for pkt_layer_name in pkt_names:
+                if pkt_layer_name not in out:
+                    print dts.RED("Fail to detect %s" % pkt_layer_name)
+                    raise VerifyFailure("Failed to detect %s" % pkt_layer_name)
+            print dts.GREEN("Detected %s successfully" % pkt_type)
+
+    def test_l2pkt_detect(self):
+        """
+        Check whether L2 packet can be detected"
+        """
+        self.verify("fortville" in self.nic,
+                    "L2 packet detect only support by Fortville")
+        self.L2_types = {
+            "TIMESYNC": "(outer) L2 type: ETHER_Timesync",
+            "ARP": "(outer) L2 type: ETHER_ARP",
+            "LLDP": "(outer) L2 type: ETHER_LLDP",
+        }
+
+        for l2_type in self.L2_types.keys():
+            pkt_name = self.L2_types[l2_type]
+            pkt = Packet(pkt_type=l2_type)
+            pkt.send_pkt(tx_port=self.tester_iface)
+            out = self.dut.get_session_output(timeout=2)
+            if pkt_name in out:
+                print dts.GREEN("Detected L2 %s successfully" % l2_type)
+            else:
+                raise VerifyFailure("Failed to detect L2 %s" % l2_type)
+
+    def test_IPv4_L4(self):
+        """
+        checked that whether L3 and L4 packet can be normally detected.
+        """
+        if "fortville" in self.nic.lower():
+            outerL4Type = "(outer) L4 type: L4_NONFRAG"
+        elif "niantic" in self.nic.lower() or "i350" in self.nic.lower():
+            outerL4Type = "(outer) L4 type: Unknown"
+
+        pktType = {
+            "MAC_IP_PKT":                ["(outer) L2 type: ETHER", "(outer) L3 type: IPV4", outerL4Type],
+            "MAC_IP_UDP_PKT":            ["(outer) L4 type: UDP"],
+            "MAC_IP_TCP_PKT":            ["(outer) L4 type: TCP"],
+            "MAC_IP_SCTP_PKT":           ["(outer) L4 type: SCTP"],
+            "MAC_IP_ICMP_PKT":           ["(outer) L4 type: ICMP"],
+            "MAC_IPFRAG_TCP_PKT":        ["(outer) L2 type: ETHER", "(outer) L3 type: IPV4_EXT_UNKNOWN", "(outer) L4 type: L4_FRAG"],
+            "MAC_IPihl_PKT":             ["(outer) L3 type: IPV4_EXT", "(outer) L4 type: Unknown"],
+            "MAC_IPihl_SCTP_PKT":        ["(outer) L3 type: IPV4_EXT", "(outer) L4 type: SCTP"]
+        }
+
+        # delete the unsupported packet based on nic type
+        if "fortville" in self.nic.lower():
+            pktType.pop("MAC_IPihl_PKT")
+            pktType.pop("MAC_IPihl_SCTP_PKT")
+        elif "niantic" in self.nic.lower() or "i350" in self.nic.lower():
+            pktType.pop("MAC_IP_ICMP_PKT")
+            pktType.pop("MAC_IPFRAG_TCP_PKT")
+
+        self.run_test(pktType)
+
+    def test_IPv6_L4(self):
+        """
+        checked that whether IPv6 and L4 packet can be normally detected.
+        """
+        if "fortville" in self.nic.lower():
+            outerL4Type = "(outer) L4 type: L4_NONFRAG"
+            outerL3Type = "(outer) L3 type: IPV6_EXT_UNKNOWN"
+        elif "niantic" in self.nic.lower() or "i350" in self.nic.lower():
+            outerL4Type = "(outer) L4 type: Unknown"
+            outerL3Type = "(outer) L3 type: IPV6"
+
+        pktType = {
+            "MAC_IPv6_PKT":          ["(outer) L2 type: ETHER", outerL3Type, outerL4Type],
+            "MAC_IPv6_UDP_PKT":      ["(outer) L4 type: UDP"],
+            "MAC_IPv6_TCP_PKT":      ["(outer) L4 type: TCP"],
+            "MAC_IPv6FRAG_PKT_F":    ["(outer) L3 type: IPV6_EXT_UNKNOWN", "(outer) L4 type: L4_FRAG"],
+            "MAC_IPv6FRAG_PKT_N":    ["(outer) L3 type: IPV6_EXT", "(outer) L4 type: Unknown"]
+        }
+
+        # delete the unsupported packet based on nic type
+        if "fortville" in self.nic.lower():
+            pktType.pop("MAC_IPv6FRAG_PKT_N")
+        elif "niantic" in self.nic.lower() or "i350" in self.nic.lower():
+            pktType.pop("MAC_IPv6FRAG_PKT_F")
+
+        self.run_test(pktType)
+
+    def test_IP_in_IPv4_tunnel(self):
+        """
+        checked that whether IP in IPv4 tunnel packet can be normally
+        detected by Fortville.
+        """
+        self.verify("fortville" in self.nic,
+                    "IP in IPv4 tunnel packet type detect only support by Fortville")
+
+        pktType = {
+            "MAC_IP_IPFRAG_UDP_PKT":      ["(outer) L2 type: ETHER", "(outer) L3 type: IPV4_EXT_UNKNOWN", "(outer) L4 type: Unknown", "Tunnel type: IP", "Inner L2 type: Unknown", "Inner L3 type: IPV4_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_IP_PKT":              ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_IP_UDP_PKT":          ["Inner L4 type: UDP"],
+            "MAC_IP_IP_TCP_PKT":          ["Inner L4 type: TCP"],
+            "MAC_IP_IP_SCTP_PKT":         ["Inner L4 type: SCTP"],
+            "MAC_IP_IP_ICMP_PKT":         ["Inner L4 type: ICMP"],
+            "MAC_IP_IPv6FRAG_PKT":        ["Inner L3 type: IPV6_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_IPv6_PKT":            ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_IPv6_UDP_PKT":        ["Inner L4 type: UDP"],
+            "MAC_IP_IPv6_TCP_PKT":        ["Inner L4 type: TCP"],
+            "MAC_IP_IPv6_SCTP_PKT":       ["Inner L4 type: SCTP"],
+            "MAC_IP_IPv6_ICMP_PKT":       ["Inner L4 type: ICMP"]
+        }
+
+        self.run_test(pktType)
+
+    def test_IPv6_in_IPv4_tunnel(self):
+        """
+        checked that whether IPv4 in IPv6 tunnel packet can be normally
+        detected by Niantic and i350.
+        """
+        if "niantic" not in self.nic.lower() and "i350" not in self.nic.lower():
+            return
+
+        pktType = {
+            "MAC_IP_IPv6_PKT":            ["(outer) L2 type: ETHER", "(outer) L3 type: IPV4", "(outer) L4 type: Unknown", "Tunnel type: IP", "Inner L2 type: Unknown", "Inner L3 type: IPV6", "Inner L4 type: Unknown"],
+            "MAC_IP_IPv6EXT2_PKT":        ["Inner L3 type: IPV6_EXT"],
+            "MAC_IP_IPv6_UDP_PKT":        ["Inner L4 type: UDP"],
+            "MAC_IP_IPv6_TCP_PKT":        ["Inner L4 type: TCP"],
+            "MAC_IP_IPv6EXT2_UDP_PKT":    ["Inner L3 type: IPV6_EXT", "Inner L4 type: UDP"],
+            "MAC_IP_IPv6EXT2_TCP_PKT":    ["Inner L3 type: IPV6_EXT", "Inner L4 type: TCP"]
+        }
+        self.run_test(pktType)
+
+    def test_IP_in_IPv6_tunnel(self):
+        """
+        checked that whether IP in IPv6 tunnel packet can be normally
+        detected by Fortville.
+        """
+        self.verify("fortville" in self.nic,
+                    "IP in IPv6 tunnel packet type detect only support by Fortville")
+
+        pktType = {
+            "MAC_IP_IPFRAG_UDP_PKT":      ["(outer) L2 type: ETHER", "(outer) L3 type: IPV4_EXT_UNKNOWN", "(outer) L4 type: Unknown", "Tunnel type: IP", "Inner L2 type: Unknown", "Inner L3 type: IPV4_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_IP_PKT":              ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_IP_UDP_PKT":          ["Inner L4 type: UDP"],
+            "MAC_IP_IP_TCP_PKT":          ["Inner L4 type: TCP"],
+            "MAC_IP_IP_SCTP_PKT":         ["Inner L4 type: SCTP"],
+            "MAC_IP_IP_ICMP_PKT":         ["Inner L4 type: ICMP"],
+            "MAC_IP_IPv6FRAG_PKT":        ["Inner L3 type: IPV6_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_IPv6_PKT":            ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_IPv6_UDP_PKT":        ["Inner L4 type: UDP"],
+            "MAC_IP_IPv6_TCP_PKT":        ["Inner L4 type: TCP"],
+            "MAC_IP_IPv6_SCTP_PKT":       ["Inner L4 type: SCTP"],
+            "MAC_IP_IPv6_ICMP_PKT":       ["Inner L4 type: ICMP"]
+        }
+        self.run_test(pktType)
+
+    def test_NVGRE_tunnel(self):
+        """
+        checked that whether NVGRE tunnel packet can be normally detected
+        by Fortville.
+        """
+        self.verify("fortville" in self.nic,
+                    "NVGRE tunnel packet type detect only support by Fortville")
+
+        pktType = {
+            "MAC_IP_NVGRE_MAC_IPFRAG_PKT":              ["(outer) L2 type: ETHER", "(outer) L3 type: IPV4_EXT_UNKNOWN", "(outer) L4 type: Unknown", "Tunnel type: GRENAT", "Inner L2 type: ETHER", "Inner L3 type: IPV4_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_NVGRE_MAC_IP_PKT":                  ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_NVGRE_MAC_VLAN_PKT":                ["Inner L2 type: ETHER_VLAN", "Inner L4 type: Unknown"],
+            "MAC_IP_NVGRE_MAC_VLAN_IPFRAG_PKT":         ["Inner L3 type: IPV4_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_NVGRE_MAC_VLAN_IP_PKT":             ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_NVGRE_MAC_VLAN_IP_UDP_PKT":         ["Inner L4 type: UDP"],
+            "MAC_IP_NVGRE_MAC_VLAN_IP_TCP_PKT":         ["Inner L4 type: TCP"],
+            "MAC_IP_NVGRE_MAC_VLAN_IP_SCTP_PKT":        ["Inner L4 type: SCTP"],
+            "MAC_IP_NVGRE_MAC_VLAN_IP_ICMP_PKT":        ["Inner L4 type: ICMP"],
+            "MAC_IP_NVGRE_MAC_VLAN_IPv6FRAG_PKT":       ["Inner L3 type: IPV6_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_NVGRE_MAC_VLAN_IPv6_PKT":           ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_NVGRE_MAC_VLAN_IPv6_UDP_PKT":       ["Inner L4 type: UDP"],
+            "MAC_IP_NVGRE_MAC_VLAN_IPv6_TCP_PKT":       ["Inner L4 type: TCP"],
+            "MAC_IP_NVGRE_MAC_VLAN_IPv6_SCTP_PKT":      ["Inner L4 type: SCTP"],
+            "MAC_IP_NVGRE_MAC_VLAN_IPv6_ICMP_PKT":      ["Inner L4 type: ICMP"]
+        }
+        self.run_test(pktType)
+
+    def test_NVGRE_in_IPv6_tunnel(self):
+        """
+        checked that whether NVGRE in IPv6 tunnel packet can be normally
+        detected by Fortville.
+        """
+        self.verify("fortville" in self.nic,
+                    "NVGRE in IPv6 detect only support by Fortville")
+
+        pkt_types = {
+            "MAC_IPv6_NVGRE_MAC_PKT":             ["(outer) L2 type: ETHER", "(outer) L3 type: IPV6_EXT_UNKNOWN", "(outer) L4 type: Unknown", "Tunnel type: GRENAT", "Inner L2 type: ETHER", "Inner L3 type: Unknown", "Inner L4 type: Unknown"],
+            "MAC_IPv6_NVGRE_MAC_IPFRAG_PKT":      ["Inner L3 type: IPV4_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IPv6_NVGRE_MAC_IP_PKT":          ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IPv6_NVGRE_MAC_IP_UDP_PKT":      ["Inner L4 type: UDP"],
+            "MAC_IPv6_NVGRE_MAC_IP_TCP_PKT":      ["Inner L4 type: TCP"],
+            "MAC_IPv6_NVGRE_MAC_IP_SCTP_PKT":     ["Inner L4 type: SCTP"],
+            "MAC_IPv6_NVGRE_MAC_IP_ICMP_PKT":     ["Inner L4 type: ICMP"],
+            "MAC_IPv6_NVGRE_MAC_IPv6FRAG_PKT":    ["Inner L3 type: IPV6_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IPv6_NVGRE_MAC_IPv6_PKT":        ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IPv6_NVGRE_MAC_IPv6_UDP_PKT":    ["Inner L4 type: UDP"],
+            "MAC_IPv6_NVGRE_MAC_IPv6_TCP_PKT":    ["Inner L4 type: TCP"],
+            "MAC_IPv6_NVGRE_MAC_IPv6_SCTP_PKT":   ["Inner L4 type: SCTP"],
+            "MAC_IPv6_NVGRE_MAC_IPv6_ICMP_PKT":   ["Inner L4 type: ICMP"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IPFRAG_PKT": ["Inner L2 type: ETHER_VLAN", "Inner L3 type: IPV4_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IP_PKT":     ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IP_UDP_PKT": ["Inner L4 type: UDP"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IP_TCP_PKT": ["Inner L4 type: TCP"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IP_SCTP_PKT": ["Inner L4 type: SCTP"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IP_ICMP_PKT": ["Inner L4 type: ICMP"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IPv6FRAG_PKT": ["Inner L3 type: IPV6_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IPv6_PKT":     ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IPv6_UDP_PKT": ["Inner L4 type: UDP"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IPv6_TCP_PKT": ["Inner L4 type: TCP"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IPv6_SCTP_PKT": ["Inner L4 type: SCTP"],
+            "MAC_IPv6_NVGRE_MAC_VLAN_IPv6_ICMP_PKT": ["Inner L4 type: ICMP"],
+        }
+
+        self.run_test(pkt_types)
+
+    def test_GRE_tunnel(self):
+        """
+        checked that whether GRE tunnel packet can be normally detected by Fortville.
+        """
+        self.verify("fortville" in self.nic,
+                    "GRE tunnel packet type detect only support by Fortville")
+
+        pktType = {
+            "MAC_IP_GRE_IPFRAG_PKT":          ["(outer) L2 type: ETHER", "(outer) L3 type: IPV4_EXT_UNKNOWN", "(outer) L4 type: Unknown", "Tunnel type: GRENAT", "Inner L2 type: Unknown", "Inner L3 type: IPV4_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_GRE_IP_PKT":              ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_GRE_IP_UDP_PKT":          ["Inner L4 type: UDP"],
+            "MAC_IP_GRE_IP_TCP_PKT":          ["Inner L4 type: TCP"],
+            "MAC_IP_GRE_IP_SCTP_PKT":         ["Inner L4 type: SCTP"],
+            "MAC_IP_GRE_IP_ICMP_PKT":         ["Inner L4 type: ICMP"],
+            "MAC_IP_GRE_PKT":                 ["Inner L3 type: Unknown", "Inner L4 type: Unknown"]
+        }
+        self.run_test(pktType)
+
+    def test_Vxlan_tunnel(self):
+        """
+        checked that whether Vxlan tunnel packet can be normally detected by
+        Fortville.
+        """
+        self.verify("fortville" in self.nic,
+                    "Vxlan tunnel packet type detect only support by Fortville")
+
+        self.dut.send_expect("rx_vxlan_port add 4789 0", "testpmd>", 10)
+        self.dut.send_expect("set fwd rxonly", "testpmd>")
+        self.dut.send_expect("set verbose 1", "testpmd>")
+        self.dut.send_expect("start", "testpmd>")
+
+        pktType = {
+            "MAC_IP_UDP_VXLAN_MAC_IPFRAG_PKT":        ["(outer) L2 type: ETHER", "(outer) L3 type: IPV4_EXT_UNKNOWN", "(outer) L4 type: Unknown", "Tunnel type: GRENAT", "Inner L2 type: ETHER", "Inner L3 type: IPV4_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_UDP_VXLAN_MAC_IP_PKT":            ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_UDP_VXLAN_MAC_IP_UDP_PKT":        ["Inner L4 type: UDP"],
+            "MAC_IP_UDP_VXLAN_MAC_IP_TCP_PKT":        ["Inner L4 type: TCP"],
+            "MAC_IP_UDP_VXLAN_MAC_IP_SCTP_PKT":       ["Inner L4 type: SCTP"],
+            "MAC_IP_UDP_VXLAN_MAC_IP_ICMP_PKT":       ["Inner L4 type: ICMP"],
+            "MAC_IP_UDP_VXLAN_MAC_IPv6FRAG_PKT":      ["Inner L3 type: IPV6_EXT_UNKNOWN", "Inner L4 type: L4_FRAG"],
+            "MAC_IP_UDP_VXLAN_MAC_IPv6_PKT":          ["Inner L4 type: L4_NONFRAG"],
+            "MAC_IP_UDP_VXLAN_MAC_IPv6_UDP_PKT":      ["Inner L4 type: UDP"],
+            "MAC_IP_UDP_VXLAN_MAC_IPv6_TCP_PKT":      ["Inner L4 type: TCP"],
+            "MAC_IP_UDP_VXLAN_MAC_IPv6_SCTP_PKT":     ["Inner L4 type: SCTP"],
+            "MAC_IP_UDP_VXLAN_MAC_IPv6_ICMP_PKT":     ["Inner L4 type: ICMP"],
+            "MAC_IP_UDP_VXLAN_MAC_PKT":               ["Inner L3 type: Unknown", "Inner L4 type: Unknown"]
+        }
+        self.run_test(pktType)
+
+    def tear_down(self):
+        """
+        Run after each test case.
+        Nothing to do.
+        """
+        pass
+
+    def tear_down_all(self):
+        """
+        Run after each test suite.
+        Nothing to do.
+        """
+        self.dut.kill_all()
+        pass
-- 
1.9.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dts] [dts 4/4] add unified packet type module and test suite
  2015-09-17  1:13 [dts] [dts 0/4] add unified packet type module and test suite Yufen Mo
                   ` (2 preceding siblings ...)
  2015-09-17  1:13 ` [dts] [dts 3/4] " Yufen Mo
@ 2015-09-17  1:13 ` Yufen Mo
  3 siblings, 0 replies; 6+ messages in thread
From: Yufen Mo @ 2015-09-17  1:13 UTC (permalink / raw)
  To: dts

From: yufengmx <yufengx.mo@intel.com>

Update lldp and nvgre layer module

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 dep/lldp.py | 242 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 242 insertions(+)
 create mode 100644 dep/lldp.py

diff --git a/dep/lldp.py b/dep/lldp.py
new file mode 100644
index 0000000..d8fabe2
--- /dev/null
+++ b/dep/lldp.py
@@ -0,0 +1,242 @@
+#!/usr/bin/env python
+## This file is part of Scapy
+## See http://www.secdev.org/projects/scapy for more informations
+## Copyright (C) Philippe Biondi <phil@secdev.org>
+## This program is published under a GPLv2 license
+
+## Copyright (c) 2011 Jochen Bartl <jochen.bartl gmail com>
+
+"""
+LLDP (Link Layer Discovery Protocol)
+"""
+
+from scapy.packet import *
+from scapy.fields import *
+from scapy.layers.l2 import Ether
+from scapy.layers.inet6 import IP6Field
+
+_LLDP_tlv_cls = {0: "LLDPDUEnd",
+                 1: "LLDPChassisId",
+                 2: "LLDPPortId",
+                 3: "LLDPTTL",
+                 4: "LLDPPortDescription",
+                 5: "LLDPSystemName",
+                 6: "LLDPSystemDescription",
+                 7: "LLDPSystemCapabilities",
+                 8: "LLDPManagementAddress",
+                 127: "LLDPOrganizationalSpecific"}
+
+_LLDP_tlv_types = {0: "End of LLDPDU",
+                   1: "Chassis Id",
+                   2: "Port Id",
+                   3: "Time to Live",
+                   4: "Port Description",
+                   5: "System Name",
+                   6: "System Description",
+                   7: "System Capabilities",
+                   8: "Management Address",
+                   127: "Organization Specific"}
+
+
+# (oui, subtype)
+# 0x0080c2 - IEEE 802.1
+# 0x00120f - IEEE 802.3
+_LLDPOrgSpec_tlv_cls = {(0x0080c2, 0x01): "LLDPDot1PortVlanId",
+                       }
+
+
+def _LLDPGuessPacketClass(p=None, **kargs):
+    if p is None:
+        return LLDPGeneric(**kargs)
+
+    cls = Raw
+
+    if len(p) >= 2:
+        t = struct.unpack("!B", p[0])[0]
+        t = (0xfe & t) >> 1
+
+        if t != 127:
+            clsname = _LLDP_tlv_cls.get(t, "LLDPGeneric")
+        else:
+            oui = struct.unpack("!I", "\x00" + p[2:5])[0]
+            subtype = struct.unpack("!B", p[5])[0]
+            clsname = _LLDPOrgSpec_tlv_cls.get((oui, subtype), "LLDPOrgSpecGeneric")
+
+        cls = globals()[clsname]
+
+    return cls(p, **kargs)
+
+
+class LLDPGeneric(Packet):
+    name = "LLDP Generic TLV"
+    fields_desc = [BitField("type", 1, 7),
+                   BitFieldLenField("length", None, 9, length_of="value"),
+                   StrLenField("value", "", length_from=lambda x: x.length)]
+
+    def guess_payload_class(self, p):
+        return Padding
+
+    def post_build(self, p, pay):
+        if self.length is None:
+            l = len(p) - 2
+            p = chr((self.type << 1) ^ (l >> 8)) + chr(l & 0xff) + p[2:]
+
+        return p+pay
+
+
+class LLDPOrgSpecGeneric(LLDPGeneric):
+    name = "LLDP Org Spec Generic TLV"
+    fields_desc = [BitField("type", 127, 7),
+                   BitFieldLenField("length", None, 9, length_of="value"),
+                   X3BytesField("oui", 0),
+                   ByteField("subtype", 0), 
+                   StrLenField("value", "", length_from=lambda x: x.length - 4)]
+
+
+class LLDPDUEnd(LLDPGeneric):
+    name = "End of LLDPDU"
+    fields_desc = [BitField("type", 0, 7),
+                   BitField("length", 0, 9)]
+
+
+_LLDPChassisId_Subtypes = {0: "Reserved",
+                           1: "Chassis component",
+                           2: "Interface alias",
+                           3: "Port component",
+                           4: "MAC address",
+                           5: "Network address",
+                           6: "Interface name",
+                           7: "Locally assigned"}
+
+
+class LLDPChassisId(LLDPGeneric):
+    name = "LLDP Chassis"
+    fields_desc = [BitField("type", 1, 7),
+                   BitField("length", None, 9),
+                   ByteEnumField("subtype", 4, _LLDPChassisId_Subtypes),
+                   ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.subtype == 4),
+                   # TODO Subtype 5, IPv4 / IPv6
+                   # Catch-all field for undefined subtypes
+                   ConditionalField(StrLenField("value", "", length_from=lambda x: x.length - 1),
+                                    lambda pkt: pkt.subtype not in [4])]
+
+
+_LLDPPortId_Subtypes = {0: "Reserved",
+                        1: "Interface alias",
+                        2: "Port component",
+                        3: "MAC address",
+                        4: "Network address",
+                        5: "Interface name",
+                        6: "Agent circuit ID",
+                        7: "Locally assigned"}
+
+
+class LLDPPortId(LLDPGeneric):
+    name = "LLDP PortId"
+    fields_desc = [BitField("type", 2, 7),
+                   BitField("length", None, 9),
+                   ByteEnumField("subtype", 3, _LLDPPortId_Subtypes),
+                   ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.subtype == 3),
+                   # TODO Subtype 4, IPv4 / IPv6
+                   # Catch-all field for undefined subtypes
+                   ConditionalField(StrLenField("value", "", length_from=lambda x: x.length - 1),
+                                    lambda pkt: pkt.subtype not in [3])]
+
+
+class LLDPTTL(LLDPGeneric):
+    name = "LLDP TTL"
+    fields_desc = [BitField("type", 3, 7),
+                   BitField("length", None, 9),
+                   ShortField("seconds", 120)]
+
+
+class LLDPPortDescription(LLDPGeneric):
+    name = "LLDP Port Description"
+    type = 4
+    value = "FastEthernet0/1"
+
+
+class LLDPSystemName(LLDPGeneric):
+    name = "LLDP System Name"
+    type = 5
+    value = "Scapy"
+
+
+class LLDPSystemDescription(LLDPGeneric):
+    name = "LLDP System Description"
+    type = 6
+    value = "Scapy"
+
+
+_LLDPSystemCapabilities = ["other", "repeater", "bridge", "wlanap", "router", "telephone", "docsiscable", "stationonly"]
+
+
+class LLDPSystemCapabilities(LLDPGeneric):
+    name = "LLDP System Capabilities"
+    fields_desc = [BitField("type", 7, 7),
+                   BitField("length", None, 9),
+                   # Available capabilities
+                   FlagsField("capabilities", 0, 16, _LLDPSystemCapabilities),
+                   # Enabled capabilities
+                   FlagsField("enabled", 0, 16, _LLDPSystemCapabilities)]
+
+
+_LLDPManagementAddress_Subtype = {1: "IPv4",
+                                  2: "IPv6",
+                                  6: "802"
+                                 }
+
+_LLDPManagementAddress_IfSubtype = {1: "Unknown",
+                                    2: "ifIndex",
+                                    3: "System Port Number"
+                                   }
+
+
+class LLDPManagementAddress(LLDPGeneric):
+    name = "LLDP Management Address"
+    fields_desc = [BitField("type", 8, 7),
+                   BitField("length", None, 9),
+                   ByteField("addrlen", None),
+                   ByteEnumField("addrsubtype", 1, _LLDPManagementAddress_Subtype),
+                   ConditionalField(IPField("ipaddr", "192.168.0.1"), lambda pkt: pkt.addrsubtype == 1),
+                   ConditionalField(IP6Field("ip6addr", "2001:db8::1"), lambda pkt: pkt.addrsubtype == 2),
+                   ConditionalField(MACField("macaddr", "00:11:22:33:44:55"), lambda pkt: pkt.addrsubtype == 6),
+                   ConditionalField(StrLenField("addrval", "", length_from=lambda x: x.addrlen - 1),
+                                    lambda pkt: pkt.addrsubtype not in [1, 2, 6]),
+                   ByteEnumField("ifsubtype", 2, _LLDPManagementAddress_IfSubtype),
+                   IntField("ifnumber", 0),
+                   FieldLenField("oidlen", None, length_of="oid", fmt="B"),
+                   StrLenField("oid", "", length_from=lambda x: x.oidlen)]
+
+    def post_build(self, p, pay):
+        # TODO Remove redundant code. LLDPGeneric.post_build()
+        if self.length is None:
+            l = len(p) - 2
+            p = chr((self.type << 1) ^ (l >> 8)) + chr(l & 0xff) + p[2:]
+
+        if self.addrlen is None:
+            addrlen = len(p) - 2 - 8 - len(self.oid) + 1
+            p = p[:2] + struct.pack("B", addrlen) + p[3:]
+
+        return p+pay
+
+
+_LLDPDot1Subtype = {1: "Port VLAN Id"}
+
+
+class LLDPDot1PortVlanId(LLDPOrgSpecGeneric):
+    name = "LLDP IEEE 802.1 Port VLAN Id"
+    fields_desc = [BitField("type", 127, 7),
+                   BitField("length", None, 9),
+                   # TODO: XThreeBytesEnumField
+                   X3BytesField("oui", 0x0080c2),
+                   ByteEnumField("subtype", 0x01, _LLDPDot1Subtype),
+                   ShortField("vlan", 1)]
+
+
+class LLDP(Packet):
+    name ="LLDP"
+    fields_desc = [PacketListField("tlvlist", [], _LLDPGuessPacketClass)]
+
+
+bind_layers(Ether, LLDP, type=0x88cc)
-- 
1.9.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

* [dts] [dts 2/4] add unified packet type module and test suite
  2015-09-17  1:07 [dts] [dts 0/4] " Yufen Mo
@ 2015-09-17  1:07 ` Yufen Mo
  0 siblings, 0 replies; 6+ messages in thread
From: Yufen Mo @ 2015-09-17  1:07 UTC (permalink / raw)
  To: dts

From: yufengmx <yufengx.mo@intel.com>

This module based on scapy module function to handle packet generate and
analyse. Also based on tcpdump tool to sniff packets.

In this module, define some basic type packets which can simple used by name.
For example, "pkt=Packet(pkt_type='UDP')" will prepare default UDP packet.
After "pkt.send_pkt(tx_port='eth0')", the UDP packet will be sent out from
port "eth0".

For those tunnel packets, this module will seperate the packet type and strip
that what layers combine to this packet. For example,
"MAC_IPv6_NVGRE_MAC_IPFRAG_PKT" mean this is nvgre tunnle packet and combined
with Ether/IPv6/Nvgre/Ether/IP_frag/Raw data.

Signed-off-by: yufengmx <yufengx.mo@intel.com>
---
 framework/packet.py | 642 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 642 insertions(+)
 create mode 100755 framework/packet.py

diff --git a/framework/packet.py b/framework/packet.py
new file mode 100755
index 0000000..0a3f330
--- /dev/null
+++ b/framework/packet.py
@@ -0,0 +1,642 @@
+#!/usr/bin/python
+# BSD LICENSE
+#
+# Copyright(c) 2010-2015 Intel Corporation. All rights reserved.
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions
+# are met:
+#
+#   * Redistributions of source code must retain the above copyright
+#     notice, this list of conditions and the following disclaimer.
+#   * Redistributions in binary form must reproduce the above copyright
+#     notice, this list of conditions and the following disclaimer in
+#     the documentation and/or other materials provided with the
+#     distribution.
+#   * Neither the name of Intel Corporation nor the names of its
+#     contributors may be used to endorse or promote products derived
+#     from this software without specific prior written permission.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+"""
+Generic packet create, transmit and analyze module
+Base on scapy(python program for packet manipulation)
+"""
+
+import os
+import time
+import signal
+import sys
+import re
+import signal
+import random
+import subprocess
+from uuid import uuid4
+from settings import FOLDERS
+
+from scapy.config import conf
+conf.use_pcap = True
+
+from scapy.all import conf
+from scapy.utils import struct, socket, wrpcap, rdpcap
+from scapy.layers.inet import Ether, IP, TCP, UDP, ICMP
+from scapy.layers.inet6 import IPv6, IPv6ExtHdrRouting, IPv6ExtHdrFragment
+from scapy.layers.l2 import Dot1Q, ARP, GRE
+from scapy.layers.sctp import SCTP, SCTPChunkData
+from scapy.sendrecv import sniff
+from scapy.route import *
+from scapy.packet import bind_layers, Raw
+from scapy.sendrecv import sendp
+
+
+sys.path.append(FOLDERS['Depends'])
+# load extension layers
+from vxlan import Vxlan
+bind_layers(UDP, Vxlan, dport=4789)
+bind_layers(Vxlan, Ether)
+from nvgre import NVGRE, IPPROTO_NVGRE
+bind_layers(IP, NVGRE, proto=IPPROTO_NVGRE)
+bind_layers(NVGRE, Ether)
+from lldp import LLDP, LLDPManagementAddress
+bind_layers(Ether, LLDP, type=0x88cc)
+
+# packet generator type should be configured later
+PACKETGEN = "scapy"
+
+LayersTypes = {
+    "L2": ['ether', 'dot1q', '1588', 'arp', 'lldp'],
+    # ipv4_ext_unknown, ipv6_ext_unknown
+    "L3": ['ipv4','ipv4ihl', 'ipv6', 'ipv4_ext', 'ipv6_ext','ipv6_ext2', 'ipv6_frag'],
+    "L4": ['tcp', 'udp', 'frag', 'sctp', 'icmp', 'nofrag'],
+    "TUNNEL": ['ip', 'gre', 'vxlan', 'nvgre', 'geneve', 'grenat'],
+    "INNER L2": ['inner_mac', 'inner_mac&vlan'],
+    # inner_ipv4_unknown, inner_ipv6_unknown
+    "INNER L3": ['inner_ipv4', 'inner_ipv4_ext', 'inner_ipv6', 'inner_ipv6_ext'],
+    "INNER L4": ['inner_tcp', 'inner_udp', 'inner_frag', 'inner_sctp', 'inner_icmp', 'inner_nofrag'],
+    "PAYLOAD": ['raw']
+}
+
+# Saved back groud sniff process id
+SNIFF_PIDS = {}
+
+# Saved packet generator process id
+# used in pktgen or tgen
+PKTGEN_PIDS = {}
+
+
+class scapy(object):
+    SCAPY_LAYERS = {
+        'ether': Ether(dst="ff:ff:ff:ff:ff:ff"),
+        'dot1q': Dot1Q(),
+        '1588': Ether(type=0x88f7),
+        'arp': ARP(),
+        'ipv4': IP(),
+        'ipv4ihl': IP(ihl=10),
+        'ipv4_ext': IP(frag=5),
+        'ipv6': IPv6(src="::1"),
+        'ipv6_ext': IPv6(src="::1", nh=43)/IPv6ExtHdrRouting(),
+        'ipv6_ext2': IPv6()/IPv6ExtHdrRouting(),
+        'udp': UDP(),
+        'tcp': TCP(),
+        'sctp': SCTP(),
+        'icmp': ICMP(),
+        'gre': GRE(),
+        'raw': Raw(),
+        'vxlan': Vxlan(),
+
+        'inner_mac': Ether(),
+        'inner_mac&vlan': Ether() / Dot1Q(),
+        'inner_ipv4': IP(),
+        'inner_ipv4_ext': IP(),
+        'inner_ipv6': IPv6(src="::1"),
+        'inner_ipv6_ext': IPv6(src="::1"),
+
+        'inner_tcp': TCP(),
+        'inner_udp': UDP(),
+        'inner_sctp': SCTP(),
+        'inner_icmp': ICMP(),
+
+        'lldp': LLDP()/LLDPManagementAddress(),
+        'ip_frag': IP(frag=5),
+        'ipv6_frag': IPv6(src="::1")/IPv6ExtHdrFragment(),
+        'ip_in_ip': IP()/IP(),
+        'ip_in_ip_frag': IP()/IP(frag=5),
+        'ipv6_in_ip': IP()/IPv6(src="::1"),
+        'ipv6_frag_in_ip': IP()/IPv6(src="::1", nh=44)/IPv6ExtHdrFragment(),
+        'nvgre': NVGRE(),
+        'geneve': "Not Implement",
+    }
+
+    def __init__(self):
+        self.pkt = None
+        pass
+
+    def assign_pkt(self, pkt):
+        self.pkt = pkt
+
+    def add_layers(self, layers):
+        self.pkt = None
+        for layer in layers:
+            if self.pkt is not None:
+                self.pkt = self.pkt / self.SCAPY_LAYERS[layer]
+            else:
+                self.pkt = self.SCAPY_LAYERS[layer]
+
+    def ether(self, dst="ff:ff:ff:ff:ff:ff", src="00:00:20:00:00:00", type=None):
+        self.pkt[Ether].dst = dst
+        self.pkt[Ether].src = src
+        if type is not None:
+            self.pkt[Ether].type = type
+
+    def dot1q(self, vlan, prio=0, type=None):
+        self.pkt[Dot1Q].vlan = int(vlan)
+        self.pkt[Dot1Q].prio = prio
+        if type is not None:
+            self.pkt[Dot1Q].type = type
+
+    def strip_dot1q(self, element):
+        value = None
+
+        if self.pkt.haslayer('Dot1Q') is 0:
+            return None
+
+        if element == 'vlan':
+            value = int(str(self.pkt[Dot1Q].vlan))
+        return value
+
+    def ipv4(self, frag=0, src="127.0.0.1", proto=None, tos=0, dst="127.0.0.1", chksum=None, len=None, version=4, flags=None, ihl=None, ttl=64, id=1, options=None):
+        self.pkt[IP].frag = frag
+        self.pkt[IP].src = src
+        if proto is not None:
+            self.pkt[IP].proto = proto
+        self.pkt[IP].tos = tos
+        self.pkt[IP].dst = dst
+        if chksum is not None:
+            self.pkt[IP].chksum = chksum
+        if len is not None:
+            self.pkt[IP].len = len
+        self.pkt[IP].version = version
+        if flags is not None:
+            self.pkt[IP].flags = flags
+        if ihl is not None:
+            self.pkt[IP].ihl = ihl
+        self.pkt[IP].ttl = ttl
+        self.pkt[IP].id = id
+        if options is not None:
+            self.pkt[IP].options = options
+
+    def ipv6(self, version=6, tc=0, fl=0, plen=0, nh=0, hlim=64, src="::1", dst="::1"):
+        """
+        Configure IPv6 protocal.
+        """
+        self.pkt[IPv6].version = version
+        self.pkt[IPv6].tc = tc
+        self.pkt[IPv6].fl = fl
+        if plen:
+            self.pkt[IPv6].plen = plen
+        if nh:
+            self.pkt[IPv6].nh = nh
+        self.pkt[IPv6].src = src
+        self.pkt[IPv6].dst = dst
+
+    def inner_ipv6(self, version=6, tc=0, fl=0, plen=0, nh=0, hlim=64, src="::1", dst="::1"):
+        """
+        Configure IPv6 protocal.
+        """
+        self.pkt[IPv6][Ether][IPv6].version = version
+        self.pkt[IPv6][Ether][IPv6].tc = tc
+        self.pkt[IPv6][Ether][IPv6].fl = fl
+        if plen:
+            self.pkt[IPv6][Ether][IPv6].plen = plen
+        if nh:
+            self.pkt[IPv6][Ether][IPv6].nh = nh
+        self.pkt[IPv6][Ether][IPv6].src = src
+        self.pkt[IPv6][Ether][IPv6].dst = dst
+
+    def udp(self, src=53, dst=53, len=None, chksum=None):
+        self.pkt[UDP].sport = src
+        self.pkt[UDP].dport = dst
+        if len is not None:
+            self.pkt[UDP].len = len
+        if chksum is not None:
+            self.pkt[UDP].chksum = chksum
+
+    def raw(self, payload=None):
+        if payload is not None:
+            self.pkt[Raw].load = ''
+            for load in payload:
+                self.pkt[Raw].load += '%c' % int(load, 16)
+
+    def vxlan(self, vni=0):
+        self.pkt[Vxlan].vni = vni
+
+    def read_pcap(self, file):
+        pcap_pkts = []
+        try:
+            pcap_pkts = rdpcap(file)
+        except:
+            pass
+
+        return pcap_pkts
+
+    def write_pcap(self, file):
+        try:
+            wrpcap(file, self.pkt)
+        except:
+            pass
+
+    def send_pcap_pkt(self, crb=None, file='', intf=''):
+        if intf == '' or file == '' or crb is None:
+            print "Invalid option for send packet by scapy"
+            return
+
+        content = 'pkts=rdpcap(\"%s\");sendp(pkts, iface=\"%s\");exit()' % (file, intf)
+        cmd_file = '/tmp/scapy_%s.cmd' % intf
+
+        crb.create_file(content, cmd_file)
+        crb.send_expect("scapy -c scapy_%s.cmd &" % intf, "# ")
+
+    def print_summary(self):
+        print "Send out pkt %s" % self.pkt.summary()
+
+    def send_pkt(self, intf=''):
+        self.print_summary()
+        if intf != '':
+            sendp(self.pkt, iface=intf)
+
+
+class Packet(object):
+    """
+    Module for config/create packet
+    Based on scapy module
+    Usage: assign_layers([layers list])
+           config_layer('layername', {layer config})
+           ...
+    """
+    def_packet = {
+        'TIMESYNC': {'layers': ['ether', 'raw'], 'cfgload': False},
+        'ARP': {'layers': ['ether', 'arp'], 'cfgload': False},
+        'LLDP': {'layers': ['ether', 'lldp'], 'cfgload': False},
+        'TCP': {'layers': ['ether', 'ipv4', 'tcp', 'raw'], 'cfgload': True},
+        'UDP': {'layers': ['ether', 'ipv4', 'udp', 'raw'], 'cfgload': True},
+        'SCTP': {'layers': ['ether', 'ipv4', 'sctp', 'raw'], 'cfgload': True},
+        'IPv6_TCP': {'layers': ['ether', 'ipv6', 'tcp', 'raw'], 'cfgload': True},
+        'IPv6_UDP': {'layers': ['ether', 'ipv6', 'udp', 'raw'], 'cfgload': True},
+        'IPv6_SCTP': {'layers': ['ether', 'ipv6', 'sctp', 'raw'], 'cfgload': True},
+    }
+
+    def __init__(self, **options):
+        """
+        pkt_type: description of packet type
+                  defined in def_packet
+        options: special option for Packet module
+                 pkt_len: length of network packet
+                 ran_payload: whether payload of packet is random
+                 pkt_file:
+                 pkt_gen: packet generator type
+                          now only support scapy
+        """
+        self.pkt_layers = []
+        self.pkt_len = 64
+        self.pkt_opts = options
+
+        self.pkt_type = "UDP"
+
+        if 'pkt_type' in self.pkt_opts.keys():
+            self.pkt_type = self.pkt_opts['pkt_type']
+
+        if self.pkt_type in self.def_packet.keys():
+            self.pkt_layers = self.def_packet[self.pkt_type]['layers']
+            self.pkt_cfgload = self.def_packet[self.pkt_type]['cfgload']
+            if "IPv6" in self.pkt_type:
+                self.pkt_len = 128
+        else:
+            self._load_pkt_layers()
+            
+        if 'pkt_len' in self.pkt_opts.keys():
+            self.pkt_len = self.pkt_opts['pkt_len']
+
+        if 'pkt_file' in self.pkt_opts.keys():
+            self.uni_name = self.pkt_opts['pkt_file']
+        else:
+            self.uni_name = '/tmp/' + str(uuid4()) + '.pcap'
+
+        if 'pkt_gen' in self.pkt_opts.keys():
+            if self.pkt_opts['pkt_gen'] == 'scapy':
+                self.pktgen = scapy()
+            else:
+                print "Not support other pktgen yet!!!"
+        else:
+            self.pktgen = scapy()
+
+    def send_pkt(self, crb=None, tx_port='', auto_cfg=True):
+        if tx_port == '':
+            print "Invalid Tx interface"
+            return
+
+        self.tx_port = tx_port
+
+        # assign layer
+        self.assign_layers()
+
+        # config special layer
+        if auto_cfg is True:
+            self.config_def_layers()
+
+        # handle packet options
+        payload_len = self.pkt_len - len(self.pktgen.pkt) - 4
+
+        # if raw data has not been configured and payload should configured
+        if hasattr(self, 'configured_layer_raw') is False and self.pkt_cfgload is True:
+            payload = []
+            raw_confs = {}
+            if 'ran_payload' in self.pkt_opts.keys():
+                for loop in range(payload_len):
+                    payload.append("%02x" % random.randrange(0, 255))
+            else:
+                for loop in range(payload_len):
+                    payload.append('58')  # 'X'
+
+            raw_confs['payload'] = payload
+            self._config_layer_raw(raw_confs)
+
+        # check with port type
+        if 'ixia' in self.tx_port:
+            print "Not Support Yet"
+
+        if crb is not None:
+            self.pktgen.write_pcap(self.uni_name)
+            crb.session.copy_file_to(self.uni_name)
+            pcap_file = self.uni_name.split('/')[2]
+            self.pktgen.send_pcap_pkt(crb=crb, file=pcap_file, intf=self.tx_port)
+        else:
+            self.pktgen.send_pkt(intf=self.tx_port)
+
+    def check_layer_config(self, layer, config):
+        """
+        check the format of layer configuration
+        every layer should has different check function
+        """
+        pass
+
+    def assign_layers(self, layers=None):
+        """
+        assign layer for this packet
+        maybe need add check layer function
+        """
+        if layers is not None:
+            self.pkt_layers = layers
+
+        for layer in self.pkt_layers:
+            found = False
+            l_type = layer.lower()
+
+            for types in LayersTypes.values():
+                if l_type in types:
+                    found = True
+                    break
+
+            if found is False:
+                self.pkt_layers.remove(l_type)
+                print "INVAILD LAYER TYPE [%s]" % l_type.upper()
+
+        self.pktgen.add_layers(self.pkt_layers)
+
+    def _load_pkt_layers(self):
+        name2type = {
+            'MAC': 'ether',
+            'VLAN': 'dot1q',
+            'IP': 'ipv4',
+            'IPihl': 'ipv4ihl',
+            'IPFRAG': 'ipv4_ext',
+            'IPv6': 'ipv6',
+            'IPv6FRAG': 'ipv6_frag',
+            'IPv6EXT': 'ipv6_ext',
+            'IPv6EXT2': 'ipv6_ext2',
+            'TCP': 'tcp',
+            'UDP': 'udp',
+            'SCTP': 'sctp',
+            'ICMP': 'icmp',
+            'NVGRE': 'nvgre',
+            'GRE': 'gre',
+            'VXLAN': 'vxlan',
+            'PKT': 'raw',
+        }
+
+        layers = self.pkt_type.split('_')
+        self.pkt_layers = []
+        self.pkt_cfgload = True
+        for layer in layers:
+            if layer in name2type.keys():
+                self.pkt_layers.append(name2type[layer])
+        
+    def config_def_layers(self):
+        """
+        Handel config packet layers by default
+        """
+        if self.pkt_type == "TIMESYNC":
+            self.config_layer('ether', {'dst': 'FF:FF:FF:FF:FF:FF',
+                                        'type': 0x88f7})
+            self.config_layer('raw', {'payload': ['00', '02']})
+
+        if self.pkt_type == "ARP":
+            self.config_layer('ether', {'dst': 'FF:FF:FF:FF:FF:FF'})
+
+        if self.pkt_type == "IPv6_SCTP":
+            self.config_layer('ipv6', {'nh': 132})
+
+        if "IPv6_NVGRE" in self.pkt_type:
+            self.config_layer('ipv6', {'nh': 47})
+            if "IPv6_SCTP" in self.pkt_type:
+                self.config_layer('inner_ipv6', {'nh': 132})
+            if "IPv6_ICMP" in self.pkt_type:
+                self.config_layer('inner_ipv6', {'nh': 58})
+            if "IPFRAG" in self.pkt_type:
+                self.config_layer('raw', {'payload': ['00'] * 40})
+            else:
+                self.config_layer('raw', {'payload': ['00'] * 18})
+
+        if "MAC_IP_IPv6" in self.pkt_type or\
+           "MAC_IP_NVGRE" in self.pkt_type or \
+           "MAC_IP_UDP_VXLAN" in self.pkt_type:
+            if "IPv6_SCTP" in self.pkt_type:
+                self.config_layer('ipv6', {'nh': 132})
+            if "IPv6_ICMP" in self.pkt_type:
+                self.config_layer('ipv6', {'nh': 58})
+            if "IPFRAG" in self.pkt_type:
+                self.config_layer('raw', {'payload': ['00'] * 40})
+            else:
+                self.config_layer('raw', {'payload': ['00'] * 18})
+        
+    def config_layer(self, layer, config={}):
+        """
+        Configure packet assgined layer
+        return the status of configure result
+        """
+        try:
+            # if inner in layer mean same layer in outer
+            if 'inner' in layer:
+                dup_layer = layer[6:]
+                if self.pkt_layers.count(dup_layer) != 2:
+                    raise
+            else:
+                idx = self.pkt_layers.index(layer)
+        except Exception as e:
+            print "INVALID LAYER ID %s" % layer
+            return -1
+
+        if self.check_layer_config(layer, config) is False:
+            return -1
+
+        layer_conf = getattr(self, "_config_layer_%s" % layer)
+        setattr(self, 'configured_layer_%s' % layer, True)
+
+        return layer_conf(config)
+
+    def _config_layer_ether(self, config):
+        return self.pktgen.ether(**config)
+
+    def _config_layer_dot1q(self, config):
+        return self.pktgen.dot1q(**config)
+
+    def _config_layer_ipv4(self, config):
+        return self.pktgen.ipv4(**config)
+
+    def _config_layer_ipv6(self, config):
+        return self.pktgen.ipv6(**config)
+
+    def _config_layer_inner_ipv6(self, config):
+        return self.pktgen.inner_ipv6(**config)
+
+    def _config_layer_udp(self, config):
+        return self.pktgen.udp(**config)
+
+    def _config_layer_raw(self, config):
+        return self.pktgen.raw(**config)
+
+    def _config_layer_vxlan(self, config):
+        return self.pktgen.vxlan(**config)
+
+    def strip_layer_element(self, layer, element):
+        """
+        Strip packet layer elements
+        return the status of configure result
+        """
+        strip_element = getattr(self, "strip_element_%s" % layer)
+
+        return strip_element(element)
+
+    def strip_element_dot1q(self, element):
+        return self.pktgen.strip_dot1q(element)
+
+
+def increment_ip_address(self, addr):
+    """
+    Returns the IP address from a given one, like
+    192.168.1.1 ->192.168.1.2
+    If disable ip hw chksum, csum routine will increase ip
+    """
+    ip2int = lambda ipstr: struct.unpack('!I', socket.inet_aton(ipstr))[0]
+    x = ip2int(addr)
+    int2ip = lambda n: socket.inet_ntoa(struct.pack('!I', n))
+    return int2ip(x + 1)
+
+
+def increment_ipv6_address(self, addr):
+    """
+    Returns the IP address from a given one, like
+    FE80:0:0:0:0:0:0:0 -> FE80::1
+    csum routine will increase ip
+    """
+    ipv6addr = struct.unpack('!8H', socket.inet_pton(AF_INET6, addr))
+    addr = list(ipv6addr)
+    addr[7] += 1
+    ipv6 = socket.inet_ntop(AF_INET6, struct.pack(
+        '!8H', addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7]))
+    return ipv6
+
+
+def sniff_packets(intf, count=0, timeout=5):
+    """
+    sniff all packets for certain port in certain seconds
+    """
+    sniff_cmd = 'tcpdump -i %(INTF)s -w %(FILE)s'
+    options = {'INTF': intf, 'COUNT': count,
+               'FILE': '/tmp/sniff_%s.pcap' % intf}
+    if count:
+        sniff_cmd += ' -c %(COUNT)d'
+        cmd = sniff_cmd % options
+    else:
+        cmd = sniff_cmd % options
+
+    args = cmd.split()
+    pipe = subprocess.Popen(args)
+    index = str(time.time())
+    SNIFF_PIDS[index] = (pipe, intf, timeout)
+    return index
+
+
+def load_sniff_packets(index=''):
+    pkts = []
+    child_exit = False
+    if index in SNIFF_PIDS.keys():
+        pipe, intf, timeout = SNIFF_PIDS[index]
+        time_elapse = int(time.time() - float(index))
+        while time_elapse < timeout:
+            if pipe.poll() is not None:
+                child_exit = True
+                break
+
+            time.sleep(1)
+            time_elapse += 1
+
+        if not child_exit:
+            pipe.kill()
+
+        # wait pcap file ready
+        time.sleep(0.5)
+        try:
+            cap_pkts = rdpcap("/tmp/sniff_%s.pcap" % intf)
+            for pkt in cap_pkts:
+                # packet gen should be scapy
+                packet = Packet(tx_port=intf)
+                packet.pktgen.assign_pkt(pkt)
+                pkts.append(packet)
+        except:
+            pass
+
+    return pkts
+
+############################################################################################################
+############################################################################################################
+if __name__ == "__main__":
+    inst = sniff_packets("lo", timeout=5)
+    time.sleep(3)
+    pkts = load_sniff_packets(inst)
+
+    pkt = Packet(pkt_type='UDP', pkt_len=1500, ran_payload=True)
+    pkt.send_pkt(tx_port='lo')
+    pkt = Packet(pkt_type='IPv6_TCP')
+    pkt.send_pkt(tx_port='lo')
+    pkt = Packet(pkt_type='IPv6_SCTP')
+    pkt.send_pkt(tx_port='lo')
+
+    pkt = Packet()
+    pkt.assign_layers(['ether', 'dot1q', 'ipv4', 'udp', 'vxlan', 'inner_mac', 'inner_ipv4', 'inner_udp', 'raw'])
+    pkt.config_layer('ether', {'dst': '00:11:22:33:44:55'})
+    pkt.config_layer('dot1q', {'vlan': 2})
+    pkt.config_layer('ipv4', {'dst': '1.1.1.1'})
+    pkt.config_layer('udp', {'src': 4789, 'dst': 4789, 'chksum': 0x1111})
+    pkt.config_layer('vxlan', {'vni': 2})
+    pkt.config_layer('raw', {'payload': ['58']*18})
-- 
1.9.3

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2015-09-17  1:14 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-09-17  1:13 [dts] [dts 0/4] add unified packet type module and test suite Yufen Mo
2015-09-17  1:13 ` [dts] [dts 1/4] " Yufen Mo
2015-09-17  1:13 ` [dts] [dts 2/4] " Yufen Mo
2015-09-17  1:13 ` [dts] [dts 3/4] " Yufen Mo
2015-09-17  1:13 ` [dts] [dts 4/4] " Yufen Mo
  -- strict thread matches above, loose matches on Subject: below --
2015-09-17  1:07 [dts] [dts 0/4] " Yufen Mo
2015-09-17  1:07 ` [dts] [dts 2/4] " Yufen Mo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).