2 * Copyright (c) 2007-2013 Nicira, Inc.
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.
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.
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
19 #include <linux/module.h>
21 #include <linux/if_tunnel.h>
22 #include <linux/icmp.h>
25 #include <linux/kernel.h>
26 #include <linux/kmod.h>
27 #include <linux/netdevice.h>
28 #include <linux/skbuff.h>
29 #include <linux/spinlock.h>
33 #include <net/protocol.h>
34 #include <net/route.h>
39 static __be16 __skb_network_protocol(struct sk_buff *skb)
41 __be16 type = skb->protocol;
42 int vlan_depth = ETH_HLEN;
44 while (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
47 if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
50 vh = (struct vlan_hdr *)(skb->data + vlan_depth);
51 type = vh->h_vlan_encapsulated_proto;
52 vlan_depth += VLAN_HLEN;
58 static struct sk_buff *tnl_skb_gso_segment(struct sk_buff *skb,
59 netdev_features_t features,
62 struct iphdr *iph = ip_hdr(skb);
63 int pkt_hlen = skb_inner_network_offset(skb); /* inner l2 + tunnel hdr. */
64 int mac_offset = skb_inner_mac_offset(skb);
65 struct sk_buff *skb1 = skb;
67 __be16 proto = skb->protocol;
68 char cb[sizeof(skb->cb)];
70 /* setup whole inner packet to get protocol. */
71 __skb_pull(skb, mac_offset);
72 skb->protocol = __skb_network_protocol(skb);
74 /* setup l3 packet to gso, to get around segmentation bug on older kernel.*/
75 __skb_pull(skb, (pkt_hlen - mac_offset));
76 skb_reset_mac_header(skb);
77 skb_reset_network_header(skb);
78 skb_reset_transport_header(skb);
80 /* From 3.9 kernel skb->cb is used by skb gso. Therefore
81 * make copy of it to restore it back. */
82 memcpy(cb, skb->cb, sizeof(cb));
84 segs = __skb_gso_segment(skb, 0, tx_path);
85 if (!segs || IS_ERR(segs))
90 __skb_push(skb, pkt_hlen);
91 skb_reset_mac_header(skb);
92 skb_reset_network_header(skb);
93 skb_set_transport_header(skb, sizeof(struct iphdr));
96 memcpy(ip_hdr(skb), iph, pkt_hlen);
97 memcpy(skb->cb, cb, sizeof(cb));
98 if (OVS_GSO_CB(skb)->fix_segment)
99 OVS_GSO_CB(skb)->fix_segment(skb);
101 skb->protocol = proto;
109 int rpl_ip_local_out(struct sk_buff *skb)
111 int ret = NETDEV_TX_OK;
114 if (skb_is_gso(skb)) {
119 skb = tnl_skb_gso_segment(skb, 0, false);
120 if (!skb || IS_ERR(skb))
122 } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
125 err = skb_checksum_help(skb);
131 struct sk_buff *next_skb = skb->next;
139 iph->id = htons(id++);
141 memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
144 err = ip_local_out(skb);
145 if (unlikely(net_xmit_eval(err)))