---
title: control
description: "在 DSL 中，control是用于定义数据包处理逻辑的核心组件。control块负责在解析器解析出数据包的头部之后，根据表匹配的结果执行相应的动作，从而实现数据包的转发、修改或丢弃等功能。"
url: https://www.hikunpeng.com/document/detail/zh/flexda/devguide/dpak_dev0047.html
sourcePath: /source/zh/flexda/devguide/dpak_dev0047.html
indexId: af9533f86013760a20574552ef20fc2d56be4990cd5fda856239c5d35a18d8fa44
---
# control

在 DSL 中，control是用于定义数据包处理逻辑的核心组件。control块负责在解析器解析出数据包的头部之后，根据表匹配的结果执行相应的动作，从而实现数据包的转发、修改或丢弃等功能。

#### control的功能

- 连接parser和转发逻辑
  在数据包头部完成解析后，control块会对数据包进行处理，根据头部字段信息，通过匹配表查找来决定如何操作数据包。

- 表的匹配
  包含了匹配表的定义和应用逻辑，匹配表通过查找键（key）与数据包头部的字段进行匹配。

- action执行
  根据查找结果执行action，如果流表未命中则执行miss action。


#### control的基本语法

```
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

control中table用于定义流表结构，描述了一个match-action集合。

- table前需标注@pre、@main、@post注解说明表的类型。不同表类型的规格约束可参见  OVS规格
。
- table前可标注@rss_fastpath以使能RSS快路径。


key列表表示匹配字段的构造规则以及匹配方式，此版本支持exact和ternary匹配方式。其中ternary表示模糊匹配，在匹配过程中，先将数据包中的字段与mask进行与运算，然后根据与运算后的值去查找流表。用户可以使用基础类型、header类型和header_union类型组key。当用户使用hydra_builtin.hdr架构文件中提供的带@dpdk注解的header组key时，使用的是DPDK的标准枚举。架构文件支持DPDK的列表如表1所示。


**表1 架构文件支持 DPDK 枚举列表**

| header | 包含字段 | 对应DPDK枚举 |
| --- | --- | --- |
| @dpdk header rte\_eth\_hdr\_t | bit<16> eth\_type | RTE\_FLOW\_ITEM\_TYPE\_ETH |
| @dpdk header rte\_eth\_hdr\_t | macAddr src | RTE\_FLOW\_ITEM\_TYPE\_ETH |
| @dpdk header rte\_eth\_hdr\_t | macAddr dst | RTE\_FLOW\_ITEM\_TYPE\_ETH |
| @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 |
| @dpdk header rte\_ipv4\_hdr\_t | bit<32> src\_ip | RTE\_FLOW\_ITEM\_TYPE\_IPV4 |
| @dpdk header rte\_ipv4\_hdr\_t | bit<32> dst\_ip | RTE\_FLOW\_ITEM\_TYPE\_IPV4 |
| @dpdk header rte\_ipv6\_hdr\_t | bit<8> protocol | RTE\_FLOW\_ITEM\_TYPE\_IPV6 |
| @dpdk header rte\_ipv6\_hdr\_t | bit<128> src\_ip | RTE\_FLOW\_ITEM\_TYPE\_IPV6 |
| @dpdk header rte\_ipv6\_hdr\_t | bit<128> dst\_ip | RTE\_FLOW\_ITEM\_TYPE\_IPV6 |
| @dpdk header rte\_tcp\_hdr\_t | bit<16> src\_port | RTE\_FLOW\_ITEM\_TYPE\_TCP |
| @dpdk header rte\_tcp\_hdr\_t | bit<16> dst\_port | RTE\_FLOW\_ITEM\_TYPE\_TCP |
| @dpdk header rte\_udp\_hdr\_t | bit<16> src\_port | RTE\_FLOW\_ITEM\_TYPE\_UDP |
| @dpdk header rte\_udp\_hdr\_t | bit<16> dst\_port | RTE\_FLOW\_ITEM\_TYPE\_UDP |
| @dpdk header rte\_icmp\_hdr\_t | bit<8> type | RTE\_FLOW\_ITEM\_TYPE\_ICMP |
| @dpdk header rte\_icmp\_hdr\_t | bit<8> code | RTE\_FLOW\_ITEM\_TYPE\_ICMP |
| @dpdk header rte\_icmp\_hdr\_t | bit<16> ident | RTE\_FLOW\_ITEM\_TYPE\_ICMP |
| @dpdk header rte\_icmp6\_hdr\_t | bit<8> type | RTE\_FLOW\_ITEM\_TYPE\_ICMP6 |
| @dpdk header rte\_icmp6\_hdr\_t | bit<8> code | RTE\_FLOW\_ITEM\_TYPE\_ICMP6 |
| @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 |
| @dpdk header rte\_geneve\_hdr\_t | bit<16> protocol | RTE\_FLOW\_ITEM\_TYPE\_GENEVE |
| @dpdk header rte\_geneve\_hdr\_t | bit<24> vni | RTE\_FLOW\_ITEM\_TYPE\_GENEVE |
| @dpdk header rte\_geneve\_hdr\_t | bit<8> rsvd1 | RTE\_FLOW\_ITEM\_TYPE\_GENEVE |


- 当前版本不支持使用表达式组key，例如：a + b : exact是不被支持的。
- 当前版本不支持使用header的isValid()方法组key。
- 当前版本不支持使用枚举类型组key。
- 当前版本自定义key不可超过64个。
- 使用header_union类型组key时，其header成员对应的协议不应同时出现，例如IPv4和IPv6只会出现其中一种协议。
- 当前版本组key只支持L3层的IPv4/IPv6复用，L4层的TCP/UDP/ICMP/ICMP6复用，提供的默认header_union结构如下。

```
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;
}
```


- 使用header_union类型组key时，应在apply中显式调用setValid()，标记header_union中生效的协议类型。如下代码以ip_union为例。

```
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();
}
}
```


**表2 参数说明**

| 参数 | 说明 |
| --- | --- |
| key集合 | 用于进行流表匹配的信息集合，包含内置key和用户自定义key。 |
| actions集合 | 流表命中后可以执行的action，包含内置action和用户自定义action。 |
| default\_action | key没有匹配项时执行的action。 default\_action不能自定义，只能为架构文件中提供的flexda\_no\_action、flexda\_upcall、flexda\_drop三者之一。 如果不指定default\_action，则默认为flexda\_no\_action。 |
| size | table的表项条数。非必选项，默认值为1024。 size仅可为字面量，不支持变量和表达式。示例如下。 size = 0x1000000; // legal size = 16 \* 1024 \* 1024; // illegal |
| aging\_time | 老化时间，单位秒。非必选项，默认值为30。若不需要开启老化则需将aging\_time设置为0。aging\_time取值范围为[0,1098]。 |


- 因编程框架支持使用aging_time自定义硬件流表老化时间，所以原DPAK硬件流表老化配置项flow_max_idle在编程框架下配置不再生效。
- 对于承诺的约束范围外的数据，编译时编译器内部将自动截断，导致不可预知的错误。


#### apply

control中的apply方法是control的入口。在apply块中，可以调用table的apply方法进行该table的组key操作和查表操作，apply方法返回类型为一个包含{bool hit; bool miss; bool error;}的结构体。该结构体类型在架构文件中会声明。

下述MyPrePipe control定义了一张名为fullnat_exact的主表，使用标准 DPDK 枚举IPv4和IPv6、以及自定义src_port和dst_port作为key，流表条目为2M。在control的apply方法中根据报文解析的结果对变量进行填充，如果IPv4有效且ttl>1，则去匹配fullnat_exact流表，若命中则执行table actionsList中的actions，若未命中则执行default_action，即上送。示例代码如下所示。


```
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
();
}
}
}
```
