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

一些字符的定义

(2012-02-28 09:32:08)
标签:

杂谈

分类: linux程序
  • netlink基础知识
    我们在使用socket(2)的man手册时候可以找到man手册中有下面一行说明 PF_NETLINK          Kernel user interface device     netlink(7)
    在我们通过PF_NETLINK创建一个SOCKET以后表示我们期望同内核进行消息通讯。使用netlink(7)的手册可以看到关于PF_NETLINK的详细说明。         #include
            #include
            #include
            netlink_socket = socket(PF_NETLINK, socket_type, netlink_family);
    按照netlink的手册,socket_type可以取SOCK_RAW和SOCK_DGRAM,不过内核不区分这两个字段。netlink_family字段指定了我们期望的通讯协议,主要有:

  • NETLINK_ROUTE 用来获取,创建和修改设备的各种信息,详细参见 rtnetlink(7)
  • NETLINK_SKIP Enskip 的保留选项
  • NETLINK_USERSOCK 为今后用户程序空间协议用保留选项
  • NETLINK_FIREWALL 接收 IPv4 防火墙编码发送的数据包
  • NETLINK_TCPDIAG TCP套接字监控
  • NETLINK_NFLOG netfilter的用户空间日志
  • NETLINK_ARPD 用以维护用户地址空间里的 arp 表
  • NETLINK_ROUTE6 接收和发送 IPv6 路由表更新消息
  • NETLINK_IP6_FW 接收未通过 IPv6 防火墙检查的数据包(尚未实现)
  • NETLINK_TAPBASE 是 ethertap 设备实例
后面我们会对每一个协议进行解释和说明.
  • nlmsghdr结构介绍
    每一个发送给内核或者从内核介绍的报文都有一个相同的报文头,这个报文头的结构如下定义:               struct nlmsghdr
                  {
                          __u32 nlmsg_len;     
                          __u16 nlmsg_type;   
                          __u16 nlmsg_flags;   
                          __u32 nlmsg_seq;     
                          __u32 nlmsg_pid;     
                  };
    所有发送给内核或者内核的报文的第一部分都必须使用这个机构,后面跟随相应的内容。nlmsg_type为后面消息的内容个数,对于前面我们提到的不同通讯协议有着不同的消息类型。下面是三个通用的消息类型

  • NLMSG_NOOP 这个消息类型表示消息内容为空,应用可以忽略该报文
  • NLMSG_ERROR 这个消息类型表示后面的消息是一个错误信息,错误信息的机构为nlmsgerr           struct nlmsgerr
              {
                  int error;           
                  struct nlmsghdr msg;
              };
           
  • NLMSG_DONE 在我们接收或者发送消息给内核的时候,我们有可能一次发送多个报文,这个消息类型表示是报文的最后一个,类似于在链表中我们将最后一个成员的next指针设置为NULL。
附加的标志用于控制或者表示消息的其它信息,一些比较通用的标志是

  • NLM_F_REQUEST 表示这个消息是一个请求消息,这个消息可以同以下一个标志组合

    • NLM_F_ROOT 返回树的根
    • NLM_F_MATCH 返回所有匹配的
    • NLM_F_ATOMIC 返回对象表的单一快照
    • NLM_F_DUMP 被定义为NLM_F_ROOT|NLM_F_MATCH
    • NLM_F_REPLACE 表示替换现有的规则
    • NLM_F_EXCL 如果现有规则存在则不修改
    • NLM_F_CREAT 创建一个规则
    • NLM_F_APPEND 追加一个规则

  • NLM_F_MULTI 表示这个消息是多个报文中的一个,报文的结尾通过NLMSG_DONE来表示
  • NLM_F_ACK 表示这个消息是一个应答消息
  • NLM_F_ECHO 表示这个消息是一个要求返回请求信息的消息

  • 解析nlmsghdr数据
    为了获取netlink报文中数据的方便,netlink提供了下面几个宏进行数据的获取和解包操作        #include
           #include
           int NLMSG_ALIGN(size_t len);
           int NLMSG_LENGTH(size_t len);
           int NLMSG_SPACE(size_t len);
           void *NLMSG_DATA(struct nlmsghdr *nlh);
           struct nlmsghdr *NLMSG_NEXT(struct nlmsghdr *nlh, int len);
           int NLMSG_OK(struct nlmsghdr *nlh, int len);
           int NLMSG_PAYLOAD(struct nlmsghdr *nlh, int len);
    NLMSG_ALIGN:进行数据长度的对齐操作
    NLMSG_DATA:获取通讯报文中的数据
    NLMSG_NEXT:获取下一个报文
    NLMSG_OK:判断是否数据可以继续获取
    NLMSG_PAYLOAD:获取数据的长度
    在我们后面的实例中会介绍如何使用这几个宏。
  • sockaddr_nl结构介绍
    在socket程序中,如果我们要求接收报文则要求调用bind,表示我们期望接收什么样的报文。对于netlink也一样,我们要求指定我们期望接收的地址信息,不过同传统的sockaddr不同,这个地方是一个sockaddr_nl的结构:         struct sockaddr_nl
            {
                    sa_family_t nl_family;
                    unsigned short nl_pad;
                    pid_t nl_pid;
                    __u32 nl_groups;
            };
    每一个 netlink 数据类都有一个32位广播分组,当对套接字调用 bind(2) 时, sockaddr_nl 中的 nl_groups 字段设置成所要侦听的广播组的位掩码。其默认值为 0,表示不接收任何广播,我们会在后面中看到如何使用这个广播组的例子。
  • NETLINK_ROUTE协议介绍
    netlink目前使用最广泛的是通过这个选项来获取网络设备或者网址的一些信息。在使用这个协议时候支持的类型有:

  • RTM_NEWLINK, RTM_DELLINK, RTM_GETLINK 创建,删除或者获取网络设备的信息
  • RTM_NEWADDR, RTM_DELADDR, RTM_GETADDR 创建,删除或者获取网络设备的IP信息
  • RTM_NEWROUTE, RTM_DELROUTE, RTM_GETROUTE 创建,删除或者获取网络设备的路由信息
  • RTM_NEWNEIGH, RTM_DELNEIGH, RTM_GETNEIGH 创建,删除或者获取网络设备的相邻信息
  • RTM_NEWRULE, RTM_DELRULE, RTM_GETRULE 创建,删除或者获取路由规则信息
  • RTM_NEWQDISC, RTM_DELQDISC, RTM_GETQDISC 创建,删除或者获取队列的原则
  • RTM_NEWTCLASS, RTM_DELTCLASS, RTM_GETTCLASS 创建,删除或者获取流量的类别
  • RTM_NEWTFILTER, RTM_DELTFILTER, RTM_GETTFILTER 创建,删除或者获取流量的过虑
