diff mbox

[v3,1/4] net: Add support for hardware-offloaded encapsulation

Message ID 1354845419-22483-2-git-send-email-joseph.gasparakis@intel.com
State Changes Requested, archived
Delegated to: David Miller
Headers show

Commit Message

Joseph Gasparakis Dec. 7, 2012, 1:56 a.m. UTC
This patch adds support in the kernel for offloading in the NIC Tx and Rx
checksumming for encapsulated packets (such as VXLAN and IP GRE).

Signed-off-by: Joseph Gasparakis <joseph.gasparakis@intel.com>
Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
---
 include/linux/ip.h        |    5 ++
 include/linux/ipv6.h      |    5 ++
 include/linux/netdevice.h |    2 +
 include/linux/skbuff.h    |   90 ++++++++++++++++++++++++++++++++++++++++++++-
 include/linux/tcp.h       |   10 +++++
 include/linux/udp.h       |    5 ++
 net/core/skbuff.c         |    9 ++++
 7 files changed, 125 insertions(+), 1 deletions(-)

Comments

Ben Hutchings Dec. 7, 2012, 10:07 a.m. UTC | #1
On Thu, 2012-12-06 at 17:56 -0800, Joseph Gasparakis wrote:
> This patch adds support in the kernel for offloading in the NIC Tx and Rx
> checksumming for encapsulated packets (such as VXLAN and IP GRE).
[...]
> --- a/include/linux/netdevice.h
> +++ b/include/linux/netdevice.h
> @@ -1063,6 +1063,8 @@ struct net_device {
>  	netdev_features_t	wanted_features;
>  	/* mask of features inheritable by VLAN devices */
>  	netdev_features_t	vlan_features;
> +	/* mask of features inherited by encapsulating devices */
> +	netdev_features_t	hw_enc_features;
[...]

How will the networking core know *which* encapsulations this applies
to?  I notice that your implementation in ixgbe does not set
NETIF_F_HW_CSUM here, so presumably the hardware will parse headers to
find which ranges should be checksummed and it won't cover the next
encapsulation protocol that comes along.

Ben.
Duyck, Alexander H Dec. 7, 2012, 4:45 p.m. UTC | #2
On 12/07/2012 02:07 AM, Ben Hutchings wrote:
> On Thu, 2012-12-06 at 17:56 -0800, Joseph Gasparakis wrote:
>> This patch adds support in the kernel for offloading in the NIC Tx and Rx
>> checksumming for encapsulated packets (such as VXLAN and IP GRE).
> [...]
>> --- a/include/linux/netdevice.h
>> +++ b/include/linux/netdevice.h
>> @@ -1063,6 +1063,8 @@ struct net_device {
>>  	netdev_features_t	wanted_features;
>>  	/* mask of features inheritable by VLAN devices */
>>  	netdev_features_t	vlan_features;
>> +	/* mask of features inherited by encapsulating devices */
>> +	netdev_features_t	hw_enc_features;
> [...]
> 
> How will the networking core know *which* encapsulations this applies
> to?  I notice that your implementation in ixgbe does not set
> NETIF_F_HW_CSUM here, so presumably the hardware will parse headers to
> find which ranges should be checksummed and it won't cover the next
> encapsulation protocol that comes along.
> 
> Ben.
> 

Actually the offload is generic to any encapsulation that does not
compute a checksum on the inner headers.  So as long as you can treat
the outer headers as one giant L2 header you can pretty much ignore what
is in there as long as the inner network and transport header values are
set.  There are a number of tunnels that fall into that category since
most just use IP as the L2 and the L3 usually doesn't contain any checksum.

Thanks,

Alex




--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Ben Hutchings Dec. 7, 2012, 5:13 p.m. UTC | #3
On Fri, 2012-12-07 at 08:45 -0800, Alexander Duyck wrote:
> On 12/07/2012 02:07 AM, Ben Hutchings wrote:
> > On Thu, 2012-12-06 at 17:56 -0800, Joseph Gasparakis wrote:
> >> This patch adds support in the kernel for offloading in the NIC Tx and Rx
> >> checksumming for encapsulated packets (such as VXLAN and IP GRE).
> > [...]
> >> --- a/include/linux/netdevice.h
> >> +++ b/include/linux/netdevice.h
> >> @@ -1063,6 +1063,8 @@ struct net_device {
> >>  	netdev_features_t	wanted_features;
> >>  	/* mask of features inheritable by VLAN devices */
> >>  	netdev_features_t	vlan_features;
> >> +	/* mask of features inherited by encapsulating devices */
> >> +	netdev_features_t	hw_enc_features;
> > [...]
> > 
> > How will the networking core know *which* encapsulations this applies
> > to?  I notice that your implementation in ixgbe does not set
> > NETIF_F_HW_CSUM here, so presumably the hardware will parse headers to
> > find which ranges should be checksummed and it won't cover the next
> > encapsulation protocol that comes along.
> > 
> > Ben.
> > 
> 
> Actually the offload is generic to any encapsulation that does not
> compute a checksum on the inner headers.  So as long as you can treat
> the outer headers as one giant L2 header you can pretty much ignore what
> is in there as long as the inner network and transport header values are
> set.  There are a number of tunnels that fall into that category since
> most just use IP as the L2 and the L3 usually doesn't contain any checksum.

Yes, that should work, but it requires that the driver/hardware uses the
header offsets from the skb rather than parsing the packet.  This is not
currently required for devices with the NETIF_F_IP_CSUM and
NETIF_F_IPV6_CSUM features.

Please do state explicitly which feature flags are valid in
hw_enc_features, any changes in semantics, and in particular in what
cases the driver/hardware is supposed to use header offsets from the skb
vs parsing the packet.

Ben.
Joseph Gasparakis Dec. 7, 2012, 6:24 p.m. UTC | #4
On Fri, 7 Dec 2012, Ben Hutchings wrote:

> On Fri, 2012-12-07 at 08:45 -0800, Alexander Duyck wrote:
> > On 12/07/2012 02:07 AM, Ben Hutchings wrote:
> > > On Thu, 2012-12-06 at 17:56 -0800, Joseph Gasparakis wrote:
> > >> This patch adds support in the kernel for offloading in the NIC Tx and Rx
> > >> checksumming for encapsulated packets (such as VXLAN and IP GRE).
> > > [...]
> > >> --- a/include/linux/netdevice.h
> > >> +++ b/include/linux/netdevice.h
> > >> @@ -1063,6 +1063,8 @@ struct net_device {
> > >>  	netdev_features_t	wanted_features;
> > >>  	/* mask of features inheritable by VLAN devices */
> > >>  	netdev_features_t	vlan_features;
> > >> +	/* mask of features inherited by encapsulating devices */
> > >> +	netdev_features_t	hw_enc_features;
> > > [...]
> > > 
> > > How will the networking core know *which* encapsulations this applies
> > > to?  I notice that your implementation in ixgbe does not set
> > > NETIF_F_HW_CSUM here, so presumably the hardware will parse headers to
> > > find which ranges should be checksummed and it won't cover the next
> > > encapsulation protocol that comes along.
> > > 
> > > Ben.
> > > 
> > 
> > Actually the offload is generic to any encapsulation that does not
> > compute a checksum on the inner headers.  So as long as you can treat
> > the outer headers as one giant L2 header you can pretty much ignore what
> > is in there as long as the inner network and transport header values are
> > set.  There are a number of tunnels that fall into that category since
> > most just use IP as the L2 and the L3 usually doesn't contain any checksum.
> 
> Yes, that should work, but it requires that the driver/hardware uses the
> header offsets from the skb rather than parsing the packet.  This is not
> currently required for devices with the NETIF_F_IP_CSUM and
> NETIF_F_IPV6_CSUM features.
> 
> Please do state explicitly which feature flags are valid in
> hw_enc_features, any changes in semantics, and in particular in what
> cases the driver/hardware is supposed to use header offsets from the skb
> vs parsing the packet.
> 
> Ben.
> 
So the idea here is that the driver will use the headers for checksumming 
if the skb->encapsulation bit is on. The bit should be set in the protocol 
driver.

To answer the second comment, the flags that we use in this series of 
patches is NETIF_F_IP_CSUM, NETIF_F_IPV6_CSUM and NETIF_F_SG. These are 
the bits that we propose will be used for checksumming of encapsulation. 
As per a previous comment in v2, the hw_enc_features field should be used 
also in the future when NICs have more encap offloads, so one could
indicate these features there from the driver.

Furthermore, I submitted a patch for Rx checksumming, where NETIF_F_RXCSUM 
is used, again in conjunction with skb->encapsulation flag. As I mention 
in my logs, the driver is expected to set the ip_summed to UNNECESSARY and 
turn the skb->encapsulation on, to indicate that the inner headers are 
already HW checksummed.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Dec. 7, 2012, 7:28 p.m. UTC | #5
From: Joseph Gasparakis <joseph.gasparakis@intel.com>
Date: Fri, 7 Dec 2012 10:24:17 -0800 (PST)

> So the idea here is that the driver will use the headers for checksumming 
> if the skb->encapsulation bit is on. The bit should be set in the protocol 
> driver.
> 
> To answer the second comment, the flags that we use in this series of 
> patches is NETIF_F_IP_CSUM, NETIF_F_IPV6_CSUM and NETIF_F_SG. These are 
> the bits that we propose will be used for checksumming of encapsulation. 
> As per a previous comment in v2, the hw_enc_features field should be used 
> also in the future when NICs have more encap offloads, so one could
> indicate these features there from the driver.
> 
> Furthermore, I submitted a patch for Rx checksumming, where NETIF_F_RXCSUM 
> is used, again in conjunction with skb->encapsulation flag. As I mention 
> in my logs, the driver is expected to set the ip_summed to UNNECESSARY and 
> turn the skb->encapsulation on, to indicate that the inner headers are 
> already HW checksummed.
> 

This is the kind of language that belongs in the commit message and
code comments.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Dec. 7, 2012, 7:37 p.m. UTC | #6
From: Joseph Gasparakis <joseph.gasparakis@intel.com>
Date: Fri, 7 Dec 2012 11:41:46 -0800 (PST)

> 
> 
> On Fri, 7 Dec 2012, David Miller wrote:
> 
>> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
>> Date: Fri, 7 Dec 2012 10:24:17 -0800 (PST)
>> 
>> > So the idea here is that the driver will use the headers for checksumming 
>> > if the skb->encapsulation bit is on. The bit should be set in the protocol 
>> > driver.
>> > 
>> > To answer the second comment, the flags that we use in this series of 
>> > patches is NETIF_F_IP_CSUM, NETIF_F_IPV6_CSUM and NETIF_F_SG. These are 
>> > the bits that we propose will be used for checksumming of encapsulation. 
>> > As per a previous comment in v2, the hw_enc_features field should be used 
>> > also in the future when NICs have more encap offloads, so one could
>> > indicate these features there from the driver.
>> > 
>> > Furthermore, I submitted a patch for Rx checksumming, where NETIF_F_RXCSUM 
>> > is used, again in conjunction with skb->encapsulation flag. As I mention 
>> > in my logs, the driver is expected to set the ip_summed to UNNECESSARY and 
>> > turn the skb->encapsulation on, to indicate that the inner headers are 
>> > already HW checksummed.
>> > 
>> 
>> This is the kind of language that belongs in the commit message and
>> code comments.
>> 
> Sure. I'll wait to gather some more feedback if there is any and I will 
> re-spin this off adding more code comments and clarify this in the logs.

Great.

Please note that this request applies to your receive side change too.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joseph Gasparakis Dec. 7, 2012, 7:41 p.m. UTC | #7
On Fri, 7 Dec 2012, David Miller wrote:

> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
> Date: Fri, 7 Dec 2012 10:24:17 -0800 (PST)
> 
> > So the idea here is that the driver will use the headers for checksumming 
> > if the skb->encapsulation bit is on. The bit should be set in the protocol 
> > driver.
> > 
> > To answer the second comment, the flags that we use in this series of 
> > patches is NETIF_F_IP_CSUM, NETIF_F_IPV6_CSUM and NETIF_F_SG. These are 
> > the bits that we propose will be used for checksumming of encapsulation. 
> > As per a previous comment in v2, the hw_enc_features field should be used 
> > also in the future when NICs have more encap offloads, so one could
> > indicate these features there from the driver.
> > 
> > Furthermore, I submitted a patch for Rx checksumming, where NETIF_F_RXCSUM 
> > is used, again in conjunction with skb->encapsulation flag. As I mention 
> > in my logs, the driver is expected to set the ip_summed to UNNECESSARY and 
> > turn the skb->encapsulation on, to indicate that the inner headers are 
> > already HW checksummed.
> > 
> 
> This is the kind of language that belongs in the commit message and
> code comments.
> 
Sure. I'll wait to gather some more feedback if there is any and I will 
re-spin this off adding more code comments and clarify this in the logs.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
David Miller Dec. 7, 2012, 7:52 p.m. UTC | #8
From: Joseph Gasparakis <joseph.gasparakis@intel.com>
Date: Fri, 7 Dec 2012 11:52:43 -0800 (PST)

> 
> 
> On Fri, 7 Dec 2012, David Miller wrote:
> 
>> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
>> Date: Fri, 7 Dec 2012 11:41:46 -0800 (PST)
>> 
>> > 
>> > 
>> > On Fri, 7 Dec 2012, David Miller wrote:
>> > 
>> >> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
>> >> Date: Fri, 7 Dec 2012 10:24:17 -0800 (PST)
>> >> 
>> >> > So the idea here is that the driver will use the headers for checksumming 
>> >> > if the skb->encapsulation bit is on. The bit should be set in the protocol 
>> >> > driver.
>> >> > 
>> >> > To answer the second comment, the flags that we use in this series of 
>> >> > patches is NETIF_F_IP_CSUM, NETIF_F_IPV6_CSUM and NETIF_F_SG. These are 
>> >> > the bits that we propose will be used for checksumming of encapsulation. 
>> >> > As per a previous comment in v2, the hw_enc_features field should be used 
>> >> > also in the future when NICs have more encap offloads, so one could
>> >> > indicate these features there from the driver.
>> >> > 
>> >> > Furthermore, I submitted a patch for Rx checksumming, where NETIF_F_RXCSUM 
>> >> > is used, again in conjunction with skb->encapsulation flag. As I mention 
>> >> > in my logs, the driver is expected to set the ip_summed to UNNECESSARY and 
>> >> > turn the skb->encapsulation on, to indicate that the inner headers are 
>> >> > already HW checksummed.
>> >> > 
>> >> 
>> >> This is the kind of language that belongs in the commit message and
>> >> code comments.
>> >> 
>> > Sure. I'll wait to gather some more feedback if there is any and I will 
>> > re-spin this off adding more code comments and clarify this in the logs.
>> 
>> Great.
>> 
>> Please note that this request applies to your receive side change too.
>> 
> I believe the logs are sufficient in the rx patch:
> 
> This patch adds capability in vxlan to identify received
> checksummed inner packets and signal them to the upper layers of
> the stack. The driver needs to set the skb->encapsulation bit
> and also set the skb->ip_summed to CHECKSUM_UNNECESSARY.
> 
> ...but I can add more comments to the code if this is what you are 
> referring to.

Yes, please do.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joseph Gasparakis Dec. 7, 2012, 7:52 p.m. UTC | #9
On Fri, 7 Dec 2012, David Miller wrote:

> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
> Date: Fri, 7 Dec 2012 11:41:46 -0800 (PST)
> 
> > 
> > 
> > On Fri, 7 Dec 2012, David Miller wrote:
> > 
> >> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
> >> Date: Fri, 7 Dec 2012 10:24:17 -0800 (PST)
> >> 
> >> > So the idea here is that the driver will use the headers for checksumming 
> >> > if the skb->encapsulation bit is on. The bit should be set in the protocol 
> >> > driver.
> >> > 
> >> > To answer the second comment, the flags that we use in this series of 
> >> > patches is NETIF_F_IP_CSUM, NETIF_F_IPV6_CSUM and NETIF_F_SG. These are 
> >> > the bits that we propose will be used for checksumming of encapsulation. 
> >> > As per a previous comment in v2, the hw_enc_features field should be used 
> >> > also in the future when NICs have more encap offloads, so one could
> >> > indicate these features there from the driver.
> >> > 
> >> > Furthermore, I submitted a patch for Rx checksumming, where NETIF_F_RXCSUM 
> >> > is used, again in conjunction with skb->encapsulation flag. As I mention 
> >> > in my logs, the driver is expected to set the ip_summed to UNNECESSARY and 
> >> > turn the skb->encapsulation on, to indicate that the inner headers are 
> >> > already HW checksummed.
> >> > 
> >> 
> >> This is the kind of language that belongs in the commit message and
> >> code comments.
> >> 
> > Sure. I'll wait to gather some more feedback if there is any and I will 
> > re-spin this off adding more code comments and clarify this in the logs.
> 
> Great.
> 
> Please note that this request applies to your receive side change too.
> 
I believe the logs are sufficient in the rx patch:

This patch adds capability in vxlan to identify received
checksummed inner packets and signal them to the upper layers of
the stack. The driver needs to set the skb->encapsulation bit
and also set the skb->ip_summed to CHECKSUM_UNNECESSARY.

...but I can add more comments to the code if this is what you are 
referring to.

--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Joseph Gasparakis Dec. 7, 2012, 8:18 p.m. UTC | #10
On Fri, 7 Dec 2012, David Miller wrote:

> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
> Date: Fri, 7 Dec 2012 11:52:43 -0800 (PST)
> 
> > 
> > 
> > On Fri, 7 Dec 2012, David Miller wrote:
> > 
> >> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
> >> Date: Fri, 7 Dec 2012 11:41:46 -0800 (PST)
> >> 
> >> > 
> >> > 
> >> > On Fri, 7 Dec 2012, David Miller wrote:
> >> > 
> >> >> From: Joseph Gasparakis <joseph.gasparakis@intel.com>
> >> >> Date: Fri, 7 Dec 2012 10:24:17 -0800 (PST)
> >> >> 
> >> >> > So the idea here is that the driver will use the headers for checksumming 
> >> >> > if the skb->encapsulation bit is on. The bit should be set in the protocol 
> >> >> > driver.
> >> >> > 
> >> >> > To answer the second comment, the flags that we use in this series of 
> >> >> > patches is NETIF_F_IP_CSUM, NETIF_F_IPV6_CSUM and NETIF_F_SG. These are 
> >> >> > the bits that we propose will be used for checksumming of encapsulation. 
> >> >> > As per a previous comment in v2, the hw_enc_features field should be used 
> >> >> > also in the future when NICs have more encap offloads, so one could
> >> >> > indicate these features there from the driver.
> >> >> > 
> >> >> > Furthermore, I submitted a patch for Rx checksumming, where NETIF_F_RXCSUM 
> >> >> > is used, again in conjunction with skb->encapsulation flag. As I mention 
> >> >> > in my logs, the driver is expected to set the ip_summed to UNNECESSARY and 
> >> >> > turn the skb->encapsulation on, to indicate that the inner headers are 
> >> >> > already HW checksummed.
> >> >> > 
> >> >> 
> >> >> This is the kind of language that belongs in the commit message and
> >> >> code comments.
> >> >> 
> >> > Sure. I'll wait to gather some more feedback if there is any and I will 
> >> > re-spin this off adding more code comments and clarify this in the logs.
> >> 
> >> Great.
> >> 
> >> Please note that this request applies to your receive side change too.
> >> 
> > I believe the logs are sufficient in the rx patch:
> > 
> > This patch adds capability in vxlan to identify received
> > checksummed inner packets and signal them to the upper layers of
> > the stack. The driver needs to set the skb->encapsulation bit
> > and also set the skb->ip_summed to CHECKSUM_UNNECESSARY.
> > 
> > ...but I can add more comments to the code if this is what you are 
> > referring to.
> 
> Yes, please do.
> 
I will! Thanks.
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Jeff Kirsher Dec. 7, 2012, 11:15 p.m. UTC | #11
On 12/06/2012 05:56 PM, Joseph Gasparakis wrote:
> This patch adds support in the kernel for offloading in the NIC Tx and Rx
> checksumming for encapsulated packets (such as VXLAN and IP GRE).
>
> Signed-off-by: Joseph Gasparakis <joseph.gasparakis@intel.com>
> Signed-off-by: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
> Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
> ---
>  include/linux/ip.h        |    5 ++
>  include/linux/ipv6.h      |    5 ++
>  include/linux/netdevice.h |    2 +
>  include/linux/skbuff.h    |   90 ++++++++++++++++++++++++++++++++++++++++++++-
>  include/linux/tcp.h       |   10 +++++
>  include/linux/udp.h       |    5 ++
>  net/core/skbuff.c         |    9 ++++
>  7 files changed, 125 insertions(+), 1 deletions(-)
Acked-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
diff mbox

Patch

diff --git a/include/linux/ip.h b/include/linux/ip.h
index 58b82a2..492bc65 100644
--- a/include/linux/ip.h
+++ b/include/linux/ip.h
@@ -25,6 +25,11 @@  static inline struct iphdr *ip_hdr(const struct sk_buff *skb)
 	return (struct iphdr *)skb_network_header(skb);
 }
 
+static inline struct iphdr *inner_ip_hdr(const struct sk_buff *skb)
+{
+	return (struct iphdr *)skb_inner_network_header(skb);
+}
+
 static inline struct iphdr *ipip_hdr(const struct sk_buff *skb)
 {
 	return (struct iphdr *)skb_transport_header(skb);
diff --git a/include/linux/ipv6.h b/include/linux/ipv6.h
index 5e11905..eded08c 100644
--- a/include/linux/ipv6.h
+++ b/include/linux/ipv6.h
@@ -67,6 +67,11 @@  static inline struct ipv6hdr *ipv6_hdr(const struct sk_buff *skb)
 	return (struct ipv6hdr *)skb_network_header(skb);
 }
 
+static inline struct ipv6hdr *inner_ipv6_hdr(const struct sk_buff *skb)
+{
+	return (struct ipv6hdr *)skb_inner_network_header(skb);
+}
+
 static inline struct ipv6hdr *ipipv6_hdr(const struct sk_buff *skb)
 {
 	return (struct ipv6hdr *)skb_transport_header(skb);
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index e9929ab..58530bc 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1063,6 +1063,8 @@  struct net_device {
 	netdev_features_t	wanted_features;
 	/* mask of features inheritable by VLAN devices */
 	netdev_features_t	vlan_features;
+	/* mask of features inherited by encapsulating devices */
+	netdev_features_t	hw_enc_features;
 
 	/* Interface index. Unique device identifier	*/
 	int			ifindex;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index f2af494..d6933a0 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -376,6 +376,8 @@  typedef unsigned char *sk_buff_data_t;
  *	@mark: Generic packet mark
  *	@dropcount: total number of sk_receive_queue overflows
  *	@vlan_tci: vlan tag control information
+ *	@inner_transport_header: Inner transport layer header (encapsulation)
+ *	@inner_network_header: Network layer header (encapsulation)
  *	@transport_header: Transport layer header
  *	@network_header: Network layer header
  *	@mac_header: Link layer header
@@ -471,7 +473,8 @@  struct sk_buff {
 	__u8			wifi_acked:1;
 	__u8			no_fcs:1;
 	__u8			head_frag:1;
-	/* 8/10 bit hole (depending on ndisc_nodetype presence) */
+	__u8			encapsulation:1;
+	/* 7/9 bit hole (depending on ndisc_nodetype presence) */
 	kmemcheck_bitfield_end(flags2);
 
 #ifdef CONFIG_NET_DMA
@@ -486,6 +489,8 @@  struct sk_buff {
 		__u32		avail_size;
 	};
 
+	sk_buff_data_t		inner_transport_header;
+	sk_buff_data_t		inner_network_header;
 	sk_buff_data_t		transport_header;
 	sk_buff_data_t		network_header;
 	sk_buff_data_t		mac_header;
@@ -1435,12 +1440,53 @@  static inline void skb_reserve(struct sk_buff *skb, int len)
 	skb->tail += len;
 }
 
+static inline void skb_reset_inner_headers(struct sk_buff *skb)
+{
+	skb->inner_network_header = skb->network_header;
+	skb->inner_transport_header = skb->transport_header;
+}
+
 static inline void skb_reset_mac_len(struct sk_buff *skb)
 {
 	skb->mac_len = skb->network_header - skb->mac_header;
 }
 
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
+static inline unsigned char *skb_inner_transport_header(const struct sk_buff
+							*skb)
+{
+	return skb->head + skb->inner_transport_header;
+}
+
+static inline void skb_reset_inner_transport_header(struct sk_buff *skb)
+{
+	skb->inner_transport_header = skb->data - skb->head;
+}
+
+static inline void skb_set_inner_transport_header(struct sk_buff *skb,
+						   const int offset)
+{
+	skb_reset_inner_transport_header(skb);
+	skb->inner_transport_header += offset;
+}
+
+static inline unsigned char *skb_inner_network_header(const struct sk_buff *skb)
+{
+	return skb->head + skb->inner_network_header;
+}
+
+static inline void skb_reset_inner_network_header(struct sk_buff *skb)
+{
+	skb->inner_network_header = skb->data - skb->head;
+}
+
+static inline void skb_set_inner_network_header(struct sk_buff *skb,
+						const int offset)
+{
+	skb_reset_inner_network_header(skb);
+	skb->inner_network_header += offset;
+}
+
 static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
 {
 	return skb->head + skb->transport_header;
@@ -1496,6 +1542,38 @@  static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
 }
 
 #else /* NET_SKBUFF_DATA_USES_OFFSET */
+static inline unsigned char *skb_inner_transport_header(const struct sk_buff
+							*skb)
+{
+	return skb->inner_transport_header;
+}
+
+static inline void skb_reset_inner_transport_header(struct sk_buff *skb)
+{
+	skb->inner_transport_header = skb->data;
+}
+
+static inline void skb_set_inner_transport_header(struct sk_buff *skb,
+						   const int offset)
+{
+	skb->inner_transport_header = skb->data + offset;
+}
+
+static inline unsigned char *skb_inner_network_header(const struct sk_buff *skb)
+{
+	return skb->inner_network_header;
+}
+
+static inline void skb_reset_inner_network_header(struct sk_buff *skb)
+{
+	skb->inner_network_header = skb->data;
+}
+
+static inline void skb_set_inner_network_header(struct sk_buff *skb,
+						const int offset)
+{
+	skb->inner_network_header = skb->data + offset;
+}
 
 static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
 {
@@ -1574,11 +1652,21 @@  static inline u32 skb_network_header_len(const struct sk_buff *skb)
 	return skb->transport_header - skb->network_header;
 }
 
+static inline u32 skb_inner_network_header_len(const struct sk_buff *skb)
+{
+	return skb->inner_transport_header - skb->inner_network_header;
+}
+
 static inline int skb_network_offset(const struct sk_buff *skb)
 {
 	return skb_network_header(skb) - skb->data;
 }
 
+static inline int skb_inner_network_offset(const struct sk_buff *skb)
+{
+	return skb_inner_network_header(skb) - skb->data;
+}
+
 static inline int pskb_network_may_pull(struct sk_buff *skb, unsigned int len)
 {
 	return pskb_may_pull(skb, skb_network_offset(skb) + len);
diff --git a/include/linux/tcp.h b/include/linux/tcp.h
index 60b7aac..4e1d228 100644
--- a/include/linux/tcp.h
+++ b/include/linux/tcp.h
@@ -35,6 +35,16 @@  static inline unsigned int tcp_hdrlen(const struct sk_buff *skb)
 	return tcp_hdr(skb)->doff * 4;
 }
 
+static inline struct tcphdr *inner_tcp_hdr(const struct sk_buff *skb)
+{
+	return (struct tcphdr *)skb_inner_transport_header(skb);
+}
+
+static inline unsigned int inner_tcp_hdrlen(const struct sk_buff *skb)
+{
+	return inner_tcp_hdr(skb)->doff * 4;
+}
+
 static inline unsigned int tcp_optlen(const struct sk_buff *skb)
 {
 	return (tcp_hdr(skb)->doff - 5) * 4;
diff --git a/include/linux/udp.h b/include/linux/udp.h
index 0b67d77..9d81de1 100644
--- a/include/linux/udp.h
+++ b/include/linux/udp.h
@@ -27,6 +27,11 @@  static inline struct udphdr *udp_hdr(const struct sk_buff *skb)
 	return (struct udphdr *)skb_transport_header(skb);
 }
 
+static inline struct udphdr *inner_udp_hdr(const struct sk_buff *skb)
+{
+	return (struct udphdr *)skb_inner_transport_header(skb);
+}
+
 #define UDP_HTABLE_SIZE_MIN		(CONFIG_BASE_SMALL ? 128 : 256)
 
 static inline int udp_hashfn(struct net *net, unsigned num, unsigned mask)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 880722e2..ccbabf5 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -682,11 +682,14 @@  static void __copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 	new->transport_header	= old->transport_header;
 	new->network_header	= old->network_header;
 	new->mac_header		= old->mac_header;
+	new->inner_transport_header = old->inner_transport_header;
+	new->inner_network_header = old->inner_transport_header;
 	skb_dst_copy(new, old);
 	new->rxhash		= old->rxhash;
 	new->ooo_okay		= old->ooo_okay;
 	new->l4_rxhash		= old->l4_rxhash;
 	new->no_fcs		= old->no_fcs;
+	new->encapsulation	= old->encapsulation;
 #ifdef CONFIG_XFRM
 	new->sp			= secpath_get(old->sp);
 #endif
@@ -892,6 +895,8 @@  static void copy_skb_header(struct sk_buff *new, const struct sk_buff *old)
 	new->network_header   += offset;
 	if (skb_mac_header_was_set(new))
 		new->mac_header	      += offset;
+	new->inner_transport_header += offset;
+	new->inner_network_header   += offset;
 #endif
 	skb_shinfo(new)->gso_size = skb_shinfo(old)->gso_size;
 	skb_shinfo(new)->gso_segs = skb_shinfo(old)->gso_segs;
@@ -1089,6 +1094,8 @@  int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 	skb->network_header   += off;
 	if (skb_mac_header_was_set(skb))
 		skb->mac_header += off;
+	skb->inner_transport_header += off;
+	skb->inner_network_header += off;
 	/* Only adjust this if it actually is csum_start rather than csum */
 	if (skb->ip_summed == CHECKSUM_PARTIAL)
 		skb->csum_start += nhead;
@@ -1188,6 +1195,8 @@  struct sk_buff *skb_copy_expand(const struct sk_buff *skb,
 	n->network_header   += off;
 	if (skb_mac_header_was_set(skb))
 		n->mac_header += off;
+	n->inner_transport_header += off;
+	n->inner_network_header	   += off;
 #endif
 
 	return n;