[v4,08/23] net/cnxk: eswitch flow configurations

Message ID 20240227191550.137687-9-hkalra@marvell.com (mailing list archive)
State Changes Requested, archived
Delegated to: Jerin Jacob
Headers
Series net/cnxk: support for port representors |

Checks

Context Check Description
ci/checkpatch success coding style OK

Commit Message

Harman Kalra Feb. 27, 2024, 7:15 p.m. UTC
  Adding flow rules for eswitch PF and VF and implementing
interfaces to delete, shift flow rules

Signed-off-by: Harman Kalra <hkalra@marvell.com>
---
 drivers/net/cnxk/cnxk_eswitch.c         |  44 +++
 drivers/net/cnxk/cnxk_eswitch.h         |  25 +-
 drivers/net/cnxk/cnxk_eswitch_devargs.c |   1 +
 drivers/net/cnxk/cnxk_eswitch_flow.c    | 454 ++++++++++++++++++++++++
 drivers/net/cnxk/meson.build            |   1 +
 5 files changed, 522 insertions(+), 3 deletions(-)
 create mode 100644 drivers/net/cnxk/cnxk_eswitch_flow.c
  

Patch

diff --git a/drivers/net/cnxk/cnxk_eswitch.c b/drivers/net/cnxk/cnxk_eswitch.c
index 599ed149ae..25992fddc9 100644
--- a/drivers/net/cnxk/cnxk_eswitch.c
+++ b/drivers/net/cnxk/cnxk_eswitch.c
@@ -2,11 +2,33 @@ 
  * Copyright(C) 2024 Marvell.
  */
 
+#include <rte_thash.h>
+
 #include <cnxk_eswitch.h>
 #include <cnxk_rep.h>
 
 #define CNXK_NIX_DEF_SQ_COUNT 512
 
+struct cnxk_esw_repr_hw_info *
+cnxk_eswitch_representor_hw_info(struct cnxk_eswitch_dev *eswitch_dev, uint16_t hw_func)
+{
+	struct cnxk_eswitch_devargs *esw_da;
+	int i, j;
+
+	if (!eswitch_dev)
+		return NULL;
+
+	/* Traversing the initialized represented list */
+	for (i = 0; i < eswitch_dev->nb_esw_da; i++) {
+		esw_da = &eswitch_dev->esw_da[i];
+		for (j = 0; j < esw_da->nb_repr_ports; j++) {
+			if (esw_da->repr_hw_info[j].hw_func == hw_func)
+				return &esw_da->repr_hw_info[j];
+		}
+	}
+	return NULL;
+}
+
 static int
 eswitch_hw_rsrc_cleanup(struct cnxk_eswitch_dev *eswitch_dev, struct rte_pci_device *pci_dev)
 {
@@ -67,6 +89,10 @@  cnxk_eswitch_dev_remove(struct rte_pci_device *pci_dev)
 	if (eswitch_dev->repr_cnt.nb_repr_created)
 		cnxk_rep_dev_remove(eswitch_dev);
 
+	/* Cleanup NPC rxtx flow rules */
+	cnxk_eswitch_flow_rules_remove_list(eswitch_dev, &eswitch_dev->esw_flow_list,
+					    eswitch_dev->npc.pf_func);
+
 	/* Cleanup HW resources */
 	eswitch_hw_rsrc_cleanup(eswitch_dev, pci_dev);
 
@@ -87,6 +113,21 @@  cnxk_eswitch_nix_rsrc_start(struct cnxk_eswitch_dev *eswitch_dev)
 		goto done;
 	}
 
