鲲鹏社区首页
中文
注册
开发者
我要评分
获取效率
正确性
完整性
易理解
在线提单
论坛求助

开发数据面实践示例

  1. 了解数据面开发组成。详情请参见OVS场景数据面Hydra编程
  2. 在自定义代码工程下创建OVS数据面开发目录,以ovs_project为例。
    ovs_project/
    ├── CMakeLists.txt                       # 顶层CMake配置文件
    └── src_dsl                              # 用户数据面源代码子目录
        ├── CMakeLists.txt                   # 数据面的子目录CMake配置文件
        └── ovs_project.hdr                  # 数据面Hydra源文件
  3. 分析业务需要处理的网络数据包协议类型,实现packet parser。

    例如当前业务处理的网络报文类型为标准的vxlan、tcp、udp、icmp报文,通过表1可知,属于硬件解析器支持的范围,可以不实现用户自定义parser或混合parser,直接使用hdr_fix_parser作为解析器。

  4. 根据网络数据包处理流程,实现MainPipe。
    control MainPipe(in hdr_fix_headers hdr) {
        @main
        table ovs_exact {
                key = { ... }
                actions = { ... }
                size = 0x200000;
                default_action = flexda_upcall;
                aging_time = 200;
        }
        apply {
        }
    }
    1. 根据业务网络数据包类型,确定需要卸载的key和对应的action。

      对照表1确定是否需要自定义key,对照表1确定是否需要实现自定义action,完成table定义。

      示例代码如下所示。

      rte_port_id_hdr_t input_port;
      rte_eth_hdr_t eth;
      rte_vxlan_hdr_t vxlan_vni;
      rte_vlan_hdr_t vlan;
      ip_union l3_union;
      port_icmp_union l4_union;
      @main @rss_fastpath
      table ovs_exact {
              key = {
                  l3_union : exact;
                  l4_union : exact;
                  input_port : exact;
                  eth : exact;
                  vxlan_vni : exact;
                  vlan : exact;
              }
              actions = {
                  rte_port_id;
                  rte_of_pop_vlan;
                  rte_of_push_vlan;
                  rte_of_set_vlan_vid;
                  rte_of_set_vlan_pcp;
                  rte_vxlan_decap;
                  rte_vxlan_encap;
                  rte_set_ipv4_src;
                  rte_set_ipv4_dst;
                  rte_set_ipv6_src;
                  rte_set_ipv6_dst;
                  rte_set_tp_src;
                  rte_set_tp_dst;
                  rte_set_mac_dst;
                  rte_set_mac_src;
              }
              size = 0x200000;
              default_action = flexda_upcall;
              aging_time = 200;
      }
    2. 根据key的定义,实现apply逻辑。

      示例代码如下所示。

      apply {
              input_port.port_id = hdr_input_port_id_get();
              if (hdr.tunnel.vxlan.isValid() && (input_port.port_id >> 12) == VPORT_TYPE_BOND) {
                  if (hdr.inner_ethernet.isValid()) {
                      eth.dst = hdr.inner_ethernet.dmac;
                      eth.src = hdr.inner_ethernet.smac;
                      eth.eth_type = hdr.inner_ethernet.eth_type;
                  }
                  if (hdr.inner_vlan.isValid()) {
                      eth.eth_type = hdr.inner_vlan.eth_type;
                      vlan.vlan_tci = (bit<16>)hdr.inner_vlan.vid;
                  }
                  if (hdr.inner_l3.ipv4.isValid() || hdr.inner_l3.ipv6.isValid()) {
                      if (hdr.inner_l3.ipv4.isValid()) {
                          l3_union.dpdk_ipv4.setValid();
                          l3_union.dpdk_ipv4.protocol = hdr.inner_l3.ipv4.protocol;
                          l3_union.dpdk_ipv4.sip = hdr.inner_l3.ipv4.sip;
                          l3_union.dpdk_ipv4.dip = hdr.inner_l3.ipv4.dip;
                      } else if (hdr.inner_l3.ipv6.isValid()) {
                          l3_union.dpdk_ipv6.setValid();
                          l3_union.dpdk_ipv6.next_header = hdr.inner_l3.ipv6.next_header;
                          l3_union.dpdk_ipv6.sip = hdr.inner_l3.ipv6.sip;
                          l3_union.dpdk_ipv6.dip = hdr.inner_l3.ipv6.dip;
                      }
                      if (hdr.inner_l4.udp.isValid()) {
                          l4_union.dpdk_udp.setValid();
                          l4_union.dpdk_udp.src_port = hdr.inner_l4.udp.src_port;
                          l4_union.dpdk_udp.dst_port = hdr.inner_l4.udp.dst_port;
                      } else if (hdr.inner_l4.tcp.isValid()) {
                          l4_union.dpdk_tcp.setValid();
                          l4_union.dpdk_tcp.src_port = hdr.inner_l4.tcp.src_port;
                          l4_union.dpdk_tcp.dst_port = hdr.inner_l4.tcp.dst_port;
                      } else if (hdr.inner_l4.icmp.isValid()) {
                          if (hdr.inner_l3.ipv4.isValid()) {
                              l4_union.dpdk_icmp.setValid();
                              l4_union.dpdk_icmp.type = hdr.inner_l4.icmp.type;
                              l4_union.dpdk_icmp.code = hdr.inner_l4.icmp.code;
                              l4_union.dpdk_icmp.ident = hdr.inner_l4.icmp.identifier;
                          } else if (hdr.inner_l3.ipv6.isValid()) {
                              l4_union.dpdk_icmp6.setValid();
                              l4_union.dpdk_icmp6.type = hdr.inner_l4.icmp.type;
                              l4_union.dpdk_icmp6.code = hdr.inner_l4.icmp.code;
                          }
                      }
                      vxlan_vni.vni = hdr.tunnel.vxlan.vni;
                  }
                  ovs_exact.apply();
              }
              else {
                  if (hdr.ethernet.isValid()) {
                      eth.dst = hdr.ethernet.dmac;
                      eth.src = hdr.ethernet.smac;
                      eth.eth_type = hdr.ethernet.eth_type;
                  }
                  if (hdr.vlan.isValid()) {
                      eth.eth_type = hdr.vlan.eth_type;
                      vlan.vlan_tci = (bit<16>)hdr.vlan.vid;
                  }
                  if (hdr.l3.ipv4.isValid() || hdr.l3.ipv6.isValid()) {
                      if (hdr.l3.ipv4.isValid()) {
                          l3_union.dpdk_ipv4.setValid();
                          l3_union.dpdk_ipv4.protocol = hdr.l3.ipv4.protocol;
                          l3_union.dpdk_ipv4.sip = hdr.l3.ipv4.sip;
                          l3_union.dpdk_ipv4.dip = hdr.l3.ipv4.dip;
                      } else if (hdr.l3.ipv6.isValid()) {
                          l3_union.dpdk_ipv6.setValid();
                          l3_union.dpdk_ipv6.next_header = hdr.l3.ipv6.next_header;
                          l3_union.dpdk_ipv6.sip = hdr.l3.ipv6.sip;
                          l3_union.dpdk_ipv6.dip = hdr.l3.ipv6.dip;
                      }
                      if (hdr.l4.udp.isValid()) {
                          l4_union.dpdk_udp.setValid();
                          l4_union.dpdk_udp.src_port = hdr.l4.udp.src_port;
                          l4_union.dpdk_udp.dst_port = hdr.l4.udp.dst_port;
                      } else if (hdr.l4.tcp.isValid()) {
                          l4_union.dpdk_tcp.setValid();
                          l4_union.dpdk_tcp.src_port = hdr.l4.tcp.src_port;
                          l4_union.dpdk_tcp.dst_port = hdr.l4.tcp.dst_port;
                      } else if (hdr.l4.icmp.isValid()) {
                          if (hdr.l3.ipv4.isValid()) {
                              l4_union.dpdk_icmp.setValid();
                              l4_union.dpdk_icmp.type = hdr.l4.icmp.type;
                              l4_union.dpdk_icmp.code = hdr.l4.icmp.code;
                              l4_union.dpdk_icmp.ident = hdr.l4.icmp.identifier;
                          } else if (hdr.l3.ipv6.isValid()) {
                              l4_union.dpdk_icmp6.setValid();
                              l4_union.dpdk_icmp6.type = hdr.l4.icmp.type;
                              l4_union.dpdk_icmp6.code = hdr.l4.icmp.code;
                          }
                      }
                  }
                  vxlan_vni.vni = 0;
                  ovs_exact.apply();
              }
      }
  5. 根据网络数据包处理流程,实现PostPipe,可以无实际处理逻辑。

    示例代码如下所示。

    control PostPipe(in hdr_fix_headers hdr) {
        apply {}
    }
  6. 组装parser和control等组件。

    示例代码如下所示。

    Switch(
            TX_OVS(hdr_fix_parser(),MainPipe(),PostPipe()),
            RX_OVS(hdr_fix_parser(),MainPipe(),PostPipe())
    ) main;