netlink使用了软中断而不是内核线程来接收数据,这样就可以保证数据接收的实时性。
用户态程序:
1.1 为了创建一个 netlink socket,用户需要使用socket(PF_NETLINK, SOCK_RAW, netlink_type)创建一个套接字。第一个参数协议簇是 PF_NETLINK
第二个参数必须是SOCK_RAW或SOCK_DGRAM, 第三个参数指定netlink协议类型,它可以是一个自定义的类型,也可以使用内核预定义的类型。
1.2 socket函数返回的套接字,可以交给bind函数调用,bind函数需要绑定协议地址,netlink的socket地址使用struct sockaddr_nl结构描述。
Struct sockaddr_nl
{
sa_family_t nl_family;
unsigned short nl_pad;
__u32 nl_pid;
__u32 nl_groups;
}
成员nl_family协议簇为PF_NETLINK,成员nl_pad目前没有使用,要设置成0,成员nl_pid为接收或发送消息进程的ID,成员nl_groups用于指定多播组,bind函数把此进程的加入到改成员指定的多播组,如果设置为0,表示此进程不加入任何多播组。
1.3用户空间可以调用sendto函数向内核发送消息,同样需要用struct sockaddr_nl来描述一个对端地址,以待sendto函数来调用,与用户态进程不同的是,因为是内核,所以nl_pid成员需要设置为0
1.4 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:包括紧跟该结构的数据部分长度以及该结构的大小,使用NLMSG_LENGTH这个宏来计算这个长度,仅需向NLMSG_LENGTH宏提供需要发送的数据长度,它会自动计算对其后的总长度。
nlmsg_type:定义消息的类型,大部分情况下设置成0。
nlmsg_flags:用于设置消息标志,对于一般的使用,把它设置为0.
nlmsg_seq:顺序号
nlmsg_pid:消息来源进程ID
int sock_fd;
struct sockaddr_nl src_addr,dest_addr;
struct msg_to_kernel message;
sock_fd=socket(PF_NETLINK,SOCK_RAW,NETLINK_TEST);
if(sock_fd<0)
{
printf("can not create netlink socket/n");
exit(0);
}
memset(&src_addr,0,sizeof(src_addr));
src_addr.nl_family=PF_NETLINK;
src_addr.nl_pid=getpid();
src_addr.nl_groups=0;
if(bind(sock_fd,(struct sockaddr*)&src_addr,sizeof(src_addr))<0)
{
printf("bind netlink socket/n");
close(sock_fd);
exit(0);
}
memset(&dest_addr,0,sizeof(dest_addr));
dest_addr.nl_family=PF_NETLINK;
dest_addr.nl_pid=0;
dest_addr.nl_groups=0;
memset(&message,0,sizeof(message));
message.hdr.nlmsg_len=NLMSG_LENGTH(0);
message.hdr.nlmsg_flags=0;
message.hdr.nlmsg_type