linux内核不发(Router Solicit)RS报文问题

  最近在弄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# 
相关推荐
©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页