Skip to content

Commit

Permalink
Replace scapy pcap read write with apache 2.0 implementation in ptf (#…
Browse files Browse the repository at this point in the history
…5132)

Signed-off-by: Andy Fingerhut <[email protected]>
  • Loading branch information
jafingerhut authored Feb 19, 2025
1 parent eb0468a commit f44f445
Show file tree
Hide file tree
Showing 5 changed files with 14 additions and 37 deletions.
17 changes: 7 additions & 10 deletions backends/bmv2/bmv2stf.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env python3
# Copyright 2013-present Barefoot Networks, Inc.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -29,11 +30,7 @@
from pathlib import Path
from typing import Dict, List, Optional, Tuple

try:
import scapy.utils as scapy_util
from scapy.layers.all import *
except ImportError:
pass
from ptf.pcap_writer import LINKTYPE_ETHERNET, PcapWriter, rdpcap

FILE_DIR = Path(__file__).resolve().parent
# Append the root to the import path.
Expand Down Expand Up @@ -577,7 +574,7 @@ def execute_stf_command(self, stf_entry):
data = stf_entry[2]
time.sleep(self.packetDelay)
try:
self.interfaces[interface]._write_packet(bytes.fromhex(data))
self.interfaces[interface].write(bytes.fromhex(data))
except ValueError:
testutils.log.error("Invalid packet data %s", data)
return testutils.FAILURE
Expand Down Expand Up @@ -772,8 +769,8 @@ def run(self, stf_map: Dict[str, str]) -> int:
sw = subprocess.Popen(runswitch, cwd=self.folder)

def openInterface(ifname):
fp = self.interfaces[interface] = scapy_util.RawPcapWriter(str(ifname), linktype=0)
fp._write_header(None)
self.interfaces[interface] = PcapWriter(str(ifname), linktype=LINKTYPE_ETHERNET)
self.interfaces[interface].flush()

# Try to open input interfaces. Each time, we set a 2 second
# timeout. If the timeout expires we check if the bmv2 process is
Expand Down Expand Up @@ -875,7 +872,7 @@ def checkOutputs(self) -> int:
packets = []
else:
try:
packets = scapy_util.rdpcap(file)
packets = rdpcap(file)
except Exception as e:
testutils.log.error("Corrupt pcap file %s\n%s", file, e)
return testutils.FAILURE
Expand Down Expand Up @@ -907,7 +904,7 @@ def checkOutputs(self) -> int:
# We only care that the packet was received on this particular port.
if not expected_pkt:
continue
cmp_result = testutils.compare_pkt(expected_pkt, packets[idx].build())
cmp_result = testutils.compare_pkt(expected_pkt, packets[idx])
if cmp_result != testutils.SUCCESS:
testutils.log.error("Packet %s on port %s differs", idx, interface)
return cmp_result
Expand Down
13 changes: 6 additions & 7 deletions backends/ebpf/targets/target.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#!/usr/bin/env python3
# Copyright 2013-present Barefoot Networks, Inc.
# Copyright 2018 VMware, Inc.
# SPDX-License-Identifier: Apache-2.0
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -27,7 +28,7 @@
from glob import glob
from pathlib import Path

import scapy.utils as scapy_util
from ptf.pcap_writer import LINKTYPE_ETHERNET, PcapWriter, rdpcap

from .ebpfstf import create_table_file, parse_stf_file

