// SPDX-License-Identifier: GPL-2.0-or-later /* * Anycast support for IPv6 * Linux INET6 implementation * * Authors: * David L Stevens (dlstevens@us.ibm.com) * * based heavily on net/ipv6/mcast.c
*/
rcu_read_lock();
rt = rt6_lookup(net, addr, NULL, 0, NULL, 0); if (rt) {
dev = dst_dev_rcu(&rt->dst);
netdev_hold(dev, &dev_tracker, GFP_ATOMIC);
ip6_rt_put(rt);
} elseif (ishost) {
rcu_read_unlock();
err = -EADDRNOTAVAIL; goto error;
} else { /* router, no matching interface: just pick one */
dev = netdev_get_by_flags_rcu(net, &dev_tracker, IFF_UP,
IFF_UP | IFF_LOOPBACK);
}
rcu_read_unlock();
}
if (!dev) {
err = -ENODEV; goto error;
}
idev = in6_dev_get(dev); if (!idev) { if (ifindex)
err = -ENODEV; else
err = -EADDRNOTAVAIL; goto error;
}
/* reset ishost, now that we have a specific device */
ishost = !READ_ONCE(idev->cnf.forwarding);
pac->acl_ifindex = dev->ifindex;
/* XXX * For hosts, allow link-local or matching prefix anycasts. * This obviates the need for propagating anycast routes while * still allowing some non-router anycast participation.
*/ if (!ipv6_chk_prefix(addr, dev)) { if (ishost)
err = -EADDRNOTAVAIL; if (err) goto error_idev;
}
/* * device anycast group inc (add if not found)
*/ int __ipv6_dev_ac_inc(struct inet6_dev *idev, conststruct in6_addr *addr)
{ struct ifacaddr6 *aca; struct fib6_info *f6i; struct net *net; int err;
write_lock_bh(&idev->lock); if (idev->dead) {
err = -ENODEV; goto out;
}
/* Hold this for addrconf_join_solict() below before we unlock, * it is already exposed via idev->ac_list.
*/
aca_get(aca);
aca->aca_next = idev->ac_list;
rcu_assign_pointer(idev->ac_list, aca);
/* * check if the interface has this anycast address * called with rcu_read_lock()
*/ staticbool ipv6_chk_acast_dev(struct net_device *dev, conststruct in6_addr *addr)
{ struct inet6_dev *idev; struct ifacaddr6 *aca;
idev = __in6_dev_get(dev); if (idev) { for (aca = rcu_dereference(idev->ac_list); aca;
aca = rcu_dereference(aca->aca_next)) if (ipv6_addr_equal(&aca->aca_addr, addr)) break; return aca != NULL;
} returnfalse;
}
/* * check if given interface (or any, if dev==0) has this anycast address
*/ bool ipv6_chk_acast_addr(struct net *net, struct net_device *dev, conststruct in6_addr *addr)
{ struct net_device *nh_dev; struct ifacaddr6 *aca; bool found = false;
rcu_read_lock(); if (dev)
found = ipv6_chk_acast_dev(dev, addr); else { unsignedint hash = inet6_acaddr_hash(net, addr);
hlist_for_each_entry_rcu(aca, &inet6_acaddr_lst[hash],
aca_addr_lst) {
nh_dev = fib6_info_nh_dev(aca->aca_rt); if (!nh_dev || !net_eq(dev_net(nh_dev), net)) continue; if (ipv6_addr_equal(&aca->aca_addr, addr)) {
found = true; break;
}
}
}
rcu_read_unlock(); return found;
}
/* check if this anycast address is link-local on given interface or * is global
*/ bool ipv6_chk_acast_addr_src(struct net *net, struct net_device *dev, conststruct in6_addr *addr)
{ return ipv6_chk_acast_addr(net,
(ipv6_addr_type(addr) & IPV6_ADDR_LINKLOCAL ?
dev : NULL),
addr);
}
im = rcu_dereference(im->aca_next); while (!im) {
state->dev = next_net_device_rcu(state->dev); if (!state->dev) break;
idev = __in6_dev_get(state->dev); if (!idev) continue;
im = rcu_dereference(idev->ac_list);
} return im;
}
int __net_init ac6_proc_init(struct net *net)
{ if (!proc_create_net("anycast6", 0444, net->proc_net, &ac6_seq_ops, sizeof(struct ac6_iter_state))) return -ENOMEM;
return 0;
}
void ac6_proc_exit(struct net *net)
{
remove_proc_entry("anycast6", net->proc_net);
} #endif
/* Init / cleanup code
*/ int __init ipv6_anycast_init(void)
{ int i;
for (i = 0; i < IN6_ADDR_HSIZE; i++)
INIT_HLIST_HEAD(&inet6_acaddr_lst[i]); return 0;
}
void ipv6_anycast_cleanup(void)
{ int i;
spin_lock(&acaddr_hash_lock); for (i = 0; i < IN6_ADDR_HSIZE; i++)
WARN_ON(!hlist_empty(&inet6_acaddr_lst[i]));
spin_unlock(&acaddr_hash_lock);
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.