intel 收购 Barefoot 后推出的可编程交换机芯片 Tofino 所采用的编程语言为P4,本文记录P4基础及常用抓包方法等笔记。
1. P4基础语法 1.1. 变量类型
P4 是一种静态类型的语言
1.1.1. 常用类型 void、error、string、match_kind、bool、int、Bit-strings、Fixed-width
1.1.2. 派生类型 enum、header、header stacks、struct、header_union、tuple、type specialization 、extern、parser、control、package
1.1.3. 参数方向 每个参数都需要标记方向:
in, 只读
out, 未标记、视作无方法或函数体的值
inout, both in and out
‘No direction’
编译阶段值
只能在控制平台设置的“行为参数”
能被其他“调用行为”直接设置的值,如同局部变量
1.1.4. L-values vs I-values
L-values: 出现在赋值操作左侧、或作为 out 和 inout 函数参数(代表“存储”)
1.2. 基本语法 1.2.1. 支持运算类型
算术运算(arithmetic operations):+, -, *
逻辑运算(logical operations):~, &, |, ^, >>, <<
特殊运算(non-standard operations):
数列的切割(bit slicing):[m;l]
比特的叠加(bit concatenation):++
1.2.2. 支持语法逻辑
if-else
1 2 3 4 5 if (x == 123 ) { ... } else { ... }
switch
1 2 3 4 switch (t.apply ().action_run) { action1: {...} action2: {...} }
1.2.3. P4 查看 VLAN subinterface 表项 1 2 3 4 docker exec -it syncd /opt/bfn/install/bin/bfshell bf_switch show hostif handle 2
2. PTF查看switchd表项 2.1. PTF测试查看 switchd 表项 1 2 3 4 5 6 7 8 9 10 bfshell> bf_switch bf_switch:0> show hostif all bf_switch:0> show route all bf_switch:0> show neighbor all bf_switch:0> show nexthop all bf_switch:0> show rif all bf_switch:0> show vrf all bf_switch:0> show rmac_group all bf_switch:0> show mtu all
2.2. PTF 查看表项 1 2 3 4 5 6 7 bfshell> bfrt_python bfrt_root> bfrt bfrt> switch bfrt.switch> pipe bfrt.switch.pipe> SwitchEgress # ...
bfrt.switch.pipe.SwitchEgress.rewrite.egress_bd.bd_mapping
bfrt.switch.pipe.SwitchEgress.mtu
bfrt.switch.pipe.SwitchIngress.smac
switch_bridged_metadata_h
3. snapshot抓包示例 control: 类 table: 函数 (if else) key: 入参(需关注参数) action: 子函数 (一般在 table 上实现/被调用)
entry 中删表:
3.1. 在 table 中添加表(执行逻辑: 条件 + action) 3.1.1. 删表 delete(表名)
3.1.2. 添加表 add_with_()
添加表项(添加执行逻辑)
gw: get way 硬件
Inhibited 抑制(硬件匹配,但代码逻辑抑制gw )
entry 中删表:
3.2. 在 table 中添加表(执行逻辑: 条件 + action) 当前是 “agent” 来「替人为添加这些 逻辑」
3.2.1. 删表 delete(表名)
3.2.2. 添加表 add_with_()
添加表项(添加执行逻辑)
3.3. snapshort 抓包
两个方向
看进出口,有无丢包
看 Table info 哪些 hit 哪些没 hit,关心的哪张表
/opt/bfn/install/bin/bfshell
进入 pipe_mgr
1 2 3 4 ucli pipe_mgr bf-sde.pipe_mgr >
3.3.1. 删除旧 snapshort 句柄 1 2 3 4 5 6 7 8 9 10 11 # 删除旧 snapshort (若有) snap-delete -h 0x581 snap-delete -h 0x1583 # snap-delete -h 0x2581 # snap-delete -h 0x2583 # snap-delete -h 0x3581 # snap-delete -h 0x3583
3.3.2. 创建 snapshot(获取返回句柄) 1 2 3 4 5 6 7 8 9 10 11 12 # -i 0 是 Ingress, 1 是 Egress snap-create -d 0 -p 0 -s 0 -e 11 -i 0 snap-create -d 0 -p 1 -s 0 -e 11 -i 1 # snap-create -d 0 -p 2 -s 0 -e 11 -i 0 # snap-create -d 0 -p 2 -s 0 -e 11 -i 1 # snap-create -d 0 -p 3 -s 0 -e 11 -i 0 # snap-create -d 0 -p 3 -s 0 -e 11 -i 1
3.3.3. 创建抓包触发器 (设置触发条件) 3.3.3.1. 查看有哪些字段可抓 1 2 3 4 5 6 7 8 9 10 11 # PS 可通过 查看可用哪些「PHV 资源」 **可抓** # -i 0 是 Ingress, 1 是 Egress phv-dump -d 0 -p 1 -s 0 -i 1 # phv-dump -d 0 -p 2 -s 0 -i 0 # phv-dump -d 0 -p 2 -s 0 -i 1 # phv-dump -d 0 -p 3 -s 0 -i 0 # phv-dump -d 0 -p 3 -s 0 -i 1
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 # 抓特定 DIP 10.0.0.32(0xA000020) snap-trig-add -h 0x581 -n hdr_ipv4_dst_addr -v 0xA000020 -m 0xffffffff # 抓特定 DIP 1.0.0.100 (0x1000064) snap-trig-add -h 0x2581 -n hdr_ipv4_dst_addr -v 0x1000064 -m 0xffffffff snap-trig-add -h 0x2581 -n hdr_ipv4_dst_addr -v 0xAE3C384 -m 0xffffffff # 172.20.0.1 0xAC140001 snap-trig-add -h 0x2581 -n hdr_ipv4_dst_addr -v 0xAC140001 -m 0xffffffff # 抓特定 DIP 1.0.0.100 (0x1000064) snap-trig-add -h 0x1583 -n hdr_inner_ipv4_dst_addr -v 0x1000064 -m 0xffffffff # pipe2 Ingress 抓特定 DIP 100.106.182.121 (0x646AB679) snap-trig-add -h 0x2581 -n hdr_inner_ipv4_dst_addr -v 0x646AB679 -m 0xffffffff # pipe2 Egress 抓特定 DIP 100.106.182.121 (0x646AB679) snap-trig-add -h 0x2583 -n hdr_ipv4_dst_addr -v 0x646AB679 -m 0xffffffff # pipe3 Ingress 抓特定 DIP 100.106.182.121 (0x646AB679) snap-trig-add -h 0x3581 -n hdr_ipv4_dst_addr -v 0x646AB679 -m 0xffffffff # pipe3 Egress 抓特定 DIP 100.106.182.121 (0x646AB679) snap-trig-add -h 0x3583 -n hdr_inner_ipv4_dst_addr -v 0x646AB679 -m 0xffffffff # pipe3 Egress 抓特定 DIP 100.106.182.121 (0x646AB679) snap-trig-add -h 0x3583 -n hdr_ipv4_dst_addr -v 0xC0A81E01 -m 0xffffffff # 抓特定端口 snap-trig-add -h 0x1583 -n local_md_ingress_port -v 0x144 -m 0x1ff # 抓送往 FPGA 33 口报文 snap-trig-add -h 0x2583 -n local_md_egress_port -v 0x134 -m 0x1ff # 抓特定状态 snap-trig-add -h 0x1583 -n hdr_table_1_result_valid -v 0x1 -m 0xf
3.3.4. 开启抓包 1 2 3 4 5 6 7 8 9 10 11 12 13 # check 当前抓包配置 snap-cfg-dump -h 0x2581 snap-state-set -h 0x581 -e 1 snap-state-set -h 0x1583 -e 1 # snap-state-set -h 0x2581 -e 1 # snap-state-set -h 0x2583 -e 1 # snap-state-set -h 0x3581 -e 1 # snap-state-set -h 0x3583 -e 1
3.3.5. 查看抓包结果 1 2 3 4 5 6 7 8 9 10 snap-capture-get -h 0x581 snap-capture-get -h 0x1583 # snap-capture-get -h 0x2581 # snap-capture-get -h 0x2583 # snap-capture-get -h 0x3581 # snap-capture-get -h 0x3583
3.3.6. 停止抓包 1 2 3 4 5 6 7 8 9 10 snap-state-set -h 0x1583 -e 0 snap-state-set -h 0x581 -e 0 # snap-state-set -h 0x2581 -e ~~0~~ # snap-state-set -h 0x2583 -e 0 # snap-state-set -h 0x3581 -e 0 # snap-state-set -h 0x3583 -e 0
4. 为什么编译器 flexible 很重要 flexible 加在哪儿? (PHV、ALU、ALC 实现) 变量初始化
编译宏 – 结构体
注解 @flexible 自动优化变量结构/字节序/panding
编译器优化,两个结构体的不同变量(同大小),编译器放到了同一个存储空间
修饰符:让编译器不做优化
(pa_mutually_exclusive(“ingress”, “lkp.mpls_lookup_label”, “lkp.ip_src_addr”))
5. P4编译中常见PHV、ALU资源分配错误问题解决思路 P4编译遇到PHV和ALU资源冲突问题解决思路
struct 中尽量小 bit 成员变量在前
拆 action。拆解有多个 key、parameter 的 action 到多个子 action(一个赋值对应一个 ALU)
通过 in hash 降维?