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); |
