Android有线IPV6总结(二):内核中RS与RA的一点学习

Android有线IPV6总结(⼆):内核中RS与RA的⼀点学习RS:Router Solicitation路由器请求
RA:Router Advertisement路由器公告
在Android系统中我们想要打开⼀个⽹络接⼝(⽐如eth0)的ipv6功能,⽤命令的话我们有如下两种办法:
1,echo 0 > /proc/sys/net/ipv6/conf/eth0/disable_ipv6
直接读写的内核proc⽂件
2,ndc interface ipv6 eth0 enable
⽤ndc命令,最终也是写内核proc⽂件
如上的操作proc⽂件就是触发⽹络终端发送RS报⽂的⽅式,接下来就记录⼀下内核中对应的代码流程:
写disable_ipv6⽂件对应的⽂件系统函数为:
addrconf_sysctl_disable
static
int addrconf_sysctl_disable(struct ctl_table *ctl, int write,
void __user *buffer, size_t *lenp, loff_t *ppos)
{
int *valp = ctl->data;
int val = *valp;
loff_t pos = *ppos;
struct ctl_table lctl;
int ret;
/*
* ctl->data points to idev->cnf.disable_ipv6, we should
* not modify it until we get the rtnl lock.
*/
天津市人口与计划生育条例lctl = *ctl;
lctl.data = &val;
ret = proc_dointvec(&lctl, write, buffer, lenp, ppos);
if (write)
ret = addrconf_disable_ipv6(ctl, valp, val);
if (ret)
*ppos = pos;
return ret;
}
接下来进⼊addrconf_disable_ipv6
static int addrconf_disable_ipv6(struct ctl_table *table, int *p, int newf)
{
struct net *net;
int old;
if (!rtnl_trylock())
return restart_syscall();
电动机的单片机控制net = (struct net *)table->extra2;
old = *p;
*p = newf;
//如果值不变则不作处理
if (p == &net->ipv6.devconf_dflt->disable_ipv6) {
rtnl_unlock();
return 0;
}
if (p == &net->ipv6.devconf_all->disable_ipv6) {
net->ipv6.devconf_dflt->disable_ipv6 = newf;
addrconf_disable_change(net, newf);
} else if ((!newf) ^ (!old)) //如果值发⽣变化则作处理
dev_disable_change((struct inet6_dev *)table->extra1);
rtnl_unlock();
return 0;
}
接下来进⼊dev_disable_change
static void dev_disable_change(struct inet6_dev *idev)
{
struct netdev_notifier_info info;
if (!idev || !idev->dev)
return;
netdev_notifier_info_init(&info, idev->dev);
if (idev->cnf.disable_ipv6)
addrconf_notify(NULL, NETDEV_DOWN, &info);  //关闭ipv6
else
addrconf_notify(NULL, NETDEV_UP, &info);  //开启ipv6
}
这⾥只看开启ipv6,所以接下来看addrconf_notify对NETDEV_UP的处理
case NETDEV_UP:
case NETDEV_CHANGE:
if (dev->flags & IFF_SLAVE)
break;
if (idev && idev->cnf.disable_ipv6)
break;
if (event == NETDEV_UP) {  //NETDEV_UP
if (!addrconf_qdisc_ok(dev)) {
/
* device is not ready yet. */
pr_info("ADDRCONF(NETDEV_UP): %s: link is not ready\n",                                        dev->name);
break;
}
if (!idev && dev->mtu >= IPV6_MIN_MTU)
if (!idev && dev->mtu >= IPV6_MIN_MTU)
idev = ipv6_add_dev(dev);  //将dev加⼊ipv6协议栈
if (!IS_ERR_OR_NULL(idev)) {
idev->if_flags |= IF_READY;
run_pending = 1;
}
} else {
if (!addrconf_qdisc_ok(dev)) {
/* device is still not ready. */
break;
}
if (idev) {
if (idev->if_flags & IF_READY)
/* device is already configured. */
break;
idev->if_flags |= IF_READY;
}
pr_info("ADDRCONF(NETDEV_CHANGE): %s: link becomes ready\n",
dev->name);
run_pending = 1;
}
switch (dev->type) {
#if IS_ENABLED(CONFIG_IPV6_SIT)
case ARPHRD_SIT:
addrconf_sit_config(dev);
break;
#endif
#if IS_ENABLED(CONFIG_NET_IPGRE)
case ARPHRD_IPGRE:
addrconf_gre_config(dev);
break;
#endif
case ARPHRD_LOOPBACK:
init_loopback(dev);
break;
default:
addrconf_dev_config(dev);  //⽣成本地链路地址
break;
}
if (!IS_ERR_OR_NULL(idev)) {
if (run_pending)
addrconf_dad_run(idev); //准备跑DAD检测本地链路地址唯⼀性
/*
* If the MTU changed during the interface down,
* when the interface up, the changed MTU must be
* reflected in the idev as well as routers.
*/
if (idev-&u6 != dev->mtu &&
dev->mtu >= IPV6_MIN_MTU) {
rt6_mtu_change(dev, dev->mtu);
idev-&u6 = dev->mtu;
}
idev->tstamp = jiffies;
inet6_ifinfo_notify(RTM_NEWLINK, idev);  //netlink通信告知上层ipv6 link建⽴成功
/*
* If the changed mtu during down is lower than
中产教育鄙视链
* IPV6_MIN_MTU stop IPv6 on this interface.
*/
if (dev->mtu < IPV6_MIN_MTU)
if (dev->mtu < IPV6_MIN_MTU)
addrconf_ifdown(dev, 1);
}
break;
对于NETDEV_UP的处理主要有三点:
1,ipv6_add_dev将⽹络dev加⼊ipv6协议栈中
2,addrconf_dev_config⽣成本地链路地址
3,addrconf_dad_run跑DAD检测链路地址唯⼀性和发送RS报⽂这⾥只看后续发送RS报⽂的地⽅
static void addrconf_dad_work(struct work_struct *w)
{
struct inet6_ifaddr *ifp = container_of(to_delayed_work(w),
struct inet6_ifaddr,
dad_work);
struct inet6_dev *idev = ifp->idev;
struct in6_addr mcaddr;
enum {
DAD_PROCESS,
DAD_BEGIN,
DAD_ABORT,
} action = DAD_PROCESS;
rtnl_lock();
spin_lock_bh(&ifp->state_lock);
if (ifp->state == INET6_IFADDR_STATE_PREDAD) {
action = DAD_BEGIN;
ifp->state = INET6_IFADDR_STATE_DAD;
} else if (ifp->state == INET6_IFADDR_STATE_ERRDAD) {
action = DAD_ABORT;
ifp->state = INET6_IFADDR_STATE_POSTDAD;
}
spin_unlock_bh(&ifp->state_lock);
if (action == DAD_BEGIN) {
addrconf_dad_begin(ifp);
goto out;
} else if (action == DAD_ABORT) {
addrconf_dad_stop(ifp, 1);
goto out;
}
if (!ifp->dad_probes && addrconf_dad_end(ifp))
goto out;
write_lock_bh(&idev->lock);
if (idev->dead || !(idev->if_flags & IF_READY)) {
write_unlock_bh(&idev->lock);
goto out;
}
spin_lock(&ifp->lock);
if (ifp->state == INET6_IFADDR_STATE_DEAD) {
新国学网spin_unlock(&ifp->lock);
write_unlock_bh(&idev->lock);
goto out;
}cnf
if (ifp->dad_probes == 0) {
/*
* DAD was successful
*/
ifp->flags &= ~(IFA_F_TENTATIVE|IFA_F_OPTIMISTIC|IFA_F_DADFAILED);                spin_unlock(&ifp->lock);
write_unlock_bh(&idev->lock);
addrconf_dad_completed(ifp);    //DAD完成就会开始发送RS了
goto out;
}
ifp->dad_probes--;
addrconf_mod_dad_work(ifp,
阈值分割法NEIGH_VAR(ifp->idev->nd_parms, RETRANS_TIME));
spin_unlock(&ifp->lock);
write_unlock_bh(&idev->lock);
/* send a neighbour solicitation for our addr */
addrconf_addr_solict_mult(&ifp->addr, &mcaddr);
ndisc_send_ns(ifp->idev->dev, NULL, &ifp->addr, &mcaddr, &in6addr_any); out:
in6_ifa_put(ifp);
rtnl_unlock();
}
接下来进⼊addrconf_dad_completed

本文发布于:2024-09-20 16:52:17,感谢您对本站的认可!

本文链接:https://www.17tex.com/xueshu/718948.html

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。

标签:发送   内核   系统   对应   路由器   链路   地址
留言与评论(共有 0 条评论)
   
验证码:
Copyright ©2019-2024 Comsenz Inc.Powered by © 易纺专利技术学习网 豫ICP备2022007602号 豫公网安备41160202000603 站长QQ:729038198 关于我们 投诉建议