在接收到邻居发现协议的RA(Router Advertisement)报文之后,由ndisc_router_discovery处理。首先,以此报文的源地址查找是否存在默认的路由器(rt6_get_dflt_router),并检测是否存在可达的邻居表项,释放此路由信息。

如果RA通告的路由时长为零,并且本机中存在以其为默认路由的路由信息,表明要删除此默认路由信息。

static void ndisc_router_discovery(struct sk_buff *skb)
{struct fib6_info *rt = NULL;lifetime = ntohs(ra_msg->icmph.icmp6_rt_lifetime);/* routes added from RAs do not use nexthop objects */rt = rt6_get_dflt_router(net, &ipv6_hdr(skb)->saddr, skb->dev);if (rt) {neigh = ip6_neigh_lookup(&rt->fib6_nh->fib_nh_gw6,rt->fib6_nh->fib_nh_dev, NULL, &ipv6_hdr(skb)->saddr);if (!neigh) {ND_PRINTK(0, err, "RA: %s got default router without neighbour\n", __func__);fib6_info_release(rt);return;}}if (rt && lifetime == 0) {ip6_del_rt(net, rt, false);rt = NULL;}ND_PRINTK(3, info, "RA: rt: %p  lifetime: %d, for dev: %s\n", rt, lifetime, skb->dev->name);

其次,如果以上路由信息为空,并且本次通告的有效时长不为零,根据报文源地址添加默认路由器,并进行邻居表项检查。

    if (!rt && lifetime) {ND_PRINTK(3, info, "RA: adding default router\n");rt = rt6_add_dflt_router(net, &ipv6_hdr(skb)->saddr, skb->dev, pref);if (!rt) {ND_PRINTK(0, err, "RA: %s failed to add default route\n", __func__);return;}neigh = ip6_neigh_lookup(&rt->fib6_nh->fib_nh_gw6,rt->fib6_nh->fib_nh_dev, NULL, &ipv6_hdr(skb)->saddr);if (!neigh) {ND_PRINTK(0, err, "RA: %s got default router without neighbour\n",  __func__);fib6_info_release(rt);return;}neigh->flags |= NTF_ROUTER;} else if (rt) {rt->fib6_flags = (rt->fib6_flags & ~RTF_PREF_MASK) | RTF_PREF(pref);}if (rt)fib6_set_expires(rt, jiffies + (HZ * lifetime));if (in6_dev->cnf.accept_ra_min_hop_limit < 256 && ra_msg->icmph.icmp6_hop_limit) {if (in6_dev->cnf.accept_ra_min_hop_limit <= ra_msg->icmph.icmp6_hop_limit) {in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;fib6_metric_set(rt, RTAX_HOPLIMIT, ra_msg->icmph.icmp6_hop_limit);} else {ND_PRINTK(2, warn, "RA: Got route advertisement with lower hop_limit than minimum\n");}}

查找默认路由器

遍历路由表中所有的叶子节点,查找符合的路由信息。对于默认路由器,一定不包含nexthop属性,跳过此类路由信息。将当前遍历的路由信息的出口设备、标志、和下一跳网关与参数进行对比,全部相同表明找到路由信息。

struct fib6_info *rt6_get_dflt_router(struct net *net, const struct in6_addr *addr, struct net_device *dev)
{u32 tb_id = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT;struct fib6_info *rt;struct fib6_table *table;table = fib6_get_table(net, tb_id);if (!table)return NULL;rcu_read_lock();for_each_fib6_node_rt_rcu(&table->tb6_root) {struct fib6_nh *nh;/* RA routes do not use nexthops */if (rt->nh) continue;nh = rt->fib6_nh;if (dev == nh->fib_nh_dev &&((rt->fib6_flags & (RTF_ADDRCONF | RTF_DEFAULT)) == (RTF_ADDRCONF | RTF_DEFAULT)) &&ipv6_addr_equal(&nh->fib_nh_gw6, addr))break;}

添加默认路由器

调用通用函数ip6_route_add添加默认路由器,这里协议设定为RTPROT_RA,表明是根据RA报文生成。在默认路由器添加成功之后,将当前的路由表增加RT6_TABLE_HAS_DFLT_ROUTER标志,之后在查询默认路由器表项时会用到,起到加速查找的作用。

struct fib6_info *rt6_add_dflt_router(struct net *net,const struct in6_addr *gwaddr, struct net_device *dev, unsigned int pref)
{struct fib6_config cfg = {.fc_table   = l3mdev_fib_table(dev) ? : RT6_TABLE_DFLT,.fc_metric  = IP6_RT_PRIO_USER,.fc_ifindex = dev->ifindex,.fc_flags   = RTF_GATEWAY | RTF_ADDRCONF | RTF_DEFAULT |RTF_UP | RTF_EXPIRES | RTF_PREF(pref),.fc_protocol = RTPROT_RA,.fc_type = RTN_UNICAST,.fc_nlinfo.portid = 0,.fc_nlinfo.nlh = NULL,.fc_nlinfo.nl_net = net,};cfg.fc_gateway = *gwaddr;if (!ip6_route_add(&cfg, GFP_ATOMIC, NULL)) {struct fib6_table *table;table = fib6_get_table(dev_net(dev), cfg.fc_table);if (table)table->flags |= RT6_TABLE_HAS_DFLT_ROUTER;}return rt6_get_dflt_router(net, gwaddr, dev);

清除默认路由器

当用户修改PROC文件中的forwarding值时,清除默认路由器。PROC文件:/proc/sys/net/ipv6/conf/all/forwarding,forwarding的值决定系统遵循IPv6主机还是路由器行为。

static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int newf)
{...if (newf)rt6_purge_dflt_routers(net);return 1;
}

遍历系统中的所有路由表(由256个数组以及每个数组元素为头的哈希链表组成),检查每个表中是否包含默认路由器(RT6_TABLE_HAS_DFLT_ROUTER),由函数__rt6_purge_dflt_routers处理。

void rt6_purge_dflt_routers(struct net *net)
{struct fib6_table *table;struct hlist_head *head;unsigned int h;rcu_read_lock();for (h = 0; h < FIB6_TABLE_HASHSZ; h++) {head = &net->ipv6.fib_table_hash[h];hlist_for_each_entry_rcu(table, head, tb6_hlist) {if (table->flags & RT6_TABLE_HAS_DFLT_ROUTER)__rt6_purge_dflt_routers(net, table);}}

遍历路由表中的所有叶子节点,删除其中的默认路由器。默认路由器路由信息包括标志位(RTF_DEFAULT和RTF_ADDRCONF)。对于accept_ra为零时,不接收RA报文,删除默认路由器。accept_ra为1时,如果forwarding禁用,系统为IPv6主机,接收RA报文,此时路由表中可能包含默认路由器。

对于accept_ra等于2的情况,即forwarding启用,系统为IPv6路由器,但是接收其它路由器的RA报文,此时不删除默认路由器。

函数最后,清除路由表中的标志RT6_TABLE_HAS_DFLT_ROUTER,此路由表中不包含默认路由器。

static void __rt6_purge_dflt_routers(struct net *net, struct fib6_table *table)
{struct fib6_info *rt;restart:rcu_read_lock();for_each_fib6_node_rt_rcu(&table->tb6_root) {struct net_device *dev = fib6_info_nh_dev(rt);struct inet6_dev *idev = dev ? __in6_dev_get(dev) : NULL;if (rt->fib6_flags & (RTF_DEFAULT | RTF_ADDRCONF) &&(!idev || idev->cnf.accept_ra != 2) && fib6_info_hold_safe(rt)) {rcu_read_unlock();ip6_del_rt(net, rt, false);goto restart;}}rcu_read_unlock();table->flags &= ~RT6_TABLE_HAS_DFLT_ROUTER;

内核版本 5.10

IPv6邻居发现协议添加默认路由相关推荐

  1. IPV6邻居发现协议(NDP)

    概述 NDP(Neighbor Discovery Protocol,邻居发现协议)是IPv6的一个关键协议,它组合了IPv4中的ARP.ICMP路由器发现和ICMP重定向等协议,并对它们作了改进.作 ...

  2. IPv6邻居发现协议--NDP详解

    一.ICMPv6 -Internet控制报文协议 ICMPv6是IPV6的基础协议之一,用于向源节点传递报文转发的信息或错误 协议类型号(即:IPv6Next Header)为58 icmpv6可以提 ...

  3. linux ipv6邻居信息,IPv6邻居发现协议基本原理

    IPv6邻居发现协议提供下列功能:无服务器自动配置.路由器发现.前缀发现.解析.邻居不可达检测.链路MTU发现.下一跳决定和重复检测等. IPv6邻居发现协议定义了5种ICMPv6包: 路由器请求(R ...

  4. IPv6邻居发现协议NDP

    邻居发现协议NDP 邻居发现协议NDP(Neighbor Discovery Protocol)是IPv6协议体系中一个重要的基础协议.邻居发现协议替代了IPv4的ARP(Address Resolu ...

  5. IPv6邻居发现协议

    邻居发现协议NDP 邻居发现协议NDP(Neighbor Discovery Protocol)是IPv6协议体系中一个重要的基础协议.邻居发现协议替代了IPv4的ARP(Address Resolu ...

  6. IPV6 邻居发现协议(NDP)

    IPV6除了显著增加了地址空间外,另一个最显著的特征就是它的即插即用性. 邻居发现协议(Neighbor Discovery Protocol,NDP)就是使用以下的功能实现即插即用特性的协议: 路由 ...

  7. IPv6邻居发现协议ND学习笔记

    我们都或多或少的听说过IPv6的地址是可以自动生成的吧,那么这个自动生成是怎么生成的大家知道吗,我们来ND协议里一起寻找答案吧! 一,ND协议定义 ND(邻居发现协议)协议是IPv6非常重要的基础协议 ...

  8. 让IPv6强大的关键——NDP邻居发现协议

    邻居发现协议NDP 一.简述 二.NDP消息 三.地址解析(类PIv4的ARP) IPv6地址解析过程分析 简述 详细抓包过程 邻居通告报文中Flags字段解释: 四.邻居不可达检测(NUD) 五.重 ...

  9. ipv6单播地址包括哪两种类型_IPV6中为啥没有ARP了呢?一文带你搞懂NDP邻居发现协议...

    前言 前面我们介绍了ICMPv6协议 除了提供ICMPv4常用的基本功能之外,还有邻居发现(ND)的功能.一文带你看懂ICMPv6和ICMPv4的区别 那么究竟什么是邻居发现协议(ND)呢? 邻居发现 ...

最新文章

  1. mysql的dockerfile_Dockerfile构建MySQL
  2. Jar文件的小小总结(原创)
  3. 前端预览word文件_2020国开形考计算机练习题Word练习
  4. Lable 换行动态计算高度(2种)
  5. C语言技巧:把单一元素的数组放在末尾,struct可以拥有可变大小的数组
  6. python的集成开发环境搭建_Window版本 - Python数据分析集成开发环境 Anaconda安装(超详细)...
  7. 大数据人工智能物联网论文_物联网学报“大数据”相关论文汇总
  8. 腾讯联手华为!将让腾讯游戏越跑越快
  9. 学习mysql随笔——mysql的安装启动
  10. 多重背包O(N*V)算法详解(——使用单调队列)
  11. cmake使用教(一)多目录下多个文件的构建
  12. react中dispatch_reactjs – TypeError:dispatch不是函数.在React无状态组件中
  13. 四苯基卟啉(TPP);硝基卟啉(TPP-NOz);锌卟啉(TPP-Zn)的合成路线/实物图/结构式-齐岳供应
  14. Java获取不到tfp目录内容_AndroidRuntime引起:java.lang.unsatisfiedLinkError:无法加载tfp_jni:findLibrary返回null...
  15. 解除同居关系时共同财产的分割
  16. Java实现若干个数计算平均值并保留小数位 java计算平均值 java四舍五入保留小数
  17. JDBC 第一章 JDBC概述
  18. java基础知识学习小总结(一)
  19. 超实用的Excel自动排序小技巧,原来这么简单,早点知道就好了!
  20. 又酸啦!华为「天才少年」校招薪资曝光....

热门文章

  1. 2022 世界人工智能大会,都讲了些啥?
  2. 对中国标准时间(CST)和中国夏令时(CDT)的不同处理
  3. Python之任意阶幻方的构造
  4. 我对INFOR WMS实施的一些感想
  5. 芝士满满:TikTok快速吸粉视频技巧
  6. 【重磅推荐】哥大开源“FinRL”: 一个用于量化金融自动交易的深度强化学习库
  7. kubernetes dev client-go 进入pod执行命令
  8. Arduino使用手指测心跳模块
  9. WinRar去除弹窗广告的学习和研究
  10. Linux设置登录密码错误次数限制