Skip to content

Commit 733a5fa

Browse files
Florian Westphalklassert
authored andcommitted
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>
1 parent 1de7083 commit 733a5fa

File tree

7 files changed

+80
-14
lines changed

7 files changed

+80
-14
lines changed

include/net/xfrm.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -423,7 +423,6 @@ int xfrm_register_type_offload(const struct xfrm_type_offload *type, unsigned sh
423423
int xfrm_unregister_type_offload(const struct xfrm_type_offload *type, unsigned short family);
424424

425425
struct xfrm_mode {
426-
struct xfrm_state_afinfo *afinfo;
427426
struct module *owner;
428427
u8 encap;
429428
u8 family;

net/ipv4/xfrm4_output.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,8 @@ int xfrm4_output_finish(struct sock *sk, struct sk_buff *skb)
7272
static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
7373
{
7474
struct xfrm_state *x = skb_dst(skb)->xfrm;
75+
const struct xfrm_state_afinfo *afinfo;
76+
int ret = -EAFNOSUPPORT;
7577

7678
#ifdef CONFIG_NETFILTER
7779
if (!x) {
@@ -80,7 +82,15 @@ static int __xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)
8082
}
8183
#endif
8284

83-
return x->outer_mode->afinfo->output_finish(sk, skb);
85+
rcu_read_lock();
86+
afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
87+
if (likely(afinfo))
88+
ret = afinfo->output_finish(sk, skb);
89+
else
90+
kfree_skb(skb);
91+
rcu_read_unlock();
92+
93+
return ret;
8494
}
8595

8696
int xfrm4_output(struct net *net, struct sock *sk, struct sk_buff *skb)

net/ipv6/xfrm6_output.c

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -122,11 +122,28 @@ int xfrm6_output_finish(struct sock *sk, struct sk_buff *skb)
122122
return xfrm_output(sk, skb);
123123
}
124124

125+
static int __xfrm6_output_state_finish(struct xfrm_state *x, struct sock *sk,
126+
struct sk_buff *skb)
127+
{
128+
const struct xfrm_state_afinfo *afinfo;
129+
int ret = -EAFNOSUPPORT;
130+
131+
rcu_read_lock();
132+
afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
133+
if (likely(afinfo))
134+
ret = afinfo->output_finish(sk, skb);
135+
else
136+
kfree_skb(skb);
137+
rcu_read_unlock();
138+
139+
return ret;
140+
}
141+
125142
static int __xfrm6_output_finish(struct net *net, struct sock *sk, struct sk_buff *skb)
126143
{
127144
struct xfrm_state *x = skb_dst(skb)->xfrm;
128145

129-
return x->outer_mode->afinfo->output_finish(sk, skb);
146+
return __xfrm6_output_state_finish(x, sk, skb);
130147
}
131148

132149
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)
168185
__xfrm6_output_finish);
169186

170187
skip_frag:
171-
return x->outer_mode->afinfo->output_finish(sk, skb);
188+
return __xfrm6_output_state_finish(x, sk, skb);
172189
}
173190

174191
int xfrm6_output(struct net *net, struct sock *sk, struct sk_buff *skb)

