Skip to content

Commit 0fbd248

Browse files
authored
Add docs on using pmm (packet manipulation module) bf_pktpy, and option to select pmm by env variable (#213)
Signed-off-by: Andy Fingerhut <andy_fingerhut@alum.wustl.edu> Signed-off-by: Andy Fingerhut <andy.fingerhut@gmail.com>
1 parent 8e0fdf8 commit 0fbd248

File tree

4 files changed

+163
-9
lines changed

4 files changed

+163
-9
lines changed

README.md

Lines changed: 89 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ The following software is required to run PTF:
4848

4949
Root/sudo privilege is required on the host, in order to run `ptf`.
5050

51-
The default packet manipulator tool for `ptf` is `Scapy`. To install it use:
51+
The default packet manipulation module for `ptf` is `Scapy`. To install it use:
5252
```text
5353
pip install scapy==2.5.0
5454
```
@@ -72,6 +72,94 @@ yum install tcpdump
7272
apt-get install tcpdump
7373
```
7474

75+
### Using `bf_pktpy` as an alternate packet manipulation module
76+
77+
The Python module `bf_pktpy` is included as part of the
78+
`open-p4studio` repository:
79+
80+
+ https://github.com/p4lang/open-p4studio/tree/main/pkgsrc/ptf-modules/bf-pktpy
81+
82+
It was developed as an alternative to `scapy`. The tradeoffs of using
83+
`bf_pktpy` vs. `scapy` are:
84+
85+
+ `scapy` implements more functionality, but is licensed under the
86+
copyleft GNU General Public License v2.0 (see
87+
https://github.com/secdev/scapy/blob/master/LICENSE), so may be
88+
undesirable in use cases where you wish your tests to be released
89+
under a different license.
90+
+ `bf_pktpy` implements only a small subset of the functionality of
91+
`scapy`, but it does include support for very commonly-used packet
92+
headers. It is released under an Apache 2.0 license (see
93+
https://github.com/p4lang/open-p4studio/blob/main/pkgsrc/ptf-modules/bf-pktpy/LICENSE).
94+
95+
The package `bf_pktpy` is not currently available from PyPI. To
96+
install `bf_pktpy` from source code, choose one of these methods:
97+
98+
```bash
99+
pip install "bf-pktpy@git+https://github.com/p4lang/open-p4studio#subdirectory=pkgsrc/ptf-utils/bf-pktpy"
100+
```
101+
102+
```bash
103+
git clone https://github.com/p4lang/open-p4studio
104+
cd open-p4studio/pkgsrc/ptf-utils/bf-pktpy
105+
pip install .
106+
```
107+
108+
To make effective use of `bf_pktpy` you must also install these
109+
additional Python packages. All are released under an MIT or
110+
BSD-3-Clause license, which are compatible for releasing with
111+
`bf_pktpy`, or for importing in a project with most licenses,
112+
including `Apache-2.0`, `BSD-3-Clause`, `GPL-2.0-only`, or many
113+
others.
114+
115+
```bash
116+
pip install six getmac scapy_helper psutil
117+
sudo apt-get install python3-dev
118+
pip install netifaces
119+
```
120+
121+
If you want to use `bf_pktpy` when running the command `ptf` from the
122+
command line, provide the `-pmm` option as shown below.
123+
124+
```bash
125+
ptf -pmm bf_pktpy.ptf.packet_pktpy <other command line arguments>
126+
```
127+
128+
If you want to write a Python program that imports `ptf` and causes it
129+
to use `bf_pktpy` instead of the default `scapy`, you can do so as
130+
follows in your Python code:
131+
132+
```python
133+
import ptf
134+
ptf.config["packet_manipulation_module"] = "bf_pktpy.ptf.packet_pktpy"
135+
import ptf.packet
136+
```
137+
138+
The above methods are the highest precedence way of choosing the
139+
packet manipulation module used by `ptf`. If you do not use those
140+
methods, another way is to assign the packet manipulation module name
141+
to the environment variable `PTF_PACKET_MANIPULATION_MODULE`, e.g. in
142+
Bash:
143+
144+
```bash
145+
export PTF_PACKET_MANIPULATION_MODULE="bf_pktpy.ptf.packet_pktpy"
146+
```
147+
148+
When running such a program, you should see the following line printed
149+
to standard output confirming that it is using `bf_pktpy` instead of
150+
`scapy`:
151+
152+
```text
153+
Using packet manipulation module: bf_pktpy.ptf.packet_pktpy
154+
```
155+
156+
If instead you see this line of output, `ptf` is using `scapy`:
157+
158+
```text
159+
Using packet manipulation module: ptf.packet_scapy
160+
```
161+
162+
75163
## Run PTF
76164

77165
Once you have written tests and your switch is running, you can run 'ptf'. Use

ptf

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,6 @@ config_default = {
9797
"test_case_timeout": None,
9898
# Socket options
9999
"socket_recv_size": 4096,
100-
# Packet manipulation provider module
101-
"packet_manipulation_module": "ptf.packet_scapy",
102100
# Other configuration
103101
"port_map": None,
104102
}
@@ -435,6 +433,21 @@ be subtracted from the result by prefixing them with the '^' character. """
435433
config = config_default.copy()
436434
for key in config.keys():
437435
config[key] = getattr(args, key)
436+
# For selecting the packet manipulation module when running the
437+
# `ptf` command, the order of precedence is:
438+
# (1) If the `--packet-manipulation-module` command line option is
439+
# present, use its value.
440+
# (2) Otherwise, if the environment variable
441+
# PTF_PACKET_MANIPULATION_MODULE is defined, use its value.
442+
# (3) Otherwise, use "ptf.packet_scapy"
443+
pmm_key = "packet_manipulation_module"
444+
if getattr(args, pmm_key):
445+
# Then use the value from the command line option.
446+
config[pmm_key] = getattr(args, pmm_key)
447+
elif os.getenv("PTF_PACKET_MANIPULATION_MODULE"):
448+
config[pmm_key] = os.getenv("PTF_PACKET_MANIPULATION_MODULE")
449+
else:
450+
config[pmm_key] = "ptf.packet_scapy"
438451

439452
return (config, args)
440453

src/ptf/packet.py

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,44 @@
11
"""A pluggable packet module
22
33
This module dynamically imports definitions from packet manipulation module,
4-
specified in config or provided as an agrument.
4+
specified in config or provided as an argument.
55
The default one is Scapy, but one can develop its own packet manipulation framework and
66
then, create an implementation of packet module for it (for Scapy it is packet_scapy.py)
77
"""
88

9+
import os as _os
910
from ptf import config
1011

11-
__module = __import__(
12-
config.get("packet_manipulation_module", "ptf.packet_scapy"), fromlist=["*"]
13-
)
12+
# When module ptf.packet is imported, this is the order of precedence for
13+
# deciding which packet manipulation module is used:
14+
# (1) If the key "packet_manipulation_module" is present in dict
15+
# 'config', then its value should be a string, and it will be used
16+
# as the name of the module to use.
17+
# (2) Otherwise, if the environment variable
18+
# PTF_PACKET_MANIPULATION_MODULE is defined, use its value.
19+
# (3) Otherwise, the default module name "ptf.packet_scapy" is used.
20+
21+
# Note: Applications using ptf.packet can control the choice of packet
22+
# manipulation module in any way they wish by doing the following:
23+
#
24+
# import ptf
25+
# ptf.config["packet_manipulation_module"] = my_app_choice_of_pmm
26+
# import ptf.packet
27+
28+
if "packet_manipulation_module" in config:
29+
_packet_manipulation_module = config["packet_manipulation_module"]
30+
else:
31+
_env_val = _os.getenv("PTF_PACKET_MANIPULATION_MODULE")
32+
if _env_val:
33+
_packet_manipulation_module = _env_val
34+
else:
35+
_packet_manipulation_module = "ptf.packet_scapy"
36+
37+
__module = __import__(_packet_manipulation_module, fromlist=["*"])
1438
__keys = []
1539

16-
# import logic - everything from __all__ if provided, otherwise everything not starting
17-
# with underscore
40+
# import logic - everything from __all__ if provided, otherwise
41+
# everything not starting with underscore.
1842
print("Using packet manipulation module: %s" % __module.__name__)
1943
if "__all__" in __module.__dict__:
2044
__keys = __module.__dict__["__all__"]

src/ptf/packet_scapy.py

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
import scapy.packet
2020
import scapy.main
2121
import scapy.fields
22+
import scapy.sendrecv
2223
import scapy.utils
2324

2425
if not config.get("disable_ipv6", False):
@@ -151,3 +152,31 @@ def mysummary(self):
151152
# Scapy has its own hexdump
152153
hexdump = scapy.utils.hexdump
153154
ls = scapy.packet.ls
155+
156+
# The names below are assigned here so that, like the other names
157+
# above, they can be used by importers of the ptf.packet module as if
158+
# they were defined inside of ptf.packet, and they are commonly
159+
# available as ptf.packet.<name> regardless whether you use scapy or
160+
# bf-pktpy as the packet manipulation module.
161+
#
162+
# Commented-out lines are so because they have no equivalent function
163+
# implemented in bf-pktpy yet.
164+
165+
# sndrcv = scapy.sendrecv.sndrcv
166+
send = scapy.sendrecv.send
167+
sendp = scapy.sendrecv.sendp
168+
# sendpfast = scapy.sendrecv.sendpfast
169+
sr = scapy.sendrecv.sr
170+
sr1 = scapy.sendrecv.sr1
171+
srp = scapy.sendrecv.srp
172+
srp1 = scapy.sendrecv.srp1
173+
srloop = scapy.sendrecv.srloop
174+
srploop = scapy.sendrecv.srploop
175+
# sndrcvflood = scapy.sendrecv.sndrcvflood
176+
# srflood = scapy.sendrecv.srflood
177+
# sr1flood = scapy.sendrecv.sr1flood
178+
# srpflood = scapy.sendrecv.srpflood
179+
# srp1flood = scapy.sendrecv.srp1flood
180+
sniff = scapy.sendrecv.sniff
181+
bridge_and_sniff = scapy.sendrecv.bridge_and_sniff
182+
# tshark = scapy.sendrecv.tshark

0 commit comments

Comments
 (0)