Chinaunix

标题: linux kernelspace route 操作 [打印本页]

作者: meijusan123    时间: 2009-10-21 11:58
标题: linux kernelspace route 操作
做过linux userspace程序的的朋友对路由的操作基本有很多种方式,如:rtnetlink,ioctl,等控制,可以读出所有或部分指定路由表信息,删除或增加路由表信息。

但,在linux kernelspace中,内核中要实现对路由表读取,删除或增加等操作。哪些方式的api接口提供调用呀?
请 大虾 指点

难道 ,只能手动对struct fib_table 结构操作才可以吗?
作者: meijusan123    时间: 2009-10-22 09:17
struct fib_table {
        unsigned char        tb_id;
        unsigned        tb_stamp;
        int                (*tb_lookup)(struct fib_table *tb, const struct flowi *flp, struct fib_result *res);
        int                (*tb_insert)(struct fib_table *table, struct rtmsg *r,
                                     struct kern_rta *rta, struct nlmsghdr *n,
                                     struct netlink_skb_parms *req);
        int                (*tb_delete)(struct fib_table *table, struct rtmsg *r,
                                     struct kern_rta *rta, struct nlmsghdr *n,
                                     struct netlink_skb_parms *req);
        int                (*tb_dump)(struct fib_table *table, struct sk_buff *skb,
                                     struct netlink_callback *cb);
        int                (*tb_flush)(struct fib_table *table);
        void                (*tb_select_default)(struct fib_table *table,
                                             const struct flowi *flp, struct fib_result *res);

        unsigned char        tb_data[0];
};
这个结构,就是整个路由表所要操作的结构。
路由表本身不是由一个结构表示,而是由多个结构组合而成。路由表可以说是一个分层的结构组合。在第一层,它先将所有的路由根据子网掩码(netmask)的长度(0~32)分成33个部分(struct fn_zone),然后在同一子网掩码(同一层)中,再根据子网的不同(如10.1.1.0/24和10.1.2.0/24),划分为第二层(struct fib_node),在同一子网中,有可能由于TOS等属性的不同而使用不同的路由,这就是第三层(struct fib_alias),第三层结构表示一个路由表项,而每个路由表项又包括一个相应的参数,如协议,下一跳路由地址等等,这就是第四层(struct fib_info)。分层的好处是显而易见的,它使路由表的更加优化,逻辑上也更加清淅,并且使数据可以共享(如struct fib_info),从而减少了数据的冗余。

file:///G:/Documents%20and%20Settings/Administrator/桌面/d92b79eb163c48bbb4c0d57e58d1d887.jpg
作者: meijusan123    时间: 2009-10-22 15:52
研究发现 ,可以直接调用int ip_rt_ioctl(unsigned int cmd, void __user *arg);来多路由表的操作。
但,为什么,我编译时,总是提示
:WARNING: "ip_rt_ioctl"  undefined!
是不是,ip_rt_ioctl 接口函数就不能在kernel被调用。


郁闷 大虾 帮忙解决下哦!!
作者: zdwxck    时间: 2009-10-23 10:38
缺少头文件吧?
作者: godbach    时间: 2009-10-23 14:25
内核代码ipt_REJECT.c中有一个send_reset函数,里面涉及到路由的修改,LZ可以参考一下
作者: meijusan123    时间: 2009-10-26 09:25
标题: 回复 #4 zdwxck 的帖子
头文件,或extern都用了。但没用。

现在的问题是,内核编程时,内核是一个完整的镜像文件,相当于一个大的模块体结合,如果要把自身的方法或变量让外面使用,必须符号导出才可以,一般的加头文件,extern没用。毕竟,这不是用户层程序开发。

就相当于内核模块与模块之间的资源共享一样,只有符号导出才可调用,不然,没办法!
作者: meijusan123    时间: 2009-10-26 09:29
原帖由 godbach 于 2009-10-23 14:25 发表
内核代码ipt_REJECT.c中有一个send_reset函数,里面涉及到路由的修改,LZ可以参考一下


