aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/netdev_features.h4
-rw-r--r--include/linux/netdevice.h2
-rw-r--r--include/linux/skbuff.h123
-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
15 files changed, 149 insertions, 116 deletions
diff --git a/include/linux/netdev_features.h b/include/linux/netdev_features.h
index 09906b7ca47d..a2a89a5c7be5 100644
--- a/include/linux/netdev_features.h
+++ b/include/linux/netdev_features.h
@@ -43,8 +43,9 @@ enum {
43 NETIF_F_FSO_BIT, /* ... FCoE segmentation */ 43 NETIF_F_FSO_BIT, /* ... FCoE segmentation */
44 NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */ 44 NETIF_F_GSO_GRE_BIT, /* ... GRE with TSO */
45 NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */ 45 NETIF_F_GSO_UDP_TUNNEL_BIT, /* ... UDP TUNNEL with TSO */
46 NETIF_F_GSO_MPLS_BIT, /* ... MPLS segmentation */
46 /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */ 47 /**/NETIF_F_GSO_LAST = /* last bit, see GSO_MASK */
47 NETIF_F_GSO_UDP_TUNNEL_BIT, 48 NETIF_F_GSO_MPLS_BIT,
48 49
49 NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */ 50 NETIF_F_FCOE_CRC_BIT, /* FCoE CRC32 */
50 NETIF_F_SCTP_CSUM_BIT, /* SCTP checksum offload */ 51 NETIF_F_SCTP_CSUM_BIT, /* SCTP checksum offload */
@@ -107,6 +108,7 @@ enum {
107#define NETIF_F_RXALL __NETIF_F(RXALL) 108#define NETIF_F_RXALL __NETIF_F(RXALL)
108#define NETIF_F_GSO_GRE __NETIF_F(GSO_GRE) 109#define NETIF_F_GSO_GRE __NETIF_F(GSO_GRE)
109#define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL) 110#define NETIF_F_GSO_UDP_TUNNEL __NETIF_F(GSO_UDP_TUNNEL)
111#define NETIF_F_GSO_MPLS __NETIF_F(GSO_MPLS)
110#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER) 112#define NETIF_F_HW_VLAN_STAG_FILTER __NETIF_F(HW_VLAN_STAG_FILTER)
111#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX) 113#define NETIF_F_HW_VLAN_STAG_RX __NETIF_F(HW_VLAN_STAG_RX)
112#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX) 114#define NETIF_F_HW_VLAN_STAG_TX __NETIF_F(HW_VLAN_STAG_TX)
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index ea7b6bce9ea0..6b2bb460d1d7 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1088,6 +1088,8 @@ struct net_device {
1088 * need to set them appropriately. 1088 * need to set them appropriately.
1089 */ 1089 */
1090 netdev_features_t hw_enc_features; 1090 netdev_features_t hw_enc_features;
1091 /* mask of fetures inheritable by MPLS */
1092 netdev_features_t mpls_features;
1091 1093
1092 /* Interface index. Unique device identifier */ 1094 /* Interface index. Unique device identifier */
1093 int ifindex; 1095 int ifindex;
diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h
index 2e0ced1af3b1..8f2b830772a8 100644
--- a/include/linux/skbuff.h
+++ b/include/linux/skbuff.h
@@ -319,6 +319,8 @@ enum {
319 SKB_GSO_GRE = 1 << 6, 319 SKB_GSO_GRE = 1 << 6,
320 320
321 SKB_GSO_UDP_TUNNEL = 1 << 7, 321 SKB_GSO_UDP_TUNNEL = 1 << 7,
322
323 SKB_GSO_MPLS = 1 << 8,
322}; 324};
323 325
324#if BITS_PER_LONG > 32 326#if BITS_PER_LONG > 32
@@ -389,6 +391,7 @@ typedef unsigned char *sk_buff_data_t;
389 * @dropcount: total number of sk_receive_queue overflows 391 * @dropcount: total number of sk_receive_queue overflows
390 * @vlan_proto: vlan encapsulation protocol 392 * @vlan_proto: vlan encapsulation protocol
391 * @vlan_tci: vlan tag control information 393 * @vlan_tci: vlan tag control information
394 * @inner_protocol: Protocol (encapsulation)
392 * @inner_transport_header: Inner transport layer header (encapsulation) 395 * @inner_transport_header: Inner transport layer header (encapsulation)
393 * @inner_network_header: Network layer header (encapsulation) 396 * @inner_network_header: Network layer header (encapsulation)
394 * @inner_mac_header: Link layer header (encapsulation) 397 * @inner_mac_header: Link layer header (encapsulation)
@@ -509,12 +512,13 @@ struct sk_buff {
509 __u32 reserved_tailroom; 512 __u32 reserved_tailroom;
510 }; 513 };
511 514
512 sk_buff_data_t inner_transport_header; 515 __be16 inner_protocol;
513 sk_buff_data_t inner_network_header; 516 __u16 inner_transport_header;
514 sk_buff_data_t inner_mac_header; 517 __u16 inner_network_header;
515 sk_buff_data_t transport_header; 518 __u16 inner_mac_header;
516 sk_buff_data_t network_header; 519 __u16 transport_header;
517 sk_buff_data_t mac_header; 520 __u16 network_header;
521 __u16 mac_header;
518 /* These elements must be at the end, see alloc_skb() for details. */ 522 /* These elements must be at the end, see alloc_skb() for details. */
519 sk_buff_data_t tail; 523 sk_buff_data_t tail;
520 sk_buff_data_t end; 524 sk_buff_data_t end;
@@ -1527,7 +1531,6 @@ static inline void skb_reset_mac_len(struct sk_buff *skb)
1527 skb->mac_len = skb->network_header - skb->mac_header; 1531 skb->mac_len = skb->network_header - skb->mac_header;
1528} 1532}
1529 1533
1530#ifdef NET_SKBUFF_DATA_USES_OFFSET
1531static inline unsigned char *skb_inner_transport_header(const struct sk_buff 1534static inline unsigned char *skb_inner_transport_header(const struct sk_buff
1532 *skb) 1535 *skb)
1533{ 1536{
@@ -1638,112 +1641,6 @@ static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
1638 skb->mac_header += offset; 1641 skb->mac_header += offset;
1639} 1642}
1640 1643
1641#else /* NET_SKBUFF_DATA_USES_OFFSET */
1642static inline unsigned char *skb_inner_transport_header(const struct sk_buff
1643 *skb)
1644{
1645 return skb->inner_transport_header;
1646}
1647
1648static inline void skb_reset_inner_transport_header(struct sk_buff *skb)
1649{
1650 skb->inner_transport_header = skb->data;
1651}
1652
1653static inline void skb_set_inner_transport_header(struct sk_buff *skb,
1654 const int offset)
1655{
1656 skb->inner_transport_header = skb->data + offset;
1657}
1658
1659static inline unsigned char *skb_inner_network_header(const struct sk_buff *skb)
1660{
1661 return skb->inner_network_header;
1662}
1663
1664static inline void skb_reset_inner_network_header(struct sk_buff *skb)
1665{
1666 skb->inner_network_header = skb->data;
1667}
1668
1669static inline void skb_set_inner_network_header(struct sk_buff *skb,
1670 const int offset)
1671{
1672 skb->inner_network_header = skb->data + offset;
1673}
1674
1675static inline unsigned char *skb_inner_mac_header(const struct sk_buff *skb)
1676{
1677 return skb->inner_mac_header;
1678}
1679
1680static inline void skb_reset_inner_mac_header(struct sk_buff *skb)
1681{
1682 skb->inner_mac_header = skb->data;
1683}
1684
1685static inline void skb_set_inner_mac_header(struct sk_buff *skb,
1686 const int offset)
1687{
1688 skb->inner_mac_header = skb->data + offset;
1689}
1690static inline bool skb_transport_header_was_set(const struct sk_buff *skb)
1691{
1692 return skb->transport_header != NULL;
1693}
1694
1695static inline unsigned char *skb_transport_header(const struct sk_buff *skb)
1696{
1697 return skb->transport_header;
1698}
1699
1700static inline void skb_reset_transport_header(struct sk_buff *skb)
1701{
1702 skb->transport_header = skb->data;
1703}
1704
1705static inline void skb_set_transport_header(struct sk_buff *skb,
1706 const int offset)
1707{
1708 skb->transport_header = skb->data + offset;
1709}
1710
1711static inline unsigned char *skb_network_header(const struct sk_buff *skb)
1712{
1713 return skb->network_header;
1714}
1715
1716static inline void skb_reset_network_header(struct sk_buff *skb)
1717{
1718 skb->network_header = skb->data;
1719}
1720
1721static inline void skb_set_network_header(struct sk_buff *skb, const int offset)
1722{
1723 skb->network_header = skb->data + offset;
1724}
1725
1726static inline unsigned char *skb_mac_header(const struct sk_buff *skb)
1727{
1728 return skb->mac_header;
1729}
1730
1731static inline int skb_mac_header_was_set(const struct sk_buff *skb)
1732{
1733 return skb->mac_header != NULL;
1734}
1735
1736static inline void skb_reset_mac_header(struct sk_buff *skb)
1737{
1738 skb->mac_header = skb->data;
1739}
1740
1741static inline void skb_set_mac_header(struct sk_buff *skb, const int offset)
1742{
1743 skb->mac_header = skb->data + offset;
1744}
1745#endif /* NET_SKBUFF_DATA_USES_OFFSET */
1746
1747static inline void skb_probe_transport_header(struct sk_buff *skb, 1644static inline void skb_probe_transport_header(struct sk_buff *skb,
1748 const int offset_hint) 1645 const int offset_hint)
1749{ 1646{
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");