开发数据面实践示例
- 了解数据面开发组成。详情请参见OVS场景数据面Hydra编程。
- 在自定义代码工程下创建OVS数据面开发目录,以ovs_project为例。
ovs_project/ ├── CMakeLists.txt # 顶层CMake配置文件 └── src_dsl # 用户数据面源代码子目录 ├── CMakeLists.txt # 数据面的子目录CMake配置文件 └── ovs_project.hdr # 数据面Hydra源文件 - 分析业务需要处理的网络数据包协议类型,实现packet parser。
例如当前业务处理的网络报文类型为标准的vxlan、tcp、udp、icmp报文,通过表1可知,属于硬件解析器支持的范围,可以不实现用户自定义parser或混合parser,直接使用hdr_fix_parser作为解析器。
- 根据网络数据包处理流程,实现MainPipe。
control MainPipe(in hdr_fix_headers hdr) { @main table ovs_exact { key = { ... } actions = { ... } size = 0x200000; default_action = flexda_upcall; aging_time = 200; } apply { } }- 根据业务网络数据包类型,确定需要卸载的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; } - 根据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(); } }
- 根据业务网络数据包类型,确定需要卸载的key和对应的action。
- 根据网络数据包处理流程,实现PostPipe,可以无实际处理逻辑。
示例代码如下所示。
control PostPipe(in hdr_fix_headers hdr) { apply {} } - 组装parser和control等组件。
示例代码如下所示。
Switch( TX_OVS(hdr_fix_parser(),MainPipe(),PostPipe()), RX_OVS(hdr_fix_parser(),MainPipe(),PostPipe()) ) main;
父主题: 开发OVS代码