[dpdk-dev,2/2] examples/ipsec-secgw: add target queues in flow actions

Message ID 6ac80a2be156911ee35c894924a02f04c43f49fc.1511449894.git.nelio.laranjeiro@6wind.com (mailing list archive)
State Superseded, archived
Delegated to: Pablo de Lara Guarch
Headers

Checks

Context Check Description
ci/Intel-compilation success Compilation OK
ci/checkpatch success coding style OK

Commit Message

Nélio Laranjeiro Nov. 23, 2017, 3:12 p.m. UTC
  Mellanox INNOVA NIC needs to have final target queue actions to perform
inline crypto.

Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
---
 examples/ipsec-secgw/ipsec.c | 27 ++++++++++++++++++++++++++-
 examples/ipsec-secgw/ipsec.h |  2 +-
 2 files changed, 27 insertions(+), 2 deletions(-)
  

Comments

Anoob Joseph Nov. 29, 2017, 12:30 p.m. UTC | #1
Hi Nelio,

Since support of RSS with inline crypto/protocol is hardware 
implementation dependent, it would be better if there is some sort of 
capability check before setting the flow parameters in the application.

If the hardware doesn't support RSS with inline processing, then the RSS 
flow action will have to be ignored in the driver. This wouldn't look 
right from application's point of view. And also the PMD would need 
application-specific logic to handle such cases, which may not scale well.

Thanks,
Anoob


On 11/23/2017 08:42 PM, Nelio Laranjeiro wrote:
> Mellanox INNOVA NIC needs to have final target queue actions to perform
> inline crypto.
>
> Signed-off-by: Nelio Laranjeiro <nelio.laranjeiro@6wind.com>
> ---
>   examples/ipsec-secgw/ipsec.c | 27 ++++++++++++++++++++++++++-
>   examples/ipsec-secgw/ipsec.h |  2 +-
>   2 files changed, 27 insertions(+), 2 deletions(-)
>
> diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
> index 17bd7620d..e967f88b3 100644
> --- a/examples/ipsec-secgw/ipsec.c
> +++ b/examples/ipsec-secgw/ipsec.c
> @@ -142,6 +142,22 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   							rte_eth_dev_get_sec_ctx(
>   							sa->portid);
>   			const struct rte_security_capability *sec_cap;
> +			uint8_t rss_key[40];
> +			struct rte_eth_rss_conf rss_conf = {
> +				.rss_key = rss_key,
> +				.rss_key_len = 40,
> +			};
> +			struct rte_eth_dev *eth_dev;
> +			union {
> +				struct rte_flow_action_rss rss;
> +				struct {
> +					const struct rte_eth_rss_conf *rss_conf;
> +					uint16_t num;
> +					uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
> +				} local;
> +			} action_rss;
> +			unsigned int i;
> +			unsigned int j;
>   
>   			sa->sec_session = rte_security_session_create(ctx,
>   					&sess_conf, ipsec_ctx->session_pool);
> @@ -201,7 +217,16 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>   			sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
>   			sa->action[0].conf = sa->sec_session;
>   
> -			sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
> +			sa->action[1].type = RTE_FLOW_ACTION_TYPE_RSS;
> +			sa->action[1].conf = &action_rss;
> +			eth_dev = ctx->device;
> +			rte_eth_dev_rss_hash_conf_get(sa->portid, &rss_conf);
> +			for (i = 0, j = 0; i < eth_dev->data->nb_rx_queues; ++i)
> +				if (eth_dev->data->rx_queues[i])
> +					action_rss.local.queue[j++] = i;
> +			action_rss.local.num = j;
> +			action_rss.local.rss_conf = &rss_conf;
> +			sa->action[2].type = RTE_FLOW_ACTION_TYPE_END;
>   
>   			sa->attr.egress = (sa->direction ==
>   					RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
> diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
> index 775b316ff..82ffc1c6d 100644
> --- a/examples/ipsec-secgw/ipsec.h
> +++ b/examples/ipsec-secgw/ipsec.h
> @@ -133,7 +133,7 @@ struct ipsec_sa {
>   	uint32_t ol_flags;
>   
>   #define MAX_RTE_FLOW_PATTERN (4)
> -#define MAX_RTE_FLOW_ACTIONS (2)
> +#define MAX_RTE_FLOW_ACTIONS (4)
>   	struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN];
>   	struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS];
>   	struct rte_flow_attr attr;
  
