/* Check if link is ready: is it up and is a valid qdisc available */ staticinlinebool addrconf_link_ready(conststruct net_device *dev)
{ return netif_oper_up(dev) && !qdisc_tx_is_noop(dev);
}
staticvoid addrconf_del_rs_timer(struct inet6_dev *idev)
{ if (timer_delete(&idev->rs_timer))
__in6_dev_put(idev);
}
staticvoid addrconf_del_dad_work(struct inet6_ifaddr *ifp)
{ if (cancel_delayed_work(&ifp->dad_work))
__in6_ifa_put(ifp);
}
if (netif_running(dev) && addrconf_link_ready(dev))
ndev->if_flags |= IF_READY;
ipv6_mc_init_dev(ndev);
ndev->tstamp = jiffies; if (dev != blackhole_netdev) {
err = addrconf_sysctl_register(ndev); if (err) {
ipv6_mc_destroy_dev(ndev);
snmp6_unregister_dev(ndev); goto err_release;
}
} /* protected by rtnl_lock */
rcu_assign_pointer(dev->ip6_ptr, ndev);
if (dev != blackhole_netdev) { /* Join interface-local all-node multicast group */
ipv6_dev_mc_inc(dev, &in6addr_interfacelocal_allnodes);
/* Join all-node multicast group */
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allnodes);
/* Join all-router multicast group if forwarding is set */ if (ndev->cnf.forwarding && (dev->flags & IFF_MULTICAST))
ipv6_dev_mc_inc(dev, &in6addr_linklocal_allrouters);
} return ndev;
idev = __in6_dev_get(dev); if (!idev) {
idev = ipv6_add_dev(dev); if (IS_ERR(idev)) return idev;
}
if (dev->flags&IFF_UP)
ipv6_mc_up(idev); return idev;
}
staticint inet6_netconf_msgsize_devconf(int type)
{ int size = NLMSG_ALIGN(sizeof(struct netconfmsg))
+ nla_total_size(4); /* NETCONFA_IFINDEX */ bool all = false;
if (type == NETCONFA_ALL)
all = true;
if (all || type == NETCONFA_FORWARDING)
size += nla_total_size(4); #ifdef CONFIG_IPV6_MROUTE if (all || type == NETCONFA_MC_FORWARDING)
size += nla_total_size(4); #endif if (all || type == NETCONFA_PROXY_NEIGH)
size += nla_total_size(4);
if (all || type == NETCONFA_IGNORE_ROUTES_WITH_LINKDOWN)
size += nla_total_size(4);
return size;
}
staticint inet6_netconf_fill_devconf(struct sk_buff *skb, int ifindex, struct ipv6_devconf *devconf, u32 portid,
u32 seq, int event, unsignedint flags, int type)
{ struct nlmsghdr *nlh; struct netconfmsg *ncm; bool all = false;
void inet6_netconf_notify_devconf(struct net *net, int event, int type, int ifindex, struct ipv6_devconf *devconf)
{ struct sk_buff *skb; int err = -ENOBUFS;
skb = nlmsg_new(inet6_netconf_msgsize_devconf(type), GFP_KERNEL); if (!skb) goto errout;
/* * Each device address list is sorted in order of scope - * global before linklocal.
*/
list_for_each(p, &idev->addr_list) { struct inet6_ifaddr *ifa
= list_entry(p, struct inet6_ifaddr, if_list); if (ifp_scope >= ipv6_addr_src_scope(&ifa->addr)) break;
}
list_add_tail_rcu(&ifp->if_list, p);
}
static u32 inet6_addr_hash(conststruct net *net, conststruct in6_addr *addr)
{
u32 val = __ipv6_addr_jhash(addr, net_hash_mix(net));
/* Add to inet6_dev unicast addr list. */
ipv6_link_dev_addr(idev, ifa);
if (ifa->flags&IFA_F_TEMPORARY) {
list_add(&ifa->tmp_list, &idev->tempaddr_list);
in6_ifa_hold(ifa);
}
in6_ifa_hold(ifa);
write_unlock_bh(&idev->lock);
rcu_read_unlock();
inet6addr_notifier_call_chain(NETDEV_UP, ifa);
out: if (unlikely(err < 0)) {
fib6_info_release(f6i);
if (ifa) { if (ifa->idev)
in6_dev_put(ifa->idev);
kfree(ifa);
}
ifa = ERR_PTR(err);
}
return ifa;
}
enum cleanup_prefix_rt_t {
CLEANUP_PREFIX_RT_NOP, /* no cleanup action for prefix route */
CLEANUP_PREFIX_RT_DEL, /* delete the prefix route */
CLEANUP_PREFIX_RT_EXPIRE, /* update the lifetime of the prefix route */
};
/* * Check, whether the prefix for ifp would still need a prefix route * after deleting ifp. The function returns one of the CLEANUP_PREFIX_RT_* * constants. * * 1) we don't purge prefix if address was not permanent. * prefix is managed by its own lifetime. * 2) we also don't purge, if the address was IFA_F_NOPREFIXROUTE. * 3) if there are no addresses, delete prefix. * 4) if there are still other permanent address(es), * corresponding prefix is still permanent. * 5) if there are still other addresses with IFA_F_NOPREFIXROUTE, * don't purge the prefix, assume user space is managing it. * 6) otherwise, update prefix lifetime to the * longest valid lifetime among the corresponding * addresses on the device. * Note: subsequent RA will update lifetime.
**/ staticenum cleanup_prefix_rt_t
check_cleanup_prefix_route(struct inet6_ifaddr *ifp, unsignedlong *expires)
{ struct inet6_ifaddr *ifa; struct inet6_dev *idev = ifp->idev; unsignedlong lifetime; enum cleanup_prefix_rt_t action = CLEANUP_PREFIX_RT_DEL;
*expires = jiffies;
list_for_each_entry(ifa, &idev->addr_list, if_list) { if (ifa == ifp) continue; if (ifa->prefix_len != ifp->prefix_len ||
!ipv6_prefix_equal(&ifa->addr, &ifp->addr,
ifp->prefix_len)) continue; if (ifa->flags & (IFA_F_PERMANENT | IFA_F_NOPREFIXROUTE)) return CLEANUP_PREFIX_RT_NOP;
action = CLEANUP_PREFIX_RT_EXPIRE;
spin_lock(&ifa->lock);
lifetime = addrconf_timeout_fixup(ifa->valid_lft, HZ); /* * Note: Because this address is * not permanent, lifetime < * LONG_MAX / HZ here.
*/ if (time_before(*expires, ifa->tstamp + lifetime * HZ))
*expires = ifa->tstamp + lifetime * HZ;
spin_unlock(&ifa->lock);
}
/* From RFC 4941: * * A temporary address is created only if this calculated Preferred * Lifetime is greater than REGEN_ADVANCE time units. In * particular, an implementation must not create a temporary address * with a zero Preferred Lifetime. * * ... * * When creating a temporary address, the lifetime values MUST be * derived from the corresponding prefix as follows: * * ... * * * Its Preferred Lifetime is the lower of the Preferred Lifetime * of the public address or TEMP_PREFERRED_LIFETIME - * DESYNC_FACTOR. * * To comply with the RFC's requirements, clamp the preferred lifetime * to a minimum of regen_advance, unless that would exceed valid_lft or * ifp->prefered_lft. * * Use age calculation as in addrconf_verify to avoid unnecessary * temporary addresses being generated.
*/
age = (now - tmp_tstamp + ADDRCONF_TIMER_FUZZ_MINUS) / HZ; if (cfg.preferred_lft <= regen_advance + age) {
cfg.preferred_lft = regen_advance + age + 1; if (cfg.preferred_lft > cfg.valid_lft ||
cfg.preferred_lft > if_public_preferred_lft) {
in6_ifa_put(ifp);
in6_dev_put(idev);
ret = -1; goto out;
}
}
cfg.ifa_flags = IFA_F_TEMPORARY; /* set in addrconf_prefix_rcv() */ if (ifp->flags & IFA_F_OPTIMISTIC)
cfg.ifa_flags |= IFA_F_OPTIMISTIC;
struct ipv6_saddr_score { int rule; int addr_type; struct inet6_ifaddr *ifa;
DECLARE_BITMAP(scorebits, IPV6_SADDR_RULE_MAX); int scopedist; int matchlen;
};
struct ipv6_saddr_dst { conststruct in6_addr *addr; int ifindex; int scope; int label; unsignedint prefs;
};
staticbool ipv6_use_optimistic_addr(conststruct net *net, conststruct inet6_dev *idev)
{ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (!idev) returnfalse; if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) &&
!READ_ONCE(idev->cnf.optimistic_dad)) returnfalse; if (!READ_ONCE(net->ipv6.devconf_all->use_optimistic) &&
!READ_ONCE(idev->cnf.use_optimistic)) returnfalse;
returntrue; #else returnfalse; #endif
}
staticbool ipv6_allow_optimistic_dad(conststruct net *net, conststruct inet6_dev *idev)
{ #ifdef CONFIG_IPV6_OPTIMISTIC_DAD if (!idev) returnfalse; if (!READ_ONCE(net->ipv6.devconf_all->optimistic_dad) &&
!READ_ONCE(idev->cnf.optimistic_dad)) returnfalse;
returntrue; #else returnfalse; #endif
}
staticint ipv6_get_saddr_eval(struct net *net, struct ipv6_saddr_score *score, struct ipv6_saddr_dst *dst, int i)
{ int ret;
if (i <= score->rule) { switch (i) { case IPV6_SADDR_RULE_SCOPE:
ret = score->scopedist; break; case IPV6_SADDR_RULE_PREFIX:
ret = score->matchlen; break; default:
ret = !!test_bit(i, score->scorebits);
} goto out;
}
switch (i) { case IPV6_SADDR_RULE_INIT: /* Rule 0: remember if hiscore is not ready yet */
ret = !!score->ifa; break; case IPV6_SADDR_RULE_LOCAL: /* Rule 1: Prefer same address */
ret = ipv6_addr_equal(&score->ifa->addr, dst->addr); break; case IPV6_SADDR_RULE_SCOPE: /* Rule 2: Prefer appropriate scope * * ret * ^ * -1 | d 15 * ---+--+-+---> scope * | * | d is scope of the destination. * B-d | \ * | \ <- smaller scope is better if * B-15 | \ if scope is enough for destination. * | ret = B - scope (-1 <= scope >= d <= 15). * d-C-1 | / * |/ <- greater is better * -C / if scope is not enough for destination. * /| ret = scope - C (-1 <= d < scope <= 15). * * d - C - 1 < B -15 (for all -1 <= d <= 15). * C > d + 14 - B >= 15 + 14 - B = 29 - B. * Assume B = 0 and we get C > 29.
*/
ret = __ipv6_addr_src_scope(score->addr_type); if (ret >= dst->scope)
ret = -ret; else
ret -= 128; /* 30 is enough */
score->scopedist = ret; break; case IPV6_SADDR_RULE_PREFERRED:
{ /* Rule 3: Avoid deprecated and optimistic addresses */
u8 avoid = IFA_F_DEPRECATED;
if (!ipv6_use_optimistic_addr(net, score->ifa->idev))
avoid |= IFA_F_OPTIMISTIC;
ret = ipv6_saddr_preferred(score->addr_type) ||
!(score->ifa->flags & avoid); break;
} #ifdef CONFIG_IPV6_MIP6 case IPV6_SADDR_RULE_HOA:
{ /* Rule 4: Prefer home address */ int prefhome = !(dst->prefs & IPV6_PREFER_SRC_COA);
ret = !(score->ifa->flags & IFA_F_HOMEADDRESS) ^ prefhome; break;
} #endif case IPV6_SADDR_RULE_OIF: /* Rule 5: Prefer outgoing interface */
ret = (!dst->ifindex ||
dst->ifindex == score->ifa->idev->dev->ifindex); break; case IPV6_SADDR_RULE_LABEL: /* Rule 6: Prefer matching label */
ret = ipv6_addr_label(net,
&score->ifa->addr, score->addr_type,
score->ifa->idev->dev->ifindex) == dst->label; break; case IPV6_SADDR_RULE_PRIVACY:
{ /* Rule 7: Prefer public address * Note: prefer temporary address if use_tempaddr >= 2
*/ int preftmp = dst->prefs & (IPV6_PREFER_SRC_PUBLIC|IPV6_PREFER_SRC_TMP) ?
!!(dst->prefs & IPV6_PREFER_SRC_TMP) :
READ_ONCE(score->ifa->idev->cnf.use_tempaddr) >= 2;
ret = (!(score->ifa->flags & IFA_F_TEMPORARY)) ^ preftmp; break;
} case IPV6_SADDR_RULE_ORCHID: /* Rule 8-: Prefer ORCHID vs ORCHID or * non-ORCHID vs non-ORCHID
*/
ret = !(ipv6_addr_orchid(&score->ifa->addr) ^
ipv6_addr_orchid(dst->addr)); break; case IPV6_SADDR_RULE_PREFIX: /* Rule 8: Use longest matching prefix */
ret = ipv6_addr_diff(&score->ifa->addr, dst->addr); if (ret > score->ifa->prefix_len)
ret = score->ifa->prefix_len;
score->matchlen = ret; break; #ifdef CONFIG_IPV6_OPTIMISTIC_DAD case IPV6_SADDR_RULE_NOT_OPTIMISTIC: /* Optimistic addresses still have lower precedence than other * preferred addresses.
*/
ret = !(score->ifa->flags & IFA_F_OPTIMISTIC); break; #endif default:
ret = 0;
}
list_for_each_entry_rcu(score->ifa, &idev->addr_list, if_list) { int i;
/* * - Tentative Address (RFC2462 section 5.4) * - A tentative address is not considered * "assigned to an interface" in the traditional * sense, unless it is also flagged as optimistic. * - Candidate Source Address (section 4) * - In any case, anycast addresses, multicast * addresses, and the unspecified address MUST * NOT be included in a candidate set.
*/ if ((score->ifa->flags & IFA_F_TENTATIVE) &&
(!(score->ifa->flags & IFA_F_OPTIMISTIC))) continue;
if (minihiscore > miniscore) { if (i == IPV6_SADDR_RULE_SCOPE &&
score->scopedist > 0) { /* * special case: * each remaining entry * has too small (not enough) * scope, because ifa entries * are sorted by their scope * values.
*/ goto out;
} break;
} elseif (minihiscore < miniscore) {
swap(hiscore, score);
hiscore_idx = 1 - hiscore_idx;
/* Candidate Source Address (section 4) * - multicast and link-local destination address, * the set of candidate source address MUST only * include addresses assigned to interfaces * belonging to the same link as the outgoing * interface. * (- For site-local destination addresses, the * set of candidate source addresses MUST only * include addresses assigned to interfaces * belonging to the same site as the outgoing * interface.) * - "It is RECOMMENDED that the candidate source addresses * be the set of unicast addresses assigned to the * interface that will be used to send to the destination * (the 'outgoing' interface)." (RFC 6724)
*/ if (dst_dev) {
idev = __in6_dev_get(dst_dev); if ((dst_type & IPV6_ADDR_MULTICAST) ||
dst.scope <= IPV6_ADDR_SCOPE_LINKLOCAL ||
(idev && READ_ONCE(idev->cnf.use_oif_addrs_only))) {
use_oif_addr = true;
}
}
if (use_oif_addr) { if (idev)
hiscore_idx = __ipv6_dev_get_saddr(net, &dst, idev, scores, hiscore_idx);
} else { conststruct net_device *master; int master_idx = 0;
/* if dst_dev exists and is enslaved to an L3 device, then * prefer addresses from dst_dev and then the master over * any other enslaved devices in the L3 domain.
*/
master = l3mdev_master_dev_rcu(dst_dev); if (master) {
master_idx = master->ifindex;
int ipv6_chk_addr(struct net *net, conststruct in6_addr *addr, conststruct net_device *dev, int strict)
{ return ipv6_chk_addr_and_flags(net, addr, dev, !dev,
strict, IFA_F_TENTATIVE);
}
EXPORT_SYMBOL(ipv6_chk_addr);
/* device argument is used to find the L3 domain of interest. If * skip_dev_check is set, then the ifp device is not checked against * the passed in dev argument. So the 2 cases for addresses checks are: * 1. does the address exist in the L3 domain that dev is part of * (skip_dev_check = true), or * * 2. does the address exist on the specific device * (skip_dev_check = false)
*/ staticstruct net_device *
__ipv6_chk_addr_and_flags(struct net *net, conststruct in6_addr *addr, conststruct net_device *dev, bool skip_dev_check, int strict, u32 banned_flags)
{ unsignedint hash = inet6_addr_hash(net, addr); struct net_device *l3mdev, *ndev; struct inet6_ifaddr *ifp;
u32 ifp_flags;
rcu_read_lock();
l3mdev = l3mdev_master_dev_rcu(dev); if (skip_dev_check)
dev = NULL;
if (l3mdev_master_dev_rcu(ndev) != l3mdev) continue;
/* Decouple optimistic from tentative for evaluation here. * Ban optimistic addresses explicitly, when required.
*/
ifp_flags = (ifp->flags&IFA_F_OPTIMISTIC)
? (ifp->flags&~IFA_F_TENTATIVE)
: ifp->flags; if (ipv6_addr_equal(&ifp->addr, addr) &&
!(ifp_flags&banned_flags) &&
(!dev || ndev == dev ||
!(ifp->scope&(IFA_LINK|IFA_HOST) || strict))) {
rcu_read_unlock(); return ndev;
}
}
rcu_read_unlock(); return NULL;
}
int ipv6_chk_addr_and_flags(struct net *net, conststruct in6_addr *addr, conststruct net_device *dev, bool skip_dev_check, int strict, u32 banned_flags)
{ return __ipv6_chk_addr_and_flags(net, addr, dev, skip_dev_check,
strict, banned_flags) ? 1 : 0;
}
EXPORT_SYMBOL(ipv6_chk_addr_and_flags);
/* Compares an address/prefix_len with addresses on device @dev. * If one is found it returns true.
*/ bool ipv6_chk_custom_prefix(conststruct in6_addr *addr, constunsignedint prefix_len, struct net_device *dev)
{ conststruct inet6_ifaddr *ifa; conststruct inet6_dev *idev; bool ret = false;
rcu_read_lock();
idev = __in6_dev_get(dev); if (idev) {
list_for_each_entry_rcu(ifa, &idev->addr_list, if_list) {
ret = ipv6_prefix_equal(addr, &ifa->addr, prefix_len); if (ret) break;
}
}
rcu_read_unlock();
/** * ipv6_dev_find - find the first device with a given source address. * @net: the net namespace * @addr: the source address * @dev: used to find the L3 domain of interest * * The caller should be protected by RCU, or RTNL.
*/ struct net_device *ipv6_dev_find(struct net *net, conststruct in6_addr *addr, struct net_device *dev)
{ return __ipv6_chk_addr_and_flags(net, addr, dev, !dev, 1,
IFA_F_TENTATIVE);
}
EXPORT_SYMBOL(ipv6_dev_find);
if (retries > net->ipv6.sysctl.idgen_retries) {
net_info_ratelimited("%s: privacy stable address generation failed because of DAD conflicts!\n",
ifp->idev->dev->name); goto errdad;
}
new_addr = ifp->addr; if (ipv6_generate_stable_address(&new_addr, retries,
idev)) goto errdad;
/* <draft-ietf-6man-rfc4941bis-08.txt>, Section 3.3.1: * check if generated address is not inappropriate: * * - Reserved IPv6 Interface Identifiers * - XXX: already assigned to an address on the device
*/
/* Prevent useless cloning on PtP SIT. This thing is done here expecting that the whole class of non-broadcast devices need not cloning.
*/ #if IS_ENABLED(CONFIG_IPV6_SIT) if (dev->type == ARPHRD_SIT && (dev->flags & IFF_POINTOPOINT))
cfg.fc_flags |= RTF_NONEXTHOP; #endif
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.