最近在弄IPV6时,发现一个问题,在pppoe接入时,ppp接口不发RS请求,因为ppp接入时,上级的RADVD是配置为单播的,不会发送广播RA,导致路由器无法获取前缀。
  在UBUNTU主机上测试了一下,发现ifconfig down和up接口都不会发送RS请求,这着实很奇怪。百度google无果。
  最后偶然发现,这是由于打开了IPV6的转发导致,即cat /proc/sys/net/ipv6/conf/all/forwarding为1。在网站http://mirrors.deepspace6.net/Linux+IPv6-HOWTO/proc-sys-net-ipv6..html看到当开启了forwarding之后,就不再往外发送RS请求。可能内核觉得开了转发表示我自己就是路由器了,那我还发什么RS来请求路由呢。
  所以要解决这个问题,需要修改内核发送RS处的逻辑,如何修改可以看下addrconf.c和ndisc.c两个文件的逻辑大概就可以知道如何改了。具体修改可见最下面的差异对比。下面说下,内核何时会发送RS(下面是pppoe拨号时的逻辑)?

内核何时会发送RS
  
  首先ipv6cp阶段双方会确认一个UID,然后pppd进程就会根据这个uid配置链路本地地址,应用层配置地址会触发内核inet6_addr_add >> addrconf_dad_start >> addrconf_dad_completed >> ndisc_send_rs
这里就会发出第一个RS包,并设置定时器,定时器的时间和发包次数可以通过proc配置。如果收到了回复,那么就退出定时器,不再发送RS。
收RA包是在ndisc_rcv >> ndisc_router_discovery处理,里面会解析option信息,标志位,根据前缀配置地址,配置默认路由。

vlan2接口的RS什么时候发呢,差不了太多,是在vlan2起接口配置链路本地地址时发的,只是它是走addrconf_add_linklocal函数。注意:给接口配置链路本地地址才会触发内核发送RS报文。但内核会一直正确处理收到的RA

修改点:
addrconf.c

