Busybox: 解决IPV6路由表删除时遇到的:No Such Process问题
2012-12-17 13:34
429 查看
环境:
嵌入式系统,Busybox-1.00版本,IPV6网络环境,DHCPV6动态获取网关和路由信息。
问题:
当使用route命令尝试删除默认网关:route -A inet6 del ::/0 gw 2001::1 dev br0
操作失败,系统温馨提示: SIOC[ADD|DEL]RT: No Such Process
分析:
Busybox-1.00是enbale了IPV6的支持选项的。同时从DHCP Server处获取的默认网关也是正确的。使用 route -A inet6 命令获取默认网关的相关信息如下:
Destination Next HopFlagMetricRefUseIface
2001::1/64::/0U102400br0
从Busybox-1.00的源码入手分析route del命令。route命令对应的源文件位于: busybox-1.00/networking/route.c位置处。从代码中查找"SIOC[ADD|DEL]RT: No Such Process"错误字符串,未果。发现在代码的440行,有一个函数调用可能比较相关:
00439: if(ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0){
00440: bb_perror_msg_and_die("SIOC[ADD|DEL]RT");
00441: }
从该段代码中可以看出,No Such Process的错误应该是由ioctl返回的ErrorCode映射生成的。而ioctl系统调用是实现了busybox和kernel通信的一个接口。由于我们使用的是del命令,所以传给kernel的命令应该是SIOCDELRT。内核为什么在处理这个命令的时候返回No Such Process错误呢? Linux的最大好处就是,如果你想搞清楚一个问题,你总是能够搞清楚它的原因。因为Kernel也是开放源码的。接下来,我们就进Kernel看看,SIOCDELRT是如何被处理的。
Kernel中处理IPV6路由表设置的主要的代码位于:net/ipv6/route.c中。可以很方便找到处理SIOCDELRT命令的函数:ip6_route_del()。以下是ip6_route_del()函数的大体流程。
+ expand sourceview plaincopy
to clipboardprint?
我们首先看到返回值err被初始化成:-ESRCH。这是什么一个宏呢?在include/asm-generic/error-base.h文件中定义如下:
#define ESRCH 3 /* No such process */
多么熟悉的一个错误啊。:) 所以我们了解到原来No such process在kernel中就是被定义成ESRCH宏的。从字面上的意思理解,应该是在路由表中没有找到相应的item。是在哪里出错返回的呢?从代码中看,可能的返回值是-ESRCH以及__ip6_del_rt()函数的返回值。而__ip6_del_rt()函数是不会返回No such process错误的。所以我们根本没有进入到__ip6_del_rt()调用。经过分析,有以下4个point可能会导致该函数提前返回。
Point1: 返回的fn是NULL。
fn = fib6_locate(&table->tb6_root,&cfg->fc_dst, cfg->fc_dst_len,&cfg->fc_src, cfg->fc_src_len);
Point2-Point4:
if (fn) {
for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {
if (cfg->fc_ifindex && (rt->rt6i_dev == NULL || rt->rt6i_dev->ifindex != cfg->fc_ifindex))
continue; // Point 2
if (cfg->fc_flags & RTF_GATEWAY && !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
continue; // Point 3
if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
continue; // Point 4
... ...
return __ip6_del_rt(rt, &cfg->fc_nlinfo);
}
}
最后通过在kernel中插入debug信息,发现为题出现在Point4。原因在于:cfg->fc_metric == 1 而 rt->rt6i_metric == 1024。问题很明确了busybox传进来的metric和内核从路由表中查到的metric不一致。根据我们route -A inet6命令查询出来的结果来看,正确的metric应该是1024,意味着busybox传错了参数。回到busybox中看看为什么metric传的是1?还是busybox-1.00/networking/route.c文件,相关代码如下:
view plaincopy to clipboardprint?
static void INET6_setroute(int action,
char **args)
{
struct sockaddr_in6 sa6;
struct in6_rtmsg rt;
int prefix_len, skfd;
const char *devname;
assert((action == RTACTION_ADD) || (action == RTACTION_DEL));
{
/* We know args isn't NULL from the check in route_main. */
const char *target = *args++;
if (strcmp(target,
"default") == 0) {
prefix_len = 0;
memset(&sa6, 0, sizeof(sa6));
} else {
char *cp;
if ((cp = strchr(target,
'/'))) { /* Yes... const to non is ok. */
*cp = 0;
prefix_len = bb_xgetularg10_bnd(cp+1, 0, 128);
} else {
prefix_len = 128;
}
if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
bb_error_msg_and_die("resolving %s", target);
}
}
}
/* Clean out the RTREQ structure. */
memset((char *) &rt, 0,
sizeof(struct in6_rtmsg));
memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr,
sizeof(struct in6_addr));
/* Fill in the other fields. */
rt.rtmsg_dst_len = prefix_len;
rt.rtmsg_flags = ((prefix_len == 128) ? (RTF_UP|RTF_HOST) : RTF_UP);
rt.rtmsg_metric = 1;
...
}
最后一行已经明确了busybox的错误!!
针对这一问题,如何修改呢?其实很简单,我们只需要把rt.rtmsg_metric = 1;改成rt.rtmsg_metric = 0;即可。当metric被设置成0的时候,就是告诉内核忽略该项参数的检查。
嵌入式系统,Busybox-1.00版本,IPV6网络环境,DHCPV6动态获取网关和路由信息。
问题:
当使用route命令尝试删除默认网关:route -A inet6 del ::/0 gw 2001::1 dev br0
操作失败,系统温馨提示: SIOC[ADD|DEL]RT: No Such Process
分析:
Busybox-1.00是enbale了IPV6的支持选项的。同时从DHCP Server处获取的默认网关也是正确的。使用 route -A inet6 命令获取默认网关的相关信息如下:
Destination Next HopFlagMetricRefUseIface
2001::1/64::/0U102400br0
从Busybox-1.00的源码入手分析route del命令。route命令对应的源文件位于: busybox-1.00/networking/route.c位置处。从代码中查找"SIOC[ADD|DEL]RT: No Such Process"错误字符串,未果。发现在代码的440行,有一个函数调用可能比较相关:
00439: if(ioctl(skfd, ((action==RTACTION_ADD) ? SIOCADDRT : SIOCDELRT), &rt)<0){
00440: bb_perror_msg_and_die("SIOC[ADD|DEL]RT");
00441: }
从该段代码中可以看出,No Such Process的错误应该是由ioctl返回的ErrorCode映射生成的。而ioctl系统调用是实现了busybox和kernel通信的一个接口。由于我们使用的是del命令,所以传给kernel的命令应该是SIOCDELRT。内核为什么在处理这个命令的时候返回No Such Process错误呢? Linux的最大好处就是,如果你想搞清楚一个问题,你总是能够搞清楚它的原因。因为Kernel也是开放源码的。接下来,我们就进Kernel看看,SIOCDELRT是如何被处理的。
Kernel中处理IPV6路由表设置的主要的代码位于:net/ipv6/route.c中。可以很方便找到处理SIOCDELRT命令的函数:ip6_route_del()。以下是ip6_route_del()函数的大体流程。
+ expand sourceview plaincopy
to clipboardprint?
我们首先看到返回值err被初始化成:-ESRCH。这是什么一个宏呢?在include/asm-generic/error-base.h文件中定义如下:
#define ESRCH 3 /* No such process */
多么熟悉的一个错误啊。:) 所以我们了解到原来No such process在kernel中就是被定义成ESRCH宏的。从字面上的意思理解,应该是在路由表中没有找到相应的item。是在哪里出错返回的呢?从代码中看,可能的返回值是-ESRCH以及__ip6_del_rt()函数的返回值。而__ip6_del_rt()函数是不会返回No such process错误的。所以我们根本没有进入到__ip6_del_rt()调用。经过分析,有以下4个point可能会导致该函数提前返回。
Point1: 返回的fn是NULL。
fn = fib6_locate(&table->tb6_root,&cfg->fc_dst, cfg->fc_dst_len,&cfg->fc_src, cfg->fc_src_len);
Point2-Point4:
if (fn) {
for (rt = fn->leaf; rt; rt = rt->u.dst.rt6_next) {
if (cfg->fc_ifindex && (rt->rt6i_dev == NULL || rt->rt6i_dev->ifindex != cfg->fc_ifindex))
continue; // Point 2
if (cfg->fc_flags & RTF_GATEWAY && !ipv6_addr_equal(&cfg->fc_gateway, &rt->rt6i_gateway))
continue; // Point 3
if (cfg->fc_metric && cfg->fc_metric != rt->rt6i_metric)
continue; // Point 4
... ...
return __ip6_del_rt(rt, &cfg->fc_nlinfo);
}
}
最后通过在kernel中插入debug信息,发现为题出现在Point4。原因在于:cfg->fc_metric == 1 而 rt->rt6i_metric == 1024。问题很明确了busybox传进来的metric和内核从路由表中查到的metric不一致。根据我们route -A inet6命令查询出来的结果来看,正确的metric应该是1024,意味着busybox传错了参数。回到busybox中看看为什么metric传的是1?还是busybox-1.00/networking/route.c文件,相关代码如下:
view plaincopy to clipboardprint?
static void INET6_setroute(int action,
char **args)
{
struct sockaddr_in6 sa6;
struct in6_rtmsg rt;
int prefix_len, skfd;
const char *devname;
assert((action == RTACTION_ADD) || (action == RTACTION_DEL));
{
/* We know args isn't NULL from the check in route_main. */
const char *target = *args++;
if (strcmp(target,
"default") == 0) {
prefix_len = 0;
memset(&sa6, 0, sizeof(sa6));
} else {
char *cp;
if ((cp = strchr(target,
'/'))) { /* Yes... const to non is ok. */
*cp = 0;
prefix_len = bb_xgetularg10_bnd(cp+1, 0, 128);
} else {
prefix_len = 128;
}
if (INET6_resolve(target, (struct sockaddr_in6 *) &sa6) < 0) {
bb_error_msg_and_die("resolving %s", target);
}
}
}
/* Clean out the RTREQ structure. */
memset((char *) &rt, 0,
sizeof(struct in6_rtmsg));
memcpy(&rt.rtmsg_dst, sa6.sin6_addr.s6_addr,
sizeof(struct in6_addr));
/* Fill in the other fields. */
rt.rtmsg_dst_len = prefix_len;
rt.rtmsg_flags = ((prefix_len == 128) ? (RTF_UP|RTF_HOST) : RTF_UP);
rt.rtmsg_metric = 1;
...
}
最后一行已经明确了busybox的错误!!
针对这一问题,如何修改呢?其实很简单,我们只需要把rt.rtmsg_metric = 1;改成rt.rtmsg_metric = 0;即可。当metric被设置成0的时候,就是告诉内核忽略该项参数的检查。
相关文章推荐
- Busybox: 解决IPV6路由表删除时遇到的:No Such Process问题
- Busybox: 解决IPV6路由表删除时遇到的:No Such Process问题
- 解决IPV6路由表删除时遇到的:No Such Process问题
- 升级gcc4.8 遇到 fatal error: gnu/stubs-32.h: No such file or directory 问题的解决方法
- 如何恢复误删除的rpm包命令解决-bash: /usr/bin/yum: No such file or directory的问题
- QT中 No such file or directory 问题解决
- 问题解决 错误 C1083 无法打开包括文件: “thirdparty/textDetect/erfilter.hpp”: No such file or directory
- cygwin下trying to exec 'cc1': execvp: No such file or directory 问题的解决
- 关于java学习之中遇到的一些问题之:java.util.NoSuchElementException.
- ubuntu下解决expat.h: No such file or directory的问题
- 安全狗导致IIS Worker Process 遇到了一个问题和错误模块 ntdll.dll的解决方法
- nginx平滑重启过程中提示[alert] kill(2942, 1) failed (No such process)问题分析及解决方案
- 解决cocoapods diff: /../Podfile.lock: No such file or directory以及iOS开发同一应用多环境配置的问题
- nginx: [alert] kill(2480, 10) failed (3: No such process)的解决办法
- 全面解决Generic host process for win32 services遇到问题需要关闭
- azkaban-executor启动时出现conf/global.properties (No such file or directory)的问题解决(图文详解)
- Xlib.h No such file or directory 问题解决
- [Linux vim问题解决] -bash: ./script.sh: /usr/bin/bash^M: bad interpreter: No such file or directory
- eclipse打jar包、解决nosuchmethoderror 问题
- QT5.1在Windows下 出现QApplication: No such file or directory 问题的解决办法