Skip to content

Commit b96ba31

Browse files
choppsv1klassert
authored andcommitted
xfrm: iptfs: share page fragments of inner packets
When possible rather than appending secondary (aggregated) inner packets to the fragment list, share their page fragments with the outer IPTFS packet. This allows for more efficient packet transmission. Signed-off-by: Christian Hopps <[email protected]> Tested-by: Antony Antony <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent 0e4fbf0 commit b96ba31

File tree

1 file changed

+77
-8
lines changed

1 file changed

+77
-8
lines changed

net/xfrm/xfrm_iptfs.c

Lines changed: 77 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99

1010
#include <linux/kernel.h>
1111
#include <linux/icmpv6.h>
12+
#include <linux/skbuff_ref.h>
1213
#include <net/gro.h>
1314
#include <net/icmp.h>
1415
#include <net/ip6_route.h>
@@ -90,6 +91,23 @@ struct xfrm_iptfs_data {
9091
static u32 iptfs_get_inner_mtu(struct xfrm_state *x, int outer_mtu);
9192
static enum hrtimer_restart iptfs_delay_timer(struct hrtimer *me);
9293

94+
/* ======================= */
95+
/* IPTFS SK_BUFF Functions */
96+
/* ======================= */
97+
98+
/**
99+
* iptfs_skb_head_to_frag() - initialize a skb_frag_t based on skb head data
100+
* @skb: skb with the head data
101+
* @frag: frag to initialize
102+
*/
103+
static void iptfs_skb_head_to_frag(const struct sk_buff *skb, skb_frag_t *frag)
104+
{
105+
struct page *page = virt_to_head_page(skb->data);
106+
unsigned char *addr = (unsigned char *)page_address(page);
107+
108+
skb_frag_fill_page_desc(frag, page, skb->data - addr, skb_headlen(skb));
109+
}
110+
93111
/* ================================= */
94112
/* IPTFS Sending (ingress) Functions */
95113
/* ================================= */
@@ -297,14 +315,44 @@ static struct sk_buff **iptfs_rehome_fraglist(struct sk_buff **nextp, struct sk_
297315
return nextp;
298316
}
299317

318+
static void iptfs_consume_frags(struct sk_buff *to, struct sk_buff *from)
319+
{
320+
struct skb_shared_info *fromi = skb_shinfo(from);
321+
struct skb_shared_info *toi = skb_shinfo(to);
322+
unsigned int new_truesize;
323+
324+
/* If we have data in a head page, grab it */
325+
if (!skb_headlen(from)) {
326+
new_truesize = SKB_TRUESIZE(skb_end_offset(from));
327+
} else {
328+
iptfs_skb_head_to_frag(from, &toi->frags[toi->nr_frags]);
329+
skb_frag_ref(to, toi->nr_frags++);
330+
new_truesize = SKB_DATA_ALIGN(sizeof(struct sk_buff));
331+
}
332+
333+
/* Move any other page fragments rather than copy */
334+
memcpy(&toi->frags[toi->nr_frags], fromi->frags,
335+
sizeof(fromi->frags[0]) * fromi->nr_frags);
336+
toi->nr_frags += fromi->nr_frags;
337+
fromi->nr_frags = 0;
338+
from->data_len = 0;
339+
from->len = 0;
340+
to->truesize += from->truesize - new_truesize;
341+
from->truesize = new_truesize;
342+
343+
/* We are done with this SKB */
344+
consume_skb(from);
345+
}
346+
300347
static void iptfs_output_queued(struct xfrm_state *x, struct sk_buff_head *list)
301348
{
302349
struct xfrm_iptfs_data *xtfs = x->mode_data;
303350
struct sk_buff *skb, *skb2, **nextp;
304-
struct skb_shared_info *shi;
351+
struct skb_shared_info *shi, *shi2;
305352

306353
while ((skb = __skb_dequeue(list))) {
307354
u32 mtu = iptfs_get_cur_pmtu(x, xtfs, skb);
355+
bool share_ok = true;
308356
int remaining;
309357

310358
/* protocol comes to us cleared sometimes */
@@ -349,7 +397,7 @@ static void iptfs_output_queued(struct xfrm_state *x, struct sk_buff_head *list)
349397

350398
/* Re-home (un-nest) nested fragment lists. We need to do this
351399
* b/c we will simply be appending any following aggregated
352-
* inner packets to the frag list.
400+
* inner packets using the frag list.
353401
*/
354402
shi = skb_shinfo(skb);
355403
nextp = &shi->frag_list;
@@ -360,6 +408,9 @@ static void iptfs_output_queued(struct xfrm_state *x, struct sk_buff_head *list)
360408
nextp = &(*nextp)->next;
361409
}
362410

411+
if (shi->frag_list || skb_cloned(skb) || skb_shared(skb))
412+
share_ok = false;
413+
363414
/* See if we have enough space to simply append.
364415
*
365416
* NOTE: Maybe do not append if we will be mis-aligned,
@@ -386,17 +437,35 @@ static void iptfs_output_queued(struct xfrm_state *x, struct sk_buff_head *list)
386437
}
387438
}
388439

440+
/* skb->pp_recycle is passed to __skb_flag_unref for all
441+
* frag pages so we can only share pages with skb's who
442+
* match ourselves.
443+
*/
444+
shi2 = skb_shinfo(skb2);
445+
if (share_ok &&
446+
(shi2->frag_list ||
447+
(!skb2->head_frag && skb_headlen(skb)) ||
448+
skb->pp_recycle != skb2->pp_recycle ||
449+
skb_zcopy(skb2) ||
450+
(shi->nr_frags + shi2->nr_frags + 1 > MAX_SKB_FRAGS)))
451+
share_ok = false;
452+
389453
/* Do accounting */
390454
skb->data_len += skb2->len;
391455
skb->len += skb2->len;
392456
remaining -= skb2->len;
393457

394-
/* Append to the frag_list */
395-
*nextp = skb2;
396-
nextp = &skb2->next;
397-
if (skb_has_frag_list(skb2))
398-
nextp = iptfs_rehome_fraglist(nextp, skb2);
399-
skb->truesize += skb2->truesize;
458+
if (share_ok) {
459+
iptfs_consume_frags(skb, skb2);
460+
} else {
461+
/* Append to the frag_list */
462+
*nextp = skb2;
463+
nextp = &skb2->next;
464+
if (skb_has_frag_list(skb2))
465+
nextp = iptfs_rehome_fraglist(nextp,
466+
skb2);
467+
skb->truesize += skb2->truesize;
468+
}
400469
}
401470

402471
xfrm_output(NULL, skb);

0 commit comments

Comments
 (0)