Nélio Laranjeiro Nov. 29, 2017, 12:50 p.m. UTC | #2
Hi Anoob,

On Wed, Nov 29, 2017 at 06:00:38PM +0530, Anoob wrote:
>    Hi Nelio,
> 
>    Since support of RSS with inline crypto/protocol is hardware
>    implementation dependent, it would be better if there is some sort of
>    capability check before setting the flow parameters in the application.
> 
>    If the hardware doesn't support RSS with inline processing, then the RSS
>    flow action will have to be ignored in the driver. This wouldn't look
>    right from application's point of view. And also the PMD would need
>    application-specific logic to handle such cases, which may not scale well.

There is a real issue here, RTE_FLOW API needs a terminal action, security is
not one [1] you must have one of the followings: QUEUE, DROP, RSS, PF,
VF or PASSTHRU.

Flow API does not work with "capabilities" as the application can verify
the rule using the validate().  If it cannot be validated the
application can test another kind of rule until the PMD returns a
success.

Here, I am proposing the RSS as RSS with a single queue is equivalent to queue.

On Mellanox NIC we need the RSS or QUEUE in ingress and for Egress PASSTHRU
is good.

What are your needs?

Regards,

>    Thanks,
>    Anoob
> 
>    On 11/23/2017 08:42 PM, Nelio Laranjeiro wrote:
> 
>  Mellanox INNOVA NIC needs to have final target queue actions to perform
>  inline crypto.
> 
>  Signed-off-by: Nelio Laranjeiro [1]<nelio.laranjeiro@6wind.com>
>  ---
>   examples/ipsec-secgw/ipsec.c | 27 ++++++++++++++++++++++++++-
>   examples/ipsec-secgw/ipsec.h |  2 +-
>   2 files changed, 27 insertions(+), 2 deletions(-)
> 
>  diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
>  index 17bd7620d..e967f88b3 100644
>  --- a/examples/ipsec-secgw/ipsec.c
>  +++ b/examples/ipsec-secgw/ipsec.c
>  @@ -142,6 +142,22 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>                                                          rte_eth_dev_get_sec_ctx(
>                                                          sa->portid);
>                          const struct rte_security_capability *sec_cap;
>  +                       uint8_t rss_key[40];
>  +                       struct rte_eth_rss_conf rss_conf = {
>  +                               .rss_key = rss_key,
>  +                               .rss_key_len = 40,
>  +                       };
>  +                       struct rte_eth_dev *eth_dev;
>  +                       union {
>  +                               struct rte_flow_action_rss rss;
>  +                               struct {
>  +                                       const struct rte_eth_rss_conf *rss_conf;
>  +                                       uint16_t num;
>  +                                       uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
>  +                               } local;
>  +                       } action_rss;
>  +                       unsigned int i;
>  +                       unsigned int j;
> 
>                          sa->sec_session = rte_security_session_create(ctx,
>                                          &sess_conf, ipsec_ctx->session_pool);
>  @@ -201,7 +217,16 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>                          sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
>                          sa->action[0].conf = sa->sec_session;
> 
>  -                       sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
>  +                       sa->action[1].type = RTE_FLOW_ACTION_TYPE_RSS;
>  +                       sa->action[1].conf = &action_rss;
>  +                       eth_dev = ctx->device;
>  +                       rte_eth_dev_rss_hash_conf_get(sa->portid, &rss_conf);
>  +                       for (i = 0, j = 0; i < eth_dev->data->nb_rx_queues; ++i)
>  +                               if (eth_dev->data->rx_queues[i])
>  +                                       action_rss.local.queue[j++] = i;
>  +                       action_rss.local.num = j;
>  +                       action_rss.local.rss_conf = &rss_conf;
>  +                       sa->action[2].type = RTE_FLOW_ACTION_TYPE_END;
> 
>                          sa->attr.egress = (sa->direction ==
>                                          RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
>  diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
>  index 775b316ff..82ffc1c6d 100644
>  --- a/examples/ipsec-secgw/ipsec.h
>  +++ b/examples/ipsec-secgw/ipsec.h
>  @@ -133,7 +133,7 @@ struct ipsec_sa {
>          uint32_t ol_flags;
> 
>   #define MAX_RTE_FLOW_PATTERN (4)
>  -#define MAX_RTE_FLOW_ACTIONS (2)
>  +#define MAX_RTE_FLOW_ACTIONS (4)
>          struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN];
>          struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS];
>          struct rte_flow_attr attr;
> 
> References
> 
>    Visible links
>    1. mailto:nelio.laranjeiro@6wind.com

