Update test documentation.

- update IRB, IPv4, ipv6 doc
- revert 778c2765c8

Change-Id: I9af5ed9329ce5fe01392cf28d5bf321cfc647e48
Signed-off-by: Matej Klotton <mklotton@cisco.com>
This commit is contained in:
Matej Klotton
2016-11-11 11:38:55 +01:00
committed by Damjan Marion
parent b7c3f2c61c
commit 86d87c40dd
28 changed files with 277 additions and 315 deletions

View File

@ -212,7 +212,7 @@ build-vpp-api: $(BR)/.bootstrap.ok
VPP_PYTHON_PREFIX=$(BR)/python
define test
$(if $(filter-out $(3),retest),make -C $(BR) PLATFORM=$(1) TAG=$(2) vpp-api-install plugins-install vpp-install vpp-api-test-install,)
$(if $(filter-out $(3),retest),make -C $(BR) PLATFORM=$(1) TAG=$(2) vpp-api-install plugins-install vpp-install,)
make -C test \
VPP_TEST_BIN=$(BR)/install-$(2)-native/vpp/bin/vpp \
VPP_TEST_API_TEST_BIN=$(BR)/install-$(2)-native/vpp-api-test/bin/vpp_api_test \

View File

@ -8,13 +8,15 @@ SPHINXBUILD = sphinx-build
PAPER =
BUILD_DOC_ROOT = $(BR)/test-doc
BUILD_DOC_DIR = $(BUILD_DOC_ROOT)/build
API_DOC_GEN_DIR = $(BUILD_DOC_ROOT)/apidoc
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d $(BUILD_DOC_DIR)/.sphinx-cache $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(SRC_DOC_DIR)
ALLSPHINXOPTS = -d $(BUILD_DOC_DIR)/.sphinx-cache $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) $(API_DOC_GEN_DIR) -c $(SRC_DOC_DIR)
# the i18n builder cannot share the environment and doctrees with the others
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
INDEX_REL_PATH:=$(shell realpath --relative-to=$(API_DOC_GEN_DIR) $(SRC_DOC_DIR)/index.rst)
IN_VENV:=$(shell if pip -V | grep "virtualenv" 2>&1 > /dev/null; then echo 1; else echo 0; fi)
.PHONY: verify-virtualenv
@ -23,6 +25,13 @@ ifeq ($(IN_VENV),0)
$(error "Not running inside virtualenv (are you running 'make test-doc' from root?)")
endif
.PHONY: regen-api-doc
regen-api-doc: verify-virtualenv
@mkdir -p $(API_DOC_GEN_DIR)
#@echo ".. include:: $(INDEX_REL_PATH)" > $(API_DOC_GEN_DIR)/index.rst
@cp $(SRC_DOC_DIR)/index.rst $(API_DOC_GEN_DIR)
sphinx-apidoc -o $(API_DOC_GEN_DIR) ..
.PHONY: help
help:
@echo "Please use \`make <target>' where <target> is one of"
@ -58,44 +67,44 @@ wipe:
rm -rf $(BUILD_DOC_ROOT)
.PHONY: html
html: verify-virtualenv
html: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/html
@echo
@echo "Build finished. The HTML pages are in $(BUILD_DOC_DIR)/html."
.PHONY: dirhtml
dirhtml: verify-virtualenv
dirhtml: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/dirhtml
@echo
@echo "Build finished. The HTML pages are in $(BUILD_DOC_DIR)/dirhtml."
.PHONY: singlehtml
singlehtml: verify-virtualenv
singlehtml: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/singlehtml
@echo
@echo "Build finished. The HTML page is in $(BUILD_DOC_DIR)/singlehtml."
.PHONY: pickle
pickle: verify-virtualenv
pickle: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/pickle
@echo
@echo "Build finished; now you can process the pickle files."
.PHONY: json
json: verify-virtualenv
json: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/json
@echo
@echo "Build finished; now you can process the JSON files."
.PHONY: htmlhelp
htmlhelp: verify-virtualenv
htmlhelp: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in $(BUILD_DOC_DIR)/htmlhelp."
.PHONY: qthelp
qthelp: verify-virtualenv
qthelp: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
@ -105,7 +114,7 @@ qthelp: verify-virtualenv
@echo "# assistant -collectionFile $(BUILD_DOC_DIR)/qthelp/VPPtestframework.qhc"
.PHONY: applehelp
applehelp: verify-virtualenv
applehelp: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b applehelp $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/applehelp
@echo
@echo "Build finished. The help book is in $(BUILD_DOC_DIR)/applehelp."
@ -114,7 +123,7 @@ applehelp: verify-virtualenv
"bundle."
.PHONY: devhelp
devhelp: verify-virtualenv
devhelp: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/devhelp
@echo
@echo "Build finished."
@ -124,7 +133,7 @@ devhelp: verify-virtualenv
@echo "# devhelp"
.PHONY: epub
epub: verify-virtualenv
epub: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/epub
@echo
@echo "Build finished. The epub file is in $(BUILD_DOC_DIR)/epub."
@ -136,7 +145,7 @@ epub3:
@echo "Build finished. The epub3 file is in $(BUILD_DOC_DIR)/epub3."
.PHONY: latex
latex: verify-virtualenv
latex: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/latex
@echo
@echo "Build finished; the LaTeX files are in $(BUILD_DOC_DIR)/latex."
@ -144,33 +153,33 @@ latex: verify-virtualenv
"(use \`make latexpdf' here to do that automatically)."
.PHONY: latexpdf
latexpdf: verify-virtualenv
latexpdf: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/latex
@echo "Running LaTeX files through pdflatex..."
$(MAKE) -C $(BUILD_DOC_DIR)/latex all-pdf
@echo "pdflatex finished; the PDF files are in $(BUILD_DOC_DIR)/latex."
.PHONY: latexpdfja
latexpdfja: verify-virtualenv
latexpdfja: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/latex
@echo "Running LaTeX files through platex and dvipdfmx..."
$(MAKE) -C $(BUILD_DOC_DIR)/latex all-pdf-ja
@echo "pdflatex finished; the PDF files are in $(BUILD_DOC_DIR)/latex."
.PHONY: text
text: verify-virtualenv
text: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/text
@echo
@echo "Build finished. The text files are in $(BUILD_DOC_DIR)/text."
.PHONY: man
man: verify-virtualenv
man: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/man
@echo
@echo "Build finished. The manual pages are in $(BUILD_DOC_DIR)/man."
.PHONY: texinfo
texinfo: verify-virtualenv
texinfo: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/texinfo
@echo
@echo "Build finished. The Texinfo files are in $(BUILD_DOC_DIR)/texinfo."
@ -178,57 +187,57 @@ texinfo: verify-virtualenv
"(use \`make info' here to do that automatically)."
.PHONY: info
info: verify-virtualenv
info: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/texinfo
@echo "Running Texinfo files through makeinfo..."
make -C $(BUILD_DOC_DIR)/texinfo info
@echo "makeinfo finished; the Info files are in $(BUILD_DOC_DIR)/texinfo."
.PHONY: gettext
gettext: verify-virtualenv
gettext: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILD_DOC_DIR)/locale
@echo
@echo "Build finished. The message catalogs are in $(BUILD_DOC_DIR)/locale."
.PHONY: changes
changes: verify-virtualenv
changes: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/changes
@echo
@echo "The overview file is in $(BUILD_DOC_DIR)/changes."
.PHONY: linkcheck
linkcheck: verify-virtualenv
linkcheck: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in $(BUILD_DOC_DIR)/linkcheck/output.txt."
.PHONY: doctest
doctest: verify-virtualenv
doctest: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in $(BUILD_DOC_DIR)/doctest/output.txt."
.PHONY: coverage
coverage: verify-virtualenv
coverage: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b coverage $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/coverage
@echo "Testing of coverage in the sources finished, look at the " \
"results in $(BUILD_DOC_DIR)/coverage/python.txt."
.PHONY: xml
xml: verify-virtualenv
xml: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/xml
@echo
@echo "Build finished. The XML files are in $(BUILD_DOC_DIR)/xml."
.PHONY: pseudoxml
pseudoxml: verify-virtualenv
pseudoxml: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/pseudoxml
@echo
@echo "Build finished. The pseudo-XML files are in $(BUILD_DOC_DIR)/pseudoxml."
.PHONY: dummy
dummy: verify-virtualenv
dummy: regen-api-doc verify-virtualenv
$(SPHINXBUILD) -b dummy $(ALLSPHINXOPTS) $(BUILD_DOC_DIR)/dummy
@echo
@echo "Build finished. Dummy builder generates no files."

