Commit c50cd357887acf9fd7af3a5d492911bd825555a2

Authored by Daniel Borkmann
Committed by David S. Miller
1 parent 419076f59f

net: gre: move GSO functions to gre_offload

Similarly to TCP/UDP offloading, move all related GRE functions to
gre_offload.c to make things more explicit and similar to the rest
of the code.

Suggested-by: Eric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: Daniel Borkmann <dborkman@redhat.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

Showing 5 changed files with 546 additions and 514 deletions Side-by-side Diff

... ... @@ -32,6 +32,10 @@
32 32  
33 33 int gre_cisco_register(struct gre_cisco_protocol *proto);
34 34 int gre_cisco_unregister(struct gre_cisco_protocol *proto);
  35 +
  36 +int gre_offload_init(void);
  37 +void gre_offload_exit(void);
  38 +
35 39 void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
36 40 int hdr_len);
37 41 struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum);
... ... @@ -19,6 +19,7 @@
19 19 obj-$(CONFIG_IP_MULTIPLE_TABLES) += fib_rules.o
20 20 obj-$(CONFIG_IP_MROUTE) += ipmr.o
21 21 obj-$(CONFIG_NET_IPIP) += ipip.o
  22 +gre-y := gre_demux.o gre_offload.o
22 23 obj-$(CONFIG_NET_IPGRE_DEMUX) += gre.o
23 24 obj-$(CONFIG_NET_IPGRE) += ip_gre.o
24 25 obj-$(CONFIG_NET_IPVTI) += ip_vti.o
net/ipv4/gre.c
1   -/*
2   - * GRE over IPv4 demultiplexer driver
3   - *
4   - * Authors: Dmitry Kozlov (xeb@mail.ru)
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   - */
12   -
13   -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14   -
15   -#include <linux/module.h>
16   -#include <linux/if.h>
17   -#include <linux/icmp.h>
18   -#include <linux/kernel.h>
19   -#include <linux/kmod.h>
20   -#include <linux/skbuff.h>
21   -#include <linux/in.h>
22   -#include <linux/ip.h>
23   -#include <linux/netdevice.h>
24   -#include <linux/if_tunnel.h>
25   -#include <linux/spinlock.h>
26   -#include <net/protocol.h>
27   -#include <net/gre.h>
28   -
29   -#include <net/icmp.h>
30   -#include <net/route.h>
31   -#include <net/xfrm.h>
32   -
33   -static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
34   -static struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX];
35   -
36   -int gre_add_protocol(const struct gre_protocol *proto, u8 version)
37   -{
38   - if (version >= GREPROTO_MAX)
39   - return -EINVAL;
40   -
41   - return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ?
42   - 0 : -EBUSY;
43   -}
44   -EXPORT_SYMBOL_GPL(gre_add_protocol);
45   -
46   -int gre_del_protocol(const struct gre_protocol *proto, u8 version)
47   -{
48   - int ret;
49   -
50   - if (version >= GREPROTO_MAX)
51   - return -EINVAL;
52   -
53   - ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ?
54   - 0 : -EBUSY;
55   -
56   - if (ret)
57   - return ret;
58   -
59   - synchronize_rcu();
60   - return 0;
61   -}
62   -EXPORT_SYMBOL_GPL(gre_del_protocol);
63   -
64   -void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
65   - int hdr_len)
66   -{
67   - struct gre_base_hdr *greh;
68   -
69   - skb_push(skb, hdr_len);
70   -
71   - greh = (struct gre_base_hdr *)skb->data;
72   - greh->flags = tnl_flags_to_gre_flags(tpi->flags);
73   - greh->protocol = tpi->proto;
74   -
75   - if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) {
76   - __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
77   -
78   - if (tpi->flags&TUNNEL_SEQ) {
79   - *ptr = tpi->seq;
80   - ptr--;
81   - }
82   - if (tpi->flags&TUNNEL_KEY) {
83   - *ptr = tpi->key;
84   - ptr--;
85   - }
86   - if (tpi->flags&TUNNEL_CSUM &&
87   - !(skb_shinfo(skb)->gso_type & SKB_GSO_GRE)) {
88   - *ptr = 0;
89   - *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
90   - skb->len, 0));
91   - }
92   - }
93   -}
94   -EXPORT_SYMBOL_GPL(gre_build_header);
95   -
96   -struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
97   -{
98   - int err;
99   -
100   - if (likely(!skb->encapsulation)) {
101   - skb_reset_inner_headers(skb);
102   - skb->encapsulation = 1;
103   - }
104   -
105   - if (skb_is_gso(skb)) {
106   - err = skb_unclone(skb, GFP_ATOMIC);
107   - if (unlikely(err))
108   - goto error;
109   - skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
110   - return skb;
111   - } else if (skb->ip_summed == CHECKSUM_PARTIAL && gre_csum) {
112   - err = skb_checksum_help(skb);
113   - if (unlikely(err))
114   - goto error;
115   - } else if (skb->ip_summed != CHECKSUM_PARTIAL)
116   - skb->ip_summed = CHECKSUM_NONE;
117   -
118   - return skb;
119   -error:
120   - kfree_skb(skb);
121   - return ERR_PTR(err);
122   -}
123   -EXPORT_SYMBOL_GPL(gre_handle_offloads);
124   -
125   -static __sum16 check_checksum(struct sk_buff *skb)
126   -{
127   - __sum16 csum = 0;
128   -
129   - switch (skb->ip_summed) {
130   - case CHECKSUM_COMPLETE:
131   - csum = csum_fold(skb->csum);
132   -
133   - if (!csum)
134   - break;
135   - /* Fall through. */
136   -
137   - case CHECKSUM_NONE:
138   - skb->csum = 0;
139   - csum = __skb_checksum_complete(skb);
140   - skb->ip_summed = CHECKSUM_COMPLETE;
141   - break;
142   - }
143   -
144   - return csum;
145   -}
146   -
147   -static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
148   - bool *csum_err)
149   -{
150   - unsigned int ip_hlen = ip_hdrlen(skb);
151   - const struct gre_base_hdr *greh;
152   - __be32 *options;
153   - int hdr_len;
154   -
155   - if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
156   - return -EINVAL;
157   -
158   - greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
159   - if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
160   - return -EINVAL;
161   -
162   - tpi->flags = gre_flags_to_tnl_flags(greh->flags);
163   - hdr_len = ip_gre_calc_hlen(tpi->flags);
164   -
165   - if (!pskb_may_pull(skb, hdr_len))
166   - return -EINVAL;
167   -
168   - greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
169   - tpi->proto = greh->protocol;
170   -
171   - options = (__be32 *)(greh + 1);
172   - if (greh->flags & GRE_CSUM) {
173   - if (check_checksum(skb)) {
174   - *csum_err = true;
175   - return -EINVAL;
176   - }
177   - options++;
178   - }
179   -
180   - if (greh->flags & GRE_KEY) {
181   - tpi->key = *options;
182   - options++;
183   - } else
184   - tpi->key = 0;
185   -
186   - if (unlikely(greh->flags & GRE_SEQ)) {
187   - tpi->seq = *options;
188   - options++;
189   - } else
190   - tpi->seq = 0;
191   -
192   - /* WCCP version 1 and 2 protocol decoding.
193   - * - Change protocol to IP
194   - * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
195   - */
196   - if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
197   - tpi->proto = htons(ETH_P_IP);
198   - if ((*(u8 *)options & 0xF0) != 0x40) {
199   - hdr_len += 4;
200   - if (!pskb_may_pull(skb, hdr_len))
201   - return -EINVAL;
202   - }
203   - }
204   -
205   - return iptunnel_pull_header(skb, hdr_len, tpi->proto);
206   -}
207   -
208   -static int gre_cisco_rcv(struct sk_buff *skb)
209   -{
210   - struct tnl_ptk_info tpi;
211   - int i;
212   - bool csum_err = false;
213   -
214   - if (parse_gre_header(skb, &tpi, &csum_err) < 0)
215   - goto drop;
216   -
217   - rcu_read_lock();
218   - for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
219   - struct gre_cisco_protocol *proto;
220   - int ret;
221   -
222   - proto = rcu_dereference(gre_cisco_proto_list[i]);
223   - if (!proto)
224   - continue;
225   - ret = proto->handler(skb, &tpi);
226   - if (ret == PACKET_RCVD) {
227   - rcu_read_unlock();
228   - return 0;
229   - }
230   - }
231   - rcu_read_unlock();
232   -
233   - icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
234   -drop:
235   - kfree_skb(skb);
236   - return 0;
237   -}
238   -
239   -static void gre_cisco_err(struct sk_buff *skb, u32 info)
240   -{
241   - /* All the routers (except for Linux) return only
242   - * 8 bytes of packet payload. It means, that precise relaying of
243   - * ICMP in the real Internet is absolutely infeasible.
244   - *
245   - * Moreover, Cisco "wise men" put GRE key to the third word
246   - * in GRE header. It makes impossible maintaining even soft
247   - * state for keyed
248   - * GRE tunnels with enabled checksum. Tell them "thank you".
249   - *
250   - * Well, I wonder, rfc1812 was written by Cisco employee,
251   - * what the hell these idiots break standards established
252   - * by themselves???
253   - */
254   -
255   - const int type = icmp_hdr(skb)->type;
256   - const int code = icmp_hdr(skb)->code;
257   - struct tnl_ptk_info tpi;
258   - bool csum_err = false;
259   - int i;
260   -
261   - if (parse_gre_header(skb, &tpi, &csum_err)) {
262   - if (!csum_err) /* ignore csum errors. */
263   - return;
264   - }
265   -
266   - if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
267   - ipv4_update_pmtu(skb, dev_net(skb->dev), info,
268   - skb->dev->ifindex, 0, IPPROTO_GRE, 0);
269   - return;
270   - }
271   - if (type == ICMP_REDIRECT) {
272   - ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0,
273   - IPPROTO_GRE, 0);
274   - return;
275   - }
276   -
277   - rcu_read_lock();
278   - for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
279   - struct gre_cisco_protocol *proto;
280   -
281   - proto = rcu_dereference(gre_cisco_proto_list[i]);
282   - if (!proto)
283   - continue;
284   -
285   - if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD)
286   - goto out;
287   -
288   - }
289   -out:
290   - rcu_read_unlock();
291   -}
292   -
293   -static int gre_rcv(struct sk_buff *skb)
294   -{
295   - const struct gre_protocol *proto;
296   - u8 ver;
297   - int ret;
298   -
299   - if (!pskb_may_pull(skb, 12))
300   - goto drop;
301   -
302   - ver = skb->data[1]&0x7f;
303   - if (ver >= GREPROTO_MAX)
304   - goto drop;
305   -
306   - rcu_read_lock();
307   - proto = rcu_dereference(gre_proto[ver]);
308   - if (!proto || !proto->handler)
309   - goto drop_unlock;
310   - ret = proto->handler(skb);
311   - rcu_read_unlock();
312   - return ret;
313   -
314   -drop_unlock:
315   - rcu_read_unlock();
316   -drop:
317   - kfree_skb(skb);
318   - return NET_RX_DROP;
319   -}
320   -
321   -static void gre_err(struct sk_buff *skb, u32 info)
322   -{
323   - const struct gre_protocol *proto;
324   - const struct iphdr *iph = (const struct iphdr *)skb->data;
325   - u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
326   -
327   - if (ver >= GREPROTO_MAX)
328   - return;
329   -
330   - rcu_read_lock();
331   - proto = rcu_dereference(gre_proto[ver]);
332   - if (proto && proto->err_handler)
333   - proto->err_handler(skb, info);
334   - rcu_read_unlock();
335   -}
336   -
337   -static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
338   - netdev_features_t features)
339   -{
340   - struct sk_buff *segs = ERR_PTR(-EINVAL);
341   - netdev_features_t enc_features;
342   - int ghl = GRE_HEADER_SECTION;
343   - struct gre_base_hdr *greh;
344   - int mac_len = skb->mac_len;
345   - __be16 protocol = skb->protocol;
346   - int tnl_hlen;
347   - bool csum;
348   -
349   - if (unlikely(skb_shinfo(skb)->gso_type &
350   - ~(SKB_GSO_TCPV4 |
351   - SKB_GSO_TCPV6 |
352   - SKB_GSO_UDP |
353   - SKB_GSO_DODGY |
354   - SKB_GSO_TCP_ECN |
355   - SKB_GSO_GRE)))
356   - goto out;
357   -
358   - if (unlikely(!pskb_may_pull(skb, sizeof(*greh))))
359   - goto out;
360   -
361   - greh = (struct gre_base_hdr *)skb_transport_header(skb);
362   -
363   - if (greh->flags & GRE_KEY)
364   - ghl += GRE_HEADER_SECTION;
365   - if (greh->flags & GRE_SEQ)
366   - ghl += GRE_HEADER_SECTION;
367   - if (greh->flags & GRE_CSUM) {
368   - ghl += GRE_HEADER_SECTION;
369   - csum = true;
370   - } else
371   - csum = false;
372   -
373   - /* setup inner skb. */
374   - skb->protocol = greh->protocol;
375   - skb->encapsulation = 0;
376   -
377   - if (unlikely(!pskb_may_pull(skb, ghl)))
378   - goto out;
379   - __skb_pull(skb, ghl);
380   - skb_reset_mac_header(skb);
381   - skb_set_network_header(skb, skb_inner_network_offset(skb));
382   - skb->mac_len = skb_inner_network_offset(skb);
383   -
384   - /* segment inner packet. */
385   - enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
386   - segs = skb_mac_gso_segment(skb, enc_features);
387   - if (!segs || IS_ERR(segs))
388   - goto out;
389   -
390   - skb = segs;
391   - tnl_hlen = skb_tnl_header_len(skb);
392   - do {
393   - __skb_push(skb, ghl);
394   - if (csum) {
395   - __be32 *pcsum;
396   -
397   - if (skb_has_shared_frag(skb)) {
398   - int err;
399   -
400   - err = __skb_linearize(skb);
401   - if (err) {
402   - kfree_skb(segs);
403   - segs = ERR_PTR(err);
404   - goto out;
405   - }
406   - }
407   -
408   - greh = (struct gre_base_hdr *)(skb->data);
409   - pcsum = (__be32 *)(greh + 1);
410   - *pcsum = 0;
411   - *(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0));
412   - }
413   - __skb_push(skb, tnl_hlen - ghl);
414   -
415   - skb_reset_mac_header(skb);
416   - skb_set_network_header(skb, mac_len);
417   - skb->mac_len = mac_len;
418   - skb->protocol = protocol;
419   - } while ((skb = skb->next));
420   -out:
421   - return segs;
422   -}
423   -
424   -static int gre_gso_send_check(struct sk_buff *skb)
425   -{
426   - if (!skb->encapsulation)
427   - return -EINVAL;
428   - return 0;
429   -}
430   -
431   -static const struct net_protocol net_gre_protocol = {
432   - .handler = gre_rcv,
433   - .err_handler = gre_err,
434   - .netns_ok = 1,
435   -};
436   -
437   -static const struct net_offload gre_offload = {
438   - .callbacks = {
439   - .gso_send_check = gre_gso_send_check,
440   - .gso_segment = gre_gso_segment,
441   - },
442   -};
443   -
444   -static const struct gre_protocol ipgre_protocol = {
445   - .handler = gre_cisco_rcv,
446   - .err_handler = gre_cisco_err,
447   -};
448   -
449   -int gre_cisco_register(struct gre_cisco_protocol *newp)
450   -{
451   - struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
452   - &gre_cisco_proto_list[newp->priority];
453   -
454   - return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY;
455   -}
456   -EXPORT_SYMBOL_GPL(gre_cisco_register);
457   -
458   -int gre_cisco_unregister(struct gre_cisco_protocol *del_proto)
459   -{
460   - struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
461   - &gre_cisco_proto_list[del_proto->priority];
462   - int ret;
463   -
464   - ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL;
465   -
466   - if (ret)
467   - return ret;
468   -
469   - synchronize_net();
470   - return 0;
471   -}
472   -EXPORT_SYMBOL_GPL(gre_cisco_unregister);
473   -
474   -static int __init gre_init(void)
475   -{
476   - pr_info("GRE over IPv4 demultiplexor driver\n");
477   -
478   - if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
479   - pr_err("can't add protocol\n");
480   - goto err;
481   - }
482   -
483   - if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) {
484   - pr_info("%s: can't add ipgre handler\n", __func__);
485   - goto err_gre;
486   - }
487   -
488   - if (inet_add_offload(&gre_offload, IPPROTO_GRE)) {
489   - pr_err("can't add protocol offload\n");
490   - goto err_gso;
491   - }
492   -
493   - return 0;
494   -err_gso:
495   - gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
496   -err_gre:
497   - inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
498   -err:
499   - return -EAGAIN;
500   -}
501   -
502   -static void __exit gre_exit(void)
503   -{
504   - inet_del_offload(&gre_offload, IPPROTO_GRE);
505   - gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
506   - inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
507   -}
508   -
509   -module_init(gre_init);
510   -module_exit(gre_exit);
511   -
512   -MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
513   -MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
514   -MODULE_LICENSE("GPL");
net/ipv4/gre_demux.c
  1 +/*
  2 + * GRE over IPv4 demultiplexer driver
  3 + *
  4 + * Authors: Dmitry Kozlov (xeb@mail.ru)
  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 + */
  12 +
  13 +#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
  14 +
  15 +#include <linux/module.h>
  16 +#include <linux/if.h>
  17 +#include <linux/icmp.h>
  18 +#include <linux/kernel.h>
  19 +#include <linux/kmod.h>
  20 +#include <linux/skbuff.h>
  21 +#include <linux/in.h>
  22 +#include <linux/ip.h>
  23 +#include <linux/netdevice.h>
  24 +#include <linux/if_tunnel.h>
  25 +#include <linux/spinlock.h>
  26 +#include <net/protocol.h>
  27 +#include <net/gre.h>
  28 +
  29 +#include <net/icmp.h>
  30 +#include <net/route.h>
  31 +#include <net/xfrm.h>
  32 +
  33 +static const struct gre_protocol __rcu *gre_proto[GREPROTO_MAX] __read_mostly;
  34 +static struct gre_cisco_protocol __rcu *gre_cisco_proto_list[GRE_IP_PROTO_MAX];
  35 +
  36 +int gre_add_protocol(const struct gre_protocol *proto, u8 version)
  37 +{
  38 + if (version >= GREPROTO_MAX)
  39 + return -EINVAL;
  40 +
  41 + return (cmpxchg((const struct gre_protocol **)&gre_proto[version], NULL, proto) == NULL) ?
  42 + 0 : -EBUSY;
  43 +}
  44 +EXPORT_SYMBOL_GPL(gre_add_protocol);
  45 +
  46 +int gre_del_protocol(const struct gre_protocol *proto, u8 version)
  47 +{
  48 + int ret;
  49 +
  50 + if (version >= GREPROTO_MAX)
  51 + return -EINVAL;
  52 +
  53 + ret = (cmpxchg((const struct gre_protocol **)&gre_proto[version], proto, NULL) == proto) ?
  54 + 0 : -EBUSY;
  55 +
  56 + if (ret)
  57 + return ret;
  58 +
  59 + synchronize_rcu();
  60 + return 0;
  61 +}
  62 +EXPORT_SYMBOL_GPL(gre_del_protocol);
  63 +
  64 +void gre_build_header(struct sk_buff *skb, const struct tnl_ptk_info *tpi,
  65 + int hdr_len)
  66 +{
  67 + struct gre_base_hdr *greh;
  68 +
  69 + skb_push(skb, hdr_len);
  70 +
  71 + greh = (struct gre_base_hdr *)skb->data;
  72 + greh->flags = tnl_flags_to_gre_flags(tpi->flags);
  73 + greh->protocol = tpi->proto;
  74 +
  75 + if (tpi->flags&(TUNNEL_KEY|TUNNEL_CSUM|TUNNEL_SEQ)) {
  76 + __be32 *ptr = (__be32 *)(((u8 *)greh) + hdr_len - 4);
  77 +
  78 + if (tpi->flags&TUNNEL_SEQ) {
  79 + *ptr = tpi->seq;
  80 + ptr--;
  81 + }
  82 + if (tpi->flags&TUNNEL_KEY) {
  83 + *ptr = tpi->key;
  84 + ptr--;
  85 + }
  86 + if (tpi->flags&TUNNEL_CSUM &&
  87 + !(skb_shinfo(skb)->gso_type & SKB_GSO_GRE)) {
  88 + *ptr = 0;
  89 + *(__sum16 *)ptr = csum_fold(skb_checksum(skb, 0,
  90 + skb->len, 0));
  91 + }
  92 + }
  93 +}
  94 +EXPORT_SYMBOL_GPL(gre_build_header);
  95 +
  96 +struct sk_buff *gre_handle_offloads(struct sk_buff *skb, bool gre_csum)
  97 +{
  98 + int err;
  99 +
  100 + if (likely(!skb->encapsulation)) {
  101 + skb_reset_inner_headers(skb);
  102 + skb->encapsulation = 1;
  103 + }
  104 +
  105 + if (skb_is_gso(skb)) {
  106 + err = skb_unclone(skb, GFP_ATOMIC);
  107 + if (unlikely(err))
  108 + goto error;
  109 + skb_shinfo(skb)->gso_type |= SKB_GSO_GRE;
  110 + return skb;
  111 + } else if (skb->ip_summed == CHECKSUM_PARTIAL && gre_csum) {
  112 + err = skb_checksum_help(skb);
  113 + if (unlikely(err))
  114 + goto error;
  115 + } else if (skb->ip_summed != CHECKSUM_PARTIAL)
  116 + skb->ip_summed = CHECKSUM_NONE;
  117 +
  118 + return skb;
  119 +error:
  120 + kfree_skb(skb);
  121 + return ERR_PTR(err);
  122 +}
  123 +EXPORT_SYMBOL_GPL(gre_handle_offloads);
  124 +
  125 +static __sum16 check_checksum(struct sk_buff *skb)
  126 +{
  127 + __sum16 csum = 0;
  128 +
  129 + switch (skb->ip_summed) {
  130 + case CHECKSUM_COMPLETE:
  131 + csum = csum_fold(skb->csum);
  132 +
  133 + if (!csum)
  134 + break;
  135 + /* Fall through. */
  136 +
  137 + case CHECKSUM_NONE:
  138 + skb->csum = 0;
  139 + csum = __skb_checksum_complete(skb);
  140 + skb->ip_summed = CHECKSUM_COMPLETE;
  141 + break;
  142 + }
  143 +
  144 + return csum;
  145 +}
  146 +
  147 +static int parse_gre_header(struct sk_buff *skb, struct tnl_ptk_info *tpi,
  148 + bool *csum_err)
  149 +{
  150 + unsigned int ip_hlen = ip_hdrlen(skb);
  151 + const struct gre_base_hdr *greh;
  152 + __be32 *options;
  153 + int hdr_len;
  154 +
  155 + if (unlikely(!pskb_may_pull(skb, sizeof(struct gre_base_hdr))))
  156 + return -EINVAL;
  157 +
  158 + greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
  159 + if (unlikely(greh->flags & (GRE_VERSION | GRE_ROUTING)))
  160 + return -EINVAL;
  161 +
  162 + tpi->flags = gre_flags_to_tnl_flags(greh->flags);
  163 + hdr_len = ip_gre_calc_hlen(tpi->flags);
  164 +
  165 + if (!pskb_may_pull(skb, hdr_len))
  166 + return -EINVAL;
  167 +
  168 + greh = (struct gre_base_hdr *)(skb_network_header(skb) + ip_hlen);
  169 + tpi->proto = greh->protocol;
  170 +
  171 + options = (__be32 *)(greh + 1);
  172 + if (greh->flags & GRE_CSUM) {
  173 + if (check_checksum(skb)) {
  174 + *csum_err = true;
  175 + return -EINVAL;
  176 + }
  177 + options++;
  178 + }
  179 +
  180 + if (greh->flags & GRE_KEY) {
  181 + tpi->key = *options;
  182 + options++;
  183 + } else
  184 + tpi->key = 0;
  185 +
  186 + if (unlikely(greh->flags & GRE_SEQ)) {
  187 + tpi->seq = *options;
  188 + options++;
  189 + } else
  190 + tpi->seq = 0;
  191 +
  192 + /* WCCP version 1 and 2 protocol decoding.
  193 + * - Change protocol to IP
  194 + * - When dealing with WCCPv2, Skip extra 4 bytes in GRE header
  195 + */
  196 + if (greh->flags == 0 && tpi->proto == htons(ETH_P_WCCP)) {
  197 + tpi->proto = htons(ETH_P_IP);
  198 + if ((*(u8 *)options & 0xF0) != 0x40) {
  199 + hdr_len += 4;
  200 + if (!pskb_may_pull(skb, hdr_len))
  201 + return -EINVAL;
  202 + }
  203 + }
  204 +
  205 + return iptunnel_pull_header(skb, hdr_len, tpi->proto);
  206 +}
  207 +
  208 +static int gre_cisco_rcv(struct sk_buff *skb)
  209 +{
  210 + struct tnl_ptk_info tpi;
  211 + int i;
  212 + bool csum_err = false;
  213 +
  214 + if (parse_gre_header(skb, &tpi, &csum_err) < 0)
  215 + goto drop;
  216 +
  217 + rcu_read_lock();
  218 + for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
  219 + struct gre_cisco_protocol *proto;
  220 + int ret;
  221 +
  222 + proto = rcu_dereference(gre_cisco_proto_list[i]);
  223 + if (!proto)
  224 + continue;
  225 + ret = proto->handler(skb, &tpi);
  226 + if (ret == PACKET_RCVD) {
  227 + rcu_read_unlock();
  228 + return 0;
  229 + }
  230 + }
  231 + rcu_read_unlock();
  232 +
  233 + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
  234 +drop:
  235 + kfree_skb(skb);
  236 + return 0;
  237 +}
  238 +
  239 +static void gre_cisco_err(struct sk_buff *skb, u32 info)
  240 +{
  241 + /* All the routers (except for Linux) return only
  242 + * 8 bytes of packet payload. It means, that precise relaying of
  243 + * ICMP in the real Internet is absolutely infeasible.
  244 + *
  245 + * Moreover, Cisco "wise men" put GRE key to the third word
  246 + * in GRE header. It makes impossible maintaining even soft
  247 + * state for keyed
  248 + * GRE tunnels with enabled checksum. Tell them "thank you".
  249 + *
  250 + * Well, I wonder, rfc1812 was written by Cisco employee,
  251 + * what the hell these idiots break standards established
  252 + * by themselves???
  253 + */
  254 +
  255 + const int type = icmp_hdr(skb)->type;
  256 + const int code = icmp_hdr(skb)->code;
  257 + struct tnl_ptk_info tpi;
  258 + bool csum_err = false;
  259 + int i;
  260 +
  261 + if (parse_gre_header(skb, &tpi, &csum_err)) {
  262 + if (!csum_err) /* ignore csum errors. */
  263 + return;
  264 + }
  265 +
  266 + if (type == ICMP_DEST_UNREACH && code == ICMP_FRAG_NEEDED) {
  267 + ipv4_update_pmtu(skb, dev_net(skb->dev), info,
  268 + skb->dev->ifindex, 0, IPPROTO_GRE, 0);
  269 + return;
  270 + }
  271 + if (type == ICMP_REDIRECT) {
  272 + ipv4_redirect(skb, dev_net(skb->dev), skb->dev->ifindex, 0,
  273 + IPPROTO_GRE, 0);
  274 + return;
  275 + }
  276 +
  277 + rcu_read_lock();
  278 + for (i = 0; i < GRE_IP_PROTO_MAX; i++) {
  279 + struct gre_cisco_protocol *proto;
  280 +
  281 + proto = rcu_dereference(gre_cisco_proto_list[i]);
  282 + if (!proto)
  283 + continue;
  284 +
  285 + if (proto->err_handler(skb, info, &tpi) == PACKET_RCVD)
  286 + goto out;
  287 +
  288 + }
  289 +out:
  290 + rcu_read_unlock();
  291 +}
  292 +
  293 +static int gre_rcv(struct sk_buff *skb)
  294 +{
  295 + const struct gre_protocol *proto;
  296 + u8 ver;
  297 + int ret;
  298 +
  299 + if (!pskb_may_pull(skb, 12))
  300 + goto drop;
  301 +
  302 + ver = skb->data[1]&0x7f;
  303 + if (ver >= GREPROTO_MAX)
  304 + goto drop;
  305 +
  306 + rcu_read_lock();
  307 + proto = rcu_dereference(gre_proto[ver]);
  308 + if (!proto || !proto->handler)
  309 + goto drop_unlock;
  310 + ret = proto->handler(skb);
  311 + rcu_read_unlock();
  312 + return ret;
  313 +
  314 +drop_unlock:
  315 + rcu_read_unlock();
  316 +drop:
  317 + kfree_skb(skb);
  318 + return NET_RX_DROP;
  319 +}
  320 +
  321 +static void gre_err(struct sk_buff *skb, u32 info)
  322 +{
  323 + const struct gre_protocol *proto;
  324 + const struct iphdr *iph = (const struct iphdr *)skb->data;
  325 + u8 ver = skb->data[(iph->ihl<<2) + 1]&0x7f;
  326 +
  327 + if (ver >= GREPROTO_MAX)
  328 + return;
  329 +
  330 + rcu_read_lock();
  331 + proto = rcu_dereference(gre_proto[ver]);
  332 + if (proto && proto->err_handler)
  333 + proto->err_handler(skb, info);
  334 + rcu_read_unlock();
  335 +}
  336 +
  337 +static const struct net_protocol net_gre_protocol = {
  338 + .handler = gre_rcv,
  339 + .err_handler = gre_err,
  340 + .netns_ok = 1,
  341 +};
  342 +
  343 +static const struct gre_protocol ipgre_protocol = {
  344 + .handler = gre_cisco_rcv,
  345 + .err_handler = gre_cisco_err,
  346 +};
  347 +
  348 +int gre_cisco_register(struct gre_cisco_protocol *newp)
  349 +{
  350 + struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
  351 + &gre_cisco_proto_list[newp->priority];
  352 +
  353 + return (cmpxchg(proto, NULL, newp) == NULL) ? 0 : -EBUSY;
  354 +}
  355 +EXPORT_SYMBOL_GPL(gre_cisco_register);
  356 +
  357 +int gre_cisco_unregister(struct gre_cisco_protocol *del_proto)
  358 +{
  359 + struct gre_cisco_protocol **proto = (struct gre_cisco_protocol **)
  360 + &gre_cisco_proto_list[del_proto->priority];
  361 + int ret;
  362 +
  363 + ret = (cmpxchg(proto, del_proto, NULL) == del_proto) ? 0 : -EINVAL;
  364 +
  365 + if (ret)
  366 + return ret;
  367 +
  368 + synchronize_net();
  369 + return 0;
  370 +}
  371 +EXPORT_SYMBOL_GPL(gre_cisco_unregister);
  372 +
  373 +static int __init gre_init(void)
  374 +{
  375 + pr_info("GRE over IPv4 demultiplexor driver\n");
  376 +
  377 + if (inet_add_protocol(&net_gre_protocol, IPPROTO_GRE) < 0) {
  378 + pr_err("can't add protocol\n");
  379 + goto err;
  380 + }
  381 +
  382 + if (gre_add_protocol(&ipgre_protocol, GREPROTO_CISCO) < 0) {
  383 + pr_info("%s: can't add ipgre handler\n", __func__);
  384 + goto err_gre;
  385 + }
  386 +
  387 + if (gre_offload_init()) {
  388 + pr_err("can't add protocol offload\n");
  389 + goto err_gso;
  390 + }
  391 +
  392 + return 0;
  393 +err_gso:
  394 + gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
  395 +err_gre:
  396 + inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
  397 +err:
  398 + return -EAGAIN;
  399 +}
  400 +
  401 +static void __exit gre_exit(void)
  402 +{
  403 + gre_offload_exit();
  404 +
  405 + gre_del_protocol(&ipgre_protocol, GREPROTO_CISCO);
  406 + inet_del_protocol(&net_gre_protocol, IPPROTO_GRE);
  407 +}
  408 +
  409 +module_init(gre_init);
  410 +module_exit(gre_exit);
  411 +
  412 +MODULE_DESCRIPTION("GRE over IPv4 demultiplexer driver");
  413 +MODULE_AUTHOR("D. Kozlov (xeb@mail.ru)");
  414 +MODULE_LICENSE("GPL");
