aboutsummaryrefslogtreecommitdiffstats
path: root/net/ipv4
diff options
context:
space:
mode:
authorTom Herbert <tom@herbertland.com>2016-06-06 19:06:02 -0400
committerDavid S. Miller <davem@davemloft.net>2016-06-08 02:51:14 -0400
commitc1e48af7960e93e1fbe54934be8f4a2fb66ef6fd (patch)
tree8810d753093684aa17dd3b6f44ea6d5cba3fbf56 /net/ipv4
parent34fe76abbea5174e532681e420fb31139909efb4 (diff)
gue: Implement direction IP encapsulation
This patch implements direct encapsulation of IPv4 and IPv6 packets in UDP. This is done a version "1" of GUE and as explained in I-D draft-ietf-nvo3-gue-03. Changes here are only in the receive path, fou with IPxIPx already supports the transmit side. Both the normal receive path and GRO path are modified to check for GUE version and check for IP version in the case that GUE version is "1". Tested: IPIP with direct GUE encap 1 TCP_STREAM 4530 Mbps 200 TCP_RR 1297625 tps 135/232/444 90/95/99% latencies IP4IP6 with direct GUE encap 1 TCP_STREAM 4903 Mbps 200 TCP_RR 1184481 tps 149/253/473 90/95/99% latencies IP6IP6 direct GUE encap 1 TCP_STREAM 5146 Mbps 200 TCP_RR 1202879 tps 146/251/472 90/95/99% latencies SIT with direct GUE encap 1 TCP_STREAM 6111 Mbps 200 TCP_RR 1250337 tps 139/241/467 90/95/99% latencies Signed-off-by: Tom Herbert <tom@herbertland.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'net/ipv4')
-rw-r--r--net/ipv4/fou.c81
1 files changed, 76 insertions, 5 deletions
diff --git a/net/ipv4/fou.c b/net/ipv4/fou.c
index 5f9207c039e7..321d57f825ce 100644
--- a/net/ipv4/fou.c
+++ b/net/ipv4/fou.c
@@ -129,6 +129,36 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb)
129 129
130 guehdr = (struct guehdr *)&udp_hdr(skb)[1]; 130 guehdr = (struct guehdr *)&udp_hdr(skb)[1];
131 131
132 switch (guehdr->version) {
133 case 0: /* Full GUE header present */
134 break;
135
136 case 1: {
137 /* Direct encasulation of IPv4 or IPv6 */
138
139 int prot;
140
141 switch (((struct iphdr *)guehdr)->version) {
142 case 4:
143 prot = IPPROTO_IPIP;
144 break;
145 case 6:
146 prot = IPPROTO_IPV6;
147 break;
148 default:
149 goto drop;
150 }
151
152 if (fou_recv_pull(skb, fou, sizeof(struct udphdr)))
153 goto drop;
154
155 return -prot;
156 }
157
158 default: /* Undefined version */
159 goto drop;
160 }
161
132 optlen = guehdr->hlen << 2; 162 optlen = guehdr->hlen << 2;
133 len += optlen; 163 len += optlen;
134 164
@@ -289,6 +319,7 @@ static struct sk_buff **gue_gro_receive(struct sock *sk,
289 int flush = 1; 319 int flush = 1;
290 struct fou *fou = fou_from_sock(sk); 320 struct fou *fou = fou_from_sock(sk);
291 struct gro_remcsum grc; 321 struct gro_remcsum grc;
322 u8 proto;
292 323
293 skb_gro_remcsum_init(&grc); 324 skb_gro_remcsum_init(&grc);
294 325
@@ -302,6 +333,25 @@ static struct sk_buff **gue_gro_receive(struct sock *sk,
302 goto out; 333 goto out;
303 } 334 }
304 335
336 switch (guehdr->version) {
337 case 0:
338 break;
339 case 1:
340 switch (((struct iphdr *)guehdr)->version) {
341 case 4:
342 proto = IPPROTO_IPIP;
343 break;
344 case 6:
345 proto = IPPROTO_IPV6;
346 break;
347 default:
348 goto out;
349 }
350 goto next_proto;
351 default:
352 goto out;
353 }
354
305 optlen = guehdr->hlen << 2; 355 optlen = guehdr->hlen << 2;
306 len += optlen; 356 len += optlen;
307 357
@@ -370,6 +420,10 @@ static struct sk_buff **gue_gro_receive(struct sock *sk,
370 } 420 }
371 } 421 }
372 422
423 proto = guehdr->proto_ctype;
424
425next_proto:
426
373 /* We can clear the encap_mark for GUE as we are essentially doing 427 /* We can clear the encap_mark for GUE as we are essentially doing
374 * one of two possible things. We are either adding an L4 tunnel 428 * one of two possible things. We are either adding an L4 tunnel
375 * header to the outer L3 tunnel header, or we are are simply 429 * header to the outer L3 tunnel header, or we are are simply
@@ -383,7 +437,7 @@ static struct sk_buff **gue_gro_receive(struct sock *sk,
383 437
384 rcu_read_lock(); 438 rcu_read_lock();
385 offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; 439 offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;
386 ops = rcu_dereference(offloads[guehdr->proto_ctype]); 440 ops = rcu_dereference(offloads[proto]);
387 if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive)) 441 if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
388 goto out_unlock; 442 goto out_unlock;
389 443
@@ -404,13 +458,30 @@ static int gue_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
404 const struct net_offload **offloads; 458 const struct net_offload **offloads;
405 struct guehdr *guehdr = (struct guehdr *)(skb->data + nhoff); 459 struct guehdr *guehdr = (struct guehdr *)(skb->data + nhoff);
406 const struct net_offload *ops; 460 const struct net_offload *ops;
407 unsigned int guehlen; 461 unsigned int guehlen = 0;
408 u8 proto; 462 u8 proto;
409 int err = -ENOENT; 463 int err = -ENOENT;
410 464
411 proto = guehdr->proto_ctype; 465 switch (guehdr->version) {
412 466 case 0:
413 guehlen = sizeof(*guehdr) + (guehdr->hlen << 2); 467 proto = guehdr->proto_ctype;
468 guehlen = sizeof(*guehdr) + (guehdr->hlen << 2);
469 break;
470 case 1:
471 switch (((struct iphdr *)guehdr)->version) {
472 case 4:
473 proto = IPPROTO_IPIP;
474 break;
475 case 6:
476 proto = IPPROTO_IPV6;
477 break;
478 default:
479 return err;
480 }
481 break;
482 default:
483 return err;
484 }
414 485
415 rcu_read_lock(); 486 rcu_read_lock();
416 offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads; 487 offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;