---
title: action
description: "Hydra的hydra_builtin.hdr架构文件中提供了一系列内置action，供用户使用，用户可在table的actionsList中直接声明需要的内置action。"
url: https://www.hikunpeng.com/document/detail/zh/flexda/devguide/dpak_dev0048.html
sourcePath: /source/zh/flexda/devguide/dpak_dev0048.html
indexId: e71b1ad199c4902cae8a12e451f5b8ade38de5d347b162bb347fd49c96ec2dd844
---
# action

#### 内置action

Hydra的hydra_builtin.hdr架构文件中提供了一系列内置action，供用户使用，用户可在table的actionsList中直接声明需要的内置action。


**表1 内置action**

| action签名 | 描述 | 约束 |
| --- | --- | --- |
| @flexda action flexda\_no\_action() | 流表miss后不进行任何操作。 | 仅可用于default\_action，不可用于table的actionsList中。 |
| @flexda @pre action flexda\_upcall() | 报文上送。 | 可用于default\_action，也可用于table的actionsList中。 |
| @flexda action flexda\_drop() | 流表miss后丢包。 | 仅可用于default\_action，不可用于table的actionsList中。 |
| @flexda @pre @main action flexda\_ct() | TCP状态报文上送。 | 此action存在时只会对TCP的状态报文进行上送处理，其他报文仍可正常执行其他action。 |
| @flexda @main action flexda\_inner\_rss(bit<8> rss) | 支持用户自定义指定报文层级的Inner RSS。 | 仅可用于主表。 最多支持两层隧道的Inner RSS。合法入参为0、1、2，此外的值会走默认RSS流程。 需要在报文解析里写到用于RSS的对应层级的报文的解析流程。 开源OVS场景下需额外编写控制面下发逻辑。 默认RSS：对于非隧道报文，TCP/UDP报文支持SIP、DIP、SPORT、DPORT进行散列，IP报文支持SIP、DIP进行散列，其他类型报文不散列。 默认RSS：对于一层隧道报文，VXLAN、GENEVE支持inner rss，具体散列方式参考非隧道报文；其他隧道报文视为非隧道报文进行散列。 默认RSS：对于多层隧道报文，视为一层隧道报文进行散列。 |
| @dpdk @persist action rte\_count() | 计数。 | 将隐式添加进每个table的actionsList，用户不可手动将其加到table的actionsList中。 |
| @dpdk @main action rte\_port\_id(bit<16> id) | 将报文发送到指定端口。 | 仅可用于主表。 |
| @dpdk action rte\_set\_mac\_src(macAddr\_t src) | 修改Ethernet报文头的src\_mac字段。 | 不涉及 |
| @dpdk action rte\_set\_mac\_dst(macAddr\_t dst) | 修改Ethernet报文头的dst\_mac字段。 | 不涉及 |
| @dpdk action rte\_set\_ipv4\_src(ip4Addr\_t src) | 修改IPv4报文头的src\_ip字段。 | 不涉及 |
| @dpdk action rte\_set\_ipv4\_dst(ip4Addr\_t dst) | 修改IPv4报文头的dst\_ip字段。 | 不涉及 |
| @dpdk action rte\_set\_ipv6\_src(ip6Addr\_t src) | 修改IPv6报文头的src\_ip字段。 | 不涉及 |
| @dpdk action rte\_set\_ipv6\_dst(ip6Addr\_t dst) | 修改IPv6报文头的dst\_ip字段。 | 不涉及 |
| @dpdk action rte\_set\_ttl(bit<8> ttl) | 修改IP报文的TTL值。 | 不涉及 |
| @dpdk action rte\_dec\_ttl() | IP报文的TTL值减1。 | 不涉及 |
| @dpdk action rte\_set\_tp\_src(portAddr\_t src) | 修改TCP/UDP报文头的src\_port字段。 | 不涉及 |
| @dpdk action rte\_set\_tp\_dst(portAddr\_t dst) | 修改TCP/UDP报文头的dst\_port字段。 | 不涉及 |
| @dpdk action rte\_of\_pop\_vlan() | 删除以太头中的VXLAN帧。 | 不涉及 |
| @dpdk action rte\_of\_push\_vlan(bit<16> vlan\_id) | 在以太头中插入VXLAN帧。 | 不涉及 |
| @dpdk action rte\_of\_set\_vlan\_vid(bit<16> vlan\_vid) | 修改VLAN帧的vid字段。 | 不涉及 |
| @dpdk action rte\_of\_set\_vlan\_pcp(bit<8> vlan\_pcp) | 修改VLAN帧的pcp字段。 | 不涉及 |
| @dpdk @encap action rte\_vxlan\_encap(bit<512> item) | 封装VXLAN隧道。 | 不涉及 |
| @dpdk @decap action rte\_vxlan\_decap() | 解封装VXLAN隧道。 | 不涉及 |
| @dpdk action rte\_queue(bit<8> queue\_index) {} | 将数据包上送到指定索引的upcall队列中。 | 下发queue action时为避免数据溢出，需要保证queue index小于256。当queue index大于等于256时，流表将下发失败。 执行Queue action时，在queue index超过端口配置的upcall queue数量时，对queue index配置的upcall queue数量取余。 |
| @dpdk action rte\_rss(bit<704> item) {} | 对数据包进行处理，根据提供的参数将它们散列到多个upcall队列中。 | 支持的hash func为RTE\_ETH\_HASH\_FUNCTION\_TOEPLITZ、RTE\_ETH\_HASH\_FUNCTION\_SIMPLE\_XOR、 RTE\_ETH\_HASH\_FUNCTION\_SYMMETRIC\_TOEPLITZ，即TOEPLITZ ，简单异或和对称TOEPLITZ。当用户未指定hash算法，即func = RTE\_ETH\_HASH\_FUNCTION\_DEFAULT时，将使用简单异或进行hash值的计算。 支持设置的level为0、1和2。 0和1表示外层报文头。2表示内层报文头，仅支持一层封装的内层报文头。 支持设置的types为RTE\_ETH\_RSS\_IPV4、RTE\_ETH\_RSS\_FRAG\_IPV4、RTE\_ETH\_RSS\_NONFRAG\_IPV4\_TCP、RTE\_ETH\_RSS\_NONFRAG\_IPV4\_UDP、RTE\_ETH\_RSS\_IPV6、RTE\_ETH\_RSS\_FRAG\_IPV6、RTE\_ETH\_RSS\_NONFRAG\_IPV6\_TCP、RTE\_ETH\_RSS\_NONFRAG\_IPV6\_UDP、RTE\_ETH\_RSS\_L2\_PAYLOAD、RTE\_ETH\_RSS\_IPV6\_EX、RTE\_ETH\_RSS\_IPV6\_TCP\_EX、RTE\_ETH\_RSS\_IPV6\_UDP\_EX。 当设置的types与数据包不匹配时，会进入默认的upcall流程。L3层types指定IPv4时仅匹配IPv4，指定IPv6时仅匹配IPv6。可以同时指定IPv4和IPv6，当IPv4和IPv6同时指定时，会根据实际的数据包进行匹配。 支持queue\_num范围为[0,32]。 queue\_num为0时，默认散列到端口配置各个upcall队列中。 设置queue数组时不能为空，且数组的有效长度需要和queue\_num保持一致。在queue index超过端口配置的upcall queue数量时，对queue index关于配置的upcall queue数量取余。 |


