[dpdk-dev,v4,1/2] ethdev: add vlan type for setting ether type

Message ID 1457686179-20435-2-git-send-email-helin.zhang@intel.com (mailing list archive)
State Superseded, archived
Delegated to: Thomas Monjalon
Headers

Commit Message

Zhang, Helin March 11, 2016, 8:49 a.m. UTC
  In order to set ether type of VLAN for single VLAN, inner
and outer VLAN, the VLAN type as an input parameter is added
to 'rte_eth_dev_set_vlan_ether_type()'.
In addition, corresponding changes in e1000, ixgbe and i40e
are also added.

Signed-off-by: Helin Zhang <helin.zhang@intel.com>
Acked-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
---
 app/test-pmd/cmdline.c                      | 30 +++++++++-----
 app/test-pmd/config.c                       |  9 +++--
 app/test-pmd/testpmd.h                      |  3 +-
 doc/guides/rel_notes/release_16_04.rst      |  4 ++
 doc/guides/testpmd_app_ug/testpmd_funcs.rst | 11 +----
 drivers/net/e1000/igb_ethdev.c              | 21 +++++++---
 drivers/net/i40e/i40e_ethdev.c              | 63 +++++++++++++++++++++++++++--
 drivers/net/ixgbe/ixgbe_ethdev.c            | 19 +++++++--
 lib/librte_ether/rte_ethdev.c               | 25 +++++++++++-
 lib/librte_ether/rte_ethdev.h               | 23 ++++++++++-
 lib/librte_ether/rte_ether_version.map      |  7 ++++
 11 files changed, 175 insertions(+), 40 deletions(-)

v4:
 - Updated the doc of testpmd guide.

v3:
 - Used versioning mechanism to avoid ABI issue.
 - Re-organized the patch set.

v2:
 - Used RTE_NEXT_ABI to avoid ABI change issue.
 - Reworked the announcement of ABI change for release 16.07.
  

Comments

