xfrm: avoid extract_output indirection for ipv4
authorFlorian Westphal <fw@strlen.de>
Mon, 4 May 2020 08:06:03 +0000 (10:06 +0200)
committerSteffen Klassert <steffen.klassert@secunet.com>
Wed, 6 May 2020 07:40:08 +0000 (09:40 +0200)
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>
include/net/xfrm.h
net/ipv4/xfrm4_output.c
net/ipv4/xfrm4_state.c
net/xfrm/xfrm_output.c

index 2577666..3970073 100644 (file)
@@ -1580,7 +1580,6 @@ static inline int xfrm4_rcv_spi(struct sk_buff *skb, int nexthdr, __be32 spi)
        return xfrm_input(skb, nexthdr, spi, 0);
 }
 
-int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb);
 int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb);
 int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb);
 int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol);
index 89ba7c8..21c8fa0 100644 (file)
 #include <net/xfrm.h>
 #include <net/icmp.h>
 
-static int xfrm4_tunnel_check_size(struct sk_buff *skb)
-{
-       int mtu, ret = 0;
-
-       if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
-               goto out;
-
-       if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df)
-               goto out;
-
-       mtu = dst_mtu(skb_dst(skb));
-       if ((!skb_is_gso(skb) && skb->len > mtu) ||
-           (skb_is_gso(skb) &&
-            !skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) {
-               skb->protocol = htons(ETH_P_IP);
-
-               if (skb->sk)
-                       xfrm_local_error(skb, mtu);
-               else
-                       icmp_send(skb, ICMP_DEST_UNREACH,
-                                 ICMP_FRAG_NEEDED, htonl(mtu));
-               ret = -EMSGSIZE;
-       }
-out:
-       return ret;
-}
-
-int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb)
-{
-       int err;
-
-       err = xfrm4_tunnel_check_size(skb);
-       if (err)
-               return err;
-
-       XFRM_MODE_SKB_CB(skb)->protocol = ip_hdr(skb)->protocol;
-
-       return xfrm4_extract_header(skb);
-}
-
 int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb)
 {
        memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
index f8ed3c3..d7c2007 100644 (file)
@@ -37,7 +37,6 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
        .output                 = xfrm4_output,
        .output_finish          = xfrm4_output_finish,
        .extract_input          = xfrm4_extract_input,
-       .extract_output         = xfrm4_extract_output,
        .transport_finish       = xfrm4_transport_finish,
        .local_error            = xfrm4_local_error,
 };
index 2fd3d99..a7b3af7 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/slab.h>
 #include <linux/spinlock.h>
 #include <net/dst.h>
+#include <net/icmp.h>
 #include <net/inet_ecn.h>
 #include <net/xfrm.h>
 
@@ -609,6 +610,47 @@ out:
 }
 EXPORT_SYMBOL_GPL(xfrm_output);
 
+static int xfrm4_tunnel_check_size(struct sk_buff *skb)
+{
+       int mtu, ret = 0;
+
+       if (IPCB(skb)->flags & IPSKB_XFRM_TUNNEL_SIZE)
+               goto out;
+
+       if (!(ip_hdr(skb)->frag_off & htons(IP_DF)) || skb->ignore_df)
+               goto out;
+
+       mtu = dst_mtu(skb_dst(skb));
+       if ((!skb_is_gso(skb) && skb->len > mtu) ||
+           (skb_is_gso(skb) &&
+            !skb_gso_validate_network_len(skb, ip_skb_dst_mtu(skb->sk, skb)))) {
+               skb->protocol = htons(ETH_P_IP);
+
+               if (skb->sk)
+                       xfrm_local_error(skb, mtu);
+               else
+                       icmp_send(skb, ICMP_DEST_UNREACH,
+                                 ICMP_FRAG_NEEDED, htonl(mtu));
+               ret = -EMSGSIZE;
+       }
+out:
+       return ret;
+}
+
+static int xfrm4_extract_output(struct xfrm_state *x, struct sk_buff *skb)
+{
+       int err;
+
+       err = xfrm4_tunnel_check_size(skb);
+       if (err)
+               return err;
+
+       XFRM_MODE_SKB_CB(skb)->protocol = ip_hdr(skb)->protocol;
+
+       xfrm4_extract_header(skb);
+       return 0;
+}
+
 static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
 {
        const struct xfrm_state_afinfo *afinfo;
@@ -624,6 +666,10 @@ static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
        if (inner_mode == NULL)
                return -EAFNOSUPPORT;
 
+       switch (inner_mode->family) {
+       case AF_INET:
+               return xfrm4_extract_output(x, skb);
+       }
        rcu_read_lock();
        afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
        if (likely(afinfo))