aboutsummaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
authorSimon Horman <horms@verge.net.au>2013-05-23 17:02:52 -0400
committerDavid S. Miller <davem@davemloft.net>2013-05-28 01:50:59 -0400
commit0d89d2035fe063461a5ddb609b2c12e7fb006e44 (patch)
treecc7fd6947941ba8e7cb63d5e190e14f48503ca37 /net
parent1a37e412a0225fcba5587f24c0dfc7636efc8b69 (diff)
MPLS: Add limited GSO support
In the case where a non-MPLS packet is received and an MPLS stack is added it may well be the case that the original skb is GSO but the NIC used for transmit does not support GSO of MPLS packets. The aim of this code is to provide GSO in software for MPLS packets whose skbs are GSO. SKB Usage: When an implementation adds an MPLS stack to a non-MPLS packet it should do the following to skb metadata: * Set skb->inner_protocol to the old non-MPLS ethertype of the packet. skb->inner_protocol is added by this patch. * Set skb->protocol to the new MPLS ethertype of the packet. * Set skb->network_header to correspond to the end of the L3 header, including the MPLS label stack. I have posted a patch, "[PATCH v3.29] datapath: Add basic MPLS support to kernel" which adds MPLS support to the kernel datapath of Open vSwtich. That patch sets the above requirements in datapath/actions.c:push_mpls() and was used to exercise this code. The datapath patch is against the Open vSwtich tree but it is intended that it be added to the Open vSwtich code present in the mainline Linux kernel at some point. Features: I believe that the approach that I have taken is at least partially consistent with the handling of other protocols. Jesse, I understand that you have some ideas here. I am more than happy to change my implementation. This patch adds dev->mpls_features which may be used by devices to advertise features supported for MPLS packets. A new NETIF_F_MPLS_GSO feature is added for devices which support hardware MPLS GSO offload. Currently no devices support this and MPLS GSO always falls back to software. Alternate Implementation: One possible alternate implementation is to teach netif_skb_features() and skb_network_protocol() about MPLS, in a similar way to their understanding of VLANs. I believe this would avoid the need for net/mpls/mpls_gso.c and in particular the calls to __skb_push() and __skb_push() in mpls_gso_segment(). I have decided on the implementation in this patch as it should not introduce any overhead in the case where mpls_gso is not compiled into the kernel or inserted as a module. MPLS GSO suggested by Jesse Gross. Based in part on "v4 GRE: Add TCP segmentation offload for GRE" by Pravin B Shelar. Cc: Jesse Gross <jesse@nicira.com> Cc: Pravin B Shelar <pshelar@nicira.com> Signed-off-by: Simon Horman <horms@verge.net.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net')
-rw-r--r--net/Kconfig1
-rw-r--r--net/Makefile1
-rw-r--r--net/core/dev.c4
-rw-r--r--net/core/ethtool.c1
-rw-r--r--net/ipv4/af_inet.c1
-rw-r--r--net/ipv4/tcp.c1
-rw-r--r--net/ipv4/udp.c2
-rw-r--r--net/ipv6/ip6_offload.c1
-rw-r--r--net/ipv6/udp_offload.c3
-rw-r--r--net/mpls/Kconfig9
-rw-r--r--net/mpls/Makefile4
-rw-r--r--net/mpls/mpls_gso.c108
12 files changed, 134 insertions, 2 deletions
diff --git a/net/Kconfig b/net/Kconfig
index 08de901415ee..523e43e6da1b 100644
--- a/net/Kconfig
+++ b/net/Kconfig
@@ -218,6 +218,7 @@ source "net/batman-adv/Kconfig"
218source "net/openvswitch/Kconfig" 218source "net/openvswitch/Kconfig"
219source "net/vmw_vsock/Kconfig" 219source "net/vmw_vsock/Kconfig"
220source "net/netlink/Kconfig" 220source "net/netlink/Kconfig"
221source "net/mpls/Kconfig"
221 222
222config RPS 223config RPS
223 boolean 224 boolean
diff --git a/net/Makefile b/net/Makefile
index 091e7b04f301..9492e8cb64e9 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -70,3 +70,4 @@ obj-$(CONFIG_BATMAN_ADV) += batman-adv/
70obj-$(CONFIG_NFC) += nfc/ 70obj-$(CONFIG_NFC) += nfc/
71obj-$(CONFIG_OPENVSWITCH) += openvswitch/ 71obj-$(CONFIG_OPENVSWITCH) += openvswitch/
72obj-$(CONFIG_VSOCKETS) += vmw_vsock/ 72obj-$(CONFIG_VSOCKETS) += vmw_vsock/
73obj-$(CONFIG_NET_MPLS_GSO) += mpls/
diff --git a/net/core/dev.c b/net/core/dev.c
index 50c02ded1d69..2f09cb29cc95 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -5277,6 +5277,10 @@ int register_netdevice(struct net_device *dev)
5277 */ 5277 */
5278 dev->hw_enc_features |= NETIF_F_SG; 5278 dev->hw_enc_features |= NETIF_F_SG;
5279 5279
5280 /* Make NETIF_F_SG inheritable to MPLS.
5281 */
5282 dev->mpls_features |= NETIF_F_SG;
5283
5280 ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev); 5284 ret = call_netdevice_notifiers(NETDEV_POST_INIT, dev);
5281 ret = notifier_to_errno(ret); 5285 ret = notifier_to_errno(ret);
5282 if (ret) 5286 if (ret)
diff --git a/net/core/ethtool.c b/net/core/ethtool.c
index 22efdaa76ebf..4e6f63ade741 100644
--- a/net/core/ethtool.c
+++ b/net/core/ethtool.c
@@ -82,6 +82,7 @@ static const char netdev_features_strings[NETDEV_FEATURE_COUNT][ETH_GSTRING_LEN]
82 [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation", 82 [NETIF_F_FSO_BIT] = "tx-fcoe-segmentation",
83 [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation", 83 [NETIF_F_GSO_GRE_BIT] = "tx-gre-segmentation",
84 [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation", 84 [NETIF_F_GSO_UDP_TUNNEL_BIT] = "tx-udp_tnl-segmentation",
85 [NETIF_F_GSO_MPLS_BIT] = "tx-mpls-segmentation",
85 86
86 [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc", 87 [NETIF_F_FCOE_CRC_BIT] = "tx-checksum-fcoe-crc",
87 [NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp", 88 [NETIF_F_SCTP_CSUM_BIT] = "tx-checksum-sctp",
diff --git a/net/ipv4/af_inet.c b/net/ipv4/af_inet.c
index d01be2a3ae53..b05ae96aec44 100644
--- a/net/ipv4/af_inet.c
+++ b/net/ipv4/af_inet.c
@@ -1295,6 +1295,7 @@ static struct sk_buff *inet_gso_segment(struct sk_buff *skb,
1295 SKB_GSO_GRE | 1295 SKB_GSO_GRE |
1296 SKB_GSO_TCPV6 | 1296 SKB_GSO_TCPV6 |
1297 SKB_GSO_UDP_TUNNEL | 1297 SKB_GSO_UDP_TUNNEL |
1298 SKB_GSO_MPLS |
1298 0))) 1299 0)))
1299 goto out; 1300 goto out;
1300 1301
diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c
index d87ce72ca8aa..ba4186e1dca9 100644
--- a/net/ipv4/tcp.c
+++ b/net/ipv4/tcp.c
@@ -2917,6 +2917,7 @@ struct sk_buff *tcp_tso_segment(struct sk_buff *skb,
2917 SKB_GSO_TCP_ECN | 2917 SKB_GSO_TCP_ECN |
2918 SKB_GSO_TCPV6 | 2918 SKB_GSO_TCPV6 |
2919 SKB_GSO_GRE | 2919 SKB_GSO_GRE |
2920 SKB_GSO_MPLS |
2920 SKB_GSO_UDP_TUNNEL | 2921 SKB_GSO_UDP_TUNNEL |
2921 0) || 2922 0) ||
2922 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6)))) 2923 !(type & (SKB_GSO_TCPV4 | SKB_GSO_TCPV6))))
diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c
index 0bf5d399a03c..aa5eff46d137 100644
--- a/net/ipv4/udp.c
+++ b/net/ipv4/udp.c
@@ -2381,7 +2381,7 @@ struct sk_buff *udp4_ufo_fragment(struct sk_buff *skb,
2381 2381
2382 if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY | 2382 if (unlikely(type & ~(SKB_GSO_UDP | SKB_GSO_DODGY |
2383 SKB_GSO_UDP_TUNNEL | 2383 SKB_GSO_UDP_TUNNEL |
2384 SKB_GSO_GRE) || 2384 SKB_GSO_GRE | SKB_GSO_MPLS) ||
2385 !(type & (SKB_GSO_UDP)))) 2385 !(type & (SKB_GSO_UDP))))
2386 goto out; 2386 goto out;
2387 2387
diff --git a/net/ipv6/ip6_offload.c b/net/ipv6/ip6_offload.c
index 71b766ee821d..a263b990ee11 100644
--- a/net/ipv6/ip6_offload.c
+++ b/net/ipv6/ip6_offload.c
@@ -98,6 +98,7 @@ static struct sk_buff *ipv6_gso_segment(struct sk_buff *skb,
98 SKB_GSO_TCP_ECN | 98 SKB_GSO_TCP_ECN |
99 SKB_GSO_GRE | 99 SKB_GSO_GRE |
100 SKB_GSO_UDP_TUNNEL | 100 SKB_GSO_UDP_TUNNEL |
101 SKB_GSO_MPLS |
101 SKB_GSO_TCPV6 | 102 SKB_GSO_TCPV6 |
102 0))) 103 0)))
103 goto out; 104 goto out;
diff --git a/net/ipv6/udp_offload.c b/net/ipv6/udp_offload.c
index 3bb3a891a424..76d401a93c7a 100644
--- a/net/ipv6/udp_offload.c
+++ b/net/ipv6/udp_offload.c
@@ -63,7 +63,8 @@ static struct sk_buff *udp6_ufo_fragment(struct sk_buff *skb,
63 if (unlikely(type & ~(SKB_GSO_UDP | 63 if (unlikely(type & ~(SKB_GSO_UDP |
64 SKB_GSO_DODGY | 64 SKB_GSO_DODGY |
65 SKB_GSO_UDP_TUNNEL | 65 SKB_GSO_UDP_TUNNEL |
66 SKB_GSO_GRE) || 66 SKB_GSO_GRE |
67 SKB_GSO_MPLS) ||
67 !(type & (SKB_GSO_UDP)))) 68 !(type & (SKB_GSO_UDP))))
68 goto out; 69 goto out;
69 70
diff --git a/net/mpls/Kconfig b/net/mpls/Kconfig
new file mode 100644
index 000000000000..37421db88965
--- /dev/null
+++ b/net/mpls/Kconfig
@@ -0,0 +1,9 @@
1#
2# MPLS configuration
3#
4config NET_MPLS_GSO
5 tristate "MPLS: GSO support"
6 help
7 This is helper module to allow segmentation of non-MPLS GSO packets
8 that have had MPLS stack entries pushed onto them and thus
9 become MPLS GSO packets.
diff --git a/net/mpls/Makefile b/net/mpls/Makefile
new file mode 100644
index 000000000000..0a3c171be537
--- /dev/null
+++ b/net/mpls/Makefile
@@ -0,0 +1,4 @@
1#
2# Makefile for MPLS.
3#
4obj-y += mpls_gso.o
diff --git a/net/mpls/mpls_gso.c b/net/mpls/mpls_gso.c
new file mode 100644
index 000000000000..1bec1219ab81
--- /dev/null
+++ b/net/mpls/mpls_gso.c
@@ -0,0 +1,108 @@
1/*
2 * MPLS GSO Support
3 *
4 * Authors: Simon Horman (horms@verge.net.au)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 *
11 * Based on: GSO portions of net/ipv4/gre.c
12 */
13
14#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
15
16#include <linux/err.h>
17#include <linux/module.h>
18#include <linux/netdev_features.h>
19#include <linux/netdevice.h>
20#include <linux/skbuff.h>
21
22static struct sk_buff *mpls_gso_segment(struct sk_buff *skb,
23 netdev_features_t features)
24{
25 struct sk_buff *segs = ERR_PTR(-EINVAL);
26 netdev_features_t mpls_features;
27 __be16 mpls_protocol;
28
29 if (unlikely(skb_shinfo(skb)->gso_type &
30 ~(SKB_GSO_TCPV4 |
31 SKB_GSO_TCPV6 |
32 SKB_GSO_UDP |
33 SKB_GSO_DODGY |
34 SKB_GSO_TCP_ECN |
35 SKB_GSO_GRE |
36 SKB_GSO_MPLS)))
37 goto out;
38
39 /* Setup inner SKB. */
40 mpls_protocol = skb->protocol;
41 skb->protocol = skb->inner_protocol;
42
43 /* Push back the mac header that skb_mac_gso_segment() has pulled.
44 * It will be re-pulled by the call to skb_mac_gso_segment() below
45 */
46 __skb_push(skb, skb->mac_len);
47
48 /* Segment inner packet. */
49 mpls_features = skb->dev->mpls_features & netif_skb_features(skb);
50 segs = skb_mac_gso_segment(skb, mpls_features);
51
52
53 /* Restore outer protocol. */
54 skb->protocol = mpls_protocol;
55
56 /* Re-pull the mac header that the call to skb_mac_gso_segment()
57 * above pulled. It will be re-pushed after returning
58 * skb_mac_gso_segment(), an indirect caller of this function.
59 */
60 __skb_push(skb, skb->data - skb_mac_header(skb));
61
62out:
63 return segs;
64}
65
66static int mpls_gso_send_check(struct sk_buff *skb)
67{
68 return 0;
69}
70
71static struct packet_offload mpls_mc_offload = {
72 .type = cpu_to_be16(ETH_P_MPLS_MC),
73 .callbacks = {
74 .gso_send_check = mpls_gso_send_check,
75 .gso_segment = mpls_gso_segment,
76 },
77};
78
79static struct packet_offload mpls_uc_offload = {
80 .type = cpu_to_be16(ETH_P_MPLS_UC),
81 .callbacks = {
82 .gso_send_check = mpls_gso_send_check,
83 .gso_segment = mpls_gso_segment,
84 },
85};
86
87static int __init mpls_gso_init(void)
88{
89 pr_info("MPLS GSO support\n");
90
91 dev_add_offload(&mpls_uc_offload);
92 dev_add_offload(&mpls_mc_offload);
93
94 return 0;
95}
96
97static void __exit mpls_gso_exit(void)
98{
99 dev_remove_offload(&mpls_uc_offload);
100 dev_remove_offload(&mpls_mc_offload);
101}
102
103module_init(mpls_gso_init);
104module_exit(mpls_gso_exit);
105
106MODULE_DESCRIPTION("MPLS GSO support");
107MODULE_AUTHOR("Simon Horman (horms@verge.net.au)");
108MODULE_LICENSE("GPL");