Panu Matilainen March 11, 2016, 11:19 a.m. UTC | #1
On 03/11/2016 10:49 AM, Helin Zhang wrote:
> In order to set ether type of VLAN for single VLAN, inner
> and outer VLAN, the VLAN type as an input parameter is added
> to 'rte_eth_dev_set_vlan_ether_type()'.
> In addition, corresponding changes in e1000, ixgbe and i40e
> are also added.
>
> Signed-off-by: Helin Zhang <helin.zhang@intel.com>
> Acked-by: Wenzhuo Lu <wenzhuo.lu@intel.com>
> ---
>   app/test-pmd/cmdline.c                      | 30 +++++++++-----
>   app/test-pmd/config.c                       |  9 +++--
>   app/test-pmd/testpmd.h                      |  3 +-
>   doc/guides/rel_notes/release_16_04.rst      |  4 ++
>   doc/guides/testpmd_app_ug/testpmd_funcs.rst | 11 +----
>   drivers/net/e1000/igb_ethdev.c              | 21 +++++++---
>   drivers/net/i40e/i40e_ethdev.c              | 63 +++++++++++++++++++++++++++--
>   drivers/net/ixgbe/ixgbe_ethdev.c            | 19 +++++++--
>   lib/librte_ether/rte_ethdev.c               | 25 +++++++++++-
>   lib/librte_ether/rte_ethdev.h               | 23 ++++++++++-
>   lib/librte_ether/rte_ether_version.map      |  7 ++++
>   11 files changed, 175 insertions(+), 40 deletions(-)
>
> v4:
>   - Updated the doc of testpmd guide.
>
> v3:
>   - Used versioning mechanism to avoid ABI issue.
>   - Re-organized the patch set.
>
> v2:
>   - Used RTE_NEXT_ABI to avoid ABI change issue.
>   - Reworked the announcement of ABI change for release 16.07.
>
[...]
> @@ -1077,7 +1088,7 @@ typedef int (*vlan_filter_set_t)(struct rte_eth_dev *dev,
>   /**< @internal filtering of a VLAN Tag Identifier by an Ethernet device. */
>
>   typedef void (*vlan_tpid_set_t)(struct rte_eth_dev *dev,
> -				  uint16_t tpid);
> +				enum rte_vlan_type type, uint16_t tpid);
>   /**< @internal set the outer VLAN-TPID by an Ethernet device. */
>
>   typedef void (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
> @@ -2346,6 +2357,8 @@ int rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id,
>    *
>    * @param port_id
>    *   The port identifier of the Ethernet device.
> + * @vlan_type
> + *   The vlan type.
>    * @param tag_type
>    *   The Tag Protocol ID
>    * @return
> @@ -2353,7 +2366,13 @@ int rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id,
>    *   - (-ENOSUP) if hardware-assisted VLAN TPID setup is not supported.
>    *   - (-ENODEV) if *port_id* invalid.
>    */
> -int rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t tag_type);
> +int rte_eth_dev_set_vlan_ether_type(uint8_t port_id,
> +				    enum rte_vlan_type vlan_type,
> +				    uint16_t tag_type);
> +int rte_eth_dev_set_vlan_ether_type_v22(uint8_t port_id, uint16_t tag_type);
> +int rte_eth_dev_set_vlan_ether_type_v1604(uint8_t port_id,
> +					  enum rte_vlan_type vlan_type,
> +					  uint16_t tag_type);
>
>   /**
>    * Set VLAN offload configuration on an Ethernet device

Its nice to see people actually trying to be compatible on occasion :)

However in this case there's not much point in doing so, because 
libethdev ABI has already been broken in this cycle:
http://dpdk.org/browse/dpdk/commit/?id=cfd2279ea6299826fe992028f1dffaf9fa7e7d0a

In other words, the compatibility versions can never get invoked because 
all software built against libethdev needs to be rebuilt anyway because 
of the soname bump. Just drop the compat versions, no point carrying 
around something that cannot possibly get used.

	- Panu -
  
Thomas Monjalon March 11, 2016, 11:20 a.m. UTC | #2
2016-03-11 13:19, Panu Matilainen:
> On 03/11/2016 10:49 AM, Helin Zhang wrote:
> > -int rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t tag_type);
> > +int rte_eth_dev_set_vlan_ether_type(uint8_t port_id,
> > +				    enum rte_vlan_type vlan_type,
> > +				    uint16_t tag_type);
> > +int rte_eth_dev_set_vlan_ether_type_v22(uint8_t port_id, uint16_t tag_type);
> > +int rte_eth_dev_set_vlan_ether_type_v1604(uint8_t port_id,
> > +					  enum rte_vlan_type vlan_type,
> > +					  uint16_t tag_type);
> >
> >   /**
> >    * Set VLAN offload configuration on an Ethernet device
> 
> Its nice to see people actually trying to be compatible on occasion :)
> 
> However in this case there's not much point in doing so, because 
> libethdev ABI has already been broken in this cycle:
> http://dpdk.org/browse/dpdk/commit/?id=cfd2279ea6299826fe992028f1dffaf9fa7e7d0a
> 
> In other words, the compatibility versions can never get invoked because 
> all software built against libethdev needs to be rebuilt anyway because 
> of the soname bump. Just drop the compat versions, no point carrying 
> around something that cannot possibly get used.

Oh yes, you are right.
Sorry Helin for having required that extra work.
On the good side, you have learnt how to do it ;)
  
Zhang, Helin March 11, 2016, 2:17 p.m. UTC | #3
> -----Original Message-----
> From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> Sent: Friday, March 11, 2016 7:20 PM
> To: Panu Matilainen; Zhang, Helin
> Cc: dev@dpdk.org
> Subject: Re: [dpdk-dev] [PATCH v4 1/2] ethdev: add vlan type for setting ether
> type
> 
> 2016-03-11 13:19, Panu Matilainen:
> > On 03/11/2016 10:49 AM, Helin Zhang wrote:
> > > -int rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t
> > > tag_type);
> > > +int rte_eth_dev_set_vlan_ether_type(uint8_t port_id,
> > > +				    enum rte_vlan_type vlan_type,
> > > +				    uint16_t tag_type);
> > > +int rte_eth_dev_set_vlan_ether_type_v22(uint8_t port_id, uint16_t
> > > +tag_type); int rte_eth_dev_set_vlan_ether_type_v1604(uint8_t port_id,
> > > +					  enum rte_vlan_type vlan_type,
> > > +					  uint16_t tag_type);
> > >
> > >   /**
> > >    * Set VLAN offload configuration on an Ethernet device
> >
> > Its nice to see people actually trying to be compatible on occasion :)
> >
> > However in this case there's not much point in doing so, because
> > libethdev ABI has already been broken in this cycle:
> > http://dpdk.org/browse/dpdk/commit/?id=cfd2279ea6299826fe992028f1dffaf
> > 9fa7e7d0a
> >
> > In other words, the compatibility versions can never get invoked
> > because all software built against libethdev needs to be rebuilt
> > anyway because of the soname bump. Just drop the compat versions, no
> > point carrying around something that cannot possibly get used.
> 
> Oh yes, you are right.
> Sorry Helin for having required that extra work.
> On the good side, you have learnt how to do it ;)

Yes, as Thomas said, at leat l know how to do that, and the extra work was not too big.
Thomas, Panu, thank you very much for the great comments!

Thomas, does that mean I just need to work out a new version and just let the ABI
changes as is. No ABI annoucenment will be requried? No RTE_NEXT_ABI will be used?

Regards,
Helin
  
Thomas Monjalon March 11, 2016, 2:20 p.m. UTC | #4
2016-03-11 14:17, Zhang, Helin:
> 
> > -----Original Message-----
> > From: Thomas Monjalon [mailto:thomas.monjalon@6wind.com]
> > Sent: Friday, March 11, 2016 7:20 PM
> > To: Panu Matilainen; Zhang, Helin
> > Cc: dev@dpdk.org
> > Subject: Re: [dpdk-dev] [PATCH v4 1/2] ethdev: add vlan type for setting ether
> > type
> > 
> > 2016-03-11 13:19, Panu Matilainen:
> > > On 03/11/2016 10:49 AM, Helin Zhang wrote:
> > > > -int rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t
> > > > tag_type);
> > > > +int rte_eth_dev_set_vlan_ether_type(uint8_t port_id,
> > > > +				    enum rte_vlan_type vlan_type,
> > > > +				    uint16_t tag_type);
> > > > +int rte_eth_dev_set_vlan_ether_type_v22(uint8_t port_id, uint16_t
> > > > +tag_type); int rte_eth_dev_set_vlan_ether_type_v1604(uint8_t port_id,
> > > > +					  enum rte_vlan_type vlan_type,
> > > > +					  uint16_t tag_type);
> > > >
> > > >   /**
> > > >    * Set VLAN offload configuration on an Ethernet device
> > >
> > > Its nice to see people actually trying to be compatible on occasion :)
> > >
> > > However in this case there's not much point in doing so, because
> > > libethdev ABI has already been broken in this cycle:
> > > http://dpdk.org/browse/dpdk/commit/?id=cfd2279ea6299826fe992028f1dffaf
> > > 9fa7e7d0a
> > >
> > > In other words, the compatibility versions can never get invoked
> > > because all software built against libethdev needs to be rebuilt
> > > anyway because of the soname bump. Just drop the compat versions, no
> > > point carrying around something that cannot possibly get used.
> > 
> > Oh yes, you are right.
> > Sorry Helin for having required that extra work.
> > On the good side, you have learnt how to do it ;)
> 
> Yes, as Thomas said, at leat l know how to do that, and the extra work was not too big.
> Thomas, Panu, thank you very much for the great comments!
> 
> Thomas, does that mean I just need to work out a new version and just let the ABI
> changes as is. No ABI annoucenment will be requried? No RTE_NEXT_ABI will be used?

You just need an entry in "API changes" section of the release notes.
You can state that this API change imply an ABI change.
Thanks
  

Patch

diff --git a/app/test-pmd/cmdline.c b/app/test-pmd/cmdline.c
index 52e9f5f..1eeb8a8 100644
--- a/app/test-pmd/cmdline.c
+++ b/app/test-pmd/cmdline.c
@@ -277,8 +277,8 @@  static void cmd_help_long_parsed(void *parsed_result,
 			"    Set the VLAN QinQ (extended queue in queue)"
 			" on a port.\n\n"
 
-			"vlan set tpid (value) (port_id)\n"
-			"    Set the outer VLAN TPID for Packet Filtering on"
+			"vlan set (inner|outer) tpid (value) (port_id)\n"
+			"    Set the VLAN TPID for Packet Filtering on"
 			" a port\n\n"
 
 			"rx_vlan add (vlan_id|all) (port_id)\n"
@@ -297,10 +297,6 @@  static void cmd_help_long_parsed(void *parsed_result,
 			"    Remove a vlan_id, to the set of VLAN identifiers"
 			"filtered for VF(s) from port_id.\n\n"
 
-			"rx_vlan set tpid (value) (port_id)\n"
-			"    Set the outer VLAN TPID for Packet Filtering on"
-			" a port\n\n"
-
 			"tunnel_filter add (port_id) (outer_mac) (inner_mac) (ip_addr) "
 			"(inner_vlan) (vxlan|nvgre) (filter_type) (tenant_id) (queue_id)\n"
 			"   add a tunnel filter of a port.\n\n"
@@ -2747,6 +2743,7 @@  cmdline_parse_inst_t cmd_rx_vlan_filter_all = {
 struct cmd_vlan_offload_result {
 	cmdline_fixed_string_t vlan;
 	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t vlan_type;
 	cmdline_fixed_string_t what;
 	cmdline_fixed_string_t on;
 	cmdline_fixed_string_t port_id;
@@ -2847,6 +2844,7 @@  cmdline_parse_inst_t cmd_vlan_offload = {
 struct cmd_vlan_tpid_result {
 	cmdline_fixed_string_t vlan;
 	cmdline_fixed_string_t set;
+	cmdline_fixed_string_t vlan_type;
 	cmdline_fixed_string_t what;
 	uint16_t tp_id;
 	uint8_t port_id;
@@ -2858,8 +2856,17 @@  cmd_vlan_tpid_parsed(void *parsed_result,
 			  __attribute__((unused)) void *data)
 {
 	struct cmd_vlan_tpid_result *res = parsed_result;
-	vlan_tpid_set(res->port_id, res->tp_id);
-	return;
+	enum rte_vlan_type vlan_type;
+
+	if (!strcmp(res->vlan_type, "inner"))
+		vlan_type = ETH_VLAN_TYPE_INNER;
+	else if (!strcmp(res->vlan_type, "outer"))
+		vlan_type = ETH_VLAN_TYPE_OUTER;
+	else {
+		printf("Unknown vlan type\n");
+		return;
+	}
+	vlan_tpid_set(res->port_id, vlan_type, res->tp_id);
 }
 
 cmdline_parse_token_string_t cmd_vlan_tpid_vlan =
@@ -2868,6 +2875,9 @@  cmdline_parse_token_string_t cmd_vlan_tpid_vlan =
 cmdline_parse_token_string_t cmd_vlan_tpid_set =
 	TOKEN_STRING_INITIALIZER(struct cmd_vlan_tpid_result,
 				 set, "set");
+cmdline_parse_token_string_t cmd_vlan_type =
+	TOKEN_STRING_INITIALIZER(struct cmd_vlan_tpid_result,
+				 vlan_type, "inner#outer");
 cmdline_parse_token_string_t cmd_vlan_tpid_what =
 	TOKEN_STRING_INITIALIZER(struct cmd_vlan_tpid_result,
 				 what, "tpid");
@@ -2881,10 +2891,12 @@  cmdline_parse_token_num_t cmd_vlan_tpid_portid =
 cmdline_parse_inst_t cmd_vlan_tpid = {
 	.f = cmd_vlan_tpid_parsed,
 	.data = NULL,
-	.help_str = "set tpid tp_id port_id, set the Outer VLAN Ether type",
+	.help_str = "set inner|outer tpid tp_id port_id, set the VLAN "
+		    "Ether type",
 	.tokens = {
 		(void *)&cmd_vlan_tpid_vlan,
 		(void *)&cmd_vlan_tpid_set,
+		(void *)&cmd_vlan_type,
 		(void *)&cmd_vlan_tpid_what,
 		(void *)&cmd_vlan_tpid_tpid,
 		(void *)&cmd_vlan_tpid_portid,
diff --git a/app/test-pmd/config.c b/app/test-pmd/config.c
index 0062484..5bb09a5 100644
--- a/app/test-pmd/config.c
+++ b/app/test-pmd/config.c
@@ -1821,19 +1821,20 @@  rx_vlan_all_filter_set(portid_t port_id, int on)
 }
 
 void
-vlan_tpid_set(portid_t port_id, uint16_t tp_id)
+vlan_tpid_set(portid_t port_id, enum rte_vlan_type vlan_type, uint16_t tp_id)
 {
 	int diag;
+
 	if (port_id_is_invalid(port_id, ENABLED_WARN))
 		return;
 
-	diag = rte_eth_dev_set_vlan_ether_type(port_id, tp_id);
+	diag = rte_eth_dev_set_vlan_ether_type(port_id, vlan_type, tp_id);
 	if (diag == 0)
 		return;
 
-	printf("tx_vlan_tpid_set(port_pi=%d, tpid=%d) failed "
+	printf("tx_vlan_tpid_set(port_pi=%d, vlan_type=%d, tpid=%d) failed "
 	       "diag=%d\n",
-	       port_id, tp_id, diag);
+	       port_id, vlan_type, tp_id, diag);
 }
 
 void
diff --git a/app/test-pmd/testpmd.h b/app/test-pmd/testpmd.h
index b618998..0f72ca1 100644
--- a/app/test-pmd/testpmd.h
+++ b/app/test-pmd/testpmd.h
@@ -508,7 +508,8 @@  void rx_vlan_filter_set(portid_t port_id, int on);
 void rx_vlan_all_filter_set(portid_t port_id, int on);
 int rx_vft_set(portid_t port_id, uint16_t vlan_id, int on);
 void vlan_extend_set(portid_t port_id, int on);
-void vlan_tpid_set(portid_t port_id, uint16_t tp_id);
+void vlan_tpid_set(portid_t port_id, enum rte_vlan_type vlan_type,
+		   uint16_t tp_id);
 void tx_vlan_set(portid_t port_id, uint16_t vlan_id);
 void tx_qinq_set(portid_t port_id, uint16_t vlan_id, uint16_t vlan_id_outer);
 void tx_vlan_reset(portid_t port_id);
diff --git a/doc/guides/rel_notes/release_16_04.rst b/doc/guides/rel_notes/release_16_04.rst
index 7c09fef..c6e5ef0 100644
--- a/doc/guides/rel_notes/release_16_04.rst
+++ b/doc/guides/rel_notes/release_16_04.rst
@@ -125,6 +125,10 @@  This section should contain new features added in this release. Sample format:
 
   Af_packet device can now be detached using API, like other PMD devices.
 
+* **Added modifying ether type of both single and double VLAN for i40e**
+
+  Versioning mechanism was introduced, to avoid any ABI issue.
+
 
 Resolved Issues
 ---------------
diff --git a/doc/guides/testpmd_app_ug/testpmd_funcs.rst b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
index a520cc5..e2b2224 100644
--- a/doc/guides/testpmd_app_ug/testpmd_funcs.rst
+++ b/doc/guides/testpmd_app_ug/testpmd_funcs.rst
@@ -498,9 +498,9 @@  Set the VLAN QinQ (extended queue in queue) on for a port::
 vlan set tpid
 ~~~~~~~~~~~~~
 
-Set the outer VLAN TPID for packet filtering on a port::
+Set the inner or outer VLAN TPID for packet filtering on a port::
 
-   testpmd> vlan set tpid (value) (port_id)
+   testpmd> vlan set (inner|outer) tpid (value) (port_id)
 
 .. note::
 
@@ -540,13 +540,6 @@  Remove a VLAN ID, from the set of VLAN identifiers filtered for VF(s) for port I
 
    testpmd> rx_vlan rm (vlan_id) port (port_id) vf (vf_mask)
 
-rx_vlan set tpid
-~~~~~~~~~~~~~~~~
-
-Set the outer VLAN TPID for packet filtering on a port::
-
-   testpmd> rx_vlan set tpid (value) (port_id)
-
 tunnel_filter add
 ~~~~~~~~~~~~~~~~~
 
diff --git a/drivers/net/e1000/igb_ethdev.c b/drivers/net/e1000/igb_ethdev.c
index f889876..4549e0a 100644
--- a/drivers/net/e1000/igb_ethdev.c
+++ b/drivers/net/e1000/igb_ethdev.c
@@ -126,7 +126,9 @@  static int  eth_igb_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
 
 static int eth_igb_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
-static void eth_igb_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid_id);
+static void eth_igb_vlan_tpid_set(struct rte_eth_dev *dev,
+				  enum rte_vlan_type vlan_type,
+				  uint16_t tpid_id);
 static void eth_igb_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 
 static void igb_vlan_hw_filter_enable(struct rte_eth_dev *dev);
@@ -2194,14 +2196,23 @@  eth_igb_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 }
 
 static void
-eth_igb_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid)
+eth_igb_vlan_tpid_set(struct rte_eth_dev *dev,
+		      enum rte_vlan_type vlan_type,
+		      uint16_t tpid)
 {
 	struct e1000_hw *hw =
 		E1000_DEV_PRIVATE_TO_HW(dev->data->dev_private);
-	uint32_t reg = ETHER_TYPE_VLAN ;
+	uint32_t reg = ETHER_TYPE_VLAN;
 
-	reg |= (tpid << 16);
-	E1000_WRITE_REG(hw, E1000_VET, reg);
+	switch (vlan_type) {
+	case ETH_VLAN_TYPE_INNER:
+		reg |= (tpid << 16);
+		E1000_WRITE_REG(hw, E1000_VET, reg);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Unsupported vlan type %d\n", vlan_type);
+		break;
+	}
 }
 
 static void
diff --git a/drivers/net/i40e/i40e_ethdev.c b/drivers/net/i40e/i40e_ethdev.c
index 0c87ec1..e3fc0bc 100644
--- a/drivers/net/i40e/i40e_ethdev.c
+++ b/drivers/net/i40e/i40e_ethdev.c
@@ -266,6 +266,11 @@ 
 #define I40E_INSET_IPV6_TC_MASK       0x0009F00FUL
 #define I40E_INSET_IPV6_NEXT_HDR_MASK 0x000C00FFUL
 
+#define I40E_GL_SWT_L2TAGCTRL(_i)             (0x001C0A70 + ((_i) * 4))
+#define I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT 16
+#define I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK  \
+	I40E_MASK(0xFFFF, I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT)
+
 static int eth_i40e_dev_init(struct rte_eth_dev *eth_dev);
 static int eth_i40e_dev_uninit(struct rte_eth_dev *eth_dev);
 static int i40e_dev_configure(struct rte_eth_dev *dev);
@@ -292,7 +297,9 @@  static void i40e_dev_info_get(struct rte_eth_dev *dev,
 static int i40e_vlan_filter_set(struct rte_eth_dev *dev,
 				uint16_t vlan_id,
 				int on);
-static void i40e_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid);
+static void i40e_vlan_tpid_set(struct rte_eth_dev *dev,
+			       enum rte_vlan_type vlan_type,
+			       uint16_t tpid);
 static void i40e_vlan_offload_set(struct rte_eth_dev *dev, int mask);
 static void i40e_vlan_strip_queue_set(struct rte_eth_dev *dev,
 				      uint16_t queue,
@@ -2313,10 +2320,52 @@  i40e_vlan_filter_set(struct rte_eth_dev *dev, uint16_t vlan_id, int on)
 }
 
 static void
-i40e_vlan_tpid_set(__rte_unused struct rte_eth_dev *dev,
-		   __rte_unused uint16_t tpid)
+i40e_vlan_tpid_set(struct rte_eth_dev *dev,
+		   enum rte_vlan_type vlan_type,
+		   uint16_t tpid)
 {
-	PMD_INIT_FUNC_TRACE();
+	struct i40e_hw *hw = I40E_DEV_PRIVATE_TO_HW(dev->data->dev_private);
+	uint64_t reg_r = 0, reg_w = 0;
+	uint16_t reg_id = 0;
+	int ret;
+
+	switch (vlan_type) {
+	case ETH_VLAN_TYPE_OUTER:
+		reg_id = 2;
+		break;
+	case ETH_VLAN_TYPE_INNER:
+		reg_id = 3;
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Unsupported vlan type %d", vlan_type);
+		return;
+	}
+	ret = i40e_aq_debug_read_register(hw, I40E_GL_SWT_L2TAGCTRL(reg_id),
+					  &reg_r, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Fail to debug read from "
+			    "I40E_GL_SWT_L2TAGCTRL[%d]", reg_id);
+		return;
+	}
+	PMD_DRV_LOG(DEBUG, "Debug read from I40E_GL_SWT_L2TAGCTRL[%d]: "
+		    "0x%08"PRIx64"", reg_id, reg_r);
+
+	reg_w = reg_r & (~(I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_MASK));
+	reg_w |= ((uint64_t)tpid << I40E_GL_SWT_L2TAGCTRL_ETHERTYPE_SHIFT);
+	if (reg_r == reg_w) {
+		PMD_DRV_LOG(DEBUG, "No need to write");
+		return;
+	}
+
+	ret = i40e_aq_debug_write_register(hw, I40E_GL_SWT_L2TAGCTRL(reg_id),
+					   reg_w, NULL);
+	if (ret != I40E_SUCCESS) {
+		PMD_DRV_LOG(ERR, "Fail to debug write to "
+			    "I40E_GL_SWT_L2TAGCTRL[%d]", reg_id);
+		return;
+	}
+	PMD_DRV_LOG(DEBUG, "Debug write 0x%08"PRIx64" to "
+		    "I40E_GL_SWT_L2TAGCTRL[%d]", reg_w, reg_id);
 }
 
 static void
@@ -7332,11 +7381,17 @@  i40e_dev_filter_ctrl(struct rte_eth_dev *dev,
 static void
 i40e_hw_init(struct i40e_hw *hw)
 {
+	struct rte_eth_dev *dev = ((struct i40e_adapter *)(hw->back))->eth_dev;
+
 	/* clear the PF Queue Filter control register */
 	i40e_write_rx_ctl(hw, I40E_PFQF_CTL_0, 0);
 
 	/* Disable symmetric hash per port */
 	i40e_set_symmetric_hash_enable_per_port(hw, 0);
