Skip to content

Commit dce5251

Browse files
IurmanJPaolo Abeni
authored andcommitted
net: ipv6: ioam6_iptunnel: mitigate 2-realloc issue
This patch mitigates the two-reallocations issue with ioam6_iptunnel by providing the dst_entry (in the cache) to the first call to skb_cow_head(). As a result, the very first iteration may still trigger two reallocations (i.e., empty cache), while next iterations would only trigger a single reallocation. Performance tests before/after applying this patch, which clearly shows the improvement: - inline mode: - before: https://ibb.co/LhQ8V63 - after: https://ibb.co/x5YT2bS - encap mode: - before: https://ibb.co/3Cjm5m0 - after: https://ibb.co/TwpsxTC - encap mode with tunsrc: - before: https://ibb.co/Gpy9QPg - after: https://ibb.co/PW1bZFT This patch also fixes an incorrect behavior: after the insertion, the second call to skb_cow_head() makes sure that the dev has enough headroom in the skb for layer 2 and stuff. In that case, the "old" dst_entry was used, which is now fixed. After discussing with Paolo, it appears that both patches can be merged into a single one -this one- (for the sake of readability) and target net-next. Signed-off-by: Justin Iurman <justin.iurman@uliege.be> Signed-off-by: Paolo Abeni <pabeni@redhat.com>
1 parent 0600cf4 commit dce5251

File tree

1 file changed

+37
-36
lines changed

1 file changed

+37
-36
lines changed

net/ipv6/ioam6_iptunnel.c

Lines changed: 37 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -253,14 +253,15 @@ static int ioam6_do_fill(struct net *net, struct sk_buff *skb)
253253
}
254254

