netlink的使用方法
__u32 nl_groups;
};
成员 nl_family 为协议簇 AF_NETLINK,成员 nl_pad 当前没有使用,因此要总是设置为 0,成员 nl_pid 为接收或发送消息的进程的 ID,如果希望内核处理消息或多播消息,就把该字段设置为 0,否则设置为处理消息的进程 ID。成员 nl_groups 用于指定多播组,bind 函数用于把调用进程加入到该字段指定的多播组,如果设置为 0,表示调用者不加入任何多播组:
struct sockaddr_nl local;
memset(&local, 0, sizeof(local));
local.nl_family = AF_NETLINK;
local.nl_pid = getpid(); /*设置pid 为自己的pid 值*/
local.nl_groups = 0;
if(bind(skfd, (struct sockaddr*)&local, sizeof(local)) != 0) /*绑定套接字*/
{
printf("bind() error\n");
return -1;
}
用户空间可以调用send 函数簇向内核发送消息,如sendto、sendmsg 等,同样地,也可以使用struct sockaddr_nl 来描述一个对端地址,以待send 函数来调用,与本地地址稍不同的是,因为对端为内核,所以nl_pid 成员需要设置为0:
struct sockaddr_nl kpeer;
memset(&kpeer, 0, sizeof(kpeer));
kpeer.nl_family = AF_NETLINK;
kpeer.nl_pid = 0;
kpeer.nl_groups = 0;
另一个问题就是发内核发送的消息的组成,使用我们发送一个IP 网络数据包的话,则数据包结构为“IP 包头+IP 数据”,同样地,netlink 的消息结构是“netlink 消息头部+数据”。Netlink 消息头部使用struct nlmsghdr 结构来描述:
struct nlmsghdr
{
__u32 nlmsg_len; /* Length of message */
__u16 nlmsg_type; /* Message type*/
__u16 nlmsg_flags; /* Additional flags */
__u32 nlmsg_seq; /* Sequence number */
__u32 nlmsg_pid; /* Sending process PID */
};
字段 nlmsg_len 指定消息的总长度,包括紧跟该结构的数据部分长度以及该结构的大小,一般地,我们使用netlink 提供的宏NLMSG_LENGTH 来计算这个长度,仅需向NLMSG_LENGTH宏提供要发送的数据的长度,它会自动计算对齐后的总长度:
/*计算包含报头的数据报长度*/
#define NLMSG_LENGTH(len) ((len)+NLMSG_ALIGN(sizeof(struct nlmsghdr)))
/*字节对齐*/
#define NLMSG_ALIGN(len) (((len)+NLMSG_ALIGNTO-1)& ~(NLMSG_ALIGNTO-1) )
后面还可以看到很多netlink 提供的宏,这些宏可以为我们编写netlink 宏提供很大的方便。
字段 nlmsg_type 用于应用内部定义消息的类型,它对 netlink 内核实现是透明的,因此大部分情况下设置为 0,字段 nlmsg_flags 用于设置消息标志,对于一般的使用,用户把它设置为 0 就可以,只是一些高级应用(如 netfilter 和路由 daemon 需要它进行一些复杂的操作),字段nlmsg_seq 和 nlmsg_pid 用于应用追踪消息,前者表示顺序号,后者为消息来源进程 ID。
struct msg_to_kernel /*自定义消息首部,它仅包含了netlink 的消息首部*/
{
struct nlmsghdr hdr;