+
+	/* Set the global registers with default ether type value */
+	i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_OUTER, ETHER_TYPE_VLAN);
+	i40e_vlan_tpid_set(dev, ETH_VLAN_TYPE_INNER, ETHER_TYPE_VLAN);
 }
 
 enum i40e_filter_pctype
diff --git a/drivers/net/ixgbe/ixgbe_ethdev.c b/drivers/net/ixgbe/ixgbe_ethdev.c
index a9a1583..ce3ce9f 100644
--- a/drivers/net/ixgbe/ixgbe_ethdev.c
+++ b/drivers/net/ixgbe/ixgbe_ethdev.c
@@ -178,7 +178,9 @@  static int ixgbe_dev_mtu_set(struct rte_eth_dev *dev, uint16_t mtu);
 
 static int ixgbe_vlan_filter_set(struct rte_eth_dev *dev,
 		uint16_t vlan_id, int on);
-static void ixgbe_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid_id);
+static void ixgbe_vlan_tpid_set(struct rte_eth_dev *dev,
+				enum rte_vlan_type vlan_type,
+				uint16_t tpid_id);
 static void ixgbe_vlan_hw_strip_bitmap_set(struct rte_eth_dev *dev,
 		uint16_t queue, bool on);
 static void ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue,
@@ -1543,13 +1545,22 @@  ixgbe_vlan_strip_queue_set(struct rte_eth_dev *dev, uint16_t queue, int on)
 }
 
 static void
