快速上手(端口翻转)¶
一台交换机上的两台主机,使用静态端口翻转流水线。无需运行时表项 编程。p4net 的 "Hello World"。
你将看到什么¶
两台主机间的 pingall 全部成功,数据平面是一个 30 行左右的 P4
程序,在端口 1 ↔ 2 之间无条件互换。
拓扑¶
examples/quick_start/quick_start.py:
"""Minimal p4net quick-start: two hosts plus one BMv2 switch.
The bundled `quick_start.p4` is a port-2-port swap (port 1 <-> port 2),
so no runtime table programming is needed for hosts on opposite ports
to reach each other. Run as root so the orchestrator can create
namespaces and veth pairs:
sudo python examples/quick_start/quick_start.py
sudo p4net examples/quick_start/quick_start.py
The first form is a self-contained script. The second uses the `p4net`
console script (installed by `pip install -e .`) to load this file as a
topology module: `topology` and `setup(net)` are the two named hooks
that the console script looks for.
"""
from __future__ import annotations
from pathlib import Path
from p4net import Network
from p4net.network import RunningHost
from p4net.topo import Topology
HERE = Path(__file__).resolve().parent
def _build_topology() -> Topology:
topo = Topology()
h1 = topo.add_host("h1", ip="10.0.0.1/24", mac="00:00:00:00:00:01")
h2 = topo.add_host("h2", ip="10.0.0.2/24", mac="00:00:00:00:00:02")
s1 = topo.add_switch("s1", p4_src=HERE / "quick_start.p4")
topo.add_link(h1, s1, port_b=1)
topo.add_link(h2, s1, port_b=2)
return topo
# Module-level `topology` for the `p4net` console script.
topology = _build_topology()
def setup(net: Network) -> None:
"""Pre-seed static ARP for both hosts; called by the console script
after Network.start() and before the shell.
The same logic also runs inside this script's `__main__` block.
"""
_add_static_arp(net.host("h1"), "10.0.0.2", "00:00:00:00:00:02")
_add_static_arp(net.host("h2"), "10.0.0.1", "00:00:00:00:00:01")
def _add_static_arp(host: RunningHost, target_ip: str, target_mac: str) -> None:
iface = next(iter(host.interfaces))
host.exec(
[
"ip",
"neigh",
"replace",
target_ip,
"lladdr",
target_mac,
"dev",
iface,
"nud",
"permanent",
]
)
def main() -> None:
"""Same flow as `p4net <this file>` but self-contained for direct invocation."""
with Network(topology) as net:
setup(net)
print("hosts:", list(net.hosts))
print("switches:", list(net.switches))
print("pingall:", net.pingall())
if __name__ == "__main__":
main()
值得注意的几个点:
setup(net)是p4net控制台脚本在网络拉起后、Shell 进入前 调用的钩子。这里把静态 ARP 注入到主机邻居缓存,避免第一次 ICMP 触发地址解析。- 同一份文件既能
python quick_start.py直接运行(依赖if __name__ == "__main__"块),也能p4net quick_start.py运行(依赖模块级的topology与setup)。
P4 程序¶
examples/quick_start/quick_start.p4:
#include <core.p4>
#include <v1model.p4>
header ethernet_t {
bit<48> dstAddr;
bit<48> srcAddr;
bit<16> etherType;
}
struct headers {
ethernet_t ethernet;
}
struct metadata {}
parser MyParser(packet_in pkt, out headers hdr, inout metadata meta,
inout standard_metadata_t std) {
state start {
pkt.extract(hdr.ethernet);
transition accept;
}
}
control MyVerifyChecksum(inout headers hdr, inout metadata meta) { apply {} }
control MyIngress(inout headers hdr, inout metadata meta,
inout standard_metadata_t std) {
apply {
if (std.ingress_port == 1) {
std.egress_spec = 2;
} else if (std.ingress_port == 2) {
std.egress_spec = 1;
} else {
mark_to_drop(std);
}
}
}
control MyEgress(inout headers hdr, inout metadata meta,
inout standard_metadata_t std) { apply {} }
control MyComputeChecksum(inout headers hdr, inout metadata meta) { apply {} }
control MyDeparser(packet_out pkt, in headers hdr) {
apply {
pkt.emit(hdr.ethernet);
}
}
V1Switch(MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(),
MyComputeChecksum(), MyDeparser()) main;
入口控制根据 ingress_port 设置 std.egress_spec——没有表,
也不需要运行时控制平面。
运行¶
Shell 中:
p4net> hosts
name primary_ip primary_ip6 interfaces
h1 10.0.0.1/24 - h1-eth0
h2 10.0.0.2/24 - h2-eth0
p4net> pingall
H \ H h1 h2
h1 - 1
h2 1 -
2/2 succeeded
关键设计点¶
- 这是最小的可运行程序。如果
pingall在这里成功,说明工具链 其余部分(p4c、BMv2、命名空间、veth 对、P4Runtime)都正常 工作。 - 数据平面对 L3 一无所知——既没有 IPv4 报头解析,也没有 ARP
逻辑。
setup(net)注入静态 ARP 使 L3 ping 能够成立。
可尝试的变体¶
- 在端口 3 上加一台主机。没有表项编程的话,发往端口 3 的包会 落在隐式 drop 上(端口翻转只覆盖 1 ↔ 2)。
- 把条件分支换成单纯的
mark_to_drop(std),观察pingall全是X。 - 给
Link(..., loss_pct=20.0),跑pingall 10 1观察成功率 下降。