[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <20190327173140.16891-10-fw@strlen.de>
Date: Wed, 27 Mar 2019 18:31:38 +0100
From: Florian Westphal <fw@...len.de>
To: <netdev@...r.kernel.org>
Cc: steffen.klassert@...unet.com, Florian Westphal <fw@...len.de>
Subject: [PATCH ipsec-next 09/11] 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.
Signed-off-by: Florian Westphal <fw@...len.de>
---
include/net/xfrm.h | 1 -
net/ipv4/xfrm4_output.c | 11 ++++++++++-
net/ipv6/xfrm6_output.c | 21 +++++++++++++++++++--
net/xfrm/xfrm_input.c | 28 ++++++++++++++++++++++------
net/xfrm/xfrm_output.c | 12 +++++++++++-
net/xfrm/xfrm_policy.c | 7 ++++++-
net/xfrm/xfrm_state.c | 4 ++--
7 files changed, 70 insertions(+), 14 deletions(-)
diff --git a/include/net/xfrm.h b/include/net/xfrm.h
index 6249d44997e0..bbce45f5ca6d 100644
--- a/include/net/xfrm.h
+++ b/include/net/xfrm.h
@@ -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;
diff --git a/net/ipv4/xfrm4_output.c b/net/ipv4/xfrm4_output.c
index 6802d1aee424..cff048ad8562 100644
--- a/net/ipv4/xfrm4_output.c
+++ b/net/ipv4/xfrm4_output.c
@@ -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,14 @@ 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 (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)
diff --git a/net/ipv6/xfrm6_output.c b/net/ipv6/xfrm6_output.c
index 2b663d2ffdcd..82168de60e6b 100644
--- a/net/ipv6/xfrm6_output.c
+++ b/net/ipv6/xfrm6_output.c
@@ -122,11 +122,27 @@ 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 (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 +184,8 @@ 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)
diff --git a/net/xfrm/xfrm_input.c b/net/xfrm/xfrm_input.c
index 065ace68b26a..a6db51cee1cf 100644
--- a/net/xfrm/xfrm_input.c
+++ b/net/xfrm/xfrm_input.c
@@ -350,19 +350,29 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x, struct sk_buff *skb)
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 (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;
+ skb->protocol = afinfo->eth_proto;
+ rcu_read_unlock();
return xfrm_inner_mode_encap_remove(x, skb);
}
EXPORT_SYMBOL(xfrm_prepare_input);
@@ -437,6 +447,7 @@ static int xfrm_inner_mode_input(struct xfrm_state *x, struct sk_buff *skb)
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;
@@ -702,7 +713,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
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 (afinfo)
+ err = afinfo->transport_finish(skb, xfrm_gro || async);
+ rcu_read_unlock();
if (xfrm_gro) {
sp = skb_sec_path(skb);
if (sp)
diff --git a/net/xfrm/xfrm_output.c b/net/xfrm/xfrm_output.c
index 1174c7babcce..3e4b3fdf34a4 100644
--- a/net/xfrm/xfrm_output.c
+++ b/net/xfrm/xfrm_output.c
@@ -611,7 +611,10 @@ EXPORT_SYMBOL_GPL(xfrm_output);
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));
@@ -620,7 +623,14 @@ 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 (afinfo)
+ err = afinfo->extract_output(x, skb);
+ rcu_read_unlock();
+
+ return err;
}
EXPORT_SYMBOL_GPL(xfrm_inner_extract_output);
diff --git a/net/xfrm/xfrm_policy.c b/net/xfrm/xfrm_policy.c
index 8d1a898d0ba5..e82e022182ae 100644
--- a/net/xfrm/xfrm_policy.c
+++ b/net/xfrm/xfrm_policy.c
@@ -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,11 @@ 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);
+ dst1->output = afinfo ? afinfo->output : dst_discard_out;
+ rcu_read_unlock();
xdst_prev = xdst;
diff --git a/net/xfrm/xfrm_state.c b/net/xfrm/xfrm_state.c
index c32394b59776..358b09f0d018 100644
--- a/net/xfrm/xfrm_state.c
+++ b/net/xfrm/xfrm_state.c
@@ -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)
{
--
2.19.2
Powered by blists - more mailing lists