- 禁止修改内置action的相关声明，否则会造成不可预知的结果。
- 内置action不支持结构体作为入参，对应的流表DUMP展示时仅能显示原始的码流形式。


action的注释说明如下表2所示。


**表2 注释说明**

| 注释 | 说明 |
| --- | --- |
| @flexda | Flexda编程框架提供的内置action。 |
| @dpdk | 对应 DPDK 标准枚举的内置action。 |
| @persist | 该action会隐式加到每个table的actionsList中，用户不可手动加入。 |
| @pre | 前置action，可用于前置辅表。 |
| @main | 主action，可用于主表。 |
| @post | 后置action，可用于后置辅表。 |
| @encap | 隧道封装action，用户自定义的隧道封装action也需加上@encap注解。 |
| @decap | 隧道解封装action，用户自定义的隧道解封装action也需加上@decap注解。 |


未添加@pre、@main、@post枚举的action仅可用于主表。


#### 自定义action

对于内置action尚未支持的操作，用户可以通过自定义action来完成对应操作。Hydra中的action类似于其他语言中函数的概念，特殊之处在于action没有返回值，action的语法如下所示。


```
action max(in bit<16> a, action_data data) {
}
```

- action参数列表中有方向参数（in/out/inout）：表示来自数据面的参数。不应使用无方向的header或包含header的其他数据类型作为action的参数。
  数据面参数需在table的actionsList中进行绑定，如apply示例中的调用方式ovs_action_mod_tos(hdr);。

- action参数列表中的无方向参数：表示来自控制面的参数。
  控制面参数为流表命中后从表项中读取，所以无需在table的actionsList中绑定。


- 自定义action应定义在top-level，不应定义在control内。
- 自定义action仅支持一个数据面参数，且该参数仅可为所在control的第一个入参，参数方向只能是in。
- 自定义action可使用框架提供的extern接口实现用户自定义的报文编辑功能，报文编辑能力由extern接口规格说明统一限制。
- 自定义action的数量不可超过128个。
- 单个自定义action的action data的数据大小不可超过128Byte，若超过128Byte，action data中超出128Byte的部分会不符合预期。


用户自定义action可以调用extern func来对报文进行插入、删除、修改等一系列操作。以FullNAT为例，用户可以通过自定义action实现修改IPv4的TOS字段和TTL字段。

```
struct action_data {
bit<8>      tos;
}
action ovs_action_mod_tos(in headers hdr, action_data data) {
packet_incr_cs_param incr_checksum_para;
incr_checksum_para.old_val = (bit<32>)hdr.l3.ipv4.diff_serv;
incr_checksum_para.new_val = (bit<32>)data.tos;
incr_checksum_para.old_cs = hdr.l3.ipv4.hdr_checksum;
incr_checksum_para.cs_alg = RFC.RFC_1624;
hdr_packet_modify(hdr.l3.ipv4.diff_serv, data.tos);
hdr_packet_calc_checksum_incr(hdr.l3.ipv4.diff_serv, hdr.l3.ipv4.hdr_checksum, incr_checksum_para);
}
action ovs_action_mod_ttl(in headers hdr) {
packet_incr_cs_param incr_checksum_para;
incr_checksum_para.old_val = (bit<32>)hdr.l3.ipv4.ttl;
incr_checksum_para.new_val = (bit<32>)(hdr.l3.ipv4.ttl - 1);
incr_checksum_para.old_cs = hdr.l3.ipv4.hdr_checksum;
incr_checksum_para.cs_alg = RFC.RFC_1624;
hdr_packet_modify(hdr.l3.ipv4.ttl, hdr.l3.ipv4.ttl - 1);
hdr_packet_calc_checksum_incr(hdr.l3.ipv4.ttl, hdr.l3.ipv4.hdr_checksum, incr_checksum_para);
}
```
