common/cnxk: support for dual VLAN insert and strip actions

Message ID 20210719054157.1665582-1-psatheesh@marvell.com (mailing list archive)
State Accepted, archived
Delegated to: Jerin Jacob
Headers
Series common/cnxk: support for dual VLAN insert and strip actions |

Checks

Context Check Description
ci/checkpatch success coding style OK
ci/github-robot success github build: passed
ci/iol-intel-Functional success Functional Testing PASS
ci/iol-abi-testing success Testing PASS
ci/iol-testing success Testing PASS
ci/iol-intel-Performance success Performance Testing PASS
ci/Intel-compilation success Compilation OK
ci/intel-Testing success Testing PASS

Commit Message

Satheesh Paul Antonysamy July 19, 2021, 5:41 a.m. UTC
  From: Satheesh Paul <psatheesh@marvell.com>

Add roc API to configure dual VLAN tag addition and removal.

Signed-off-by: Satheesh Paul <psatheesh@marvell.com>
---
 drivers/common/cnxk/roc_npc.c      | 339 ++++++++++++++++++++++-------
 drivers/common/cnxk/roc_npc.h      |   1 +
 drivers/common/cnxk/roc_npc_priv.h |  11 +-
 3 files changed, 267 insertions(+), 84 deletions(-)
  

Comments

Jerin Jacob Sept. 7, 2021, 1:58 a.m. UTC | #1
On Mon, Jul 19, 2021 at 11:12 AM <psatheesh@marvell.com> wrote:
>
> From: Satheesh Paul <psatheesh@marvell.com>
>
> Add roc API to configure dual VLAN tag addition and removal.
>
> Signed-off-by: Satheesh Paul <psatheesh@marvell.com>

Added following in release notes
+* **Updated Marvell cnxk ethdev driver.**
+
+  * Added rte_flow support for dual VLAN insert and strip actions
+


Applied to dpdk-next-net-mrvl/for-next-net. Thanks


