diff options
author | Tom Herbert <therbert@google.com> | 2014-11-25 14:21:20 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2014-11-26 12:25:44 -0500 |
commit | 4fd671ded14f92cb8db0bf72747f4df508ba5e3d (patch) | |
tree | 553e4f9745b404e0d1db149192e303fd51681e80 /net/ipv4/fou.c | |
parent | 7c967b224a9a7061009ccbc47e1a0b605f1b6d81 (diff) |
gue: Call remcsum_adjust
Change remote checksum offload to call remcsum_adjust. This also
eliminates the optimization to skip an IP header as part of the
adjustment (really does not seem to be much of a win).
Signed-off-by: Tom Herbert <therbert@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4/fou.c')
-rw-r--r-- | net/ipv4/fou.c | 84 |
1 files changed, 17 insertions, 67 deletions
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c index 3dfe9828e7ef..b986298a7ba3 100644 --- a/net/ipv4/fou.c +++ b/net/ipv4/fou.c | |||
@@ -64,15 +64,13 @@ static int fou_udp_recv(struct sock *sk, struct sk_buff *skb) | |||
64 | } | 64 | } |
65 | 65 | ||
66 | static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, | 66 | static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, |
67 | void *data, int hdrlen, u8 ipproto) | 67 | void *data, size_t hdrlen, u8 ipproto) |
68 | { | 68 | { |
69 | __be16 *pd = data; | 69 | __be16 *pd = data; |
70 | u16 start = ntohs(pd[0]); | 70 | size_t start = ntohs(pd[0]); |
71 | u16 offset = ntohs(pd[1]); | 71 | size_t offset = ntohs(pd[1]); |
72 | u16 poffset = 0; | 72 | size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start); |
73 | u16 plen; | 73 | __wsum delta; |
74 | __wsum csum, delta; | ||
75 | __sum16 *psum; | ||
76 | 74 | ||
77 | if (skb->remcsum_offload) { | 75 | if (skb->remcsum_offload) { |
78 | /* Already processed in GRO path */ | 76 | /* Already processed in GRO path */ |
@@ -80,35 +78,15 @@ static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, | |||
80 | return guehdr; | 78 | return guehdr; |
81 | } | 79 | } |
82 | 80 | ||
83 | if (start > skb->len - hdrlen || | ||
84 | offset > skb->len - hdrlen - sizeof(u16)) | ||
85 | return NULL; | ||
86 | |||
87 | if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE)) | ||
88 | __skb_checksum_complete(skb); | ||
89 | |||
90 | plen = hdrlen + offset + sizeof(u16); | ||
91 | if (!pskb_may_pull(skb, plen)) | 81 | if (!pskb_may_pull(skb, plen)) |
92 | return NULL; | 82 | return NULL; |
93 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; | 83 | guehdr = (struct guehdr *)&udp_hdr(skb)[1]; |
94 | 84 | ||
95 | if (ipproto == IPPROTO_IP && sizeof(struct iphdr) < plen) { | 85 | if (unlikely(skb->ip_summed != CHECKSUM_COMPLETE)) |
96 | struct iphdr *ip = (struct iphdr *)(skb->data + hdrlen); | 86 | __skb_checksum_complete(skb); |
97 | |||
98 | /* If next header happens to be IP we can skip that for the | ||
99 | * checksum calculation since the IP header checksum is zero | ||
100 | * if correct. | ||
101 | */ | ||
102 | poffset = ip->ihl * 4; | ||
103 | } | ||
104 | |||
105 | csum = csum_sub(skb->csum, skb_checksum(skb, poffset + hdrlen, | ||
106 | start - poffset - hdrlen, 0)); | ||
107 | 87 | ||
108 | /* Set derived checksum in packet */ | 88 | delta = remcsum_adjust((void *)guehdr + hdrlen, |
109 | psum = (__sum16 *)(skb->data + hdrlen + offset); | 89 | skb->csum, start, offset); |
110 | delta = csum_sub(csum_fold(csum), *psum); | ||
111 | *psum = csum_fold(csum); | ||
112 | 90 | ||
113 | /* Adjust skb->csum since we changed the packet */ | 91 | /* Adjust skb->csum since we changed the packet */ |
114 | skb->csum = csum_add(skb->csum, delta); | 92 | skb->csum = csum_add(skb->csum, delta); |
@@ -158,9 +136,6 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb) | |||
158 | 136 | ||
159 | ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(skb)->tot_len) - len); | 137 | ip_hdr(skb)->tot_len = htons(ntohs(ip_hdr(skb)->tot_len) - len); |
160 | 138 | ||
161 | /* Pull UDP header now, skb->data points to guehdr */ | ||
162 | __skb_pull(skb, sizeof(struct udphdr)); | ||
163 | |||
164 | /* Pull csum through the guehdr now . This can be used if | 139 | /* Pull csum through the guehdr now . This can be used if |
165 | * there is a remote checksum offload. | 140 | * there is a remote checksum offload. |
166 | */ | 141 | */ |
@@ -188,7 +163,7 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb) | |||
188 | if (unlikely(guehdr->control)) | 163 | if (unlikely(guehdr->control)) |
189 | return gue_control_message(skb, guehdr); | 164 | return gue_control_message(skb, guehdr); |
190 | 165 | ||
191 | __skb_pull(skb, hdrlen); | 166 | __skb_pull(skb, sizeof(struct udphdr) + hdrlen); |
192 | skb_reset_transport_header(skb); | 167 | skb_reset_transport_header(skb); |
193 | 168 | ||
194 | return -guehdr->proto_ctype; | 169 | return -guehdr->proto_ctype; |
@@ -248,24 +223,17 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, | |||
248 | size_t hdrlen, u8 ipproto) | 223 | size_t hdrlen, u8 ipproto) |
249 | { | 224 | { |
250 | __be16 *pd = data; | 225 | __be16 *pd = data; |
251 | u16 start = ntohs(pd[0]); | 226 | size_t start = ntohs(pd[0]); |
252 | u16 offset = ntohs(pd[1]); | 227 | size_t offset = ntohs(pd[1]); |
253 | u16 poffset = 0; | 228 | size_t plen = hdrlen + max_t(size_t, offset + sizeof(u16), start); |
254 | u16 plen; | 229 | __wsum delta; |
255 | void *ptr; | ||
256 | __wsum csum, delta; | ||
257 | __sum16 *psum; | ||
258 | 230 | ||
259 | if (skb->remcsum_offload) | 231 | if (skb->remcsum_offload) |
260 | return guehdr; | 232 | return guehdr; |
261 | 233 | ||
262 | if (start > skb_gro_len(skb) - hdrlen || | 234 | if (!NAPI_GRO_CB(skb)->csum_valid) |
263 | offset > skb_gro_len(skb) - hdrlen - sizeof(u16) || | ||
264 | !NAPI_GRO_CB(skb)->csum_valid || skb->remcsum_offload) | ||
265 | return NULL; | 235 | return NULL; |
266 | 236 | ||
267 | plen = hdrlen + offset + sizeof(u16); | ||
268 | |||
269 | /* Pull checksum that will be written */ | 237 | /* Pull checksum that will be written */ |
270 | if (skb_gro_header_hard(skb, off + plen)) { | 238 | if (skb_gro_header_hard(skb, off + plen)) { |
271 | guehdr = skb_gro_header_slow(skb, off + plen, off); | 239 | guehdr = skb_gro_header_slow(skb, off + plen, off); |
@@ -273,26 +241,8 @@ static struct guehdr *gue_gro_remcsum(struct sk_buff *skb, unsigned int off, | |||
273 | return NULL; | 241 | return NULL; |
274 | } | 242 | } |
275 | 243 | ||
276 | ptr = (void *)guehdr + hdrlen; | 244 | delta = remcsum_adjust((void *)guehdr + hdrlen, |
277 | 245 | NAPI_GRO_CB(skb)->csum, start, offset); | |
278 | if (ipproto == IPPROTO_IP && | ||
279 | (hdrlen + sizeof(struct iphdr) < plen)) { | ||
280 | struct iphdr *ip = (struct iphdr *)(ptr + hdrlen); | ||
281 | |||
282 | /* If next header happens to be IP we can skip | ||
283 | * that for the checksum calculation since the | ||
284 | * IP header checksum is zero if correct. | ||
285 | */ | ||
286 | poffset = ip->ihl * 4; | ||
287 | } | ||
288 | |||
289 | csum = csum_sub(NAPI_GRO_CB(skb)->csum, | ||
290 | csum_partial(ptr + poffset, start - poffset, 0)); | ||
291 | |||
292 | /* Set derived checksum in packet */ | ||
293 | psum = (__sum16 *)(ptr + offset); | ||
294 | delta = csum_sub(csum_fold(csum), *psum); | ||
295 | *psum = csum_fold(csum); | ||
296 | 246 | ||
297 | /* Adjust skb->csum since we changed the packet */ | 247 | /* Adjust skb->csum since we changed the packet */ |
298 | skb->csum = csum_add(skb->csum, delta); | 248 | skb->csum = csum_add(skb->csum, delta); |