Skip to content

Commit 56ef9c9

Browse files
marceloleitnerdavem330
authored andcommitted
vxlan: Move socket initialization to within rtnl scope
Currently, if a multicast join operation fail, the vxlan interface will be UP but not functional, without even a log message informing the user. Now that we can grab socket lock after already having rntl, we don't need to defer socket creation and multicast operations. By not deferring we can do proper error reporting to the user through ip exit code. This patch thus removes all deferred work that vxlan had and put it back inline. Now the socket will only be created, bound and join multicast group when one bring the interface up, and will undo all that as soon as one put the interface down. As vxlan_sock_hold() is not used after this patch, it was removed too. Signed-off-by: Marcelo Ricardo Leitner <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent 54ff9ef commit 56ef9c9

File tree

1 file changed

+51
-102
lines changed

1 file changed

+51
-102
lines changed

drivers/net/vxlan.c

Lines changed: 51 additions & 102 deletions
Original file line numberDiff line numberDiff line change
@@ -127,10 +127,6 @@ struct vxlan_dev {
127127
__u8 ttl;
128128
u32 flags; /* VXLAN_F_* in vxlan.h */
129129

130-
struct work_struct sock_work;
131-
struct work_struct igmp_join;
132-
struct work_struct igmp_leave;
133-
134130
unsigned long age_interval;
135131
struct timer_list age_timer;
136132
spinlock_t hash_lock;
@@ -144,8 +140,6 @@ struct vxlan_dev {
144140
static u32 vxlan_salt __read_mostly;
145141
static struct workqueue_struct *vxlan_wq;
146142

147-
static void vxlan_sock_work(struct work_struct *work);
148-
149143
#if IS_ENABLED(CONFIG_IPV6)
150144
static inline
151145
bool vxlan_addr_equal(const union vxlan_addr *a, const union vxlan_addr *b)
@@ -1072,11 +1066,6 @@ static bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev)
10721066
return false;
10731067
}
10741068

1075-
static void vxlan_sock_hold(struct vxlan_sock *vs)
1076-
{
1077-
atomic_inc(&vs->refcnt);
1078-
}
1079-
10801069
void vxlan_sock_release(struct vxlan_sock *vs)
10811070
{
10821071
struct sock *sk = vs->sock->sk;
@@ -1095,69 +1084,62 @@ void vxlan_sock_release(struct vxlan_sock *vs)
10951084
}
10961085
EXPORT_SYMBOL_GPL(vxlan_sock_release);
10971086

1098-
/* Callback to update multicast group membership when first VNI on
1087+
/* Update multicast group membership when first VNI on
10991088
* multicast asddress is brought up
11001089
*/
1101-
static void vxlan_igmp_join(struct work_struct *work)
1090+
static int vxlan_igmp_join(struct vxlan_dev *vxlan)
11021091
{
1103-
struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_join);
11041092
struct vxlan_sock *vs = vxlan->vn_sock;
11051093
struct sock *sk = vs->sock->sk;
11061094
union vxlan_addr *ip = &vxlan->default_dst.remote_ip;
11071095
int ifindex = vxlan->default_dst.remote_ifindex;
1096+
int ret;
11081097

1109-
rtnl_lock();
11101098
lock_sock(sk);
11111099
if (ip->sa.sa_family == AF_INET) {
11121100
struct ip_mreqn mreq = {
11131101
.imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr,
11141102
.imr_ifindex = ifindex,
11151103
};
11161104

1117-
ip_mc_join_group(sk, &mreq);
1105+
ret = ip_mc_join_group(sk, &mreq);
11181106
#if IS_ENABLED(CONFIG_IPV6)
11191107
} else {
1120-
ipv6_stub->ipv6_sock_mc_join(sk, ifindex,
1121-
&ip->sin6.sin6_addr);
1108+
ret = ipv6_stub->ipv6_sock_mc_join(sk, ifindex,
1109+
&ip->sin6.sin6_addr);
11221110
#endif
11231111
}
11241112
release_sock(sk);
1125-
rtnl_unlock();
11261113

1127-
vxlan_sock_release(vs);
1128-
dev_put(vxlan->dev);
1114+
return ret;
11291115
}
11301116

11311117
/* Inverse of vxlan_igmp_join when last VNI is brought down */
1132-
static void vxlan_igmp_leave(struct work_struct *work)
1118+
static int vxlan_igmp_leave(struct vxlan_dev *vxlan)
11331119
{
1134-
struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, igmp_leave);
11351120
struct vxlan_sock *vs = vxlan->vn_sock;
11361121
struct sock *sk = vs->sock->sk;
11371122
union vxlan_addr *ip = &vxlan->default_dst.remote_ip;
11381123
int ifindex = vxlan->default_dst.remote_ifindex;
1124+
int ret;
11391125

