32790c338ae5512b66de7d8a027958ef9072b9db
[cascardo/ovs.git] / datapath / linux / compat / gso.c
1 /*
2  * Copyright (c) 2007-2013 Nicira, Inc.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of version 2 of the GNU General Public
6  * License as published by the Free Software Foundation.
7  *
8  * This program is distributed in the hope that it will be useful, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program; if not, write to the Free Software
15  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
16  * 02110-1301, USA
17  */
18
19 #include <linux/version.h>
20
21 #include <linux/module.h>
22 #include <linux/if.h>
23 #include <linux/if_tunnel.h>
24 #include <linux/if_vlan.h>
25 #include <linux/icmp.h>
26 #include <linux/in.h>
27 #include <linux/ip.h>
28 #include <linux/ipv6.h>
29 #include <linux/kernel.h>
30 #include <linux/kmod.h>
31 #include <linux/netdevice.h>
32 #include <linux/skbuff.h>
33 #include <linux/spinlock.h>
34
35 #include <net/gre.h>
36 #include <net/icmp.h>
37 #include <net/mpls.h>
38 #include <net/protocol.h>
39 #include <net/route.h>
40 #include <net/xfrm.h>
41
42 #include "gso.h"
43
44 #ifdef OVS_USE_COMPAT_GSO_SEGMENTATION
45 /* Strictly this is not needed and will be optimised out
46  * as this code is guarded by if LINUX_VERSION_CODE < KERNEL_VERSION(3,19,0).
47  * It is here to make things explicit should the compatibility
48  * code be extended in some way prior extending its life-span
49  * beyond v3.19.
50  */
51 static bool supports_mpls_gso(void)
52 {
53 /* MPLS GSO was introduced in v3.11, however it was not correctly
54  * activated using mpls_features until v3.19. */
55 #ifdef OVS_USE_COMPAT_GSO_SEGMENTATION
56         return true;
57 #else
58         return false;
59 #endif
60 }
61
62 int rpl_dev_queue_xmit(struct sk_buff *skb)
63 {
64 #undef dev_queue_xmit
65         int err = -ENOMEM;
66         bool mpls;
67
68         mpls = false;
69
70         /* Avoid traversing any VLAN tags that are present to determine if
71          * the ethtype is MPLS. Instead compare the mac_len (end of L2) and
72          * skb_network_offset() (beginning of L3) whose inequality will
73          * indicate the presence of an MPLS label stack. */
74         if (skb->mac_len != skb_network_offset(skb) && !supports_mpls_gso())
75                 mpls = true;
76
77         if (mpls) {
78                 int features;
79
80                 features = netif_skb_features(skb);
81
82                 /* As of v3.11 the kernel provides an mpls_features field in
83                  * struct net_device which allows devices to advertise which
84                  * features its supports for MPLS. This value defaults to
85                  * NETIF_F_SG and as of v3.19.
86                  *
87                  * This compatibility code is intended for kernels older
88                  * than v3.19 that do not support MPLS GSO and do not
89                  * use mpls_features. Thus this code uses NETIF_F_SG
90                  * directly in place of mpls_features.
91                  */
92                 if (mpls)
93                         features &= NETIF_F_SG;
94
95                 if (netif_needs_gso(skb, features)) {
96                         struct sk_buff *nskb;
97
98                         nskb = skb_gso_segment(skb, features);
99                         if (!nskb) {
100                                 if (unlikely(skb_cloned(skb) &&
101                                     pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
102                                         goto drop;
103
104                                 skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY;
105                                 goto xmit;
106                         }
107
108                         if (IS_ERR(nskb)) {
109                                 err = PTR_ERR(nskb);
110                                 goto drop;
111                         }
112                         consume_skb(skb);
113                         skb = nskb;
114
115                         do {
116                                 nskb = skb->next;
117                                 skb->next = NULL;
118                                 err = dev_queue_xmit(skb);
119                                 skb = nskb;
120                         } while (skb);
121
122                         return err;
123                 }
124         }
125 xmit:
126         return dev_queue_xmit(skb);
127
128 drop:
129         kfree_skb(skb);
130         return err;
131 }
132 EXPORT_SYMBOL_GPL(rpl_dev_queue_xmit);
133 #endif /* OVS_USE_COMPAT_GSO_SEGMENTATION */
134
135 #if LINUX_VERSION_CODE < KERNEL_VERSION(3,18,0)
136 static __be16 __skb_network_protocol(struct sk_buff *skb)
137 {
138         __be16 type = skb->protocol;
139         int vlan_depth = ETH_HLEN;
140
141         while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
142                 struct vlan_hdr *vh;
143
144                 if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
145                         return 0;
146
147                 vh = (struct vlan_hdr *)(skb->data + vlan_depth);
148                 type = vh->h_vlan_encapsulated_proto;
149                 vlan_depth += VLAN_HLEN;
150         }
151
152         if (eth_p_mpls(type))
153                 type = ovs_skb_get_inner_protocol(skb);
154
155         return type;
156 }
157
158 static struct sk_buff *tnl_skb_gso_segment(struct sk_buff *skb,
159                                            netdev_features_t features,
160                                            bool tx_path,
161                                            sa_family_t sa_family)
162 {
163         void *iph = skb_network_header(skb);
164         int pkt_hlen = skb_inner_network_offset(skb); /* inner l2 + tunnel hdr. */
165         int mac_offset = skb_inner_mac_offset(skb);
166         int outer_l3_offset = skb_network_offset(skb);
167         int outer_l4_offset = skb_transport_offset(skb);
168         struct sk_buff *skb1 = skb;
169         struct dst_entry *dst = skb_dst(skb);
170         struct sk_buff *segs;
171         __be16 proto = skb->protocol;
172         char cb[sizeof(skb->cb)];
173
174         OVS_GSO_CB(skb)->ipv6 = (sa_family == AF_INET6);
175         /* setup whole inner packet to get protocol. */
176         __skb_pull(skb, mac_offset);
177         skb->protocol = __skb_network_protocol(skb);
178
179         /* setup l3 packet to gso, to get around segmentation bug on older kernel.*/
180         __skb_pull(skb, (pkt_hlen - mac_offset));
181         skb_reset_mac_header(skb);
182         skb_reset_network_header(skb);
183         skb_reset_transport_header(skb);
184
185         /* From 3.9 kernel skb->cb is used by skb gso. Therefore
186          * make copy of it to restore it back. */
187         memcpy(cb, skb->cb, sizeof(cb));
188
189         /* We are handling offloads by segmenting l3 packet, so
190          * no need to call OVS compat segmentation function. */
191
192 #ifdef HAVE___SKB_GSO_SEGMENT
193 #undef __skb_gso_segment
194         segs = __skb_gso_segment(skb, 0, tx_path);
195 #else
196 #undef skb_gso_segment
197         segs = skb_gso_segment(skb, 0);
198 #endif
199
200         if (!segs || IS_ERR(segs))
201                 goto free;
202
203         skb = segs;
204         while (skb) {
205                 __skb_push(skb, pkt_hlen);
206                 skb_reset_mac_header(skb);
207                 skb_set_network_header(skb, outer_l3_offset);
208                 skb_set_transport_header(skb, outer_l4_offset);
209                 skb->mac_len = 0;
210
211                 memcpy(skb_network_header(skb), iph, pkt_hlen);
212                 memcpy(skb->cb, cb, sizeof(cb));
213
214                 skb->protocol = proto;
215                 if (skb->next)
216                         dst = dst_clone(dst);
217
218                 skb_dst_set(skb, dst);
219                 OVS_GSO_CB(skb)->fix_segment(skb);
220
221                 skb = skb->next;
222         }
223 free:
224         consume_skb(skb1);
225         return segs;
226 }
227
228 static int output_ip(struct sk_buff *skb)
229 {
230         int ret = NETDEV_TX_OK;
231         int err;
232
233         memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
234
235 #undef ip_local_out
236         err = ip_local_out(skb);
237         if (unlikely(net_xmit_eval(err)))
238                 ret = err;
239
240         return ret;
241 }
242
243 int rpl_ip_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
244 {
245         int ret = NETDEV_TX_OK;
246         int id = -1;
247
248         if (!OVS_GSO_CB(skb)->fix_segment)
249                 return output_ip(skb);
250
251         if (skb_is_gso(skb)) {
252                 struct iphdr *iph;
253
254                 iph = ip_hdr(skb);
255                 id = ntohs(iph->id);
256                 skb = tnl_skb_gso_segment(skb, 0, false, AF_INET);
257                 if (!skb || IS_ERR(skb))
258                         return 0;
259         }  else if (skb->ip_summed == CHECKSUM_PARTIAL) {
260                 int err;
261
262                 err = skb_checksum_help(skb);
263                 if (unlikely(err))
264                         return 0;
265         }
266
267         while (skb) {
268                 struct sk_buff *next_skb = skb->next;
269                 struct iphdr *iph;
270
271                 skb->next = NULL;
272
273                 iph = ip_hdr(skb);
274                 if (id >= 0)
275                         iph->id = htons(id++);
276
277                 ret = output_ip(skb);
278                 skb = next_skb;
279         }
280         return ret;
281 }
282 EXPORT_SYMBOL_GPL(rpl_ip_local_out);
283
284 static int output_ipv6(struct sk_buff *skb)
285 {
286         int ret = NETDEV_TX_OK;
287         int err;
288
289         memset(IP6CB(skb), 0, sizeof (*IP6CB(skb)));
290 #undef ip6_local_out
291         err = ip6_local_out(skb);
292         if (unlikely(net_xmit_eval(err)))
293                 ret = err;
294
295         return ret;
296 }
297
298 int rpl_ip6_local_out(struct net *net, struct sock *sk, struct sk_buff *skb)
299 {
300         int ret = NETDEV_TX_OK;
301
302         if (!OVS_GSO_CB(skb)->fix_segment)
303                 return output_ipv6(skb);
304
305         if (skb_is_gso(skb)) {
306                 skb = tnl_skb_gso_segment(skb, 0, false, AF_INET6);
307                 if (!skb || IS_ERR(skb))
308                         return 0;
309         }  else if (skb->ip_summed == CHECKSUM_PARTIAL) {
310                 int err;
311
312                 err = skb_checksum_help(skb);
313                 if (unlikely(err))
314                         return 0;
315         }
316
317         while (skb) {
318                 struct sk_buff *next_skb = skb->next;
319
320                 skb->next = NULL;
321                 ret = output_ipv6(skb);
322                 skb = next_skb;
323         }
324         return ret;
325 }
326 EXPORT_SYMBOL_GPL(rpl_ip6_local_out);
327 #endif /* 3.18 */