Skip to content

Commit 8571ab4

Browse files
Yuval Mintzdavem330
authored andcommitted
ip6mr: Make mroute_sk rcu-based
In ipmr the mr_table socket is handled under RCU. Introduce the same for ip6mr. Signed-off-by: Yuval Mintz <[email protected]> Acked-by: Nikolay Aleksandrov <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 6853f21 commit 8571ab4

File tree

3 files changed

+31
-22
lines changed

3 files changed

+31
-22
lines changed

include/linux/mroute6.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,12 @@ extern int ip6mr_get_route(struct net *net, struct sk_buff *skb,
111111
struct rtmsg *rtm, u32 portid);
112112

113113
#ifdef CONFIG_IPV6_MROUTE
114-
extern struct sock *mroute6_socket(struct net *net, struct sk_buff *skb);
114+
bool mroute6_is_socket(struct net *net, struct sk_buff *skb);
115115
extern int ip6mr_sk_done(struct sock *sk);
116116
#else
117-
static inline struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
117+
static inline bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
118118
{
119-
return NULL;
119+
return false;
120120
}
121121
static inline int ip6mr_sk_done(struct sock *sk)
122122
{

net/ipv6/ip6_output.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ static int ip6_finish_output2(struct net *net, struct sock *sk, struct sk_buff *
7171
struct inet6_dev *idev = ip6_dst_idev(skb_dst(skb));
7272

7373
if (!(dev->flags & IFF_LOOPBACK) && sk_mc_loop(sk) &&
74-
((mroute6_socket(net, skb) &&
74+
((mroute6_is_socket(net, skb) &&
7575
!(IP6CB(skb)->flags & IP6SKB_FORWARDED)) ||
7676
ipv6_chk_mcast_addr(dev, &ipv6_hdr(skb)->daddr,
7777
&ipv6_hdr(skb)->saddr))) {

net/ipv6/ip6mr.c

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ struct mr6_table {
5858
struct list_head list;
5959
possible_net_t net;
6060
u32 id;
61-
struct sock *mroute6_sk;
61+
struct sock __rcu *mroute6_sk;
6262
struct timer_list ipmr_expire_timer;
6363
struct list_head mfc6_unres_queue;
6464
struct list_head mfc6_cache_array[MFC6_LINES];
@@ -1121,6 +1121,7 @@ static void ip6mr_cache_resolve(struct net *net, struct mr6_table *mrt,
11211121
static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
11221122
mifi_t mifi, int assert)
11231123
{
1124+
struct sock *mroute6_sk;
11241125
struct sk_buff *skb;
11251126
struct mrt6msg *msg;
11261127
int ret;
@@ -1190,17 +1191,19 @@ static int ip6mr_cache_report(struct mr6_table *mrt, struct sk_buff *pkt,
11901191
skb->ip_summed = CHECKSUM_UNNECESSARY;
11911192
}
11921193

1193-
if (!mrt->mroute6_sk) {
1194+
rcu_read_lock();
1195+
mroute6_sk = rcu_dereference(mrt->mroute6_sk);
1196+
if (!mroute6_sk) {
1197+
rcu_read_unlock();
11941198
kfree_skb(skb);
11951199
return -EINVAL;
11961200
}
11971201

11981202
mrt6msg_netlink_event(mrt, skb);
11991203

1200-
/*
1201-
* Deliver to user space multicast routing algorithms
1202-
*/
1203-
ret = sock_queue_rcv_skb(mrt->mroute6_sk, skb);
1204+
/* Deliver to user space multicast routing algorithms */
1205+
ret = sock_queue_rcv_skb(mroute6_sk, skb);
1206+
rcu_read_unlock();
12041207
if (ret < 0) {
12051208
net_warn_ratelimited("mroute6: pending queue full, dropping entries\n");
12061209
kfree_skb(skb);
@@ -1584,11 +1587,11 @@ static int ip6mr_sk_init(struct mr6_table *mrt, struct sock *sk)
15841587

15851588
rtnl_lock();
15861589
write_lock_bh(&mrt_lock);
1587-
if (likely(mrt->mroute6_sk == NULL)) {
1588-
mrt->mroute6_sk = sk;
1589-
net->ipv6.devconf_all->mc_forwarding++;
1590-
} else {
1590+
if (rtnl_dereference(mrt->mroute6_sk)) {
15911591
err = -EADDRINUSE;
1592+
} else {
1593+
rcu_assign_pointer(mrt->mroute6_sk, sk);
1594+
net->ipv6.devconf_all->mc_forwarding++;
15921595
}
15931596
write_unlock_bh(&mrt_lock);
15941597

@@ -1614,9 +1617,9 @@ int ip6mr_sk_done(struct sock *sk)
16141617

16151618
rtnl_lock();
16161619
ip6mr_for_each_table(mrt, net) {
1617-
if (sk == mrt->mroute6_sk) {
1620+
if (sk == rtnl_dereference(mrt->mroute6_sk)) {
16181621
write_lock_bh(&mrt_lock);
1619-
mrt->mroute6_sk = NULL;
1622+
RCU_INIT_POINTER(mrt->mroute6_sk, NULL);
16201623
net->ipv6.devconf_all->mc_forwarding--;
16211624
write_unlock_bh(&mrt_lock);
16221625
inet6_netconf_notify_devconf(net, RTM_NEWNETCONF,
@@ -1630,11 +1633,12 @@ int ip6mr_sk_done(struct sock *sk)
16301633
}
16311634
}
16321635
rtnl_unlock();
1636+
synchronize_rcu();
16331637

16341638
return err;
16351639
}
16361640

1637-
struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
1641+
bool mroute6_is_socket(struct net *net, struct sk_buff *skb)
16381642
{
16391643
struct mr6_table *mrt;
16401644
struct flowi6 fl6 = {
@@ -1646,8 +1650,9 @@ struct sock *mroute6_socket(struct net *net, struct sk_buff *skb)
16461650
if (ip6mr_fib_lookup(net, &fl6, &mrt) < 0)
16471651
return NULL;
16481652

1649-
return mrt->mroute6_sk;
1653+
return rcu_access_pointer(mrt->mroute6_sk);
16501654
}
1655+
EXPORT_SYMBOL(mroute6_is_socket);
16511656

16521657
/*
16531658
* Socket options and virtual interface manipulation. The whole
@@ -1674,7 +1679,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
16741679
return -ENOENT;
16751680

16761681
if (optname != MRT6_INIT) {
1677-
if (sk != mrt->mroute6_sk && !ns_capable(net->user_ns, CAP_NET_ADMIN))
1682+
if (sk != rcu_access_pointer(mrt->mroute6_sk) &&
1683+
!ns_capable(net->user_ns, CAP_NET_ADMIN))
16781684
return -EACCES;
16791685
}
16801686

@@ -1696,7 +1702,8 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
16961702
if (vif.mif6c_mifi >= MAXMIFS)
16971703
return -ENFILE;
16981704
rtnl_lock();
1699-
ret = mif6_add(net, mrt, &vif, sk == mrt->mroute6_sk);
1705+
ret = mif6_add(net, mrt, &vif,
1706+
sk == rtnl_dereference(mrt->mroute6_sk));
17001707
rtnl_unlock();
17011708
return ret;
17021709

@@ -1731,7 +1738,9 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
17311738
ret = ip6mr_mfc_delete(mrt, &mfc, parent);
17321739
else
17331740
ret = ip6mr_mfc_add(net, mrt, &mfc,
1734-
sk == mrt->mroute6_sk, parent);
1741+
sk ==
1742+
rtnl_dereference(mrt->mroute6_sk),
1743+
parent);
17351744
rtnl_unlock();
17361745
return ret;
17371746

@@ -1783,7 +1792,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, uns
17831792
/* "pim6reg%u" should not exceed 16 bytes (IFNAMSIZ) */
17841793
if (v != RT_TABLE_DEFAULT && v >= 100000000)
17851794
return -EINVAL;
1786-
if (sk == mrt->mroute6_sk)
1795+
if (sk == rcu_access_pointer(mrt->mroute6_sk))
17871796
return -EBUSY;
17881797

17891798
rtnl_lock();

0 commit comments

Comments
 (0)