1140-
rtnl_lock();
11411126
lock_sock(sk);
11421127
if (ip->sa.sa_family == AF_INET) {
11431128
struct ip_mreqn mreq = {
11441129
.imr_multiaddr.s_addr = ip->sin.sin_addr.s_addr,
11451130
.imr_ifindex = ifindex,
11461131
};
11471132

1148-
ip_mc_leave_group(sk, &mreq);
1133+
ret = ip_mc_leave_group(sk, &mreq);
11491134
#if IS_ENABLED(CONFIG_IPV6)
11501135
} else {
1151-
ipv6_stub->ipv6_sock_mc_drop(sk, ifindex,
1152-
&ip->sin6.sin6_addr);
1136+
ret = ipv6_stub->ipv6_sock_mc_drop(sk, ifindex,
1137+
&ip->sin6.sin6_addr);
11531138
#endif
11541139
}
1155-
11561140
release_sock(sk);
1157-
rtnl_unlock();
11581141

1159-
vxlan_sock_release(vs);
1160-
dev_put(vxlan->dev);
1142+
return ret;
11611143
}
11621144

11631145
static struct vxlanhdr *vxlan_remcsum(struct sk_buff *skb, struct vxlanhdr *vh,
@@ -2178,37 +2160,22 @@ static void vxlan_cleanup(unsigned long arg)
21782160

21792161
static void vxlan_vs_add_dev(struct vxlan_sock *vs, struct vxlan_dev *vxlan)
21802162
{
2163+
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
21812164
__u32 vni = vxlan->default_dst.remote_vni;
21822165

21832166
vxlan->vn_sock = vs;
2167+
spin_lock(&vn->sock_lock);
21842168
hlist_add_head_rcu(&vxlan->hlist, vni_head(vs, vni));
2169+
spin_unlock(&vn->sock_lock);
21852170
}
21862171

21872172
/* Setup stats when device is created */
21882173
static int vxlan_init(struct net_device *dev)
21892174
{
2190-
struct vxlan_dev *vxlan = netdev_priv(dev);
2191-
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
2192-
struct vxlan_sock *vs;
2193-
bool ipv6 = vxlan->flags & VXLAN_F_IPV6;
2194-
21952175
dev->tstats = netdev_alloc_pcpu_stats(struct pcpu_sw_netstats);
21962176
if (!dev->tstats)
21972177
return -ENOMEM;
21982178

2199-
spin_lock(&vn->sock_lock);
2200-
vs = vxlan_find_sock(vxlan->net, ipv6 ? AF_INET6 : AF_INET,
2201-
vxlan->dst_port, vxlan->flags);
2202-
if (vs && atomic_add_unless(&vs->refcnt, 1, 0)) {
2203-
/* If we have a socket with same port already, reuse it */
2204-
vxlan_vs_add_dev(vs, vxlan);
2205-
} else {
2206-
/* otherwise make new socket outside of RTNL */
2207-
dev_hold(dev);
2208-
queue_work(vxlan_wq, &vxlan->sock_work);
2209-
}
2210-
spin_unlock(&vn->sock_lock);
2211-
22122179
return 0;
22132180
}
22142181

@@ -2226,35 +2193,38 @@ static void vxlan_fdb_delete_default(struct vxlan_dev *vxlan)
22262193
static void vxlan_uninit(struct net_device *dev)
22272194
{
22282195
struct vxlan_dev *vxlan = netdev_priv(dev);
2229-
struct vxlan_sock *vs = vxlan->vn_sock;
22302196

22312197
vxlan_fdb_delete_default(vxlan);
22322198

2233-
if (vs)
2234-
vxlan_sock_release(vs);
22352199
free_percpu(dev->tstats);
22362200
}
22372201

22382202
/* Start ageing timer and join group when device is brought up */
22392203
static int vxlan_open(struct net_device *dev)
22402204
{
22412205
struct vxlan_dev *vxlan = netdev_priv(dev);
2242-
struct vxlan_sock *vs = vxlan->vn_sock;
2206+
struct vxlan_sock *vs;
2207+
int ret = 0;
22432208

2244-
/* socket hasn't been created */
2245-
if (!vs)
2246-
return -ENOTCONN;
2209+
vs = vxlan_sock_add(vxlan->net, vxlan->dst_port, vxlan_rcv, NULL,
2210+
false, vxlan->flags);
2211+
if (IS_ERR(vs))
2212+
return PTR_ERR(vs);
2213+
2214+
vxlan_vs_add_dev(vs, vxlan);
22472215

22482216
if (vxlan_addr_multicast(&vxlan->default_dst.remote_ip)) {
2249-
vxlan_sock_hold(vs);
2250-
dev_hold(dev);
2251-
queue_work(vxlan_wq, &vxlan->igmp_join);
2217+
ret = vxlan_igmp_join(vxlan);
2218+
if (ret) {
2219+
vxlan_sock_release(vs);
2220+
return ret;
2221+
}
22522222
}
22532223

22542224
if (vxlan->age_interval)
22552225
mod_timer(&vxlan->age_timer, jiffies + FDB_AGE_INTERVAL);
22562226

2257-
return 0;
2227+
return ret;
22582228
}
22592229

22602230
/* Purge the forwarding table */
@@ -2282,19 +2252,21 @@ static int vxlan_stop(struct net_device *dev)
22822252
struct vxlan_dev *vxlan = netdev_priv(dev);
22832253
struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
22842254
struct vxlan_sock *vs = vxlan->vn_sock;
2255+
int ret = 0;
22852256

22862257
if (vs && vxlan_addr_multicast(&vxlan->default_dst.remote_ip) &&
22872258
!vxlan_group_used(vn, vxlan)) {
2288-
vxlan_sock_hold(vs);
2289-
dev_hold(dev);
2290-
queue_work(vxlan_wq, &vxlan->igmp_leave);
2259+
ret = vxlan_igmp_leave(vxlan);
2260+
if (ret)
2261+
return ret;
22912262
}
22922263

22932264
del_timer_sync(&vxlan->age_timer);
22942265

22952266
vxlan_flush(vxlan);
2267+
vxlan_sock_release(vs);
22962268

2297-
return 0;
2269+
return ret;
22982270
}
22992271

