Include <sys/time.h> in socket-util.h
[openvswitch] / datapath / checksum.h
1 /*
2  * Copyright (c) 2010, 2011 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 #include <net/checksum.h>
16
17 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \
18         (defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID))
19 #define NEED_CSUM_NORMALIZE
20 #endif
21
22 /* These are the same values as the checksum constants in 2.6.22+. */
23 enum csum_type {
24         OVS_CSUM_NONE = 0,
25         OVS_CSUM_UNNECESSARY = 1,
26         OVS_CSUM_COMPLETE = 2,
27         OVS_CSUM_PARTIAL = 3,
28 };
29
30 #ifdef NEED_CSUM_NORMALIZE
31 int compute_ip_summed(struct sk_buff *skb, bool xmit);
32 void forward_ip_summed(struct sk_buff *skb, bool xmit);
33 u8 get_ip_summed(struct sk_buff *skb);
34 void set_ip_summed(struct sk_buff *skb, u8 ip_summed);
35 void get_skb_csum_pointers(const struct sk_buff *skb, u16 *csum_start,
36                            u16 *csum_offset);
37 void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start, u16 csum_offset);
38 #else
39 static inline int compute_ip_summed(struct sk_buff *skb, bool xmit)
40 {
41         return 0;
42 }
43
44 static inline void forward_ip_summed(struct sk_buff *skb, bool xmit) { }
45
46 static inline u8 get_ip_summed(struct sk_buff *skb)
47 {
48         return skb->ip_summed;
49 }
50
51 static inline void set_ip_summed(struct sk_buff *skb, u8 ip_summed)
52 {
53         skb->ip_summed = ip_summed;
54 }
55
56 static inline void get_skb_csum_pointers(const struct sk_buff *skb,
57                                          u16 *csum_start, u16 *csum_offset)
58 {
59         *csum_start = skb->csum_start;
60         *csum_offset = skb->csum_offset;
61 }
62
63 static inline void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
64                                          u16 csum_offset)
65 {
66         skb->csum_start = csum_start;
67         skb->csum_offset = csum_offset;
68 }
69 #endif
70
71 /* This is really compatibility code that belongs in the compat directory.
72  * However, it needs access to our normalized checksum values, so put it here.
73  */
74 #if defined(NEED_CSUM_NORMALIZE) || LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
75 #define inet_proto_csum_replace4 rpl_inet_proto_csum_replace4
76 static inline void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
77                                             __be32 from, __be32 to,
78                                             int pseudohdr)
79 {
80         __be32 diff[] = { ~from, to };
81
82         if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
83                 *sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
84                                 ~csum_unfold(*sum)));
85                 if (get_ip_summed(skb) == OVS_CSUM_COMPLETE && pseudohdr)
86                         skb->csum = ~csum_partial((char *)diff, sizeof(diff),
87                                                 ~skb->csum);
88         } else if (pseudohdr)
89                 *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff),
90                                 csum_unfold(*sum)));
91 }
92 #endif
93
94 #ifdef NEED_CSUM_NORMALIZE
95 static inline void update_csum_start(struct sk_buff *skb, int delta)
96 {
97         if (get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
98                 u16 csum_start, csum_offset;
99
100                 get_skb_csum_pointers(skb, &csum_start, &csum_offset);
101                 set_skb_csum_pointers(skb, csum_start + delta, csum_offset);
102         }
103 }
104
105 static inline int rpl_pskb_expand_head(struct sk_buff *skb, int nhead,
106                                        int ntail, gfp_t gfp_mask)
107 {
108         int err;
109         int old_headroom = skb_headroom(skb);
110
111         err = pskb_expand_head(skb, nhead, ntail, gfp_mask);
112         if (unlikely(err))
113                 return err;
114
115         update_csum_start(skb, skb_headroom(skb) - old_headroom);
116
117         return 0; 
118 }
119 #define pskb_expand_head rpl_pskb_expand_head
120
121 static inline unsigned char *rpl__pskb_pull_tail(struct sk_buff *skb,
122                                                   int delta)
123 {
124         unsigned char *ret;
125         int old_headroom = skb_headroom(skb);
126
127         ret = __pskb_pull_tail(skb, delta);
128         if (unlikely(!ret))
129                 return ret;
130
131         update_csum_start(skb, skb_headroom(skb) - old_headroom);
132
133         return ret;
134 }
135 #define __pskb_pull_tail rpl__pskb_pull_tail
136 #endif
137
138 #endif /* checksum.h */