ILD

netlink消息类型和格式
作者:YuanJianpeng 邮箱:yuanjp89@163.com
发布时间:2020-1-6 站点:Inside Linux Development

Netlink types

最顶层的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。


Netlink message format

消息格式如下:

从内核收到的消息,可能包含多个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)),来计算属性列表的大小。


Attributes

属性也是按类似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

Copyright © insidelinuxdev.net 2017-2021. Some Rights Reserved.