Controls
In
Functions of a Control Block
- Connecting the parser to the forwarding logic
Initiates packet processing upon completion of packet header parsing. It utilizes extracted header field information to perform table lookup, which determines the specific action to be executed on the packet.
- Table lookup
Defines the match table and application logic. Table lookup is performed by matching lookup keys against packet header fields.
- Action execution
Executes the action based on the lookup result. A table miss triggers the miss action.
Basic Syntax of a Control Block
control <control_name> (param1, param2, ...) {
@<pre/main/post>
table <table_name> {
key = {
<field_name>: <match_type>;
...
}
actions = {
<action_name0>;
<action_name1>;
...
}
default_action = <default_action>
size = <val>
timer_en = <true/false>
aging_time = <val>
}
apply {
//apply_result res = xxx.apply();
if(<table_name>.apply().hit){
...
}
}
}
Table
The table in a control block is used to define the flow table structure and describe a match-action collection.
- The @pre, @main, or @post annotation must be marked before the table to indicate the table type. For details about the specifications and constraints of different table types, see OVS Specifications.
- The @rss_fastpath annotation can be marked before the table to enable the Receive-Side Scaling (RSS) fast path.
The key list specifies the construction rule and matching mechanism for match fields. This version supports exact and ternary matching. Ternary matching is also known as fuzzy match. During the matching, AND operations are applied to the packet fields and a mask; the results are used for flow table lookup. You can construct a key using basic, header, and header_union types. If you construct a key using headers (with the @dpdk annotation) provided in hydra_builtin.hdr, standard
Header |
Included Field |
Corresponding DPDK Enumeration |
|---|---|---|
@dpdk header rte_eth_hdr_t |
bit<16> eth_type |
RTE_FLOW_ITEM_TYPE_ETH |
macAddr src |
||
macAddr dst |
||
@dpdk header rte_vlan_hdr_t |
bit<16> vlan_tci |
RTE_FLOW_ITEM_TYPE_VLAN |
@dpdk header rte_ipv4_hdr_t |
bit<8> protocol |
RTE_FLOW_ITEM_TYPE_IPV4 |
bit<32> src_ip |
||
bit<32> dst_ip |
||
@dpdk header rte_ipv6_hdr_t |
bit<8> protocol |
RTE_FLOW_ITEM_TYPE_IPV6 |
bit<128> src_ip |
||
bit<128> dst_ip |
||
@dpdk header rte_tcp_hdr_t |
bit<16> src_port |
RTE_FLOW_ITEM_TYPE_TCP |
bit<16> dst_port |
||
@dpdk header rte_udp_hdr_t |
bit<16> src_port |
RTE_FLOW_ITEM_TYPE_UDP |
bit<16> dst_port |
||
@dpdk header rte_icmp_hdr_t |
bit<8> type |
RTE_FLOW_ITEM_TYPE_ICMP |
bit<8> code |
||
bit<16> ident |
||
@dpdk header rte_icmp6_hdr_t |
bit<8> type |
RTE_FLOW_ITEM_TYPE_ICMP6 |
bit<8> code |
||
@dpdk header rte_vxlan_hdr_t |
bit<24> vni |
RTE_FLOW_ITEM_TYPE_VXLAN |
@dpdk header rte_port_id_hdr_t |
bit<16> port_id |
RTE_FLOW_ITEM_TYPE_PORT_ID |
@dpdk header rte_geneve_hdr_t |
bit<16> ver_opt_len_o_c_rsvd0 |
RTE_FLOW_ITEM_TYPE_GENEVE |
bit<16> protocol |
||
bit<24> vni |
||
bit<8> rsvd1 |
- This version does not support the use of expressions for key construction; for example, "a + b : exact" is not supported.
- The isValid() method of headers cannot be used to construct keys.
- Enumeration types cannot be used to construct keys.
- The number of custom keys cannot exceed 64.
- When utilizing the header_union type for key construction, the protocols corresponding to the header members cannot co-exist (e.g., a packet may contain either IPv4 or IPv6, not both).
- Key construction supports IPv4/IPv6 multiplexing at L3 and TCP/UDP/ICMP/ICMPv6 multiplexing at L4. The following default header_union structures are provided:
header_union ip_union { rte_ipv4_hdr_t dpdk_ipv4; rte_ipv6_hdr_t dpdk_ipv6; } header_union port_icmp_union { rte_tcp_hdr_t dpdk_tcp; rte_udp_hdr_t dpdk_udp; rte_icmp_hdr_t dpdk_icmp; rte_icmp6_hdr_t dpdk_icmp6; } header_union port_union { rte_tcp_hdr_t dpdk_tcp; rte_udp_hdr_t dpdk_udp; } header_union icmp_union { rte_icmp_hdr_t dpdk_icmp; rte_icmp6_hdr_t dpdk_icmp6; } - When utilizing the header_union type for key construction, setValid() must be explicitly called in the apply block to mark the protocol type that takes effect in header_union. The following uses ip_union as an example:
control Pipe(in headers hdr){ ip_union l3_union; table t{ ... key = { l3_union : exact; ... } ... } apply{ 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; } ... t.apply(); } }
Parameter |
Description |
|---|---|
Key collection |
Collection of information used for flow table matching, including built-in keys and user-defined keys. |
Action collection |
Actions executed upon table hits, including built-in actions and user-defined actions. |
default_action |
Action executed when the key has no matching entry.
|
size |
Optional. Number of entries in a table. The default value is 1024. size can only be a literal. Variables and expressions are not supported. The following is an example:
size = 0x1000000; // legal size = 16 * 1024 * 1024; // illegal |
aging_time |
Optional. Aging time, in seconds. The default value is 30. If the aging function is not required, set aging_time to 0. Its value ranges from 0 to 1098. |
- The programming framework supports the use of aging_time to customize hardware flow table aging intervals. The
DPAK 's original aging configuration item flow_max_idle is no longer effective under this framework. - For data beyond the committed constraints, the compiler automatically truncates the data during compilation, which may lead to unexpected errors.
apply
The apply method serves as the entry point for a control. In the apply block, you can invoke the apply method of a table to perform key construction and lookup operations. This method returns a structure containing {bool hit; bool miss; bool error;}. This structure type is declared in the architecture file.
The following MyPrePipe control defines a main table named fullnat_exact. It utilizes standard
control MyPrePipe(in headers hdr) {
rte_ipv4_hdr_t dpdk_ipv4;
rte_ipv6_hdr_t dpdk_ipv6;
bit<16> src_port;
bit<16> dst_port;
@main
table fullnat_exact {
key = {
dpdk_ipv4 : exact;
dpdk_ipv6 : exact;
src_port : exact;
dst_port : exact;
}
actions = {
ovs_action_mod_tos(hdr);
ovs_action_mod_ttl(hdr);
rte_port_id;
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 = 2097152;
default_action = flexda_upcall;
}
apply {
if (hdr.l3.ipv4.isValid()) {
dpdk_ipv4.protocol = hdr.l3.ipv4.protocol;
dpdk_ipv4.sip = hdr.l3.ipv4.sip;
dpdk_ipv4.dip = hdr.l3.ipv4.dip;
}
else if (hdr.l3.ipv6.isValid()) {
dpdk_ipv6.next_header = hdr.l3.ipv6.next_header;
dpdk_ipv6.sip = hdr.l3.ipv6.sip;
dpdk_ipv6.dip = hdr.l3.ipv6.dip;
}
if(hdr.l4.tcp.isValid()) {
src_port = hdr.l4.tcp.src_port;
dst_port = hdr.l4.tcp.dst_port;
}
else if (hdr.l4.udp.isValid()) {
src_port = hdr.l4.udp.src_port;
dst_port = hdr.l4.udp.dst_port;
}
if (hdr.l3.ipv4.isValid() && hdr.l3.ipv4.ttl > 1) {
fullnat_exact.apply();
}
}
}