定义一种新的header,实现ipv4转发和自定义头部协议转发的优先级
控制平面代码下发给交换机table。除了定义ipv4转发的地址与行为匹配,还定义了自定义header的转发行为匹配。
{
"target": "bmv2",
"p4info": "build/basic_tunnel.p4info",
"bmv2_json": "build/basic_tunnel.json",
"table_entries": [
{
"table": "MyIngress.ipv4_lpm",
"match": {
"hdr.ipv4.dstAddr": ["10.0.1.1", 32]
},
"action_name": "MyIngress.ipv4_forward",
"action_params": {
"dstAddr": "00:00:00:00:01:01",
"port": 1
}
},
{
"table": "MyIngress.ipv4_lpm",
"match": {
"hdr.ipv4.dstAddr": ["10.0.2.2", 32]
},
"action_name": "MyIngress.ipv4_forward",
"action_params": {
"dstAddr": "00:00:00:02:02:00",
"port": 2
}
},
{
"table": "MyIngress.ipv4_lpm",
"match": {
"hdr.ipv4.dstAddr": ["10.0.3.3", 32]
},
"action_name": "MyIngress.ipv4_forward",
"action_params": {
"dstAddr": "00:00:00:03:03:00",
"port": 3
}
},
{
"table": "MyIngress.myTunnel_exact",
"match": {
"hdr.myTunnel.dst_id": [1]
},
"action_name": "MyIngress.myTunnel_forward",
"action_params": {
"port": 1
}
},
{
"table": "MyIngress.myTunnel_exact",
"match": {
"hdr.myTunnel.dst_id": [2]
},
"action_name": "MyIngress.myTunnel_forward",
"action_params": {
"port": 2
}
},
{
"table": "MyIngress.myTunnel_exact",
"match": {
"hdr.myTunnel.dst_id": [3]
},
"action_name": "MyIngress.myTunnel_forward",
"action_params": {
"port": 3
}
}
]
}
拓扑平面代码
{
"hosts": [
"h1",
"h2",
"h3"
],
"switches": {
"s1": { "runtime_json" : "s1-runtime.json" },
"s2": { "runtime_json" : "s2-runtime.json" },
"s3": { "runtime_json" : "s3-runtime.json" }
},
"links": [
["h1", "s1"], ["s1", "s2"], ["s1", "s3"],
["s3", "s2"], ["s2", "h2"], ["s3", "h3"]
]
}
P4文件
#include扩展#include const bit<16> TYPE_MYTUNNEL = 0x1212; const bit<16> TYPE_IPV4 = 0x800; typedef bit<9> egressSpec_t; typedef bit<48> macAddr_t; typedef bit<32> ip4Addr_t; header ethernet_t { macAddr_t dstAddr; macAddr_t srcAddr; bit<16> etherType; } header myTunnel_t { bit<16> proto_id; bit<16> dst_id; } header ipv4_t { bit<4> version; bit<4> ihl; bit<8> diffserv; bit<16> totalLen; bit<16> identification; bit<3> flags; bit<13> fragOffset; bit<8> ttl; bit<8> protocol; bit<16> hdrChecksum; ip4Addr_t srcAddr; ip4Addr_t dstAddr; } struct metadata { } struct headers { ethernet_t ethernet; myTunnel_t myTunnel; ipv4_t ipv4; } parser MyParser(packet_in packet, out headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { state start { transition parse_ethernet; } state parse_ethernet { packet.extract(hdr.ethernet); transition select(hdr.ethernet.etherType) { TYPE_MYTUNNEL: parse_myTunnel;//mac层后跟着自定义头部和ipv4头 TYPE_IPV4: parse_ipv4; default: accept; } } state parse_myTunnel { packet.extract(hdr.myTunnel); transition select(hdr.myTunnel.proto_id) { TYPE_IPV4: parse_ipv4;//一层层的解析 default: accept; } } state parse_ipv4 { packet.extract(hdr.ipv4); transition accept; } } control MyVerifyChecksum(inout headers hdr, inout metadata meta) { apply { } } control MyIngress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { action drop() { mark_to_drop(); } action ipv4_forward(macAddr_t dstAddr, egressSpec_t port) { standard_metadata.egress_spec = port; hdr.ethernet.srcAddr = hdr.ethernet.dstAddr; hdr.ethernet.dstAddr = dstAddr; hdr.ipv4.ttl = hdr.ipv4.ttl - 1; } table ipv4_lpm { key = { hdr.ipv4.dstAddr: lpm; } actions = { ipv4_forward; drop; NoAction; } size = 1024; default_action = drop(); } action myTunnel_forward(egressSpec_t port) { standard_metadata.egress_spec = port;//根据传入的参数决定端口发送 } table myTunnel_exact { key = { hdr.myTunnel.dst_id: exact; } actions = { myTunnel_forward; drop; } size = 1024; default_action = drop(); } apply { //如果只有ipv4,根据ipv4转发 if (hdr.ipv4.isValid() && !hdr.myTunnel.isValid()) { // Process only non-tunneled IPv4 packets ipv4_lpm.apply(); } //如果有自定义头部,根据自定义头部的行为参数转发 if (hdr.myTunnel.isValid()) { // process tunneled packets myTunnel_exact.apply(); } } } control MyEgress(inout headers hdr, inout metadata meta, inout standard_metadata_t standard_metadata) { apply { } } control MyComputeChecksum(inout headers hdr, inout metadata meta) { apply { update_checksum( hdr.ipv4.isValid(), { hdr.ipv4.version, hdr.ipv4.ihl, hdr.ipv4.diffserv, hdr.ipv4.totalLen, hdr.ipv4.identification, hdr.ipv4.flags, hdr.ipv4.fragOffset, hdr.ipv4.ttl, hdr.ipv4.protocol, hdr.ipv4.srcAddr, hdr.ipv4.dstAddr }, hdr.ipv4.hdrChecksum, HashAlgorithm.csum16); } } control MyDeparser(packet_out packet, in headers hdr) { apply { packet.emit(hdr.ethernet); packet.emit(hdr.myTunnel); packet.emit(hdr.ipv4); //重新打包所有header } } V1Switch( MyParser(), MyVerifyChecksum(), MyIngress(), MyEgress(), MyComputeChecksum(), MyDeparser() ) main;
如何实现在网络入口增加自定义头部并在网络出口删除自定义头部
增加:对于入口交换机,根据ipv4地址设置自定义header的内容,并设置自定义header为isValid()。
删除:在出口交换机,根据自定义header设置出口port,并设置自定义header为notValid()。



