Skip to content

Commit c1e48af

Browse files
tomratbertdavem330
authored andcommitted
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 <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 34fe76a commit c1e48af

File tree

1 file changed

+76
-5
lines changed

1 file changed

+76
-5
lines changed

net/ipv4/fou.c

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,36 @@ static int gue_udp_recv(struct sock *sk, struct sk_buff *skb)
129129

130130
guehdr = (struct guehdr *)&udp_hdr(skb)[1];
131131

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+
132162
optlen = guehdr->hlen << 2;
133163
len += optlen;
134164

@@ -289,6 +319,7 @@ static struct sk_buff **gue_gro_receive(struct sock *sk,
289319
int flush = 1;
290320
struct fou *fou = fou_from_sock(sk);
291321
struct gro_remcsum grc;
322+
u8 proto;
292323

293324
skb_gro_remcsum_init(&grc);
294325

@@ -302,6 +333,25 @@ static struct sk_buff **gue_gro_receive(struct sock *sk,
302333
goto out;
303334
}
304335

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+
305355
optlen = guehdr->hlen << 2;
306356
len += optlen;
307357

@@ -370,6 +420,10 @@ static struct sk_buff **gue_gro_receive(struct sock *sk,
370420
}
371421
}
372422

423+
proto = guehdr->proto_ctype;
424+
425+
next_proto:
426+
373427
/* We can clear the encap_mark for GUE as we are essentially doing
374428
* one of two possible things. We are either adding an L4 tunnel
375429
* 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,
383437

384438
rcu_read_lock();
385439
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]);
387441
if (WARN_ON_ONCE(!ops || !ops->callbacks.gro_receive))
388442
goto out_unlock;
389443

@@ -404,13 +458,30 @@ static int gue_gro_complete(struct sock *sk, struct sk_buff *skb, int nhoff)
404458
const struct net_offload **offloads;
405459
struct guehdr *guehdr = (struct guehdr *)(skb->data + nhoff);
406460
const struct net_offload *ops;
407-
unsigned int guehlen;
461+
unsigned int guehlen = 0;
408462
u8 proto;
409463
int err = -ENOENT;
410464

411-
proto = guehdr->proto_ctype;
412-
413-
guehlen = sizeof(*guehdr) + (guehdr->hlen << 2);
465+
switch (guehdr->version) {
466+
case 0:
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+
}
414485

415486
rcu_read_lock();
416487
offloads = NAPI_GRO_CB(skb)->is_ipv6 ? inet6_offloads : inet_offloads;

0 commit comments

Comments
 (0)