Lab 1:黑盒观察与调试¶
在本节实验中,实验者将运行一个已经编译好的 Tofino 程序,通过主机抓包、CPU 接口抓包、交换机端口计数器和控制面日志观察数据包的处理结果。
本实验不需要编写或编译 P4/C 代码。实验者需要分别发送 ARP、UDP 和 ICMP 报文,并根据观测结果判断报文被交换机回复、丢弃或上传至控制面的条件。
实验目标¶
- 运行已经编译好的 Tofino 程序并检查端口状态;
- 使用
tcpdump对比 ARP Request 与交换机生成的 ARP Reply; - 发送 UDP 探测报文,并结合 CPU 接口抓包和控制面日志定位触发 CPU upload 的端口;
- 使用 ICMP 作为对照流量,理解 CPU upload 依赖的协议字段。
实验环境¶
本实验只使用 Host A。Tofino 的 9/0 端口配置为网关 192.168.1.1,控制面预先写入静态端口信息,不执行动态 ARP 学习。
| 组件 | 配置 |
|---|---|
| Host A | 192.168.1.2/24 |
| 网关 | 192.168.1.1 |
| Front-panel port | 9/0 |
| Device port | 132 |
| CPU port | 64 |
实验步骤¶
各步骤的记录要求见实验目录中的 README.md,报告模板为同目录下的 report.md。
1. 运行交换机程序¶
p4-blackbox-observe 目录提供预编译控制面程序 contrl、校验文件 SHA256SUMS、启动脚本 run_switch.sh、UDP 探测脚本和报告模板,不提供数据面和控制面源码,无需运行 make。observe 数据面的编译产物已预先部署在实验机的 SDE 中。
登录 Tofino 交换机,加载课程 SDE 环境并确认 SDE_INSTALL 指向安装目录。进入 p4-blackbox-observe 目录,检查文件完整性并设置动态库搜索路径:
sha256sum -c SHA256SUMS
export LD_LIBRARY_PATH="$SDE_INSTALL/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"
ldd ./contrl
ldd 输出不应出现 not found。随后运行启动脚本:
./run_switch.sh
脚本启动 contrl,由它以库模式启动 bf_switchd、加载 observe、开启 9/0 并下发表项,日志写入本目录的 observe.log。终端出现以下输出后开始测试:
[CPU] interface=... status=READY
interface= 后的名称就是交换机控制面 Linux 上的 CPU 接口,下文记为 <cpu-interface>。例如输出 interface=enp4s0f0 时就使用 enp4s0f0,不要填写 Host A 的 eth0。
2. 配置实验主机¶
在 Host A 上配置接口地址和默认路由:
ip link set eth0 up
ip addr replace 192.168.1.2/24 dev eth0
ip route replace default via 192.168.1.1 dev eth0
ip -br addr show dev eth0
ip route
接口应显示 UP 和 LOWER_UP。如果显示 LOWERLAYERDOWN,应先检查端口容器是否正确连接到 Tofino 9/0,此时继续发送报文不会得到有效的实验结果。
3. 启动抓包与日志¶
在 Host A 启动抓包,不加过滤条件:
tcpdump -i eth0 -Q inout -nn -e -vvv -XX
在 Tofino 交换机上分别观察 CPU 接口和控制面日志:
tcpdump -i <cpu-interface> -nn -e 'ether proto 0x0866' -vvv -XX
tail -f observe.log
4. 观察 ARP 报文¶
清空邻居缓存并查询网关地址:
ip neigh flush all
arping -c 1 -I eth0 192.168.1.1
抓包中应同时出现 ARP Request 和 ARP Reply。比较两个报文的以下字段:
| 字段 | ARP Request | ARP Reply |
|---|---|---|
| Ethernet source/destination MAC | Host A / broadcast | 网关 / Host A |
| ARP opcode | request | reply |
| ARP sender IP | 192.168.1.2 |
192.168.1.1 |
| ARP target IP | 192.168.1.1 |
192.168.1.2 |
随后查询一个不是网关的地址:
ip neigh flush all
arping -c 1 -I eth0 192.168.1.254
记录请求已发出的证据、等待时间和应答情况,结合请求/应答地址和实验拓扑解释两次结果的差异。
5. 观察 CPU Upload¶
某个 UDP destination port 会触发 CPU upload,该端口位于 10000 至 10031 之间。请通过探测和观测自行找出这个端口,不要依赖其他实验组或历史运行的结果。
先发送一个普通 UDP 报文作为对照:
python3 scripts/send_udp.py --iface eth0 \
--src-ip 192.168.1.2 --dst-ip 192.168.1.1 \
--src-port 40000 --dst-port 9998 --payload normal
再运行扫描脚本。脚本从 192.168.1.2:40001 向 192.168.1.1 的 UDP 端口 10000 至 10031 各发送一个探测报文;接口不是 eth0 时用 --iface 指定:
python3 scripts/scan_udp_ports.py
运行时观察 observe.log 和 CPU 接口抓包。只有一个端口会产生类似以下的日志:
[UPLOAD] ingress=132 proto=UDP ...
找到后,使用 send_udp.py 向该端口单独发送一次报文,对照 Host A 抓包、CPU 抓包和 [UPLOAD] 日志。命中的报文不会返回 Host A,而是被转换为 EtherType 0x0866 的 upload 报文送到 CPU port。日志中的 length 对应原 IPv4 报文的 total length,不是 UDP length;日志不打印 payload 内容。EtherType 需要从两端抓包中读取。
6. ICMP 对照¶
ping -c 1 -W 1 192.168.1.1
记录 ICMP 的发送结果以及同一时段的 CPU 抓包和日志。ICMP 没有传输层端口,结合协议字段解释它是否会触发 CPU upload。
实验验证¶
完成实验后,应能够根据外部观测整理出以下三条报文路径:
| 输入报文 | 观测结果 |
|---|---|
查询 192.168.1.1 的 ARP Request |
交换机生成 ARP Reply 并返回 Host A |
| 普通 UDP 报文 | Host A 和 CPU 均未收到相应报文 |
| 命中隐藏 destination port 的 UDP | 转换为 EtherType 0x0866 的报文并上传 CPU |
路径图只标出外部观测支持的收发关系,不能从“未收到”推断具体的内部丢弃位置。每项结论应引用发送端、接收端或 CPU 日志等至少两类证据,并附上每项测试前后 9/0 端口的 RX/TX 计数器增量。增量中可能包含 Host A 自动发出的 IPv6 邻居发现报文(Neighbor Solicitation、Router Solicitation)、MLD 组播监听报告和 ARP 请求等非测试报文,需结合同一时段的 Host A 抓包逐个核对。
结束实验¶
清空 Host A 的邻居缓存:
ip neigh flush all
在运行 ./run_switch.sh 的终端按 Ctrl-C 停止控制面。重复运行时,建议每次启动前删除旧日志:
rm -f observe.log