CLI reference¶
This page documents p4net, the interactive shell installed by
pip install -e '.[dev]'. The shell wraps a Network and exposes
host commands, table programming, counter reads, and multicast control
without writing Python.
Starting the shell¶
Both forms accept the same flags:
usage: p4net [-h] [--no-shell] [--unsafe] [--log-dir LOG_DIR]
[--pcap-dir PCAP_DIR] [--extra-compile-arg ARG]
topology_file
--no-shell— bring the network up, runsetup(net)if defined, block untilSIGINT, then tear down. Useful for scripted lab setups.--unsafe— skipTopology.validate(). Only use if you know your topology is well-formed.--log-dir DIR— directory for BMv2 log files. Defaults to a fresh tempdir.--pcap-dir DIR— per-port BMv2 packet captures. Disabled by default.--extra-compile-arg ARG— extra argument forwarded top4c, repeatable.
Note on sudo and PATH¶
sudo strips the venv from PATH by default (secure_path in
/etc/sudoers). If sudo p4net ... reports "command not found", run
it via the venv-resolved binary:
or install p4net system-wide so the binary lives on secure_path.
Top-level commands¶
help and help <command>¶
Lists every command, or prints the usage and description of one:
p4net> help
Commands
help List commands or show details for one.
exit Exit the shell.
...
p4net> help pingall
pingall [count] [timeout]
Ping every pair of hosts; print a result matrix.
exit, quit¶
Tear down the network and exit. Ctrl-D on an empty line is equivalent.
status¶
Print the network's running state, host/switch counts, and log directory.
hosts¶
List every host with its primary IPv4, primary IPv6, and interfaces. Hosts
without an IPv6 (or IPv4) primary show - in the corresponding column.
p4net> hosts
name primary_ip primary_ip6 interfaces
h1 10.0.0.1/24 fd00::1/64 h1-eth0
h2 10.0.0.2/24 - h2-eth0
switches¶
List every switch with its gRPC address and BMv2 PID.
pingall [count] [timeout]¶
Ping every pair of hosts and print a result matrix. count defaults to
1, timeout to 1.0 seconds. Cells: 1 succeeded, X failed, - self,
? unknown.
pingall6 [count] [timeout]¶
IPv6 connectivity matrix over hosts that have a primary_ip6 set. Same
matrix renderer as pingall. Hosts without IPv6 are silently excluded.
Returns (no IPv6-equipped hosts in topology) if no host has a v6
address.
topology graph [path] [layout=LR|TB|BT|RL] [format=png|svg|pdf|dot]¶
Render the topology as a Graphviz DOT graph.
- No
pathargument: prints the DOT source to stdout. - With
pathandformat=dot: writes the source to that file verbatim, without invokingdot(works without graphviz installed). - With
pathand any other format: invokes the systemdotbinary to render to the file. Returns the absolute path to the rendered file.
layout controls rankdir and defaults to LR. format defaults to
png. The dispatcher calls Topology.validate() before rendering, so
malformed topologies surface a clear error instead of producing
misleading graphs.
p4net> topology graph layout=TB
digraph p4net {
rankdir=TB;
node [fontname="monospace"];
"h1" [shape=ellipse, label="h1\n10.0.0.1/24\nfd00::1/64"];
"h2" [shape=ellipse, label="h2\n10.0.0.2/24"];
"s1" [shape=box, label="s1\ngrpc :50051"];
"h1" -> "s1" [arrowhead=none];
"h2" -> "s1" [arrowhead=none];
}
p4net> topology graph /tmp/topo.png
/tmp/topo.png
Host commands¶
<host> ping <target> [count] [timeout]¶
Ping <target> from <host>. <target> is resolved as a host name
first (using its primary IP); any string that does not match a host name
is forwarded verbatim to iputils-ping. Defaults: count=1,
timeout=1.0. Auto-detects IPv4 vs IPv6 from the target string
(presence of : selects IPv6). Pass <host> ping6 to force IPv6 when
both stacks are present.
<host> ping6 <target> [count] [timeout]¶
Explicit IPv6 ping. <target> may be a host name (resolved to that
host's primary_ip6) or a literal IPv6 address. Errors out if the
target is a host name without a primary_ip6.
<host> xterm¶
Spawn an xterm running bash inside the host's namespace. Requires
$DISPLAY to be set; raises an error otherwise. The orchestrator
tracks the spawned process and terminates it on Network.stop().
(Output captured against a host with $DISPLAY set; the example is not
exercised by the test suite because CI has no X server.)
<host> cmd <argv>...¶
Run a command inside the host's namespace. Quoting follows shell rules
(shlex). Stdout is rendered first, stderr lines are prefixed with
[stderr], and a non-zero exit code is reported with [exit N].
<host> ifconfig¶
Shorthand for <host> cmd ip -br addr.
Switch commands¶
<switch> log¶
Print the absolute path of the switch's BMv2 log file.
<switch> table list¶
List the switch's tables and their match-key types.
<switch> table dump <table>¶
Print every entry in the named table. IPv4 (32-bit) and IPv6 (128-bit)
match values are rendered in human form (10.0.0.1/24, fd00::/64);
MAC (48-bit) values use the canonical colon form; other widths render
as decimal integers. Action parameters decode width-aware too: a 9-bit
port shows as '2', not b'\x02'.
p4net> s1 table dump MyIngress.ipv4_lpm
#0
table: MyIngress.ipv4_lpm
match: {'hdr.ipv4.dstAddr': '10.0.0.1/32'}
action: MyIngress.set_egress_port
params: {'port': '1'}
p4net> s1 table dump MyIngress.ipv6_lpm
#0
table: MyIngress.ipv6_lpm
match: {'hdr.ipv6.dstAddr': 'fd00::1/128'}
action: MyIngress.set_egress_port
params: {'port': '1'}
<switch> table add <table> match: <kv>... action: <name> [params: <kv>...] [priority: <n>]¶
Insert a table entry. Section markers (match:, action:, params:,
priority:) introduce each field; key=value pairs within a section may
be comma-separated and may have spaces around the commas. A full
worked example:
p4net> s1 table add MyIngress.ipv4_lpm \
match: hdr.ipv4.dstAddr=10.0.0.5/32 \
action: MyIngress.set_egress_port \
params: port=2
ok
For ternary or range tables, supply a priority: section. Tables
without ternary/range fields reject priority:.
<switch> table del <table> match: <kv>...¶
Delete an entry by match key. The match: syntax matches table add.
<switch> table clear <table>¶
Delete every entry from a table. Returns the count deleted.
<switch> counter [reset] <name> [<index>]¶
Read or zero a counter cell. Without reset, prints pkts=N bytes=M
for the given index (or every populated cell if no index is given).
With reset, zeroes the cell instead.
p4net> s1 counter MyIngress.ingress_pkts 0
pkts=2 bytes=196
p4net> s1 counter reset MyIngress.ingress_pkts 0
ok
<switch> mcast list¶
List every multicast group as <id>: [<port>, ...].
<switch> mcast add <id> <port,port,...>¶
Create a multicast group with the given replication ports.
<switch> mcast del <id>¶
Delete a multicast group.
<switch> packet send <hex_payload> [metadata: <k>=<v>[,<k>=<v>...]]¶
Send a PacketOut over the StreamChannel. <hex_payload> is an
even-length hex string parsed via bytes.fromhex. The optional
metadata: section names P4Info-defined packet_out controller fields;
missing fields are auto-zero-padded.
<switch> packet listen [count=N] [timeout=T]¶
Block until count packets arrive or timeout seconds elapse,
whichever first. Defaults: count=1, timeout=10.0. Renders one line
per packet: [ingress_port=N] <hex>... with the hex payload truncated
at 64 characters.
p4net> s1 packet listen count=2 timeout=3
[ingress_port=1] ffffffffffff000000000001...
[ingress_port=1] 3333000000160000000000018611...
Keyboard shortcuts¶
Ctrl-C— cancel the current input. If a command is mid-execution, the underlying process group is signalled and the shell returns to the prompt.Ctrl-Don an empty line — exit cleanly (same asexit/quit).↑/↓— walk command history (persisted in~/.p4net_history).Tab— completion on top-level commands, host names, switch names, and their sub-verbs.