Skip to content

Commit

Permalink
Repair the static DPDK PTF tests. (#4210)
Browse files Browse the repository at this point in the history
* Repair the static DPDK PTF tests.

* Remove unused code.
  • Loading branch information
fruffy authored Jan 23, 2024
1 parent 0736b4d commit 45dabff
Show file tree
Hide file tree
Showing 8 changed files with 419 additions and 345 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/disabled/ci-dpdk-ptf-p4testgen-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -109,5 +109,5 @@ jobs:
- name: Run DPDK PTF tests using P4Testgen
working-directory: p4c/build
run: |
sudo $IPDK_INSTALL_DIR/sbin/set_hugepages.sh
sudo -E ctest -j1 --output-on-failure --schedule-random -R testgen-p4c-pna-ptf
sudo $IPDK_INSTALL_DIR/sbin/set_hugepages.sh
sudo -E ctest -j1 --output-on-failure --schedule-random -R "testgen-p4c-pna-ptf|dpdk-ptf"
6 changes: 5 additions & 1 deletion backends/dpdk/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,11 @@ set (P4_16_SUITES

#### DPDK-PTF Tests
# PTF tests for DPDK are only enabled when both infrap4d and dpdk-target are installed.
set(DPDK_PTF_TEST_SUITES "${P4C_SOURCE_DIR}/testdata/p4_16_samples/pna-dpdk-add_on_miss0.p4")
set(DPDK_PTF_TEST_SUITES
"${P4C_SOURCE_DIR}/testdata/p4_16_samples/pna-dpdk-add_on_miss0.p4"
"${P4C_SOURCE_DIR}/testdata/p4_16_samples/pna-dpdk-small_sample.p4"
)

# Check for infrap4d.
find_program(INFRAP4D infrap4d PATHS ${IPDK_INSTALL_DIR}/sbin)
# DPDK_SDK_INSTALL is the path to the dpdk-target install directory
Expand Down
13 changes: 0 additions & 13 deletions backends/dpdk/run-dpdk-ptf-test.py
Original file line number Diff line number Diff line change
Expand Up @@ -250,19 +250,6 @@ def build_and_load_pipeline(
testutils.log.error("Failed to build pipeline")
return returncode

# Load pipeline.
# NOTE: in generated PTF tests, the pipelines are loaded in individual test cases.
# This should be commented when working with Testgen.
# command = (
# f"{self.options.ipdk_install_dir}/bin/p4rt-ctl "
# "set-pipe br0 "
# f"{conf_bin} "
# f"{info_name} "
# )
# returncode = self.bridge.ns_exec(command, timeout=30)
# if returncode != testutils.SUCCESS:
# testutils.log.error("Failed to load pipeline")
# return returncode
return testutils.SUCCESS

def run_ptf(self, P4RUNTIME_PORT: int, info_name, conf_bin) -> int:
Expand Down
1 change: 1 addition & 0 deletions cmake/Linters.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,7 @@ endif()
file(
GLOB_RECURSE P4C_PYTHON_LINT_LIST FOLLOW_SYMLINKS
backends/*.py
testdata/*.py
tools/*.py
)
list(FILTER P4C_PYTHON_LINT_LIST EXCLUDE REGEX "backends/p4tools/submodules")
Expand Down
218 changes: 108 additions & 110 deletions testdata/p4_16_samples/pna-dpdk-add_on_miss0.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,170 +16,168 @@

# Andy Fingerhut, andy.fingerhut@gmail.com

import logging
import pprint
import queue
import time
from enum import Enum
from pathlib import Path

import ptf
import ptf.testutils as tu
from ptf.base_tests import BaseTest
import p4runtime_sh.shell as sh
import p4runtime_sh.utils as shutils
import p4runtime_sh.p4runtime as p4rt
from ptf import testutils as ptfutils
from ptf.mask import Mask
from ptf.packet import *

# The base_test.py path is relative to the test file, this should be improved
FILE_DIR = Path(__file__).resolve().parent
BASE_TEST_PATH = FILE_DIR.joinpath("../../backends/dpdk/base_test.py")
sys.path.append(str(BASE_TEST_PATH))
import base_test as bt

# Bsed on https://github.com/jafingerhut/p4-guide/blob/master/ipdk/23.01/add_on_miss0/ptf-tests/ptf-test1.py
# This global variable ensure that the forwarding pipeline will only be pushed once in one tes
PIPELINE_PUSHED = False


logger = logging.getLogger(None)
ch = logging.StreamHandler()
ch.setLevel(logging.INFO)
# create formatter and add it to the handlers
formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
ch.setFormatter(formatter)
logger.addHandler(ch)
class AbstractTest(bt.P4RuntimeTest):
EnumColor = Enum("EnumColor", ["GREEN", "YELLOW", "RED"], start=0)

pp = pprint.PrettyPrinter(indent=4)


class AbstractIdleTimeoutTest(BaseTest):
def setUp(self):
# Setting up PTF dataplane
self.dataplane = ptf.dataplane_instance
self.dataplane.flush()

logging.info("AbstractIdleTimeoutTest.setUp()")
grpc_addr = tu.test_param_get("grpcaddr")
if grpc_addr is None:
grpc_addr = 'localhost:9559'
certs_dir = '/usr/share/stratum/certs'
root_certificate = certs_dir + '/ca.crt'
private_key = certs_dir + '/client.key'
certificate_chain = certs_dir + '/client.crt'
# Default to insecure
ssl_opts = p4rt.SSLOptions(True, root_certificate, certificate_chain,
private_key)
sh.setup(device_id=1,
grpc_addr=grpc_addr,
election_id=(0, 1),
ssl_options=ssl_opts)
bt.P4RuntimeTest.setUp(self)
global PIPELINE_PUSHED
if not PIPELINE_PUSHED:
success = bt.P4RuntimeTest.updateConfig(self)
assert success
PIPELINE_PUSHED = True
packet_wait_time = ptfutils.test_param_get("packet_wait_time")
if not packet_wait_time:
self.packet_wait_time = 0.1
else:
self.packet_wait_time = float(packet_wait_time)

def tearDown(self):
logging.info("IdleTimeoutTest.tearDown()")
sh.teardown()
bt.P4RuntimeTest.tearDown(self)

def setupCtrlPlane(self):
pass

def sendPacket(self):
pass

def verifyPackets(self):
pass

@bt.autocleanup
def runTestImpl(self):
self.setupCtrlPlane()
logger.info("Sending Packet ...")
bt.testutils.log.info("Sending Packet ...")
self.sendPacket()
logger.info("Verifying Packet ...")
bt.testutils.log.info("Verifying Packet ...")
self.verifyPackets()


#############################################################
# Define a few small helper functions that help construct
# parameters for the table_add() method.
#############################################################

def entry_count(table_name):
te = sh.TableEntry(table_name)
n = 0
for x in te.read():
n = n + 1
return n

def init_key_from_read_tableentry(read_te):
new_te = sh.TableEntry(read_te.name)
# This is only written to work for tables where all key fields are
# match_kind exact.
for f in read_te.match._fields:
new_te.match[f] = '%d' % (int.from_bytes(read_te.match[f].exact.value, 'big'))
return new_te

def delete_all_entries(tname):
te = sh.TableEntry(tname)
for e in te.read():
d = init_key_from_read_tableentry(e)
d.delete()

def add_ipv4_host_entry_action_send(ipv4_addr_str, port_int):
te = sh.TableEntry('ipv4_host')(action='send')
te.match['dst_addr'] = '%s' % (ipv4_addr_str)
te.action['port'] = '%d' % (port_int)
te.insert()

class OneEntryTest(AbstractTest):
def entry_count(self, table_name):
req, table = self.make_table_read_request(table_name)
n = 0
for response in self.response_dump_helper(req):
n += len(response.entities)
return n

class OneEntryTest(AbstractIdleTimeoutTest):
def delete_all_table_entries(self, table_name):
req, _ = self.make_table_read_request(table_name)
for response in self.response_dump_helper(req):
for entity in response.entities:
assert entity.HasField("table_entry")
self.delete_table_entry(entity.table_entry)
return
return

def sendPacket(self):
in_dmac = 'ee:30:ca:9d:1e:00'
in_smac = 'ee:cd:00:7e:70:00'
ip_src_addr = '1.1.1.1'
ip_dst_addr = '2.2.2.2'
in_dmac = "ee:30:ca:9d:1e:00"
in_smac = "ee:cd:00:7e:70:00"
ip_src_addr = "1.1.1.1"
ip_dst_addr = "2.2.2.2"
ig_port = 0
sport = 59597
dport = 7503
pkt_in = tu.simple_tcp_packet(eth_src=in_smac, eth_dst=in_dmac,
ip_src=ip_src_addr, ip_dst=ip_dst_addr,
tcp_sport=sport, tcp_dport=dport)

pkt_in = ptfutils.simple_tcp_packet(
eth_src=in_smac,
eth_dst=in_dmac,
ip_src=ip_src_addr,
ip_dst=ip_dst_addr,
tcp_sport=sport,
tcp_dport=dport,
)

# Send in a first packet that should experience a miss on
# table ct_tcp_table, cause a new entry to be added by the
# data plane with a 30-second expiration time, and be
# forwarded with a change to its source MAC address that the
# add_on_miss0.p4 program uses to indicate that a miss
# occurred.
logging.info("Sending packet #1")
tu.send_packet(self, ig_port, pkt_in)
bt.testutils.log.info("Sending packet #1")
ptfutils.send_packet(self, ig_port, pkt_in)
first_pkt_time = time.time()

def verifyPackets(self):
in_dmac = 'ee:30:ca:9d:1e:00'
in_smac = 'ee:cd:00:7e:70:00'
ip_src_addr = '1.1.1.1'
ip_dst_addr = '2.2.2.2'
in_dmac = "ee:30:ca:9d:1e:00"
in_smac = "ee:cd:00:7e:70:00"
ip_src_addr = "1.1.1.1"
ip_dst_addr = "2.2.2.2"
sport = 59597
dport = 7503
# add_on_miss0.p4 replaces least significant 8 bits of source
# MAC address with 0xf1 on a hit of table ct_tcp_table, or
# 0xa5 on a miss.
out_smac_for_miss = in_smac[:-2] + 'a5'
out_smac_for_miss = in_smac[:-2] + "a5"
eg_port = 1
exp_pkt_for_miss = \
tu.simple_tcp_packet(eth_src=out_smac_for_miss, eth_dst=in_dmac,
ip_src=ip_src_addr, ip_dst=ip_dst_addr,
tcp_sport=sport, tcp_dport=dport)
exp_pkt_for_miss = ptfutils.simple_tcp_packet(
eth_src=out_smac_for_miss,
eth_dst=in_dmac,
ip_src=ip_src_addr,
ip_dst=ip_dst_addr,
tcp_sport=sport,
tcp_dport=dport,
)

# Check hit not tested for now for simplicity
# out_smac_for_hit = in_smac[:-2] + 'f1'
# out_smac_for_hit = in_smac[:-2] + "f1"
# exp_pkt_for_hit = \
# tu.simple_tcp_packet(eth_src=out_smac_for_hit, eth_dst=in_dmac,
# ptfutils.simple_tcp_packet(eth_src=out_smac_for_hit, eth_dst=in_dmac,
# ip_src=ip_src_addr, ip_dst=ip_dst_addr,
# tcp_sport=sport, tcp_dport=dport)


tu.verify_packets(self, exp_pkt_for_miss, [eg_port])
logging.info(" packet experienced a miss in ct_tcp_table as expected")
ptfutils.verify_packets(self, exp_pkt_for_miss, [eg_port])
bt.testutils.log.info("packet experienced a miss in ct_tcp_table as expected")

bt.testutils.log.info("Attempting to delete all entries in ipv4_host")
# TODO: This code does not seem functional?
# self.delete_all_table_entries("MainControlImpl.ipv4_host")
# assert self.entry_count("MainControlImpl.ipv4_host") == 0

def setupCtrlPlane(self):
ig_port = 0
eg_port = 1

ip_src_addr = '1.1.1.1'
ip_dst_addr = '2.2.2.2'

logging.info("Attempting to delete all entries in ipv4_host")
delete_all_entries('ipv4_host')
logging.info("Attempting to add entries to ipv4_host")
add_ipv4_host_entry_action_send(ip_src_addr, ig_port)
add_ipv4_host_entry_action_send(ip_dst_addr, eg_port)
logging.info("Now ipv4_host contains %d entries"
"" % (entry_count('ipv4_host')))
ip_src_addr = 16843009 # "1.1.1.1"
ip_dst_addr = 33686018 # "2.2.2.2"
table_name = "MainControlImpl.ipv4_host"

assert self.entry_count(table_name) == 0
bt.testutils.log.info("Attempting to add entries to ipv4_host")
self.table_add(
(table_name, [self.Exact("hdr.ipv4.dst_addr", ip_src_addr)]),
("MainControlImpl.send", [("port", ig_port)]),
)
self.table_add(
(table_name, [self.Exact("hdr.ipv4.dst_addr", ip_dst_addr)]),
("MainControlImpl.send", [("port", eg_port)]),
)
entry_count = self.entry_count(table_name)
bt.testutils.log.info("Now ipv4_host contains %d entries" "", entry_count)
assert entry_count == 2

def runTest(self):
self.runTestImpl()





Loading

0 comments on commit 45dabff

Please sign in to comment.