2 * Copyright (c) 2007-2011 Nicira Networks.
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 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
23 #include <linux/tcp.h>
24 #include <linux/udp.h>
29 #ifdef NEED_CSUM_NORMALIZE
31 #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
32 /* This code is based on skb_checksum_setup() from Xen's net/dev/core.c. We
33 * can't call this function directly because it isn't exported in all
35 static int vswitch_skb_checksum_setup(struct sk_buff *skb)
40 __u16 csum_start, csum_offset;
42 if (!skb->proto_csum_blank)
45 if (skb->protocol != htons(ETH_P_IP))
48 if (!pskb_may_pull(skb, skb_network_header(skb) + sizeof(struct iphdr) - skb->data))
52 th = skb_network_header(skb) + 4 * iph->ihl;
54 csum_start = th - skb->head;
55 switch (iph->protocol) {
57 csum_offset = offsetof(struct tcphdr, check);
60 csum_offset = offsetof(struct udphdr, check);
64 pr_err("Attempting to checksum a non-TCP/UDP packet, "
65 "dropping a protocol %d packet",
70 if (!pskb_may_pull(skb, th + csum_offset + 2 - skb->data))
73 skb->proto_csum_blank = 0;
74 set_ip_summed(skb, OVS_CSUM_PARTIAL);
75 set_skb_csum_pointers(skb, csum_start, csum_offset);
83 static int vswitch_skb_checksum_setup(struct sk_buff *skb)
87 #endif /* not Xen old style checksums */
90 * compute_ip_summed - map external checksum state onto OVS representation
92 * @skb: Packet to manipulate.
93 * @xmit: Whether we were on transmit path of network stack. For example,
94 * this is true for the internal dev vport because it receives skbs
95 * that passed through dev_queue_xmit() but false for the netdev vport
96 * because its packets come from netif_receive_skb().
98 * Older kernels (and various versions of Xen) were not explicit enough about
99 * checksum offload parameters and rely on a combination of context and
100 * non standard fields. This deals with all those variations so that we
101 * can internally manipulate checksum offloads without worrying about kernel
104 * Types of checksums that we can receive (these all refer to L4 checksums):
105 * 1. CHECKSUM_NONE: Device that did not compute checksum, contains full
106 * (though not verified) checksum in packet but not in skb->csum. Packets
107 * from the bridge local port will also have this type.
108 * 2. CHECKSUM_COMPLETE (CHECKSUM_HW): Good device that computes checksums,
109 * also the GRE module. This is the same as CHECKSUM_NONE, except it has
110 * a valid skb->csum. Importantly, both contain a full checksum (not
111 * verified) in the packet itself. The only difference is that if the
112 * packet gets to L4 processing on this machine (not in DomU) we won't
113 * have to recompute the checksum to verify. Most hardware devices do not
114 * produce packets with this type, even if they support receive checksum
115 * offloading (they produce type #5).
116 * 3. CHECKSUM_PARTIAL (CHECKSUM_HW): Packet without full checksum and needs to
117 * be computed if it is sent off box. Unfortunately on earlier kernels,
118 * this case is impossible to distinguish from #2, despite having opposite
119 * meanings. Xen adds an extra field on earlier kernels (see #4) in order
120 * to distinguish the different states.
121 * 4. CHECKSUM_UNNECESSARY (with proto_csum_blank true): This packet was
122 * generated locally by a Xen DomU and has a partial checksum. If it is
123 * handled on this machine (Dom0 or DomU), then the checksum will not be
124 * computed. If it goes off box, the checksum in the packet needs to be
125 * completed. Calling skb_checksum_setup converts this to CHECKSUM_HW
126 * (CHECKSUM_PARTIAL) so that the checksum can be completed. In later
127 * kernels, this combination is replaced with CHECKSUM_PARTIAL.
128 * 5. CHECKSUM_UNNECESSARY (with proto_csum_blank false): Packet with a correct
129 * full checksum or using a protocol without a checksum. skb->csum is
130 * undefined. This is common from devices with receive checksum
131 * offloading. This is somewhat similar to CHECKSUM_NONE, except that
132 * nobody will try to verify the checksum with CHECKSUM_UNNECESSARY.
134 * Note that on earlier kernels, CHECKSUM_COMPLETE and CHECKSUM_PARTIAL are
135 * both defined as CHECKSUM_HW. Normally the meaning of CHECKSUM_HW is clear
136 * based on whether it is on the transmit or receive path. After the datapath
137 * it will be intepreted as CHECKSUM_PARTIAL. If the packet already has a
138 * checksum, we will panic. Since we can receive packets with checksums, we
139 * assume that all CHECKSUM_HW packets have checksums and map them to
140 * CHECKSUM_NONE, which has a similar meaning (the it is only different if the
141 * packet is processed by the local IP stack, in which case it will need to
142 * be reverified). If we receive a packet with CHECKSUM_HW that really means
143 * CHECKSUM_PARTIAL, it will be sent with the wrong checksum. However, there
144 * shouldn't be any devices that do this with bridging.
146 int compute_ip_summed(struct sk_buff *skb, bool xmit)
148 /* For our convenience these defines change repeatedly between kernel
149 * versions, so we can't just copy them over...
151 switch (skb->ip_summed) {
153 set_ip_summed(skb, OVS_CSUM_NONE);
155 case CHECKSUM_UNNECESSARY:
156 set_ip_summed(skb, OVS_CSUM_UNNECESSARY);
159 /* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
160 * However, on the receive side we should only get CHECKSUM_PARTIAL
161 * packets from Xen, which uses some special fields to represent this
162 * (see vswitch_skb_checksum_setup()). Since we can only make one type
163 * work, pick the one that actually happens in practice.
165 * On the transmit side (basically after skb_checksum_setup()
166 * has been run or on internal dev transmit), packets with
167 * CHECKSUM_COMPLETE aren't generated, so assume CHECKSUM_PARTIAL.
171 set_ip_summed(skb, OVS_CSUM_COMPLETE);
173 set_ip_summed(skb, OVS_CSUM_PARTIAL);
176 case CHECKSUM_COMPLETE:
177 set_ip_summed(skb, OVS_CSUM_COMPLETE);
179 case CHECKSUM_PARTIAL:
180 set_ip_summed(skb, OVS_CSUM_PARTIAL);
185 OVS_CB(skb)->csum_start = skb_headroom(skb) + skb_transport_offset(skb);
187 return vswitch_skb_checksum_setup(skb);
191 * forward_ip_summed - map internal checksum state back onto native
194 * @skb: Packet to manipulate.
195 * @xmit: Whether we are about send on the transmit path the network stack.
196 * This follows the same logic as the @xmit field in compute_ip_summed().
197 * Generally, a given vport will have opposite values for @xmit passed to
198 * these two functions.
200 * When a packet is about to egress from OVS take our internal fields (including
201 * any modifications we have made) and recreate the correct representation for
202 * this kernel. This may do things like change the transport header offset.
204 void forward_ip_summed(struct sk_buff *skb, bool xmit)
206 switch (get_ip_summed(skb)) {
208 skb->ip_summed = CHECKSUM_NONE;
210 case OVS_CSUM_UNNECESSARY:
211 skb->ip_summed = CHECKSUM_UNNECESSARY;
212 #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
213 skb->proto_data_valid = 1;
217 case OVS_CSUM_COMPLETE:
219 skb->ip_summed = CHECKSUM_HW;
221 skb->ip_summed = CHECKSUM_NONE;
223 case OVS_CSUM_PARTIAL:
225 skb->ip_summed = CHECKSUM_UNNECESSARY;
226 #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
227 skb->proto_csum_blank = 1;
230 skb->ip_summed = CHECKSUM_HW;
234 case OVS_CSUM_COMPLETE:
235 skb->ip_summed = CHECKSUM_COMPLETE;
237 case OVS_CSUM_PARTIAL:
238 skb->ip_summed = CHECKSUM_PARTIAL;
243 if (get_ip_summed(skb) == OVS_CSUM_PARTIAL)
244 skb_set_transport_header(skb, OVS_CB(skb)->csum_start -
248 u8 get_ip_summed(struct sk_buff *skb)
250 return OVS_CB(skb)->ip_summed;
253 void set_ip_summed(struct sk_buff *skb, u8 ip_summed)
255 OVS_CB(skb)->ip_summed = ip_summed;
258 void get_skb_csum_pointers(const struct sk_buff *skb, u16 *csum_start,
261 *csum_start = OVS_CB(skb)->csum_start;
262 *csum_offset = skb->csum;
265 void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
268 OVS_CB(skb)->csum_start = csum_start;
269 skb->csum = csum_offset;
271 #endif /* NEED_CSUM_NORMALIZE */