2 * Copyright (c) 2010 Nicira Networks.
3 * Distributed under the terms of the GNU GPL version 2.
5 * Significant portions of this file may be copied from parts of the Linux
6 * kernel, by Linus Torvalds and others.
12 #include <linux/skbuff.h>
13 #include <linux/version.h>
15 #include <net/checksum.h>
17 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \
18 (defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID))
19 #define NEED_CSUM_NORMALIZE
22 /* These are the same values as the checksum constants in 2.6.22+. */
25 OVS_CSUM_UNNECESSARY = 1,
26 OVS_CSUM_COMPLETE = 2,
30 #ifdef NEED_CSUM_NORMALIZE
31 void compute_ip_summed(struct sk_buff *skb, bool xmit);
32 u8 get_ip_summed(struct sk_buff *skb);
34 static inline void compute_ip_summed(struct sk_buff *skb, bool xmit) { }
35 static inline u8 get_ip_summed(struct sk_buff *skb)
37 return skb->ip_summed;
41 /* This function closely resembles skb_forward_csum() used by the bridge. It
42 * is slightly different because we are only concerned with bridging and not
43 * other types of forwarding and can get away with slightly more optimal
46 static inline void forward_ip_summed(struct sk_buff *skb)
49 if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
50 skb->ip_summed = CHECKSUM_NONE;
54 #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
55 int vswitch_skb_checksum_setup(struct sk_buff *skb);
57 static inline int vswitch_skb_checksum_setup(struct sk_buff *skb)
63 static inline void get_skb_csum_pointers(const struct sk_buff *skb,
64 u16 *csum_start, u16 *csum_offset)
66 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
67 *csum_start = skb->csum_start;
68 *csum_offset = skb->csum_offset;
70 *csum_start = skb_headroom(skb) + skb_transport_offset(skb);
71 *csum_offset = skb->csum;
75 static inline void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
78 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
79 skb->csum_start = csum_start;
80 skb->csum_offset = csum_offset;
82 skb_set_transport_header(skb, csum_start - skb_headroom(skb));
83 skb->csum = csum_offset;
87 #if defined(NEED_CSUM_NORMALIZE) || LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
88 /* This is really compatibility code that belongs in the compat directory.
89 * However, it needs access to our normalized checksum values, so put it here.
91 #define inet_proto_csum_replace4 rpl_inet_proto_csum_replace4
92 static inline void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
93 __be32 from, __be32 to,
96 __be32 diff[] = { ~from, to };
98 if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
99 *sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
100 ~csum_unfold(*sum)));
101 if (get_ip_summed(skb) == OVS_CSUM_COMPLETE && pseudohdr)
102 skb->csum = ~csum_partial((char *)diff, sizeof(diff),
104 } else if (pseudohdr)
105 *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff),
110 #endif /* checksum.h */