加载中…
个人资料
  • 博客等级:
  • 博客积分:
  • 博客访问:
  • 关注人气:
  • 获赠金笔:0支
  • 赠出金笔:0支
  • 荣誉徽章:
正文 字体大小:

struct rtentry fib_convert_rtentry()

(2010-01-12 08:42:46)
标签:

杂谈

分类: 路由

先来看nlmsghdr:

struct nlmsghdr {

_u32 nlmsg_len;

_u32 nlmsg_type;

_u16 nlmsg_flags;

_u32 nlmsg_seq;

_u32 nlmsg_pid;

};

 

 

nlmsg_type决定这次要执行的操作,如查询当前路由表信息,所使用的就是RTM_GETROUTE。标准nlmsg_type包括:NLMSG_NOOP, NLMSG_DONE, NLMSG_ERROR等。根据采用的nlmsg_type不同,还要选取不同的数据结构来填充到nlmsghdr后面:

操作 数据结构

RTM_NEWLINK ifinfomsg

RTM_DELLINK

RTM_GETLINK

RTM_NEWADDR ifaddrmsg

RTM_DELADDR

RTM_GETADDR

RTM_NEWROUTE rtmsg

RTM_DELROUTE

RTM_GETROUTE

RTM_NEWNEIGH ndmsg/nda_chcheinfo

RTM_DELNEIGH

RTM_GETNEIGH

RTM_NEWRULE rtmsg

RTM_DELRULE

RTM_GETRULE

RTM_NEWQDISC tcmsg

RTM_DELQDISC

RTM_GETQDISC

RTM_NEWTCLASS tcmsg

RTM_DELTCLASS

RTM_GETTCLASS

RTM_NEWTFILTER tcmsg

RTM_DELTFILTER

RTM_GETTFILTER

由于情形众多,我从现在开始将用一个特定的例子来说明问题。我们的目的是从内核读取IPV4路由表信息。从上面表看,nlmsg_type一定使用RTM_xxxROUTE操作,对应的数据结构是rtmsg。既然是读取,那么应该是RTM_GETROUTE了。

struct rtmsg {

unsigned char rtm_family;

unsigned char rtm_dst_len;

unsigned char rtm_src_len; (2.4.10头文件的注释标反了?)

unsigned char rtm_tos;

 

unsigned char rtm_table;

unsigned char rtm_protocol;

unsigned char rtm_scope;

unsigned char rtm_type;

 

unsigned int rtm_flags;

};

对于RTM_GETROUTE操作来说,我们只需指定两个成员:rtm_family:AF_INET, rtm_table: RT_TABLE_MAIN。其他成员都初始化为0即可。将这个结构体跟nlmsghdr结合起来,得到我们自己的新结构体:

struct {

struct nlmsghdr nl;

struct rtmsg rt;

}req;

struct kern_rta
{
    void        *rta_dst;
    void        *rta_src;
    int     *rta_iif;
    int     *rta_oif;
    void        *rta_gw;
    u32     *rta_priority;
    void        *rta_prefsrc;
    struct rtattr   *rta_mx;
    struct rtattr   *rta_mp;
    unsigned char   *rta_protoinfo;
    unsigned char   *rta_flow;
    struct rta_cacheinfo *rta_ci;
};

Note that this structure has a one to one correspondance with the routing table attributes so that the typecasting makes sense.

enum rtattr_type_t
{
    RTA_UNSPEC,
    RTA_DST,
    RTA_SRC,
    RTA_IIF,
    RTA_OIF,
    RTA_GATEWAY,
    RTA_PRIORITY,
    RTA_PREFSRC,
    RTA_METRICS,
    RTA_MULTIPATH,
    RTA_PROTOINFO,
    RTA_FLOW,
    RTA_CACHEINFO
};

 

struct rtentry

{

        unsigned long   rt_pad1;

        struct sockaddr rt_dst;        

        struct sockaddr rt_gateway;    

        struct sockaddr rt_genmask;    

        unsigned short  rt_flags;

        short           rt_pad2;

        unsigned long   rt_pad3;

        void            *rt_pad4;

        short           rt_metric;     

        char            *rt_dev;       

        unsigned long   rt_mtu;        

#ifndef __KERNEL__

#define rt_mss  rt_mtu                 

#endif

        unsigned long   rt_window;     

        unsigned short  rt_irtt;       

};

                                                                                                                                              

                                                                                                                                               

#define RTF_UP          0x0001         

#define RTF_GATEWAY     0x0002         

#define RTF_HOST        0x0004         

#define RTF_REINSTATE   0x0008         

#define RTF_DYNAMIC     0x0010         

#define RTF_MODIFIED    0x0020         

#define RTF_MTU         0x0040         

#define RTF_MSS         RTF_MTU        

#define RTF_WINDOW      0x0080         

#define RTF_IRTT        0x0100         

#define RTF_REJECT      0x0200         

fib_convert_rtentry(int cmd, struct nlmsghdr *nl, struct rtmsg *rtm,

                    struct kern_rta *rta, struct rtentry *r)

{

        int    plen;

        u32    *ptr;

 

        memset(rtm, 0, sizeof(*rtm));

        memset(rta, 0, sizeof(*rta));

 

        if (r->rt_dst.sa_family != AF_INET)

                return -EAFNOSUPPORT;

 

       

        plen = 32;

        ptr = &((struct sockaddr_in*)&r->rt_dst)->sin_addr.s_addr;