[1] http://dpdk.org/doc/guides/prog_guide/rte_flow.html?highlight=rte_flow#actions
  
Anoob Joseph Nov. 30, 2017, 10:46 a.m. UTC | #3
Hi Nelio,

Please see inline.

Thanks,

Anoob


On 11/29/2017 06:20 PM, Nelio Laranjeiro wrote:
> Hi Anoob,
>
> On Wed, Nov 29, 2017 at 06:00:38PM +0530, Anoob wrote:
>>     Hi Nelio,
>>
>>     Since support of RSS with inline crypto/protocol is hardware
>>     implementation dependent, it would be better if there is some sort of
>>     capability check before setting the flow parameters in the application.
>>
>>     If the hardware doesn't support RSS with inline processing, then the RSS
>>     flow action will have to be ignored in the driver. This wouldn't look
>>     right from application's point of view. And also the PMD would need
>>     application-specific logic to handle such cases, which may not scale well.
> There is a real issue here, RTE_FLOW API needs a terminal action, security is
> not one [1] you must have one of the followings: QUEUE, DROP, RSS, PF,
> VF or PASSTHRU.
>
> Flow API does not work with "capabilities" as the application can verify
> the rule using the validate().  If it cannot be validated the
> application can test another kind of rule until the PMD returns a
> success.
>
> Here, I am proposing the RSS as RSS with a single queue is equivalent to queue.
>
> On Mellanox NIC we need the RSS or QUEUE in ingress and for Egress PASSTHRU
> is good.
>
> What are your needs?
Thanks for the clarification. Understood the issue here. On Cavium 
hardware SECURITY will be terminating. So a better approach would be to 
first check from the application (using rte_flow_verify()) if SECURITY 
is terminating action. If it fails, then application can do RSS/QUEUE. 
That should solve the issue.
>
> Regards,
>
>>     Thanks,
>>     Anoob
>>
>>     On 11/23/2017 08:42 PM, Nelio Laranjeiro wrote:
>>
>>   Mellanox INNOVA NIC needs to have final target queue actions to perform
>>   inline crypto.
>>
>>   Signed-off-by: Nelio Laranjeiro [1]<nelio.laranjeiro@6wind.com>
>>   ---
>>    examples/ipsec-secgw/ipsec.c | 27 ++++++++++++++++++++++++++-
>>    examples/ipsec-secgw/ipsec.h |  2 +-
>>    2 files changed, 27 insertions(+), 2 deletions(-)
>>
>>   diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
>>   index 17bd7620d..e967f88b3 100644
>>   --- a/examples/ipsec-secgw/ipsec.c
>>   +++ b/examples/ipsec-secgw/ipsec.c
>>   @@ -142,6 +142,22 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>>                                                           rte_eth_dev_get_sec_ctx(
>>                                                           sa->portid);
>>                           const struct rte_security_capability *sec_cap;
>>   +                       uint8_t rss_key[40];
>>   +                       struct rte_eth_rss_conf rss_conf = {
>>   +                               .rss_key = rss_key,
>>   +                               .rss_key_len = 40,
>>   +                       };
>>   +                       struct rte_eth_dev *eth_dev;
>>   +                       union {
>>   +                               struct rte_flow_action_rss rss;
>>   +                               struct {
>>   +                                       const struct rte_eth_rss_conf *rss_conf;
>>   +                                       uint16_t num;
>>   +                                       uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
>>   +                               } local;
>>   +                       } action_rss;
>>   +                       unsigned int i;
>>   +                       unsigned int j;
>>
>>                           sa->sec_session = rte_security_session_create(ctx,
>>                                           &sess_conf, ipsec_ctx->session_pool);
>>   @@ -201,7 +217,16 @@ create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
>>                           sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
>>                           sa->action[0].conf = sa->sec_session;
>>
>>   -                       sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
>>   +                       sa->action[1].type = RTE_FLOW_ACTION_TYPE_RSS;
>>   +                       sa->action[1].conf = &action_rss;
>>   +                       eth_dev = ctx->device;
>>   +                       rte_eth_dev_rss_hash_conf_get(sa->portid, &rss_conf);
>>   +                       for (i = 0, j = 0; i < eth_dev->data->nb_rx_queues; ++i)
>>   +                               if (eth_dev->data->rx_queues[i])
>>   +                                       action_rss.local.queue[j++] = i;
>>   +                       action_rss.local.num = j;
>>   +                       action_rss.local.rss_conf = &rss_conf;
>>   +                       sa->action[2].type = RTE_FLOW_ACTION_TYPE_END;
>>
>>                           sa->attr.egress = (sa->direction ==
>>                                           RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
>>   diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
>>   index 775b316ff..82ffc1c6d 100644
>>   --- a/examples/ipsec-secgw/ipsec.h
>>   +++ b/examples/ipsec-secgw/ipsec.h
>>   @@ -133,7 +133,7 @@ struct ipsec_sa {
>>           uint32_t ol_flags;
>>
>>    #define MAX_RTE_FLOW_PATTERN (4)
>>   -#define MAX_RTE_FLOW_ACTIONS (2)
>>   +#define MAX_RTE_FLOW_ACTIONS (4)
>>           struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN];
>>           struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS];
>>           struct rte_flow_attr attr;
>>
>> References
>>
>>     Visible links
>>     1. mailto:nelio.laranjeiro@6wind.com
> [1] http://dpdk.org/doc/guides/prog_guide/rte_flow.html?highlight=rte_flow#actions
>
  
