xfrm: remove afinfo pointer from xfrm_mode
Adds an EXPORT_SYMBOL for afinfo_get_rcu, as it will now be called from ipv6 in case of CONFIG_IPV6=m. This change has virtually no effect on vmlinux size, but it reduces afinfo size and allows followup patch to make xfrm modes const. v2: mark if (afinfo) tests as likely (Sabrina) re-fetch afinfo according to inner_mode in xfrm_prepare_input(). Signed-off-by: Florian Westphal <fw@strlen.de> Reviewed-by: Sabrina Dubroca <sd@queasysnail.net> Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
This commit is contained in:
parent
1de7083006
commit
733a5fac2f
|
@ -423,7 +423,6 @@ int xfrm_register_type_offload(const struct xfrm_type_offload *type, unsigned sh
|
|||
int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family);
|
||||
|
||||
struct xfrm_mode {
|
||||
struct xfrm_state_afinfo *afinfo;
|
||||
struct module *owner;
|
||||
u8 encap;
|
||||
u8 family;
|
||||
|
|
|
@ -72,6 +72,8 @@ int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb)
|
|||
static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct xfrm_state *x = skb_dst(skb)->xfrm;
|
||||
const struct xfrm_state_afinfo *afinfo;
|
||||
int ret = -EAFNOSUPPORT;
|
||||
|
||||
#ifdef CONFIG_NETFILTER
|
||||
if (!x) {
|
||||
|
@ -80,7 +82,15 @@ static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|||
}
|
||||
#endif
|
||||
|
||||
return x->outer_mode->afinfo->output_finish(sk, skb);
|
||||
rcu_read_lock();
|
||||
afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
|
||||
if (likely(afinfo))
|
||||
ret = afinfo->output_finish(sk, skb);
|
||||
else
|
||||
kfree_skb(skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
|
|
|
@ -122,11 +122,28 @@ int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb)
|
|||
return xfrm_output(sk, skb);
|
||||
}
|
||||
|
||||
static int __xfrm6_output_state_finish(struct xfrm_state *x, struct sock *sk,
|
||||
struct sk_buff *skb)
|
||||
{
|
||||
const struct xfrm_state_afinfo *afinfo;
|
||||
int ret = -EAFNOSUPPORT;
|
||||
|
||||
rcu_read_lock();
|
||||
afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
|
||||
if (likely(afinfo))
|
||||
ret = afinfo->output_finish(sk, skb);
|
||||
else
|
||||
kfree_skb(skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
{
|
||||
struct xfrm_state *x = skb_dst(skb)->xfrm;
|
||||
|
||||
return x->outer_mode->afinfo->output_finish(sk, skb);
|
||||
return __xfrm6_output_state_finish(x, sk, skb);
|
||||
}
|
||||
|
||||
static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
|
@ -168,7 +185,7 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
|||
__xfrm6_output_finish);
|
||||
|
||||
skip_frag:
|
||||
return x->outer_mode->afinfo->output_finish(sk, skb);
|
||||
return __xfrm6_output_state_finish(x, sk, skb);
|
||||
}
|
||||
|
||||
int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
|
||||
|
|
|
@ -352,19 +352,35 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x,
|
|||
static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
|
||||
{
|
||||
struct xfrm_mode *inner_mode = x->inner_mode;
|
||||
int err;
|
||||
const struct xfrm_state_afinfo *afinfo;
|
||||
int err = -EAFNOSUPPORT;
|
||||
|
||||
err = x->outer_mode->afinfo->extract_input(x, skb);
|
||||
if (err)
|
||||
rcu_read_lock();
|
||||
afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
|
||||
if (likely(afinfo))
|
||||
err = afinfo->extract_input(x, skb);
|
||||
|
||||
if (err) {
|
||||
rcu_read_unlock();
|
||||
return err;
|
||||
}
|
||||
|
||||
if (x->sel.family == AF_UNSPEC) {
|
||||
inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
|
||||
if (inner_mode == NULL)
|
||||
if (!inner_mode) {
|
||||
rcu_read_unlock();
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
}
|
||||
|
||||
skb->protocol = inner_mode->afinfo->eth_proto;
|
||||
afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
|
||||
if (unlikely(!afinfo)) {
|
||||
rcu_read_unlock();
|
||||
return -EAFNOSUPPORT;
|
||||
}
|
||||
|
||||
skb->protocol = afinfo->eth_proto;
|
||||
rcu_read_unlock();
|
||||
return xfrm_inner_mode_encap_remove(x, inner_mode, skb);
|
||||
}
|
||||
|
||||
|
@ -440,6 +456,7 @@ static int xfrm_inner_mode_input(struct xfrm_state *x,
|
|||
|
||||
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
|
||||
{
|
||||
const struct xfrm_state_afinfo *afinfo;
|
||||
struct net *net = dev_net(skb->dev);
|
||||
int err;
|
||||
__be32 seq;
|
||||
|
@ -705,7 +722,12 @@ resume:
|
|||
if (xo)
|
||||
xfrm_gro = xo->flags & XFRM_GRO;
|
||||
|
||||
err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async);
|
||||
err = -EAFNOSUPPORT;
|
||||
rcu_read_lock();
|
||||
afinfo = xfrm_state_afinfo_get_rcu(x->inner_mode->family);
|
||||
if (likely(afinfo))
|
||||
err = afinfo->transport_finish(skb, xfrm_gro || async);
|
||||
rcu_read_unlock();
|
||||
if (xfrm_gro) {
|
||||
sp = skb_sec_path(skb);
|
||||
if (sp)
|
||||
|
|
|
@ -623,7 +623,10 @@ EXPORT_SYMBOL_GPL(xfrm_output);
|
|||
|
||||
static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
|
||||
{
|
||||
const struct xfrm_state_afinfo *afinfo;
|
||||
struct xfrm_mode *inner_mode;
|
||||
int err = -EAFNOSUPPORT;
|
||||
|
||||
if (x->sel.family == AF_UNSPEC)
|
||||
inner_mode = xfrm_ip2inner_mode(x,
|
||||
xfrm_af2proto(skb_dst(skb)->ops->family));
|
||||
|
@ -632,7 +635,14 @@ static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
|
|||
|
||||
if (inner_mode == NULL)
|
||||
return -EAFNOSUPPORT;
|
||||
return inner_mode->afinfo->extract_output(x, skb);
|
||||
|
||||
rcu_read_lock();
|
||||
afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
|
||||
if (likely(afinfo))
|
||||
err = afinfo->extract_output(x, skb);
|
||||
rcu_read_unlock();
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
void xfrm_local_error(struct sk_buff *skb, int mtu)
|
||||
|
|
|
@ -2545,6 +2545,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
|||
const struct flowi *fl,
|
||||
struct dst_entry *dst)
|
||||
{
|
||||
const struct xfrm_state_afinfo *afinfo;
|
||||
struct net *net = xp_net(policy);
|
||||
unsigned long now = jiffies;
|
||||
struct net_device *dev;
|
||||
|
@ -2622,7 +2623,14 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
|
|||
dst1->lastuse = now;
|
||||
|
||||
dst1->input = dst_discard;
|
||||
dst1->output = inner_mode->afinfo->output;
|
||||
|
||||
rcu_read_lock();
|
||||
afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
|
||||
if (likely(afinfo))
|
||||
dst1->output = afinfo->output;
|
||||
else
|
||||
dst1->output = dst_discard_out;
|
||||
rcu_read_unlock();
|
||||
|
||||
xdst_prev = xdst;
|
||||
|
||||
|
|
|
@ -354,7 +354,6 @@ int xfrm_register_mode(struct xfrm_mode *mode)
|
|||
if (!try_module_get(afinfo->owner))
|
||||
goto out;
|
||||
|
||||
mode->afinfo = afinfo;
|
||||
modemap[mode->encap] = mode;
|
||||
err = 0;
|
||||
|
||||
|
@ -378,7 +377,7 @@ void xfrm_unregister_mode(struct xfrm_mode *mode)
|
|||
spin_lock_bh(&xfrm_mode_lock);
|
||||
if (likely(modemap[mode->encap] == mode)) {
|
||||
modemap[mode->encap] = NULL;
|
||||
module_put(mode->afinfo->owner);
|
||||
module_put(afinfo->owner);
|
||||
}
|
||||
|
||||
spin_unlock_bh(&xfrm_mode_lock);
|
||||
|
@ -2188,6 +2187,7 @@ struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family)
|
|||
|
||||
return rcu_dereference(xfrm_state_afinfo[family]);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu);
|
||||
|
||||
struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
|
||||
{
|
||||
|
|
Loading…
Reference in New Issue