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

本文详细介绍了在Android系统中开启IPv6功能时,内核中的RS(Router Solicitation)和RA(Router Advertisement)处理流程。通过分析addrconf_sysctl_disable等函数,揭示了如何触发发送RS报文,以及RA报文接收后如何设置路由和生成全局IPv6地址。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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)
                                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->t
### IPv6 邻居发现协议 (NDP) 的工作原理 IPv6 邻居发现协议 (NDP) 是一种用于执行各种本地链路操作的基础工具集[^2]。该协议替代了传统的 IPv4 地址解析协议 (ARP),并引入了一种更高效的方式来进行地址解析、邻居可达性检测以及其他网络管理任务[^3]。 #### 工作机制概述 NDP 使用五种 ICMPv6 消息类型来完成其功能,这些消息包括: - **路由器请求 (Router Solicitation)** 和 **路由器通告 (Router Advertisement)**:用于主机获取网络中的默认网关信息。 - **邻居请求 (Neighbor Solicitation)** 和 **邻居通告 (Neighbor Advertisement)**:用于地址解析和邻居状态确认。 - **重定向消息 (Redirect Message)**:允许路由器指导主机选择更好的下一跳路径。 以下是 NDP 的主要功能及其工作机制: 1. **地址解析** 当一台设备需要知道另一台设备的链路层地址时,它会发送一个邻居请求 (NS) 消息给目标节点。目标节点收到此消息后,将以邻居通告 (NA) 响应源节点,提供其链路层地址[^4]。 2. **邻居不可达性检测** 如果某个邻居被认为可能已失效,则可以通过定期发送 NS/NA 消息对邻居的状态进行验证。如果连续多次尝试失败,则认为邻居不可到达。 3. **重复地址检测 (DAD)** 在分配新的接口标识符之前,设备会向潜在冲突的目标地址发送 NS 消息。如果没有接收到任何 NA 响应,则可以安全地假设该地址未被占用。 4. **路由器发现** 主机通过监听 RA 消息或者主动发出 RS 请求,从而得知当前子网上可用的路由器列表及其属性(如前缀长度、MTU 等)。这有助于动态配置无状态自动化的 IP 地址分配过程。 5. **重定向优化路由决策** 路由器能够利用 Redirect Messages 来建议特定流量的最佳下一跳位置,帮助减少不必要的数据包转发次数,提高整体效率。 #### 配置方法示例 以下是一个简单的 Linux 平台上启用和查看 ND 功能的例子: ```bash # 启用 IPv6 协议栈支持 sysctl net.ipv6.conf.all.disable_ipv6=0 # 查看当前系统的 Router Advertisements 设置情况 ip -6 neigh show # 手动触发一次 DAD 测试流程 ndisc6 -r fe80::abcd:efgh %eth0 ``` 上述命令展示了如何调整操作系统内核参数以确保正常运行 IPv6 及其关联服务;同时也演示了一些常用的诊断工具调用方式以便于排查可能出现的问题。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值