P4 03-L2_Basic_Forwarding

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

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

拓扑结构

拓扑结构

代码

  1. 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"
    }
    }
    }
  2. 原代码
    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;
  3. Headers
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    typedef 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;// 只包含一个以太网头部
    }
  4. Parser
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    parser MyParser(packet_in packet,// 输入原始数据包
    out headers hdr,// 输出解析后的头部
    inout metadata meta,// 输入输出元数据
    inout standard_metadata_t standard_metadata) {// 输入输出标准元数据

    state start {// 起始解析状态
    packet.extract(hdr.ethernet);// 提取以太网头部
    transition accept;// 进入解析完成状态
    }
    }
  5. Checksum Verification
    1
    2
    3
    control MyVerifyChecksum(inout headers hdr, inout metadata meta) {
    apply { }
    }
  6. 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
    29
    control 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 表进行转发决策
    }
    }
  7. Egress Processing
    1
    2
    3
    4
    5
    6
    control MyEgress(inout headers hdr,// 输出:头部
    inout metadata meta,// 输出:元数据
    inout standard_metadata_t standard_metadata) {

    apply { }// 此处不进行出口处理
    }
  8. Checksum Computation
    1
    2
    3
    control MyComputeChecksum(inout headers hdr, inout metadata meta) {
    apply { }
    }
  9. DE parser
    1
    2
    3
    4
    5
    6
    control MyDeparser(packet_out packet, in headers hdr) {
    apply {
    // 将头部重新打包到输出数据包中
    packet.emit(hdr.ethernet);// 输出以太网头部
    }
    }
  10. Switch
    1
    2
    3
    4
    5
    6
    7
    8
    V1Switch(
    MyParser(),
    MyVerifyChecksum(),
    MyIngress(),
    MyEgress(),
    MyComputeChecksum(),
    MyDeparser()
    ) main;
  11. s1-commands.txt
    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
  12. controller.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    from 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命令探测主机之间是否连接正常
pingall命令
  • 连接正常,实验完成

P4 03-L2_Basic_Forwarding
http://example.com/2025/07/25/P4 03-L2_Basic_Forwarding/
作者
Wsdbybyd
发布于
2025年7月25日
许可协议