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>
This commit is contained in:

committed by
Steffen Klassert

parent
26333c37fc
commit
6d64be3da2
@@ -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);
|
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(struct net *net, struct sock *sk, struct sk_buff *skb);
|
||||||
int xfrm4_output_finish(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);
|
int xfrm4_protocol_register(struct xfrm4_protocol *handler, unsigned char protocol);
|
||||||
|
@@ -14,46 +14,6 @@
|
|||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
#include <net/icmp.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)
|
int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
|
memset(IPCB(skb), 0, sizeof(*IPCB(skb)));
|
||||||
|
@@ -37,7 +37,6 @@ static struct xfrm_state_afinfo xfrm4_state_afinfo = {
|
|||||||
.output = xfrm4_output,
|
.output = xfrm4_output,
|
||||||
.output_finish = xfrm4_output_finish,
|
.output_finish = xfrm4_output_finish,
|
||||||
.extract_input = xfrm4_extract_input,
|
.extract_input = xfrm4_extract_input,
|
||||||
.extract_output = xfrm4_extract_output,
|
|
||||||
.transport_finish = xfrm4_transport_finish,
|
.transport_finish = xfrm4_transport_finish,
|
||||||
.local_error = xfrm4_local_error,
|
.local_error = xfrm4_local_error,
|
||||||
};
|
};
|
||||||
|
@@ -13,6 +13,7 @@
|
|||||||
#include <linux/slab.h>
|
#include <linux/slab.h>
|
||||||
#include <linux/spinlock.h>
|
#include <linux/spinlock.h>
|
||||||
#include <net/dst.h>
|
#include <net/dst.h>
|
||||||
|
#include <net/icmp.h>
|
||||||
#include <net/inet_ecn.h>
|
#include <net/inet_ecn.h>
|
||||||
#include <net/xfrm.h>
|
#include <net/xfrm.h>
|
||||||
|
|
||||||
@@ -609,6 +610,47 @@ out:
|
|||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(xfrm_output);
|
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)
|
static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
const struct xfrm_state_afinfo *afinfo;
|
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)
|
if (inner_mode == NULL)
|
||||||
return -EAFNOSUPPORT;
|
return -EAFNOSUPPORT;
|
||||||
|
|
||||||
|
switch (inner_mode->family) {
|
||||||
|
case AF_INET:
|
||||||
|
return xfrm4_extract_output(x, skb);
|
||||||
|
}
|
||||||
rcu_read_lock();
|
rcu_read_lock();
|
||||||
afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
|
afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
|
||||||
if (likely(afinfo))
|
if (likely(afinfo))
|
||||||
|
Reference in New Issue
Block a user