optimistic-dad

2023-12-19 09:32
文章标签 optimistic dad

本文主要是介绍optimistic-dad,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

配置项optimistic_dad用于控制是否执行优化的DAD检查;配置项use_optimistic控制在源地址选择时,可使用optimistic地址,但是其优先级低于Preferred地址。如下函数ipv6_allow_optimistic_dad,命名空间和设备的optimistic_dad配置项有一个为真,就启用此功能。

static bool ipv6_allow_optimistic_dad(struct net *net, struct inet6_dev *idev)                  
{ 
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD  if (!idev)return false;if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)return false;return true;
#elsereturn false;
#endif
}

配置项use_optimistic仅在optimistic_dad开启后有效,也是只有命名空间或者设备其中一个的use_optimistic为真,即开启此功能。

static bool ipv6_use_optimistic_addr(struct net *net, struct inet6_dev *idev)                  
{ 
#ifdef CONFIG_IPV6_OPTIMISTIC_DAD  if (!idev)return false;              if (!net->ipv6.devconf_all->optimistic_dad && !idev->cnf.optimistic_dad)return false;              if (!net->ipv6.devconf_all->use_optimistic && !idev->cnf.use_optimistic)return false;return true;
#elsereturn false;                  
#endif
} 

SLAAC自动配置地址

根据RA报文中的前缀信息配置接口地址,如果命名空间中conf/{all,interface}/optimistic_dad的值有一个不为零,则认为开启了优化DAD功能,此时如果转发功能未启用,并且RA报文中带有sllao(Source Link-Layer Address Options)的情况下,设置IFA_F_OPTIMISTIC标记,将地址标识为优化地址。

如果报文RA中没有携带sllao,将得不到路由器的链路地址。由于不能使用Optimistic地址发送NS报文,需要将数据报文(子网内)发送给路由器中转,或者路由器回复重定向报文,告知报文目的IP的链路地址,所以,如果没有sllao,Optimistic功能将不可用。

