xref: /linux/drivers/net/vxlan/vxlan_multicast.c (revision 7e9e6844befcbbed3b576c16e75d5348639774ff)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  *	Vxlan multicast group handling
4  *
5  */
6 #include <linux/kernel.h>
7 #include <net/net_namespace.h>
8 #include <net/sock.h>
9 #include <linux/igmp.h>
10 #include <net/vxlan.h>
11 
12 #include "vxlan_private.h"
13 
14 /* Update multicast group membership when first VNI on
15  * multicast address is brought up
16  */
17 int vxlan_igmp_join(struct vxlan_dev *vxlan, const union vxlan_addr *rip,
18 		    int rifindex)
19 {
20 	const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
21 	const union vxlan_addr *ip = (rip ? : &cfg->remote_ip);
22 	int ifindex = (rifindex ? : cfg->remote_ifindex);
23 	int ret = -EINVAL;
24 	struct sock *sk;
25 
26 	if (ip->sa.sa_family == AF_INET) {
27 		struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
28 		struct ip_mreqn mreq = {
29 			.imr_multiaddr.s_addr	= ip->sin.sin_addr.s_addr,
30 			.imr_ifindex		= ifindex,
31 		};
32 
33 		sk = sock4->sk;
34 		lock_sock(sk);
35 		ret = ip_mc_join_group(sk, &mreq);
36 		release_sock(sk);
37 #if IS_ENABLED(CONFIG_IPV6)
38 	} else {
39 		struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
40 
41 		sk = sock6->sk;
42 		lock_sock(sk);
43 		ret = ipv6_sock_mc_join(sk, ifindex, &ip->sin6.sin6_addr);
44 		release_sock(sk);
45 #endif
46 	}
47 
48 	return ret;
49 }
50 
51 int vxlan_igmp_leave(struct vxlan_dev *vxlan, const union vxlan_addr *rip,
52 		     int rifindex)
53 {
54 	const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
55 	const union vxlan_addr *ip = (rip ? : &cfg->remote_ip);
56 	int ifindex = (rifindex ? : cfg->remote_ifindex);
57 	int ret = -EINVAL;
58 	struct sock *sk;
59 
60 	if (ip->sa.sa_family == AF_INET) {
61 		struct vxlan_sock *sock4 = rtnl_dereference(vxlan->vn4_sock);
62 		struct ip_mreqn mreq = {
63 			.imr_multiaddr.s_addr	= ip->sin.sin_addr.s_addr,
64 			.imr_ifindex		= ifindex,
65 		};
66 
67 		sk = sock4->sk;
68 		lock_sock(sk);
69 		ret = ip_mc_leave_group(sk, &mreq);
70 		release_sock(sk);
71 #if IS_ENABLED(CONFIG_IPV6)
72 	} else {
73 		struct vxlan_sock *sock6 = rtnl_dereference(vxlan->vn6_sock);
74 
75 		sk = sock6->sk;
76 		lock_sock(sk);
77 		ret = ipv6_sock_mc_drop(sk, ifindex, &ip->sin6.sin6_addr);
78 		release_sock(sk);
79 #endif
80 	}
81 
82 	return ret;
83 }
84 
85 static bool vxlan_group_used_match(const union vxlan_addr *ip, int ifindex,
86 				   const union vxlan_addr *rip, int rifindex)
87 {
88 	if (!vxlan_addr_multicast(rip))
89 		return false;
90 
91 	if (!vxlan_addr_equal(rip, ip))
92 		return false;
93 
94 	if (rifindex != ifindex)
95 		return false;
96 
97 	return true;
98 }
99 
100 static bool vxlan_group_used_by_vnifilter(struct vxlan_dev *vxlan,
101 					  const struct vxlan_config *cfg,
102 					  const union vxlan_addr *ip,
103 					  int ifindex)
104 {
105 	struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
106 	struct vxlan_vni_node *v, *tmp;
107 
108 	if (vxlan_group_used_match(ip, ifindex,
109 				   &cfg->remote_ip,
110 				   cfg->remote_ifindex))
111 		return true;
112 
113 	list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
114 		if (!vxlan_addr_multicast(&v->remote_ip))
115 			continue;
116 
117 		if (vxlan_group_used_match(ip, ifindex,
118 					   &v->remote_ip,
119 					   cfg->remote_ifindex))
120 			return true;
121 	}
122 
123 	return false;
124 }
125 
126 /* See if multicast group is already in use by other ID */
127 bool vxlan_group_used(struct vxlan_net *vn, struct vxlan_dev *dev,
128 		      __be32 vni, const union vxlan_addr *rip, int rifindex)
129 {
130 	const struct vxlan_config *dev_cfg = rtnl_dereference(dev->cfg);
131 	const union vxlan_addr *ip = (rip ? : &dev_cfg->remote_ip);
132 	int ifindex = (rifindex ? : dev_cfg->remote_ifindex);
133 	struct vxlan_dev *vxlan;
134 	struct vxlan_sock *sock4;
135 #if IS_ENABLED(CONFIG_IPV6)
136 	struct vxlan_sock *sock6;
137 #endif
138 	unsigned short family = dev_cfg->remote_ip.sa.sa_family;
139 
140 	sock4 = rtnl_dereference(dev->vn4_sock);
141 
142 	/* The vxlan_sock is only used by dev, leaving group has
143 	 * no effect on other vxlan devices.
144 	 */
145 	if (family == AF_INET && sock4 && refcount_read(&sock4->refcnt) == 1)
146 		return false;
147 
148 #if IS_ENABLED(CONFIG_IPV6)
149 	sock6 = rtnl_dereference(dev->vn6_sock);
150 	if (family == AF_INET6 && sock6 && refcount_read(&sock6->refcnt) == 1)
151 		return false;
152 #endif
153 
154 	list_for_each_entry(vxlan, &vn->vxlan_list, next) {
155 		const struct vxlan_config *cfg;
156 
157 		if (!netif_running(vxlan->dev) || vxlan == dev)
158 			continue;
159 
160 		if (family == AF_INET &&
161 		    rtnl_dereference(vxlan->vn4_sock) != sock4)
162 			continue;
163 #if IS_ENABLED(CONFIG_IPV6)
164 		if (family == AF_INET6 &&
165 		    rtnl_dereference(vxlan->vn6_sock) != sock6)
166 			continue;
167 #endif
168 		cfg = rtnl_dereference(vxlan->cfg);
169 
170 		if (cfg->flags & VXLAN_F_VNIFILTER) {
171 			if (!vxlan_group_used_by_vnifilter(vxlan, cfg, ip, ifindex))
172 				continue;
173 		} else {
174 			if (!vxlan_group_used_match(ip, ifindex,
175 						    &cfg->remote_ip,
176 						    cfg->remote_ifindex))
177 				continue;
178 		}
179 
180 		return true;
181 	}
182 
183 	return false;
184 }
185 
186 static int vxlan_multicast_join_vnigrp(struct vxlan_dev *vxlan,
187 				       const struct vxlan_config *cfg)
188 {
189 	struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
190 	struct vxlan_vni_node *v, *tmp, *vgood = NULL;
191 	int ret = 0;
192 
193 	list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
194 		if (!vxlan_addr_multicast(&v->remote_ip))
195 			continue;
196 		/* skip if address is same as default address */
197 		if (vxlan_addr_equal(&v->remote_ip,
198 				     &cfg->remote_ip))
199 			continue;
200 		ret = vxlan_igmp_join(vxlan, &v->remote_ip, 0);
201 		if (ret == -EADDRINUSE)
202 			ret = 0;
203 		if (ret)
204 			goto out;
205 		vgood = v;
206 	}
207 out:
208 	if (ret) {
209 		list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
210 			if (!vxlan_addr_multicast(&v->remote_ip))
211 				continue;
212 			if (vxlan_addr_equal(&v->remote_ip,
213 					     &cfg->remote_ip))
214 				continue;
215 			vxlan_igmp_leave(vxlan, &v->remote_ip, 0);
216 			if (v == vgood)
217 				break;
218 		}
219 	}
220 
221 	return ret;
222 }
223 
224 static int vxlan_multicast_leave_vnigrp(struct vxlan_dev *vxlan,
225 					const struct vxlan_config *cfg)
226 {
227 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
228 	struct vxlan_vni_group *vg = rtnl_dereference(vxlan->vnigrp);
229 	struct vxlan_vni_node *v, *tmp;
230 	int last_err = 0, ret;
231 
232 	list_for_each_entry_safe(v, tmp, &vg->vni_list, vlist) {
233 		if (!vxlan_addr_multicast(&v->remote_ip))
234 			continue;
235 		/* skip if address is same as default address */
236 		if (vxlan_addr_equal(&v->remote_ip,
237 				     &cfg->remote_ip))
238 			continue;
239 		if (!vxlan_group_used(vn, vxlan, v->vni, &v->remote_ip,
240 				      0)) {
241 			ret = vxlan_igmp_leave(vxlan, &v->remote_ip, 0);
242 			if (ret == -EADDRNOTAVAIL)
243 				ret = 0;
244 			if (ret)
245 				last_err = ret;
246 		}
247 	}
248 
249 	return last_err;
250 }
251 
252 int vxlan_multicast_join(struct vxlan_dev *vxlan)
253 {
254 	const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
255 	int ret = 0;
256 
257 	if (vxlan_addr_multicast(&cfg->remote_ip)) {
258 		ret = vxlan_igmp_join(vxlan, &cfg->remote_ip,
259 				      cfg->remote_ifindex);
260 		if (ret == -EADDRINUSE)
261 			ret = 0;
262 		if (ret)
263 			return ret;
264 	}
265 
266 	if (cfg->flags & VXLAN_F_VNIFILTER)
267 		return vxlan_multicast_join_vnigrp(vxlan, cfg);
268 
269 	return 0;
270 }
271 
272 int vxlan_multicast_leave(struct vxlan_dev *vxlan)
273 {
274 	const struct vxlan_config *cfg = rtnl_dereference(vxlan->cfg);
275 	struct vxlan_net *vn = net_generic(vxlan->net, vxlan_net_id);
276 	int ret = 0;
277 
278 	if (vxlan_addr_multicast(&cfg->remote_ip) &&
279 	    !vxlan_group_used(vn, vxlan, 0, NULL, 0)) {
280 		ret = vxlan_igmp_leave(vxlan, &cfg->remote_ip,
281 				       cfg->remote_ifindex);
282 		if (ret == -EADDRNOTAVAIL)
283 			ret = 0;
284 		if (ret)
285 			return ret;
286 	}
287 
288 	if (cfg->flags & VXLAN_F_VNIFILTER)
289 		return vxlan_multicast_leave_vnigrp(vxlan, cfg);
290 
291 	return 0;
292 }
293