> ---
>  drivers/common/cnxk/roc_npc.c      | 339 ++++++++++++++++++++++-------
>  drivers/common/cnxk/roc_npc.h      |   1 +
>  drivers/common/cnxk/roc_npc_priv.h |  11 +-
>  3 files changed, 267 insertions(+), 84 deletions(-)
>
> diff --git a/drivers/common/cnxk/roc_npc.c b/drivers/common/cnxk/roc_npc.c
> index aff4eef554..52a54b3990 100644
> --- a/drivers/common/cnxk/roc_npc.c
> +++ b/drivers/common/cnxk/roc_npc.c
> @@ -10,7 +10,7 @@ roc_npc_vtag_actions_get(struct roc_npc *roc_npc)
>  {
>         struct npc *npc = roc_npc_to_npc_priv(roc_npc);
>
> -       return npc->vtag_actions;
> +       return npc->vtag_strip_actions;
>  }
>
>  int
> @@ -18,8 +18,8 @@ roc_npc_vtag_actions_sub_return(struct roc_npc *roc_npc, uint32_t count)
>  {
>         struct npc *npc = roc_npc_to_npc_priv(roc_npc);
>
> -       npc->vtag_actions -= count;
> -       return npc->vtag_actions;
> +       npc->vtag_strip_actions -= count;
> +       return npc->vtag_strip_actions;
>  }
>
>  int
> @@ -481,6 +481,23 @@ npc_parse_actions(struct npc *npc, const struct roc_npc_attr *attr,
>                         goto err_exit;
>                 }
>
> +               if (req_act &
> +                   ~(ROC_NPC_ACTION_TYPE_VLAN_INSERT |
> +                     ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT |
> +                     ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT |
> +                     ROC_NPC_ACTION_TYPE_DROP | ROC_NPC_ACTION_TYPE_COUNT)) {
> +                       plt_err("Only VLAN insert, drop, count supported on Egress");
> +                       errcode = NPC_ERR_ACTION_NOTSUP;
> +                       goto err_exit;
> +               }
> +
> +               if (vlan_insert_action &&
> +                   (req_act & ROC_NPC_ACTION_TYPE_DROP)) {
> +                       plt_err("Both VLAN insert and drop actions cannot be supported");
> +                       errcode = NPC_ERR_ACTION_NOTSUP;
> +                       goto err_exit;
> +               }
> +
>                 if (req_act & ROC_NPC_ACTION_TYPE_DROP) {
>                         flow->npc_action = NIX_TX_ACTIONOP_DROP;
>                 } else if ((req_act & ROC_NPC_ACTION_TYPE_COUNT) ||
> @@ -526,14 +543,14 @@ npc_parse_actions(struct npc *npc, const struct roc_npc_attr *attr,
>         }
>
>         if (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP)
> -               npc->vtag_actions++;
> -
> -       /* Only VLAN action is provided */
> -       if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
> -               flow->npc_action = NIX_RX_ACTIONOP_UCAST;
> +               npc->vtag_strip_actions++;
>
>         /* Set NIX_RX_ACTIONOP */
> -       if (req_act & (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
> +       if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
> +               /* Only VLAN action is provided */
> +               flow->npc_action = NIX_RX_ACTIONOP_UCAST;
> +       } else if (req_act &
> +                  (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
>                 flow->npc_action = NIX_RX_ACTIONOP_UCAST;
>                 if (req_act & ROC_NPC_ACTION_TYPE_QUEUE)
>                         flow->npc_action |= (uint64_t)rq << 20;
> @@ -872,6 +889,11 @@ npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
>         vtag_cfg->tx.vtag0_idx = tx_vtag_action.act.vtag0_def;
>         vtag_cfg->tx.free_vtag0 = true;
>
> +       if (flow->vtag_insert_count == 2) {
> +               vtag_cfg->tx.vtag1_idx = tx_vtag_action.act.vtag1_def;
> +               vtag_cfg->tx.free_vtag1 = true;
> +       }
> +
>         rc = mbox_process_msg(mbox, (void *)&rsp);
>         if (rc)
>                 return rc;
> @@ -880,120 +902,271 @@ npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
>  }
>
>  static int
> -npc_vtag_action_program(struct roc_npc *roc_npc,
> -                       const struct roc_npc_action actions[],
> -                       struct roc_npc_flow *flow)
> +npc_vtag_insert_action_parse(const struct roc_npc_action actions[],
> +                            struct roc_npc_flow *flow,
> +                            struct npc_action_vtag_info *vlan_info,
> +                            int *parsed_cnt)
>  {
> -       uint16_t vlan_id = 0, vlan_ethtype = ROC_ETHER_TYPE_VLAN;
> -       struct npc *npc = roc_npc_to_npc_priv(roc_npc);
> -       struct roc_nix *roc_nix = roc_npc->roc_nix;
> -       struct nix_vtag_config *vtag_cfg;
> -       struct nix_vtag_config_rsp *rsp;
> -       uint64_t rx_vtag_action = 0;
> -       uint8_t vlan_pcp = 0;
> -       struct mbox *mbox;
> -       struct nix *nix;
> -       int rc;
> -
> -       union {
> -               uint64_t reg;
> -               struct nix_tx_vtag_action_s act;
> -       } tx_vtag_action;
> -
> -       nix = roc_nix_to_nix_priv(roc_nix);
> -       mbox = (&nix->dev)->mbox;
> -
> -       flow->vtag_insert_enabled = false;
> -
> -       for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
> -               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
> -                       if (npc->vtag_actions == 1) {
> -                               vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
> +       bool vlan_id_found = false, ethtype_found = false, pcp_found = false;
> +       int count = 0;
>
> -                               if (vtag_cfg == NULL)
> -                                       return -ENOSPC;
> +       *parsed_cnt = 0;
>
> -                               vtag_cfg->cfg_type = VTAG_RX;
> -                               vtag_cfg->rx.strip_vtag = 1;
> -                               /* Always capture */
> -                               vtag_cfg->rx.capture_vtag = 1;
> -                               vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
> -                               vtag_cfg->rx.vtag_type = 0;
> +       /* This function parses parameters of one VLAN. When a parameter is
> +        * found repeated, it treats it as the end of first VLAN's parameters
> +        * and returns. The caller calls again to parse the parameters of the
> +        * second VLAN.
> +        */
>
> -                               rc = mbox_process(mbox);
> -                               if (rc)
> -                                       return rc;
> -                       }
> +       for (; count < NPC_ACTION_MAX_VLAN_PARAMS; count++, actions++) {
> +               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
> +                       if (vlan_id_found)
> +                               return 0;
>
> -                       rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
> -                       rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
> -                       rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
> -                       flow->vtag_action = rx_vtag_action;
> -               } else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
>                         const struct roc_npc_action_of_set_vlan_vid *vtag =
>                                 (const struct roc_npc_action_of_set_vlan_vid *)
>                                         actions->conf;
> -                       vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
> -                       if (vlan_id > 0xfff) {
> +
> +                       vlan_info->vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
> +
> +                       if (vlan_info->vlan_id > 0xfff) {
>                                 plt_err("Invalid vlan_id for set vlan action");
>                                 return -EINVAL;
>                         }
> +
>                         flow->vtag_insert_enabled = true;
> +                       (*parsed_cnt)++;
> +                       vlan_id_found = true;
>                 } else if (actions->type ==
>                            ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT) {
> +                       if (ethtype_found)
> +                               return 0;
> +
>                         const struct roc_npc_action_of_push_vlan *ethtype =
>                                 (const struct roc_npc_action_of_push_vlan *)
>                                         actions->conf;
> -                       vlan_ethtype = plt_be_to_cpu_16(ethtype->ethertype);
> -                       if (vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
> -                           vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
> +                       vlan_info->vlan_ethtype =
> +                               plt_be_to_cpu_16(ethtype->ethertype);
> +                       if (vlan_info->vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
> +                           vlan_info->vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
>                                 plt_err("Invalid ethtype specified for push"
>                                         " vlan action");
>                                 return -EINVAL;
>                         }
>                         flow->vtag_insert_enabled = true;
> +                       (*parsed_cnt)++;
> +                       ethtype_found = true;
>                 } else if (actions->type ==
>                            ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
> +                       if (pcp_found)
> +                               return 0;
>                         const struct roc_npc_action_of_set_vlan_pcp *pcp =
>                                 (const struct roc_npc_action_of_set_vlan_pcp *)
>                                         actions->conf;
> -                       vlan_pcp = pcp->vlan_pcp;
> -                       if (vlan_pcp > 0x7) {
> +                       vlan_info->vlan_pcp = pcp->vlan_pcp;
> +                       if (vlan_info->vlan_pcp > 0x7) {
>                                 plt_err("Invalid PCP value for pcp action");
>                                 return -EINVAL;
>                         }
>                         flow->vtag_insert_enabled = true;
> +                       (*parsed_cnt)++;
> +                       pcp_found = true;
> +               } else {
> +                       return 0;
>                 }
>         }
>
> -       if (flow->vtag_insert_enabled) {
> -               vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
> +       return 0;
> +}
>
> -               if (vtag_cfg == NULL)
> -                       return -ENOSPC;
> +static int
> +npc_vtag_insert_action_configure(struct mbox *mbox, struct roc_npc_flow *flow,
> +                                struct npc_action_vtag_info *vlan_info)
> +{
> +       struct nix_vtag_config *vtag_cfg;
> +       struct nix_vtag_config_rsp *rsp;
> +       int rc = 0;
>
> -               vtag_cfg->cfg_type = VTAG_TX;
> -               vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
> -               vtag_cfg->tx.vtag0 =
> -                       ((vlan_ethtype << 16) | (vlan_pcp << 13) | vlan_id);
> +       union {
> +               uint64_t reg;
> +               struct nix_tx_vtag_action_s act;
> +       } tx_vtag_action;
>
> -               vtag_cfg->tx.cfg_vtag0 = 1;
> -               rc = mbox_process_msg(mbox, (void *)&rsp);
> -               if (rc)
> -                       return rc;
> +       vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
>
> -               if (rsp->vtag0_idx < 0) {
> -                       plt_err("Failed to config TX VTAG action");
> -                       return -EINVAL;
> -               }
> +       if (vtag_cfg == NULL)
> +               return -ENOSPC;
> +
> +       vtag_cfg->cfg_type = VTAG_TX;
> +       vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
> +       vtag_cfg->tx.vtag0 =
> +               ((vlan_info[0].vlan_ethtype << 16) |
> +                (vlan_info[0].vlan_pcp << 13) | vlan_info[0].vlan_id);
> +
> +       vtag_cfg->tx.cfg_vtag0 = 1;
> +
> +       if (flow->vtag_insert_count == 2) {
> +               vtag_cfg->tx.vtag1 =
> +                       ((vlan_info[1].vlan_ethtype << 16) |
> +                        (vlan_info[1].vlan_pcp << 13) | vlan_info[1].vlan_id);
> +
> +               vtag_cfg->tx.cfg_vtag1 = 1;
> +       }
> +
> +       rc = mbox_process_msg(mbox, (void *)&rsp);
> +       if (rc)
> +               return rc;
> +
> +       if (rsp->vtag0_idx < 0 ||
> +           ((flow->vtag_insert_count == 2) && (rsp->vtag1_idx < 0))) {
> +               plt_err("Failed to config TX VTAG action");
> +               return -EINVAL;
> +       }
>
> -               tx_vtag_action.reg = 0;
> -               tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
> -               tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
> -               tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
> -               tx_vtag_action.act.vtag0_relptr =
> +       tx_vtag_action.reg = 0;
> +       tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
> +       tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
> +       tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
> +       tx_vtag_action.act.vtag0_relptr = NIX_TX_VTAGACTION_VTAG0_RELPTR;
> +
> +       if (flow->vtag_insert_count == 2) {
> +               tx_vtag_action.act.vtag1_def = rsp->vtag1_idx;
> +               tx_vtag_action.act.vtag1_lid = NPC_LID_LA;
> +               tx_vtag_action.act.vtag1_op = NIX_TX_VTAGOP_INSERT;
> +               /* NIX_TX_VTAG_ACTION_S
> +                *  If Vtag 0 is inserted, hardware adjusts the Vtag 1 byte
> +                *  offset accordingly. Thus, if the two offsets are equal in
> +                *  the structure, hardware inserts Vtag 1 immediately after
> +                *  Vtag 0 in the packet.
> +                */
> +               tx_vtag_action.act.vtag1_relptr =
>                         NIX_TX_VTAGACTION_VTAG0_RELPTR;
> -               flow->vtag_action = tx_vtag_action.reg;
> +       }
> +
> +       flow->vtag_action = tx_vtag_action.reg;
> +
> +       return 0;
> +}
> +
> +static int
> +npc_vtag_strip_action_configure(struct mbox *mbox,
> +                               const struct roc_npc_action actions[],
> +                               struct roc_npc_flow *flow, int *strip_cnt)
> +{
> +       struct nix_vtag_config *vtag_cfg;
> +       uint64_t rx_vtag_action = 0;
> +       int count = 0, rc = 0;
> +
> +       *strip_cnt = 0;
> +
> +       for (; count < NPC_ACTION_MAX_VLANS_STRIPPED; count++, actions++) {
> +               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
> +                       (*strip_cnt)++;
> +       }
> +
> +       vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
> +
> +       if (vtag_cfg == NULL)
> +               return -ENOSPC;
> +
> +       vtag_cfg->cfg_type = VTAG_RX;
> +       vtag_cfg->rx.strip_vtag = 1;
> +       /* Always capture */
> +       vtag_cfg->rx.capture_vtag = 1;
> +       vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
> +       vtag_cfg->rx.vtag_type = 0;
> +
> +       rc = mbox_process(mbox);
> +       if (rc)
> +               return rc;
> +
> +       rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
> +       rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
> +       rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
> +
> +       if (*strip_cnt == 2) {
> +               rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 47);
> +               rx_vtag_action |= ((uint64_t)NPC_LID_LB << 40);
> +               rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR << 32;
> +       }
> +       flow->vtag_action = rx_vtag_action;
> +
> +       return 0;
> +}
> +
> +static int
> +npc_vtag_action_program(struct roc_npc *roc_npc,
> +                       const struct roc_npc_action actions[],
> +                       struct roc_npc_flow *flow)
> +{
> +       bool vlan_strip_parsed = false, vlan_insert_parsed = false;
> +       const struct roc_npc_action *insert_actions;
> +       struct roc_nix *roc_nix = roc_npc->roc_nix;
> +       struct npc_action_vtag_info vlan_info[2];
> +       int parsed_cnt = 0, strip_cnt = 0;
> +       int tot_vlan_params = 0;
> +       struct mbox *mbox;
> +       struct nix *nix;
> +       int i, rc;
> +
> +       nix = roc_nix_to_nix_priv(roc_nix);
> +       mbox = (&nix->dev)->mbox;
> +
> +       memset(vlan_info, 0, sizeof(vlan_info));
> +
> +       flow->vtag_insert_enabled = false;
> +
> +       for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
> +               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
> +                       if (vlan_strip_parsed) {
> +                               plt_err("Incorrect VLAN strip actions");
> +                               return -EINVAL;
> +                       }
> +                       rc = npc_vtag_strip_action_configure(mbox, actions,
> +                                                            flow, &strip_cnt);
> +                       if (rc)
> +                               return rc;
> +
> +                       if (strip_cnt == 2)
> +                               actions++;
> +
> +                       vlan_strip_parsed = true;
> +               } else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT ||
> +                          actions->type ==
> +                                  ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT ||
> +                          actions->type ==
> +                                  ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
> +                       if (vlan_insert_parsed) {
> +                               plt_err("Incorrect VLAN insert actions");
> +                               return -EINVAL;
> +                       }
> +
> +                       insert_actions = actions;
> +
> +                       for (i = 0; i < 2; i++) {
> +                               rc = npc_vtag_insert_action_parse(
> +                                       insert_actions, flow, &vlan_info[i],
> +                                       &parsed_cnt);
> +
> +                               if (rc)
> +                                       return rc;
> +
> +                               if (parsed_cnt) {
> +                                       insert_actions += parsed_cnt;
> +                                       tot_vlan_params += parsed_cnt;
> +                                       flow->vtag_insert_count++;
> +                               }
> +                       }
> +                       actions += tot_vlan_params - 1;
> +                       vlan_insert_parsed = true;
> +               }
> +       }
> +
> +       if (flow->vtag_insert_enabled) {
> +               rc = npc_vtag_insert_action_configure(mbox, flow, vlan_info);
> +
> +               if (rc)
> +                       return rc;
>         }
>         return 0;
>  }
> diff --git a/drivers/common/cnxk/roc_npc.h b/drivers/common/cnxk/roc_npc.h
> index 2c0a536c93..e86595fe9a 100644
> --- a/drivers/common/cnxk/roc_npc.h
> +++ b/drivers/common/cnxk/roc_npc.h
> @@ -124,6 +124,7 @@ struct roc_npc_flow {
>         uint64_t npc_action;
>         uint64_t vtag_action;
>         bool vtag_insert_enabled;
> +       uint8_t vtag_insert_count;
>  #define ROC_NPC_MAX_FLOW_PATTERNS 32
>         struct roc_npc_flow_dump_data dump_data[ROC_NPC_MAX_FLOW_PATTERNS];
>         uint16_t num_patterns;
> diff --git a/drivers/common/cnxk/roc_npc_priv.h b/drivers/common/cnxk/roc_npc_priv.h
> index 484c3aeb1f..1ba8adcd4b 100644
> --- a/drivers/common/cnxk/roc_npc_priv.h
> +++ b/drivers/common/cnxk/roc_npc_priv.h
> @@ -57,6 +57,15 @@
>         (NPC_NIXLF_MAX * NPC_MCAME_PER_LF +                                    \
>          (NPC_RVUPF_MAX_10XX - 1) * NPC_MCAME_PER_PF)
>
> +#define NPC_ACTION_MAX_VLAN_PARAMS    3
> +#define NPC_ACTION_MAX_VLANS_STRIPPED 2
> +
> +struct npc_action_vtag_info {
> +       uint16_t vlan_id;
> +       uint16_t vlan_ethtype;
> +       uint8_t vlan_pcp;
> +};
> +
>  enum npc_err_status {
>         NPC_ERR_PARAM = -1024,
>         NPC_ERR_NO_MEM,
> @@ -350,7 +359,7 @@ struct npc {
>         uint16_t flow_max_priority;             /* Max priority for flow */
>         uint16_t switch_header_type; /* Suppprted switch header type */
>         uint32_t mark_actions;       /* Number of mark actions */
> -       uint32_t vtag_actions;       /* vtag insert/strip actions */
> +       uint32_t vtag_strip_actions; /* vtag insert/strip actions */
>         uint16_t pf_func;            /* pf_func of device */
>         npc_dxcfg_t prx_dxcfg;       /* intf, lid, lt, extract */
>         npc_fxcfg_t prx_fxcfg;       /* Flag extract */
> --
> 2.25.4
>
  
Jerin Jacob Sept. 16, 2021, 2:30 p.m. UTC | #2
On Tue, Sep 7, 2021 at 7:28 AM Jerin Jacob <jerinjacobk@gmail.com> wrote:
>
> On Mon, Jul 19, 2021 at 11:12 AM <psatheesh@marvell.com> wrote:
> >
> > From: Satheesh Paul <psatheesh@marvell.com>
> >
> > Add roc API to configure dual VLAN tag addition and removal.
> >
> > Signed-off-by: Satheesh Paul <psatheesh@marvell.com>


Acked-by: Jerin Jacob <jerinj@marvell.com>


>
> Added following in release notes
> +* **Updated Marvell cnxk ethdev driver.**
> +
> +  * Added rte_flow support for dual VLAN insert and strip actions
> +
>
>
> Applied to dpdk-next-net-mrvl/for-next-net. Thanks
>
>
> > ---
> >  drivers/common/cnxk/roc_npc.c      | 339 ++++++++++++++++++++++-------
> >  drivers/common/cnxk/roc_npc.h      |   1 +
> >  drivers/common/cnxk/roc_npc_priv.h |  11 +-
> >  3 files changed, 267 insertions(+), 84 deletions(-)
> >
> > diff --git a/drivers/common/cnxk/roc_npc.c b/drivers/common/cnxk/roc_npc.c
> > index aff4eef554..52a54b3990 100644
> > --- a/drivers/common/cnxk/roc_npc.c
> > +++ b/drivers/common/cnxk/roc_npc.c
> > @@ -10,7 +10,7 @@ roc_npc_vtag_actions_get(struct roc_npc *roc_npc)
> >  {
> >         struct npc *npc = roc_npc_to_npc_priv(roc_npc);
> >
> > -       return npc->vtag_actions;
> > +       return npc->vtag_strip_actions;
> >  }
> >
> >  int
> > @@ -18,8 +18,8 @@ roc_npc_vtag_actions_sub_return(struct roc_npc *roc_npc, uint32_t count)
> >  {
> >         struct npc *npc = roc_npc_to_npc_priv(roc_npc);
> >
> > -       npc->vtag_actions -= count;
> > -       return npc->vtag_actions;
> > +       npc->vtag_strip_actions -= count;
> > +       return npc->vtag_strip_actions;
> >  }
> >
> >  int
> > @@ -481,6 +481,23 @@ npc_parse_actions(struct npc *npc, const struct roc_npc_attr *attr,
> >                         goto err_exit;
> >                 }
> >
> > +               if (req_act &
> > +                   ~(ROC_NPC_ACTION_TYPE_VLAN_INSERT |
> > +                     ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT |
> > +                     ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT |
> > +                     ROC_NPC_ACTION_TYPE_DROP | ROC_NPC_ACTION_TYPE_COUNT)) {
> > +                       plt_err("Only VLAN insert, drop, count supported on Egress");
> > +                       errcode = NPC_ERR_ACTION_NOTSUP;
> > +                       goto err_exit;
> > +               }
> > +
> > +               if (vlan_insert_action &&
> > +                   (req_act & ROC_NPC_ACTION_TYPE_DROP)) {
> > +                       plt_err("Both VLAN insert and drop actions cannot be supported");
> > +                       errcode = NPC_ERR_ACTION_NOTSUP;
> > +                       goto err_exit;
> > +               }
> > +
> >                 if (req_act & ROC_NPC_ACTION_TYPE_DROP) {
> >                         flow->npc_action = NIX_TX_ACTIONOP_DROP;
> >                 } else if ((req_act & ROC_NPC_ACTION_TYPE_COUNT) ||
> > @@ -526,14 +543,14 @@ npc_parse_actions(struct npc *npc, const struct roc_npc_attr *attr,
> >         }
> >
> >         if (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP)
> > -               npc->vtag_actions++;
> > -
> > -       /* Only VLAN action is provided */
> > -       if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
> > -               flow->npc_action = NIX_RX_ACTIONOP_UCAST;
> > +               npc->vtag_strip_actions++;
> >
> >         /* Set NIX_RX_ACTIONOP */
> > -       if (req_act & (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
> > +       if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
> > +               /* Only VLAN action is provided */
> > +               flow->npc_action = NIX_RX_ACTIONOP_UCAST;
> > +       } else if (req_act &
> > +                  (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
> >                 flow->npc_action = NIX_RX_ACTIONOP_UCAST;
> >                 if (req_act & ROC_NPC_ACTION_TYPE_QUEUE)
> >                         flow->npc_action |= (uint64_t)rq << 20;
> > @@ -872,6 +889,11 @@ npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
> >         vtag_cfg->tx.vtag0_idx = tx_vtag_action.act.vtag0_def;
> >         vtag_cfg->tx.free_vtag0 = true;
> >
> > +       if (flow->vtag_insert_count == 2) {
> > +               vtag_cfg->tx.vtag1_idx = tx_vtag_action.act.vtag1_def;
> > +               vtag_cfg->tx.free_vtag1 = true;
> > +       }
> > +
> >         rc = mbox_process_msg(mbox, (void *)&rsp);
> >         if (rc)
> >                 return rc;
> > @@ -880,120 +902,271 @@ npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
> >  }
> >
> >  static int
> > -npc_vtag_action_program(struct roc_npc *roc_npc,
> > -                       const struct roc_npc_action actions[],
> > -                       struct roc_npc_flow *flow)
> > +npc_vtag_insert_action_parse(const struct roc_npc_action actions[],
> > +                            struct roc_npc_flow *flow,
> > +                            struct npc_action_vtag_info *vlan_info,
> > +                            int *parsed_cnt)
> >  {
> > -       uint16_t vlan_id = 0, vlan_ethtype = ROC_ETHER_TYPE_VLAN;
> > -       struct npc *npc = roc_npc_to_npc_priv(roc_npc);
> > -       struct roc_nix *roc_nix = roc_npc->roc_nix;
> > -       struct nix_vtag_config *vtag_cfg;
> > -       struct nix_vtag_config_rsp *rsp;
> > -       uint64_t rx_vtag_action = 0;
> > -       uint8_t vlan_pcp = 0;
> > -       struct mbox *mbox;
> > -       struct nix *nix;
> > -       int rc;
> > -
> > -       union {
> > -               uint64_t reg;
> > -               struct nix_tx_vtag_action_s act;
> > -       } tx_vtag_action;
> > -
> > -       nix = roc_nix_to_nix_priv(roc_nix);
> > -       mbox = (&nix->dev)->mbox;
> > -
> > -       flow->vtag_insert_enabled = false;
> > -
> > -       for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
> > -               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
> > -                       if (npc->vtag_actions == 1) {
> > -                               vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
> > +       bool vlan_id_found = false, ethtype_found = false, pcp_found = false;
> > +       int count = 0;
> >
> > -                               if (vtag_cfg == NULL)
> > -                                       return -ENOSPC;
> > +       *parsed_cnt = 0;
> >
> > -                               vtag_cfg->cfg_type = VTAG_RX;
> > -                               vtag_cfg->rx.strip_vtag = 1;
> > -                               /* Always capture */
> > -                               vtag_cfg->rx.capture_vtag = 1;
> > -                               vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
> > -                               vtag_cfg->rx.vtag_type = 0;
> > +       /* This function parses parameters of one VLAN. When a parameter is
> > +        * found repeated, it treats it as the end of first VLAN's parameters
> > +        * and returns. The caller calls again to parse the parameters of the
> > +        * second VLAN.
> > +        */
> >
> > -                               rc = mbox_process(mbox);
> > -                               if (rc)
> > -                                       return rc;
> > -                       }
> > +       for (; count < NPC_ACTION_MAX_VLAN_PARAMS; count++, actions++) {
> > +               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
> > +                       if (vlan_id_found)
> > +                               return 0;
> >
> > -                       rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
> > -                       rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
> > -                       rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
> > -                       flow->vtag_action = rx_vtag_action;
> > -               } else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
> >                         const struct roc_npc_action_of_set_vlan_vid *vtag =
> >                                 (const struct roc_npc_action_of_set_vlan_vid *)
> >                                         actions->conf;
> > -                       vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
> > -                       if (vlan_id > 0xfff) {
> > +
> > +                       vlan_info->vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
> > +
> > +                       if (vlan_info->vlan_id > 0xfff) {
> >                                 plt_err("Invalid vlan_id for set vlan action");
> >                                 return -EINVAL;
> >                         }
> > +
> >                         flow->vtag_insert_enabled = true;
> > +                       (*parsed_cnt)++;
> > +                       vlan_id_found = true;
> >                 } else if (actions->type ==
> >                            ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT) {
> > +                       if (ethtype_found)
> > +                               return 0;
> > +
> >                         const struct roc_npc_action_of_push_vlan *ethtype =
> >                                 (const struct roc_npc_action_of_push_vlan *)
> >                                         actions->conf;
> > -                       vlan_ethtype = plt_be_to_cpu_16(ethtype->ethertype);
> > -                       if (vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
> > -                           vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
> > +                       vlan_info->vlan_ethtype =
> > +                               plt_be_to_cpu_16(ethtype->ethertype);
> > +                       if (vlan_info->vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
> > +                           vlan_info->vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
> >                                 plt_err("Invalid ethtype specified for push"
> >                                         " vlan action");
> >                                 return -EINVAL;
> >                         }
> >                         flow->vtag_insert_enabled = true;
> > +                       (*parsed_cnt)++;
> > +                       ethtype_found = true;
> >                 } else if (actions->type ==
> >                            ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
> > +                       if (pcp_found)
> > +                               return 0;
> >                         const struct roc_npc_action_of_set_vlan_pcp *pcp =
> >                                 (const struct roc_npc_action_of_set_vlan_pcp *)
> >                                         actions->conf;
> > -                       vlan_pcp = pcp->vlan_pcp;
> > -                       if (vlan_pcp > 0x7) {
> > +                       vlan_info->vlan_pcp = pcp->vlan_pcp;
> > +                       if (vlan_info->vlan_pcp > 0x7) {
> >                                 plt_err("Invalid PCP value for pcp action");
> >                                 return -EINVAL;
> >                         }
> >                         flow->vtag_insert_enabled = true;
> > +                       (*parsed_cnt)++;
> > +                       pcp_found = true;
> > +               } else {
> > +                       return 0;
> >                 }
> >         }
> >
> > -       if (flow->vtag_insert_enabled) {
> > -               vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
> > +       return 0;
> > +}
> >
> > -               if (vtag_cfg == NULL)
> > -                       return -ENOSPC;
> > +static int
> > +npc_vtag_insert_action_configure(struct mbox *mbox, struct roc_npc_flow *flow,
> > +                                struct npc_action_vtag_info *vlan_info)
> > +{
> > +       struct nix_vtag_config *vtag_cfg;
> > +       struct nix_vtag_config_rsp *rsp;
> > +       int rc = 0;
> >
> > -               vtag_cfg->cfg_type = VTAG_TX;
> > -               vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
> > -               vtag_cfg->tx.vtag0 =
> > -                       ((vlan_ethtype << 16) | (vlan_pcp << 13) | vlan_id);
> > +       union {
> > +               uint64_t reg;
> > +               struct nix_tx_vtag_action_s act;
> > +       } tx_vtag_action;
> >
> > -               vtag_cfg->tx.cfg_vtag0 = 1;
> > -               rc = mbox_process_msg(mbox, (void *)&rsp);
> > -               if (rc)
> > -                       return rc;
> > +       vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
> >
> > -               if (rsp->vtag0_idx < 0) {
> > -                       plt_err("Failed to config TX VTAG action");
> > -                       return -EINVAL;
> > -               }
> > +       if (vtag_cfg == NULL)
> > +               return -ENOSPC;
> > +
> > +       vtag_cfg->cfg_type = VTAG_TX;
> > +       vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
> > +       vtag_cfg->tx.vtag0 =
> > +               ((vlan_info[0].vlan_ethtype << 16) |
> > +                (vlan_info[0].vlan_pcp << 13) | vlan_info[0].vlan_id);
> > +
> > +       vtag_cfg->tx.cfg_vtag0 = 1;
> > +
> > +       if (flow->vtag_insert_count == 2) {
> > +               vtag_cfg->tx.vtag1 =
> > +                       ((vlan_info[1].vlan_ethtype << 16) |
> > +                        (vlan_info[1].vlan_pcp << 13) | vlan_info[1].vlan_id);
> > +
> > +               vtag_cfg->tx.cfg_vtag1 = 1;
> > +       }
> > +
> > +       rc = mbox_process_msg(mbox, (void *)&rsp);
> > +       if (rc)
> > +               return rc;
> > +
> > +       if (rsp->vtag0_idx < 0 ||
> > +           ((flow->vtag_insert_count == 2) && (rsp->vtag1_idx < 0))) {
> > +               plt_err("Failed to config TX VTAG action");
> > +               return -EINVAL;
> > +       }
> >
> > -               tx_vtag_action.reg = 0;
> > -               tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
> > -               tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
> > -               tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
> > -               tx_vtag_action.act.vtag0_relptr =
> > +       tx_vtag_action.reg = 0;
> > +       tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
> > +       tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
> > +       tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
> > +       tx_vtag_action.act.vtag0_relptr = NIX_TX_VTAGACTION_VTAG0_RELPTR;
> > +
> > +       if (flow->vtag_insert_count == 2) {
> > +               tx_vtag_action.act.vtag1_def = rsp->vtag1_idx;
> > +               tx_vtag_action.act.vtag1_lid = NPC_LID_LA;
> > +               tx_vtag_action.act.vtag1_op = NIX_TX_VTAGOP_INSERT;
> > +               /* NIX_TX_VTAG_ACTION_S
> > +                *  If Vtag 0 is inserted, hardware adjusts the Vtag 1 byte
> > +                *  offset accordingly. Thus, if the two offsets are equal in
> > +                *  the structure, hardware inserts Vtag 1 immediately after
> > +                *  Vtag 0 in the packet.
> > +                */
> > +               tx_vtag_action.act.vtag1_relptr =
> >                         NIX_TX_VTAGACTION_VTAG0_RELPTR;
> > -               flow->vtag_action = tx_vtag_action.reg;
> > +       }
> > +
> > +       flow->vtag_action = tx_vtag_action.reg;
> > +
> > +       return 0;
> > +}
> > +
> > +static int
> > +npc_vtag_strip_action_configure(struct mbox *mbox,
> > +                               const struct roc_npc_action actions[],
> > +                               struct roc_npc_flow *flow, int *strip_cnt)
> > +{
> > +       struct nix_vtag_config *vtag_cfg;
> > +       uint64_t rx_vtag_action = 0;
> > +       int count = 0, rc = 0;
> > +
> > +       *strip_cnt = 0;
> > +
> > +       for (; count < NPC_ACTION_MAX_VLANS_STRIPPED; count++, actions++) {
> > +               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
> > +                       (*strip_cnt)++;
> > +       }
> > +
> > +       vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
> > +
> > +       if (vtag_cfg == NULL)
> > +               return -ENOSPC;
> > +
> > +       vtag_cfg->cfg_type = VTAG_RX;
> > +       vtag_cfg->rx.strip_vtag = 1;
> > +       /* Always capture */
> > +       vtag_cfg->rx.capture_vtag = 1;
> > +       vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
> > +       vtag_cfg->rx.vtag_type = 0;
> > +
> > +       rc = mbox_process(mbox);
> > +       if (rc)
> > +               return rc;
> > +
> > +       rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
> > +       rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
> > +       rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
> > +
> > +       if (*strip_cnt == 2) {
> > +               rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 47);
> > +               rx_vtag_action |= ((uint64_t)NPC_LID_LB << 40);
> > +               rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR << 32;
> > +       }
> > +       flow->vtag_action = rx_vtag_action;
> > +
> > +       return 0;
> > +}
> > +
> > +static int
> > +npc_vtag_action_program(struct roc_npc *roc_npc,
> > +                       const struct roc_npc_action actions[],
> > +                       struct roc_npc_flow *flow)
> > +{
> > +       bool vlan_strip_parsed = false, vlan_insert_parsed = false;
> > +       const struct roc_npc_action *insert_actions;
> > +       struct roc_nix *roc_nix = roc_npc->roc_nix;
> > +       struct npc_action_vtag_info vlan_info[2];
> > +       int parsed_cnt = 0, strip_cnt = 0;
> > +       int tot_vlan_params = 0;
> > +       struct mbox *mbox;
> > +       struct nix *nix;
> > +       int i, rc;
> > +
> > +       nix = roc_nix_to_nix_priv(roc_nix);
> > +       mbox = (&nix->dev)->mbox;
> > +
> > +       memset(vlan_info, 0, sizeof(vlan_info));
> > +
> > +       flow->vtag_insert_enabled = false;
> > +
> > +       for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
> > +               if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
> > +                       if (vlan_strip_parsed) {
> > +                               plt_err("Incorrect VLAN strip actions");
> > +                               return -EINVAL;
> > +                       }
> > +                       rc = npc_vtag_strip_action_configure(mbox, actions,
> > +                                                            flow, &strip_cnt);
> > +                       if (rc)
> > +                               return rc;
> > +
> > +                       if (strip_cnt == 2)
> > +                               actions++;
> > +
> > +                       vlan_strip_parsed = true;
> > +               } else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT ||
> > +                          actions->type ==
> > +                                  ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT ||
> > +                          actions->type ==
> > +                                  ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
> > +                       if (vlan_insert_parsed) {
> > +                               plt_err("Incorrect VLAN insert actions");
> > +                               return -EINVAL;
> > +                       }
> > +
> > +                       insert_actions = actions;
> > +
> > +                       for (i = 0; i < 2; i++) {
> > +                               rc = npc_vtag_insert_action_parse(
> > +                                       insert_actions, flow, &vlan_info[i],
> > +                                       &parsed_cnt);
> > +
> > +                               if (rc)
> > +                                       return rc;
> > +
> > +                               if (parsed_cnt) {
> > +                                       insert_actions += parsed_cnt;
> > +                                       tot_vlan_params += parsed_cnt;
> > +                                       flow->vtag_insert_count++;
> > +                               }
> > +                       }
> > +                       actions += tot_vlan_params - 1;
> > +                       vlan_insert_parsed = true;
> > +               }
> > +       }
> > +
> > +       if (flow->vtag_insert_enabled) {
> > +               rc = npc_vtag_insert_action_configure(mbox, flow, vlan_info);
> > +
> > +               if (rc)
> > +                       return rc;
> >         }
> >         return 0;
> >  }
> > diff --git a/drivers/common/cnxk/roc_npc.h b/drivers/common/cnxk/roc_npc.h
> > index 2c0a536c93..e86595fe9a 100644
> > --- a/drivers/common/cnxk/roc_npc.h
> > +++ b/drivers/common/cnxk/roc_npc.h
> > @@ -124,6 +124,7 @@ struct roc_npc_flow {
> >         uint64_t npc_action;
> >         uint64_t vtag_action;
> >         bool vtag_insert_enabled;
> > +       uint8_t vtag_insert_count;
> >  #define ROC_NPC_MAX_FLOW_PATTERNS 32
> >         struct roc_npc_flow_dump_data dump_data[ROC_NPC_MAX_FLOW_PATTERNS];
> >         uint16_t num_patterns;
> > diff --git a/drivers/common/cnxk/roc_npc_priv.h b/drivers/common/cnxk/roc_npc_priv.h
> > index 484c3aeb1f..1ba8adcd4b 100644
> > --- a/drivers/common/cnxk/roc_npc_priv.h
> > +++ b/drivers/common/cnxk/roc_npc_priv.h
> > @@ -57,6 +57,15 @@
> >         (NPC_NIXLF_MAX * NPC_MCAME_PER_LF +                                    \
> >          (NPC_RVUPF_MAX_10XX - 1) * NPC_MCAME_PER_PF)
> >
> > +#define NPC_ACTION_MAX_VLAN_PARAMS    3
> > +#define NPC_ACTION_MAX_VLANS_STRIPPED 2
> > +
> > +struct npc_action_vtag_info {
> > +       uint16_t vlan_id;
> > +       uint16_t vlan_ethtype;
> > +       uint8_t vlan_pcp;
> > +};
> > +
> >  enum npc_err_status {
> >         NPC_ERR_PARAM = -1024,
> >         NPC_ERR_NO_MEM,
> > @@ -350,7 +359,7 @@ struct npc {
> >         uint16_t flow_max_priority;             /* Max priority for flow */
> >         uint16_t switch_header_type; /* Suppprted switch header type */
> >         uint32_t mark_actions;       /* Number of mark actions */
> > -       uint32_t vtag_actions;       /* vtag insert/strip actions */
> > +       uint32_t vtag_strip_actions; /* vtag insert/strip actions */
> >         uint16_t pf_func;            /* pf_func of device */
> >         npc_dxcfg_t prx_dxcfg;       /* intf, lid, lt, extract */
> >         npc_fxcfg_t prx_fxcfg;       /* Flag extract */
> > --
> > 2.25.4
> >
  

Patch

diff --git a/drivers/common/cnxk/roc_npc.c b/drivers/common/cnxk/roc_npc.c
index aff4eef554..52a54b3990 100644
--- a/drivers/common/cnxk/roc_npc.c
+++ b/drivers/common/cnxk/roc_npc.c
@@ -10,7 +10,7 @@  roc_npc_vtag_actions_get(struct roc_npc *roc_npc)
 {
 	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
 
-	return npc->vtag_actions;
+	return npc->vtag_strip_actions;
 }
 
 int
@@ -18,8 +18,8 @@  roc_npc_vtag_actions_sub_return(struct roc_npc *roc_npc, uint32_t count)
 {
 	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
 
-	npc->vtag_actions -= count;
-	return npc->vtag_actions;
+	npc->vtag_strip_actions -= count;
+	return npc->vtag_strip_actions;
 }
 
 int
@@ -481,6 +481,23 @@  npc_parse_actions(struct npc *npc, const struct roc_npc_attr *attr,
 			goto err_exit;
 		}
 
+		if (req_act &
+		    ~(ROC_NPC_ACTION_TYPE_VLAN_INSERT |
+		      ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT |
+		      ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT |
+		      ROC_NPC_ACTION_TYPE_DROP | ROC_NPC_ACTION_TYPE_COUNT)) {
+			plt_err("Only VLAN insert, drop, count supported on Egress");
+			errcode = NPC_ERR_ACTION_NOTSUP;
+			goto err_exit;
+		}
+
+		if (vlan_insert_action &&
+		    (req_act & ROC_NPC_ACTION_TYPE_DROP)) {
+			plt_err("Both VLAN insert and drop actions cannot be supported");
+			errcode = NPC_ERR_ACTION_NOTSUP;
+			goto err_exit;
+		}
+
 		if (req_act & ROC_NPC_ACTION_TYPE_DROP) {
 			flow->npc_action = NIX_TX_ACTIONOP_DROP;
 		} else if ((req_act & ROC_NPC_ACTION_TYPE_COUNT) ||
@@ -526,14 +543,14 @@  npc_parse_actions(struct npc *npc, const struct roc_npc_attr *attr,
 	}
 
 	if (req_act & ROC_NPC_ACTION_TYPE_VLAN_STRIP)
-		npc->vtag_actions++;
-
-	/* Only VLAN action is provided */
-	if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
-		flow->npc_action = NIX_RX_ACTIONOP_UCAST;
+		npc->vtag_strip_actions++;
 
 	/* Set NIX_RX_ACTIONOP */
-	if (req_act & (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
+	if (req_act == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
+		/* Only VLAN action is provided */
+		flow->npc_action = NIX_RX_ACTIONOP_UCAST;
+	} else if (req_act &
+		   (ROC_NPC_ACTION_TYPE_PF | ROC_NPC_ACTION_TYPE_VF)) {
 		flow->npc_action = NIX_RX_ACTIONOP_UCAST;
 		if (req_act & ROC_NPC_ACTION_TYPE_QUEUE)
 			flow->npc_action |= (uint64_t)rq << 20;
@@ -872,6 +889,11 @@  npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
 	vtag_cfg->tx.vtag0_idx = tx_vtag_action.act.vtag0_def;
 	vtag_cfg->tx.free_vtag0 = true;
 
+	if (flow->vtag_insert_count == 2) {
+		vtag_cfg->tx.vtag1_idx = tx_vtag_action.act.vtag1_def;
+		vtag_cfg->tx.free_vtag1 = true;
+	}
+
 	rc = mbox_process_msg(mbox, (void *)&rsp);
 	if (rc)
 		return rc;
@@ -880,120 +902,271 @@  npc_vtag_cfg_delete(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
 }
 
 static int
-npc_vtag_action_program(struct roc_npc *roc_npc,
-			const struct roc_npc_action actions[],
-			struct roc_npc_flow *flow)
+npc_vtag_insert_action_parse(const struct roc_npc_action actions[],
+			     struct roc_npc_flow *flow,
+			     struct npc_action_vtag_info *vlan_info,
+			     int *parsed_cnt)
 {
-	uint16_t vlan_id = 0, vlan_ethtype = ROC_ETHER_TYPE_VLAN;
-	struct npc *npc = roc_npc_to_npc_priv(roc_npc);
-	struct roc_nix *roc_nix = roc_npc->roc_nix;
-	struct nix_vtag_config *vtag_cfg;
-	struct nix_vtag_config_rsp *rsp;
-	uint64_t rx_vtag_action = 0;
-	uint8_t vlan_pcp = 0;
-	struct mbox *mbox;
-	struct nix *nix;
-	int rc;
-
-	union {
-		uint64_t reg;
-		struct nix_tx_vtag_action_s act;
-	} tx_vtag_action;
-
-	nix = roc_nix_to_nix_priv(roc_nix);
-	mbox = (&nix->dev)->mbox;
-
-	flow->vtag_insert_enabled = false;
-
-	for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
-		if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
-			if (npc->vtag_actions == 1) {
-				vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+	bool vlan_id_found = false, ethtype_found = false, pcp_found = false;
+	int count = 0;
 
-				if (vtag_cfg == NULL)
-					return -ENOSPC;
+	*parsed_cnt = 0;
 
-				vtag_cfg->cfg_type = VTAG_RX;
-				vtag_cfg->rx.strip_vtag = 1;
-				/* Always capture */
-				vtag_cfg->rx.capture_vtag = 1;
-				vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
-				vtag_cfg->rx.vtag_type = 0;
+	/* This function parses parameters of one VLAN. When a parameter is
+	 * found repeated, it treats it as the end of first VLAN's parameters
+	 * and returns. The caller calls again to parse the parameters of the
+	 * second VLAN.
+	 */
 
-				rc = mbox_process(mbox);
-				if (rc)
-					return rc;
-			}
+	for (; count < NPC_ACTION_MAX_VLAN_PARAMS; count++, actions++) {
+		if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
+			if (vlan_id_found)
+				return 0;
 
-			rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
-			rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
-			rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
-			flow->vtag_action = rx_vtag_action;
-		} else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT) {
 			const struct roc_npc_action_of_set_vlan_vid *vtag =
 				(const struct roc_npc_action_of_set_vlan_vid *)
 					actions->conf;
-			vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
-			if (vlan_id > 0xfff) {
+
+			vlan_info->vlan_id = plt_be_to_cpu_16(vtag->vlan_vid);
+
+			if (vlan_info->vlan_id > 0xfff) {
 				plt_err("Invalid vlan_id for set vlan action");
 				return -EINVAL;
 			}
+
 			flow->vtag_insert_enabled = true;
+			(*parsed_cnt)++;
+			vlan_id_found = true;
 		} else if (actions->type ==
 			   ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT) {
+			if (ethtype_found)
+				return 0;
+
 			const struct roc_npc_action_of_push_vlan *ethtype =
 				(const struct roc_npc_action_of_push_vlan *)
 					actions->conf;
-			vlan_ethtype = plt_be_to_cpu_16(ethtype->ethertype);
-			if (vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
-			    vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
+			vlan_info->vlan_ethtype =
+				plt_be_to_cpu_16(ethtype->ethertype);
+			if (vlan_info->vlan_ethtype != ROC_ETHER_TYPE_VLAN &&
+			    vlan_info->vlan_ethtype != ROC_ETHER_TYPE_QINQ) {
 				plt_err("Invalid ethtype specified for push"
 					" vlan action");
 				return -EINVAL;
 			}
 			flow->vtag_insert_enabled = true;
+			(*parsed_cnt)++;
+			ethtype_found = true;
 		} else if (actions->type ==
 			   ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
+			if (pcp_found)
+				return 0;
 			const struct roc_npc_action_of_set_vlan_pcp *pcp =
 				(const struct roc_npc_action_of_set_vlan_pcp *)
 					actions->conf;
-			vlan_pcp = pcp->vlan_pcp;
-			if (vlan_pcp > 0x7) {
+			vlan_info->vlan_pcp = pcp->vlan_pcp;
+			if (vlan_info->vlan_pcp > 0x7) {
 				plt_err("Invalid PCP value for pcp action");
 				return -EINVAL;
 			}
 			flow->vtag_insert_enabled = true;
+			(*parsed_cnt)++;
+			pcp_found = true;
+		} else {
+			return 0;
 		}
 	}
 
-	if (flow->vtag_insert_enabled) {
-		vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+	return 0;
+}
 
-		if (vtag_cfg == NULL)
-			return -ENOSPC;
+static int
+npc_vtag_insert_action_configure(struct mbox *mbox, struct roc_npc_flow *flow,
+				 struct npc_action_vtag_info *vlan_info)
+{
+	struct nix_vtag_config *vtag_cfg;
+	struct nix_vtag_config_rsp *rsp;
+	int rc = 0;
 
-		vtag_cfg->cfg_type = VTAG_TX;
-		vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
-		vtag_cfg->tx.vtag0 =
-			((vlan_ethtype << 16) | (vlan_pcp << 13) | vlan_id);
+	union {
+		uint64_t reg;
+		struct nix_tx_vtag_action_s act;
+	} tx_vtag_action;
 
-		vtag_cfg->tx.cfg_vtag0 = 1;
-		rc = mbox_process_msg(mbox, (void *)&rsp);
-		if (rc)
-			return rc;
+	vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
 
-		if (rsp->vtag0_idx < 0) {
-			plt_err("Failed to config TX VTAG action");
-			return -EINVAL;
-		}
+	if (vtag_cfg == NULL)
+		return -ENOSPC;
+
+	vtag_cfg->cfg_type = VTAG_TX;
+	vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
+	vtag_cfg->tx.vtag0 =
+		((vlan_info[0].vlan_ethtype << 16) |
+		 (vlan_info[0].vlan_pcp << 13) | vlan_info[0].vlan_id);
+
+	vtag_cfg->tx.cfg_vtag0 = 1;
+
+	if (flow->vtag_insert_count == 2) {
+		vtag_cfg->tx.vtag1 =
+			((vlan_info[1].vlan_ethtype << 16) |
+			 (vlan_info[1].vlan_pcp << 13) | vlan_info[1].vlan_id);
+
+		vtag_cfg->tx.cfg_vtag1 = 1;
+	}
+
+	rc = mbox_process_msg(mbox, (void *)&rsp);
+	if (rc)
+		return rc;
+
+	if (rsp->vtag0_idx < 0 ||
+	    ((flow->vtag_insert_count == 2) && (rsp->vtag1_idx < 0))) {
+		plt_err("Failed to config TX VTAG action");
+		return -EINVAL;
+	}
 
-		tx_vtag_action.reg = 0;
-		tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
-		tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
-		tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
-		tx_vtag_action.act.vtag0_relptr =
+	tx_vtag_action.reg = 0;
+	tx_vtag_action.act.vtag0_def = rsp->vtag0_idx;
+	tx_vtag_action.act.vtag0_lid = NPC_LID_LA;
+	tx_vtag_action.act.vtag0_op = NIX_TX_VTAGOP_INSERT;
+	tx_vtag_action.act.vtag0_relptr = NIX_TX_VTAGACTION_VTAG0_RELPTR;
+
+	if (flow->vtag_insert_count == 2) {
+		tx_vtag_action.act.vtag1_def = rsp->vtag1_idx;
+		tx_vtag_action.act.vtag1_lid = NPC_LID_LA;
+		tx_vtag_action.act.vtag1_op = NIX_TX_VTAGOP_INSERT;
+		/* NIX_TX_VTAG_ACTION_S
+		 *  If Vtag 0 is inserted, hardware adjusts the Vtag 1 byte
+		 *  offset accordingly. Thus, if the two offsets are equal in
+		 *  the structure, hardware inserts Vtag 1 immediately after
+		 *  Vtag 0 in the packet.
+		 */
+		tx_vtag_action.act.vtag1_relptr =
 			NIX_TX_VTAGACTION_VTAG0_RELPTR;
-		flow->vtag_action = tx_vtag_action.reg;
+	}
+
+	flow->vtag_action = tx_vtag_action.reg;
+
+	return 0;
+}
+
+static int
+npc_vtag_strip_action_configure(struct mbox *mbox,
+				const struct roc_npc_action actions[],
+				struct roc_npc_flow *flow, int *strip_cnt)
+{
+	struct nix_vtag_config *vtag_cfg;
+	uint64_t rx_vtag_action = 0;
+	int count = 0, rc = 0;
+
+	*strip_cnt = 0;
+
+	for (; count < NPC_ACTION_MAX_VLANS_STRIPPED; count++, actions++) {
+		if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP)
+			(*strip_cnt)++;
+	}
+
+	vtag_cfg = mbox_alloc_msg_nix_vtag_cfg(mbox);
+
+	if (vtag_cfg == NULL)
+		return -ENOSPC;
+
+	vtag_cfg->cfg_type = VTAG_RX;
+	vtag_cfg->rx.strip_vtag = 1;
+	/* Always capture */
+	vtag_cfg->rx.capture_vtag = 1;
+	vtag_cfg->vtag_size = NIX_VTAGSIZE_T4;
+	vtag_cfg->rx.vtag_type = 0;
+
+	rc = mbox_process(mbox);
+	if (rc)
+		return rc;
+
+	rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 15);
+	rx_vtag_action |= ((uint64_t)NPC_LID_LB << 8);
+	rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR;
+
+	if (*strip_cnt == 2) {
+		rx_vtag_action |= (NIX_RX_VTAGACTION_VTAG_VALID << 47);
+		rx_vtag_action |= ((uint64_t)NPC_LID_LB << 40);
+		rx_vtag_action |= NIX_RX_VTAGACTION_VTAG0_RELPTR << 32;
+	}
+	flow->vtag_action = rx_vtag_action;
+
+	return 0;
+}
+
+static int
+npc_vtag_action_program(struct roc_npc *roc_npc,
+			const struct roc_npc_action actions[],
+			struct roc_npc_flow *flow)
+{
+	bool vlan_strip_parsed = false, vlan_insert_parsed = false;
+	const struct roc_npc_action *insert_actions;
+	struct roc_nix *roc_nix = roc_npc->roc_nix;
+	struct npc_action_vtag_info vlan_info[2];
+	int parsed_cnt = 0, strip_cnt = 0;
+	int tot_vlan_params = 0;
+	struct mbox *mbox;
+	struct nix *nix;
+	int i, rc;
+
+	nix = roc_nix_to_nix_priv(roc_nix);
+	mbox = (&nix->dev)->mbox;
+
+	memset(vlan_info, 0, sizeof(vlan_info));
+
+	flow->vtag_insert_enabled = false;
+
+	for (; actions->type != ROC_NPC_ACTION_TYPE_END; actions++) {
+		if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_STRIP) {
+			if (vlan_strip_parsed) {
+				plt_err("Incorrect VLAN strip actions");
+				return -EINVAL;
+			}
+			rc = npc_vtag_strip_action_configure(mbox, actions,
+							     flow, &strip_cnt);
+			if (rc)
+				return rc;
+
+			if (strip_cnt == 2)
+				actions++;
+
+			vlan_strip_parsed = true;
+		} else if (actions->type == ROC_NPC_ACTION_TYPE_VLAN_INSERT ||
+			   actions->type ==
+				   ROC_NPC_ACTION_TYPE_VLAN_ETHTYPE_INSERT ||
+			   actions->type ==
+				   ROC_NPC_ACTION_TYPE_VLAN_PCP_INSERT) {
+			if (vlan_insert_parsed) {
+				plt_err("Incorrect VLAN insert actions");
+				return -EINVAL;
+			}
+
+			insert_actions = actions;
+
+			for (i = 0; i < 2; i++) {
+				rc = npc_vtag_insert_action_parse(
+					insert_actions, flow, &vlan_info[i],
+					&parsed_cnt);
+
+				if (rc)
+					return rc;
+
+				if (parsed_cnt) {
+					insert_actions += parsed_cnt;
+					tot_vlan_params += parsed_cnt;
+					flow->vtag_insert_count++;
+				}
+			}
+			actions += tot_vlan_params - 1;
+			vlan_insert_parsed = true;
+		}
+	}
+
+	if (flow->vtag_insert_enabled) {
+		rc = npc_vtag_insert_action_configure(mbox, flow, vlan_info);
+
+		if (rc)
+			return rc;
 	}
 	return 0;
 }
diff --git a/drivers/common/cnxk/roc_npc.h b/drivers/common/cnxk/roc_npc.h
index 2c0a536c93..e86595fe9a 100644
--- a/drivers/common/cnxk/roc_npc.h
+++ b/drivers/common/cnxk/roc_npc.h
@@ -124,6 +124,7 @@  struct roc_npc_flow {
 	uint64_t npc_action;
 	uint64_t vtag_action;
 	bool vtag_insert_enabled;
+	uint8_t vtag_insert_count;
 #define ROC_NPC_MAX_FLOW_PATTERNS 32
 	struct roc_npc_flow_dump_data dump_data[ROC_NPC_MAX_FLOW_PATTERNS];
 	uint16_t num_patterns;
diff --git a/drivers/common/cnxk/roc_npc_priv.h b/drivers/common/cnxk/roc_npc_priv.h
index 484c3aeb1f..1ba8adcd4b 100644
--- a/drivers/common/cnxk/roc_npc_priv.h
+++ b/drivers/common/cnxk/roc_npc_priv.h
@@ -57,6 +57,15 @@ 
 	(NPC_NIXLF_MAX * NPC_MCAME_PER_LF +                                    \
 	 (NPC_RVUPF_MAX_10XX - 1) * NPC_MCAME_PER_PF)
 
+#define NPC_ACTION_MAX_VLAN_PARAMS    3
+#define NPC_ACTION_MAX_VLANS_STRIPPED 2
+
+struct npc_action_vtag_info {
+	uint16_t vlan_id;
+	uint16_t vlan_ethtype;
+	uint8_t vlan_pcp;
+};
+
 enum npc_err_status {
 	NPC_ERR_PARAM = -1024,
 	NPC_ERR_NO_MEM,
@@ -350,7 +359,7 @@  struct npc {
 	uint16_t flow_max_priority;		/* Max priority for flow */
 	uint16_t switch_header_type; /* Suppprted switch header type */
 	uint32_t mark_actions;	     /* Number of mark actions */
-	uint32_t vtag_actions;	     /* vtag insert/strip actions */
+	uint32_t vtag_strip_actions; /* vtag insert/strip actions */
 	uint16_t pf_func;	     /* pf_func of device */
 	npc_dxcfg_t prx_dxcfg;	     /* intf, lid, lt, extract */
 	npc_fxcfg_t prx_fxcfg;	     /* Flag extract */