最顶层的netlink消息类型是套接字层指定的,创建了这种类型的套接字,就只能和这种类型的netlink消息通信:
如:nlsock = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
常见的netlink消息类型有:
#define NETLINK_ROUTE 0
#define NETLINK_NETFILTER 12
#define NETLINK_GENERIC 16
对于自定义的NETLINK消息,可以走NETLINK_GENERIC。
消息格式如下:
从内核收到的消息,可能包含多个nlmsg消息。如上所示。每个消息都要align到nlmsg的对齐字节数。
multipart的各个msg,以及msg中的各个单元(如hdr,data等)都要对齐到如下宏定义的字节数。
#define NLMSG_ALIGNTO 4U
nlmsghdr的定义如下:
1 2 3 4 5 6 7 | 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 port ID */ }; |
nlmsg_len
整个nlmsg的长度,包括nlmsghdr+padding+data。可以看到nlmsghdr结构体的大小是16,是对齐到4的,因此实际上头和data之间的padding的长度是0。
nlmsg_type
它表示nlmsg的类型,比如对于NETLINK_ROUTE来说,它的类型定义在rtnetlink.h,下面是部分定义:
1 2 3 4 5 6 7 8 9 | enum { RTM_BASE = 16, #define RTM_BASE RTM_BASE RTM_NEWLINK = 16, #define RTM_NEWLINK RTM_NEWLINK RTM_DELLINK, #define RTM_DELLINK RTM_DELLINK RTM_GETLINK, |
还有几个通用的类型:
1 2 3 4 | #define NLMSG_NOOP 0x1 /* Nothing. */ #define NLMSG_ERROR 0x2 /* Error */ #define NLMSG_DONE 0x3 /* End of a dump */ #define NLMSG_OVERRUN 0x4 /* Data lost */ |
对于multipart,NLMSG_DONE表示最后一个msg。
下面是NLMSG的几个宏:
NLMSG_ALIGN(len) | 返回len对齐到4的大小 |
NLMSG_HDRLEN | 返回头对齐后的大小 |
NLMSG_LENGTH(len) | 返回data大小为len时,整个nlmsg的大小。通常用来计算nlmsg_len的值 |
NLMSG_SPACE(len) | 返回data大小为len时,整个nlmsg对齐后的大小 |
NLMSG_DATA(nlh) | 返回nlmsg的data的指针。 |
NLMSG_NEXT(nlh,len) | 返回下一个nlmsg,并且len减去前一个nlmsg对齐的大小 |
NLMSG_OK(nlh,len) | 判断当前len是否可以容纳nlmsg |
NLMSG_PAYLOAD(nlh,len) | 返回data中len对齐后剩余的空间大小 |
用图表示更清晰:
data的内容是根据nlmsg_type消息类型决定的。常见的有一个头,然后跟着属性列表(属性也是对齐的,因此属性和头之间可能有padding)。此时可以使用
NLMSG_PAYLOAD(nlh,sizeof(data head)),来计算属性列表的大小。
属性也是按类似nlmsg排布的,直接截图netlink.h的注释如下:
属性头,及几个宏如下:
1 2 3 4 5 6 7 | struct nlattr { __u16 nla_len; __u16 nla_type; }; #define NLA_ALIGNTO 4 #define NLA_ALIGN(len) (((len) + NLA_ALIGNTO - 1) & ~(NLA_ALIGNTO - 1)) #define NLA_HDRLEN ((int) NLA_ALIGN(sizeof(struct nlattr))) |
注意,每个顶级netlink类型,都有特定的属性定义,如NETLINK_ROUTE的属性定义在rtnetlink.h。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /* Generic structure for encapsulation of optional route information. It is reminiscent of sockaddr, but with sa_family replaced with attribute type. */ struct rtattr { unsigned short rta_len; unsigned short rta_type; }; /* Macros to handle rtattributes */ #define RTA_ALIGNTO 4 #define RTA_ALIGN(len) ( ((len)+RTA_ALIGNTO-1) & ~(RTA_ALIGNTO-1) ) #define RTA_OK(rta,len) ((len) >= (int)sizeof(struct rtattr) && \ (rta)->rta_len >= sizeof ( struct rtattr) && \ (rta)->rta_len <= (len)) #define RTA_NEXT(rta,attrlen) ((attrlen) -= RTA_ALIGN((rta)->rta_len), \ ( struct rtattr*)((( char *)(rta)) + RTA_ALIGN((rta)->rta_len))) #define RTA_LENGTH(len) (RTA_ALIGN(sizeof(struct rtattr)) + (len)) #define RTA_SPACE(len) RTA_ALIGN(RTA_LENGTH(len)) #define RTA_DATA(rta) ((void*)(((char*)(rta)) + RTA_LENGTH(0))) #define RTA_PAYLOAD(rta) ((int)((rta)->rta_len) - RTA_LENGTH(0)) |
参考:
include/linux/netlink.h
include/linux/rtnetlink.h