netlink和rtnetlink(一)

转到:http://blogold.chinaunix.net/u/15993/showart.php?id=89359

我们先从netlink说起,netlink其实就是一组宏,这组宏用来访问和创建netlink数据报,其实和其他套结字一样,只不过它是用来给用户进程和内核模块之间进行通信的,它的宏定义有:
        #include <asm/types.h>
        #include <linux/netlink.h>
        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);
这些宏的含义我就不多说了,大家可以man 3 netlink。这里要说的是netlink的用法,netlink的用法在初始化的时候和一般的socket相似,如下:
        #include <asm/types.h>
        #include <sys/socket.h>
        #include <linux/netlink.h>
        netlink_socket = socket(PF_NETLINK, socket_type, netlink_family);
 
socket_type为SOCK_RAW或者SOCK_DGRAM都可以,因为netlink本身是基于数据报的。
netlink_family有下面几种:
NETLINK_ROUTE
       用来修改和读取路由表的,这是我们后面要讨论的关键问题.
NETLINK_FIREWALL
       接收IPv4防火墙代码发送的信息。
NETLINK_ARPD
       在用户空间中管理ARP表.
NETLINK_ROUTE6
       接收和发送路由表更新.
NETLINK_IP6_FW
       to  receive  packets  that failed the IPv6 firewall
       checks (currently not implemented).
NETLINK_TAPBASE...NETLINK_TAPBASE+15
       are the instances of the ethertap device.  Ethertap
       is  a  pseudo  network tunnel device that allows an
       ethernet driver to be simulated from user space.
NETLINK_SKIP
       Reserved for ENskip.
NETLINK_USERSOCK
       is reserved for future user space protocols.
Netlink消息是一个含有一个或者多个nlmsghdr头和相关载荷组成的字节流。除了最后一个nlmsghdr头的类型是NLMSG_DONE,其他的nlmsghdr头都是NLM_F_MULTI类型。这个字节流只能被上面描述过的标准NLMSG_*宏来访问。
Netlink是一个不可靠的协议。如果出现内存用尽或者其他错误,它就会丢包。如果需要可靠传输。发送者可以通过设置NLM_F_ACK标志 来向接收端要求一个ACK。一个ACK其实就是一个NLMSG_ERROR包,只不过它的error field设置为0。应用程序需要为接收的消息自己产生ACK。内核尽力为每个失败的包产生NLMSG_ERROR消息。用户进程也要遵守这个规范。
struct nlmsghdr
       {
    __u32    nlmsg_len;  /* Length of message including header */
    __u16    nlmsg_type; /* Message content */
    __u16    nlmsg_flags;/* Additional flags */
    __u32    nlmsg_seq;  /* Sequence number */
    __u32    nlmsg_pid;  /* Sending process PID */
       };

   struct nlmsgerr
   {
    int    error;      /* negative errno or 0 for acks. */
    struct nlmsghdr msg; /* message header that caused the error */
   };
  nlmsg_flag的标准flag
        NLM_F_REQUEST   set on all request messages
        NLM_F_MULTI     the message is part of a multipart mes-
         sage terminated by NLMSG_DONE
        NLM_F_ACK       reply with an acknowledgment on success
        NLM_F_ECHO      echo this request
        GET请求的附加标志位
        NLM_F_ROOT     Return the complete table instead of a single entry.
        NLM_F_MATCH    Not implemented yet.
        NLM_F_ATOMIC   Return an atomic snapshot of the table.
        NLM_F_DUMP     not documented yet.
        NEW请求的附加标志位
        NLM_F_REPLACE   Override existing object.
        NLM_F_EXCL      Don't replace if the object already exists.
        NLM_F_CREATE    Create object if it doesn't already exist.
        NLM_F_APPEND    Add to the end of the object list.
 
 sockaddr_nl结构描述了一个用户空间或者内核空间里面的netlink客户端。一个sockaddr_nl可以为单播也可以为组播。
 struct sockaddr_nl
       {
    sa_family_t nl_family;    /* AF_NETLINK */
    unsigned short nl_pad;    /* zero */
    pid_t       nl_pid;     /* process pid */
    __u32       nl_groups;    /* multicast groups mask */
       };
 nl_pid是用户空间netlink的pid,如果为0,就代表是内核空间。nl_groups是一个位掩码,每个bit代表了一个组号。如果是0就是单播。
(未完待续)
  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
下面是一个简单的示例代码,用于检测所有网口的 UP 和 DOWN 状态。该代码使用了 Netlink Socket API,需要在 Linux 系统中编译和运行。 ```c #include <stdio.h> #include <stdlib.h> #include <string.h> #include <unistd.h> #include <sys/socket.h> #include <linux/netlink.h> #include <linux/rtnetlink.h> #define BUFSIZE 8192 int main() { int fd; struct sockaddr_nl sa; char buf[BUFSIZE]; struct nlmsghdr *nh; struct ifinfomsg *ifinfo; int len; // 创建 Netlink Socket if ((fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) < 0) { perror("socket"); exit(1); } memset(&sa, 0, sizeof(sa)); sa.nl_family = AF_NETLINK; sa.nl_groups = RTMGRP_LINK; // 监听网卡变化事件 if (bind(fd, (struct sockaddr *)&sa, sizeof(sa)) < 0) { perror("bind"); exit(1); } // 接收 Netlink 消息 while ((len = recv(fd, buf, BUFSIZE, 0)) > 0) { for (nh = (struct nlmsghdr *)buf; NLMSG_OK(nh, len); nh = NLMSG_NEXT(nh, len)) { if (nh->nlmsg_type == NLMSG_DONE) { break; } else if (nh->nlmsg_type == NLMSG_ERROR) { perror("recv"); exit(1); } else if (nh->nlmsg_type != RTM_NEWLINK) { continue; } ifinfo = (struct ifinfomsg *)NLMSG_DATA(nh); // 监听到网卡 UP 或 DOWN 事件 if (ifinfo->ifi_change & (IFACE_UP | IFACE_DOWN)) { printf("Interface %d is %s\n", ifinfo->ifi_index, (ifinfo->ifi_flags & IFF_UP) ? "UP" : "DOWN"); } } } close(fd); return 0; } ``` 该程序使用了 Netlink Socket API 监听 RTMGRP_LINK 组,对于每个 RTM_NEWLINK 消息,解析其中的 ifinfomsg 结构体,检查其 ifi_change 和 ifi_flags 成员以确定网卡 UP 或 DOWN 事件。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值