View File

@ -1,7 +0,0 @@
framework module
================
.. automodule:: framework
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
hook module
===========
.. automodule:: hook
:members:
:undoc-members:
:show-inheritance:

View File

@ -22,7 +22,7 @@ Anatomy of a test case
######################
Python's unittest_ is used as the base framework upon which the VPP test
framework is built. A test suite in the |vtf| constists of multiple classes
framework is built. A test suite in the |vtf| consists of multiple classes
derived from `VppTestCase`, which is itself derived from TestCase_.
The test class defines one or more test functions, which act as test cases.
@ -44,11 +44,11 @@ Function flow when running a test case is:
The tearDown function is called after each test function with the purpose
of doing partial cleanup.
5. `tearDownClass <VppTestCase.tearDownClass>`:
Method called once after running all of the test funnctions to perform
Method called once after running all of the test functions to perform
the final cleanup.
Test temporary directory and VPP life cycle
################################################
###########################################
Test separation is achieved by separating the test files and vpp instances.
Each test creates a temporary directory and it's name is used to create
@ -60,7 +60,7 @@ are stored in this temporary test directory.
Virtual environment
###################
Virtualenv_ is a python module which provides a means to crate an environment
Virtualenv_ is a python module which provides a means to create an environment
containing the dependencies required by the |vtf|, allowing a separation
from any existing system-wide packages. |vtf|'s Makefile automatically
creates a virtualenv_ inside build-root and installs the required packages
@ -72,7 +72,7 @@ Naming conventions
Most unit tests do some kind of packet manipulation - sending and receiving
packets between VPP and virtual hosts connected to the VPP. Referring
to the sides, addresses, etc.. is always done as if looking from the VPP side,
to the sides, addresses, etc. is always done as if looking from the VPP side,
thus:
* *local_* prefix is used for the VPP side.

