P4支持ternary匹配,也就是对于一个匹配字段,你可以用mask指定这个字段中的哪些bits是你关心的(1表示关心,0表示忽略),从而只匹配你关心的bits的值而忽略其他的值。
那在代码中怎么使用呢?话不多说,直接上代码(P4版本为 P4_16)!
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata){
action drop() {
mark_to_drop(standard_metadata);
}
action your_action (bit<8> param1, bit<16> param2) {
// your action logic here
}
table ipv4_ternary {
key = {
hdr.ipv4.srcAddr: ternary; //ternary匹配ipv4的 src address
hdr.ipv4.dstAddr: ternary; //ternary匹配ipv4的 dst address
}
actions = {
your_action;
drop;
}
default_action = drop();
//以下代码用于加入表项,同时也展示了如何使用ternary匹配的特性
const entries = {
// 对于每一个ternary字段,表项的值由两部分组成:value &&& mask,先value后mask,顺序一定不能错!
// mask表示在这个字段上希望匹配哪些bits,1表示匹配,0表示忽略
// 若 匹配字段&mask = value 则匹配成功
// 该表项表示匹配那些ip src address前24位为10.0.1的数据包,而忽略了ip src
// address的最后8位以及ip dst address
(0x0a000100 &&& 0xffffff00, 0x00000000 &&& 0x00000000): your_action(0x66, 0x8888);
// 该表项表示匹配ip src address为10.0.2.x,且ip dst address为10.0.1.1的数据包
// 如果mask全为1,则可以省略mask而只写value
(0x0a000200 &&& 0xffffff00, 0x0a000101): your_action(0x11, 0x2222);
// 最后,由于是ternary匹配,一个数据包可能匹配多条表项,因而表项之间需要有优先级
// 以上述方式书写表项时,越早出现的表项优先级越高。
// 当使用控制器动态的加入表项时,应该显式指定插入表项的优先级以确保正确性。
}
}
}
当然,除了以const entries的形式写入表项,还可以通过P4 Controller 来写入。以下为如何构造一个新的表项(Python):
table_entry = p4info_helper.buildTableEntry(
table_name="MyIngress.ipv4_ternary",
match_fields={
"hdr.ipv4.srcAddr": (0x0a000200, 0xffffff00), # (value, mask)
"hdr.ipv4.dstAddr": (0x0b000100, 0xffffff00)
},
action_name="MyIngress.your_action",
action_params={
"param1": 0x66,
"param2": 0x1234
},
priority=1
)
通过控制器写入表项时要注意一点,如果你不关心某个字段,应该直接在match_fields中直接不写该字段而不是将mask全设为0,这与const entries是不一样的。
比如,我们只想匹配src addr而忽略dst addr,我们应该这样写:
table_entry = p4info_helper.buildTableEntry(
table_name="MyIngress.ipv4_ternary",
match_fields={
"hdr.ipv4.srcAddr": (0x0a000200, 0xffffff00)
},
action_name="MyIngress.your_action",
action_params={
"param1": 0x66,
"param2": 0x1234
},
priority=1
)
而不是:
table_entry = p4info_helper.buildTableEntry(
table_name="MyIngress.ipv4_ternary",
match_fields={
"hdr.ipv4.srcAddr": (0x0a000200, 0xffffff00),
"hdr.ipv4.dstAddr": (0x00000000, 0x00000000) # 这一行应该被删除!
},
action_name="MyIngress.your_action",
action_params={
"param1": 0x66,
"param2": 0x1234
},
priority=1
)
否则查询log会发现以下报错:
[bmv2] [E] [thread 11605] [P4Runtime] Invalid representation of ‘don’t care’ ternary match, omit match field instead of using 0 mask