版主的意思,我知道。
你所说的这段代码是用于内核协议栈的重新路由,以前我用过。

但,我现在要实现的东西部室重新路由那么复杂的过程,只要对路由表的删除,增加,查询操作。只是想让在用户层实现的东西,放到内核中实现。现在是找到了接口,但是出现了符号导出问题,内核资源被限制,无法使用。

2.6.15版本kernel还是可以使用ip_rt_ioctl()操作路由表的,但现在2.6.18版本kernel就无法符号导出了。咋整???
作者: Godbach    时间: 2009-10-26 10:02
2.6.15版本kernel还是可以使用ip_rt_ioctl()操作路由表的,但现在2.6.18版本kernel就无法符号导出了。咋整???

你指的是原有内核版本中没有导出吧,可以自己导出啊
作者: meijusan123    时间: 2009-10-26 10:18
原帖由 Godbach 于 2009-10-26 10:02 发表

你指的是原有内核版本中没有导出吧,可以自己导出啊


自己手动导出,就需修改本来的内核文件,重新编译kernel了。
目前,我这功能是在linux的pc上运行的。不能给用户的客户机上重编译kernel的。

有没别的办法整!!
作者: meijusan123    时间: 2009-10-26 10:19
或是,有没内核中,还有直接可以使用的内核api直接调用,去操作路由表信息,但达到删除,添加,查询的效果。
作者: Godbach    时间: 2009-10-26 11:02
原帖由 meijusan123 于 2009-10-26 10:19 发表
或是,有没内核中,还有直接可以使用的内核api直接调用,去操作路由表信息,但达到删除,添加,查询的效果。

呵呵,路由方面的开发做的不多。。

看看其他朋友有什么好的方法
作者: meijusan123    时间: 2009-10-26 17:32
现在 分析了大半天 ,最终还是要理解:

struct fib_table * __init fib_hash_init(int id)
{
        struct fib_table *tb;

        if (fn_hash_kmem == NULL)
                fn_hash_kmem = kmem_cache_create("ip_fib_hash",
                                                 sizeof(struct fib_node),
                                                 0, SLAB_HWCACHE_ALIGN,
                                                 NULL, NULL);

        if (fn_alias_kmem == NULL)
                fn_alias_kmem = kmem_cache_create("ip_fib_alias",
                                                  sizeof(struct fib_alias),
                                                  0, SLAB_HWCACHE_ALIGN,
                                                  NULL, NULL);

        tb = kmalloc(sizeof(struct fib_table) + sizeof(struct fn_hash),
                     GFP_KERNEL);
        if (tb == NULL)
                return NULL;

        tb->tb_id = id;
        tb->tb_lookup = fn_hash_lookup;
        tb->tb_insert = fn_hash_insert;
        tb->tb_delete = fn_hash_delete;
        tb->tb_flush = fn_hash_flush;
        tb->tb_select_default = fn_hash_select_default;
        tb->tb_dump = fn_hash_dump;
        memset(tb->tb_data, 0, sizeof(struct fn_hash));
        return tb;
}
这个kernel 的api一些回调函数的使用。
作者: meijusan123    时间: 2009-10-29 14:25
一般,我们在用户态对路由操作无外乎就是使用到ioctl,netlink,/proc的相关操作。
但在内核态实现对内核路由的操作,ioctl可以实现对路由的删除和增加功能,但没有实现对路由表的查询功能,现在着手研究内核态netlink的路由查询功能,但涉及到netlink_kernel_create()接口的使用,不太好入手。

一般,用户态使用netlink访问内核态路由查询时调用了netlink_kernel_create()接口函数,但,现在我想实现,直接在内核态调用netlink_kernel_create()接口查询路由,是否可以实现??

高手请帮忙给点思路!




欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2