net/ipv4/gre_offload.c
  1 +/*
  2 + * IPV4 GSO/GRO offload support
  3 + * Linux INET implementation
  4 + *
  5 + * This program is free software; you can redistribute it and/or
  6 + * modify it under the terms of the GNU General Public License
  7 + * as published by the Free Software Foundation; either version
  8 + * 2 of the License, or (at your option) any later version.
  9 + *
  10 + * GRE GSO support
  11 + */
  12 +
  13 +#include <linux/skbuff.h>
  14 +#include <net/protocol.h>
  15 +#include <net/gre.h>
  16 +
  17 +static int gre_gso_send_check(struct sk_buff *skb)
  18 +{
  19 + if (!skb->encapsulation)
  20 + return -EINVAL;
  21 + return 0;
  22 +}
  23 +
  24 +static struct sk_buff *gre_gso_segment(struct sk_buff *skb,
  25 + netdev_features_t features)
  26 +{
  27 + struct sk_buff *segs = ERR_PTR(-EINVAL);
  28 + netdev_features_t enc_features;
  29 + int ghl = GRE_HEADER_SECTION;
  30 + struct gre_base_hdr *greh;
  31 + int mac_len = skb->mac_len;
  32 + __be16 protocol = skb->protocol;
  33 + int tnl_hlen;
  34 + bool csum;
  35 +
  36 + if (unlikely(skb_shinfo(skb)->gso_type &
  37 + ~(SKB_GSO_TCPV4 |
  38 + SKB_GSO_TCPV6 |
  39 + SKB_GSO_UDP |
  40 + SKB_GSO_DODGY |
  41 + SKB_GSO_TCP_ECN |
  42 + SKB_GSO_GRE)))
  43 + goto out;
  44 +
  45 + if (unlikely(!pskb_may_pull(skb, sizeof(*greh))))
  46 + goto out;
  47 +
  48 + greh = (struct gre_base_hdr *)skb_transport_header(skb);
  49 +
  50 + if (greh->flags & GRE_KEY)
  51 + ghl += GRE_HEADER_SECTION;
  52 + if (greh->flags & GRE_SEQ)
  53 + ghl += GRE_HEADER_SECTION;
  54 + if (greh->flags & GRE_CSUM) {
  55 + ghl += GRE_HEADER_SECTION;
  56 + csum = true;
  57 + } else
  58 + csum = false;
  59 +
  60 + /* setup inner skb. */
  61 + skb->protocol = greh->protocol;
  62 + skb->encapsulation = 0;
  63 +
  64 + if (unlikely(!pskb_may_pull(skb, ghl)))
  65 + goto out;
  66 +
  67 + __skb_pull(skb, ghl);
  68 + skb_reset_mac_header(skb);
  69 + skb_set_network_header(skb, skb_inner_network_offset(skb));
  70 + skb->mac_len = skb_inner_network_offset(skb);
  71 +
  72 + /* segment inner packet. */
  73 + enc_features = skb->dev->hw_enc_features & netif_skb_features(skb);
  74 + segs = skb_mac_gso_segment(skb, enc_features);
  75 + if (!segs || IS_ERR(segs))
  76 + goto out;
  77 +
  78 + skb = segs;
  79 + tnl_hlen = skb_tnl_header_len(skb);
  80 + do {
  81 + __skb_push(skb, ghl);
  82 + if (csum) {
  83 + __be32 *pcsum;
  84 +
  85 + if (skb_has_shared_frag(skb)) {
  86 + int err;
  87 +
  88 + err = __skb_linearize(skb);
  89 + if (err) {
  90 + kfree_skb(segs);
  91 + segs = ERR_PTR(err);
  92 + goto out;
  93 + }
  94 + }
  95 +
  96 + greh = (struct gre_base_hdr *)(skb->data);
  97 + pcsum = (__be32 *)(greh + 1);
  98 + *pcsum = 0;
  99 + *(__sum16 *)pcsum = csum_fold(skb_checksum(skb, 0, skb->len, 0));
  100 + }
  101 + __skb_push(skb, tnl_hlen - ghl);
  102 +
  103 + skb_reset_mac_header(skb);
  104 + skb_set_network_header(skb, mac_len);
  105 + skb->mac_len = mac_len;
  106 + skb->protocol = protocol;
  107 + } while ((skb = skb->next));
  108 +out:
  109 + return segs;
  110 +}
  111 +
  112 +static const struct net_offload gre_offload = {
  113 + .callbacks = {
  114 + .gso_send_check = gre_gso_send_check,
  115 + .gso_segment = gre_gso_segment,
  116 + },
  117 +};
  118 +
  119 +int __init gre_offload_init(void)
  120 +{
  121 + return inet_add_offload(&gre_offload, IPPROTO_GRE);
  122 +}
  123 +
  124 +void __exit gre_offload_exit(void)
  125 +{
  126 + inet_del_offload(&gre_offload, IPPROTO_GRE);
  127 +}