非对称链路¶
一台交换机上的两台主机,每条链路只在单一方向上加延迟,反向不 整形。最终的 ping RTT 等于两条单向延迟之和。
你将看到什么¶
h1 ping h2 报告大约 220ms 的 RTT,抖动在亚毫秒级别——集成测试
中实测的 RTT 是
min/avg/max/mdev = 220.981/221.288/222.048/0.396 ms。
拓扑¶
examples/asymmetric_link/topology.py:
"""Two hosts plus one switch with asymmetric link delays.
The h1↔s1 link adds 200 ms egress delay at h1 (h1→s1 direction); the
h2↔s1 link adds 20 ms egress delay at s1 (s1→h2 direction). End-to-end
one-way h1→h2 delay is therefore ~220 ms; reverse h2→h1 is ~0 ms; ping
RTT from h1 to h2 is ~220 ms.
Run with:
sudo p4net examples/asymmetric_link/topology.py
Then in the shell:
h1 ping h2 count=10 timeout=2
"""
from __future__ import annotations
from pathlib import Path
from p4net import Network
from p4net.topo import Topology
HERE = Path(__file__).resolve().parent
topology = Topology()
h1 = topology.add_host("h1", ip="10.0.0.1/24", mac="00:00:00:00:00:01")
h2 = topology.add_host("h2", ip="10.0.0.2/24", mac="00:00:00:00:00:02")
s1 = topology.add_switch("s1", p4_src=HERE / "asymmetric.p4")
# h1↔s1: shape only the h1→s1 direction (egress at h1).
topology.add_link(h1, s1, port_b=1, delay_a_to_b="200ms")
# h2↔s1: shape only the s1→h2 direction. With a=h2 and b=s1, "b→a" =
# "s1→h2", so delay_b_to_a applies in that direction.
topology.add_link(h2, s1, port_b=2, delay_b_to_a="20ms")
def setup(net: Network) -> None:
"""Pre-seed static ARP."""
h1 = net.host("h1")
h2 = net.host("h2")
h1.exec(
[
"ip",
"neigh",
"replace",
"10.0.0.2",
"lladdr",
"00:00:00:00:00:02",
"dev",
"h1-eth0",
"nud",
"permanent",
]
)
h2.exec(
[
"ip",
"neigh",
"replace",
"10.0.0.1",
"lladdr",
"00:00:00:00:00:01",
"dev",
"h2-eth0",
"nud",
"permanent",
]
)
if __name__ == "__main__":
from p4net.cli.main import main
raise SystemExit(main([__file__]))
h1↔s1 链路上的 delay_a_to_b="200ms" 应用在 a 侧(h1 命名
空间)。h2↔s1 链路上的 delay_b_to_a="20ms" 应用在 b 侧
(root 命名空间里 s1 朝向 h2 的 veth)。
| 方向 | 路径 | 整形延迟 |
|---|---|---|
| h1 → s1 | h1 出向 veth | 200ms |
| s1 → h2 | s1 出向 veth | 20ms |
| h2 → s1 | (无) | 0ms |
| s1 → h1 | (无) | 0ms |
端到端单向 h1→h2:200 + 20 = 220ms。反向 h2→h1:0ms。 ping RTT(h1→h2 echo + h2→h1 reply):220ms。
P4 程序¶
examples/asymmetric_link/asymmetric.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;
与快速上手相同的端口翻转流水线。非对称完全 依赖链路损伤实现,与数据平面无关。
运行¶
p4net> h1 ping h2 5 3
PING 10.0.0.2 (10.0.0.2) 56(84) bytes of data.
64 bytes from 10.0.0.2: icmp_seq=1 ttl=64 time=222 ms
64 bytes from 10.0.0.2: icmp_seq=2 ttl=64 time=221 ms
64 bytes from 10.0.0.2: icmp_seq=3 ttl=64 time=221 ms
64 bytes from 10.0.0.2: icmp_seq=4 ttl=64 time=221 ms
64 bytes from 10.0.0.2: icmp_seq=5 ttl=64 time=221 ms
--- 10.0.0.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4126ms
rtt min/avg/max/mdev = 220.981/221.288/222.048/0.396 ms
(这是 phase-12 验证时实测的输出。)
在 h1 命名空间执行 tc qdisc show 可以确认 netem 队列在哪一侧:
关键设计点¶
- 方向语义由
(a, b)顺序决定。Link(h1, s1, delay_a_to_b="200ms")整形 h1→s1。如果交换写法 为Link(s1, h1, ...),同样的delay_a_to_b整形的将是 s1→h1。add_link(a, b, ...)的参数顺序就是基准。 - 同一参数同时给对称值与非对称值会被构造期拒绝。不能既写
delay="50ms"又写delay_a_to_b="100ms"——同一个参数只能 二选一。但跨参数自由组合是允许的(例如对称bandwidth加 非对称delay)。
可尝试的变体¶
- 改用
loss_pct_a_to_b=50.0替代延迟,观察pingall矩阵呈 50% 丢包。 - 把
delay_a_to_b="200ms"与delay_b_to_a="200ms"同时设上, 恢复对称 400ms RTT。 - 用非对称延迟搭配对称带宽整形(
bandwidth="1mbit")模拟典型的 家用宽带链路。