net/xfrm/xfrm_input.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -352,19 +352,35 @@ xfrm_inner_mode_encap_remove(struct xfrm_state *x,
352352
static int xfrm_prepare_input(struct xfrm_state *x, struct sk_buff *skb)
353353
{
354354
struct xfrm_mode *inner_mode = x->inner_mode;
355-
int err;
355+
const struct xfrm_state_afinfo *afinfo;
356+
int err = -EAFNOSUPPORT;
356357

357-
err = x->outer_mode->afinfo->extract_input(x, skb);
358-
if (err)
358+
rcu_read_lock();
359+
afinfo = xfrm_state_afinfo_get_rcu(x->outer_mode->family);
360+
if (likely(afinfo))
361+
err = afinfo->extract_input(x, skb);
362+
363+
if (err) {
364+
rcu_read_unlock();
359365
return err;
366+
}
360367

361368
if (x->sel.family == AF_UNSPEC) {
362369
inner_mode = xfrm_ip2inner_mode(x, XFRM_MODE_SKB_CB(skb)->protocol);
363-
if (inner_mode == NULL)
370+
if (!inner_mode) {
371+
rcu_read_unlock();
364372
return -EAFNOSUPPORT;
373+
}
365374
}
366375

367-
skb->protocol = inner_mode->afinfo->eth_proto;
376+
afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
377+
if (unlikely(!afinfo)) {
378+
rcu_read_unlock();
379+
return -EAFNOSUPPORT;
380+
}
381+
382+
skb->protocol = afinfo->eth_proto;
383+
rcu_read_unlock();
368384
return xfrm_inner_mode_encap_remove(x, inner_mode, skb);
369385
}
370386

@@ -440,6 +456,7 @@ static int xfrm_inner_mode_input(struct xfrm_state *x,
440456

441457
int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
442458
{
459+
const struct xfrm_state_afinfo *afinfo;
443460
struct net *net = dev_net(skb->dev);
444461
int err;
445462
__be32 seq;
@@ -705,7 +722,12 @@ int xfrm_input(struct sk_buff *skb, int nexthdr, __be32 spi, int encap_type)
705722
if (xo)
706723
xfrm_gro = xo->flags & XFRM_GRO;
707724

708-
err = x->inner_mode->afinfo->transport_finish(skb, xfrm_gro || async);
725+
err = -EAFNOSUPPORT;
726+
rcu_read_lock();
727+
afinfo = xfrm_state_afinfo_get_rcu(x->inner_mode->family);
728+
if (likely(afinfo))
729+
err = afinfo->transport_finish(skb, xfrm_gro || async);
730+
rcu_read_unlock();
709731
if (xfrm_gro) {
710732
sp = skb_sec_path(skb);
711733
if (sp)

net/xfrm/xfrm_output.c

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -623,7 +623,10 @@ EXPORT_SYMBOL_GPL(xfrm_output);
623623

624624
static int xfrm_inner_extract_output(struct xfrm_state *x, struct sk_buff *skb)
625625
{
626+
const struct xfrm_state_afinfo *afinfo;
626627
struct xfrm_mode *inner_mode;
628+
int err = -EAFNOSUPPORT;
629+
627630
if (x->sel.family == AF_UNSPEC)
628631
inner_mode = xfrm_ip2inner_mode(x,
629632
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)
632635

633636
if (inner_mode == NULL)
634637
return -EAFNOSUPPORT;
635-
return inner_mode->afinfo->extract_output(x, skb);
638+
639+
rcu_read_lock();
640+
afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
641+
if (likely(afinfo))
642+
err = afinfo->extract_output(x, skb);
643+
rcu_read_unlock();
644+
645+
return err;
636646
}
637647

638648
void xfrm_local_error(struct sk_buff *skb, int mtu)

net/xfrm/xfrm_policy.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2545,6 +2545,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
25452545
const struct flowi *fl,
25462546
struct dst_entry *dst)
25472547
{
2548+
const struct xfrm_state_afinfo *afinfo;
25482549
struct net *net = xp_net(policy);
25492550
unsigned long now = jiffies;
25502551
struct net_device *dev;
@@ -2622,7 +2623,14 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
26222623
dst1->lastuse = now;
26232624

26242625
dst1->input = dst_discard;
2625-
dst1->output = inner_mode->afinfo->output;
2626+
2627+
rcu_read_lock();
2628+
afinfo = xfrm_state_afinfo_get_rcu(inner_mode->family);
2629+
if (likely(afinfo))
2630+
dst1->output = afinfo->output;
2631+
else
2632+
dst1->output = dst_discard_out;
2633+
rcu_read_unlock();
26262634

26272635
xdst_prev = xdst;
26282636

net/xfrm/xfrm_state.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -354,7 +354,6 @@ int xfrm_register_mode(struct xfrm_mode *mode)
354354
if (!try_module_get(afinfo->owner))
355355
goto out;
356356

357-
mode->afinfo = afinfo;
358357
modemap[mode->encap] = mode;
359358
err = 0;
360359

@@ -378,7 +377,7 @@ void xfrm_unregister_mode(struct xfrm_mode *mode)
378377
spin_lock_bh(&xfrm_mode_lock);
379378
if (likely(modemap[mode->encap] == mode)) {
380379
modemap[mode->encap] = NULL;
381-
module_put(mode->afinfo->owner);
380+
module_put(afinfo->owner);
382381
}
383382

384383
spin_unlock_bh(&xfrm_mode_lock);
@@ -2188,6 +2187,7 @@ struct xfrm_state_afinfo *xfrm_state_afinfo_get_rcu(unsigned int family)
21882187

21892188
return rcu_dereference(xfrm_state_afinfo[family]);
21902189
}
2190+
EXPORT_SYMBOL_GPL(xfrm_state_afinfo_get_rcu);
21912191

21922192
struct xfrm_state_afinfo *xfrm_state_get_afinfo(unsigned int family)
21932193
{

0 commit comments

Comments
 (0)