diff --git a/drivers/net/hns3/hns3_ethdev.c b/drivers/net/hns3/hns3_ethdev.c
index 244a3b8..62d8758 100644
--- a/drivers/net/hns3/hns3_ethdev.c
+++ b/drivers/net/hns3/hns3_ethdev.c
@@ -35,8 +35,6 @@
 #define HNS3_DEFAULT_PORT_CONF_QUEUES_NUM	1
 
 #define HNS3_SERVICE_INTERVAL		1000000 /* us */
-#define HNS3_PORT_BASE_VLAN_DISABLE	0
-#define HNS3_PORT_BASE_VLAN_ENABLE	1
 #define HNS3_INVLID_PVID		0xFFFF
 
 #define HNS3_FILTER_TYPE_VF		0
@@ -313,13 +311,14 @@ static int
 hns3_restore_vlan_table(struct hns3_adapter *hns)
 {
 	struct hns3_user_vlan_table *vlan_entry;
+	struct hns3_hw *hw = &hns->hw;
 	struct hns3_pf *pf = &hns->pf;
 	uint16_t vlan_id;
 	int ret = 0;
 
-	if (pf->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_ENABLE)
+	if (hw->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_ENABLE)
 		return hns3_vlan_pvid_configure(hns,
-						pf->port_base_vlan_cfg.pvid, 1);
+						hw->port_base_vlan_cfg.pvid, 1);
 
 	LIST_FOREACH(vlan_entry, &pf->vlan_list, next) {
 		if (vlan_entry->hd_tbl_status) {
@@ -336,7 +335,7 @@ hns3_restore_vlan_table(struct hns3_adapter *hns)
 static int
 hns3_vlan_filter_configure(struct hns3_adapter *hns, uint16_t vlan_id, int on)
 {
-	struct hns3_pf *pf = &hns->pf;
+	struct hns3_hw *hw = &hns->hw;
 	bool writen_to_tbl = false;
 	int ret = 0;
 
@@ -354,7 +353,7 @@ hns3_vlan_filter_configure(struct hns3_adapter *hns, uint16_t vlan_id, int on)
 	 * vlan list. The vlan id in vlan list will be writen in vlan filter
 	 * table until port base vlan disabled
 	 */
-	if (pf->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_DISABLE) {
+	if (hw->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_DISABLE) {
 		ret = hns3_set_port_vlan_filter(hns, vlan_id, on);
 		writen_to_tbl = true;
 	}
@@ -507,11 +506,10 @@ static int
 hns3_en_hw_strip_rxvtag(struct hns3_adapter *hns, bool enable)
 {
 	struct hns3_rx_vtag_cfg rxvlan_cfg;
-	struct hns3_pf *pf = &hns->pf;
 	struct hns3_hw *hw = &hns->hw;
 	int ret;
 
-	if (pf->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_DISABLE) {
+	if (hw->port_base_vlan_cfg.state == HNS3_PORT_BASE_VLAN_DISABLE) {
 		rxvlan_cfg.strip_tag1_en = false;
 		rxvlan_cfg.strip_tag2_en = enable;
 	} else {
@@ -728,12 +726,12 @@ hns3_vlan_txvlan_cfg(struct hns3_adapter *hns, uint16_t port_base_vlan_state,
 static void
 hns3_store_port_base_vlan_info(struct hns3_adapter *hns, uint16_t pvid, int on)
 {
-	struct hns3_pf *pf = &hns->pf;
+	struct hns3_hw *hw = &hns->hw;
 
-	pf->port_base_vlan_cfg.state = on ?
+	hw->port_base_vlan_cfg.state = on ?
 	    HNS3_PORT_BASE_VLAN_ENABLE : HNS3_PORT_BASE_VLAN_DISABLE;
 
-	pf->port_base_vlan_cfg.pvid = pvid;
+	hw->port_base_vlan_cfg.pvid = pvid;
 }
 
 static void
@@ -777,13 +775,12 @@ static void
 hns3_remove_all_vlan_table(struct hns3_adapter *hns)
 {
 	struct hns3_hw *hw = &hns->hw;
-	struct hns3_pf *pf = &hns->pf;
 	int ret;
 
 	hns3_rm_all_vlan_table(hns, true);
-	if (pf->port_base_vlan_cfg.pvid != HNS3_INVLID_PVID) {
+	if (hw->port_base_vlan_cfg.pvid != HNS3_INVLID_PVID) {
 		ret = hns3_set_port_vlan_filter(hns,
-						pf->port_base_vlan_cfg.pvid, 0);
+						hw->port_base_vlan_cfg.pvid, 0);
 		if (ret) {
 			hns3_err(hw, "Failed to remove all vlan table, ret =%d",
 				 ret);
@@ -797,7 +794,6 @@ hns3_update_vlan_filter_entries(struct hns3_adapter *hns,
 				uint16_t port_base_vlan_state,
 				uint16_t new_pvid, uint16_t old_pvid)
 {
-	struct hns3_pf *pf = &hns->pf;
 	struct hns3_hw *hw = &hns->hw;
 	int ret = 0;
 
@@ -825,7 +821,7 @@ hns3_update_vlan_filter_entries(struct hns3_adapter *hns,
 		}
 	}
 
-	if (new_pvid == pf->port_base_vlan_cfg.pvid)
+	if (new_pvid == hw->port_base_vlan_cfg.pvid)
 		hns3_add_all_vlan_table(hns);
 
 	return ret;
@@ -862,17 +858,16 @@ hns3_en_pvid_strip(struct hns3_adapter *hns, int on)
 static int
 hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid, int on)
 {
-	struct hns3_pf *pf = &hns->pf;
 	struct hns3_hw *hw = &hns->hw;
 	uint16_t port_base_vlan_state;
 	uint16_t old_pvid;
 	int ret;
 
-	if (on == 0 && pvid != pf->port_base_vlan_cfg.pvid) {
-		if (pf->port_base_vlan_cfg.pvid != HNS3_INVLID_PVID)
+	if (on == 0 && pvid != hw->port_base_vlan_cfg.pvid) {
+		if (hw->port_base_vlan_cfg.pvid != HNS3_INVLID_PVID)
 			hns3_warn(hw, "Invalid operation! As current pvid set "
 				  "is %u, disable pvid %u is invalid",
-				  pf->port_base_vlan_cfg.pvid, pvid);
+				  hw->port_base_vlan_cfg.pvid, pvid);
 		return 0;
 	}
 
@@ -894,7 +889,7 @@ hns3_vlan_pvid_configure(struct hns3_adapter *hns, uint16_t pvid, int on)
 
 	if (pvid == HNS3_INVLID_PVID)
 		goto out;
-	old_pvid = pf->port_base_vlan_cfg.pvid;
+	old_pvid = hw->port_base_vlan_cfg.pvid;
 	ret = hns3_update_vlan_filter_entries(hns, port_base_vlan_state, pvid,
 					      old_pvid);
 	if (ret) {
@@ -930,11 +925,8 @@ hns3_vlan_pvid_set(struct rte_eth_dev *dev, uint16_t pvid, int on)
 static void
 init_port_base_vlan_info(struct hns3_hw *hw)
 {
-	struct hns3_adapter *hns = HNS3_DEV_HW_TO_ADAPTER(hw);
-	struct hns3_pf *pf = &hns->pf;
-
-	pf->port_base_vlan_cfg.state = HNS3_PORT_BASE_VLAN_DISABLE;
-	pf->port_base_vlan_cfg.pvid = HNS3_INVLID_PVID;
+	hw->port_base_vlan_cfg.state = HNS3_PORT_BASE_VLAN_DISABLE;
+	hw->port_base_vlan_cfg.pvid = HNS3_INVLID_PVID;
 }
 
 static int
diff --git a/drivers/net/hns3/hns3_ethdev.h b/drivers/net/hns3/hns3_ethdev.h
index bc458cb..21412c4 100644
--- a/drivers/net/hns3/hns3_ethdev.h
+++ b/drivers/net/hns3/hns3_ethdev.h
@@ -171,6 +171,13 @@ struct hns3_fake_queue_data {
 	uint16_t nb_fake_tx_queues; /* Number of fake TX queues. */
 };
 
+#define HNS3_PORT_BASE_VLAN_DISABLE	0
+#define HNS3_PORT_BASE_VLAN_ENABLE	1
+struct hns3_port_base_vlan_config {
+	uint16_t state;
+	uint16_t pvid;
+};
+
 /* Primary process maintains driver state in main thread.
  *
  * +---------------+
@@ -395,6 +402,8 @@ struct hns3_hw {
 	uint16_t tx_qnum_per_tc;    /* TX queue number per TC */
 
 	uint32_t flag;
+
+	struct hns3_port_base_vlan_config port_base_vlan_cfg;
 	/*
 	 * PMD setup and configuration is not thread safe. Since it is not
 	 * performance sensitive, it is better to guarantee thread-safety
@@ -424,11 +433,6 @@ struct hns3_user_vlan_table {
 	uint16_t vlan_id;
 };
 
-struct hns3_port_base_vlan_config {
-	uint16_t state;
-	uint16_t pvid;
-};
-
 /* Vlan tag configuration for RX direction */
 struct hns3_rx_vtag_cfg {
 	uint8_t rx_vlan_offload_en; /* Whether enable rx vlan offload */
@@ -504,7 +508,6 @@ struct hns3_pf {
 	bool support_sfp_query;
 
 	struct hns3_vtag_cfg vtag_config;
-	struct hns3_port_base_vlan_config port_base_vlan_cfg;
 	LIST_HEAD(vlan_tbl, hns3_user_vlan_table) vlan_list;
 
 	struct hns3_fdir_info fdir; /* flow director info */
diff --git a/drivers/net/hns3/hns3_rxtx.c b/drivers/net/hns3/hns3_rxtx.c
index 25ba3b8..d870d51 100644
--- a/drivers/net/hns3/hns3_rxtx.c
+++ b/drivers/net/hns3/hns3_rxtx.c
@@ -1255,9 +1255,9 @@ rxd_pkt_info_to_pkt_type(uint32_t pkt_info, uint32_t ol_info)
 
 	static const uint32_t l2table[HNS3_L2TBL_NUM] = {
 		RTE_PTYPE_L2_ETHER,
-		RTE_PTYPE_L2_ETHER_VLAN,
 		RTE_PTYPE_L2_ETHER_QINQ,
-		0
+		RTE_PTYPE_L2_ETHER_VLAN,
+		RTE_PTYPE_L2_ETHER_VLAN
 	};
 
 	static const uint32_t l3table[HNS3_L3TBL_NUM] = {
@@ -1450,6 +1450,58 @@ hns3_rx_set_cksum_flag(struct rte_mbuf *rxm, uint64_t packet_type,
 	}
 }
 
+static inline void
+hns3_rxd_to_vlan_tci(struct rte_eth_dev *dev, struct rte_mbuf *mb,
+		     uint32_t l234_info, const struct hns3_desc *rxd)
+{
+#define HNS3_STRP_STATUS_NUM		0x4
+
+#define HNS3_NO_STRP_VLAN_VLD		0x0
+#define HNS3_INNER_STRP_VLAN_VLD	0x1
+#define HNS3_OUTER_STRP_VLAN_VLD	0x2
+	struct hns3_adapter *hns = dev->data->dev_private;
+	struct hns3_hw *hw = &hns->hw;
+	uint32_t strip_status;
+	uint32_t report_mode;
+
+	/*
+	 * Since HW limiation, the vlan tag will always be inserted into RX
+	 * descriptor when strip the tag from packet, dirver needs to determine
+	 * reporting which tag to mbuf according to the PVID configuration
+	 * and vlan striped status.
+	 */
+	static const uint32_t report_type[][HNS3_STRP_STATUS_NUM] = {
+		{
+			HNS3_NO_STRP_VLAN_VLD,
+			HNS3_OUTER_STRP_VLAN_VLD,
+			HNS3_INNER_STRP_VLAN_VLD,
+			HNS3_OUTER_STRP_VLAN_VLD
+		},
+		{
+			HNS3_NO_STRP_VLAN_VLD,
+			HNS3_NO_STRP_VLAN_VLD,
+			HNS3_NO_STRP_VLAN_VLD,
+			HNS3_INNER_STRP_VLAN_VLD
+		}
+	};
+	strip_status = hns3_get_field(l234_info, HNS3_RXD_STRP_TAGP_M,
+				      HNS3_RXD_STRP_TAGP_S);
+	report_mode = report_type[hw->port_base_vlan_cfg.state][strip_status];
+	switch (report_mode) {
+	case HNS3_NO_STRP_VLAN_VLD:
+		mb->vlan_tci = 0;
+		return;
+	case HNS3_INNER_STRP_VLAN_VLD:
+		mb->ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
+		mb->vlan_tci = rte_le_to_cpu_16(rxd->rx.vlan_tag);
+		return;
+	case HNS3_OUTER_STRP_VLAN_VLD:
+		mb->ol_flags |= PKT_RX_VLAN | PKT_RX_VLAN_STRIPPED;
+		mb->vlan_tci = rte_le_to_cpu_16(rxd->rx.ot_vlan_tag);
+		return;
+	}
+}
+
 uint16_t
 hns3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 {
@@ -1625,10 +1677,8 @@ hns3_recv_pkts(void *rx_queue, struct rte_mbuf **rx_pkts, uint16_t nb_pkts)
 			hns3_rx_set_cksum_flag(first_seg,
 					       first_seg->packet_type,
 					       cksum_err);
+		hns3_rxd_to_vlan_tci(dev, first_seg, l234_info, &rxd);
 
-		first_seg->vlan_tci = rte_le_to_cpu_16(rxd.rx.vlan_tag);
-		first_seg->vlan_tci_outer =
-			rte_le_to_cpu_16(rxd.rx.ot_vlan_tag);
 		rx_pkts[nb_rx++] = first_seg;
 		first_seg = NULL;
 		continue;