View File

@ -1,7 +0,0 @@
log module
==========
.. automodule:: log
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,24 +0,0 @@
test
====
.. toctree::
:maxdepth: 4
framework
hook
log
run_tests
scapy_handlers
template_bd
test_ip4
test_ip6
test_l2bd
test_l2xc
test_lb
test_mpls
test_vxlan
util
vpp_interface
vpp_papi_provider
vpp_pg_interface
vpp_sub_interface

View File

@ -1,7 +0,0 @@
run_tests module
================
.. automodule:: run_tests
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,22 +0,0 @@
scapy_handlers package
======================
Submodules
----------
scapy_handlers.vxlan module
---------------------------
.. automodule:: scapy_handlers.vxlan
:members:
:undoc-members:
:show-inheritance:
Module contents
---------------
.. automodule:: scapy_handlers
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
template_bd module
==================
.. automodule:: template_bd
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
test_ip module
==============
.. automodule:: test_ip4
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
test_ip6 module
===============
.. automodule:: test_ip6
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
test_l2bd module
================
.. automodule:: test_l2bd
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
test_l2xc module
================
.. automodule:: test_l2xc
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
test_lb module
==============
.. automodule:: test_lb
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
test_mpls module
================
.. automodule:: test_mpls
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
test_vxlan module
=================
.. automodule:: test_vxlan
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
util module
===========
.. automodule:: util
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
vpp_interface module
====================
.. automodule:: vpp_interface
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
vpp_papi_provider module
========================
.. automodule:: vpp_papi_provider
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
vpp_pg_interface module
=======================
.. automodule:: vpp_pg_interface
:members:
:undoc-members:
:show-inheritance:

View File

@ -1,7 +0,0 @@
vpp_sub_interface module
========================
.. automodule:: vpp_sub_interface
:members:
:undoc-members:
:show-inheritance:

View File

@ -29,22 +29,15 @@ class _PacketInfo(object):
Help process information about the next packet.
Set variables to default values.
@property index
Integer variable to store the index of the packet.
@property src
Integer variable to store the index of the source packet generator
interface of the packet.
@property dst
Integer variable to store the index of the destination packet generator
interface of the packet.
@property data
Object variable to store the copy of the former packet.
"""
#: Store the index of the packet.
index = -1
#: Store the index of the source packet generator interface of the packet.
src = -1
#: Store the index of the destination packet generator interface
#: of the packet.
dst = -1
#: Store the copy of the former packet.
data = None
@ -54,12 +47,8 @@ def pump_output(out, queue):
class VppTestCase(unittest.TestCase):
"""
Subclass of the python unittest.TestCase class.
This subclass is a base class for test cases that are implemented as classes
It provides methods to create and run test case.
"""This subclass is a base class for VPP test cases that are implemented as
classes. It provides methods to create and run test case.
"""
@property
@ -189,7 +178,7 @@ class VppTestCase(unittest.TestCase):
cls.packet_infos = {}
cls.verbose = 0
print(double_line_delim)
print(colorize(getdoc(cls), YELLOW))
print(colorize(getdoc(cls).splitlines()[0], YELLOW))
print(double_line_delim)
# need to catch exceptions here because if we raise, then the cleanup
# doesn't get called and we might end with a zombie vpp