Expand Down Expand Up @@ -122,12 +123,10 @@ def _write_pcap_files(self, iface_pkts_map):
for iface, pkts in iface_pkts_map.items():
direction = "in"
infile = self.filename(iface, direction)
# Linktype 1 the Ethernet Link Type, see also 'man pcap-linktype'
fp = scapy_util.RawPcapWriter(infile, linktype=1)
fp._write_header(None)
fp = PcapWriter(infile, linktype=LINKTYPE_ETHERNET)
for pkt_data in pkts:
try:
fp._write_packet(pkt_data)
fp.write(pkt_data)
except ValueError:
testutils.log.error(f"Invalid packet data {pkt_data}")
return testutils.FAILURE
Expand Down Expand Up @@ -180,7 +179,7 @@ def check_outputs(self):
packets = []
else:
try:
packets = scapy_util.rdpcap(file)
packets = rdpcap(file)
except Exception as e:
testutils.log.error("Corrupt pcap file %s\n%s", file, e)
return testutils.FAILURE
Expand Down Expand Up @@ -208,7 +207,7 @@ def check_outputs(self):
)
return testutils.FAILURE
for idx, expected_pkt in enumerate(expected):
cmp = testutils.compare_pkt(expected_pkt, packets[idx].build())
cmp = testutils.compare_pkt(expected_pkt, packets[idx])
if cmp != testutils.SUCCESS:
testutils.log.error("Packet %s on port %s differs", idx, interface)
return cmp
Expand Down
12 changes: 0 additions & 12 deletions backends/p4tools/modules/testgen/targets/bmv2/test_backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@

namespace P4::P4Tools::P4Testgen::Bmv2 {

const big_int Bmv2TestBackend::ZERO_PKT_VAL = 0x2000000;
const big_int Bmv2TestBackend::ZERO_PKT_MAX = 0xffffffff;
const std::set<std::string> Bmv2TestBackend::SUPPORTED_BACKENDS = {"PTF", "STF", "PROTOBUF",
"PROTOBUF_IR", "METADATA"};

Expand Down Expand Up @@ -73,16 +71,6 @@ TestBackEnd::TestInfo Bmv2TestBackend::produceTestInfo(
const std::vector<std::reference_wrapper<const TraceEvent>> *programTraces) {
auto testInfo = TestBackEnd::produceTestInfo(executionState, finalModel, outputPacketExpr,
outputPortExpr, programTraces);
// This is a hack to deal with a behavioral model quirk.
// Packets that are too small are truncated to 02000000 (in hex) with width 32 bit.
if (testInfo.outputPacket->type->width_bits() == 0 &&
TestgenOptions::get().testBackend == "STF") {
int outPktSize = ZERO_PKT_WIDTH;
testInfo.outputPacket =
IR::Constant::get(IR::Type_Bits::get(outPktSize), Bmv2TestBackend::ZERO_PKT_VAL);
testInfo.packetTaintMask =
IR::Constant::get(IR::Type_Bits::get(outPktSize), Bmv2TestBackend::ZERO_PKT_MAX);
}
return testInfo;
}

Expand Down
7 changes: 0 additions & 7 deletions backends/p4tools/modules/testgen/targets/bmv2/test_backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,6 @@ namespace P4::P4Tools::P4Testgen::Bmv2 {

class Bmv2TestBackend : public TestBackEnd {
private:
/// These three constants are used for a special case. When the output packet is 0 in BMv2, the
/// packet is not dropped, instead you receive garbage (02000000) to be precise.
/// These values model this output.
/// See also: https://github.com/p4lang/behavioral-model/issues/977
static const int ZERO_PKT_WIDTH = 32;
static const big_int ZERO_PKT_VAL;
static const big_int ZERO_PKT_MAX;
/// List of the supported back ends.
static const std::set<std::string> SUPPORTED_BACKENDS;

Expand Down
2 changes: 1 addition & 1 deletion requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
pyroute2==0.7.3
ply==3.11
# Version 0.10.0
ptf @ git+https://github.com/p4lang/ptf@c554f83685186be4cfa9387eb5d6d700d2bbd7c0
ptf @ git+https://github.com/p4lang/ptf@d016cdfe99f2d609cc9c7fd7f8c414b56d5b3c5c
# FIXME: We should figure out a way to synchronize P4Runtime versions across CMake and Python.
# This is the same commit hash as defined in the top-level CMakelists.txt
p4runtime @ git+https://github.com/p4lang/p4runtime@ec4eb5ef70dbcbcbf2f8357a4b2b8c2f218845a5#subdirectory=py
Expand Down

0 comments on commit f44f445

Please sign in to comment.