-ixgbe_vlan_tpid_set(struct rte_eth_dev *dev, uint16_t tpid)
+ixgbe_vlan_tpid_set(struct rte_eth_dev *dev,
+		    enum rte_vlan_type vlan_type,
+		    uint16_t tpid)
 {
 	struct ixgbe_hw *hw =
 		IXGBE_DEV_PRIVATE_TO_HW(dev->data->dev_private);
 
-	/* Only the high 16-bits is valid */
-	IXGBE_WRITE_REG(hw, IXGBE_EXVET, tpid << 16);
+	switch (vlan_type) {
+	case ETH_VLAN_TYPE_INNER:
+		/* Only the high 16-bits is valid */
+		IXGBE_WRITE_REG(hw, IXGBE_EXVET, tpid << 16);
+		break;
+	default:
+		PMD_DRV_LOG(ERR, "Unsupported vlan type %d\n", vlan_type);
+		break;
+	}
 }
 
 void
diff --git a/lib/librte_ether/rte_ethdev.c b/lib/librte_ether/rte_ethdev.c
index a6e83c1..bb0c3eb 100644
--- a/lib/librte_ether/rte_ethdev.c
+++ b/lib/librte_ether/rte_ethdev.c
@@ -65,6 +65,7 @@ 
 #include <rte_errno.h>
 #include <rte_spinlock.h>
 #include <rte_string_fns.h>