View File

@ -2,24 +2,38 @@
import unittest
import socket
from logging import *
from framework import VppTestCase, VppTestRunner
from vpp_interface import VppInterface
from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
from scapy.packet import Raw
from scapy.layers.l2 import Ether, Dot1Q, ARP
from scapy.layers.l2 import Ether, Dot1Q
from scapy.layers.inet import IP, UDP
class TestIPv4(VppTestCase):
""" IPv4 Test Case """
@classmethod
def setUpClass(cls):
super(TestIPv4, cls).setUpClass()
def setUp(self):
"""
Perform test setup before test case.
**Config:**
- create 3 pg interfaces
- untagged pg0 interface
- Dot1Q subinterface on pg1
- Dot1AD subinterface on pg2
- setup interfaces:
- put it into UP state
- set IPv4 addresses
- resolve neighbor address using ARP
- configure 200 fib entries
:ivar list interfaces: pg interfaces and subinterfaces.
:ivar dict flows: IPv4 packet flows in test.
:ivar list pg_if_packet_sizes: packet sizes in test.
"""
super(TestIPv4, self).setUp()
# create 3 pg interfaces
@ -49,16 +63,26 @@ class TestIPv4(VppTestCase):
i.config_ip4()
i.resolve_arp()
# config 2M FIB enries
# config 2M FIB entries
self.config_fib_entries(200)
def tearDown(self):
"""Run standard test teardown and log ``show ip arp``."""
super(TestIPv4, self).tearDown()
if not self.vpp_dead:
info(self.vapi.cli("show ip arp"))
self.logger.info(self.vapi.cli("show ip arp"))
# info(self.vapi.cli("show ip fib")) # many entries
def config_fib_entries(self, count):
"""For each interface add to the FIB table *count* routes to
"10.0.0.1/32" destination with interface's local address as next-hop
address.
:param int count: Number of FIB entries.
- *TODO:* check if the next-hop address shouldn't be remote address
instead of local address.
"""
n_int = len(self.interfaces)
percent = 0
counter = 0.0
@ -69,13 +93,18 @@ class TestIPv4(VppTestCase):
for j in range(count / n_int):
self.vapi.ip_add_del_route(
dest_addr, dest_addr_len, next_hop_address)
counter = counter + 1
counter += 1
if counter / count * 100 > percent:
info("Configure %d FIB entries .. %d%% done" %
(count, percent))
percent = percent + 1
self.logger.info("Configure %d FIB entries .. %d%% done" %
(count, percent))
percent += 1
def create_stream(self, src_if, packet_sizes):
"""Create input packet stream for defined interface.
:param VppInterface src_if: Interface to create packet stream for.
:param list packet_sizes: Required packet sizes.
"""
pkts = []
for i in range(0, 257):
dst_if = self.flows[src_if][i % 2]
@ -95,7 +124,13 @@ class TestIPv4(VppTestCase):
return pkts
def verify_capture(self, dst_if, capture):
info("Verifying capture on interface %s" % dst_if.name)
"""Verify captured input packet stream for defined interface.
:param VppInterface dst_if: Interface to verify captured packet stream
for.
:param list capture: Captured packet stream.
"""
self.logger.info("Verifying capture on interface %s" % dst_if.name)
last_info = dict()
for i in self.interfaces:
last_info[i.sw_if_index] = None
@ -114,8 +149,8 @@ class TestIPv4(VppTestCase):
payload_info = self.payload_to_info(str(packet[Raw]))
packet_index = payload_info.index
self.assertEqual(payload_info.dst, dst_sw_if_index)
debug("Got packet on port %s: src=%u (id=%u)" %
(dst_if.name, payload_info.src, packet_index))
self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
(dst_if.name, payload_info.src, packet_index))
next_info = self.get_next_packet_info_for_interface2(
payload_info.src, dst_sw_if_index,
last_info[payload_info.src])
@ -129,8 +164,8 @@ class TestIPv4(VppTestCase):
self.assertEqual(udp.sport, saved_packet[UDP].sport)
self.assertEqual(udp.dport, saved_packet[UDP].dport)
except:
error("Unexpected or invalid packet:")
error(packet.show())
self.logger.error("Unexpected or invalid packet:")
self.logger.error(packet.show())
raise
for i in self.interfaces:
remaining_packet = self.get_next_packet_info_for_interface2(
@ -141,7 +176,14 @@ class TestIPv4(VppTestCase):
(dst_if.name, i.name))
def test_fib(self):
""" IPv4 FIB test """
""" IPv4 FIB test
Test scenario:
- Create IPv4 stream for pg0 interface
- Create IPv4 tagged streams for pg1's and pg2's subinterface.
- Send and verify received packets on each interface.
"""
pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes)
self.pg0.add_stream(pkts)