Nélio Laranjeiro Nov. 30, 2017, 12:28 p.m. UTC | #4
Hi Annob,

On Thu, Nov 30, 2017 at 04:16:23PM +0530, Anoob wrote:
> On 11/29/2017 06:20 PM, Nelio Laranjeiro wrote:
> > Hi Anoob,
> > 
> > On Wed, Nov 29, 2017 at 06:00:38PM +0530, Anoob wrote:
> > >     Hi Nelio,
> > > 
> > >     Since support of RSS with inline crypto/protocol is hardware
> > >     implementation dependent, it would be better if there is some sort of
> > >     capability check before setting the flow parameters in the application.
> > > 
> > >     If the hardware doesn't support RSS with inline processing, then the RSS
> > >     flow action will have to be ignored in the driver. This wouldn't look
> > >     right from application's point of view. And also the PMD would need
> > >     application-specific logic to handle such cases, which may not scale well.
> > There is a real issue here, RTE_FLOW API needs a terminal action, security is
> > not one [1] you must have one of the followings: QUEUE, DROP, RSS, PF,
> > VF or PASSTHRU.
> > 
> > Flow API does not work with "capabilities" as the application can verify
> > the rule using the validate().  If it cannot be validated the
> > application can test another kind of rule until the PMD returns a
> > success.
> > 
> > Here, I am proposing the RSS as RSS with a single queue is equivalent to queue.
> > 
> > On Mellanox NIC we need the RSS or QUEUE in ingress and for Egress PASSTHRU
> > is good.
> > 
> > What are your needs?
> Thanks for the clarification. Understood the issue here. On Cavium hardware
> SECURITY will be terminating.