+#include <rte_compat.h>
 
 #include "rte_ether.h"
 #include "rte_ethdev.h"
@@ -1697,17 +1698,37 @@  rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id, int o
 }
 
 int
-rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t tpid)
+rte_eth_dev_set_vlan_ether_type_v22(uint8_t port_id, uint16_t tpid)
 {
 	struct rte_eth_dev *dev;
 
 	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
 	dev = &rte_eth_devices[port_id];
 	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->vlan_tpid_set, -ENOTSUP);
-	(*dev->dev_ops->vlan_tpid_set)(dev, tpid);
+	(*dev->dev_ops->vlan_tpid_set)(dev, ETH_VLAN_TYPE_INNER, tpid);
 
 	return 0;
 }
+VERSION_SYMBOL(rte_eth_dev_set_vlan_ether_type, _v22, 2.2);
+
+int
+rte_eth_dev_set_vlan_ether_type_v1604(uint8_t port_id,
+				      enum rte_vlan_type vlan_type,
+				      uint16_t tpid)
+{
+	struct rte_eth_dev *dev;
+
+	RTE_ETH_VALID_PORTID_OR_ERR_RET(port_id, -ENODEV);
+	dev = &rte_eth_devices[port_id];
+	RTE_FUNC_PTR_OR_ERR_RET(*dev->dev_ops->vlan_tpid_set, -ENOTSUP);
+	(*dev->dev_ops->vlan_tpid_set)(dev, vlan_type, tpid);
+
+	return 0;
+}
+BIND_DEFAULT_SYMBOL(rte_eth_dev_set_vlan_ether_type, _v1604, 16.04);
+MAP_STATIC_SYMBOL(int rte_eth_dev_set_vlan_ether_type(uint8_t port_id,
+		  enum rte_vlan_type vlan_type, uint16_t tpid),
+		  rte_eth_dev_set_vlan_ether_type_v1604);
 
 int
 rte_eth_dev_set_vlan_offload(uint8_t port_id, int offload_mask)