View File

@ -1,39 +1,51 @@
#!/usr/bin/env python
"""IRB Test Case HLD:
**config**
- L2 MAC learning enabled in l2bd
- 2 routed interfaces untagged, bvi (Bridge Virtual Interface)
- 2 bridged interfaces in l2bd with bvi
**test**
- sending ip4 eth pkts between routed interfaces
- 2 routed interfaces
- 2 bridged interfaces
- 64B, 512B, 1518B, 9200B (ether_size)
- burst of pkts per interface
- 257pkts per burst
- routed pkts hitting different FIB entries
- bridged pkts hitting different MAC entries
**verify**
- all packets received correctly
"""
import unittest
from random import choice, randint
from random import choice
from scapy.packet import Raw
from scapy.layers.l2 import Ether
from scapy.layers.inet import IP, UDP
from logging import *
from framework import VppTestCase, VppTestRunner
""" IRB Test Case
config
L2 MAC learning enabled in l2bd
2 routed interfaces untagged, bvi
2 bridged interfaces in l2bd with bvi
test
sending ip4 eth pkts between routed interfaces
2 routed interfaces
2 bridged interfaces
64B, 512B, 1518B, 9200B (ether_size)
burst of pkts per interface
257pkts per burst
routed pkts hitting different FIB entries
bridged pkts hitting different MAC entries
verify
all packets received correctly
"""
class TestIpIrb(VppTestCase):
""" IRB Test Case """
"""IRB Test Case"""
@classmethod
def setUpClass(cls):
"""
#. Create BD with MAC learning enabled and put interfaces to this BD.
#. Configure IPv4 addresses on loopback interface and routed interface.
#. Configure MAC address binding to IPv4 neighbors on loop0.
#. Configure MAC address on pg2.
#. Loopback BVI interface has remote hosts, one half of hosts are
behind pg0 second behind pg1.
"""
super(TestIpIrb, cls).setUpClass()
cls.pg_if_packet_sizes = [64, 512, 1518, 9018] # packet sizes
@ -58,27 +70,34 @@ class TestIpIrb(VppTestCase):
cls.vapi.sw_interface_set_l2_bridge(
cls.pg1.sw_if_index, bd_id=cls.bd_id)
# Configure IPv4 addresses on loopback interface and routed interface
cls.loop0.config_ip4()
cls.pg2.config_ip4()
# configure MAC address binding to IPv4 neighbors on loop0
# Configure MAC address binding to IPv4 neighbors on loop0
cls.loop0.generate_remote_hosts(cls.remote_hosts_count)
cls.loop0.configure_extend_ipv4_mac_binding()
cls.loop0.configure_ipv4_neighbors()
# configure MAC address on pg2
cls.pg2.resolve_arp()
# one half of hosts are behind pg0 second behind pg1
# Loopback BVI interface has remote hosts, one half of hosts are behind
# pg0 second behind pg1
half = cls.remote_hosts_count // 2
cls.pg0.remote_hosts = cls.loop0.remote_hosts[:half]
cls.pg1.remote_hosts = cls.loop0.remote_hosts[half:]
def tearDown(self):
"""Run standard test teardown and log ``show l2patch``,
``show l2fib verbose``,``show bridge-domain <bd_id> detail``,
``show ip arp``.
"""
super(TestIpIrb, self).tearDown()
if not self.vpp_dead:
info(self.vapi.cli("show l2patch"))
info(self.vapi.cli("show l2fib verbose"))
info(self.vapi.cli("show bridge-domain %s detail" % self.bd_id))
info(self.vapi.cli("show ip arp"))
self.logger.info(self.vapi.cli("show l2patch"))
self.logger.info(self.vapi.cli("show l2fib verbose"))
self.logger.info(self.vapi.cli("show bridge-domain %s detail" %
self.bd_id))
self.logger.info(self.vapi.cli("show ip arp"))
def create_stream(self, src_ip_if, dst_ip_if, packet_sizes):
pkts = []
@ -200,8 +219,8 @@ class TestIpIrb(VppTestCase):
""" IPv4 IRB test 1
Test scenario:
ip traffic from pg2 interface must ends in both pg0 and pg1
- arp entry present in loop0 interface for dst IP
- ip traffic from pg2 interface must ends in both pg0 and pg1
- arp entry present in loop0 interface for destination IP
- no l2 entree configured, pg0 and pg1 are same
"""
@ -224,7 +243,7 @@ class TestIpIrb(VppTestCase):
""" IPv4 IRB test 2
Test scenario:
ip traffic from pg0 and pg1 ends on pg2
- ip traffic from pg0 and pg1 ends on pg2
"""
stream1 = self.create_stream_l2_to_ip(

View File

@ -2,14 +2,13 @@
import unittest
import socket
from logging import *
from framework import VppTestCase, VppTestRunner
from vpp_sub_interface import VppSubInterface, VppDot1QSubint, VppDot1ADSubint
from vpp_sub_interface import VppSubInterface, VppDot1QSubint
from scapy.packet import Raw
from scapy.layers.l2 import Ether, Dot1Q
from scapy.layers.inet6 import ICMPv6ND_NS, IPv6, UDP
from scapy.layers.inet6 import IPv6, UDP
class TestIPv6(VppTestCase):
@ -20,6 +19,26 @@ class TestIPv6(VppTestCase):
super(TestIPv6, cls).setUpClass()
def setUp(self):
"""
Perform test setup before test case.
**Config:**
- create 3 pg interfaces
- untagged pg0 interface
- Dot1Q subinterface on pg1
- Dot1AD subinterface on pg2
- setup interfaces:
- put it into UP state
- set IPv6 addresses
- resolve neighbor address using NDP
- configure 200 fib entries
:ivar list interfaces: pg interfaces and subinterfaces.
:ivar dict flows: IPv4 packet flows in test.
:ivar list pg_if_packet_sizes: packet sizes in test.
*TODO:* Create AD sub interface
"""
super(TestIPv6, self).setUp()
# create 3 pg interfaces
@ -28,8 +47,9 @@ class TestIPv6(VppTestCase):
# create 2 subinterfaces for p1 and pg2
self.sub_interfaces = [
VppDot1QSubint(self, self.pg1, 100),
VppDot1QSubint(self, self.pg2, 200)]
VppDot1QSubint(self, self.pg2, 200)
# TODO: VppDot1ADSubint(self, self.pg2, 200, 300, 400)
]
# packet flows mapping pg0 -> pg1.sub, pg2.sub, etc.
self.flows = dict()
@ -50,16 +70,26 @@ class TestIPv6(VppTestCase):
i.config_ip6()
i.resolve_ndp()
# config 2M FIB enries
# config 2M FIB entries
self.config_fib_entries(200)
def tearDown(self):
"""Run standard test teardown and log ``show ip6 neighbors``."""
super(TestIPv6, self).tearDown()
if not self.vpp_dead:
info(self.vapi.cli("show ip6 neighbors"))
self.logger.info(self.vapi.cli("show ip6 neighbors"))
# info(self.vapi.cli("show ip6 fib")) # many entries
def config_fib_entries(self, count):
"""For each interface add to the FIB table *count* routes to
"fd02::1/128" destination with interface's local address as next-hop
address.
:param int count: Number of FIB entries.
- *TODO:* check if the next-hop address shouldn't be remote address
instead of local address.
"""
n_int = len(self.interfaces)
percent = 0
counter = 0.0
@ -70,13 +100,18 @@ class TestIPv6(VppTestCase):
for j in range(count / n_int):
self.vapi.ip_add_del_route(
dest_addr, dest_addr_len, next_hop_address, is_ipv6=1)
counter = counter + 1
counter += 1
if counter / count * 100 > percent:
info("Configure %d FIB entries .. %d%% done" %
self.logger.info("Configure %d FIB entries .. %d%% done" %
(count, percent))
percent = percent + 1
percent += 1
def create_stream(self, src_if, packet_sizes):
"""Create input packet stream for defined interface.
:param VppInterface src_if: Interface to create packet stream for.
:param list packet_sizes: Required packet sizes.
"""
pkts = []
for i in range(0, 257):
dst_if = self.flows[src_if][i % 2]
@ -96,7 +131,13 @@ class TestIPv6(VppTestCase):
return pkts
def verify_capture(self, dst_if, capture):
info("Verifying capture on interface %s" % dst_if.name)
"""Verify captured input packet stream for defined interface.
:param VppInterface dst_if: Interface to verify captured packet stream
for.
:param list capture: Captured packet stream.
"""
self.logger.info("Verifying capture on interface %s" % dst_if.name)
last_info = dict()
for i in self.interfaces:
last_info[i.sw_if_index] = None
@ -115,8 +156,8 @@ class TestIPv6(VppTestCase):
payload_info = self.payload_to_info(str(packet[Raw]))
packet_index = payload_info.index
self.assertEqual(payload_info.dst, dst_sw_if_index)
debug("Got packet on port %s: src=%u (id=%u)" %
(dst_if.name, payload_info.src, packet_index))
self.logger.debug("Got packet on port %s: src=%u (id=%u)" %
(dst_if.name, payload_info.src, packet_index))
next_info = self.get_next_packet_info_for_interface2(
payload_info.src, dst_sw_if_index,
last_info[payload_info.src])
@ -130,8 +171,8 @@ class TestIPv6(VppTestCase):
self.assertEqual(udp.sport, saved_packet[UDP].sport)
self.assertEqual(udp.dport, saved_packet[UDP].dport)
except:
error("Unexpected or invalid packet:")
error(packet.show())
self.logger.error("Unexpected or invalid packet:")
self.logger.error(packet.show())
raise
for i in self.interfaces:
remaining_packet = self.get_next_packet_info_for_interface2(
@ -142,7 +183,13 @@ class TestIPv6(VppTestCase):
(dst_if.name, i.name))
def test_fib(self):
""" IPv6 FIB test """
""" IPv6 FIB test
Test scenario:
- Create IPv6 stream for pg0 interface
- Create IPv6 tagged streams for pg1's and pg2's subinterface.
- Send and verify received packets on each interface.
"""
pkts = self.create_stream(self.pg0, self.pg_if_packet_sizes)
self.pg0.add_stream(pkts)

View File

@ -6,59 +6,57 @@ from util import Host
class VppInterface(object):
"""
Generic VPP interface
"""
"""Generic VPP interface."""
__metaclass__ = ABCMeta
@property
def sw_if_index(self):
"""Interface index assigned by VPP"""
"""Interface index assigned by VPP."""
return self._sw_if_index
@property
def remote_mac(self):
"""MAC-address of the remote interface "connected" to this interface"""
"""MAC-address of the remote interface "connected" to this interface."""
return self._remote_hosts[0].mac
@property
def local_mac(self):
"""MAC-address of the VPP interface"""
"""MAC-address of the VPP interface."""
return self._local_mac
@property
def local_ip4(self):
"""Local IPv4 address on VPP interface (string)"""
"""Local IPv4 address on VPP interface (string)."""
return self._local_ip4
@property
def local_ip4n(self):
"""Local IPv4 address - raw, suitable as API parameter"""
"""Local IPv4 address - raw, suitable as API parameter."""
return socket.inet_pton(socket.AF_INET, self._local_ip4)
@property
def remote_ip4(self):
"""IPv4 address of remote peer "connected" to this interface"""
"""IPv4 address of remote peer "connected" to this interface."""
return self._remote_hosts[0].ip4
@property
def remote_ip4n(self):
"""IPv4 address of remote peer - raw, suitable as API parameter"""
"""IPv4 address of remote peer - raw, suitable as API parameter."""
return socket.inet_pton(socket.AF_INET, self.remote_ip4)
@property
def local_ip6(self):
"""Local IPv6 address on VPP interface (string)"""
"""Local IPv6 address on VPP interface (string)."""
return self._local_ip6
@property
def local_ip6n(self):
"""Local IPv6 address - raw, suitable as API parameter"""
"""Local IPv6 address - raw, suitable as API parameter."""
return socket.inet_pton(socket.AF_INET6, self.local_ip6)
@property
def remote_ip6(self):
"""IPv6 address of remote peer "connected" to this interface"""
"""IPv6 address of remote peer "connected" to this interface."""
return self._remote_hosts[0].ip6
@property
@ -68,17 +66,17 @@ class VppInterface(object):
@property
def name(self):
"""Name of the interface"""
"""Name of the interface."""
return self._name
@property
def dump(self):
"""Raw result of sw_interface_dump for this interface"""
"""RAW result of sw_interface_dump for this interface."""
return self._dump
@property
def test(self):
"""Test case creating this interface"""
"""Test case creating this interface."""
return self._test
@property
@ -88,20 +86,44 @@ class VppInterface(object):
@remote_hosts.setter
def remote_hosts(self, value):
"""
:param list value: List of remote hosts.
"""
self._remote_hosts = value
#TODO: set hosts_by dicts
self._hosts_by_mac = {}
self._hosts_by_ip4 = {}
self._hosts_by_ip6 = {}
for host in self._remote_hosts:
self._hosts_by_mac[host.mac] = host
self._hosts_by_ip4[host.ip4] = host
self._hosts_by_ip6[host.ip6] = host
def host_by_mac(self, mac):
"""
:param ip: MAC address to find host by.
:return: Host object assigned to interface.
"""
return self._hosts_by_mac[mac]
def host_by_ip4(self, ip):
"""
:param ip: IPv4 address to find host by.
:return: Host object assigned to interface.
"""
return self._hosts_by_ip4[ip]
def host_by_ip6(self, ip):
"""
:param ip: IPv6 address to find host by.
:return: Host object assigned to interface.
"""
return self._hosts_by_ip6[ip]
def generate_remote_hosts(self, count=1):
"""Generate and add remote hosts for the interface."""
"""Generate and add remote hosts for the interface.
:param int count: Number of generated remote hosts.
"""
self._remote_hosts = []
self._hosts_by_mac = {}
self._hosts_by_ip4 = {}
@ -117,7 +139,7 @@ class VppInterface(object):
self._hosts_by_ip6[ip6] = host
def post_init_setup(self):
"""Additional setup run after creating an interface object"""
"""Additional setup run after creating an interface object."""
self.generate_remote_hosts()
@ -149,21 +171,21 @@ class VppInterface(object):
(self.__name__, self.remote_mac, self.remote_ip4, self.local_ip4))
def config_ip4(self):
"""Configure IPv4 address on the VPP interface"""
"""Configure IPv4 address on the VPP interface."""
addr = self.local_ip4n
addr_len = 24
self.test.vapi.sw_interface_add_del_address(
self.sw_if_index, addr, addr_len)
def configure_extend_ipv4_mac_binding(self):
"""Configure neighbor MAC to IPv4 addresses."""
def configure_ipv4_neighbors(self):
"""For every remote host assign neighbor's MAC to IPv4 addresses."""
for host in self._remote_hosts:
macn = host.mac.replace(":", "").decode('hex')
ipn = host.ip4n
self.test.vapi.ip_neighbor_add_del(self.sw_if_index, macn, ipn)
def config_ip6(self):
"""Configure IPv6 address on the VPP interface"""
"""Configure IPv6 address on the VPP interface."""
addr = self._local_ip6n
addr_len = 64
self.test.vapi.sw_interface_add_del_address(
@ -171,30 +193,31 @@ class VppInterface(object):
def set_table_ip4(self, table_id):
"""Set the interface in a IPv4 Table.
Must be called before configuring IP4 addresses"""
.. note:: Must be called before configuring IP4 addresses."""
self.test.vapi.sw_interface_set_table(
self.sw_if_index, 0, table_id)
def set_table_ip6(self, table_id):
"""Set the interface in a IPv6 Table.
Must be called before configuring IP6 addresses"""
.. note:: Must be called before configuring IP6 addresses.
"""
self.test.vapi.sw_interface_set_table(
self.sw_if_index, 1, table_id)
def disable_ipv6_ra(self):
"""Configure IPv6 RA suppress on the VPP interface"""
"""Configure IPv6 RA suppress on the VPP interface."""
self.test.vapi.sw_interface_ra_suppress(self.sw_if_index)
def admin_up(self):
""" Put interface ADMIN-UP """
"""Put interface ADMIN-UP."""
self.test.vapi.sw_interface_set_flags(self.sw_if_index, admin_up_down=1)
def add_sub_if(self, sub_if):
"""
Register a sub-interface with this interface
"""Register a sub-interface with this interface.
:param sub_if: sub-interface
"""
if not hasattr(self, 'sub_if'):
self.sub_if = sub_if
@ -205,6 +228,6 @@ class VppInterface(object):
self.sub_if = sub_if
def enable_mpls(self):
"""Enable MPLS on the VPP interface"""
"""Enable MPLS on the VPP interface."""
self.test.vapi.sw_interface_enable_disable_mpls(
self.sw_if_index)

View File

@ -3,9 +3,7 @@ from vpp_interface import VppInterface
class VppLoInterface(VppInterface):
"""
VPP loopback interface
"""
"""VPP loopback interface."""
def __init__(self, test, lo_index):
""" Create VPP loopback interface """