Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

xfrm: avoid extract_output indirection for ipv4

We can use a direct call for ipv4, so move the needed functions
to net/xfrm/xfrm_output.c and call them directly.

For ipv6 the indirection can be avoided as well but it will need
a bit more work -- to ease review it will be done in another patch.

Signed-off-by: Florian Westphal <fw@strlen.de>
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>

authored by

Florian Westphal and committed by
Steffen Klassert
6d64be3d 26333c37

+46 -42
-1
include/net/xfrm.h
··· 1580 1580 return xfrm_input(skb, nexthdr, spi, 0); 1581 1581 } 1582 1582 1583 - int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb); 1584 1583 int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb); 1585 1584 int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb); 1586 1585 int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol);
-40
net/ipv4/xfrm4_output.c
··· 14 14 #include <net/xfrm.h> 15 15 #include <net/icmp.h> 16 16 17 - static int xfrm4_tunnel_check_size(struct sk_buff *skb) 18 - { 19 - int mtu, ret = 0; 20 - 21 - if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) 22 - goto out; 23 - 24 - if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df) 25 - goto out; 26 - 27 - mtu = dst_mtu(skb_dst(skb)); 28 - if ((!skb_is_gso(skb) && skb->len > mtu) || 29 - (skb_is_gso(skb) && 30 - !skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) { 31 - skb->protocol = htons(ETH_P_IP); 32 - 33 - if (skb->sk) 34 - xfrm_local_error(skb, mtu); 35 - else 36 - icmp_send(skb, ICMP_DEST_UNREACH, 37 - ICMP_FRAG_NEEDED, htonl(mtu)); 38 - ret = -EMSGSIZE; 39 - } 40 - out: 41 - return ret; 42 - } 43 - 44 - int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb) 45 - { 46 - int err; 47 - 48 - err = xfrm4_tunnel_check_size(skb); 49 - if (err) 50 - return err; 51 - 52 - XFRM_MODE_SKB_CB(skb)->protocol = ip_hdr(skb)->protocol; 53 - 54 - return xfrm4_extract_header(skb); 55 - } 56 - 57 17 int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb) 58 18 { 59 19 memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
-1
net/ipv4/xfrm4_state.c
··· 37 37 .output = xfrm4_output, 38 38 .output_finish = xfrm4_output_finish, 39 39 .extract_input = xfrm4_extract_input, 40 - .extract_output = xfrm4_extract_output, 41 40 .transport_finish = xfrm4_transport_finish, 42 41 .local_error = xfrm4_local_error, 43 42 };
+46
net/xfrm/xfrm_output.c
··· 13 13 #include <linux/slab.h> 14 14 #include <linux/spinlock.h> 15 15 #include <net/dst.h> 16 + #include <net/icmp.h> 16 17 #include <net/inet_ecn.h> 17 18 #include <net/xfrm.h> 18 19 ··· 610 609 } 611 610 EXPORT_SYMBOL_GPL(xfrm_output); 612 611 612 + static int xfrm4_tunnel_check_size(struct sk_buff *skb) 613 + { 614 + int mtu, ret = 0; 615 + 616 + if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE) 617 + goto out; 618 + 619 + if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df) 620 + goto out; 621 + 622 + mtu = dst_mtu(skb_dst(skb)); 623 + if ((!skb_is_gso(skb) && skb->len > mtu) || 624 + (skb_is_gso(skb) && 625 + !skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) { 626 + skb->protocol = htons(ETH_P_IP); 627 + 628 + if (skb->sk) 629 + xfrm_local_error(skb, mtu); 630 + else 631 + icmp_send(skb, ICMP_DEST_UNREACH, 632 + ICMP_FRAG_NEEDED, htonl(mtu)); 633 + ret = -EMSGSIZE; 634 + } 635 + out: 636 + return ret; 637 + } 638 + 639 + static int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb) 640 + { 641 + int err; 642 + 643 + err = xfrm4_tunnel_check_size(skb); 644 + if (err) 645 + return err; 646 + 647 + XFRM_MODE_SKB_CB(skb)->protocol = ip_hdr(skb)->protocol; 648 + 649 + xfrm4_extract_header(skb); 650 + return 0; 651 + } 652 + 613 653 static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb) 614 654 { 615 655 const struct xfrm_state_afinfo *afinfo; ··· 666 624 if (inner_mode == NULL) 667 625 return -EAFNOSUPPORT; 668 626 627 + switch (inner_mode->family) { 628 + case AF_INET: 629 + return xfrm4_extract_output(x, skb); 630 + } 669 631 rcu_read_lock(); 670 632 afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family); 671 633 if (likely(afinfo))