datapath: Consolidate checksum compatibility code.
[sliver-openvswitch.git] / datapath / checksum.h
1 /*
2  * Copyright (c) 2010 Nicira Networks.
3  * Distributed under the terms of the GNU GPL version 2.
4  *
5  * Significant portions of this file may be copied from parts of the Linux
6  * kernel, by Linus Torvalds and others.
7  */
8
9 #ifndef CHECKSUM_H
10 #define CHECKSUM_H 1
11
12 #include <linux/skbuff.h>
13 #include <linux/version.h>
14
15 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \
16         (defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID))
17 #define NEED_CSUM_NORMALIZE
18 #endif
19
20 /* These are the same values as the checksum constants in 2.6.22+. */
21 enum csum_type {
22         OVS_CSUM_NONE = 0,
23         OVS_CSUM_UNNECESSARY = 1,
24         OVS_CSUM_COMPLETE = 2,
25         OVS_CSUM_PARTIAL = 3,
26 };
27
28 #ifdef NEED_CSUM_NORMALIZE
29 void compute_ip_summed(struct sk_buff *skb, bool xmit);
30 u8 get_ip_summed(struct sk_buff *skb);
31 #else
32 static inline void compute_ip_summed(struct sk_buff *skb, bool xmit) { }
33 static inline u8 get_ip_summed(struct sk_buff *skb)
34 {
35         return skb->ip_summed;
36 }
37 #endif
38
39 /* This function closely resembles skb_forward_csum() used by the bridge.  It
40  * is slightly different because we are only concerned with bridging and not
41  * other types of forwarding and can get away with slightly more optimal
42  * behavior.
43  */
44 static inline void forward_ip_summed(struct sk_buff *skb)
45 {
46 #ifdef CHECKSUM_HW
47         if (get_ip_summed(skb) == OVS_CSUM_COMPLETE)
48                 skb->ip_summed = CHECKSUM_NONE;
49 #endif
50 }
51
52 #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
53 int vswitch_skb_checksum_setup(struct sk_buff *skb);
54 #else
55 static inline int vswitch_skb_checksum_setup(struct sk_buff *skb)
56 {
57         return 0;
58 }
59 #endif
60
61 static inline void set_skb_csum_bits(const struct sk_buff *old_skb,
62                                      struct sk_buff *new_skb)
63 {
64 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
65         /* Before 2.6.24 these fields were not copied when
66          * doing an skb_copy_expand. */
67         new_skb->ip_summed = old_skb->ip_summed;
68         new_skb->csum = old_skb->csum;
69 #endif
70 #if defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID)
71         /* These fields are copied in skb_clone but not in
72          * skb_copy or related functions.  We need to manually
73          * copy them over here. */
74         new_skb->proto_data_valid = old_skb->proto_data_valid;
75         new_skb->proto_csum_blank = old_skb->proto_csum_blank;
76 #endif
77 }
78
79 static inline void get_skb_csum_pointers(const struct sk_buff *skb,
80                                          u16 *csum_start, u16 *csum_offset)
81 {
82 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
83         *csum_start = skb->csum_start - skb_headroom(skb);
84         *csum_offset = skb->csum_offset;
85 #else
86         *csum_start = skb_transport_header(skb) - skb->data;
87         *csum_offset = skb->csum;
88 #endif
89 }
90
91 static inline void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
92                                          u16 csum_offset)
93 {
94 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
95         skb->csum_start = csum_start;
96         skb->csum_offset = csum_offset;
97 #else
98         skb_set_transport_header(skb, csum_start - skb_headroom(skb));
99         skb->csum = csum_offset;
100 #endif
101 }
102
103 #endif /* checksum.h */