You should finalise with PASSTHRU to be compliant with the API,
otherwise application makers won't understand why it does not work
according to the API implementation.

> So a better approach would be to first check from the application
> (using rte_flow_verify()) if SECURITY is terminating action. If it
> fails, then application can do RSS/QUEUE. That should solve
> the issue.
<snip>

I think we have an agreement here, in order the final action to be
tested:

 1. PASSTHRU
 2. RSS
 3. QUEUE

If those 3 fails, the functions fails to create the rule, the first
succeeding is the one applied.

Do you agree?

Thanks,
  
Anoob Joseph Dec. 1, 2017, 3:04 p.m. UTC | #5
Hi Nelio,

On 30-11-2017 17:58, Nelio Laranjeiro wrote:
> Hi Annob,
>
> On Thu, Nov 30, 2017 at 04:16:23PM +0530, Anoob wrote:
>> On 11/29/2017 06:20 PM, Nelio Laranjeiro wrote:
>>> Hi Anoob,
>>>
>>> On Wed, Nov 29, 2017 at 06:00:38PM +0530, Anoob wrote:
>>>>      Hi Nelio,
>>>>
>>>>      Since support of RSS with inline crypto/protocol is hardware
>>>>      implementation dependent, it would be better if there is some sort of
>>>>      capability check before setting the flow parameters in the application.
>>>>
>>>>      If the hardware doesn't support RSS with inline processing, then the RSS
>>>>      flow action will have to be ignored in the driver. This wouldn't look
>>>>      right from application's point of view. And also the PMD would need
>>>>      application-specific logic to handle such cases, which may not scale well.
>>> There is a real issue here, RTE_FLOW API needs a terminal action, security is
>>> not one [1] you must have one of the followings: QUEUE, DROP, RSS, PF,
>>> VF or PASSTHRU.
>>>
>>> Flow API does not work with "capabilities" as the application can verify
>>> the rule using the validate().  If it cannot be validated the
>>> application can test another kind of rule until the PMD returns a
>>> success.
>>>
>>> Here, I am proposing the RSS as RSS with a single queue is equivalent to queue.
>>>
>>> On Mellanox NIC we need the RSS or QUEUE in ingress and for Egress PASSTHRU
>>> is good.
>>>
>>> What are your needs?
>> Thanks for the clarification. Understood the issue here. On Cavium hardware
>> SECURITY will be terminating.
> You should finalise with PASSTHRU to be compliant with the API,
> otherwise application makers won't understand why it does not work
> according to the API implementation.
Cavium hardware would be supporting only terminating actions. So 
PASSTHRU will not be supported.
>> So a better approach would be to first check from the application
>> (using rte_flow_verify()) if SECURITY is terminating action. If it
>> fails, then application can do RSS/QUEUE. That should solve
>> the issue.
> <snip>
>
> I think we have an agreement here, in order the final action to be
> tested:
>
>   1. PASSTHRU
>   2. RSS
>   3. QUEUE
>
> If those 3 fails, the functions fails to create the rule, the first
> succeeding is the one applied.
PASSTHRU itself is non-terminating, right? So I'm not sure, how a check 
with PASSTHRU would help us. SECURITY will be terminating action on 
Cavium hardware. So, the first check could be without any addition. If 
that fails, RSS. And then QUEUE. That should be fine.

Any thoughts?
Anoob
>
> Do you agree?
>
> Thanks,
>
  
Nélio Laranjeiro Dec. 1, 2017, 4:26 p.m. UTC | #6
Hi Annob

