2019-10-31 13:31:07 -05:00
|
|
|
#!/usr/bin/env python3
|
2016-10-03 19:44:57 +02:00
|
|
|
|
2017-02-14 02:55:31 +01:00
|
|
|
from __future__ import print_function
|
2019-12-01 22:24:28 -05:00
|
|
|
import logging
|
Revert "VPP-1508 python3 tests: raw_input"
This reverts commit 72f0004ac5f6e201cbe042593d76df6f2491d743.
Reason for revert: Traceback (most recent call last):
File "/home/ksekera/vpp/test/test_ipsec_ah.py", line 36, in
setUpClass
super(TemplateIpsecAh, cls).setUpClass()
File "/home/ksekera/vpp/test/template_ipsec.py", line 105, in
setUpClass
super(TemplateIpsec, cls).setUpClass()
File "/home/ksekera/vpp/test/framework.py", line 459, in setUpClass
cls.quit()
File "/home/ksekera/vpp/test/framework.py", line 475, in quit
six.input("When done debugging, press ENTER to kill the "
AttributeError: 'module' object has no attribute 'input'
Change-Id: Idf0bbfea231730b37bae5dcb4557a0f82ab1b810
Signed-off-by: Ole Troan <ot@cisco.com>
2018-11-26 10:27:50 +00:00
|
|
|
import sys
|
2017-02-14 02:55:31 +01:00
|
|
|
import os
|
|
|
|
import select
|
2019-06-20 12:24:12 -04:00
|
|
|
import signal
|
2020-12-05 22:39:14 +00:00
|
|
|
import subprocess
|
Revert "VPP-1508 python3 tests: raw_input"
This reverts commit 72f0004ac5f6e201cbe042593d76df6f2491d743.
Reason for revert: Traceback (most recent call last):
File "/home/ksekera/vpp/test/test_ipsec_ah.py", line 36, in
setUpClass
super(TemplateIpsecAh, cls).setUpClass()
File "/home/ksekera/vpp/test/template_ipsec.py", line 105, in
setUpClass
super(TemplateIpsec, cls).setUpClass()
File "/home/ksekera/vpp/test/framework.py", line 459, in setUpClass
cls.quit()
File "/home/ksekera/vpp/test/framework.py", line 475, in quit
six.input("When done debugging, press ENTER to kill the "
AttributeError: 'module' object has no attribute 'input'
Change-Id: Idf0bbfea231730b37bae5dcb4557a0f82ab1b810
Signed-off-by: Ole Troan <ot@cisco.com>
2018-11-26 10:27:50 +00:00
|
|
|
import unittest
|
2021-05-31 16:08:53 +02:00
|
|
|
import re
|
2016-10-28 13:20:27 +02:00
|
|
|
import time
|
Revert "VPP-1508 python3 tests: raw_input"
This reverts commit 72f0004ac5f6e201cbe042593d76df6f2491d743.
Reason for revert: Traceback (most recent call last):
File "/home/ksekera/vpp/test/test_ipsec_ah.py", line 36, in
setUpClass
super(TemplateIpsecAh, cls).setUpClass()
File "/home/ksekera/vpp/test/template_ipsec.py", line 105, in
setUpClass
super(TemplateIpsec, cls).setUpClass()
File "/home/ksekera/vpp/test/framework.py", line 459, in setUpClass
cls.quit()
File "/home/ksekera/vpp/test/framework.py", line 475, in quit
six.input("When done debugging, press ENTER to kill the "
AttributeError: 'module' object has no attribute 'input'
Change-Id: Idf0bbfea231730b37bae5dcb4557a0f82ab1b810
Signed-off-by: Ole Troan <ot@cisco.com>
2018-11-26 10:27:50 +00:00
|
|
|
import faulthandler
|
|
|
|
import random
|
|
|
|
import copy
|
2018-11-29 09:37:08 +01:00
|
|
|
import platform
|
2021-05-31 16:08:53 +02:00
|
|
|
import shutil
|
2016-12-08 10:16:41 +01:00
|
|
|
from collections import deque
|
2018-11-25 11:05:13 -08:00
|
|
|
from threading import Thread, Event
|
Revert "VPP-1508 python3 tests: raw_input"
This reverts commit 72f0004ac5f6e201cbe042593d76df6f2491d743.
Reason for revert: Traceback (most recent call last):
File "/home/ksekera/vpp/test/test_ipsec_ah.py", line 36, in
setUpClass
super(TemplateIpsecAh, cls).setUpClass()
File "/home/ksekera/vpp/test/template_ipsec.py", line 105, in
setUpClass
super(TemplateIpsec, cls).setUpClass()
File "/home/ksekera/vpp/test/framework.py", line 459, in setUpClass
cls.quit()
File "/home/ksekera/vpp/test/framework.py", line 475, in quit
six.input("When done debugging, press ENTER to kill the "
AttributeError: 'module' object has no attribute 'input'
Change-Id: Idf0bbfea231730b37bae5dcb4557a0f82ab1b810
Signed-off-by: Ole Troan <ot@cisco.com>
2018-11-26 10:27:50 +00:00
|
|
|
from inspect import getdoc, isclass
|
2018-11-25 11:05:13 -08:00
|
|
|
from traceback import format_exception
|
Revert "VPP-1508 python3 tests: raw_input"
This reverts commit 72f0004ac5f6e201cbe042593d76df6f2491d743.
Reason for revert: Traceback (most recent call last):
File "/home/ksekera/vpp/test/test_ipsec_ah.py", line 36, in
setUpClass
super(TemplateIpsecAh, cls).setUpClass()
File "/home/ksekera/vpp/test/template_ipsec.py", line 105, in
setUpClass
super(TemplateIpsec, cls).setUpClass()
File "/home/ksekera/vpp/test/framework.py", line 459, in setUpClass
cls.quit()
File "/home/ksekera/vpp/test/framework.py", line 475, in quit
six.input("When done debugging, press ENTER to kill the "
AttributeError: 'module' object has no attribute 'input'
Change-Id: Idf0bbfea231730b37bae5dcb4557a0f82ab1b810
Signed-off-by: Ole Troan <ot@cisco.com>
2018-11-26 10:27:50 +00:00
|
|
|
from logging import FileHandler, DEBUG, Formatter
|
2021-01-14 10:19:08 +00:00
|
|
|
from enum import Enum
|
2021-04-08 19:37:41 +02:00
|
|
|
from abc import ABC, abstractmethod
|
2021-09-22 11:24:06 +01:00
|
|
|
from struct import pack, unpack
|
2019-03-10 10:04:23 -07:00
|
|
|
|
|
|
|
import scapy.compat
|
2022-01-10 21:57:27 +00:00
|
|
|
from scapy.packet import Raw, Packet
|
2024-09-27 17:11:18 +03:00
|
|
|
from vpp_pg_interface import VppPGInterface, is_ipv6_misc
|
2018-12-21 16:04:22 +01:00
|
|
|
from vpp_sub_interface import VppSubInterface
|
Revert "VPP-1508 python3 tests: raw_input"
This reverts commit 72f0004ac5f6e201cbe042593d76df6f2491d743.
Reason for revert: Traceback (most recent call last):
File "/home/ksekera/vpp/test/test_ipsec_ah.py", line 36, in
setUpClass
super(TemplateIpsecAh, cls).setUpClass()
File "/home/ksekera/vpp/test/template_ipsec.py", line 105, in
setUpClass
super(TemplateIpsec, cls).setUpClass()
File "/home/ksekera/vpp/test/framework.py", line 459, in setUpClass
cls.quit()
File "/home/ksekera/vpp/test/framework.py", line 475, in quit
six.input("When done debugging, press ENTER to kill the "
AttributeError: 'module' object has no attribute 'input'
Change-Id: Idf0bbfea231730b37bae5dcb4557a0f82ab1b810
Signed-off-by: Ole Troan <ot@cisco.com>
2018-11-26 10:27:50 +00:00
|
|
|
from vpp_lo_interface import VppLoInterface
|
2019-03-15 02:16:20 -07:00
|
|
|
from vpp_bvi_interface import VppBviInterface
|
Revert "VPP-1508 python3 tests: raw_input"
This reverts commit 72f0004ac5f6e201cbe042593d76df6f2491d743.
Reason for revert: Traceback (most recent call last):
File "/home/ksekera/vpp/test/test_ipsec_ah.py", line 36, in
setUpClass
super(TemplateIpsecAh, cls).setUpClass()
File "/home/ksekera/vpp/test/template_ipsec.py", line 105, in
setUpClass
super(TemplateIpsec, cls).setUpClass()
File "/home/ksekera/vpp/test/framework.py", line 459, in setUpClass
cls.quit()
File "/home/ksekera/vpp/test/framework.py", line 475, in quit
six.input("When done debugging, press ENTER to kill the "
AttributeError: 'module' object has no attribute 'input'
Change-Id: Idf0bbfea231730b37bae5dcb4557a0f82ab1b810
Signed-off-by: Ole Troan <ot@cisco.com>
2018-11-26 10:27:50 +00:00
|
|
|
from vpp_papi_provider import VppPapiProvider
|
2021-06-03 14:43:21 +00:00
|
|
|
from vpp_papi import VppEnum
|
2019-12-02 21:42:28 -05:00
|
|
|
import vpp_papi
|
2018-11-25 11:05:13 -08:00
|
|
|
from vpp_object import VppObjectRegistry
|
Revert "VPP-1508 python3 tests: raw_input"
This reverts commit 72f0004ac5f6e201cbe042593d76df6f2491d743.
Reason for revert: Traceback (most recent call last):
File "/home/ksekera/vpp/test/test_ipsec_ah.py", line 36, in
setUpClass
super(TemplateIpsecAh, cls).setUpClass()
File "/home/ksekera/vpp/test/template_ipsec.py", line 105, in
setUpClass
super(TemplateIpsec, cls).setUpClass()
File "/home/ksekera/vpp/test/framework.py", line 459, in setUpClass
cls.quit()
File "/home/ksekera/vpp/test/framework.py", line 475, in quit
six.input("When done debugging, press ENTER to kill the "
AttributeError: 'module' object has no attribute 'input'
Change-Id: Idf0bbfea231730b37bae5dcb4557a0f82ab1b810
Signed-off-by: Ole Troan <ot@cisco.com>
2018-11-26 10:27:50 +00:00
|
|
|
from util import ppp, is_core_present
|
|
|
|
from scapy.layers.inet import IPerror, TCPerror, UDPerror, ICMPerror
|
|
|
|
from scapy.layers.inet6 import ICMPv6DestUnreach, ICMPv6EchoRequest
|
|
|
|
from scapy.layers.inet6 import ICMPv6EchoReply
|
2022-08-30 13:59:03 -07:00
|
|
|
from vpp_running import use_running
|
2023-08-31 00:47:44 -04:00
|
|
|
from asfframework import VppAsfTestCase
|
2018-12-09 15:37:04 -08:00
|
|
|
|
2021-04-08 19:37:41 +02:00
|
|
|
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
2023-08-31 00:47:44 -04:00
|
|
|
Packet Generator / Scapy Test framework module.
|
2016-10-11 11:47:09 +02:00
|
|
|
|
|
|
|
The module provides a set of tools for constructing and running tests and
|
|
|
|
representing the results.
|
|
|
|
"""
|
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
|
|
|
|
class _PacketInfo(object):
|
2016-10-11 11:47:09 +02:00
|
|
|
"""Private class to create packet info object.
|
|
|
|
|
|
|
|
Help process information about the next packet.
|
|
|
|
Set variables to default values.
|
|
|
|
"""
|
2022-04-26 19:02:15 +02:00
|
|
|
|
2016-11-11 11:38:55 +01:00
|
|
|
#: Store the index of the packet.
|
2016-10-03 19:44:57 +02:00
|
|
|
index = -1
|
2016-11-11 11:38:55 +01:00
|
|
|
#: Store the index of the source packet generator interface of the packet.
|
2016-10-03 19:44:57 +02:00
|
|
|
src = -1
|
2016-11-11 11:38:55 +01:00
|
|
|
#: Store the index of the destination packet generator interface
|
|
|
|
#: of the packet.
|
2016-10-03 19:44:57 +02:00
|
|
|
dst = -1
|
2017-03-02 15:22:47 +01:00
|
|
|
#: Store expected ip version
|
|
|
|
ip = -1
|
|
|
|
#: Store expected upper protocol
|
|
|
|
proto = -1
|
2016-11-11 11:38:55 +01:00
|
|
|
#: Store the copy of the former packet.
|
2016-10-03 19:44:57 +02:00
|
|
|
data = None
|
2016-10-11 11:47:09 +02:00
|
|
|
|
2024-07-23 01:28:19 -04:00
|
|
|
def __repr__(self):
|
|
|
|
return f"_PacketInfo index:{self.index} src:{self.src} dst:{self.dst} ip:{self.ip} proto:{self.proto} data:{self.data}"
|
|
|
|
|
2016-12-07 15:09:13 +01:00
|
|
|
def __eq__(self, other):
|
|
|
|
index = self.index == other.index
|
|
|
|
src = self.src == other.src
|
|
|
|
dst = self.dst == other.dst
|
|
|
|
data = self.data == other.data
|
|
|
|
return index and src and dst and data
|
|
|
|
|
2016-10-11 11:47:09 +02:00
|
|
|
|
2022-08-30 13:59:03 -07:00
|
|
|
@use_running
|
2023-08-31 00:47:44 -04:00
|
|
|
class VppTestCase(VppAsfTestCase):
|
2016-11-11 11:38:55 +01:00
|
|
|
"""This subclass is a base class for VPP test cases that are implemented as
|
|
|
|
classes. It provides methods to create and run test case.
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
|
|
|
|
|
|
|
@property
|
|
|
|
def packet_infos(self):
|
|
|
|
"""List of packet infos"""
|
|
|
|
return self._packet_infos
|
|
|
|
|
2016-12-21 08:50:14 +01:00
|
|
|
@classmethod
|
|
|
|
def get_packet_count_for_if_idx(cls, dst_if_index):
|
|
|
|
"""Get the number of packet info for specified destination if index"""
|
|
|
|
if dst_if_index in cls._packet_count_for_dst_if_idx:
|
|
|
|
return cls._packet_count_for_dst_if_idx[dst_if_index]
|
|
|
|
else:
|
|
|
|
return 0
|
2016-10-11 11:47:09 +02:00
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
@classmethod
|
|
|
|
def setUpClass(cls):
|
2019-01-25 14:05:48 -08:00
|
|
|
super(VppTestCase, cls).setUpClass()
|
2016-12-21 08:50:14 +01:00
|
|
|
cls.reset_packet_infos()
|
2021-04-01 18:19:29 +02:00
|
|
|
cls._pcaps = []
|
|
|
|
cls._old_pcaps = []
|
2016-10-28 13:20:27 +02:00
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
@classmethod
|
|
|
|
def tearDownClass(cls):
|
2022-04-26 19:02:15 +02:00
|
|
|
cls.logger.debug("--- tearDownClass() for %s called ---" % cls.__name__)
|
2018-02-17 13:41:33 +01:00
|
|
|
cls.reset_packet_infos()
|
2023-08-31 00:47:44 -04:00
|
|
|
super(VppTestCase, cls).tearDownClass()
|
2016-10-03 19:44:57 +02:00
|
|
|
|
|
|
|
@classmethod
|
2017-09-20 08:26:30 +02:00
|
|
|
def pg_enable_capture(cls, interfaces=None):
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
|
|
|
Enable capture on packet-generator interfaces
|
|
|
|
|
2017-09-20 08:26:30 +02:00
|
|
|
:param interfaces: iterable interface indexes (if None,
|
|
|
|
use self.pg_interfaces)
|
2016-10-11 11:47:09 +02:00
|
|
|
|
|
|
|
"""
|
2017-09-20 08:26:30 +02:00
|
|
|
if interfaces is None:
|
|
|
|
interfaces = cls.pg_interfaces
|
2016-10-11 11:47:09 +02:00
|
|
|
for i in interfaces:
|
|
|
|
i.enable_capture()
|
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
@classmethod
|
2021-04-01 18:19:29 +02:00
|
|
|
def register_pcap(cls, intf, worker):
|
2022-04-26 19:02:15 +02:00
|
|
|
"""Register a pcap in the testclass"""
|
2016-12-12 08:36:58 +01:00
|
|
|
# add to the list of captures with current timestamp
|
2021-04-01 18:19:29 +02:00
|
|
|
cls._pcaps.append((intf, worker))
|
2016-12-12 08:36:58 +01:00
|
|
|
|
|
|
|
@classmethod
|
2023-12-06 19:21:49 +01:00
|
|
|
def pg_start(cls, trace=True, traceFilter=False):
|
2022-04-26 19:02:15 +02:00
|
|
|
"""Enable the PG, wait till it is done, then clean up"""
|
2023-08-15 19:05:26 -04:00
|
|
|
for intf, worker in cls._old_pcaps:
|
2023-08-31 00:47:44 -04:00
|
|
|
intf.remove_old_pcap_file(intf.get_in_path(worker))
|
2021-04-01 18:19:29 +02:00
|
|
|
cls._old_pcaps = []
|
2021-02-19 16:39:13 +01:00
|
|
|
if trace:
|
|
|
|
cls.vapi.cli("clear trace")
|
2023-12-06 19:21:49 +01:00
|
|
|
cls.vapi.cli("trace add pg-input 1000" + (" filter" if traceFilter else ""))
|
2022-04-26 19:02:15 +02:00
|
|
|
cls.vapi.cli("packet-generator enable")
|
2019-10-13 10:09:50 +00:00
|
|
|
# PG, when starts, runs to completion -
|
|
|
|
# so let's avoid a race condition,
|
|
|
|
# and wait a little till it's done.
|
|
|
|
# Then clean it up - and then be gone.
|
|
|
|
deadline = time.time() + 300
|
2022-04-26 19:02:15 +02:00
|
|
|
while cls.vapi.cli("show packet-generator").find("Yes") != -1:
|
2019-10-13 10:09:50 +00:00
|
|
|
cls.sleep(0.01) # yield
|
|
|
|
if time.time() > deadline:
|
|
|
|
cls.logger.error("Timeout waiting for pg to stop")
|
|
|
|
break
|
2021-04-01 18:19:29 +02:00
|
|
|
for intf, worker in cls._pcaps:
|
2022-04-26 19:02:15 +02:00
|
|
|
cls.vapi.cli("packet-generator delete %s" % intf.get_cap_name(worker))
|
2021-04-01 18:19:29 +02:00
|
|
|
cls._old_pcaps = cls._pcaps
|
|
|
|
cls._pcaps = []
|
2016-10-03 19:44:57 +02:00
|
|
|
|
|
|
|
@classmethod
|
2022-04-26 19:02:15 +02:00
|
|
|
def create_pg_interfaces_internal(cls, interfaces, gso=0, gso_size=0, mode=None):
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
2016-12-22 11:06:56 +01:00
|
|
|
Create packet-generator interfaces.
|
2016-10-11 11:47:09 +02:00
|
|
|
|
2016-12-22 11:06:56 +01:00
|
|
|
:param interfaces: iterable indexes of the interfaces.
|
|
|
|
:returns: List of created interfaces.
|
2016-10-11 11:47:09 +02:00
|
|
|
|
|
|
|
"""
|
|
|
|
result = []
|
|
|
|
for i in interfaces:
|
2021-06-03 14:43:21 +00:00
|
|
|
intf = VppPGInterface(cls, i, gso, gso_size, mode)
|
2016-10-11 11:47:09 +02:00
|
|
|
setattr(cls, intf.name, intf)
|
|
|
|
result.append(intf)
|
|
|
|
cls.pg_interfaces = result
|
|
|
|
return result
|
|
|
|
|
2021-06-03 14:43:21 +00:00
|
|
|
@classmethod
|
|
|
|
def create_pg_ip4_interfaces(cls, interfaces, gso=0, gso_size=0):
|
2022-09-20 21:52:18 -04:00
|
|
|
if not hasattr(cls, "vpp"):
|
|
|
|
cls.pg_interfaces = []
|
|
|
|
return cls.pg_interfaces
|
2021-06-03 14:43:21 +00:00
|
|
|
pgmode = VppEnum.vl_api_pg_interface_mode_t
|
2022-04-26 19:02:15 +02:00
|
|
|
return cls.create_pg_interfaces_internal(
|
|
|
|
interfaces, gso, gso_size, pgmode.PG_API_MODE_IP4
|
|
|
|
)
|
2021-06-03 14:43:21 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create_pg_ip6_interfaces(cls, interfaces, gso=0, gso_size=0):
|
2022-09-20 21:52:18 -04:00
|
|
|
if not hasattr(cls, "vpp"):
|
|
|
|
cls.pg_interfaces = []
|
|
|
|
return cls.pg_interfaces
|
2021-06-03 14:43:21 +00:00
|
|
|
pgmode = VppEnum.vl_api_pg_interface_mode_t
|
2022-04-26 19:02:15 +02:00
|
|
|
return cls.create_pg_interfaces_internal(
|
|
|
|
interfaces, gso, gso_size, pgmode.PG_API_MODE_IP6
|
|
|
|
)
|
2021-06-03 14:43:21 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create_pg_interfaces(cls, interfaces, gso=0, gso_size=0):
|
2022-09-20 21:52:18 -04:00
|
|
|
if not hasattr(cls, "vpp"):
|
|
|
|
cls.pg_interfaces = []
|
|
|
|
return cls.pg_interfaces
|
2021-06-03 14:43:21 +00:00
|
|
|
pgmode = VppEnum.vl_api_pg_interface_mode_t
|
2022-04-26 19:02:15 +02:00
|
|
|
return cls.create_pg_interfaces_internal(
|
|
|
|
interfaces, gso, gso_size, pgmode.PG_API_MODE_ETHERNET
|
|
|
|
)
|
2021-06-03 14:43:21 +00:00
|
|
|
|
|
|
|
@classmethod
|
|
|
|
def create_pg_ethernet_interfaces(cls, interfaces, gso=0, gso_size=0):
|
2022-09-20 21:52:18 -04:00
|
|
|
if not hasattr(cls, "vpp"):
|
|
|
|
cls.pg_interfaces = []
|
|
|
|
return cls.pg_interfaces
|
2021-06-03 14:43:21 +00:00
|
|
|
pgmode = VppEnum.vl_api_pg_interface_mode_t
|
2022-04-26 19:02:15 +02:00
|
|
|
return cls.create_pg_interfaces_internal(
|
|
|
|
interfaces, gso, gso_size, pgmode.PG_API_MODE_ETHERNET
|
|
|
|
)
|
2021-06-03 14:43:21 +00:00
|
|
|
|
2016-11-04 11:11:44 +01:00
|
|
|
@classmethod
|
2018-06-24 22:49:33 +02:00
|
|
|
def create_loopback_interfaces(cls, count):
|
2016-11-04 11:11:44 +01:00
|
|
|
"""
|
2016-12-22 11:06:56 +01:00
|
|
|
Create loopback interfaces.
|
2016-11-04 11:11:44 +01:00
|
|
|
|
2018-06-24 22:49:33 +02:00
|
|
|
:param count: number of interfaces created.
|
2016-12-22 11:06:56 +01:00
|
|
|
:returns: List of created interfaces.
|
2016-11-04 11:11:44 +01:00
|
|
|
"""
|
2022-09-20 21:52:18 -04:00
|
|
|
if not hasattr(cls, "vpp"):
|
|
|
|
cls.lo_interfaces = []
|
|
|
|
return cls.lo_interfaces
|
2018-06-24 22:49:33 +02:00
|
|
|
result = [VppLoInterface(cls) for i in range(count)]
|
|
|
|
for intf in result:
|
2016-11-04 11:11:44 +01:00
|
|
|
setattr(cls, intf.name, intf)
|
|
|
|
cls.lo_interfaces = result
|
|
|
|
return result
|
|
|
|
|
2019-03-15 02:16:20 -07:00
|
|
|
@classmethod
|
|
|
|
def create_bvi_interfaces(cls, count):
|
|
|
|
"""
|
|
|
|
Create BVI interfaces.
|
|
|
|
|
|
|
|
:param count: number of interfaces created.
|
|
|
|
:returns: List of created interfaces.
|
|
|
|
"""
|
2022-09-20 21:52:18 -04:00
|
|
|
if not hasattr(cls, "vpp"):
|
|
|
|
cls.bvi_interfaces = []
|
|
|
|
return cls.bvi_interfaces
|
2019-03-15 02:16:20 -07:00
|
|
|
result = [VppBviInterface(cls) for i in range(count)]
|
|
|
|
for intf in result:
|
|
|
|
setattr(cls, intf.name, intf)
|
|
|
|
cls.bvi_interfaces = result
|
|
|
|
return result
|
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
@staticmethod
|
2022-04-26 19:02:15 +02:00
|
|
|
def extend_packet(packet, size, padding=" "):
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
2017-09-20 08:26:30 +02:00
|
|
|
Extend packet to given size by padding with spaces or custom padding
|
2016-10-11 11:47:09 +02:00
|
|
|
NOTE: Currently works only when Raw layer is present.
|
|
|
|
|
|
|
|
:param packet: packet
|
|
|
|
:param size: target size
|
2017-09-20 08:26:30 +02:00
|
|
|
:param padding: padding used to extend the payload
|
2016-10-11 11:47:09 +02:00
|
|
|
|
|
|
|
"""
|
2016-10-03 19:44:57 +02:00
|
|
|
packet_len = len(packet) + 4
|
|
|
|
extend = size - packet_len
|
|
|
|
if extend > 0:
|
2019-05-07 10:39:57 +02:00
|
|
|
num = (extend // len(padding)) + 1
|
|
|
|
packet[Raw].load += (padding * num)[:extend].encode("ascii")
|
2016-10-11 11:47:09 +02:00
|
|
|
|
2016-12-21 08:50:14 +01:00
|
|
|
@classmethod
|
|
|
|
def reset_packet_infos(cls):
|
2022-04-26 19:02:15 +02:00
|
|
|
"""Reset the list of packet info objects and packet counts to zero"""
|
2016-12-21 08:50:14 +01:00
|
|
|
cls._packet_infos = {}
|
|
|
|
cls._packet_count_for_dst_if_idx = {}
|
2016-10-11 11:47:09 +02:00
|
|
|
|
2016-12-21 08:50:14 +01:00
|
|
|
@classmethod
|
|
|
|
def create_packet_info(cls, src_if, dst_if):
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
|
|
|
Create packet info object containing the source and destination indexes
|
|
|
|
and add it to the testcase's packet info list
|
|
|
|
|
2016-12-21 08:50:14 +01:00
|
|
|
:param VppInterface src_if: source interface
|
|
|
|
:param VppInterface dst_if: destination interface
|
2016-10-11 11:47:09 +02:00
|
|
|
|
|
|
|
:returns: _PacketInfo object
|
|
|
|
|
|
|
|
"""
|
2016-10-03 19:44:57 +02:00
|
|
|
info = _PacketInfo()
|
2016-12-21 08:50:14 +01:00
|
|
|
info.index = len(cls._packet_infos)
|
|
|
|
info.src = src_if.sw_if_index
|
|
|
|
info.dst = dst_if.sw_if_index
|
|
|
|
if isinstance(dst_if, VppSubInterface):
|
|
|
|
dst_idx = dst_if.parent.sw_if_index
|
|
|
|
else:
|
|
|
|
dst_idx = dst_if.sw_if_index
|
|
|
|
if dst_idx in cls._packet_count_for_dst_if_idx:
|
|
|
|
cls._packet_count_for_dst_if_idx[dst_idx] += 1
|
|
|
|
else:
|
|
|
|
cls._packet_count_for_dst_if_idx[dst_idx] = 1
|
|
|
|
cls._packet_infos[info.index] = info
|
2016-10-03 19:44:57 +02:00
|
|
|
return info
|
2016-10-11 11:47:09 +02:00
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
@staticmethod
|
|
|
|
def info_to_payload(info):
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
|
|
|
Convert _PacketInfo object to packet payload
|
|
|
|
|
|
|
|
:param info: _PacketInfo object
|
|
|
|
|
|
|
|
:returns: string containing serialized data from packet info
|
|
|
|
"""
|
2021-09-22 11:24:06 +01:00
|
|
|
|
|
|
|
# retrieve payload, currently 18 bytes (4 x ints + 1 short)
|
2022-04-26 19:02:15 +02:00
|
|
|
return pack("iiiih", info.index, info.src, info.dst, info.ip, info.proto)
|
2016-10-03 19:44:57 +02:00
|
|
|
|
|
|
|
@staticmethod
|
2022-04-26 19:02:15 +02:00
|
|
|
def payload_to_info(payload, payload_field="load"):
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
|
|
|
Convert packet payload to _PacketInfo object
|
|
|
|
|
|
|
|
:param payload: packet payload
|
2019-03-12 20:04:56 -07:00
|
|
|
:type payload: <class 'scapy.packet.Raw'>
|
|
|
|
:param payload_field: packet fieldname of payload "load" for
|
2019-03-06 11:58:06 -08:00
|
|
|
<class 'scapy.packet.Raw'>
|
2019-03-12 20:04:56 -07:00
|
|
|
:type payload_field: str
|
2016-10-11 11:47:09 +02:00
|
|
|
:returns: _PacketInfo object containing de-serialized data from payload
|
|
|
|
|
|
|
|
"""
|
2021-09-22 11:24:06 +01:00
|
|
|
|
|
|
|
# retrieve payload, currently 18 bytes (4 x ints + 1 short)
|
|
|
|
payload_b = getattr(payload, payload_field)[:18]
|
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
info = _PacketInfo()
|
2022-04-26 19:02:15 +02:00
|
|
|
info.index, info.src, info.dst, info.ip, info.proto = unpack("iiiih", payload_b)
|
2021-09-22 11:24:06 +01:00
|
|
|
|
|
|
|
# some SRv6 TCs depend on get an exception if bad values are detected
|
|
|
|
if info.index > 0x4000:
|
2022-04-26 19:02:15 +02:00
|
|
|
raise ValueError("Index value is invalid")
|
2021-09-22 11:24:06 +01:00
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
return info
|
2016-10-11 11:47:09 +02:00
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
def get_next_packet_info(self, info):
|
2016-10-11 11:47:09 +02:00
|
|
|
"""
|
|
|
|
Iterate over the packet info list stored in the testcase
|
|
|
|
Start iteration with first element if info is None
|
|
|
|
Continue based on index in info if info is specified
|
|
|
|
|
|
|
|
:param info: info or None
|
|
|
|
:returns: next info in list or None if no more infos
|
|
|
|
"""
|
2016-10-03 19:44:57 +02:00
|
|
|
if info is None:
|
|
|
|
next_index = 0
|
|
|
|
else:
|
|
|
|
next_index = info.index + 1
|
2016-12-21 08:50:14 +01:00
|
|
|
if next_index == len(self._packet_infos):
|
2016-10-03 19:44:57 +02:00
|
|
|
return None
|
|
|
|
else:
|
2016-12-21 08:50:14 +01:00
|
|
|
return self._packet_infos[next_index]
|
2016-10-11 11:47:09 +02:00
|
|
|
|
|
|
|
def get_next_packet_info_for_interface(self, src_index, info):
|
|
|
|
"""
|
|
|
|
Search the packet info list for the next packet info with same source
|
|
|
|
interface index
|
|
|
|
|
|
|
|
:param src_index: source interface index to search for
|
|
|
|
:param info: packet info - where to start the search
|
|
|
|
:returns: packet info or None
|
|
|
|
|
|
|
|
"""
|
2016-10-03 19:44:57 +02:00
|
|
|
while True:
|
|
|
|
info = self.get_next_packet_info(info)
|
|
|
|
if info is None:
|
|
|
|
return None
|
2016-10-11 11:47:09 +02:00
|
|
|
if info.src == src_index:
|
2016-10-03 19:44:57 +02:00
|
|
|
return info
|
2016-10-11 11:47:09 +02:00
|
|
|
|
|
|
|
def get_next_packet_info_for_interface2(self, src_index, dst_index, info):
|
|
|
|
"""
|
|
|
|
Search the packet info list for the next packet info with same source
|
|
|
|
and destination interface indexes
|
|
|
|
|
|
|
|
:param src_index: source interface index to search for
|
|
|
|
:param dst_index: destination interface index to search for
|
|
|
|
:param info: packet info - where to start the search
|
|
|
|
:returns: packet info or None
|
|
|
|
|
|
|
|
"""
|
2016-10-03 19:44:57 +02:00
|
|
|
while True:
|
2016-10-11 11:47:09 +02:00
|
|
|
info = self.get_next_packet_info_for_interface(src_index, info)
|
2016-10-03 19:44:57 +02:00
|
|
|
if info is None:
|
|
|
|
return None
|
2016-10-11 11:47:09 +02:00
|
|
|
if info.dst == dst_index:
|
2016-10-03 19:44:57 +02:00
|
|
|
return info
|
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
def assert_packet_checksums_valid(self, packet, ignore_zero_udp_checksums=True):
|
2019-03-10 10:04:23 -07:00
|
|
|
received = packet.__class__(scapy.compat.raw(packet))
|
2022-04-26 19:02:15 +02:00
|
|
|
udp_layers = ["UDP", "UDPerror"]
|
|
|
|
checksum_fields = ["cksum", "chksum"]
|
2018-05-16 10:52:54 +02:00
|
|
|
checksums = []
|
|
|
|
counter = 0
|
2019-03-10 10:04:23 -07:00
|
|
|
temp = received.__class__(scapy.compat.raw(received))
|
2018-05-16 10:52:54 +02:00
|
|
|
while True:
|
|
|
|
layer = temp.getlayer(counter)
|
|
|
|
if layer:
|
2019-12-05 13:13:21 +00:00
|
|
|
layer = layer.copy()
|
|
|
|
layer.remove_payload()
|
2018-05-16 10:52:54 +02:00
|
|
|
for cf in checksum_fields:
|
|
|
|
if hasattr(layer, cf):
|
2022-04-26 19:02:15 +02:00
|
|
|
if (
|
|
|
|
ignore_zero_udp_checksums
|
|
|
|
and 0 == getattr(layer, cf)
|
|
|
|
and layer.name in udp_layers
|
|
|
|
):
|
2018-05-16 10:52:54 +02:00
|
|
|
continue
|
2019-12-05 13:13:21 +00:00
|
|
|
delattr(temp.getlayer(counter), cf)
|
2018-05-16 10:52:54 +02:00
|
|
|
checksums.append((counter, cf))
|
|
|
|
else:
|
|
|
|
break
|
|
|
|
counter = counter + 1
|
2018-06-24 22:49:55 +02:00
|
|
|
if 0 == len(checksums):
|
|
|
|
return
|
2019-03-10 10:04:23 -07:00
|
|
|
temp = temp.__class__(scapy.compat.raw(temp))
|
2022-11-14 11:26:18 +01:00
|
|
|
for layer, cf in reversed(checksums):
|
2018-06-24 22:49:55 +02:00
|
|
|
calc_sum = getattr(temp[layer], cf)
|
|
|
|
self.assert_equal(
|
2022-04-26 19:02:15 +02:00
|
|
|
getattr(received[layer], cf),
|
|
|
|
calc_sum,
|
|
|
|
"packet checksum on layer #%d: %s" % (layer, temp[layer].name),
|
|
|
|
)
|
2018-06-24 22:49:55 +02:00
|
|
|
self.logger.debug(
|
2022-04-26 19:02:15 +02:00
|
|
|
"Checksum field `%s` on `%s` layer has correct value `%s`"
|
|
|
|
% (cf, temp[layer].name, calc_sum)
|
|
|
|
)
|
|
|
|
|
|
|
|
def assert_checksum_valid(
|
2022-11-14 11:26:18 +01:00
|
|
|
self,
|
|
|
|
received_packet,
|
|
|
|
layer,
|
|
|
|
checksum_field_names=["chksum", "cksum"],
|
|
|
|
ignore_zero_checksum=False,
|
2022-04-26 19:02:15 +02:00
|
|
|
):
|
|
|
|
"""Check checksum of received packet on given layer"""
|
2022-11-14 11:26:18 +01:00
|
|
|
layer_copy = received_packet[layer].copy()
|
|
|
|
layer_copy.remove_payload()
|
|
|
|
field_name = None
|
|
|
|
for f in checksum_field_names:
|
|
|
|
if hasattr(layer_copy, f):
|
|
|
|
field_name = f
|
|
|
|
break
|
|
|
|
if field_name is None:
|
|
|
|
raise Exception(
|
|
|
|
f"Layer `{layer}` has none of checksum fields: `{checksum_field_names}`."
|
|
|
|
)
|
2018-05-16 10:52:54 +02:00
|
|
|
received_packet_checksum = getattr(received_packet[layer], field_name)
|
|
|
|
if ignore_zero_checksum and 0 == received_packet_checksum:
|
|
|
|
return
|
2022-04-26 19:02:15 +02:00
|
|
|
recalculated = received_packet.__class__(scapy.compat.raw(received_packet))
|
2018-05-16 10:52:54 +02:00
|
|
|
delattr(recalculated[layer], field_name)
|
2019-03-10 10:04:23 -07:00
|
|
|
recalculated = recalculated.__class__(scapy.compat.raw(recalculated))
|
2022-04-26 19:02:15 +02:00
|
|
|
self.assert_equal(
|
|
|
|
received_packet_checksum,
|
|
|
|
getattr(recalculated[layer], field_name),
|
2022-11-14 11:26:18 +01:00
|
|
|
f"packet checksum (field: {field_name}) on layer: %s" % layer,
|
2022-04-26 19:02:15 +02:00
|
|
|
)
|
|
|
|
|
|
|
|
def assert_ip_checksum_valid(self, received_packet, ignore_zero_checksum=False):
|
|
|
|
self.assert_checksum_valid(
|
|
|
|
received_packet, "IP", ignore_zero_checksum=ignore_zero_checksum
|
|
|
|
)
|
|
|
|
|
|
|
|
def assert_tcp_checksum_valid(self, received_packet, ignore_zero_checksum=False):
|
|
|
|
self.assert_checksum_valid(
|
|
|
|
received_packet, "TCP", ignore_zero_checksum=ignore_zero_checksum
|
|
|
|
)
|
|
|
|
|
|
|
|
def assert_udp_checksum_valid(self, received_packet, ignore_zero_checksum=True):
|
|
|
|
self.assert_checksum_valid(
|
|
|
|
received_packet, "UDP", ignore_zero_checksum=ignore_zero_checksum
|
|
|
|
)
|
2018-05-16 10:52:54 +02:00
|
|
|
|
|
|
|
def assert_embedded_icmp_checksum_valid(self, received_packet):
|
|
|
|
if received_packet.haslayer(IPerror):
|
2022-04-26 19:02:15 +02:00
|
|
|
self.assert_checksum_valid(received_packet, "IPerror")
|
2018-05-16 10:52:54 +02:00
|
|
|
if received_packet.haslayer(TCPerror):
|
2022-04-26 19:02:15 +02:00
|
|
|
self.assert_checksum_valid(received_packet, "TCPerror")
|
2018-05-16 10:52:54 +02:00
|
|
|
if received_packet.haslayer(UDPerror):
|
2022-04-26 19:02:15 +02:00
|
|
|
self.assert_checksum_valid(
|
|
|
|
received_packet, "UDPerror", ignore_zero_checksum=True
|
|
|
|
)
|
2018-05-16 10:52:54 +02:00
|
|
|
if received_packet.haslayer(ICMPerror):
|
2022-04-26 19:02:15 +02:00
|
|
|
self.assert_checksum_valid(received_packet, "ICMPerror")
|
2018-05-16 10:52:54 +02:00
|
|
|
|
|
|
|
def assert_icmp_checksum_valid(self, received_packet):
|
2022-04-26 19:02:15 +02:00
|
|
|
self.assert_checksum_valid(received_packet, "ICMP")
|
2018-05-16 10:52:54 +02:00
|
|
|
self.assert_embedded_icmp_checksum_valid(received_packet)
|
|
|
|
|
|
|
|
def assert_icmpv6_checksum_valid(self, pkt):
|
|
|
|
if pkt.haslayer(ICMPv6DestUnreach):
|
2022-11-14 11:26:18 +01:00
|
|
|
self.assert_checksum_valid(pkt, "ICMPv6DestUnreach")
|
2018-05-16 10:52:54 +02:00
|
|
|
self.assert_embedded_icmp_checksum_valid(pkt)
|
|
|
|
if pkt.haslayer(ICMPv6EchoRequest):
|
2022-11-14 11:26:18 +01:00
|
|
|
self.assert_checksum_valid(pkt, "ICMPv6EchoRequest")
|
2018-05-16 10:52:54 +02:00
|
|
|
if pkt.haslayer(ICMPv6EchoReply):
|
2022-11-14 11:26:18 +01:00
|
|
|
self.assert_checksum_valid(pkt, "ICMPv6EchoReply")
|
2018-05-16 10:52:54 +02:00
|
|
|
|
2018-11-08 11:24:34 +01:00
|
|
|
def assert_packet_counter_equal(self, counter, expected_value):
|
2022-02-18 10:32:08 +00:00
|
|
|
counter_value = self.get_counter(counter)
|
2022-04-26 19:02:15 +02:00
|
|
|
self.assert_equal(
|
|
|
|
counter_value, expected_value, "packet counter `%s'" % counter
|
|
|
|
)
|
2018-11-08 11:24:34 +01:00
|
|
|
|
2021-02-19 16:39:13 +01:00
|
|
|
def pg_send(self, intf, pkts, worker=None, trace=True):
|
2019-12-23 04:10:25 +00:00
|
|
|
intf.add_stream(pkts, worker=worker)
|
2018-01-08 04:41:42 -08:00
|
|
|
self.pg_enable_capture(self.pg_interfaces)
|
2021-02-19 16:39:13 +01:00
|
|
|
self.pg_start(trace=trace)
|
2019-02-20 09:01:14 -08:00
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
def send_and_assert_no_replies(
|
|
|
|
self, intf, pkts, remark="", timeout=None, stats_diff=None, trace=True, msg=None
|
|
|
|
):
|
tests: add enhanced packet counter verification
Add support for inline packet counter verification to send_and_* functions.
Diff dictionary is a dictionary of dictionaries of interesting stats:
diff_dictionary =
{
"err" : { '/error/counter1' : 4, },
sw_if_index1 : { '/stat/segment/counter1' : 5,
'/stat/segment/counter2' : 6,
},
sw_if_index2 : { '/stat/segment/counter1' : 7,
},
}
It describes a per sw-if-index diffset, where each key is stat segment
path and value is the expected change for that counter for sw-if-index.
Special case string "err" is used for error counters.
This then allows more precise packet counter verification by first
defining a "zero" dictionary, e.g. for ED NAT:
cls.no_diff = StatsDiff({
pg.sw_if_index: {
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
}
for pg in cls.pg_interfaces
})
and then to specify only changed counters directly when calling
one of send_and_* functions:
self.send_and_assert_no_replies(
self.pg0, pkts, msg="i2o pkts",
stats_diff=self.no_diff | {
"err": {
'/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
},
self.pg0.sw_if_index: {
'/nat44-ed/in2out/slowpath/drops': len(pkts),
},
}
)
operator | is overloaded by StatsDiff class to perform a deep merge operation,
so in above case, dictionaries for "err" and self.pg0.sw_if_index do not
overwrite whole sub-dictionaries, rather the contents are merged,
assuring that all the remaining counters are verified to be zero.
Type: improvement
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9
2022-02-18 10:34:35 +00:00
|
|
|
if stats_diff:
|
|
|
|
stats_snapshot = self.snapshot_stats(stats_diff)
|
|
|
|
|
2019-02-20 09:01:14 -08:00
|
|
|
self.pg_send(intf, pkts)
|
tests: add enhanced packet counter verification
Add support for inline packet counter verification to send_and_* functions.
Diff dictionary is a dictionary of dictionaries of interesting stats:
diff_dictionary =
{
"err" : { '/error/counter1' : 4, },
sw_if_index1 : { '/stat/segment/counter1' : 5,
'/stat/segment/counter2' : 6,
},
sw_if_index2 : { '/stat/segment/counter1' : 7,
},
}
It describes a per sw-if-index diffset, where each key is stat segment
path and value is the expected change for that counter for sw-if-index.
Special case string "err" is used for error counters.
This then allows more precise packet counter verification by first
defining a "zero" dictionary, e.g. for ED NAT:
cls.no_diff = StatsDiff({
pg.sw_if_index: {
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
}
for pg in cls.pg_interfaces
})
and then to specify only changed counters directly when calling
one of send_and_* functions:
self.send_and_assert_no_replies(
self.pg0, pkts, msg="i2o pkts",
stats_diff=self.no_diff | {
"err": {
'/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
},
self.pg0.sw_if_index: {
'/nat44-ed/in2out/slowpath/drops': len(pkts),
},
}
)
operator | is overloaded by StatsDiff class to perform a deep merge operation,
so in above case, dictionaries for "err" and self.pg0.sw_if_index do not
overwrite whole sub-dictionaries, rather the contents are merged,
assuring that all the remaining counters are verified to be zero.
Type: improvement
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9
2022-02-18 10:34:35 +00:00
|
|
|
|
|
|
|
try:
|
|
|
|
if not timeout:
|
|
|
|
timeout = 1
|
|
|
|
for i in self.pg_interfaces:
|
2022-02-18 10:35:08 +00:00
|
|
|
i.assert_nothing_captured(timeout=timeout, remark=remark)
|
tests: add enhanced packet counter verification
Add support for inline packet counter verification to send_and_* functions.
Diff dictionary is a dictionary of dictionaries of interesting stats:
diff_dictionary =
{
"err" : { '/error/counter1' : 4, },
sw_if_index1 : { '/stat/segment/counter1' : 5,
'/stat/segment/counter2' : 6,
},
sw_if_index2 : { '/stat/segment/counter1' : 7,
},
}
It describes a per sw-if-index diffset, where each key is stat segment
path and value is the expected change for that counter for sw-if-index.
Special case string "err" is used for error counters.
This then allows more precise packet counter verification by first
defining a "zero" dictionary, e.g. for ED NAT:
cls.no_diff = StatsDiff({
pg.sw_if_index: {
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
}
for pg in cls.pg_interfaces
})
and then to specify only changed counters directly when calling
one of send_and_* functions:
self.send_and_assert_no_replies(
self.pg0, pkts, msg="i2o pkts",
stats_diff=self.no_diff | {
"err": {
'/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
},
self.pg0.sw_if_index: {
'/nat44-ed/in2out/slowpath/drops': len(pkts),
},
}
)
operator | is overloaded by StatsDiff class to perform a deep merge operation,
so in above case, dictionaries for "err" and self.pg0.sw_if_index do not
overwrite whole sub-dictionaries, rather the contents are merged,
assuring that all the remaining counters are verified to be zero.
Type: improvement
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9
2022-02-18 10:34:35 +00:00
|
|
|
timeout = 0.1
|
|
|
|
finally:
|
|
|
|
if trace:
|
|
|
|
if msg:
|
|
|
|
self.logger.debug(f"send_and_assert_no_replies: {msg}")
|
|
|
|
self.logger.debug(self.vapi.cli("show trace"))
|
|
|
|
|
|
|
|
if stats_diff:
|
|
|
|
self.compare_stats_with_snapshot(stats_diff, stats_snapshot)
|
2018-01-08 04:41:42 -08:00
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
def send_and_expect(
|
|
|
|
self,
|
|
|
|
intf,
|
|
|
|
pkts,
|
|
|
|
output,
|
|
|
|
n_rx=None,
|
|
|
|
worker=None,
|
|
|
|
trace=True,
|
|
|
|
msg=None,
|
|
|
|
stats_diff=None,
|
2024-09-27 17:11:18 +03:00
|
|
|
filter_out_fn=is_ipv6_misc,
|
2022-04-26 19:02:15 +02:00
|
|
|
):
|
tests: add enhanced packet counter verification
Add support for inline packet counter verification to send_and_* functions.
Diff dictionary is a dictionary of dictionaries of interesting stats:
diff_dictionary =
{
"err" : { '/error/counter1' : 4, },
sw_if_index1 : { '/stat/segment/counter1' : 5,
'/stat/segment/counter2' : 6,
},
sw_if_index2 : { '/stat/segment/counter1' : 7,
},
}
It describes a per sw-if-index diffset, where each key is stat segment
path and value is the expected change for that counter for sw-if-index.
Special case string "err" is used for error counters.
This then allows more precise packet counter verification by first
defining a "zero" dictionary, e.g. for ED NAT:
cls.no_diff = StatsDiff({
pg.sw_if_index: {
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
}
for pg in cls.pg_interfaces
})
and then to specify only changed counters directly when calling
one of send_and_* functions:
self.send_and_assert_no_replies(
self.pg0, pkts, msg="i2o pkts",
stats_diff=self.no_diff | {
"err": {
'/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
},
self.pg0.sw_if_index: {
'/nat44-ed/in2out/slowpath/drops': len(pkts),
},
}
)
operator | is overloaded by StatsDiff class to perform a deep merge operation,
so in above case, dictionaries for "err" and self.pg0.sw_if_index do not
overwrite whole sub-dictionaries, rather the contents are merged,
assuring that all the remaining counters are verified to be zero.
Type: improvement
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9
2022-02-18 10:34:35 +00:00
|
|
|
if stats_diff:
|
|
|
|
stats_snapshot = self.snapshot_stats(stats_diff)
|
|
|
|
|
2019-03-28 08:56:10 +00:00
|
|
|
if not n_rx:
|
2022-01-10 21:57:27 +00:00
|
|
|
n_rx = 1 if isinstance(pkts, Packet) else len(pkts)
|
2021-02-19 16:39:13 +01:00
|
|
|
self.pg_send(intf, pkts, worker=worker, trace=trace)
|
2024-09-27 17:11:18 +03:00
|
|
|
rx = output.get_capture(n_rx, filter_out_fn=filter_out_fn)
|
2021-05-26 13:02:35 +02:00
|
|
|
if trace:
|
tests: add enhanced packet counter verification
Add support for inline packet counter verification to send_and_* functions.
Diff dictionary is a dictionary of dictionaries of interesting stats:
diff_dictionary =
{
"err" : { '/error/counter1' : 4, },
sw_if_index1 : { '/stat/segment/counter1' : 5,
'/stat/segment/counter2' : 6,
},
sw_if_index2 : { '/stat/segment/counter1' : 7,
},
}
It describes a per sw-if-index diffset, where each key is stat segment
path and value is the expected change for that counter for sw-if-index.
Special case string "err" is used for error counters.
This then allows more precise packet counter verification by first
defining a "zero" dictionary, e.g. for ED NAT:
cls.no_diff = StatsDiff({
pg.sw_if_index: {
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
}
for pg in cls.pg_interfaces
})
and then to specify only changed counters directly when calling
one of send_and_* functions:
self.send_and_assert_no_replies(
self.pg0, pkts, msg="i2o pkts",
stats_diff=self.no_diff | {
"err": {
'/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
},
self.pg0.sw_if_index: {
'/nat44-ed/in2out/slowpath/drops': len(pkts),
},
}
)
operator | is overloaded by StatsDiff class to perform a deep merge operation,
so in above case, dictionaries for "err" and self.pg0.sw_if_index do not
overwrite whole sub-dictionaries, rather the contents are merged,
assuring that all the remaining counters are verified to be zero.
Type: improvement
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9
2022-02-18 10:34:35 +00:00
|
|
|
if msg:
|
|
|
|
self.logger.debug(f"send_and_expect: {msg}")
|
2021-05-26 13:02:35 +02:00
|
|
|
self.logger.debug(self.vapi.cli("show trace"))
|
tests: add enhanced packet counter verification
Add support for inline packet counter verification to send_and_* functions.
Diff dictionary is a dictionary of dictionaries of interesting stats:
diff_dictionary =
{
"err" : { '/error/counter1' : 4, },
sw_if_index1 : { '/stat/segment/counter1' : 5,
'/stat/segment/counter2' : 6,
},
sw_if_index2 : { '/stat/segment/counter1' : 7,
},
}
It describes a per sw-if-index diffset, where each key is stat segment
path and value is the expected change for that counter for sw-if-index.
Special case string "err" is used for error counters.
This then allows more precise packet counter verification by first
defining a "zero" dictionary, e.g. for ED NAT:
cls.no_diff = StatsDiff({
pg.sw_if_index: {
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
}
for pg in cls.pg_interfaces
})
and then to specify only changed counters directly when calling
one of send_and_* functions:
self.send_and_assert_no_replies(
self.pg0, pkts, msg="i2o pkts",
stats_diff=self.no_diff | {
"err": {
'/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
},
self.pg0.sw_if_index: {
'/nat44-ed/in2out/slowpath/drops': len(pkts),
},
}
)
operator | is overloaded by StatsDiff class to perform a deep merge operation,
so in above case, dictionaries for "err" and self.pg0.sw_if_index do not
overwrite whole sub-dictionaries, rather the contents are merged,
assuring that all the remaining counters are verified to be zero.
Type: improvement
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9
2022-02-18 10:34:35 +00:00
|
|
|
|
|
|
|
if stats_diff:
|
|
|
|
self.compare_stats_with_snapshot(stats_diff, stats_snapshot)
|
|
|
|
|
2018-10-10 07:22:51 -07:00
|
|
|
return rx
|
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
def send_and_expect_load_balancing(
|
|
|
|
self, input, pkts, outputs, worker=None, trace=True
|
|
|
|
):
|
2022-02-17 09:22:16 +00:00
|
|
|
self.pg_send(input, pkts, worker=worker, trace=trace)
|
|
|
|
rxs = []
|
|
|
|
for oo in outputs:
|
|
|
|
rx = oo._get_capture(1)
|
2023-08-31 00:47:44 -04:00
|
|
|
self.assertNotEqual(0, len(rx), f"0 != len(rx) ({len(rx)})")
|
2022-02-17 09:22:16 +00:00
|
|
|
rxs.append(rx)
|
|
|
|
if trace:
|
|
|
|
self.logger.debug(self.vapi.cli("show trace"))
|
|
|
|
return rxs
|
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
def send_and_expect_some(self, intf, pkts, output, worker=None, trace=True):
|
2022-02-17 09:08:47 +00:00
|
|
|
self.pg_send(intf, pkts, worker=worker, trace=trace)
|
|
|
|
rx = output._get_capture(1)
|
|
|
|
if trace:
|
|
|
|
self.logger.debug(self.vapi.cli("show trace"))
|
|
|
|
self.assertTrue(len(rx) > 0)
|
2023-08-31 00:47:44 -04:00
|
|
|
self.assertTrue(
|
|
|
|
len(rx) <= len(pkts), f"len(rx) ({len(rx)}) > len(pkts) ({len(pkts)})"
|
|
|
|
)
|
2022-02-17 09:08:47 +00:00
|
|
|
return rx
|
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
def send_and_expect_only(self, intf, pkts, output, timeout=None, stats_diff=None):
|
tests: add enhanced packet counter verification
Add support for inline packet counter verification to send_and_* functions.
Diff dictionary is a dictionary of dictionaries of interesting stats:
diff_dictionary =
{
"err" : { '/error/counter1' : 4, },
sw_if_index1 : { '/stat/segment/counter1' : 5,
'/stat/segment/counter2' : 6,
},
sw_if_index2 : { '/stat/segment/counter1' : 7,
},
}
It describes a per sw-if-index diffset, where each key is stat segment
path and value is the expected change for that counter for sw-if-index.
Special case string "err" is used for error counters.
This then allows more precise packet counter verification by first
defining a "zero" dictionary, e.g. for ED NAT:
cls.no_diff = StatsDiff({
pg.sw_if_index: {
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
}
for pg in cls.pg_interfaces
})
and then to specify only changed counters directly when calling
one of send_and_* functions:
self.send_and_assert_no_replies(
self.pg0, pkts, msg="i2o pkts",
stats_diff=self.no_diff | {
"err": {
'/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
},
self.pg0.sw_if_index: {
'/nat44-ed/in2out/slowpath/drops': len(pkts),
},
}
)
operator | is overloaded by StatsDiff class to perform a deep merge operation,
so in above case, dictionaries for "err" and self.pg0.sw_if_index do not
overwrite whole sub-dictionaries, rather the contents are merged,
assuring that all the remaining counters are verified to be zero.
Type: improvement
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9
2022-02-18 10:34:35 +00:00
|
|
|
if stats_diff:
|
|
|
|
stats_snapshot = self.snapshot_stats(stats_diff)
|
|
|
|
|
2019-02-20 09:01:14 -08:00
|
|
|
self.pg_send(intf, pkts)
|
2019-01-07 16:29:26 -08:00
|
|
|
rx = output.get_capture(len(pkts))
|
|
|
|
outputs = [output]
|
2018-10-10 07:22:51 -07:00
|
|
|
if not timeout:
|
|
|
|
timeout = 1
|
|
|
|
for i in self.pg_interfaces:
|
|
|
|
if i not in outputs:
|
2022-02-18 10:35:08 +00:00
|
|
|
i.assert_nothing_captured(timeout=timeout)
|
2018-10-10 07:22:51 -07:00
|
|
|
timeout = 0.1
|
|
|
|
|
tests: add enhanced packet counter verification
Add support for inline packet counter verification to send_and_* functions.
Diff dictionary is a dictionary of dictionaries of interesting stats:
diff_dictionary =
{
"err" : { '/error/counter1' : 4, },
sw_if_index1 : { '/stat/segment/counter1' : 5,
'/stat/segment/counter2' : 6,
},
sw_if_index2 : { '/stat/segment/counter1' : 7,
},
}
It describes a per sw-if-index diffset, where each key is stat segment
path and value is the expected change for that counter for sw-if-index.
Special case string "err" is used for error counters.
This then allows more precise packet counter verification by first
defining a "zero" dictionary, e.g. for ED NAT:
cls.no_diff = StatsDiff({
pg.sw_if_index: {
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
'/nat44-ed/in2out/fastpath/tcp': 0,
'/nat44-ed/in2out/fastpath/udp': 0,
'/nat44-ed/in2out/fastpath/icmp': 0,
'/nat44-ed/in2out/fastpath/drops': 0,
'/nat44-ed/in2out/slowpath/tcp': 0,
'/nat44-ed/in2out/slowpath/udp': 0,
'/nat44-ed/in2out/slowpath/icmp': 0,
'/nat44-ed/in2out/slowpath/drops': 0,
}
for pg in cls.pg_interfaces
})
and then to specify only changed counters directly when calling
one of send_and_* functions:
self.send_and_assert_no_replies(
self.pg0, pkts, msg="i2o pkts",
stats_diff=self.no_diff | {
"err": {
'/err/nat44-ed-in2out-slowpath/out of ports': len(pkts),
},
self.pg0.sw_if_index: {
'/nat44-ed/in2out/slowpath/drops': len(pkts),
},
}
)
operator | is overloaded by StatsDiff class to perform a deep merge operation,
so in above case, dictionaries for "err" and self.pg0.sw_if_index do not
overwrite whole sub-dictionaries, rather the contents are merged,
assuring that all the remaining counters are verified to be zero.
Type: improvement
Signed-off-by: Klement Sekera <klement.sekera@gmail.com>
Change-Id: I2b87f7bd58a7d4b34ee72344e2f871b2f372e2d9
2022-02-18 10:34:35 +00:00
|
|
|
if stats_diff:
|
|
|
|
self.compare_stats_with_snapshot(stats_diff, stats_snapshot)
|
|
|
|
|
2018-01-08 04:41:42 -08:00
|
|
|
return rx
|
|
|
|
|
2016-10-03 19:44:57 +02:00
|
|
|
|
2022-04-26 19:02:15 +02:00
|
|
|
if __name__ == "__main__":
|
2019-01-13 16:09:10 -08:00
|
|
|
pass
|