]> git.proxmox.com Git - mirror_ovs.git/blob - datapath/checksum.h
Revert "datapath: Increase maximum allocation size of action list."
[mirror_ovs.git] / datapath / checksum.h
1 /*
2 * Copyright (c) 2007-2011 Nicira, Inc.
3 *
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.
7 *
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.
12 *
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
16 * 02110-1301, USA
17 */
18
19 #ifndef CHECKSUM_H
20 #define CHECKSUM_H 1
21
22 #include <linux/skbuff.h>
23 #include <linux/version.h>
24
25 #include <net/checksum.h>
26
27 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22) || \
28 (defined(CONFIG_XEN) && defined(HAVE_PROTO_DATA_VALID))
29 #define NEED_CSUM_NORMALIZE
30 #endif
31
32 /* These are the same values as the checksum constants in 2.6.22+. */
33 enum csum_type {
34 OVS_CSUM_NONE = 0,
35 OVS_CSUM_UNNECESSARY = 1,
36 OVS_CSUM_COMPLETE = 2,
37 OVS_CSUM_PARTIAL = 3,
38 };
39
40 #ifdef NEED_CSUM_NORMALIZE
41 int compute_ip_summed(struct sk_buff *skb, bool xmit);
42 void forward_ip_summed(struct sk_buff *skb, bool xmit);
43 u8 get_ip_summed(struct sk_buff *skb);
44 void set_ip_summed(struct sk_buff *skb, u8 ip_summed);
45 void get_skb_csum_pointers(const struct sk_buff *skb, u16 *csum_start,
46 u16 *csum_offset);
47 void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
48 u16 csum_offset);
49 #else
50 static inline int compute_ip_summed(struct sk_buff *skb, bool xmit)
51 {
52 return 0;
53 }
54
55 static inline void forward_ip_summed(struct sk_buff *skb, bool xmit) { }
56
57 static inline u8 get_ip_summed(struct sk_buff *skb)
58 {
59 return skb->ip_summed;
60 }
61
62 static inline void set_ip_summed(struct sk_buff *skb, u8 ip_summed)
63 {
64 skb->ip_summed = ip_summed;
65 }
66
67 static inline void get_skb_csum_pointers(const struct sk_buff *skb,
68 u16 *csum_start, u16 *csum_offset)
69 {
70 *csum_start = skb->csum_start;
71 *csum_offset = skb->csum_offset;
72 }
73
74 static inline void set_skb_csum_pointers(struct sk_buff *skb, u16 csum_start,
75 u16 csum_offset)
76 {
77 skb->csum_start = csum_start;
78 skb->csum_offset = csum_offset;
79 }
80 #endif
81
82 /* This is really compatibility code that belongs in the compat directory.
83 * However, it needs access to our normalized checksum values, so put it here.
84 */
85 #if defined(NEED_CSUM_NORMALIZE) || LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
86 #define inet_proto_csum_replace4 rpl_inet_proto_csum_replace4
87 static inline void inet_proto_csum_replace4(__sum16 *sum, struct sk_buff *skb,
88 __be32 from, __be32 to,
89 int pseudohdr)
90 {
91 __be32 diff[] = { ~from, to };
92
93 if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
94 *sum = csum_fold(csum_partial((char *)diff, sizeof(diff),
95 ~csum_unfold(*sum)));
96 if (get_ip_summed(skb) == OVS_CSUM_COMPLETE && pseudohdr)
97 skb->csum = ~csum_partial((char *)diff, sizeof(diff),
98 ~skb->csum);
99 } else if (pseudohdr)
100 *sum = ~csum_fold(csum_partial((char *)diff, sizeof(diff),
101 csum_unfold(*sum)));
102 }
103 #endif
104
105 #if defined(NEED_CSUM_NORMALIZE) || LINUX_VERSION_CODE < KERNEL_VERSION(3,7,0)
106 #define inet_proto_csum_replace16 rpl_inet_proto_csum_replace16
107 static inline void inet_proto_csum_replace16(__sum16 *sum,
108 struct sk_buff *skb,
109 const __be32 *from,
110 const __be32 *to,
111 int pseudohdr)
112 {
113 __be32 diff[] = {
114 ~from[0], ~from[1], ~from[2], ~from[3],
115 to[0], to[1], to[2], to[3],
116 };
117 if (get_ip_summed(skb) != OVS_CSUM_PARTIAL) {
118 *sum = csum_fold(csum_partial(diff, sizeof(diff),
119 ~csum_unfold(*sum)));
120 if (get_ip_summed(skb) == OVS_CSUM_COMPLETE && pseudohdr)
121 skb->csum = ~csum_partial(diff, sizeof(diff),
122 ~skb->csum);
123 } else if (pseudohdr)
124 *sum = ~csum_fold(csum_partial(diff, sizeof(diff),
125 csum_unfold(*sum)));
126 }
127 #endif
128
129 #ifdef NEED_CSUM_NORMALIZE
130 static inline void update_csum_start(struct sk_buff *skb, int delta)
131 {
132 if (get_ip_summed(skb) == OVS_CSUM_PARTIAL) {
133 u16 csum_start, csum_offset;
134
135 get_skb_csum_pointers(skb, &csum_start, &csum_offset);
136 set_skb_csum_pointers(skb, csum_start + delta, csum_offset);
137 }
138 }
139
140 static inline int rpl_pskb_expand_head(struct sk_buff *skb, int nhead,
141 int ntail, gfp_t gfp_mask)
142 {
143 int err;
144 int old_headroom = skb_headroom(skb);
145
146 err = pskb_expand_head(skb, nhead, ntail, gfp_mask);
147 if (unlikely(err))
148 return err;
149
150 update_csum_start(skb, skb_headroom(skb) - old_headroom);
151
152 return 0;
153 }
154 #define pskb_expand_head rpl_pskb_expand_head
155
156 static inline unsigned char *rpl__pskb_pull_tail(struct sk_buff *skb,
157 int delta)
158 {
159 unsigned char *ret;
160 int old_headroom = skb_headroom(skb);
161
162 ret = __pskb_pull_tail(skb, delta);
163 if (unlikely(!ret))
164 return ret;
165
166 update_csum_start(skb, skb_headroom(skb) - old_headroom);
167
168 return ret;
169 }
170 #define __pskb_pull_tail rpl__pskb_pull_tail
171 #endif
172
173 #endif /* checksum.h */