+	/* Install eswitch PF mcam rules */
+	rc = cnxk_eswitch_pfvf_flow_rules_install(eswitch_dev, false);
+	if (rc) {
+		plt_err("Failed to install rxtx rules, rc %d", rc);
+		goto done;
+	}
+
+	/* Configure TPID for Eswitch PF LFs */
+	rc = roc_eswitch_nix_vlan_tpid_set(&eswitch_dev->nix, ROC_NIX_VLAN_TYPE_OUTER,
+					   CNXK_ESWITCH_VLAN_TPID, false);
+	if (rc) {
+		plt_err("Failed to configure tpid, rc %d", rc);
+		goto done;
+	}
+
 	rc = roc_npc_mcam_enable_all_entries(&eswitch_dev->npc, 1);
 	if (rc) {
 		plt_err("Failed to enable NPC entries %d", rc);
@@ -524,6 +565,9 @@  eswitch_hw_rsrc_setup(struct cnxk_eswitch_dev *eswitch_dev, struct rte_pci_devic
 	if (rc)
 		goto rsrc_cleanup;
 
+	/* List for eswitch default flows */
+	TAILQ_INIT(&eswitch_dev->esw_flow_list);
+
 	return rc;
 rsrc_cleanup:
 	eswitch_hw_rsrc_cleanup(eswitch_dev, pci_dev);
diff --git a/drivers/net/cnxk/cnxk_eswitch.h b/drivers/net/cnxk/cnxk_eswitch.h
index dcd5add6d0..5b4e1b0a71 100644
--- a/drivers/net/cnxk/cnxk_eswitch.h
+++ b/drivers/net/cnxk/cnxk_eswitch.h
@@ -13,11 +13,10 @@ 
 #include "cn10k_tx.h"
 
 #define CNXK_ESWITCH_CTRL_MSG_SOCK_PATH "/tmp/cxk_rep_ctrl_msg_sock"
+#define CNXK_ESWITCH_VLAN_TPID		ROC_ESWITCH_VLAN_TPID
 #define CNXK_REP_ESWITCH_DEV_MZ		"cnxk_eswitch_dev"
-#define CNXK_ESWITCH_VLAN_TPID		0x8100
 #define CNXK_ESWITCH_MAX_TXQ		256
 #define CNXK_ESWITCH_MAX_RXQ		256
-#define CNXK_ESWITCH_LBK_CHAN		63
 #define CNXK_ESWITCH_VFPF_SHIFT		8
 
 #define CNXK_ESWITCH_QUEUE_STATE_RELEASED   0
@@ -25,6 +24,7 @@ 
 #define CNXK_ESWITCH_QUEUE_STATE_STARTED    2
 #define CNXK_ESWITCH_QUEUE_STATE_STOPPED    3
 
+TAILQ_HEAD(eswitch_flow_list, roc_npc_flow);
 enum cnxk_esw_da_pattern_type {
 	CNXK_ESW_DA_TYPE_LIST = 0,
 	CNXK_ESW_DA_TYPE_PFVF,
@@ -39,6 +39,9 @@  struct cnxk_esw_repr_hw_info {
 	uint16_t pfvf;
 	/* representor port id assigned to representee */
 	uint16_t port_id;
+	uint16_t num_flow_entries;
+
+	TAILQ_HEAD(flow_list, roc_npc_flow) repr_flow_list;
 };
 
 /* Structure representing per devarg information - this can be per representee
@@ -90,7 +93,6 @@  struct cnxk_eswitch_cxq {
 	uint8_t state;
 };
 
-TAILQ_HEAD(eswitch_flow_list, roc_npc_flow);
 struct cnxk_eswitch_dev {
 	/* Input parameters */
 	struct plt_pci_device *pci_dev;
@@ -116,6 +118,13 @@  struct cnxk_eswitch_dev {
 	uint16_t rep_cnt;
 	uint8_t configured;
 
+	/* NPC rxtx rules */
+	struct flow_list esw_flow_list;
+	uint16_t num_entries;
+	bool eswitch_vf_rules_setup;
+	uint16_t esw_pf_entry;
+	uint16_t esw_vf_entry;
+
 	/* Eswitch Representors Devargs */
 	uint16_t nb_esw_da;
 	uint16_t last_probed;
@@ -144,7 +153,10 @@  cnxk_eswitch_pmd_priv(void)
 	return mz->addr;
 }
 
+/* HW Resources */
 int cnxk_eswitch_nix_rsrc_start(struct cnxk_eswitch_dev *eswitch_dev);
+struct cnxk_esw_repr_hw_info *cnxk_eswitch_representor_hw_info(struct cnxk_eswitch_dev *eswitch_dev,
+							       uint16_t hw_func);
 int cnxk_eswitch_repr_devargs(struct rte_pci_device *pci_dev, struct cnxk_eswitch_dev *eswitch_dev);
 int cnxk_eswitch_representor_info_get(struct cnxk_eswitch_dev *eswitch_dev,
 				      struct rte_eth_representor_info *info);
@@ -158,4 +170,11 @@  int cnxk_eswitch_rxq_start(struct cnxk_eswitch_dev *eswitch_dev, uint16_t qid);
 int cnxk_eswitch_rxq_stop(struct cnxk_eswitch_dev *eswitch_dev, uint16_t qid);
 int cnxk_eswitch_txq_start(struct cnxk_eswitch_dev *eswitch_dev, uint16_t qid);
 int cnxk_eswitch_txq_stop(struct cnxk_eswitch_dev *eswitch_dev, uint16_t qid);
+/* Flow Rules */
+int cnxk_eswitch_flow_rules_install(struct cnxk_eswitch_dev *eswitch_dev, uint16_t hw_func);
+int cnxk_eswitch_flow_rules_delete(struct cnxk_eswitch_dev *eswitch_dev, uint16_t hw_func);
+int cnxk_eswitch_pfvf_flow_rules_install(struct cnxk_eswitch_dev *eswitch_dev, bool is_vf);
+int cnxk_eswitch_flow_rule_shift(uint16_t hw_func, uint16_t *new_entry);
+int cnxk_eswitch_flow_rules_remove_list(struct cnxk_eswitch_dev *eswitch_dev,
+					struct flow_list *list, uint16_t hw_func);
 #endif /* __CNXK_ESWITCH_H__ */
diff --git a/drivers/net/cnxk/cnxk_eswitch_devargs.c b/drivers/net/cnxk/cnxk_eswitch_devargs.c
index 58383fb835..8167ce673a 100644
--- a/drivers/net/cnxk/cnxk_eswitch_devargs.c
+++ b/drivers/net/cnxk/cnxk_eswitch_devargs.c
@@ -72,6 +72,7 @@  populate_repr_hw_info(struct cnxk_eswitch_dev *eswitch_dev, struct rte_eth_devar
 		esw_da->repr_hw_info[i].pfvf = (eth_da->type == RTE_ETH_REPRESENTOR_PF) ?
 						       eth_da->ports[0] :
 						       eth_da->representor_ports[i];
+		TAILQ_INIT(&esw_da->repr_hw_info[i].repr_flow_list);
 		plt_esw_dbg("	HW func %x index %d type %d", hw_func, j, eth_da->type);
 	}
 
diff --git a/drivers/net/cnxk/cnxk_eswitch_flow.c b/drivers/net/cnxk/cnxk_eswitch_flow.c
new file mode 100644
index 0000000000..06077bfe92
--- /dev/null
+++ b/drivers/net/cnxk/cnxk_eswitch_flow.c
@@ -0,0 +1,454 @@ 
+/* SPDX-License-Identifier: BSD-3-Clause
+ * Copyright(C) 2024 Marvell.
+ */
+
+#include <rte_thash.h>
+
+#include <cnxk_eswitch.h>
+
+const uint8_t eswitch_vlan_rss_key[ROC_NIX_RSS_KEY_LEN] = {
+	0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+	0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+	0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+	0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+	0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
+	0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE};
+
+int
+cnxk_eswitch_flow_rules_remove_list(struct cnxk_eswitch_dev *eswitch_dev, struct flow_list *list,
+				    uint16_t hw_func)
+{
+	struct roc_npc_flow *flow, *tvar;
+	int rc = 0;
+
+	RTE_TAILQ_FOREACH_SAFE(flow, list, next, tvar) {
+		plt_esw_dbg("Removing flow %d", flow->mcam_id);
+		rc = roc_eswitch_npc_mcam_delete_rule(&eswitch_dev->npc, flow,
+						      hw_func);
+		if (rc)
+			plt_err("Failed to delete rule %d", flow->mcam_id);
+		rc = roc_npc_mcam_free(&eswitch_dev->npc, flow);
+		if (rc)
+			plt_err("Failed to free entry %d", flow->mcam_id);
+		TAILQ_REMOVE(list, flow, next);
+		rte_free(flow);
+	}
+
+	return rc;
+}
+
+static int
+eswitch_npc_vlan_rss_configure(struct roc_npc *roc_npc, struct roc_npc_flow *flow)
+{
+	struct roc_nix *roc_nix = roc_npc->roc_nix;
+	uint32_t qid, idx, hash, vlan_tci;
+	uint16_t *reta, reta_sz, id;
+	int rc = 0;
+
+	id = flow->mcam_id;
+	/* Setting up the key */
+	roc_nix_rss_key_set(roc_nix, eswitch_vlan_rss_key);
+
+	reta_sz = roc_nix->reta_sz;
+	reta = plt_zmalloc(reta_sz * sizeof(uint16_t), 0);
+	if (!reta) {
+		plt_err("Failed to allocate mem for reta table");
+		rc = -ENOMEM;
+		goto fail;
+	}
+	for (qid = 0; qid < reta_sz; qid++) {
+		vlan_tci = (1 << CNXK_ESWITCH_VFPF_SHIFT) | qid;
+		hash = rte_softrss(&vlan_tci, 1, eswitch_vlan_rss_key);
+		idx = hash & 0xFF;
+		reta[idx] = qid;
+	}
+	flow->mcam_id = id;
+	rc = roc_eswitch_npc_rss_action_configure(roc_npc, flow, FLOW_KEY_TYPE_VLAN, reta);
+	if (rc) {
+		plt_err("Failed to configure rss action, err %d", rc);
+		goto done;
+	}
+
+done:
+	plt_free(reta);
+fail:
+	return rc;
+}
+
+static int
+eswitch_pfvf_mcam_install_rules(struct cnxk_eswitch_dev *eswitch_dev, struct roc_npc_flow *flow,
+				bool is_vf)
+{
+	uint16_t vlan_tci = 0, hw_func;
+	int rc;
+
+	hw_func = eswitch_dev->npc.pf_func | is_vf;
+	if (!is_vf) {
+		/* Eswitch PF RX VLAN rule */
+		vlan_tci = 1ULL << CNXK_ESWITCH_VFPF_SHIFT;
+		rc = roc_eswitch_npc_mcam_rx_rule(&eswitch_dev->npc, flow, hw_func, vlan_tci,
+						  0xFF00);
+		if (rc) {
+			plt_err("Failed to install RX rule for ESW PF to ESW VF, rc %d", rc);
+			goto exit;
+		}
+		plt_esw_dbg("Installed eswitch PF RX rule %d", flow->mcam_id);
+		rc = eswitch_npc_vlan_rss_configure(&eswitch_dev->npc, flow);
+		if (rc)
+			goto exit;
+		flow->enable = true;
+	} else {
+		/* Eswitch VF RX VLAN rule */
+		rc = roc_eswitch_npc_mcam_rx_rule(&eswitch_dev->npc, flow, hw_func, vlan_tci,
+						  0xFF00);
+		if (rc) {
+			plt_err("Failed to install RX rule for ESW VF to ESW PF, rc %d", rc);
+			goto exit;
+		}
+		flow->enable = true;
+		plt_esw_dbg("Installed eswitch PF RX rule %d", flow->mcam_id);
+	}
+
+	return 0;
+exit:
+	return rc;
+}
+
+static int
+eswitch_npc_get_counter(struct roc_npc *npc, struct roc_npc_flow *flow)
+{
+	uint16_t ctr_id;
+	int rc;
+
+	rc = roc_npc_mcam_alloc_counter(npc, &ctr_id);
+	if (rc < 0) {
+		plt_err("Failed to allocate counter, rc %d", rc);
+		goto fail;
+	}
+	flow->ctr_id = ctr_id;
+	flow->use_ctr = true;
+
+	rc = roc_npc_mcam_clear_counter(npc, flow->ctr_id);
+	if (rc < 0) {
+		plt_err("Failed to clear counter idx %d, rc %d", flow->ctr_id, rc);
+		goto free;
+	}
+	return 0;
+free:
+	roc_npc_mcam_free_counter(npc, ctr_id);
+fail:
+	return rc;
+}
+
+static int
+eswitch_npc_get_counter_entry_ref(struct roc_npc *npc, struct roc_npc_flow *flow,
+				  struct roc_npc_flow *ref_flow)
+{
+	int rc = 0, resp_count;
+
+	rc = eswitch_npc_get_counter(npc, flow);
+	if (rc)
+		goto free;
+
+	/* Allocate an entry viz higher priority than ref flow */
+	rc = roc_npc_mcam_alloc_entry(npc, flow, ref_flow, NPC_MCAM_HIGHER_PRIO, &resp_count);
+	if (rc) {
+		plt_err("Failed to allocate entry, err %d", rc);
+		goto free;
+	}
+	plt_esw_dbg("New entry %d ref entry %d resp_count %d", flow->mcam_id, ref_flow->mcam_id,
+		    resp_count);
+
+	return 0;
+free:
+	roc_npc_mcam_free_counter(npc, flow->ctr_id);
+	return rc;
+}
+
+int
+cnxk_eswitch_flow_rule_shift(uint16_t hw_func, uint16_t *entry)
+{
+	struct cnxk_esw_repr_hw_info *repr_info;
+	struct cnxk_eswitch_dev *eswitch_dev;
+	struct roc_npc_flow *ref_flow, *flow;
+	uint16_t curr_entry, new_entry;
+	int rc = 0, resp_count;
+
+	eswitch_dev = cnxk_eswitch_pmd_priv();
+	if (!eswitch_dev) {
+		plt_err("Invalid eswitch_dev handle");
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	repr_info = cnxk_eswitch_representor_hw_info(eswitch_dev, hw_func);
+	if (!repr_info) {
+		plt_warn("Failed to get representor group for %x", hw_func);
+		rc = -ENOENT;
+		goto fail;
+	}
+
+	ref_flow = TAILQ_FIRST(&repr_info->repr_flow_list);
+	if (*entry > ref_flow->mcam_id) {
+		flow = plt_zmalloc(sizeof(struct roc_npc_flow), 0);
+		if (!flow) {
+			plt_err("Failed to allocate memory");
+			rc = -ENOMEM;
+			goto fail;
+		}
+
+		/* Allocate a higher priority flow rule */
+		rc = roc_npc_mcam_alloc_entry(&eswitch_dev->npc, flow, ref_flow,
+					      NPC_MCAM_HIGHER_PRIO, &resp_count);
+		if (rc < 0) {
+			plt_err("Failed to allocate a newmcam entry, rc %d", rc);
+			goto fail;
+		}
+
+		if (flow->mcam_id > ref_flow->mcam_id) {
+			plt_err("New flow %d is still at higher priority than ref_flow %d",
+				flow->mcam_id, ref_flow->mcam_id);
+			rc = -EINVAL;
+			goto free_entry;
+		}
+
+		plt_info("Before shift: HW_func %x curr_entry %d ref flow id %d new_entry %d",
+			 hw_func, *entry, ref_flow->mcam_id, flow->mcam_id);
+
+		curr_entry = *entry;
+		new_entry = flow->mcam_id;
+
+		rc = roc_npc_mcam_move(&eswitch_dev->npc, curr_entry, new_entry);
+		if (rc) {
+			plt_err("Failed to shift the new index %d to curr index %d, err	%d", *entry,
+				curr_entry, rc);
+			goto free_entry;
+		}
+		*entry = flow->mcam_id;
+
+		/* Freeing the current entry */
+		rc = roc_npc_mcam_free_entry(&eswitch_dev->npc, curr_entry);
+		if (rc) {
+			plt_err("Failed to free the old entry. err %d", rc);
+			goto free_entry;
+		}
+
+		plt_free(flow);
+		plt_info("After shift: HW_func %x old_entry %d new_entry %d", hw_func, curr_entry,
+			 *entry);
+	}
+
+	return 0;
+free_entry:
+
+fail:
+	return rc;
+}
+
+int
+cnxk_eswitch_flow_rules_delete(struct cnxk_eswitch_dev *eswitch_dev, uint16_t hw_func)
+{
+	struct cnxk_esw_repr_hw_info *repr_info;
+	struct flow_list *list;
+	int rc = 0;
+
+	repr_info = cnxk_eswitch_representor_hw_info(eswitch_dev, hw_func);
+	if (!repr_info) {
+		plt_warn("Failed to get representor group for %x", hw_func);
+		rc = -ENOENT;
+		goto fail;
+	}
+	list = &repr_info->repr_flow_list;
+
+	plt_esw_dbg("Deleting flows for %x", hw_func);
+	rc = cnxk_eswitch_flow_rules_remove_list(eswitch_dev, list, hw_func);
+	if (rc)
+		plt_err("Failed to delete rules for hw func %x", hw_func);
+
+fail:
+	return rc;
+}
+
+int
+cnxk_eswitch_flow_rules_install(struct cnxk_eswitch_dev *eswitch_dev, uint16_t hw_func)
+{
+	struct roc_npc_flow *rx_flow, *tx_flow, *flow_iter, *esw_pf_flow = NULL;
+	struct cnxk_esw_repr_hw_info *repr_info;
+	struct flow_list *list;
+	uint16_t vlan_tci;
+	int rc = 0;
+
+	repr_info = cnxk_eswitch_representor_hw_info(eswitch_dev, hw_func);
+	if (!repr_info) {
+		plt_err("Failed to get representor group for %x", hw_func);
+		rc = -EINVAL;
+		goto fail;
+	}
+	list = &repr_info->repr_flow_list;
+
+	/* Taking ESW PF as reference entry for installing new rules */
+	TAILQ_FOREACH(flow_iter, &eswitch_dev->esw_flow_list, next) {
+		if (flow_iter->mcam_id == eswitch_dev->esw_pf_entry) {
+			esw_pf_flow = flow_iter;
+			break;
+		}
+	}
+
+	if (!esw_pf_flow) {
+		plt_err("Failed to get the ESW PF flow");
+		rc = -EINVAL;
+		goto fail;
+	}
+
+	/* Installing RX rule */
+	rx_flow = plt_zmalloc(sizeof(struct roc_npc_flow), 0);
+	if (!rx_flow) {
+		plt_err("Failed to allocate memory");
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	rc = eswitch_npc_get_counter_entry_ref(&eswitch_dev->npc, rx_flow, esw_pf_flow);
+	if (rc) {
+		plt_err("Failed to get counter and mcam entry, rc %d", rc);
+		goto free_rx_flow;
+	}
+
+	/* VLAN TCI value for this representee is the rep id from AF driver */
+	vlan_tci = repr_info->rep_id;
+	rc = roc_eswitch_npc_mcam_rx_rule(&eswitch_dev->npc, rx_flow, hw_func, vlan_tci, 0xFFFF);
+	if (rc) {
+		plt_err("Failed to install RX rule for ESW PF to ESW VF, rc %d", rc);
+		goto free_rx_entry;
+	}
+	rx_flow->enable = true;
+	/* List in ascending order of mcam entries */
+	TAILQ_FOREACH(flow_iter, list, next) {
+		if (flow_iter->mcam_id > rx_flow->mcam_id) {
+			TAILQ_INSERT_BEFORE(flow_iter, rx_flow, next);
+			goto done_rx;
+		}
+	}
+	TAILQ_INSERT_TAIL(list, rx_flow, next);
+done_rx:
+	repr_info->num_flow_entries++;
+	plt_esw_dbg("Installed RX flow rule %d for representee %x with vlan tci %x MCAM id %d",
+		    eswitch_dev->num_entries, hw_func, vlan_tci, rx_flow->mcam_id);
+
+	/* Installing TX rule */
+	tx_flow = plt_zmalloc(sizeof(struct roc_npc_flow), 0);
+	if (!tx_flow) {
+		plt_err("Failed to allocate memory");
+		rc = -ENOMEM;
+		goto remove_rx_rule;
+	}
+
+	rc = eswitch_npc_get_counter_entry_ref(&eswitch_dev->npc, tx_flow, esw_pf_flow);
+	if (rc) {
+		plt_err("Failed to get counter and mcam entry, rc %d", rc);
+		goto free_tx_flow;
+	}
+
+	vlan_tci = (1ULL << CNXK_ESWITCH_VFPF_SHIFT) | repr_info->rep_id;
+	rc = roc_eswitch_npc_mcam_tx_rule(&eswitch_dev->npc, tx_flow, hw_func, vlan_tci);
+	if (rc) {
+		plt_err("Failed to install RX rule for ESW PF to ESW VF, rc %d", rc);
+		goto free_tx_entry;
+	}
+	tx_flow->enable = true;
+	/* List in ascending order of mcam entries */
+	TAILQ_FOREACH(flow_iter, list, next) {
+		if (flow_iter->mcam_id > tx_flow->mcam_id) {
+			TAILQ_INSERT_BEFORE(flow_iter, tx_flow, next);
+			goto done_tx;
+		}
+	}
+	TAILQ_INSERT_TAIL(list, tx_flow, next);
+done_tx:
+	repr_info->num_flow_entries++;
+	plt_esw_dbg("Installed TX flow rule %d for representee %x with vlan tci %x MCAM id %d",
+		    repr_info->num_flow_entries, hw_func, vlan_tci, tx_flow->mcam_id);
+
+	return 0;
+free_tx_entry:
+	roc_npc_mcam_free(&eswitch_dev->npc, tx_flow);
+free_tx_flow:
+	rte_free(tx_flow);
+remove_rx_rule:
+	TAILQ_REMOVE(list, rx_flow, next);
+free_rx_entry:
+	roc_npc_mcam_free(&eswitch_dev->npc, rx_flow);
+free_rx_flow:
+	rte_free(rx_flow);
+fail:
+	return rc;
+}
+
+int
+cnxk_eswitch_pfvf_flow_rules_install(struct cnxk_eswitch_dev *eswitch_dev, bool is_vf)
+{
+	struct roc_npc_flow *flow, *flow_iter;
+	struct flow_list *list;
+	int rc = 0;
+
+	list = &eswitch_dev->esw_flow_list;
+	flow = plt_zmalloc(sizeof(struct roc_npc_flow), 0);
+	if (!flow) {
+		plt_err("Failed to allocate memory");
+		rc = -ENOMEM;
+		goto fail;
+	}
+
+	rc = eswitch_npc_get_counter(&eswitch_dev->npc, flow);
+	if (rc) {
+		plt_err("Failed to get counter and mcam entry, rc %d", rc);
+		goto free_flow;
+	}
+	if (!is_vf) {
+		/* Reserving an entry for esw VF but will not be installed */
+		rc = roc_npc_get_free_mcam_entry(&eswitch_dev->npc, flow);
+		if (rc < 0) {
+			plt_err("Failed to allocate entry for vf, err %d", rc);
+			goto free_flow;
+		}
+		eswitch_dev->esw_vf_entry = flow->mcam_id;
+		/* Allocate an entry for esw PF */
+		rc = eswitch_npc_get_counter_entry_ref(&eswitch_dev->npc, flow, flow);
+		if (rc) {
+			plt_err("Failed to allocate entry for pf, err %d", rc);
+			goto free_flow;
+		}
+		eswitch_dev->esw_pf_entry = flow->mcam_id;
+		plt_esw_dbg("Allocated entries for esw: PF %d and VF %d", eswitch_dev->esw_pf_entry,
+			    eswitch_dev->esw_vf_entry);
+	} else {
+		flow->mcam_id = eswitch_dev->esw_vf_entry;
+	}
+
+	rc = eswitch_pfvf_mcam_install_rules(eswitch_dev, flow, is_vf);
+	if (rc) {
+		plt_err("Failed to install entries, rc %d", rc);
+		goto free_flow;
+	}
+
+	/* List in ascending order of mcam entries */
+	TAILQ_FOREACH(flow_iter, list, next) {
+		if (flow_iter->mcam_id > flow->mcam_id) {
+			TAILQ_INSERT_BEFORE(flow_iter, flow, next);
+			goto done;
+		}
+	}
+	TAILQ_INSERT_TAIL(list, flow, next);
+done:
+	eswitch_dev->num_entries++;
+	plt_esw_dbg("Installed new eswitch flow rule %d with MCAM id %d", eswitch_dev->num_entries,
+		    flow->mcam_id);
+
+	return 0;
+
+free_flow:
+	cnxk_eswitch_flow_rules_remove_list(eswitch_dev, &eswitch_dev->esw_flow_list,
+					    eswitch_dev->npc.pf_func);
+fail:
+	return rc;
+}
diff --git a/drivers/net/cnxk/meson.build b/drivers/net/cnxk/meson.build
index fcd5d3d569..488e89253d 100644
--- a/drivers/net/cnxk/meson.build
+++ b/drivers/net/cnxk/meson.build
@@ -30,6 +30,7 @@  sources = files(
         'cnxk_ethdev_sec_telemetry.c',
         'cnxk_eswitch.c',
         'cnxk_eswitch_devargs.c',
+        'cnxk_eswitch_flow.c',
         'cnxk_link.c',
         'cnxk_lookup.c',
         'cnxk_ptp.c',