P4 03-L2_Basic_Forwarding
P4示例程序-03 L2基本交换机
功能:交换机根据MAC地址查表、确定转发出端口
拓扑结构
代码
p4app.json的拓扑结构1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21"topology": {
"assignment_strategy": "l2",
"links": [["h1", "s1"], ["h2", "s1"], ["h3", "s1"], ["h4","s1"]],
"hosts": {
"h1": {
},
"h2": {
}
,
"h3": {
}
,
"h4": {
}
},
"switches": {
"s1": {
"cli_input": "s1-commands.txt"
}
}
}- 原代码
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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77/* -*- P4_16 -*- */
#include <core.p4>
#include <v1model.p4>
/*************************************************************************
*********************** H E A D E R S ***********************************
*************************************************************************/
//TODO 1: Define ethernet header, metadata and headers struct
/*************************************************************************
*********************** P A R S E R ***********************************
*************************************************************************/
parser MyParser(packet_in packet,
out headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
state start {
//TODO 2: parse ethernet header
transition accept;
}
}
/*************************************************************************
************ C H E C K S U M V E R I F I C A T I O N *************
*************************************************************************/
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
apply { }
}
/*************************************************************************
************** I N G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyIngress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
action drop() {
mark_to_drop(standard_metadata);
}
//TODO 4: define an action to set the egress port
//TODO 3: define a l2 forwarding table and define a match to set the egress port
apply {
//TODO 5: call the forwarding table
}
}
/*************************************************************************
**************** E G R E S S P R O C E S S I N G *******************
*************************************************************************/
control MyEgress(inout headers hdr,
inout metadata meta,
inout standard_metadata_t standard_metadata) {
apply { }
}
/*************************************************************************
************* C H E C K S U M C O M P U T A T I O N **************
*************************************************************************/
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
apply {
}
}
/*************************************************************************
*********************** D E P A R S E R *******************************
*************************************************************************/
control MyDeparser(packet_out packet, in headers hdr) {
apply {
//TODO 6: deparse ethernet header
}
}
/*************************************************************************
*********************** S W I T C H *******************************
*************************************************************************/
//switch architecture
V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main; - Headers
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17typedef bit<9> egressSpec_t;// 定义 egress 端口类型,占 9 位
typedef bit<48> macAddr_t;// 定义 MAC 地址类型,占 48 位
typedef bit<32> ip4Addr_t;// 定义 IPv4 地址类型,占 32 位
header ethernet_t {// 定义以太网头部
macAddr_t dstAddr;// 目的 MAC 地址
macAddr_t srcAddr;// 源 MAC 地址
bit<16> etherType;// 以太网类型字段
}
struct metadata { // 自定义元数据结构
/* empty */
}
struct headers {// 定义所有需要用到的头部
ethernet_t ethernet;// 只包含一个以太网头部
} - Parser
1
2
3
4
5
6
7
8
9
10parser MyParser(packet_in packet,// 输入原始数据包
out headers hdr,// 输出解析后的头部
inout metadata meta,// 输入输出元数据
inout standard_metadata_t standard_metadata) {// 输入输出标准元数据
state start {// 起始解析状态
packet.extract(hdr.ethernet);// 提取以太网头部
transition accept;// 进入解析完成状态
}
} - Checksum Verification
1
2
3control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
apply { }
} - Ingress Processing
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
29control MyIngress(inout headers hdr,// 输入:头部
inout metadata meta,// 输入输出:元数据
inout standard_metadata_t standard_metadata) { // 输入输出:标准元数据
action drop() {// 丢弃数据包的动作
mark_to_drop(standard_metadata);// 设置为丢弃状态
}
action forward(bit<9> egress_port) {// 转发动作,参数为输出端口
standard_metadata.egress_spec = egress_port;// 设置出口端口
}
table dmac {// dmac 表:匹配目的 MAC
key = {
hdr.ethernet.dstAddr: exact;// 精确匹配目的 MAC 地址
}
actions = {
forward;// 命中则执行 forward 动作
NoAction;// 不命中则什么都不做
}
size = 256;// 表项容量最大为 256
default_action = NoAction;// 默认动作为不做处理
}
apply {// 入口处理的 apply 区块
dmac.apply();// 应用 dmac 表进行转发决策
}
} - Egress Processing
1
2
3
4
5
6control MyEgress(inout headers hdr,// 输出:头部
inout metadata meta,// 输出:元数据
inout standard_metadata_t standard_metadata) {
apply { }// 此处不进行出口处理
} - Checksum Computation
1
2
3control MyComputeChecksum(inout headers hdr, inout metadata meta) {
apply { }
} - DE parser
1
2
3
4
5
6control MyDeparser(packet_out packet, in headers hdr) {
apply {
// 将头部重新打包到输出数据包中
packet.emit(hdr.ethernet);// 输出以太网头部
}
} - Switch
1
2
3
4
5
6
7
8V1Switch(
MyParser(),
MyVerifyChecksum(),
MyIngress(),
MyEgress(),
MyComputeChecksum(),
MyDeparser()
) main; s1-commands.txt1
2
3
4table_add dmac forward 00:00:0a:00:00:01 => 1
table_add dmac forward 00:00:0a:00:00:02 => 2
table_add dmac forward 00:00:0a:00:00:03 => 3
table_add dmac forward 00:00:0a:00:00:04 => 4controller.py1
2
3
4
5
6
7
8
9
10
11
12
13
14
15from p4utils.utils.helper import load_topo
from p4utils.utils.sswitch_p4runtime_API import SimpleSwitchP4RuntimeAPI
topo = load_topo('topology.json')
controllers = {}
for switch, data in topo.get_p4rtswitches().items():
controllers[switch] = SimpleSwitchP4RuntimeAPI(data['device_id'],data['grpc_port'],p4rt_path=data['p4rt_path'],json_path=data['json_path'])
controller = controllers['s1']
controller.table_add('dmac', 'forward', ['00:00:0a:00:00:01'], ['1'])
controller.table_add('dmac', 'forward', ['00:00:0a:00:00:02'], ['2'])
controller.table_add('dmac', 'forward', ['00:00:0a:00:00:03'], ['3'])
controller.table_add('dmac', 'forward', ['00:00:0a:00:00:04'], ['4'])
P4仿真
- 启动网络拓扑
1
sudo p4run
- 使用
pingall命令探测主机之间是否连接正常
- 连接正常,实验完成
P4 03-L2_Basic_Forwarding
http://example.com/2025/07/25/P4 03-L2_Basic_Forwarding/