Featured image of post P4示例程序-3 L2基本交换机

P4示例程序-3 L2基本交换机

交换机根据MAC地址查表、确定转发出端口

例程拓扑

拓扑描述文件

以下为拓扑描述文件的Python脚本形式,JSON格式同理可参考之前的几篇文章。

 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
from p4utils.mininetlib.network_API import NetworkAPI

net = NetworkAPI()

# Network general options
net.setLogLevel('info')

# Network definition
net.addP4Switch('s1')
net.setP4Source('s1','./p4src/l2_basic_forwarding.p4')
net.setP4CliInput('s1', './s1-commands.txt')
net.addHost('h1')
net.addHost('h2')
net.addHost('h3')
net.addHost('h4')
net.addLink('s1', 'h1')
net.addLink('s1', 'h2')
net.addLink('s1', 'h3')
net.addLink('s1', 'h4')

# Assignment strategy
net.l2()

# Nodes general options
net.disablePcapDumpAll()
net.disableLogAll()
net.enableCli()
net.startNetwork()

交换机程序

main函数

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#include <core.p4>
#include <v1model.p4>

V1Switch(
    MyParser(),
    MyVerifyChecksum(),
    MyIngress(),
    MyEgress(),
    MyComputeChecksum(),
    MyDeparser()
) main;

定义头部

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
// 定义占48个比特的MAC地址
typedef bit<48> macAddr_t;

// 定义链路层头部的各字段
header ethernet_t {
    macAddr_t dstAddr;
    macAddr_t srcAddr;
    bit<16>   etherType;
}

// 即使未使用到元数据,但同样需求定义
struct metadata {
}

// 实例化数据包头部
struct headers {
    ethernet_t ethernet;
}

数据包解析

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
parser MyParser(packet_in packet,
                out headers hdr,
                inout metadata meta,
                inout standard_metadata_t standard_metadata) {
    state start {
        // 解析提取数据包的头部,并填充进headers的ethernet中
        packet.extract(hdr.ethernet);
        // 解析器以accept结束,accept表示解析成功
        transition accept;
    }
}

检查校验和

1
2
3
control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
    apply { }
}

入队列侧处理

 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
control MyIngress(inout headers hdr,
                  inout metadata meta,
                  inout standard_metadata_t standard_metadata) {
    action drop() {
        // v1model提供的动作原语mark_to_drop
        // 功能是将standard_metadata.egress_spec赋值为DROP_PORT
        mark_to_drop(standard_metadata);
    }

    // 定义转发动作forward,将匹配值egress_port写入标准元数据中的出端口
    action forward(bit<9> egress_port) {
        standard_metadata.egress_spec = egress_port;
    }

    // 定义名为dmac的匹配表
    table dmac {
        // 精确匹配以太网头部的dstAddr字段
        key = {
            hdr.ethernet.dstAddr: exact;
        }
        // 定义动作集合
        actions = {
            forward;
            drop;
            NoAction;
        }
        // 定义匹配表的大小
        size = 256;
        // 定义默认动作
        default_action = NoAction;
    }

    apply {
        // 查询名为dmac的匹配表
        dmac.apply();
    }
}

出队列侧处理

1
2
3
4
5
control MyEgress(inout headers hdr,
                 inout metadata meta,
                 inout standard_metadata_t standard_metadata) {
    apply { }
}

计算校验和

1
2
3
control MyComputeChecksum(inout headers hdr, inout metadata meta) {
     apply { }
}

封装数据包

1
2
3
4
5
6
7

control MyDeparser(packet_out packet, in headers hdr) {
    apply {
        // 使用emit函数重新封装headers中的ethernet头部
        packet.emit(hdr.ethernet);
    }
}

运行测试

在s1-commands.txt文件中填写匹配表项,使用P4Runtime同理可参考之前的几篇文章。

1
table-add <表的名字> <动作的名字> <匹配项> => <目标端口>
1
2
3
4
table_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 => 4

随后即可启动网络,进行测试。

1
2
3
sudo p4run
mininet > pingall
mininet > iperf h1 h4

Licensed under CC BY-NC-SA 4.0
皖ICP备2025083746号-1
公安备案 陕公网安备61019002003315号



使用 Hugo 构建
主题 StackJimmy 设计