int addrconf_prefix_rcv_add_addr(struct net *net, struct net_device *dev,const struct prefix_info *pinfo, struct inet6_dev *in6_dev,const struct in6_addr *addr, int addr_type,u32 addr_flags, bool sllao, bool tokenized, __u32 valid_lft, u32 prefered_lft)
{struct inet6_ifaddr *ifp = ipv6_get_ifaddr(net, addr, dev, 1);int create = 0;if (!ifp && valid_lft) {int max_addresses = in6_dev->cnf.max_addresses;struct ifa6_config cfg = {.pfx = addr,.plen = pinfo->prefix_len,.ifa_flags = addr_flags,.valid_lft = valid_lft,.preferred_lft = prefered_lft,.scope = addr_type & IPV6_ADDR_SCOPE_MASK,};#ifdef CONFIG_IPV6_OPTIMISTIC_DADif ((net->ipv6.devconf_all->optimistic_dad ||in6_dev->cnf.optimistic_dad) &&!net->ipv6.devconf_all->forwarding && sllao)cfg.ifa_flags |= IFA_F_OPTIMISTIC;
#endif/* Do not allow to create too much of autoconfigured* addresses; this would be too easy way to crash kernel.*/if (!max_addresses || ipv6_count_addresses(in6_dev) < max_addresses)ifp = ipv6_add_addr(in6_dev, &cfg, false, NULL);if (IS_ERR_OR_NULL(ifp)) return -1;create = 1;spin_lock_bh(&ifp->lock);ifp->flags |= IFA_F_MANAGETEMPADDR;ifp->cstamp = jiffies;ifp->tokenized = tokenized;spin_unlock_bh(&ifp->lock);addrconf_dad_start(ifp);}

链路本地地址

与上节相同,内核打开了IPV6_OPTIMISTIC_DAD编译选项之后,在添加链路本地地址时,如果开启了优化dad配置,并且命名空间的forwarding为0,即工作在主机模式,设置IFA_F_OPTIMISTIC标志。对于路由器,不能设置optimistic地址,参考上一节说明的原因。

void addrconf_add_linklocal(struct inet6_dev *idev, const struct in6_addr *addr, u32 flags)
{struct ifa6_config cfg = {.pfx = addr,.plen = 64,.ifa_flags = flags | IFA_F_PERMANENT,.valid_lft = INFINITY_LIFE_TIME,.preferred_lft = INFINITY_LIFE_TIME,.scope = IFA_LINK};struct inet6_ifaddr *ifp;#ifdef CONFIG_IPV6_OPTIMISTIC_DADif ((dev_net(idev->dev)->ipv6.devconf_all->optimistic_dad ||idev->cnf.optimistic_dad) &&!dev_net(idev->dev)->ipv6.devconf_all->forwarding)cfg.ifa_flags |= IFA_F_OPTIMISTIC;
#endififp = ipv6_add_addr(idev, &cfg, true, NULL);if (!IS_ERR(ifp)) {addrconf_prefix_route(&ifp->addr, ifp->prefix_len, 0, idev->dev,0, 0, GFP_ATOMIC);addrconf_dad_start(ifp);in6_ifa_put(ifp);}
}

应用层配置地址

用户层通过IP命令设置IPv6地址时,IFA_F_NODAD 和 IFA_F_OPTIMISTIC是互斥的,不能同时设置。

static int inet6_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, struct netlink_ext_ack *extack)
{if (tb[IFA_FLAGS])cfg.ifa_flags = nla_get_u32(tb[IFA_FLAGS]);elsecfg.ifa_flags = ifm->ifa_flags;/* We ignore other flags so far. */cfg.ifa_flags &= IFA_F_NODAD | IFA_F_HOMEADDRESS |IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE |IFA_F_MCAUTOJOIN | IFA_F_OPTIMISTIC;idev = ipv6_find_idev(dev);if (IS_ERR(idev))return PTR_ERR(idev);if (!ipv6_allow_optimistic_dad(net, idev))cfg.ifa_flags &= ~IFA_F_OPTIMISTIC;if (cfg.ifa_flags & IFA_F_NODAD &&cfg.ifa_flags & IFA_F_OPTIMISTIC) {NL_SET_ERR_MSG(extack, "IFA_F_NODAD and IFA_F_OPTIMISTIC are mutually exclusive");return -EINVAL;}ifa = ipv6_get_ifaddr(net, cfg.pfx, dev, 1);if (!ifa) {/** It would be best to check for !NLM_F_CREATE here but* userspace already relies on not having to provide this.*/return inet6_addr_add(net, ifm->ifa_index, &cfg, extack);}

源地址选择

在选择源地址时,不考虑暂定tentative地址,除非其设置了IFA_F_OPTIMISTIC标志。

static int __ipv6_dev_get_saddr(struct net *net,struct ipv6_saddr_dst *dst, struct inet6_dev *idev,struct ipv6_saddr_score *scores, int hiscore_idx)
{struct ipv6_saddr_score *score = &scores[1 - hiscore_idx], *hiscore = &scores[hiscore_idx];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;

不能使用DEPRECATED废弃地址,如果没有打开使用use_optimistic地址配置,也不能使用IFA_F_OPTIMISTIC地址。即使使用OPTIMISTIC优化地址,其优先级也是低于preferred地址。

static int ipv6_get_saddr_eval(struct net *net, struct ipv6_saddr_score *score,struct ipv6_saddr_dst *dst, int i)
{switch (i) {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_OPTIMISTIC_DADcase IPV6_SADDR_RULE_NOT_OPTIMISTIC:/* Optimistic addresses still have lower precedence than other* preferred addresses.*/ret = !(score->ifa->flags & IFA_F_OPTIMISTIC);break;
#endifdefault:ret = 0;}

优化DAD

对于不使用DAD的情况,如果仅为tentative地址,没有同时设置optimistic标志,发送NA报文通知邻居。否则,如果设置了optimistic标志,不能发送NA,以免遇到地址冲突的情况下,破坏邻居设备中的地址表项。

函数addrconf_dad_completed中发送NA时,将设置Override标志。

static void addrconf_dad_begin(struct inet6_ifaddr *ifp)
{net = dev_net(dev);if (dev->flags&(IFF_NOARP|IFF_LOOPBACK) ||(net->ipv6.devconf_all->accept_dad < 1 &&idev->cnf.accept_dad < 1) ||!(ifp->flags&IFA_F_TENTATIVE) ||ifp->flags & IFA_F_NODAD) {bool send_na = false;if (ifp->flags & IFA_F_TENTATIVE &&!(ifp->flags & IFA_F_OPTIMISTIC))send_na = true;bump_id = ifp->flags & IFA_F_TENTATIVE;ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);spin_unlock(&ifp->lock);read_unlock_bh(&idev->lock);addrconf_dad_completed(ifp, bump_id, send_na);return;}

对于使用DAD的情况,优化地址在DAD完成之前已经可以使用,这里插入路由表项,并且,向上层发送新地址通知。

    /* Optimistic nodes can start receiving Frames right away*/if (ifp->flags & IFA_F_OPTIMISTIC) {ip6_ins_rt(net, ifp->rt);if (ipv6_use_optimistic_addr(net, idev)) {/* Because optimistic nodes can use this address,* notify listeners. If DAD fails, RTM_DELADDR is sent.*/notify = true;}}addrconf_dad_kick(ifp);

在DAD成功结束之后,对于OPTIMISTIC优化地址,不需要发送NA报文,与以上函数addrconf_dad_begin中处理相同。

static void addrconf_dad_work(struct work_struct *w)
{if (ifp->dad_probes == 0) {bool send_na = false;/* DAD was successful*/if (ifp->flags & IFA_F_TENTATIVE &&!(ifp->flags & IFA_F_OPTIMISTIC))send_na = true;bump_id = ifp->flags & IFA_F_TENTATIVE;ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);spin_unlock(&ifp->lock);write_unlock_bh(&idev->lock);addrconf_dad_completed(ifp, bump_id, send_na);goto out;}

另外,对于优化Optimistic地址,不需要延时,立即调用DAD处理函数,发送NS报文,源地址使用未指定地址in6addr_any,报文在不包括SLLAO。

/*  Duplicate Address Detection*/
static void addrconf_dad_kick(struct inet6_ifaddr *ifp)
{unsigned long rand_num;struct inet6_dev *idev = ifp->idev;u64 nonce;if (ifp->flags & IFA_F_OPTIMISTIC)rand_num = 0;elserand_num = prandom_u32() % (idev->cnf.rtr_solicit_delay ? : 1);nonce = 0;if (idev->cnf.enhanced_dad ||dev_net(idev->dev)->ipv6.devconf_all->enhanced_dad) {doget_random_bytes(&nonce, 6);while (nonce == 0);}ifp->dad_nonce = nonce;ifp->dad_probes = idev->cnf.dad_transmits;addrconf_mod_dad_work(ifp, rand_num);
}

对于PERMANENT地址,如果dad失败,将其设置为tentative地址,清除optimistic标志位,地址不可用。

static void addrconf_dad_stop(struct inet6_ifaddr *ifp, int dad_failed)
{   if (dad_failed)ifp->flags |= IFA_F_DADFAILED;if (ifp->flags&IFA_F_TEMPORARY) {...} else if (ifp->flags&IFA_F_PERMANENT || !dad_failed) {spin_lock_bh(&ifp->lock);addrconf_del_dad_work(ifp);ifp->flags |= IFA_F_TENTATIVE;if (dad_failed)ifp->flags &= ~IFA_F_OPTIMISTIC;spin_unlock_bh(&ifp->lock);if (dad_failed)ipv6_ifa_notify(0, ifp);in6_ifa_put(ifp);} else {ipv6_del_addr(ifp);

邻居发现

在发送RS报文时,如果使用的源地址为优化地址,报文中不应包含sllao选项。另外,在找不到相应接口地址时,也不包含sllao选项。

void ndisc_send_rs(struct net_device *dev, const struct in6_addr *saddr, const struct in6_addr *daddr)
{struct rs_msg *msg;int send_sllao = dev->addr_len;#ifdef CONFIG_IPV6_OPTIMISTIC_DAD/** According to section 2.2 of RFC 4429, we must not* send router solicitations with a sllao from* optimistic addresses, but we may send the solicitation* if we don't include the sllao.  So here we check* if our address is optimistic, and if so, we* suppress the inclusion of the sllao.*/if (send_sllao) {struct inet6_ifaddr *ifp = ipv6_get_ifaddr(dev_net(dev), saddr, dev, 1);if (ifp) {if (ifp->flags & IFA_F_OPTIMISTIC)  {send_sllao = 0;}in6_ifa_put(ifp);} else {send_sllao = 0;}}
#endifif (send_sllao)optlen += ndisc_opt_addr_space(dev, NDISC_ROUTER_SOLICITATION);skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);if (!skb) return;

在发送NA报文时,如果源地址为优化地址,报文中的覆盖标志override为false,以免破坏接收设备的邻居表项。

void ndisc_send_na(struct net_device *dev, const struct in6_addr *daddr,const struct in6_addr *solicited_addr,bool router, bool solicited, bool override, bool inc_opt)
{struct inet6_ifaddr *ifp;const struct in6_addr *src_addr;struct nd_msg *msg;/* for anycast or proxy, solicited_addr != src_addr */ifp = ipv6_get_ifaddr(dev_net(dev), solicited_addr, dev, 1);if (ifp) {src_addr = solicited_addr;if (ifp->flags & IFA_F_OPTIMISTIC)override = false;inc_opt |= ifp->idev->cnf.force_tllao;in6_ifa_put(ifp);} else {if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr,inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs,&tmpaddr))return;src_addr = &tmpaddr;}if (!dev->addr_len)inc_opt = false;if (inc_opt)optlen += ndisc_opt_addr_space(dev, NDISC_NEIGHBOUR_ADVERTISEMENT);skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);if (!skb)return;msg = skb_put(skb, sizeof(*msg));*msg = (struct nd_msg) {.icmph = {.icmp6_type = NDISC_NEIGHBOUR_ADVERTISEMENT,.icmp6_router = router,.icmp6_solicited = solicited,.icmp6_override = override,},.target = *solicited_addr,};

在发送非请求的NA报文时,对于未设置IFA_F_OPTIMISTIC标志的TENTATIVE地址,不进行发送。需要等待其完成DAD。

static void ndisc_send_unsol_na(struct net_device *dev)
{struct inet6_dev *idev;struct inet6_ifaddr *ifa;idev = in6_dev_get(dev);if (!idev)return;read_lock_bh(&idev->lock);list_for_each_entry(ifa, &idev->addr_list, if_list) {/* skip tentative addresses until dad completes */if (ifa->flags & IFA_F_TENTATIVE &&!(ifa->flags & IFA_F_OPTIMISTIC))continue;ndisc_send_na(dev, &in6addr_linklocal_allnodes, &ifa->addr,/*router=*/ !!idev->cnf.forwarding,/*solicited=*/ false, /*override=*/ true,/*inc_opt=*/ true);}read_unlock_bh(&idev->lock);in6_dev_put(idev);
}

在发送NS报文时,如果未指定源地址,选择除TENTATIVE和OPTIMISTIC地址类型之外的其它地址做源地址。

void ndisc_send_ns(struct net_device *dev, const struct in6_addr *solicit,const struct in6_addr *daddr, const struct in6_addr *saddr, u64 nonce)
{struct sk_buff *skb;struct in6_addr addr_buf;int inc_opt = dev->addr_len;int optlen = 0;struct nd_msg *msg;if (!saddr) {if (ipv6_get_lladdr(dev, &addr_buf, (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)))return;saddr = &addr_buf;}if (ipv6_addr_any(saddr))inc_opt = false;if (inc_opt)optlen += ndisc_opt_addr_space(dev, NDISC_NEIGHBOUR_SOLICITATION);if (nonce != 0)optlen += 8;skb = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);if (!skb)return;

如果没有找到非tentative/optimistic的地址,源地址saddr将为空,在以上的发送函数ndisc_send_ns中,需要查找符合的链路本地地址,找不到将不能发送。

static void ndisc_solicit(struct neighbour *neigh, struct sk_buff *skb)
{struct in6_addr *saddr = NULL;struct net_device *dev = neigh->dev;struct in6_addr *target = (struct in6_addr *)&neigh->primary_key;if (skb && ipv6_chk_addr_and_flags(dev_net(dev), &ipv6_hdr(skb)->saddr, dev, false, 1,IFA_F_TENTATIVE|IFA_F_OPTIMISTIC))saddr = &ipv6_hdr(skb)->saddr;probes -= NEIGH_VAR(neigh->parms, UCAST_PROBES);if (probes < 0) {if (!(neigh->nud_state & NUD_VALID)) {ND_PRINTK(1, dbg, "%s: trying to ucast probe in NUD_INVALID: %pI6\n", __func__, target);}ndisc_send_ns(dev, target, target, saddr, 0);} else if ((probes -= NEIGH_VAR(neigh->parms, APP_PROBES)) < 0) {neigh_app_ns(neigh);} else {addrconf_addr_solict_mult(target, &mcaddr);ndisc_send_ns(dev, target, &mcaddr, saddr, 0);

如果接收到的NS报文不是DAD检查报文,对于Optimistic地址回复NA报文,其中Override标志设置为0。

static void ndisc_recv_ns(struct sk_buff *skb)
{ifp = ipv6_get_ifaddr(dev_net(dev), &msg->target, dev, 1);if (ifp) {
have_ifp:if (ifp->flags & (IFA_F_TENTATIVE|IFA_F_OPTIMISTIC)) {if (dad) {if (nonce != 0 && ifp->dad_nonce == nonce) {u8 *np = (u8 *)&nonce;/* Matching nonce if looped back */ND_PRINTK(2, notice, "%s: IPv6 DAD loopback for address %pI6c nonce %pM ignored\n",ifp->idev->dev->name, &ifp->addr, np);goto out;}/* We are colliding with another node who is doing DAD so fail our DAD process */addrconf_dad_failure(skb, ifp);return;} else {/** This is not a dad solicitation.* If we are an optimistic node, we should respond.* Otherwise, we should ignore it.*/if (!(ifp->flags & IFA_F_OPTIMISTIC))goto out;}}idev = ifp->idev;} else {struct net *net = dev_net(dev);/* perhaps an address on the master device */if (netif_is_l3_slave(dev)) {struct net_device *mdev;mdev = netdev_master_upper_dev_get_rcu(dev);if (mdev) {ifp = ipv6_get_ifaddr(net, &msg->target, mdev, 1);if (ifp) goto have_ifp;}}

报文发送

如果当前报文目的地址的邻居表项不可用,而报文的源地址使用的是Optimistic地址,不能发送NS报文,需要将报文发给默认的网关。

static int ip6_dst_lookup_tail(struct net *net, const struct sock *sk, struct dst_entry **dst, struct flowi6 *fl6)
{
#ifdef CONFIG_IPV6_OPTIMISTIC_DADstruct neighbour *n;struct rt6_info *rt;
#endif#ifdef CONFIG_IPV6_OPTIMISTIC_DAD/** Here if the dst entry we've looked up* has a neighbour entry that is in the INCOMPLETE* state and the src address from the flow is* marked as OPTIMISTIC, we release the found* dst entry and replace it instead with the* dst entry of the nexthop router*/rt = (struct rt6_info *) *dst;rcu_read_lock_bh();n = __ipv6_neigh_lookup_noref(rt->dst.dev, rt6_nexthop(rt, &fl6->daddr));err = n && !(n->nud_state & NUD_VALID) ? -EINVAL : 0;rcu_read_unlock_bh();if (err) {struct inet6_ifaddr *ifp;struct flowi6 fl_gw6;ifp = ipv6_get_ifaddr(net, &fl6->saddr, (*dst)->dev, 1);redirect = (ifp && ifp->flags & IFA_F_OPTIMISTIC);if (ifp) in6_ifa_put(ifp);if (redirect) {/* We need to get the dst entry for the default router instead*/dst_release(*dst);memcpy(&fl_gw6, fl6, sizeof(struct flowi6));memset(&fl_gw6.daddr, 0, sizeof(struct in6_addr));*dst = ip6_route_output(net, sk, &fl_gw6);err = (*dst)->error;if (err) goto out_err_release;}}
#endif

网关在接收到此报文之后,判断其目的地址就位于链路本地网络中,将发送ND的重定向报文,在其中携带目的地址的链路地址,如下,增加TLLAO选项。

void ndisc_send_redirect(struct sk_buff *skb, const struct in6_addr *target)
{if (dev->addr_len) {struct neighbour *neigh = dst_neigh_lookup(skb_dst(skb), target);if (!neigh) {ND_PRINTK(2, warn, "Redirect: no neigh for target address\n");goto release;}read_lock_bh(&neigh->lock);if (neigh->nud_state & NUD_VALID) {memcpy(ha_buf, neigh->ha, dev->addr_len);read_unlock_bh(&neigh->lock);ha = ha_buf;optlen += ndisc_redirect_opt_addr_space(dev, neigh, ops_data_buf, &ops_data);} elseread_unlock_bh(&neigh->lock);neigh_release(neigh);}buff = ndisc_alloc_skb(dev, sizeof(*msg) + optlen);if (!buff) goto release;msg = skb_put(buff, sizeof(*msg));*msg = (struct rd_msg) {.icmph = {.icmp6_type = NDISC_REDIRECT,},.target = *target,.dest = ipv6_hdr(skb)->daddr,};/* include target_address option */if (ha)ndisc_fill_redirect_addr_option(buff, ha, ops_data);

地址处理

如果开启了DAD,并且Optimistic标志没有设置,发送上层通知。

static int inet6_addr_add(struct net *net, int ifindex, struct ifa6_config *cfg, struct netlink_ext_ack *extack)
{struct inet6_ifaddr *ifp;ifp = ipv6_add_addr(idev, cfg, true, extack);if (!IS_ERR(ifp)) {.../* Send a netlink notification if DAD is enabled and* optimistic flag is not set*/if (!(ifp->flags & (IFA_F_OPTIMISTIC | IFA_F_NODAD)))ipv6_ifa_notify(0, ifp);

在修改地址时,对于非tentative地址,或者DAD失败的地址,清除配置的Optimistic标志,不允许设置。

static int inet6_addr_modify(struct inet6_ifaddr *ifp, struct ifa6_config *cfg)
{u32 flags;if (cfg->ifa_flags & IFA_F_MANAGETEMPADDR &&(ifp->flags & IFA_F_TEMPORARY || ifp->prefix_len != 64))return -EINVAL;if (!(ifp->flags & IFA_F_TENTATIVE) || ifp->flags & IFA_F_DADFAILED)cfg->ifa_flags &= ~IFA_F_OPTIMISTIC;

获取设备的未设置TENTATIVE和OPTIMISTIC标志的链路本地地址,作为源地址发送RS请求报文。

static int inet6_set_iftoken(struct inet6_dev *idev, struct in6_addr *token)
{struct inet6_ifaddr *ifp;struct net_device *dev = idev->dev;bool clear_token, update_rs = false;struct in6_addr ll_addr;BUILD_BUG_ON(sizeof(token->s6_addr) != 16);memcpy(idev->token.s6_addr + 8, token->s6_addr + 8, 8);write_unlock_bh(&idev->lock);clear_token = ipv6_addr_any(token);if (clear_token) goto update_lft;if (!idev->dead && (idev->if_flags & IF_READY) &&!ipv6_get_lladdr(dev, &ll_addr, IFA_F_TENTATIVE |IFA_F_OPTIMISTIC)) {/* If we're not ready, then normal ifup will take care* of this. Otherwise, we need to request our rs here.*/ndisc_send_rs(dev, &ll_addr, &in6addr_linklocal_allrouters);update_rs = true;}

临时隐私地址,继承其生成地址的IFA_F_OPTIMISTIC标志。

static int ipv6_create_tempaddr(struct inet6_ifaddr *ifp, bool block)
{cfg.ifa_flags = IFA_F_TEMPORARY;/* set in addrconf_prefix_rcv() */if (ifp->flags & IFA_F_OPTIMISTIC)cfg.ifa_flags |= IFA_F_OPTIMISTIC;cfg.pfx = &addr;cfg.scope = ipv6_addr_scope(cfg.pfx);ift = ipv6_add_addr(idev, &cfg, block, NULL);if (IS_ERR(ift)) {in6_ifa_put(ifp);in6_dev_put(idev);pr_info("%s: retry temporary address regeneration\n", __func__);write_lock_bh(&idev->lock);goto retry;}

在检查地址函数中,如果没有明确指定禁止optimistic地址,将认为其也是合法的。由于大多数情况下,optimistic和tentative标志都是同时设置了,这里将两者分开。

static struct net_device *__ipv6_chk_addr_and_flags(struct net *net, const struct in6_addr *addr,const struct net_device *dev, bool skip_dev_check, int strict, u32 banned_flags)
{unsigned int hash = inet6_addr_hash(net, addr);struct inet6_ifaddr *ifp;hlist_for_each_entry_rcu(ifp, &inet6_addr_lst[hash], addr_lst) {ndev = ifp->idev->dev;if (!net_eq(dev_net(ndev), net)) continue;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;

如下函数ipv6_lonely_lladdr判断ifp是否为接口上唯一的链路本地地址,由于addr_list是按照地址的scope排序的,如果第一个地址的scope大于IFA_LINK,表明链表中没有任何链路本地地址。

一个合法的地址,应当设置了IFA_F_PERMANENT标志,并且没有其它的三个标志。

static bool ipv6_lonely_lladdr(struct inet6_ifaddr *ifp)
{struct inet6_ifaddr *ifpiter;struct inet6_dev *idev = ifp->idev;list_for_each_entry_reverse(ifpiter, &idev->addr_list, if_list) {if (ifpiter->scope > IFA_LINK)break;if (ifp != ifpiter && ifpiter->scope == IFA_LINK &&(ifpiter->flags & (IFA_F_PERMANENT|IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED)) ==IFA_F_PERMANENT)return false;}return true;
}

内核版本 5.10

这篇关于optimistic-dad的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/511696

相关文章

Optimistic乐观挑战游戏Sharelock审计大赛

1. 引言 Optimistic的Sherlock审计大赛已进入升级期,fault proofs距离OP主网上线又更近一步了。本文将分享一些初步竞赛结果以及通往Stage 1的后续安排。 2. 审计状态更新 2024年3月27日,Optimistic团队开始针对拟议的 OP Stack fault proof系统进行 Sherlock 审计竞赛。本次竞赛主要关注: 1)允许Optimism

An Optimistic Perspective on Offline Reinforcement Learning(ICML2020)

Abstract \quad 该文章利用了 the DQN replay dataset 研究了Offline RL,该数据集包含了一个 DQN agent 在60款Atari 2600游戏上的 the entire replay experience 。 \quad 我们证明了 recent off-policy deep RL 算法,即使仅仅在 replay dataset 上训练,