root@ubuntu:ipv6# diff -u addrconf_old.c addrconf.c
--- addrconf_old.c  2015-06-29 13:40:06.000000000 +0800
+++ addrconf.c  2017-03-29 11:46:10.723980700 +0800
@@ -258,6 +258,26 @@AC_RS,};+/* return 1, is wan dev */
+int is_wan_dev(char* ifname)
+{+    char *wan_ifnames[] = {"vlan2", "eth0.2", "ppp0", "ppp1", "ppp2", "ppp3"};
+    int i = 0;
+
+    if(!ifname)
+        return 0;
+
+    for(i = 0; i < sizeof(wan_ifnames)/sizeof(char*); i++)
+    {+        if(!strcmp(ifname, wan_ifnames[i]))
+            return 1;
+    }
+    return 0;
+}
+
+EXPORT_SYMBOL(is_wan_dev);
+
+static void addrconf_mod_timer(struct inet6_ifaddr *ifp,enum addrconf_timer_t what,unsigned long when)
@@ -270,6 +290,7 @@ifp->timer.function = addrconf_dad_timer;break;case AC_RS:
+       //printk(KERN_DEBUG "llm[%s](%d) %s add a rs timer\n", __FUNCTION__, __LINE__, ifp->idev->dev->name);ifp->timer.function = addrconf_rs_timer;break;default:
@@ -1590,6 +1611,8 @@int err = -1;struct inet6_ifaddr *ifp;+
+    //printk(KERN_DEBUG "llm[%s](%d) %s inherit eui64\n", __FUNCTION__, __LINE__, idev->dev->name);read_lock_bh(&idev->lock);list_for_each_entry(ifp, &idev->addr_list, if_list) {if (ifp->scope == IFA_LINK && !(ifp->flags&IFA_F_TENTATIVE)) {
@@ -1599,6 +1622,8 @@}}read_unlock_bh(&idev->lock);
+
+    //printk(KERN_DEBUG "llm[%s](%d) %s return %d\n", __FUNCTION__, __LINE__, idev->dev->name, err);return err;}@@ -1806,6 +1831,7 @@return;}+    //printk(KERN_DEBUG "llm[%s](%d) %s recv prefix\n", __FUNCTION__, __LINE__, in6_dev->dev->name);/**  Two things going on here:*  1) Add routes for on-link prefixes
@@ -2128,6 +2154,8 @@return PTR_ERR(idev);scope = ipv6_addr_scope(pfx);
+
+    //printk(KERN_DEBUG "llm[%s](%d) %s add addr\n", __FUNCTION__, __LINE__, idev->dev->name);timeout = addrconf_timeout_fixup(valid_lft, HZ);if (addrconf_finite_timeout(timeout)) {
@@ -2346,7 +2374,7 @@addr_flags |= IFA_F_OPTIMISTIC;#endif-
+    //printk(KERN_DEBUG "llm[%s](%d) %s add linklocal\n", __FUNCTION__, __LINE__, idev->dev->name);ifp = ipv6_add_addr(idev, addr, 64, IFA_LINK, addr_flags);if (!IS_ERR(ifp)) {addrconf_prefix_route(&ifp->addr, ifp->prefix_len, idev->dev, 0, 0);
@@ -2789,7 +2817,8 @@if (idev->dead || !(idev->if_flags & IF_READY))goto out;-   if (idev->cnf.forwarding)
+    // llm modify
+   if (idev->cnf.forwarding && !is_wan_dev(idev->dev->name))goto out;/* Announcement received after solicitation was sent */
@@ -2952,7 +2981,9 @@start sending router solicitations.*/-   if (ifp->idev->cnf.forwarding == 0 &&
+    //llm modify
+   if ((ifp->idev->cnf.forwarding == 0 ||
+        is_wan_dev(dev->name)) &&ifp->idev->cnf.rtr_solicits > 0 &&(dev->flags&IFF_LOOPBACK) == 0 &&(ipv6_addr_type(&ifp->addr) & IPV6_ADDR_LINKLOCAL)) {
@@ -2961,6 +2992,8 @@*  [...] as part of DAD [...] there is no need*  to delay again before sending the first RS*/
+
+       //printk(KERN_DEBUG "llm[%s](%d) %s send rs\n", __FUNCTION__, __LINE__, ifp->idev->dev->name);ndisc_send_rs(ifp->idev->dev, &ifp->addr, &in6addr_linklocal_allrouters);spin_lock_bh(&ifp->lock);
@@ -4100,11 +4133,15 @@*/if (!(ifp->rt->rt6i_node))ip6_ins_rt(ifp->rt);
-       if (ifp->idev->cnf.forwarding)
+
+       // llm modify
+       if (ifp->idev->cnf.forwarding && !is_wan_dev(ifp->idev->dev->name))addrconf_join_anycast(ifp);break;case RTM_DELADDR:
-       if (ifp->idev->cnf.forwarding)
+
+       // llm modify
+       if (ifp->idev->cnf.forwarding && !is_wan_dev(ifp->idev->dev->name))addrconf_leave_anycast(ifp);addrconf_leave_solict(ifp->idev, &ifp->addr);dst_hold(&ifp->rt->dst);
root@ubuntu:ipv6# 

ndisc.c

root@ubuntu:ipv6# diff -u ndisc_old.c ndisc.c
--- ndisc_old.c 2015-06-29 13:40:06.000000000 +0800
+++ ndisc.c 2017-03-29 11:44:45.485694700 +0800
@@ -178,6 +178,8 @@#define NDISC_OPT_SPACE(len) (((len)+2+7)&~7)+extern int is_wan_dev(char* ifname);
+/** Return the padding between the option length and the start of the* link addr.  Currently only IP-over-InfiniBand needs this, although
@@ -1021,7 +1023,8 @@}/* Don't accept RS if we're not in router mode */
-   if (!idev->cnf.forwarding)
+   // llm modify
+   if (!idev->cnf.forwarding || is_wan_dev(idev->dev->name))goto out;/*
@@ -1149,6 +1152,7 @@return;}+    //printk(KERN_DEBUG "llm[%s](%d) %s recv RA\n", __FUNCTION__, __LINE__, in6_dev->dev->name);if (!ndisc_parse_options(opt, optlen, &ndopts)) {in6_dev_put(in6_dev);ND_PRINTK2(KERN_WARNING
@@ -1157,7 +1161,9 @@}/* skip route and link configuration on routers */
-   if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
+   // llm modify
+   if ((in6_dev->cnf.forwarding && !is_wan_dev(in6_dev->dev->name))
+       || !in6_dev->cnf.accept_ra)goto skip_linkparms;#ifdef CONFIG_IPV6_NDISC_NODETYPE
@@ -1308,7 +1314,9 @@}/* skip route and link configuration on routers */
-   if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_ra)
+   // llm modify
+   if ((in6_dev->cnf.forwarding && !is_wan_dev(in6_dev->dev->name))
+       || !in6_dev->cnf.accept_ra)goto out;#ifdef CONFIG_IPV6_ROUTE_INFO
@@ -1447,7 +1455,10 @@in6_dev = in6_dev_get(skb->dev);if (!in6_dev)return;
-   if (in6_dev->cnf.forwarding || !in6_dev->cnf.accept_redirects) {+
+   // llm modify
+   if ((in6_dev->cnf.forwarding && !is_wan_dev(in6_dev->dev->name))
+       || !in6_dev->cnf.accept_redirects) {in6_dev_put(in6_dev);return;}
root@ubuntu:ipv6# 

linux内核不发(Router Solicit)RS报文问题相关推荐

  1. 查看Linux内核及发行商版本命令

    一.查看Linux内核版本命令(两种方法): 1. cat /proc/version Linux version 3.10.0-327.el7.x86_64 (builder@kbuilder.de ...

  2. linux内核协议栈 邻居协议之 arp 数据包收发处理流程

    目录 前言 1 arp数据包文接收 arp_rcv() 1.1 处理arp请求 arp_process()[核心] 2 arp数据包发送 arp_send() 2.1 arp 数据包构造 arp_cr ...

  3. 【转】Linux内核报文收发

    赵占旭的博客 Linux内核报文收发-网卡部分 https://zhaozhanxu.com/2016/07/12/Linux/2016-07-12-Linux-Kernel-Pkts_Process ...

  4. linux内核中如何修改skb报文

    前言 在内核开发中,我们很多时候需要修改linux网络数据包的内容.那么怎样修改skb报文才正确?这个问题在网上的资料讲解的不是很全,下面是我这几天梳理的步骤 skb修改数据包流程 -内核代码中有许多 ...

  5. linux内核丢弃udp报文,c++ Linux UDP数据包丢失的原因

    我有一个 Linux C应用程序接收有序的UDP数据包.由于排序,我可以很容易地确定数据包何时丢失或重新排序,即当遇到"间隙"时.该系统具有处理差距的恢复机制,但最好避免出现差距. ...

  6. linux内核丢弃udp报文,内核udp报文截取、修改和发送

    近来做一个产品需要在网关上获取特定UDP端口(假设是1000端口)的报文,并将其转发给其它设备的1000端口.虽然此类文章网上已经有很多了,但我还是贴上来,这样自己也做下记录,大家也多一份参考. 下面 ...

  7. linux 内核开发huu红山竹发布于 2019-12-23linux的体系结构

    linux的体系结构 从大的方面可以分为用户空间(User Space)和内核空间(Kernal Space). 用户空间 C库 用户应用程序 shell(某些体系包含) 内核空间 硬件平台 平台依赖 ...

  8. Linux内核邻接子系统(arp协议)的工作原理

    主要参考了<深入linux内核架构>和<精通Linux内核网络>相关章节 文章目录 Linux内核邻接子系统(二层到三层) 邻接子系统的核心 struct neighbour ...

  9. linux内核网络协议栈--监控和调优:发送数据(三十)

    译者序 本文翻译自 2017 年的一篇英文博客 Monitoring and Tuning the Linux Networking Stack: Sending Data.如果能看懂英文,建议阅读原 ...

最新文章

  1. vmware 共享文件夹(win10下的vmware安装了centos7)
  2. springboot项目中session和cookie
  3. 不同特权级代码段之间的跳转
  4. 答与微博前端教主在吃饭时讨论到的一道微软面试题
  5. linux常用的脚本、命令
  6. 百度大脑公开课!快速定制高精度计算机视觉模型
  7. .NET简谈组件程序设计之(渗入序列化过程)
  8. 典型微型计算机的基本结构包括,第二章 微型计算机基础.doc
  9. 190305每日一句
  10. java 应用编程接口_java 应用程序接口(api)是什么
  11. 基于Arduino和Mixly(超声波+蜂鸣器)实现距离报警
  12. 离散数学2:命题逻辑的推理
  13. 懒羊羊的作业:看过国产动画片的同学都知道,懒羊羊是一只非常懒的羊,整天除了吃就是睡,根本没有时间做作业。明天就是周一了,村长慢羊羊留的作业:把 n 个整数从大到小排序,它还没开始写...
  14. 在校园网中进行无线路由器设置
  15. BGP路由协议的那些事?(上)
  16. 2015年3月美国桌面搜索份额:Bing首超20%,谷歌、雅虎均下跌
  17. 软件工程(速成)——第三章 需求分析
  18. 2023王道考研数据结构第一章---基本概念
  19. cs/bs软件架构优缺点
  20. Day6:可靠数据传输的原理

热门文章

  1. 博客园php教程,PHP仿博客园,个人博客(1)_PHP教程
  2. lateX 编译中文_LaTeX | 为学术论文排版而生【入门篇】
  3. vue标准时间改为时间戳_2021考研网上确认照片采集新标准公布 网上确认时间表...
  4. category和extension的区别
  5. 配置 MySQL 服务器容器
  6. React Native按钮详解|Touchable系列组件使用详解
  7. 集成Glide4.3.1出错!AbstractMethodError: abstract method void com.bumptech.glide.module
  8. nginx - 性能优化
  9. 8皇后问题--回溯法 (循环递归)
  10. linux上的一些命令