* [PATCH v2 net-next 1/5] udp: Generalize skb_udp_segment
2014-09-30 3:22 [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels Tom Herbert
@ 2014-09-30 3:22 ` Tom Herbert
2014-09-30 3:22 ` [PATCH v2 net-next 2/5] sit: Set inner IP protocol in sit Tom Herbert
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
skb_udp_segment is the function called from udp4_ufo_fragment to
segment a UDP tunnel packet. This function currently assumes
segmentation is transparent Ethernet bridging (i.e. VXLAN
encapsulation). This patch generalizes the function to
operate on either Ethertype or IP protocol.
The inner_protocol field must be set to the protocol of the inner
header. This can now be either an Ethertype or an IP protocol
(in a union). A new flag in the skbuff indicates which type is
effective. skb_set_inner_protocol and skb_set_inner_ipproto
helper functions were added to set the inner_protocol. These
functions are called from the point where the tunnel encapsulation
is occuring.
When skb_udp_tunnel_segment is called, the function to segment the
inner packet is selected based on the inner IP or Ethertype. In the
case of an IP protocol encapsulation, the function is derived from
inet[6]_offloads. In the case of Ethertype, skb->protocol is
set to the inner_protocol and skb_mac_gso_segment is called. (GRE
currently does this, but it might be possible to lookup the protocol
in offload_base and call the appropriate segmenation function
directly).
Signed-off-by: Tom Herbert <therbert@google.com>
---
include/linux/skbuff.h | 26 +++++++++++++++++++++++--
include/net/udp.h | 3 ++-
net/ipv4/udp_offload.c | 51 +++++++++++++++++++++++++++++++++++++++++++++-----
net/ipv6/udp_offload.c | 2 +-
4 files changed, 73 insertions(+), 9 deletions(-)
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 262efdb..49bc464 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -596,7 +596,8 @@ struct sk_buff {
__u8 ndisc_nodetype:2;
#endif
__u8 ipvs_property:1;
- /* 5 or 7 bit hole */
+ __u8 inner_protocol_type:1;
+ /* 4 or 6 bit hole */
#ifdef CONFIG_NET_SCHED
__u16 tc_index; /* traffic control index */
@@ -632,7 +633,11 @@ struct sk_buff {
__u32 reserved_tailroom;
};
- __be16 inner_protocol;
+ union {
+ __be16 inner_protocol;
+ __u8 inner_ipproto;
+ };
+
__u16 inner_transport_header;
__u16 inner_network_header;
__u16 inner_mac_header;
@@ -1737,6 +1742,23 @@ static inline void skb_reserve(struct sk_buff *skb, int len)
skb->tail += len;
}
+#define ENCAP_TYPE_ETHER 0
+#define ENCAP_TYPE_IPPROTO 1
+
+static inline void skb_set_inner_protocol(struct sk_buff *skb,
+ __be16 protocol)
+{
+ skb->inner_protocol = protocol;
+ skb->inner_protocol_type = ENCAP_TYPE_ETHER;
+}
+
+static inline void skb_set_inner_ipproto(struct sk_buff *skb,
+ __u8 ipproto)
+{
+ skb->inner_ipproto = ipproto;
+ skb->inner_protocol_type = ENCAP_TYPE_IPPROTO;
+}
+
static inline void skb_reset_inner_headers(struct sk_buff *skb)
{
skb->inner_mac_header = skb->mac_header;
diff --git a/include/net/udp.h b/include/net/udp.h
index 16f4e80..07f9b70 100644
--- a/include/net/udp.h
+++ b/include/net/udp.h
@@ -239,7 +239,8 @@ int udp_ioctl(struct sock *sk, int cmd, unsigned long arg);
int udp_disconnect(struct sock *sk, int flags);
unsigned int udp_poll(struct file *file, struct socket *sock, poll_table *wait);
struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
- netdev_features_t features);
+ netdev_features_t features,
+ bool is_ipv6);
int udp_lib_getsockopt(struct sock *sk, int level, int optname,
char __user *optval, int __user *optlen);
int udp_lib_setsockopt(struct sock *sk, int level, int optname,
diff --git a/net/ipv4/udp_offload.c b/net/ipv4/udp_offload.c
index 19ebe6a..8c35f2c 100644
--- a/net/ipv4/udp_offload.c
+++ b/net/ipv4/udp_offload.c
@@ -25,8 +25,11 @@ struct udp_offload_priv {
struct udp_offload_priv __rcu *next;
};
-struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
- netdev_features_t features)
+static struct sk_buff *__skb_udp_tunnel_segment(struct sk_buff *skb,
+ netdev_features_t features,
+ struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb,
+ netdev_features_t features),
+ __be16 new_protocol)
{
struct sk_buff *segs = ERR_PTR(-EINVAL);
u16 mac_offset = skb->mac_header;
@@ -48,7 +51,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
skb_reset_mac_header(skb);
skb_set_network_header(skb, skb_inner_network_offset(skb));
skb->mac_len = skb_inner_network_offset(skb);
- skb->protocol = htons(ETH_P_TEB);
+ skb->protocol = new_protocol;
need_csum = !!(skb_shinfo(skb)->gso_type & SKB_GSO_UDP_TUNNEL_CSUM);
if (need_csum)
@@ -56,7 +59,7 @@ struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
/* segment inner packet. */
enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
- segs = skb_mac_gso_segment(skb, enc_features);
+ segs = gso_inner_segment(skb, enc_features);
if (IS_ERR_OR_NULL(segs)) {
skb_gso_error_unwind(skb, protocol, tnl_hlen, mac_offset,
mac_len);
@@ -101,6 +104,44 @@ out:
return segs;
}
+struct sk_buff *skb_udp_tunnel_segment(struct sk_buff *skb,
+ netdev_features_t features,
+ bool is_ipv6)
+{
+ __be16 protocol = skb->protocol;
+ const struct net_offload **offloads;
+ const struct net_offload *ops;
+ struct sk_buff *segs = ERR_PTR(-EINVAL);
+ struct sk_buff *(*gso_inner_segment)(struct sk_buff *skb,
+ netdev_features_t features);
+
+ rcu_read_lock();
+
+ switch (skb->inner_protocol_type) {
+ case ENCAP_TYPE_ETHER:
+ protocol = skb->inner_protocol;
+ gso_inner_segment = skb_mac_gso_segment;
+ break;
+ case ENCAP_TYPE_IPPROTO:
+ offloads = is_ipv6 ? inet6_offloads : inet_offloads;
+ ops = rcu_dereference(offloads[skb->inner_ipproto]);
+ if (!ops || !ops->callbacks.gso_segment)
+ goto out_unlock;
+ gso_inner_segment = ops->callbacks.gso_segment;
+ break;
+ default:
+ goto out_unlock;
+ }
+
+ segs = __skb_udp_tunnel_segment(skb, features, gso_inner_segment,
+ protocol);
+
+out_unlock:
+ rcu_read_unlock();
+
+ return segs;
+}
+
static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
netdev_features_t features)
{
@@ -113,7 +154,7 @@ static struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
if (skb->encapsulation &&
(skb_shinfo(skb)->gso_type &
(SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))) {
- segs = skb_udp_tunnel_segment(skb, features);
+ segs = skb_udp_tunnel_segment(skb, features, false);
goto out;
}
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 212ebfc..8f96988 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -58,7 +58,7 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
if (skb->encapsulation && skb_shinfo(skb)->gso_type &
(SKB_GSO_UDP_TUNNEL|SKB_GSO_UDP_TUNNEL_CSUM))
- segs = skb_udp_tunnel_segment(skb, features);
+ segs = skb_udp_tunnel_segment(skb, features, true);
else {
const struct ipv6hdr *ipv6h;
struct udphdr *uh;
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 net-next 2/5] sit: Set inner IP protocol in sit
2014-09-30 3:22 [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels Tom Herbert
2014-09-30 3:22 ` [PATCH v2 net-next 1/5] udp: Generalize skb_udp_segment Tom Herbert
@ 2014-09-30 3:22 ` Tom Herbert
2014-09-30 3:22 ` [PATCH v2 net-next 3/5] ipip: Set inner IP protocol in ipip Tom Herbert
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
Call skb_set_inner_ipproto to set inner IP protocol to IPPROTO_IPV6
before tunnel_xmit. This is needed if UDP encapsulation (fou) is
being done.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv6/sit.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/net/ipv6/sit.c b/net/ipv6/sit.c
index db75809..0d4e274 100644
--- a/net/ipv6/sit.c
+++ b/net/ipv6/sit.c
@@ -982,6 +982,8 @@ static netdev_tx_t ipip6_tunnel_xmit(struct sk_buff *skb,
goto tx_error;
}
+ skb_set_inner_ipproto(skb, IPPROTO_IPV6);
+
err = iptunnel_xmit(skb->sk, rt, skb, fl4.saddr, fl4.daddr,
protocol, tos, ttl, df,
!net_eq(tunnel->net, dev_net(dev)));
@@ -1006,6 +1008,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (IS_ERR(skb))
goto out;
+ skb_set_inner_ipproto(skb, IPPROTO_IPIP);
+
ip_tunnel_xmit(skb, dev, tiph, IPPROTO_IPIP);
return NETDEV_TX_OK;
out:
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 net-next 3/5] ipip: Set inner IP protocol in ipip
2014-09-30 3:22 [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels Tom Herbert
2014-09-30 3:22 ` [PATCH v2 net-next 1/5] udp: Generalize skb_udp_segment Tom Herbert
2014-09-30 3:22 ` [PATCH v2 net-next 2/5] sit: Set inner IP protocol in sit Tom Herbert
@ 2014-09-30 3:22 ` Tom Herbert
2014-09-30 3:22 ` [PATCH v2 net-next 4/5] gre: Set inner protocol in v4 and v6 GRE transmit Tom Herbert
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
Call skb_set_inner_ipproto to set inner IP protocol to IPPROTO_IPV4
before tunnel_xmit. This is needed if UDP encapsulation (fou) is
being done.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv4/ipip.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/net/ipv4/ipip.c b/net/ipv4/ipip.c
index bfec31d..ea88ab3 100644
--- a/net/ipv4/ipip.c
+++ b/net/ipv4/ipip.c
@@ -224,6 +224,8 @@ static netdev_tx_t ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
if (IS_ERR(skb))
goto out;
+ skb_set_inner_ipproto(skb, IPPROTO_IPIP);
+
ip_tunnel_xmit(skb, dev, tiph, tiph->protocol);
return NETDEV_TX_OK;
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 net-next 4/5] gre: Set inner protocol in v4 and v6 GRE transmit
2014-09-30 3:22 [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels Tom Herbert
` (2 preceding siblings ...)
2014-09-30 3:22 ` [PATCH v2 net-next 3/5] ipip: Set inner IP protocol in ipip Tom Herbert
@ 2014-09-30 3:22 ` Tom Herbert
2014-09-30 3:22 ` [PATCH v2 net-next 5/5] vxlan: Set inner protocol before transmit Tom Herbert
2014-10-02 1:36 ` [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels David Miller
5 siblings, 0 replies; 7+ messages in thread
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
Call skb_set_inner_protocol to set inner Ethernet protocol to
protocol being encapsulation by GRE before tunnel_xmit. This is
needed for GSO if UDP encapsulation (fou) is being done.
Signed-off-by: Tom Herbert <therbert@google.com>
---
net/ipv4/ip_gre.c | 2 ++
net/ipv6/ip6_gre.c | 8 ++++++--
2 files changed, 8 insertions(+), 2 deletions(-)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index 829aff8b..0485ef1 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -241,6 +241,8 @@ static void __gre_xmit(struct sk_buff *skb, struct net_device *dev,
/* Push GRE header. */
gre_build_header(skb, &tpi, tunnel->tun_hlen);
+ skb_set_inner_protocol(skb, tpi.proto);
+
ip_tunnel_xmit(skb, dev, tnl_params, tnl_params->protocol);
}
diff --git a/net/ipv6/ip6_gre.c b/net/ipv6/ip6_gre.c
index 5f19dfb..9a0a1aa 100644
--- a/net/ipv6/ip6_gre.c
+++ b/net/ipv6/ip6_gre.c
@@ -616,6 +616,7 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
int err = -1;
u8 proto;
struct sk_buff *new_skb;
+ __be16 protocol;
if (dev->type == ARPHRD_ETHER)
IPCB(skb)->flags = 0;
@@ -732,8 +733,9 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
ipv6h->daddr = fl6->daddr;
((__be16 *)(ipv6h + 1))[0] = tunnel->parms.o_flags;
- ((__be16 *)(ipv6h + 1))[1] = (dev->type == ARPHRD_ETHER) ?
- htons(ETH_P_TEB) : skb->protocol;
+ protocol = (dev->type == ARPHRD_ETHER) ?
+ htons(ETH_P_TEB) : skb->protocol;
+ ((__be16 *)(ipv6h + 1))[1] = protocol;
if (tunnel->parms.o_flags&(GRE_KEY|GRE_CSUM|GRE_SEQ)) {
__be32 *ptr = (__be32 *)(((u8 *)ipv6h) + tunnel->hlen - 4);
@@ -754,6 +756,8 @@ static netdev_tx_t ip6gre_xmit2(struct sk_buff *skb,
}
}
+ skb_set_inner_protocol(skb, protocol);
+
ip6tunnel_xmit(skb, dev);
if (ndst)
ip6_tnl_dst_store(tunnel, ndst);
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 7+ messages in thread* [PATCH v2 net-next 5/5] vxlan: Set inner protocol before transmit
2014-09-30 3:22 [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels Tom Herbert
` (3 preceding siblings ...)
2014-09-30 3:22 ` [PATCH v2 net-next 4/5] gre: Set inner protocol in v4 and v6 GRE transmit Tom Herbert
@ 2014-09-30 3:22 ` Tom Herbert
2014-10-02 1:36 ` [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels David Miller
5 siblings, 0 replies; 7+ messages in thread
From: Tom Herbert @ 2014-09-30 3:22 UTC (permalink / raw)
To: davem, netdev
Call skb_set_inner_protocol to set inner Ethernet protocol to
ETH_P_TEB before transmit. This is needed for GSO with UDP tunnels.
Signed-off-by: Tom Herbert <therbert@google.com>
---
drivers/net/vxlan.c | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/drivers/net/vxlan.c b/drivers/net/vxlan.c
index 34e102e..2af795d 100644
--- a/drivers/net/vxlan.c
+++ b/drivers/net/vxlan.c
@@ -1610,6 +1610,8 @@ static int vxlan6_xmit_skb(struct vxlan_sock *vs,
vxh->vx_flags = htonl(VXLAN_FLAGS);
vxh->vx_vni = vni;
+ skb_set_inner_protocol(skb, htons(ETH_P_TEB));
+
udp_tunnel6_xmit_skb(vs->sock, dst, skb, dev, saddr, daddr, prio,
ttl, src_port, dst_port);
return 0;
@@ -1652,6 +1654,8 @@ int vxlan_xmit_skb(struct vxlan_sock *vs,
vxh->vx_flags = htonl(VXLAN_FLAGS);
vxh->vx_vni = vni;
+ skb_set_inner_protocol(skb, htons(ETH_P_TEB));
+
return udp_tunnel_xmit_skb(vs->sock, rt, skb, src, dst, tos,
ttl, df, src_port, dst_port, xnet);
}
--
2.1.0.rc2.206.gedb03e5
^ permalink raw reply related [flat|nested] 7+ messages in thread* Re: [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels
2014-09-30 3:22 [PATCH v2 net-next 0/5] udp: Generalize GSO for UDP tunnels Tom Herbert
` (4 preceding siblings ...)
2014-09-30 3:22 ` [PATCH v2 net-next 5/5] vxlan: Set inner protocol before transmit Tom Herbert
@ 2014-10-02 1:36 ` David Miller
5 siblings, 0 replies; 7+ messages in thread
From: David Miller @ 2014-10-02 1:36 UTC (permalink / raw)
To: therbert; +Cc: netdev
From: Tom Herbert <therbert@google.com>
Date: Mon, 29 Sep 2014 20:22:28 -0700
> This patch set generalizes the UDP tunnel segmentation functions so
> that they can work with various protocol encapsulations. The primary
> change is to set the inner_protocol field in the skbuff when creating
> the encapsulated packet, and then in skb_udp_tunnel_segment this data
> is used to determine the function for segmenting the encapsulated
> packet. The inner_protocol field is overloaded to take either an
> Ethertype or IP protocol.
>
> The inner_protocol is set on transmit using skb_set_inner_ipproto or
> skb_set_inner_protocol functions. VXLAN and IP tunnels (for fou GSO)
> were modified to call these.
Series applied, thanks Tom.
^ permalink raw reply [flat|nested] 7+ messages in thread