255255
static int ioam6_do_inline(struct net *net, struct sk_buff *skb,
256-
struct ioam6_lwt_encap *tuninfo)
256+
struct ioam6_lwt_encap *tuninfo,
257+
struct dst_entry *cache_dst)
257258
{
258259
struct ipv6hdr *oldhdr, *hdr;
259260
int hdrlen, err;
260261

261262
hdrlen = (tuninfo->eh.hdrlen + 1) << 3;
262263

263-
err = skb_cow_head(skb, hdrlen + skb->mac_len);
264+
err = skb_cow_head(skb, hdrlen + dst_dev_overhead(cache_dst, skb));
264265
if (unlikely(err))
265266
return err;
266267

@@ -291,7 +292,8 @@ static int ioam6_do_encap(struct net *net, struct sk_buff *skb,
291292
struct ioam6_lwt_encap *tuninfo,
292293
bool has_tunsrc,
293294
struct in6_addr *tunsrc,
294-
struct in6_addr *tundst)
295+
struct in6_addr *tundst,
296+
struct dst_entry *cache_dst)
295297
{
296298
struct dst_entry *dst = skb_dst(skb);
297299
struct ipv6hdr *hdr, *inner_hdr;
@@ -300,7 +302,7 @@ static int ioam6_do_encap(struct net *net, struct sk_buff *skb,
300302
hdrlen = (tuninfo->eh.hdrlen + 1) << 3;
301303
len = sizeof(*hdr) + hdrlen;
302304

303-
err = skb_cow_head(skb, len + skb->mac_len);
305+
err = skb_cow_head(skb, len + dst_dev_overhead(cache_dst, skb));
304306
if (unlikely(err))
305307
return err;
306308

@@ -334,7 +336,7 @@ static int ioam6_do_encap(struct net *net, struct sk_buff *skb,
334336

335337
static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
336338
{
337-
struct dst_entry *dst = skb_dst(skb);
339+
struct dst_entry *dst = skb_dst(skb), *cache_dst;
338340
struct in6_addr orig_daddr;
339341
struct ioam6_lwt *ilwt;
340342
int err = -EINVAL;
@@ -352,14 +354,18 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
352354

353355
orig_daddr = ipv6_hdr(skb)->daddr;
354356

357+
local_bh_disable();
358+
cache_dst = dst_cache_get(&ilwt->cache);
359+
local_bh_enable();
360+
355361
switch (ilwt->mode) {
356362
case IOAM6_IPTUNNEL_MODE_INLINE:
357363
do_inline:
358364
/* Direct insertion - if there is no Hop-by-Hop yet */
359365
if (ipv6_hdr(skb)->nexthdr == NEXTHDR_HOP)
360366
goto out;
361367

362-
err = ioam6_do_inline(net, skb, &ilwt->tuninfo);
368+
err = ioam6_do_inline(net, skb, &ilwt->tuninfo, cache_dst);
363369
if (unlikely(err))
364370
goto drop;
365371

@@ -369,7 +375,7 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
369375
/* Encapsulation (ip6ip6) */
370376
err = ioam6_do_encap(net, skb, &ilwt->tuninfo,
371377
ilwt->has_tunsrc, &ilwt->tunsrc,
372-
&ilwt->tundst);
378+
&ilwt->tundst, cache_dst);
373379
if (unlikely(err))
374380
goto drop;
375381

@@ -387,41 +393,36 @@ static int ioam6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
387393
goto drop;
388394
}
389395

390-
err = skb_cow_head(skb, LL_RESERVED_SPACE(dst->dev));
391-
if (unlikely(err))
392-
goto drop;
396+
if (unlikely(!cache_dst)) {
397+
struct ipv6hdr *hdr = ipv6_hdr(skb);
398+
struct flowi6 fl6;
399+
400+
memset(&fl6, 0, sizeof(fl6));
401+
fl6.daddr = hdr->daddr;
402+
fl6.saddr = hdr->saddr;
403+
fl6.flowlabel = ip6_flowinfo(hdr);
404+
fl6.flowi6_mark = skb->mark;
405+
fl6.flowi6_proto = hdr->nexthdr;
406+
407+
cache_dst = ip6_route_output(net, NULL, &fl6);
408+
if (cache_dst->error) {
409+
err = cache_dst->error;
410+
dst_release(cache_dst);
411+
goto drop;
412+
}
393413

394-
if (!ipv6_addr_equal(&orig_daddr, &ipv6_hdr(skb)->daddr)) {
395414
local_bh_disable();
396-
dst = dst_cache_get(&ilwt->cache);
415+
dst_cache_set_ip6(&ilwt->cache, cache_dst, &fl6.saddr);
397416
local_bh_enable();
398417

399-
if (unlikely(!dst)) {
400-
struct ipv6hdr *hdr = ipv6_hdr(skb);
401-
struct flowi6 fl6;
402-
403-
memset(&fl6, 0, sizeof(fl6));
404-
fl6.daddr = hdr->daddr;
405-
fl6.saddr = hdr->saddr;
406-
fl6.flowlabel = ip6_flowinfo(hdr);
407-
fl6.flowi6_mark = skb->mark;
408-
fl6.flowi6_proto = hdr->nexthdr;
409-
410-
dst = ip6_route_output(net, NULL, &fl6);
411-
if (dst->error) {
412-
err = dst->error;
413-
dst_release(dst);
414-
goto drop;
415-
}
416-
417-
local_bh_disable();
418-
dst_cache_set_ip6(&ilwt->cache, dst, &fl6.saddr);
419-
local_bh_enable();
420-
}
418+
err = skb_cow_head(skb, LL_RESERVED_SPACE(cache_dst->dev));
419+
if (unlikely(err))
420+
goto drop;
421+
}
421422

423+
if (!ipv6_addr_equal(&orig_daddr, &ipv6_hdr(skb)->daddr)) {
422424
skb_dst_drop(skb);
423-
skb_dst_set(skb, dst);
424-
425+
skb_dst_set(skb, cache_dst);
425426
return dst_output(net, sk, skb);
426427
}
427428
out:

0 commit comments

Comments
 (0)