9
9
10
10
#include <linux/kernel.h>
11
11
#include <linux/icmpv6.h>
12
+ #include <linux/skbuff_ref.h>
12
13
#include <net/gro.h>
13
14
#include <net/icmp.h>
14
15
#include <net/ip6_route.h>
@@ -90,6 +91,23 @@ struct xfrm_iptfs_data {
90
91
static u32 iptfs_get_inner_mtu (struct xfrm_state * x , int outer_mtu );
91
92
static enum hrtimer_restart iptfs_delay_timer (struct hrtimer * me );
92
93
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
+
93
111
/* ================================= */
94
112
/* IPTFS Sending (ingress) Functions */
95
113
/* ================================= */
@@ -297,14 +315,44 @@ static struct sk_buff **iptfs_rehome_fraglist(struct sk_buff **nextp, struct sk_
297
315
return nextp ;
298
316
}
299
317
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
+
300
347
static void iptfs_output_queued (struct xfrm_state * x , struct sk_buff_head * list )
301
348
{
302
349
struct xfrm_iptfs_data * xtfs = x -> mode_data ;
303
350
struct sk_buff * skb , * skb2 , * * nextp ;
304
- struct skb_shared_info * shi ;
351
+ struct skb_shared_info * shi , * shi2 ;
305
352
306
353
while ((skb = __skb_dequeue (list ))) {
307
354
u32 mtu = iptfs_get_cur_pmtu (x , xtfs , skb );
355
+ bool share_ok = true;
308
356
int remaining ;
309
357
310
358
/* protocol comes to us cleared sometimes */
@@ -349,7 +397,7 @@ static void iptfs_output_queued(struct xfrm_state *x, struct sk_buff_head *list)
349
397
350
398
/* Re-home (un-nest) nested fragment lists. We need to do this
351
399
* b/c we will simply be appending any following aggregated
352
- * inner packets to the frag list.
400
+ * inner packets using the frag list.
353
401
*/
354
402
shi = skb_shinfo (skb );
355
403
nextp = & shi -> frag_list ;
@@ -360,6 +408,9 @@ static void iptfs_output_queued(struct xfrm_state *x, struct sk_buff_head *list)
360
408
nextp = & (* nextp )-> next ;
361
409
}
362
410
411
+ if (shi -> frag_list || skb_cloned (skb ) || skb_shared (skb ))
412
+ share_ok = false;
413
+
363
414
/* See if we have enough space to simply append.
364
415
*
365
416
* 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)
386
437
}
387
438
}
388
439
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
+
389
453
/* Do accounting */
390
454
skb -> data_len += skb2 -> len ;
391
455
skb -> len += skb2 -> len ;
392
456
remaining -= skb2 -> len ;
393
457
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
+ }
400
469
}
401
470
402
471
xfrm_output (NULL , skb );
0 commit comments