]> git.proxmox.com Git - mirror_ovs.git/blame - datapath/linux/compat/gso.c
datapath: Fix few mpls issues.
[mirror_ovs.git] / datapath / linux / compat / gso.c
CommitLineData
5ebaf571
PS
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
29c71cfa 19#include <linux/version.h>
ccf43786 20#if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0)
29c71cfa 21
5ebaf571
PS
22#include <linux/module.h>
23#include <linux/if.h>
24#include <linux/if_tunnel.h>
ccf43786 25#include <linux/if_vlan.h>
5ebaf571
PS
26#include <linux/icmp.h>
27#include <linux/in.h>
28#include <linux/ip.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>
2baf0e0c 37#include <net/mpls.h>
5ebaf571
PS
38#include <net/protocol.h>
39#include <net/route.h>
40#include <net/xfrm.h>
41
42#include "gso.h"
ccf43786 43#include "vlan.h"
5ebaf571 44
c1f90e07
SH
45#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,37) && \
46 !defined(HAVE_VLAN_BUG_WORKAROUND)
47#include <linux/module.h>
48
49static int vlan_tso __read_mostly;
50module_param(vlan_tso, int, 0644);
51MODULE_PARM_DESC(vlan_tso, "Enable TSO for VLAN packets");
52#else
53#define vlan_tso true
54#endif
55
c1f90e07
SH
56static bool dev_supports_vlan_tx(struct net_device *dev)
57{
ccf43786
SH
58#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,37)
59 return true;
60#elif defined(HAVE_VLAN_BUG_WORKAROUND)
c1f90e07
SH
61 return dev->features & NETIF_F_HW_VLAN_TX;
62#else
63 /* Assume that the driver is buggy. */
64 return false;
65#endif
66}
67
ccf43786
SH
68/* Strictly this is not needed and will be optimised out
69 * as this code is guarded by if LINUX_VERSION_CODE < KERNEL_VERSION(3,16,0).
70 * It is here to make things explicit should the compatibility
71 * code be extended in some way prior extending its life-span
72 * beyond v3.16.
73 */
74static bool supports_mpls_gso(void)
75{
76/* MPLS GSO was introduced in v3.11, however it was not correctly
77 * activated using mpls_features until v3.16. */
78#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,16,0)
79 return true;
80#else
81 return false;
82#endif
83}
84
c1f90e07
SH
85int rpl_dev_queue_xmit(struct sk_buff *skb)
86{
87#undef dev_queue_xmit
88 int err = -ENOMEM;
ccf43786
SH
89 bool vlan, mpls;
90
91 vlan = mpls = false;
92
93 /* Avoid traversing any VLAN tags that are present to determine if
94 * the ethtype is MPLS. Instead compare the mac_len (end of L2) and
95 * skb_network_offset() (beginning of L3) whose inequality will
96 * indicate the presence of an MPLS label stack. */
97 if (skb->mac_len != skb_network_offset(skb) && !supports_mpls_gso())
98 mpls = true;
99
100 if (vlan_tx_tag_present(skb) && !dev_supports_vlan_tx(skb->dev))
101 vlan = true;
c1f90e07 102
ccf43786 103 if (vlan || mpls) {
c1f90e07
SH
104 int features;
105
106 features = netif_skb_features(skb);
107
ccf43786
SH
108 if (vlan) {
109 if (!vlan_tso)
110 features &= ~(NETIF_F_TSO | NETIF_F_TSO6 |
111 NETIF_F_UFO | NETIF_F_FSO);
c1f90e07 112
ccf43786
SH
113 skb = __vlan_put_tag(skb, skb->vlan_proto,
114 vlan_tx_tag_get(skb));
115 if (unlikely(!skb))
116 return err;
117 vlan_set_tci(skb, 0);
118 }
119
120 /* As of v3.11 the kernel provides an mpls_features field in
121 * struct net_device which allows devices to advertise which
122 * features its supports for MPLS. This value defaults to
123 * NETIF_F_SG and as of v3.16.
124 *
125 * This compatibility code is intended for kernels older
126 * than v3.16 that do not support MPLS GSO and do not
127 * use mpls_features. Thus this code uses NETIF_F_SG
128 * directly in place of mpls_features.
129 */
130 if (mpls)
131 features &= NETIF_F_SG;
c1f90e07
SH
132
133 if (netif_needs_gso(skb, features)) {
134 struct sk_buff *nskb;
135
136 nskb = skb_gso_segment(skb, features);
137 if (!nskb) {
138 if (unlikely(skb_cloned(skb) &&
139 pskb_expand_head(skb, 0, 0, GFP_ATOMIC)))
140 goto drop;
141
142 skb_shinfo(skb)->gso_type &= ~SKB_GSO_DODGY;
143 goto xmit;
144 }
145
146 if (IS_ERR(nskb)) {
147 err = PTR_ERR(nskb);
148 goto drop;
149 }
150 consume_skb(skb);
151 skb = nskb;
152
153 do {
154 nskb = skb->next;
155 skb->next = NULL;
156 err = dev_queue_xmit(skb);
157 skb = nskb;
158 } while (skb);
159
160 return err;
161 }
162 }
163xmit:
164 return dev_queue_xmit(skb);
165
166drop:
167 kfree_skb(skb);
168 return err;
169}
c1f90e07 170
47916a64 171static __be16 __skb_network_protocol(struct sk_buff *skb)
5ebaf571
PS
172{
173 __be16 type = skb->protocol;
174 int vlan_depth = ETH_HLEN;
175
176 while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
177 struct vlan_hdr *vh;
178
179 if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
180 return 0;
181
182 vh = (struct vlan_hdr *)(skb->data + vlan_depth);
183 type = vh->h_vlan_encapsulated_proto;
184 vlan_depth += VLAN_HLEN;
185 }
186
ccf43786
SH
187 if (eth_p_mpls(type))
188 type = ovs_skb_get_inner_protocol(skb);
189
5ebaf571
PS
190 return type;
191}
192
ccf43786
SH
193#if LINUX_VERSION_CODE < KERNEL_VERSION(3,12,0)
194static void tnl_fix_segment(struct sk_buff *skb)
195{
196 if (OVS_GSO_CB(skb)->fix_segment)
197 OVS_GSO_CB(skb)->fix_segment(skb);
198}
199#else
200static void tnl_fix_segment(struct sk_buff *skb) { }
201#endif
202
5ebaf571
PS
203static struct sk_buff *tnl_skb_gso_segment(struct sk_buff *skb,
204 netdev_features_t features,
205 bool tx_path)
206{
207 struct iphdr *iph = ip_hdr(skb);
208 int pkt_hlen = skb_inner_network_offset(skb); /* inner l2 + tunnel hdr. */
209 int mac_offset = skb_inner_mac_offset(skb);
210 struct sk_buff *skb1 = skb;
211 struct sk_buff *segs;
212 __be16 proto = skb->protocol;
7ceda296 213 char cb[sizeof(skb->cb)];
5ebaf571
PS
214
215 /* setup whole inner packet to get protocol. */
216 __skb_pull(skb, mac_offset);
47916a64 217 skb->protocol = __skb_network_protocol(skb);
5ebaf571
PS
218
219 /* setup l3 packet to gso, to get around segmentation bug on older kernel.*/
220 __skb_pull(skb, (pkt_hlen - mac_offset));
221 skb_reset_mac_header(skb);
222 skb_reset_network_header(skb);
223 skb_reset_transport_header(skb);
224
7ceda296
KM
225 /* From 3.9 kernel skb->cb is used by skb gso. Therefore
226 * make copy of it to restore it back. */
227 memcpy(cb, skb->cb, sizeof(cb));
228
5ebaf571
PS
229 segs = __skb_gso_segment(skb, 0, tx_path);
230 if (!segs || IS_ERR(segs))
231 goto free;
232
233 skb = segs;
234 while (skb) {
235 __skb_push(skb, pkt_hlen);
236 skb_reset_mac_header(skb);
237 skb_reset_network_header(skb);
238 skb_set_transport_header(skb, sizeof(struct iphdr));
239 skb->mac_len = 0;
240
241 memcpy(ip_hdr(skb), iph, pkt_hlen);
7ceda296 242 memcpy(skb->cb, cb, sizeof(cb));
ccf43786 243 tnl_fix_segment(skb);
5ebaf571
PS
244
245 skb->protocol = proto;
246 skb = skb->next;
247 }
248free:
249 consume_skb(skb1);
250 return segs;
251}
252
253int rpl_ip_local_out(struct sk_buff *skb)
254{
255 int ret = NETDEV_TX_OK;
6d3e8965 256 int id = -1;
5ebaf571
PS
257
258 if (skb_is_gso(skb)) {
259 struct iphdr *iph;
260
261 iph = ip_hdr(skb);
262 id = ntohs(iph->id);
263 skb = tnl_skb_gso_segment(skb, 0, false);
264 if (!skb || IS_ERR(skb))
265 return 0;
266 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
267 int err;
268
269 err = skb_checksum_help(skb);
270 if (unlikely(err))
271 return 0;
5ebaf571
PS
272 }
273
274 while (skb) {
275 struct sk_buff *next_skb = skb->next;
276 struct iphdr *iph;
277 int err;
278
279 skb->next = NULL;
280
281 iph = ip_hdr(skb);
282 if (id >= 0)
283 iph->id = htons(id++);
284
285 memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
286
287#undef ip_local_out
288 err = ip_local_out(skb);
289 if (unlikely(net_xmit_eval(err)))
290 ret = err;
291
292 skb = next_skb;
293 }
294 return ret;
295}
ccf43786 296#endif /* 3.16 */