        if (!(r->rt_flags&RTF_HOST)) {

                u32 mask = ((struct sockaddr_in*)&r->rt_genmask)->sin_addr.s_addr;

                if (r->rt_genmask.sa_family != AF_INET) {

                        if (mask || r->rt_genmask.sa_family)

                                return -EAFNOSUPPORT;

                }

                if (bad_mask(mask, *ptr))

                        return -EINVAL;

                plen = inet_mask_len(mask);

        }

 

        nl->nlmsg_flags = NLM_F_REQUEST;

        nl->nlmsg_pid = 0;

        nl->nlmsg_seq = 0;

        nl->nlmsg_len = NLMSG_LENGTH(sizeof(*rtm));

        if (cmd == SIOCDELRT) {

                nl->nlmsg_type = RTM_DELROUTE;

                nl->nlmsg_flags = 0;

        } else {

                nl->nlmsg_type = RTM_NEWROUTE;

                nl->nlmsg_flags = NLM_F_REQUEST|NLM_F_CREATE;

                rtm->rtm_protocol = RTPROT_BOOT;

        }

 

        rtm->rtm_dst_len = plen;

        rta->rta_dst = ptr;

 

        if (r->rt_metric) {

                *(u32*)&r->rt_pad3 = r->rt_metric - 1;

                rta->rta_priority = (u32*)&r->rt_pad3;

        }

        if (r->rt_flags&RTF_REJECT) {

                rtm->rtm_scope = RT_SCOPE_HOST;

                rtm->rtm_type = RTN_UNREACHABLE;

                return 0;

        }

        rtm->rtm_scope = RT_SCOPE_NOWHERE;

        rtm->rtm_type = RTN_UNICAST;

 

        if (r->rt_dev) {

#ifdef CONFIG_IP_ALIAS

                char *colon;

#endif

                struct net_device *dev;

                char   devname[IFNAMSIZ];

 

                if (copy_from_user(devname, r->rt_dev, IFNAMSIZ-1))

                        return -EFAULT;

                devname[IFNAMSIZ-1] = 0;

#ifdef CONFIG_IP_ALIAS

                colon = strchr(devname, ':');

                if (colon)

                        *colon = 0;

#endif

                dev = dev_get(devname);

                if (!dev)

                        return -ENODEV;

                rta->rta_oif = &dev->ifindex;

#ifdef CONFIG_IP_ALIAS

                if (colon) {

                        struct in_ifaddr *ifa;

                        struct in_device *in_dev = dev->ip_ptr;

                        if (!in_dev)

                                return -ENODEV;

                        *colon = ':';

                        for (ifa = in_dev->ifa_list; ifa; ifa = ifa->ifa_next)

                                if (strcmp(ifa->ifa_label, devname) == 0)

                                        break;

                        if (ifa == NULL)

                                return -ENODEV;

                        rta->rta_prefsrc = &ifa->ifa_local;

                }

#endif

        }

 

        ptr = &((struct sockaddr_in*)&r->rt_gateway)->sin_addr.s_addr;

        if (r->rt_gateway.sa_family == AF_INET && *ptr) {

                rta->rta_gw = ptr;

                if (r->rt_flags&RTF_GATEWAY && inet_addr_type(*ptr) == RTN_UNICAST)

                        rtm->rtm_scope = RT_SCOPE_UNIVERSE;

        }

 

        if (cmd == SIOCDELRT)

                return 0;

 

        if (r->rt_flags&RTF_GATEWAY && rta->rta_gw == NULL)

                return -EINVAL;

 

        if (rtm->rtm_scope == RT_SCOPE_NOWHERE)

                rtm->rtm_scope = RT_SCOPE_LINK;

 

        if (r->rt_flags&(RTF_MTU|RTF_WINDOW|RTF_IRTT)) {

                struct rtattr *rec;

                struct rtattr *mx = kmalloc(RTA_LENGTH(3*RTA_LENGTH(4)), GFP_KERNEL);

                if (mx == NULL)

                        return -ENOMEM;

                rta->rta_mx = mx;

                mx->rta_type = RTA_METRICS;

                mx->rta_len  = RTA_LENGTH(0);

                if (r->rt_flags&RTF_MTU) {

                        rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));

                        rec->rta_type = RTAX_MTU;

                        rec->rta_len = RTA_LENGTH(4);

                        mx->rta_len += RTA_LENGTH(4);

                        *(u32*)RTA_DATA(rec) = r->rt_mtu;

                }

                if (r->rt_flags&RTF_WINDOW) {

                        rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));

                        rec->rta_type = RTAX_WINDOW;

                        rec->rta_len = RTA_LENGTH(4);

                        mx->rta_len += RTA_LENGTH(4);

                        *(u32*)RTA_DATA(rec) = r->rt_window;

                }

                if (r->rt_flags&RTF_IRTT) {

                        rec = (void*)((char*)mx + RTA_ALIGN(mx->rta_len));

                        rec->rta_type = RTAX_RTT;

                        rec->rta_len = RTA_LENGTH(4);

                        mx->rta_len += RTA_LENGTH(4);

                        *(u32*)RTA_DATA(rec) = r->rt_irtt;

                }

        }

        return 0;

}

0

阅读 收藏 喜欢 打印举报/Report
  

新浪BLOG意见反馈留言板 欢迎批评指正

新浪简介 | About Sina | 广告服务 | 联系我们 | 招聘信息 | 网站律师 | SINA English | 产品答疑

新浪公司 版权所有