Skip to content

Commit 3f33398

Browse files
choppsv1klassert
authored andcommitted
xfrm: iptfs: add reusing received skb for the tunnel egress packet
Add an optimization of re-using the tunnel outer skb re-transmission of the inner packet to avoid skb allocation and copy. Signed-off-by: Christian Hopps <[email protected]> Tested-by: Antony Antony <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent 0756947 commit 3f33398

File tree

1 file changed

+108
-15
lines changed

1 file changed

+108
-15
lines changed

net/xfrm/xfrm_iptfs.c

Lines changed: 108 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -601,19 +601,20 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data,
601601
struct list_head *sublist)
602602
{
603603
u8 hbytes[sizeof(struct ipv6hdr)];
604-
struct sk_buff *first_skb, *next, *skb;
604+
struct sk_buff *defer, *first_skb, *next, *skb;
605605
const unsigned char *old_mac;
606606
struct xfrm_iptfs_data *xtfs;
607607
struct iphdr *iph;
608608
struct net *net;
609-
u32 remaining, iplen, iphlen, tail;
609+
u32 first_iplen, iphlen, iplen, remaining, tail;
610610
u32 capturelen;
611611
u64 seq;
612612

613613
xtfs = x->mode_data;
614614
net = xs_net(x);
615615
skb = skbseq->root_skb;
616616
first_skb = NULL;
617+
defer = NULL;
617618

618619
seq = __esp_seq(skb);
619620

@@ -688,23 +689,92 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data,
688689
skb_prepare_seq_read(save, data, tail, skbseq);
689690
}
690691

691-
if (!first_skb)
692+
if (first_skb) {
693+
skb = NULL;
694+
} else {
692695
first_skb = skb;
696+
first_iplen = iplen;
697+
698+
/* We are going to skip over `data` bytes to reach the
699+
* start of the IP header of `iphlen` len for `iplen`
700+
* inner packet.
701+
*/
702+
703+
if (skb_has_frag_list(skb)) {
704+
defer = skb;
705+
skb = NULL;
706+
} else if (data + iphlen <= skb_headlen(skb) &&
707+
/* make sure our header is 32-bit aligned? */
708+
/* ((uintptr_t)(skb->data + data) & 0x3) == 0 && */
709+
skb_tailroom(skb) + tail - data >= iplen) {
710+
/* Reuse the received skb.
711+
*
712+
* We have enough headlen to pull past any
713+
* initial fragment data, leaving at least the
714+
* IP header in the linear buffer space.
715+
*
716+
* For linear buffer space we only require that
717+
* linear buffer space is large enough to
718+
* eventually hold the entire reassembled
719+
* packet (by including tailroom in the check).
720+
*
721+
* For non-linear tailroom is 0 and so we only
722+
* re-use if the entire packet is present
723+
* already.
724+
*
725+
* NOTE: there are many more options for
726+
* sharing, KISS for now. Also, this can produce
727+
* skb's with the IP header unaligned to 32
728+
* bits. If that ends up being a problem then a
729+
* check should be added to the conditional
730+
* above that the header lies on a 32-bit
731+
* boundary as well.
732+
*/
733+
skb_pull(skb, data);
734+
735+
/* our range just changed */
736+
data = 0;
737+
tail = skb->len;
738+
remaining = skb->len;
739+
740+
skb->protocol = protocol;
741+
skb_mac_header_rebuild(skb);
742+
if (skb->mac_len)
743+
eth_hdr(skb)->h_proto = skb->protocol;
744+
745+
/* all pointers could be changed now reset walk */
746+
skb_abort_seq_read(skbseq);
747+
skb_prepare_seq_read(skb, data, tail, skbseq);
748+
} else {
749+
/* We couldn't reuse the input skb so allocate a
750+
* new one.
751+
*/
752+
defer = skb;
753+
skb = NULL;
754+
}
755+
756+
/* Don't trim `first_skb` until the end as we are
757+
* walking that data now.
758+
*/
759+
}
693760

694761
capturelen = min(iplen, remaining);
695-
skb = iptfs_pskb_extract_seq(iplen, skbseq, data, capturelen);
696762
if (!skb) {
697-
/* skip to next packet or done */
698-
data += capturelen;
699-
continue;
700-
}
763+
skb = iptfs_pskb_extract_seq(iplen, skbseq, data,
764+
capturelen);
765+
if (!skb) {
766+
/* skip to next packet or done */
767+
data += capturelen;
768+
continue;
769+
}
701770

702-
skb->protocol = protocol;
703-
if (old_mac) {
704-
/* rebuild the mac header */
705-
skb_set_mac_header(skb, -first_skb->mac_len);
706-
memcpy(skb_mac_header(skb), old_mac, first_skb->mac_len);
707-
eth_hdr(skb)->h_proto = skb->protocol;
771+
skb->protocol = protocol;
772+
if (old_mac) {
773+
/* rebuild the mac header */
774+
skb_set_mac_header(skb, -first_skb->mac_len);
775+
memcpy(skb_mac_header(skb), old_mac, first_skb->mac_len);
776+
eth_hdr(skb)->h_proto = skb->protocol;
777+
}
708778
}
709779

710780
data += capturelen;
@@ -735,14 +805,37 @@ static bool __input_process_payload(struct xfrm_state *x, u32 data,
735805
/* this should not happen from the above code */
736806
XFRM_INC_STATS(net, LINUX_MIB_XFRMINIPTFSERROR);
737807

808+
if (first_skb && first_iplen && !defer && first_skb != xtfs->ra_newskb) {
809+
/* first_skb is queued b/c !defer and not partial */
810+
if (pskb_trim(first_skb, first_iplen)) {
811+
/* error trimming */
812+
list_del(&first_skb->list);
813+
defer = first_skb;
814+
}
815+
first_skb->ip_summed = CHECKSUM_NONE;
816+
}
817+
738818
/* Send the packets! */
739819
list_for_each_entry_safe(skb, next, sublist, list) {
740820
skb_list_del_init(skb);
741821
if (xfrm_input(skb, 0, 0, -2))
742822
kfree_skb(skb);
743823
}
744824
done:
745-
return false;
825+
skb = skbseq->root_skb;
826+
skb_abort_seq_read(skbseq);
827+
828+
if (defer) {
829+
consume_skb(defer);
830+
} else if (!first_skb) {
831+
/* skb is the original passed in skb, but we didn't get far
832+
* enough to process it as the first_skb, if we had it would
833+
* either be save in ra_newskb, trimmed and sent on as an skb or
834+
* placed in defer to be freed.
835+
*/
836+
kfree_skb(skb);
837+
}
838+
return true;
746839
}
747840

748841
/**

0 commit comments

Comments
 (0)