On Fri, Dec 01, 2017 at 08:34:04PM +0530, Anoob Joseph wrote:
<snip>
> > 
> > I think we have an agreement here, in order the final action to be
> > tested:
> > 
> >   1. PASSTHRU
> >   2. RSS
> >   3. QUEUE
> > 
> > If those 3 fails, the functions fails to create the rule, the first
> > succeeding is the one applied.
> PASSTHRU itself is non-terminating, right? So I'm not sure, how a check with
> PASSTHRU would help us. SECURITY will be terminating action on Cavium
> hardware. So, the first check could be without any addition. If that fails,
> RSS. And then QUEUE. That should be fine.

Agreed, assuming PASSTHRU [1] is not mandatory (i.e. explicit) when the
rule action list is not terminal.

A small suggestion, you should accept/ignore such action in your PMD,
the API also allows applications to add it.

Thanks,

[1] http://dpdk.org/doc/guides/prog_guide/rte_flow.html#action-types
  

Patch

diff --git a/examples/ipsec-secgw/ipsec.c b/examples/ipsec-secgw/ipsec.c
index 17bd7620d..e967f88b3 100644
--- a/examples/ipsec-secgw/ipsec.c
+++ b/examples/ipsec-secgw/ipsec.c
@@ -142,6 +142,22 @@  create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
 							rte_eth_dev_get_sec_ctx(
 							sa->portid);
 			const struct rte_security_capability *sec_cap;
+			uint8_t rss_key[40];
+			struct rte_eth_rss_conf rss_conf = {
+				.rss_key = rss_key,
+				.rss_key_len = 40,
+			};
+			struct rte_eth_dev *eth_dev;
+			union {
+				struct rte_flow_action_rss rss;
+				struct {
+					const struct rte_eth_rss_conf *rss_conf;
+					uint16_t num;
+					uint16_t queue[RTE_MAX_QUEUES_PER_PORT];
+				} local;
+			} action_rss;
+			unsigned int i;
+			unsigned int j;
 
 			sa->sec_session = rte_security_session_create(ctx,
 					&sess_conf, ipsec_ctx->session_pool);
@@ -201,7 +217,16 @@  create_session(struct ipsec_ctx *ipsec_ctx, struct ipsec_sa *sa)
 			sa->action[0].type = RTE_FLOW_ACTION_TYPE_SECURITY;
 			sa->action[0].conf = sa->sec_session;
 
-			sa->action[1].type = RTE_FLOW_ACTION_TYPE_END;
+			sa->action[1].type = RTE_FLOW_ACTION_TYPE_RSS;
+			sa->action[1].conf = &action_rss;
+			eth_dev = ctx->device;
+			rte_eth_dev_rss_hash_conf_get(sa->portid, &rss_conf);
+			for (i = 0, j = 0; i < eth_dev->data->nb_rx_queues; ++i)
+				if (eth_dev->data->rx_queues[i])
+					action_rss.local.queue[j++] = i;
+			action_rss.local.num = j;
+			action_rss.local.rss_conf = &rss_conf;
+			sa->action[2].type = RTE_FLOW_ACTION_TYPE_END;
 
 			sa->attr.egress = (sa->direction ==
 					RTE_SECURITY_IPSEC_SA_DIR_EGRESS);
diff --git a/examples/ipsec-secgw/ipsec.h b/examples/ipsec-secgw/ipsec.h
index 775b316ff..82ffc1c6d 100644
--- a/examples/ipsec-secgw/ipsec.h
+++ b/examples/ipsec-secgw/ipsec.h
@@ -133,7 +133,7 @@  struct ipsec_sa {
 	uint32_t ol_flags;
 
 #define MAX_RTE_FLOW_PATTERN (4)
-#define MAX_RTE_FLOW_ACTIONS (2)
+#define MAX_RTE_FLOW_ACTIONS (4)
 	struct rte_flow_item pattern[MAX_RTE_FLOW_PATTERN];
 	struct rte_flow_action action[MAX_RTE_FLOW_ACTIONS];
 	struct rte_flow_attr attr;