aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4/fou.c
diff options
context:
space:
mode:
authorTom Herbert <therbert@google.com>2014-11-25 14:21:20 -0500
committerDavid S. Miller <davem@davemloft.net>2014-11-26 12:25:44 -0500
commit4fd671ded14f92cb8db0bf72747f4df508ba5e3d (patch)
tree553e4f9745b404e0d1db149192e303fd51681e80 /net/ipv4/fou.c
parent7c967b224a9a7061009ccbc47e1a0b605f1b6d81 (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.c84
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
66static struct guehdr *gue_remcsum(struct sk_buff *skb, struct guehdr *guehdr, 66static 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);