diff options
Diffstat (limited to 'net/mpls')
-rw-r--r-- | net/mpls/Kconfig | 9 | ||||
-rw-r--r-- | net/mpls/Makefile | 4 | ||||
-rw-r--r-- | net/mpls/mpls_gso.c | 108 |
3 files changed, 121 insertions, 0 deletions
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 | # | ||
4 | config 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 | # | ||
4 | obj-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 | |||
22 | static 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 | |||
62 | out: | ||
63 | return segs; | ||
64 | } | ||
65 | |||
66 | static int mpls_gso_send_check(struct sk_buff *skb) | ||
67 | { | ||
68 | return 0; | ||
69 | } | ||
70 | |||
71 | static 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 | |||
79 | static 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 | |||
87 | static 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 | |||
97 | static void __exit mpls_gso_exit(void) | ||
98 | { | ||
99 | dev_remove_offload(&mpls_uc_offload); | ||
100 | dev_remove_offload(&mpls_mc_offload); | ||
101 | } | ||
102 | |||
103 | module_init(mpls_gso_init); | ||
104 | module_exit(mpls_gso_exit); | ||
105 | |||
106 | MODULE_DESCRIPTION("MPLS GSO support"); | ||
107 | MODULE_AUTHOR("Simon Horman (horms@verge.net.au)"); | ||
108 | MODULE_LICENSE("GPL"); | ||