diff --git a/lib/librte_ether/rte_ethdev.h b/lib/librte_ether/rte_ethdev.h
index e2893ba..21db144 100644
--- a/lib/librte_ether/rte_ethdev.h
+++ b/lib/librte_ether/rte_ethdev.h
@@ -351,6 +351,17 @@  struct rte_eth_rxmode {
 };
 
 /**
+ * VLAN types to indicate if it is for single VLAN, inner VLAN or outer VLAN.
+ * Note that single VLAN is treated the same as inner VLAN.
+ */
+enum rte_vlan_type {
+	ETH_VLAN_TYPE_UNKNOWN = 0,
+	ETH_VLAN_TYPE_INNER, /**< Single VLAN, or inner VLAN. */
+	ETH_VLAN_TYPE_OUTER, /**< Outer VLAN. */
+	ETH_VLAN_TYPE_MAX,
+};
+
+/**
  * A structure used to configure the Receive Side Scaling (RSS) feature
  * of an Ethernet port.
  * If not NULL, the *rss_key* pointer of the *rss_conf* structure points
@@ -1077,7 +1088,7 @@  typedef int (*vlan_filter_set_t)(struct rte_eth_dev *dev,
 /**< @internal filtering of a VLAN Tag Identifier by an Ethernet device. */
 
 typedef void (*vlan_tpid_set_t)(struct rte_eth_dev *dev,
-				  uint16_t tpid);
+				enum rte_vlan_type type, uint16_t tpid);
 /**< @internal set the outer VLAN-TPID by an Ethernet device. */
 
 typedef void (*vlan_offload_set_t)(struct rte_eth_dev *dev, int mask);
