+#endif /* CONFIG_XEN && HAVE_PROTO_DATA_VALID */
+
+ /* Types of checksums that we can receive (these all refer to L4 checksums):
+ * 1. CHECKSUM_NONE: Device that did not compute checksum, contains full
+ * (though not verified) checksum in packet but not in skb->csum. Packets
+ * from the bridge local port will also have this type.
+ * 2. CHECKSUM_COMPLETE (CHECKSUM_HW): Good device that computes checksums,
+ * also the GRE module. This is the same as CHECKSUM_NONE, except it has
+ * a valid skb->csum. Importantly, both contain a full checksum (not
+ * verified) in the packet itself. The only difference is that if the
+ * packet gets to L4 processing on this machine (not in DomU) we won't
+ * have to recompute the checksum to verify. Most hardware devices do not
+ * produce packets with this type, even if they support receive checksum
+ * offloading (they produce type #5).
+ * 3. CHECKSUM_PARTIAL (CHECKSUM_HW): Packet without full checksum and needs to
+ * be computed if it is sent off box. Unfortunately on earlier kernels,
+ * this case is impossible to distinguish from #2, despite having opposite
+ * meanings. Xen adds an extra field on earlier kernels (see #4) in order
+ * to distinguish the different states. The only real user of this type
+ * with bridging is Xen (on later kernels).
+ * 4. CHECKSUM_UNNECESSARY (with proto_csum_blank true): This packet was
+ * generated locally by a Xen DomU and has a partial checksum. If it is
+ * handled on this machine (Dom0 or DomU), then the checksum will not be
+ * computed. If it goes off box, the checksum in the packet needs to be
+ * completed. Calling skb_checksum_setup converts this to CHECKSUM_HW
+ * (CHECKSUM_PARTIAL) so that the checksum can be completed. In later
+ * kernels, this combination is replaced with CHECKSUM_PARTIAL.
+ * 5. CHECKSUM_UNNECESSARY (with proto_csum_blank false): Packet with a correct
+ * full checksum or using a protocol without a checksum. skb->csum is
+ * undefined. This is common from devices with receive checksum
+ * offloading. This is somewhat similar to CHECKSUM_NONE, except that
+ * nobody will try to verify the checksum with CHECKSUM_UNNECESSARY.
+ *
+ * Note that on earlier kernels, CHECKSUM_COMPLETE and CHECKSUM_PARTIAL are
+ * both defined as CHECKSUM_HW. Normally the meaning of CHECKSUM_HW is clear
+ * based on whether it is on the transmit or receive path. After the datapath
+ * it will be intepreted as CHECKSUM_PARTIAL. If the packet already has a
+ * checksum, we will panic. Since we can receive packets with checksums, we
+ * assume that all CHECKSUM_HW packets have checksums and map them to
+ * CHECKSUM_NONE, which has a similar meaning (the it is only different if the
+ * packet is processed by the local IP stack, in which case it will need to
+ * be reverified). If we receive a packet with CHECKSUM_HW that really means
+ * CHECKSUM_PARTIAL, it will be sent with the wrong checksum. However, there
+ * shouldn't be any devices that do this with bridging.
+ *
+ * The bridge has similar behavior and this function closely resembles
+ * skb_forward_csum(). It is slightly different because we are only concerned
+ * with bridging and not other types of forwarding and can get away with
+ * slightly more optimal behavior.*/
+void
+compute_ip_summed(struct sk_buff *skb, bool xmit)
+{
+ /* For our convenience these defines change repeatedly between kernel
+ * versions, so we can't just copy them over... */
+ switch (skb->ip_summed) {
+ case CHECKSUM_NONE:
+ OVS_CB(skb)->ip_summed = OVS_CSUM_NONE;
+ break;
+ case CHECKSUM_UNNECESSARY:
+ OVS_CB(skb)->ip_summed = OVS_CSUM_UNNECESSARY;
+ break;
+#ifdef CHECKSUM_HW
+ /* In theory this could be either CHECKSUM_PARTIAL or CHECKSUM_COMPLETE.
+ * However, we should only get CHECKSUM_PARTIAL packets from Xen, which
+ * uses some special fields to represent this (see below). Since we
+ * can only make one type work, pick the one that actually happens in
+ * practice.
+ *
+ * The one exception to this is if we are on the transmit path
+ * (basically after skb_checksum_setup() has been run) the type has
+ * already been converted, so we should stay with that. */
+ case CHECKSUM_HW:
+ if (!xmit)
+ OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE;
+ else
+ OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
+
+ break;
+#else
+ case CHECKSUM_COMPLETE:
+ OVS_CB(skb)->ip_summed = OVS_CSUM_COMPLETE;
+ break;
+ case CHECKSUM_PARTIAL:
+ OVS_CB(skb)->ip_summed = OVS_CSUM_PARTIAL;
+ break;