Commit 733a5fac authored by Florian Westphal's avatar Florian Westphal Committed by Steffen Klassert

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: default avatarFlorian Westphal <fw@strlen.de>
Reviewed-by: default avatarSabrina Dubroca <sd@queasysnail.net>
Signed-off-by: default avatarSteffen Klassert <steffen.klassert@secunet.com>
parent 1de70830
...@@ -423,7 +423,6 @@ int xfrm_register_type_offload(const struct xfrm_type_offload *type, unsigned sh ...@@ -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); int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family);
struct xfrm_mode { struct xfrm_mode {
struct xfrm_state_afinfo *afinfo;
struct module *owner; struct module *owner;
u8 encap; u8 encap;
u8 family; u8 family;
......
...@@ -72,6 +72,8 @@ int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb) ...@@ -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) static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
{ {
struct xfrm_state *x = skb_dst(skb)->xfrm; struct xfrm_state *x = skb_dst(skb)->xfrm;
const struct xfrm_state_afinfo *afinfo;
int ret = -EAFNOSUPPORT;
#ifdef CONFIG_NETFILTER #ifdef CONFIG_NETFILTER
if (!x) { if (!x) {
...@@ -80,7 +82,15 @@ static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb) ...@@ -80,7 +82,15 @@ static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
} }
#endif #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) 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) ...@@ -122,11 +122,28 @@ int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb)
return xfrm_output(sk, 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) static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
{ {
struct xfrm_state *x = skb_dst(skb)->xfrm; 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) 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) ...@@ -168,7 +185,7 @@ static int __xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)
__xfrm6_output_finish); __xfrm6_output_finish);
skip_frag: 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) 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, ...@@ -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) static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
{ {
struct xfrm_mode *inner_mode = x->inner_mode; 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); rcu_read_lock();
if (err) 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; return err;
}
if (x->sel.family == AF_UNSPEC) { if (x->sel.family == AF_UNSPEC) {
inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol); inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
if (inner_mode == NULL) if (!inner_mode) {
rcu_read_unlock();
return -EAFNOSUPPORT; 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); return xfrm_inner_mode_encap_remove(x, inner_mode, skb);
} }
...@@ -440,6 +456,7 @@ static int xfrm_inner_mode_input(struct xfrm_state *x, ...@@ -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) 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); struct net *net = dev_net(skb->dev);
int err; int err;
__be32 seq; __be32 seq;
...@@ -705,7 +722,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type) ...@@ -705,7 +722,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
if (xo) if (xo)
xfrm_gro = xo->flags & XFRM_GRO; 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) { if (xfrm_gro) {
sp = skb_sec_path(skb); sp = skb_sec_path(skb);
if (sp) if (sp)
......
...@@ -623,7 +623,10 @@ EXPORT_SYMBOL_GPL(xfrm_output); ...@@ -623,7 +623,10 @@ EXPORT_SYMBOL_GPL(xfrm_output);
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;
struct xfrm_mode *inner_mode; struct xfrm_mode *inner_mode;
int err = -EAFNOSUPPORT;
if (x->sel.family == AF_UNSPEC) if (x->sel.family == AF_UNSPEC)
inner_mode = xfrm_ip2inner_mode(x, inner_mode = xfrm_ip2inner_mode(x,
xfrm_af2proto(skb_dst(skb)->ops->family)); 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) ...@@ -632,7 +635,14 @@ 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;
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) 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, ...@@ -2545,6 +2545,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
const struct flowi *fl, const struct flowi *fl,
struct dst_entry *dst) struct dst_entry *dst)
{ {
const struct xfrm_state_afinfo *afinfo;
struct net *net = xp_net(policy); struct net *net = xp_net(policy);
unsigned long now = jiffies; unsigned long now = jiffies;
struct net_device *dev; struct net_device *dev;
...@@ -2622,7 +2623,14 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy, ...@@ -2622,7 +2623,14 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
dst1->lastuse = now; dst1->lastuse = now;
dst1->input = dst_discard; 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; xdst_prev = xdst;
......
...@@ -354,7 +354,6 @@ int xfrm_register_mode(struct xfrm_mode *mode) ...@@ -354,7 +354,6 @@ int xfrm_register_mode(struct xfrm_mode *mode)
if (!try_module_get(afinfo->owner)) if (!try_module_get(afinfo->owner))
goto out; goto out;
mode->afinfo = afinfo;
modemap[mode->encap] = mode; modemap[mode->encap] = mode;
err = 0; err = 0;
...@@ -378,7 +377,7 @@ void xfrm_unregister_mode(struct xfrm_mode *mode) ...@@ -378,7 +377,7 @@ void xfrm_unregister_mode(struct xfrm_mode *mode)
spin_lock_bh(&xfrm_mode_lock); spin_lock_bh(&xfrm_mode_lock);
if (likely(modemap[mode->encap] == mode)) { if (likely(modemap[mode->encap] == mode)) {
modemap[mode->encap] = NULL; modemap[mode->encap] = NULL;
module_put(mode->afinfo->owner); module_put(afinfo->owner);
} }
spin_unlock_bh(&xfrm_mode_lock); spin_unlock_bh(&xfrm_mode_lock);
...@@ -2188,6 +2187,7 @@ struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family) ...@@ -2188,6 +2187,7 @@ struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family)
return rcu_dereference(xfrm_state_afinfo[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) struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
{ {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment