diff --git a/drivers/net/cpfl/cpfl_ethdev.c b/drivers/net/cpfl/cpfl_ethdev.c
index 31a5822d2c..ad21f901bb 100644
--- a/drivers/net/cpfl/cpfl_ethdev.c
+++ b/drivers/net/cpfl/cpfl_ethdev.c
@@ -10,6 +10,7 @@
 #include <rte_dev.h>
 #include <errno.h>
 #include <rte_alarm.h>
+#include <rte_hash_crc.h>
 
 #include "cpfl_ethdev.h"
 #include "cpfl_rxtx.h"
@@ -1504,6 +1505,108 @@ cpfl_handle_vchnl_event_msg(struct cpfl_adapter_ext *adapter, uint8_t *msg, uint
 	}
 }
 
+static int
+cpfl_vport_info_create(struct cpfl_adapter_ext *adapter,
+		       struct cpfl_vport_id *vport_identity,
+		       struct cpchnl2_vport_info *vport_info)
+{
+	struct cpfl_vport_info *info = NULL;
+	int ret;
+
+	rte_spinlock_lock(&adapter->vport_map_lock);
+	ret = rte_hash_lookup_data(adapter->vport_map_hash, vport_identity, (void **)&info);
+	if (ret >= 0) {
+		PMD_DRV_LOG(WARNING, "vport already exist, overwrite info anyway");
+		/* overwrite info */
+		if (info)
+			info->vport_info = *vport_info;
+		goto fini;
+	}
+
+	info = rte_zmalloc(NULL, sizeof(*info), 0);
+	if (info == NULL) {
+		PMD_DRV_LOG(ERR, "Failed to alloc memory for vport map info");
+		ret = -ENOMEM;
+		goto err;
+	}
+
+	info->vport_info = *vport_info;
+
+	ret = rte_hash_add_key_data(adapter->vport_map_hash, vport_identity, info);
+	if (ret < 0) {
+		PMD_DRV_LOG(ERR, "Failed to add vport map into hash");
+		rte_free(info);
+		goto err;
+	}
+
+fini:
+	rte_spinlock_unlock(&adapter->vport_map_lock);
+	return 0;
+err:
+	rte_spinlock_unlock(&adapter->vport_map_lock);
+	return ret;
+}
+
+static int
+cpfl_vport_info_destroy(struct cpfl_adapter_ext *adapter, struct cpfl_vport_id *vport_identity)
+{
+	struct cpfl_vport_info *info;
+	int ret;
+
+	rte_spinlock_lock(&adapter->vport_map_lock);
+	ret = rte_hash_lookup_data(adapter->vport_map_hash, vport_identity, (void **)&info);
+	if (ret < 0) {
+		PMD_DRV_LOG(ERR, "vport id not exist");
+		goto err;
+	}
+
+	rte_hash_del_key(adapter->vport_map_hash, vport_identity);
+	rte_spinlock_unlock(&adapter->vport_map_lock);
+	rte_free(info);
+
+	return 0;
+
+err:
+	rte_spinlock_unlock(&adapter->vport_map_lock);
+	return ret;
+}
+
+static void
+cpfl_handle_cpchnl_event_msg(struct cpfl_adapter_ext *adapter, uint8_t *msg, uint16_t msglen)
+{
+	struct cpchnl2_event_info *cpchnl2_event = (struct cpchnl2_event_info *)msg;
+	struct cpchnl2_vport_info *info;
+	struct cpfl_vport_id vport_identity = { 0 };
+
+	if (msglen < sizeof(struct cpchnl2_event_info)) {
+		PMD_DRV_LOG(ERR, "Error event");
+		return;
+	}
+
+	switch (cpchnl2_event->header.type) {
+	case CPCHNL2_EVENT_VPORT_CREATED:
+		vport_identity.vport_id = cpchnl2_event->data.vport_created.vport.vport_id;
+		info = &cpchnl2_event->data.vport_created.info;
+		vport_identity.func_type = info->func_type;
+		vport_identity.pf_id = info->pf_id;
+		vport_identity.vf_id = info->vf_id;
+		if (cpfl_vport_info_create(adapter, &vport_identity, info))
+			PMD_DRV_LOG(WARNING, "Failed to handle CPCHNL2_EVENT_VPORT_CREATED");
+		break;
+	case CPCHNL2_EVENT_VPORT_DESTROYED:
+		vport_identity.vport_id = cpchnl2_event->data.vport_destroyed.vport.vport_id;
+		vport_identity.func_type = cpchnl2_event->data.vport_destroyed.func.func_type;
+		vport_identity.pf_id = cpchnl2_event->data.vport_destroyed.func.pf_id;
+		vport_identity.vf_id = cpchnl2_event->data.vport_destroyed.func.vf_id;
+		if (cpfl_vport_info_destroy(adapter, &vport_identity))
+			PMD_DRV_LOG(WARNING, "Failed to handle CPCHNL2_EVENT_VPORT_DESTROY");
+		break;
+	default:
+		PMD_DRV_LOG(ERR, " unknown event received %u", cpchnl2_event->header.type);
+		break;
+	}
+}
+
 static void
 cpfl_handle_virtchnl_msg(struct cpfl_adapter_ext *adapter)
 {
@@ -1535,6 +1638,9 @@ cpfl_handle_virtchnl_msg(struct cpfl_adapter_ext *adapter)
 			if (vc_op == VIRTCHNL2_OP_EVENT) {
 				cpfl_handle_vchnl_event_msg(adapter, adapter->base.mbx_resp,
 							    ctlq_msg.data_len);
+			} else if (vc_op == CPCHNL2_OP_EVENT) {
+				cpfl_handle_cpchnl_event_msg(adapter, adapter->base.mbx_resp,
+							     ctlq_msg.data_len);
 			} else {
 				if (vc_op == base->pend_cmd)
 					notify_cmd(base, base->cmd_retval);
@@ -1610,6 +1716,48 @@ static struct virtchnl2_get_capabilities req_caps = {
 	.other_caps = VIRTCHNL2_CAP_WB_ON_ITR
 };
 
+static int
+cpfl_vport_map_init(struct cpfl_adapter_ext *adapter)
+{
+	char hname[32];
+
+	snprintf(hname, 32, "%s-vport", adapter->name);
+
+	rte_spinlock_init(&adapter->vport_map_lock);
+
+#define CPFL_VPORT_MAP_HASH_ENTRY_NUM 2048
+
+	struct rte_hash_parameters params = {
+		.name = adapter->name,
+		.entries = CPFL_VPORT_MAP_HASH_ENTRY_NUM,
+		.key_len = sizeof(struct cpfl_vport_id),
+		.hash_func = rte_hash_crc,
+		.socket_id = SOCKET_ID_ANY,
+	};
+
+	adapter->vport_map_hash = rte_hash_create(&params);
+
+	if (adapter->vport_map_hash == NULL) {
+		PMD_INIT_LOG(ERR, "Failed to create vport map hash");
+		return -EINVAL;
+	}
+
+	return 0;
+}
+
+static void
+cpfl_vport_map_uninit(struct cpfl_adapter_ext *adapter)
+{
+	const void *key = NULL;
+	struct cpfl_vport_map_info *info;
+	uint32_t iter = 0;
+
+	while (rte_hash_iterate(adapter->vport_map_hash, &key, (void **)&info, &iter) >= 0)
+		rte_free(info);
+
+	rte_hash_free(adapter->vport_map_hash);
+}
+
 static int
 cpfl_adapter_ext_init(struct rte_pci_device *pci_dev, struct cpfl_adapter_ext *adapter)
 {
@@ -1634,6 +1782,12 @@ cpfl_adapter_ext_init(struct rte_pci_device *pci_dev, struct cpfl_adapter_ext *a
 		goto err_adapter_init;
 	}
 
+	ret = cpfl_vport_map_init(adapter);
+	if (ret) {
+		PMD_INIT_LOG(ERR, "Failed to init vport map");
+		goto err_vport_map_init;
+	}
+
 	rte_eal_alarm_set(CPFL_ALARM_INTERVAL, cpfl_dev_alarm_handler, adapter);
 
 	adapter->max_vport_nb = adapter->base.caps.max_vports > CPFL_MAX_VPORT_NUM ?
@@ -1658,6 +1812,8 @@ cpfl_adapter_ext_init(struct rte_pci_device *pci_dev, struct cpfl_adapter_ext *a
 
 err_vports_alloc:
 	rte_eal_alarm_cancel(cpfl_dev_alarm_handler, adapter);
+	cpfl_vport_map_uninit(adapter);
+err_vport_map_init:
 	idpf_adapter_deinit(base);
 err_adapter_init:
 	return ret;
@@ -1887,6 +2043,7 @@ static void
 cpfl_adapter_ext_deinit(struct cpfl_adapter_ext *adapter)
 {
 	rte_eal_alarm_cancel(cpfl_dev_alarm_handler, adapter);
+	cpfl_vport_map_uninit(adapter);
 	idpf_adapter_deinit(&adapter->base);
 
 	rte_free(adapter->vports);
diff --git a/drivers/net/cpfl/cpfl_ethdev.h b/drivers/net/cpfl/cpfl_ethdev.h
index feb1edc4b8..de86c49016 100644
--- a/drivers/net/cpfl/cpfl_ethdev.h
+++ b/drivers/net/cpfl/cpfl_ethdev.h
@@ -10,16 +10,18 @@
 #include <rte_spinlock.h>
 #include <rte_ethdev.h>
 #include <rte_kvargs.h>
+#include <rte_hash.h>
 #include <ethdev_driver.h>
 #include <ethdev_pci.h>
 
-#include "cpfl_logs.h"
-
 #include <idpf_common_device.h>
 #include <idpf_common_virtchnl.h>
 #include <base/idpf_prototype.h>
 #include <base/virtchnl2.h>
 
+#include "cpfl_logs.h"
+#include "cpfl_cpchnl.h"
+
 /* Currently, backend supports up to 8 vports */
 #define CPFL_MAX_VPORT_NUM	8
 
@@ -86,6 +88,18 @@ struct p2p_queue_chunks_info {
 	uint32_t rx_buf_qtail_spacing;
 };
 
+struct cpfl_vport_id {
+	uint32_t vport_id;
+	uint8_t func_type;
+	uint8_t pf_id;
+	uint16_t vf_id;
+};
+
+struct cpfl_vport_info {
+	struct cpchnl2_vport_info vport_info;
+	bool enabled;
+};
+
 enum cpfl_itf_type {
 	CPFL_ITF_TYPE_VPORT,
 };
@@ -127,6 +141,9 @@ struct cpfl_adapter_ext {
 
 	uint16_t used_vecs_num;
 	struct cpfl_devargs devargs;
+
+	rte_spinlock_t vport_map_lock;
+	struct rte_hash *vport_map_hash;
 };
 
 TAILQ_HEAD(cpfl_adapter_list, cpfl_adapter_ext);
diff --git a/drivers/net/cpfl/meson.build b/drivers/net/cpfl/meson.build
index 8d62ebfd77..28167bb81d 100644
--- a/drivers/net/cpfl/meson.build
+++ b/drivers/net/cpfl/meson.build
@@ -11,7 +11,7 @@ if dpdk_conf.get('RTE_IOVA_IN_MBUF') == 0
     subdir_done()
 endif
 
-deps += ['common_idpf']
+deps += ['hash', 'common_idpf']
 
 sources = files(
         'cpfl_ethdev.c',