23002272
/* Stub, nothing needs to be done. */
@@ -2405,9 +2377,6 @@ static void vxlan_setup(struct net_device *dev)
24052377

24062378
INIT_LIST_HEAD(&vxlan->next);
24072379
spin_lock_init(&vxlan->hash_lock);
2408-
INIT_WORK(&vxlan->igmp_join, vxlan_igmp_join);
2409-
INIT_WORK(&vxlan->igmp_leave, vxlan_igmp_leave);
2410-
INIT_WORK(&vxlan->sock_work, vxlan_sock_work);
24112380

24122381
init_timer_deferrable(&vxlan->age_timer);
24132382
vxlan->age_timer.function = vxlan_cleanup;
@@ -2554,6 +2523,8 @@ static struct vxlan_sock *vxlan_socket_create(struct net *net, __be16 port,
25542523

25552524
sock = vxlan_create_sock(net, ipv6, port, flags);
25562525
if (IS_ERR(sock)) {
2526+
pr_info("Cannot bind port %d, err=%ld\n", ntohs(port),
2527+
PTR_ERR(sock));
25572528
kfree(vs);
25582529
return ERR_CAST(sock);
25592530
}
@@ -2593,45 +2564,23 @@ struct vxlan_sock *vxlan_sock_add(struct net *net, __be16 port,
25932564
struct vxlan_sock *vs;
25942565
bool ipv6 = flags & VXLAN_F_IPV6;
25952566

2596-
vs = vxlan_socket_create(net, port, rcv, data, flags);
2597-
if (!IS_ERR(vs))
2598-
return vs;
2599-
2600-
if (no_share) /* Return error if sharing is not allowed. */
2601-
return vs;
2602-
2603-
spin_lock(&vn->sock_lock);
2604-
vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port, flags);
2605-
if (vs && ((vs->rcv != rcv) ||
2606-
!atomic_add_unless(&vs->refcnt, 1, 0)))
2607-
vs = ERR_PTR(-EBUSY);
2608-
spin_unlock(&vn->sock_lock);
2609-
2610-
if (!vs)
2611-
vs = ERR_PTR(-EINVAL);
2567+
if (!no_share) {
2568+
spin_lock(&vn->sock_lock);
2569+
vs = vxlan_find_sock(net, ipv6 ? AF_INET6 : AF_INET, port,
2570+
flags);
2571+
if (vs && vs->rcv == rcv) {
2572+
if (!atomic_add_unless(&vs->refcnt, 1, 0))
2573+
vs = ERR_PTR(-EBUSY);
2574+
spin_unlock(&vn->sock_lock);
2575+
return vs;
2576+
}
2577+
spin_unlock(&vn->sock_lock);
2578+
}
26122579

2613-
return vs;
2580+
return vxlan_socket_create(net, port, rcv, data, flags);
26142581
}
26152582
EXPORT_SYMBOL_GPL(vxlan_sock_add);
26162583

2617-
/* Scheduled at device creation to bind to a socket */
2618-
static void vxlan_sock_work(struct work_struct *work)
2619-
{
2620-
struct vxlan_dev *vxlan = container_of(work, struct vxlan_dev, sock_work);
2621-
struct net *net = vxlan->net;
2622-
struct vxlan_net *vn = net_generic(net, vxlan_net_id);
2623-
__be16 port = vxlan->dst_port;
2624-
struct vxlan_sock *nvs;
2625-
2626-
nvs = vxlan_sock_add(net, port, vxlan_rcv, NULL, false, vxlan->flags);
2627-
spin_lock(&vn->sock_lock);
2628-
if (!IS_ERR(nvs))
2629-
vxlan_vs_add_dev(nvs, vxlan);
2630-
spin_unlock(&vn->sock_lock);
2631-
2632-
dev_put(vxlan->dev);
2633-
}
2634-
26352584
static int vxlan_newlink(struct net *src_net, struct net_device *dev,
26362585
struct nlattr *tb[], struct nlattr *data[])
26372586
{

0 commit comments

Comments
 (0)