@@ -2346,6 +2357,8 @@  int rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id,
  *
  * @param port_id
  *   The port identifier of the Ethernet device.
+ * @vlan_type
+ *   The vlan type.
  * @param tag_type
  *   The Tag Protocol ID
  * @return
@@ -2353,7 +2366,13 @@  int rte_eth_dev_set_vlan_strip_on_queue(uint8_t port_id, uint16_t rx_queue_id,
  *   - (-ENOSUP) if hardware-assisted VLAN TPID setup is not supported.
  *   - (-ENODEV) if *port_id* invalid.
  */
-int rte_eth_dev_set_vlan_ether_type(uint8_t port_id, uint16_t tag_type);
+int rte_eth_dev_set_vlan_ether_type(uint8_t port_id,
+				    enum rte_vlan_type vlan_type,
+				    uint16_t tag_type);
+int rte_eth_dev_set_vlan_ether_type_v22(uint8_t port_id, uint16_t tag_type);
+int rte_eth_dev_set_vlan_ether_type_v1604(uint8_t port_id,
+					  enum rte_vlan_type vlan_type,
+					  uint16_t tag_type);
 
 /**
  * Set VLAN offload configuration on an Ethernet device
diff --git a/lib/librte_ether/rte_ether_version.map b/lib/librte_ether/rte_ether_version.map
index d8db24d..6098de5 100644
--- a/lib/librte_ether/rte_ether_version.map
+++ b/lib/librte_ether/rte_ether_version.map
@@ -117,3 +117,10 @@  DPDK_2.2 {
 
 	local: *;
 };
+
+DPDK_16.04 {
+	global:
+
+	rte_eth_dev_set_vlan_ether_type;
+
+} DPDK_2.2;