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