由于NETLINK_ROUTE支持的类型实在太多了,我们这个地方只重点介绍一下RTM_GETLINK这个类型,然后通过一个例子介绍如何同内核进行通讯。关于其它类型的用法大家可以参考rtnetlink(7)的man手册。
按照rtnetlink的说法,在获取设备信息的时候我们要求首先发送一个报文给内核表示我们的请求,这个报文的格式是1个nlmsghdr头部机构+1个ifinfomsg接口结构+多个rtattr属性机构。其中后面两个结构的定义是:               struct ifinfomsg
              {
                  unsigned char  ifi_family;  
                  unsigned short ifi_type;   
                  int            ifi_index;   
                  unsigned int   ifi_flags;   
                  unsigned int   ifi_change;  
              };
              struct rtattr
              {
                  unsigned short rta_len;     
                  unsigned short rta_type;   
                  
              };
ifi_type:这个字段包含了硬件的类型,可以参考比较常见的是         ARPHRD_ETHER         10M以太网
        ARPHRD_PPP      PPP拨号
        ARPHRD_LOOPBACK 环路设备
ifi_flags:这个字段包含了设备的一些标志,相应的值为:               IFF_UP             接口正在运行.
              IFF_BROADCAST      有效的广播地址集.
              IFF_DEBUG          内部调试标志.
              IFF_LOOPBACK       这是自环接口.
              IFF_POINTOPOINT    这是点到点的链路接口.
              IFF_RUNNING        资源已分配.
              IFF_NOARP          无arp协议, 没有设置第二层目的地址.
              IFF_PROMISC        接口为杂凑(promiscuous)模式.
              IFF_NOTRAILERS     避免使用trailer .
              IFF_ALLMULTI       接收所有组播(multicast)报文.
              IFF_MASTER         主负载平衡群(bundle).
              IFF_SLAVE          从负载平衡群(bundle).
              IFF_MULTICAST      支持组播(multicast).
              IFF_PORTSEL        可以通过ifmap选择介质(media)类型.
              IFF_AUTOMEDIA      自动选择介质.
              IFF_DYNAMIC        接口关闭时丢弃地址.
rta_type:这个字段指定属性的类型,相应的值为:     IFLA_UNSPEC 后面的数据格式未指定
    IFLA_ADDRESS 后面的数据是一个硬件地址
    IFLA_BROADCAST 后面的数据是一个硬件广播地址
    IFLA_IFNAME 后面的数据是一个char型的设备名称
    IFLA_MTU unsigned int型的设备MTU值
    IFLA_LINK int型的链路类型
    IFLA_QDISC 字符串型的队列规则
    IFLA_STATS struct net_device_stats型的设备信息
在我们接收和发送数据的时候为了我们获取属性的方便,rtnetlink提供了一个宏供我们取获取其中的结构,这些宏的定义为:        #include
       #include
       #include
       #include
       int RTA_OK(struct rtattr *rta, int rtabuflen);
       void *RTA_DATA(struct rtattr *rta);
       unsigned int RTA_PAYLOAD(struct rtattr *rta);
       struct rtattr *RTA_NEXT(struct rtattr *rta, unsigned int rtabuflen);
       unsigned int RTA_LENGTH(unsigned int length);
       unsigned int RTA_SPACE(unsigned int length);

0

阅读 评论 收藏 转载 喜欢 打印举报/Report
  • 评论加载中,请稍候...
发评论

    发评论

    以上网友发言只代表其个人观点,不代表新浪网的观点或立场。

      

    新浪BLOG意见反馈留言板 电话:4000520066 提示音后按1键(按当地市话标准计费) 欢迎批评指正

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

    新浪公司 版权所有