P4 02-Repeater

P4示例程序-02 中继器

功能:实现了简单的双端口交换机,使得两个主机能够进行通信,即类似于中继器的功能

拓扑结构

拓扑结构

代码

  1. p4app.json的拓扑结构
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    "topology": {
    "assignment_strategy": "l2",
    "links": [["h1", "s1"], ["h2", "s1"]],
    "hosts": {
    "h1": {
    },
    "h2": {
    }
    },
    "switches": {
    "s1": {
    }
    }
    }
  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
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    /* -*- P4_16 -*- */
    #include <core.p4>
    #include <v1model.p4>
    /*************************************************************************

    *********************** H E A D E R S  ***********************************

    *************************************************************************/
    struct metadata {
    }
    struct headers {
    }
    /*************************************************************************

    *********************** 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{
    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) {
    /* TODO 1: For solution 2 -> define a table that matches standard_metadata.ingress_port */
    /* TODO 2: For solution 2 -> define an action that modifies the egress_port */
    apply {
    /* TODO 3:*/
    /* Solution 1: Without tables, write the algorithm directly here*/
    /* Solution 2: Apply the table you use */
    }
    }
    /*************************************************************************

    ****************  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 {
    /* Deparser not needed */
    }
    }
    /*************************************************************************

    ***********************  S W I T C H  *******************************

    *************************************************************************/
    V1Switch(
    MyParser(),
    MyVerifyChecksum(),
    MyIngress(),
    MyEgress(),
    MyComputeChecksum(),
    MyDeparser()
    ) main;
  3. Solution 1 静态配置方案
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    // solution 1
    control MyIngress(inout headers hdr,
    inout metadata meta,
    inout standard_metadata_t standard_metadata) {

    apply {

    // 如果入口是 1 号端口 => 从 2 号端口发出
    if (standard_metadata.ingress_port == 1){
    standard_metadata.egress_spec = 2;
    }

    // 如果入口是 2 号端口 => 从 1 号端口发出
    else if (standard_metadata.ingress_port == 2){
    standard_metadata.egress_spec = 1;
    }
    }
    }
    • ingress_port:数据包的入端口,解析之前设置,只读
    • egress_spec:在入端口流水线的匹配-动作过程之后设置,指定数据包出端口,可以是物理端口、逻辑端口或者多播组
    1. Solution 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
      control MyIngress(inout headers hdr,
      inout metadata meta,
      inout standard_metadata_t standard_metadata) {

      // 定义一个 action,确定出口端
      action forward(bit<9> egress_port){ // 这里的参数是无方向的,因为是来查表得到的
      standard_metadata.egress_spec = egress_port;
      }

      table repeater {
      key = {
      standard_metadata.ingress_port: exact; // 完全 match 才可以
      }
      actions = { // 两种动作
      forward; // 一定是之前已经声明的 action
      NoAction;
      }
      size = 2; // 只需要两个端口的规则,所以表里只需要两个 entries
      default_action = NoAction;
      }

      apply {
      repeater.apply();
      }
  • 实现该solution还要新建命令表s1-commands.txt
    1
    2
    table_add repeater forward 1 => 2
    table_add repeater forward 2 => 1
  • 语法
    1
    tabel_add <table_name> <action_name> <match_fields> => <action_parameters>
  • 另外还要修改p4app.json
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    "topology": {
    "assignment_strategy": "l2",
    "links": [
    ["h1", "s1"],
    ["h2", "s1"]
    ],
    "hosts": {
    "h1": {},
    "h2": {}
    },
    "switches": {
    "s1": {
    "cli_input": "s1-commands.txt"
    }
    }
    }
  1. P4仿真
  • 启动网络拓扑

    1
    sudo p4run
    启动p4run

  • 打开h1,h2命令窗口

    1
    2
    xterm h1
    xterm h2
    h1 h2 命令窗口

  • 打开 h2 的终端,运行 python receive.py

    h2命令窗口
  • 打开一个 h1 的终端,运行 python send.py 10.0.0.2 "hello world" h1命令窗口

  • h2端接收到消息并成功解码

    h2接收到消息

问题

  1. h2接收端msg无法显示发送端内容
  • 截图

    msg显示raw
  • 原因 Scapy 会自动尝试根据上下文推断下一层协议类型。字符串 str 类型的 payload,默认被包装为 Raw 类型。

  • 解决方案 Send.py

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    def main():

    if len(sys.argv)<3:
    print('pass 2 arguments: <destination> "<message>"')
    exit(1)

    addr = socket.gethostbyname(sys.argv[1])
    iface = get_if()

    if len(sys.argv) > 3:
    tos = int(sys.argv[3]) % 256
    else:
    tos = 0

    ether_dst = get_dst_mac(addr)

    if not ether_dst:
    print("Mac address for %s was not found in the ARP table" % addr)
    exit(1)

    print("Sending on interface %s to %s" % (iface, str(addr)))
    pkt = Ether(src=get_if_hwaddr(iface), dst=ether_dst)
    pkt = pkt / IP(dst=addr, tos=tos) / Raw(load=sys.argv[2])
    sendp(pkt, iface=iface, verbose=False)
    Rceiver.py
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    def handle_pkt(pkt):

    print("Packet Received:")
    ether = pkt.getlayer(Ether)
    ip = pkt.getlayer(IP)
    msg = ip.payload
    raw_data = pkt[Raw].load
    decoded = raw_data.decode(errors='ignore')

    print("###[ Ethernet ]###")
    print(" src: {}".format(ether.src))
    print(" dst: {}".format(ether.dst))
    print("###[ IP ]###")
    print(" src: {}".format(ip.src))
    print(" dst: {}".format(ip.dst))
    print("###[ MESSAGE ]###")
    print(f" msg: {decoded}")
    print()


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