至今单身的风衣 · Getting Started | ...· 1 月前 · |
阳光的金鱼 · Expired SSL Cert - ...· 2 月前 · |
稳重的肉夹馍 · Pandas+SQLAlchemy与数据库交 ...· 3 月前 · |
刚失恋的回锅肉 · 手电筒在手机哪里打开?手机手电筒灰色点不了, ...· 3 月前 · |
行走的键盘 · Java 并发——基石篇 - ...· 1 年前 · |
The core library contains the fundamentals required to communicate over netlink sockets. It deals with connecting and disconnectng of sockets, sending and receiving of data, construction and parsing of messages, provides a customizeable receiving state machine, and provides a abstract data type framework which eases the implementation of object based netlink protocols where objects are added, removed, or modified using a netlink based protocol.
The suite is split into multiple libraries:
The libraries provide a broad set of APIs of which most applications only require a small subset of it. Depending on the type of application, some users may only be interested in the low level netlink messaging API while others wish to make heavy use of the high level API.
In any case it is recommended to get familiar with the netlink protocol first.
Projects using autoconf may use
PKG_CHECK_MODULES()
to check if
a specific version of libnl is available on the system. The example
below also shows how to retrieve the
CFLAGS
and linking dependencies
required to link against the library.
The following example shows how to check for a specific version of libnl. If
found, it extends the
CFLAGS
and
LIBS
variable appropriately:
PKG_CHECK_MODULES(LIBNL3, libnl-3.0 >= 3.1, [have_libnl3=yes], [have_libnl3=no])
if (test "${have_libnl3}" = "yes"); then
CFLAGS+="$LIBNL3_CFLAGS"
LIBS+="$LIBNL3_LIBS"
Header FilesThe main header file is <netlink/netlink.h>
. Additional headers may need to
be included in your sources depending on the subsystems and components your
program makes use of.
#include <netlink/netlink.h>
#include <netlink/cache.h>
#include <netlink/route/link.h>
Version Dependent CodeIf your code wishes to be capable to link against multiple versions of libnl
you may have direct the compiler to only include portions on the code depending
on the version of libnl that it is compiled against.
#include <netlink/version.h>
#if LIBNL_VER_NUM >= LIBNL_VER(3,1)
/* include code if compiled with libnl version >= 3.1 */
#endif
The library has been compiled with debugging statements enabled it will
print debug information to stderr
if the environment variable NLDBG
is set to > 0.
Debugging the Netlink ProtocolIt is often useful to peek into the stream of netlink messages exchanged
with other sockets. Setting the environment variable NLCB=debug
will
cause the debugging message handlers to be used which in turn print the
netlink messages exchanged in a human readable format to to stderr
:
-- Debug: Sent Message:
-------------------------- BEGIN NETLINK MESSAGE ---------------------------
[HEADER] 16 octets
.nlmsg_len = 20
.nlmsg_type = 18 <route/link::get>
.nlmsg_flags = 773 <REQUEST,ACK,ROOT,MATCH>
.nlmsg_seq = 1301410712
.nlmsg_pid = 20014
[PAYLOAD] 16 octets
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
--------------------------- END NETLINK MESSAGE ---------------------------
-- Debug: Received Message:
-------------------------- BEGIN NETLINK MESSAGE ---------------------------
[HEADER] 16 octets
.nlmsg_len = 996
.nlmsg_type = 16 <route/link::new>
.nlmsg_flags = 2 <MULTI>
.nlmsg_seq = 1301410712
.nlmsg_pid = 20014
[PAYLOAD] 16 octets
00 00 04 03 01 00 00 00 49 00 01 00 00 00 00 00 ........I.......
[ATTR 03] 3 octets
6c 6f 00 lo.
[PADDING] 1 octets
00 .
[ATTR 13] 4 octets
00 00 00 00 ....
[ATTR 16] 1 octets
00 .
[PADDING] 3 octets
00 00 00 ...
[ATTR 17] 1 octets
00 .
[...]
--------------------------- END NETLINK MESSAGE ---------------------------
The netlink protocol is a socket based IPC mechanism used for
communication between userspace processes and the kernel or between
userspace processes themselves. The netlink protocol is based on BSD
sockets and uses the AF_NETLINK
address family. Every netlink
protocol uses its own protocol number (e.g. NETLINK_ROUTE
,
NETLINK_NETFILTER
, etc). Its addressing schema is based on a 32 bit
port number, formerly referred to as PID, which uniquely identifies
each peer.
2.1. Addressing
The netlink address (port) consists of a 32bit integer. Port 0 (zero)
is reserved for the kernel and refers to the kernel side socket of each
netlink protocol family. Other port numbers usually refer to user space
owned sockets, although this is not enforced.
In the beginning, it was common practice to use the process
identifier (PID) as the local port number. This became unpractical
with the introduction of threaded netlink applications and
applications requiring multiple sockets. Therefore libnl generates
unique port numbers based on the process identifier and adds an
offset to it allowing for multiple sockets to be used. The initial
socket will still equal to the process identifier for backwards
compatibility reasons.
The above figure illustrates three applications and the kernel side
exposing two kernel side sockets. It shows the common netlink use
cases:
User Space to KernelThe most common form of netlink usage is for a user space application
to send requests to the kernel and process the reply which is either
an error message or a success notification.
User Space to User SpaceNetlink may also be used as an IPC mechanism to communicate between user
space applications directly. Communication is not limited to two peers,
any number of peers may communicate with each other and multicasting
capabilities allow to reach multiple peers with a single message.
In order for the sockets to be visible to each other, both sockets must
be created for the same netlink protocol family.
User space listening to kernel notificationsThis form of netlink communication is typically found in user space
daemons that need to act on certain kernel events. Such daemons will
typically maintain a netlink socket subscribed to a multicast group that
is used by the kernel to notify interested user space parties about
specific events.
Use of multicasting is preferred over direct addressing due to the
flexibility in exchanging the user space component at any time without
the kernel noticing.
A netlink protocol is typically based on messages and consists of the
netlink message header (struct nlmsghdr
) plus the payload attached
to it. The payload can consist of arbitrary data but usually contains
a fixed size protocol specific header followed by a stream of
attributes.
Netlink message header (struct nlmsghdr)
The message type specifies the type of payload the message is carrying.
Several standard message types are defined by the netlink protocol.
Additional message types may be defined by each protocol family. See
Message Types for additional information.
The sequence number is optional and may be used to allow referring to
a previous message, e.g. an error message can refer to the original
request causing the error.
The port number specifies the peer to which the message should be delivered
to. If not specified, the message will be delivered to the first matching
kernel side socket of the same protocol family.
Netlink differs between requests, notifications, and replies. Requests
are messages which have the NLM_F_REQUEST
flag set and are meant to
request an action from the receiver. A request is typically sent from
a userspace process to the kernel. While not strictly enforced, requests
should carry a sequence number incremented for each request sent.
Depending on the nature of the request, the receiver may reply to the
request with another netlink message. The sequence number of a reply
must match the sequence number of the request it relates to.
Notifications are of informal nature and no reply is expected, therefore
the sequence number is typically set to 0.
Every netlink protocol is free to define own message types. Note that
message type values < NLMSG_MIN_TYPE (0x10)
are reserved and may
not be used.
It is common practice to use own message types to implement RPC schemas.
Suppose the goal of the netlink protocol you are implementing is allow
configuration of a particular network device, therefore you want to
provide read/write access to various configuration options. The typical
"netlink way" of doing this would be to define two message types
MSG_SETCFG
, MSG_GETCFG
:
#define MSG_SETCFG 0x11
#define MSG_GETCFG 0x12
Sending a MSG_GETCFG
request message will typically trigger a reply
with the message type MSG_SETCFG
containing the current configuration.
In object oriented terms one would describe this as "the kernel sets
the local copy of the configuration in userspace".
The configuration may be changed by sending a MSG_SETCFG
which will
be responded to with either a ACK (see ACKs)
or a error message (see Error Message).
Optionally, the kernel may send out notifications for configuration
changes allowing userspace to listen for changes instead of polling
frequently. Notifications typically reuse an existing message type
and rely on the application using a separate socket to differ between
requests and notifications but you may also specify a separate message
type.
2.3.1. Multipart Messages
Although in theory a netlink message can be up to 4GiB in size. The socket
buffers are very likely not large enough to hold message of such sizes.
Therefore it is common to limit messages to one page size (PAGE_SIZE) and
use the multipart mechanism to split large pieces of data into several
messages. A multipart message has the flag NLM_F_MULTI
set and the
receiver is expected to continue receiving and parsing until the special
message type NLMSG_DONE
is received.
Multipart messages unlike fragmented ip packets must not be reassmbled
even though it is perfectly legal to do so if the protocols wishes to
work this way. Often multipart message are used to send lists or trees
of objects were each multipart message simply carries multiple objects
allow for each message to be parsed independently.
2.3.2. Error Message
Error messages can be sent in response to a request. Error messages must
use the standard message type NLMSG_ERROR
. The payload consists of a
error code and the original netlink mesage header of the request.
A sender can request an ACK message to be sent back for each request
processed by setting the NLM_F_ACK
flag in the request. This is typically
used to allow the sender to synchronize further processing until the
request has been processed by the receiver.
The flag NLM_F_ECHO
is similar to the NLM_F_ACK
flag. It can be
used in combination with NLM_F_REQUEST
and causes a notification
which is sent as a result of a request to also be sent to the sender
regardless of whether the sender has subscribed to the corresponding
multicast group or not. See Multicast Groups
Additional universal message flags are defined which only apply for
GET
requests:
#define NLM_F_ROOT 0x100
#define NLM_F_MATCH 0x200
#define NLM_F_ATOMIC 0x400
#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
Use of these flags is completely optional and many netlink protocols only
make use of the NLM_F_DUMP
flag which typically requests the receiver
to send a list of all objects in the context of the message type as a
sequence of multipart messages (see Multipart Messages).
Another set of flags exist related to NEW
or SET
requests. These
flags are mutually exclusive to the GET
flags:
#define NLM_F_REPLACE 0x100
#define NLM_F_EXCL 0x200
#define NLM_F_CREATE 0x400
#define NLM_F_APPEND 0x800
2.4. Sequence Numbers
Netlink allows the use of sequence numbers to help relate replies to
requests. It should be noted that unlike in protocols such as TCP
there is no strict enforcment of the sequence number. The sole purpose
of sequence numbers is to assist a sender in relating replies to the
corresponding requests. See Message Types for more information.
Sequence numbers are managed on a per socket basis, see
Sequence Numbers for more information on how to use sequence numbers.
In order to use the netlink protocol, a netlink socket is required.
Each socket defines an independent context for sending and receiving of
messages. An application may make use multiple sockets, e.g. a socket to
send requests and receive the replies and another socket subscribed to a
multicast group to receive notifications.
3.1. Socket structure (struct nl_sock)
The netlink socket and all related attributes including the actual file
descriptor are represented by struct nl_sock
.
#include <netlink/socket.h>
struct nl_sock *nl_socket_alloc(void)
void nl_socket_free(struct nl_sock *sk)
The application must allocate an instance of struct nl_sock
for each
netlink socket it wishes to use.
3.2. Sequence Numbers
The library will automatically take care of sequence number handling
for the application. A sequence number counter is stored in the
socket structure which is used and incremented automatically when a
message needs to be sent which is expected to generate a reply such as
an error or any other message type that needs to be related to the
original message.
Alternatively, the counter can be used directly via the function
nl_socket_use_seq(). It will return the current value of the counter
and increment it by one afterwards.
#include <netlink/socket.h>
unsigned int nl_socket_use_seq(struct nl_sock *sk);
Most applications will not want to deal with sequence number handling
themselves though. When using nl_send_auto() the sequence number is
filled in automatically and matched again when a reply is received. See
section Sending and Receiving of Messages / Data for more information.
This behaviour can and must be disabled if the netlink protocol
implemented does not use a request/reply model, e.g. when a socket is
used to receive notification messages.
#include <netlink/socket.h>
void nl_socket_disable_seq_check(struct nl_sock *sk);
For more information on the theory behind netlink sequence numbers,
see section Sequence Numbers.
3.3. Multicast Group Subscriptions
Each socket can subscribe to any number of multicast groups of the
netlink protocol it is connected to. The socket will then receive a
copy of each message sent to any of the groups. Multicast groups are
commonly used to implement event notifications.
Prior to kernel 2.6.14 the group subscription was performed using a
bitmask which limited the number of groups per protocol family to 32.
This outdated interface can still be accessed via the function
nl_join_groups() even though it is not recommended for new code.
#include <netlink/socket.h>
void nl_join_groups(struct nl_sock *sk, int bitmask);
Starting with 2.6.14 a new method was introduced which supports subscribing
to an almost infinite number of multicast groups.
#include <netlink/socket.h>
int nl_socket_add_memberships(struct nl_sock *sk, int group, ...);
int nl_socket_drop_memberships(struct nl_sock *sk, int group, ...);
* This function will be called for each valid netlink message received
* in nl_recvmsgs_default()
static int my_func(struct nl_msg *msg, void *arg)
return 0;
struct nl_sock *sk;
/* Allocate a new socket */
sk = nl_socket_alloc();
* Notifications do not use sequence numbers, disable sequence number
* checking.
nl_socket_disable_seq_check(sk);
* Define a callback function, which will be called for each notification
* received
nl_socket_modify_cb(sk, NL_CB_VALID, NL_CB_CUSTOM, my_func, NULL);
/* Connect to routing netlink protocol */
nl_connect(sk, NETLINK_ROUTE);
/* Subscribe to link notifications group */
nl_socket_add_memberships(sk, RTNLGRP_LINK, 0);
* Start receiving messages. The function nl_recvmsgs_default() will block
* until one or more netlink messages (notification) are received which
* will be passed on to my_func().
while (1)
nl_recvmsgs_default(sock);
3.4. Modifiying Socket Callback Configuration
See Callback Configurations for more information on
callback hooks and overwriting capabilities.
Each socket is assigned a callback configuration which controls the
behaviour of the socket. This is f.e. required to have a separate
message receive function per socket. It is perfectly legal to share
callback configurations between sockets though.
The following functions can be used to access and set the callback
configuration of a socket:
#include <netlink/socket.h>
struct nl_cb *nl_socket_get_cb(const struct nl_sock *sk);
void nl_socket_set_cb(struct nl_sock *sk, struct nl_cb *cb);
Additionaly a shortcut exists to modify the callback configuration
assigned to a socket directly:
#include <netlink/socket.h>
int nl_socket_modify_cb(struct nl_sock *sk, enum nl_cb_type type, enum nl_cb_kind kind,
nl_recvmsg_msg_cb_t func, void *arg);
3.5. Socket Attributes
Local PortThe local port number uniquely identifies the socket and is used to
address it. A unique local port is generated automatically when the
socket is allocated. It will consist of the Process ID (22 bits) and a
random number (10 bits) thus allowing up to 1024 sockets per process.
#include <netlink/socket.h>
uint32_t nl_socket_get_local_port(const struct nl_sock *sk);
void nl_socket_set_local_port(struct nl_sock *sk, uint32_t port);
See section Addressing for more information on port numbers.
Overwriting the local port is possible but you have to ensure
that the provided value is unique and no other socket in any other
application is using the same value.
Peer PortA peer port can be assigned to the socket which will result in all
unicast messages sent over the socket to be addresses to the peer. If
no peer is specified, the message is sent to the kernel which will try
to automatically bind the socket to a kernel side socket of the same
netlink protocol family. It is common practice not to bind the socket
to a peer port as typically only one kernel side socket exists per
netlink protocol family.
#include <netlink/socket.h>
uint32_t nl_socket_get_peer_port(const struct nl_sock *sk);
void nl_socket_set_peer_port(struct nl_sock *sk, uint32_t port);
See section Addressing for more information on port numbers.
File DescriptorNetlink uses the BSD socket interface, therefore a file descriptor is
behind each socket and you may use it directly.
#include <netlink/socket.h>
int nl_socket_get_fd(const struct nl_sock *sk);
If a socket is used to only receive notifications it usually is best
to put the socket in non-blocking mode and periodically poll for new
notifications.
#include <netlink/socket.h>
int nl_socket_set_nonblocking(const struct nl_sock *sk);
Send/Receive Buffer SizeThe socket buffer is used to queue netlink messages between sender and
receiver. The size of these buffers specifies the maximum size you
will be able to write() to a netlink socket, i.e. it will indirectly
define the maximum message size. The default is 32KiB.
#include <netlink/socket.h>
int nl_socket_set_buffer_size(struct nl_sock *sk, int rx, int tx);
Enable/Disable CredentialsTODO
#include <netlink/socket.h>
int nl_socket_set_passcred(struct nl_sock *sk, int state);
Enable/Disable Auto-ACK ModeThe following functions allow to enable/disable Auto-ACK mode on a socket.
See Auto-ACK Mode for more information on what implications that has.
Auto-ACK mode is enabled by default.
#include <netlink/socket.h>
void nl_socket_enable_auto_ack(struct nl_sock *sk);
void nl_socket_disable_auto_ack(struct nl_sock *sk);
Enable/Disable Message PeekingIf enabled, message peeking causes nl_recv() to try and use MSG_PEEK
to retrieve the size of the next message received and allocate a
buffer of that size. Message peeking is enabled by default but can be
disabled using the following function:
#include <netlink/socket.h>
void nl_socket_enable_msg_peek(struct nl_sock *sk);
void nl_socket_disable_msg_peek(struct nl_sock *sk);
Enable/Disable Receival of Packet InformationIf enabled, each received netlink message from the kernel will include
an additional struct nl_pktinfo in the control message. The following
function can be used to enable/disable receival of packet information.
#include <netlink/socket.h>
int nl_socket_recv_pktinfo(struct nl_sock *sk, int state);
4.1. Sending Messages
The standard method of sending a netlink message over a netlink socket
is to use the function nl_send_auto(). It will automatically complete
the netlink message by filling the missing bits and pieces in the
netlink message header and will deal with addressing based on the
options and address set in the netlink socket. The message is then
passed on to nl_send().
If the default sending semantics implemented by nl_send() do not suit
the application, it may overwrite the sending function nl_send() by
specifying an own implementation using the function
nl_cb_overwrite_send().
nl_send_auto(sk, msg)
|-----> nl_complete_msg(sk, msg)
| Own send function specified via nl_cb_overwrite_send()
|- - - - - - - - - - - - - - - - - - - -
nl_send(sk, msg) send_func()
Using nl_send()If you do not require any of the automatic message completion
functionality you may use nl_send() directly but beware that any
internal calls to nl_send_auto() by the library to send netlink
messages will still use nl_send(). Therefore if you wish to use any
higher level interfaces and the behaviour of nl_send() is to your
dislike then you must overwrite the nl_send() function via
nl_cb_overwrite_send()
The purpose of nl_send() is to embed the netlink message into a iovec
structure and pass it on to nl_send_iovec().
nl_send(sk, msg)
nl_send_iovec(sk, msg, iov, iovlen)
Using nl_send_iovec()nl_send_iovec() expects a finalized netlink message and fills out the
struct msghdr used for addressing. It will first check if the struct
nl_msg is addressed to a specific peer (see nlmsg_set_dst()). If not,
it will try to fall back to the peer address specified in the socket
(see nl_socket_set_peer_port(). Otherwise the message will be sent
unaddressed and it is left to the kernel to find the correct peer.
nl_send_iovec() also adds credentials if present and enabled
(see [core_sk_cred]).
The message is then passed on to nl_sendmsg().
nl_send_iovec(sk, msg, iov, iovlen)
nl_sendmsg(sk, msg, msghdr)
Using nl_sendmsg()nl_sendmsg() expects a finalized netlink message and an optional
struct msghdr containing the peer address. It will copy the local
address as defined in the socket (see nl_socket_set_local_port()) into
the netlink message header.
At this point, construction of the message finished and it is ready to
be sent.
nl_sendmsg(sk, msg, msghdr)
|- - - - - - - - - - - - - - - - - - - - v
| NL_CB_MSG_OUT()
|<- - - - - - - - - - - - - - - - - - - -+
sendmsg()
Before sending the application has one last chance to modify the
message. It is passed to the NL_CB_MSG_OUT callback function which
may inspect or modify the message and return an error code. If this
error code is NL_OK the message is sent using sendmsg() resulting in
the number of bytes written being returned. Otherwise the message
sending process is aborted and the error code specified by the
callback function is returned. See Modifiying Socket Callback Configuration for more information
on how to set callbacks.
Sending Raw Data with nl_sendto()If you wish to send raw data over a netlink socket, the following
function will pass on any buffer provided to it directly to sendto():
#include <netlink/netlink.h>
int nl_sendto(struct nl_sock *sk, void *buf, size_t size);
Sending of Simple MessagesA special interface exists for sending of trivial messages. The function
expects the netlink message type, optional netlink message flags, and an
optional data buffer and data length.
#include <netlink/netlink.h>
int nl_send_simple(struct nl_sock *sk, int type, int flags,
void *buf, size_t size);
The function will construct a netlink message header based on the message
type and flags provided and append the data buffer as message payload. The
newly constructed message is sent with nl_send_auto().
The following example will send a netlink request message causing the
kernel to dump a list of all network links to userspace:
#include <netlink/netlink.h>
struct nl_sock *sk;
struct rtgenmsg rt_hdr = {
.rtgen_family = AF_UNSPEC,
sk = nl_socket_alloc();
nl_connect(sk, NETLINK_ROUTE);
nl_send_simple(sock, RTM_GETLINK, NLM_F_DUMP, &rt_hdr, sizeof(rt_hdr));
4.2. Receiving Messages
The easiest method to receive netlink messages is to call nl_recvmsgs_default().
It will receive messages based on the semantics defined in the socket. The
application may customize these in detail although the default behaviour will
probably suit most applications.
nl_recvmsgs_default() will also be called internally by the library whenever
it needs to receive and parse a netlink message.
The function will fetch the callback configuration stored in the socket and
call nl_recvmsgs():
nl_recvmsgs_default(sk)
| cb = nl_socket_get_cb(sk)
nl_recvmsgs(sk, cb)
Using nl_recvmsgs()nl_recvmsgs() implements the actual receiving loop, it blocks until a
netlink message has been received unless the socket has been put into
non-blocking mode.
For the unlikely scenario that certain required receive characteristics
can not be achieved by fine tuning the internal recvmsgs function using
the callback configuration (see Modifiying Socket Callback Configuration) the application may provide
a complete own implementation of it and overwrite all calls to nl_recvmsgs()
with the function nl_cb_overwrite_recvmsgs().
nl_recvmsgs(sk, cb)
| Own recvmsgs function specified via nl_cb_overwrite_recvmsgs()
|- - - - - - - - - - - - - - - - - - - -
internal_recvmsgs() my_recvmsgs()
Receive Characteristics
If the application does not provide its own recvmsgs() implementation
with the function nl_cb_overwrite_recvmsgs() the following characteristics
apply while receiving data from a netlink socket:
internal_recvmsgs()
+-------------->| Own recv function specified with nl_cb_overwrite_recv()
| |- - - - - - - - - - - - - - - -
| v v
| nl_recv() my_recv()
| |<- - - - - - - - - - - - - - -+
| |<-------------+
| v | More data to parse? (nlmsg_next())
| Parse Message |
| |--------------+
+------- NLM_F_MULTI set?
(SUCCESS)
The function nl_recv() is invoked first to receive data from the
netlink socket. This function may be overwritten by the application
by an own implementation using the function nl_cb_overwrite_recv().
This may be useful if the netlink byte stream is in fact not received
from a socket directly but is read from a file or another source.
If data has been read, it will be attemped to parse the data. This
will be done repeately until the parser returns NL_STOP, an error was
returned or all data has been parsed.
In case the last message parsed successfully was a multipart message
(see Multipart Messages) and the parser did not
quit due to either an error or NL_STOP nl_recv() respectively the
applications own implementation will be called again and the parser
starts all over.
See [core_parse_character] for information on how to extract valid
netlink messages from the parser and on how to control the behaviour
of it.
Parsing CharacteristicsThe internal parser is invoked for each netlink message received from
a netlink socket. It is typically fed by nl_recv() (see
[core_recv_character]).
The parser will first ensure that the length of the data stream
provided is sufficient to contain a netlink message header and that
the message length as specified in the message header does not exceed
If this criteria is met, a new struct nl_msg is allocated and the
message is passed on to the the callback function NL_CB_MSG_IN if one
is set. Like any other callback function, it may return NL_SKIP to
skip the current message but continue parsing the next message or
NL_STOP to stop parsing completely.
The next step is to check the sequence number of the message against
the currently expected sequence number. The application may provide
its own sequence number checking algorithm by setting the callback
function NL_CB_SEQ_CHECK to its own implementation. In fact, calling
nl_socket_disable_seq_check() to disable sequence number checking will
do nothing more than set the NL_CB_SEQ_CHECK hook to a function which
always returns NL_OK.
Another callback hook NL_CB_SEND_ACK exists which is called if the
message has the NLM_F_ACK flag set. Although I am not aware of any
userspace netlink socket doing this, the application may want to send
an ACK message back to the sender (see ACKs).
parse()
nlmsg_ok() --> Ignore
|- - - - - - - - - - - - - - - v
| NL_CB_MSG_IN()
|<- - - - - - - - - - - - - - -+
|- - - - - - - - - - - - - - - v
Sequence Check NL_CB_SEQ_CHECK()
|<- - - - - - - - - - - - - - -+
| Message has NLM_F_ACK set
|- - - - - - - - - - - - - - - v
| NL_CB_SEND_ACK()
|<- - - - - - - - - - - - - - -+
Handle Message Type
See Netlink Protocol Fundamentals for an introduction to the netlink
protocol and its message format.
AlignmentMost netlink protocols enforce a strict alignment policy for all
boundries. The alignment value is defined by NLMSG_ALIGNTO and is
fixed to 4 bytes. Therefore all netlink message headers, begin of
payload sections, protocol specific headers, and attribute sections
must start at an offset which is a multiple of NLMSG_ALIGNTO.
#include <netlink/msg.h>
int nlmsg_size(int payloadlen);
int nlmsg_total_size(int payloadlen);
The library provides a set of function to handle alignment
requirements automatically. The function nlmsg_total_size() returns
the total size of a netlink message including the padding to ensure
the next message header is aligned correctly.
<----------- nlmsg_total_size(len) ------------>
<----------- nlmsg_size(len) ------------>
+-------------------+- - -+- - - - - - - - +- - -+-------------------+- - -
| struct nlmsghdr | Pad | Payload | Pad | struct nlsmghdr |
+-------------------+- - -+- - - - - - - - +- - -+-------------------+- - -
<---- NLMSG_HDRLEN -----> <- NLMSG_ALIGN(len) -> <---- NLMSG_HDRLEN ---
If you need to know if padding needs to be added at the end of a
message, nlmsg_padlen() returns the number of padding bytes that need
to be added for a specific payload length.
#include <netlink/msg.h>
int nlmsg_padlen(int payloadlen);
5.2. Parsing a Message
The library offers two different methods of parsing netlink messages.
It offers a low level interface for applications which want to do all
the parsing manually. This method is described below. Alternatively
the library also offers an interface to implement a parser as part of
a cache operations set which is especially useful when your protocol
deals with objects of any sort such as network links, routes, etc.
This high level interface is described in Cache System.
Splitting a byte stream into separate messagesWhat you receive from a netlink socket is typically a stream of
messages. You will be given a buffer and its length, the buffer may
contain any number of netlink messages.
The first message header starts at the beginning of message stream.
Any subsequent message headers are access by calling nlmsg_next() on
the previous header.
#include <netlink/msg.h>
struct nlmsghdr *nlmsg_next(struct nlmsghdr *hdr, int *remaining);
The function nlmsg_next() will automatically substract the size of the
previous message from the remaining number of bytes.
Please note, there is no indication in the previous message whether
another message follows or not. You must assume that more messages
follow until all bytes of the message stream have been processed.
To simplify this, the function nlmsg_ok() exists which returns true if
another message fits into the remaining number of bytes in the message
stream. nlmsg_valid_hdr() is similar, it checks whether a specific
netlink message contains at least a minimum of payload.
#include <netlink/msg.h>
int nlmsg_valid_hdr(const struct nlmsghdr *hdr, int payloadlen);
int nlmsg_ok(const struct nlmsghdr *hdr, int remaining);
A typical use of these functions looks like this:
#include <netlink/msg.h>
void my_parse(void *stream, int length)
struct nlmsghdr *hdr = stream;
while (nlmsg_ok(hdr, length)) {
// Parse message here
hdr = nlmsg_next(hdr, &length);
nlmsg_ok() only returns true if the complete message including
the message payload fits into the remaining buffer length. It will
return false if only a part of it fits.
Message PayloadThe message payload is appended to the message header and is guranteed
to start at a multiple of NLMSG_ALIGNTO
. Padding at the end of the
message header is added if necessary to ensure this. The function
nlmsg_data() will calculate the necessary offset based on the message
and returns a pointer to the start of the message payload.
#include <netlink/msg.h>
void *nlmsg_data(const struct nlmsghdr *nlh);
void *nlmsg_tail(const struct nlmsghdr *nlh);
int nlmsg_datalen(const struct nlmsghdr *nlh);
The length of the message payload is returned by nlmsg_datalen().
<--- nlmsg_datalen(nlh) --->
+-------------------+- - -+----------------------------+- - -+
| struct nlmsghdr | Pad | Payload | Pad |
+-------------------+- - -+----------------------------+- - -+
nlmsg_data(nlh) ---------------^ ^
nlmsg_tail(nlh) --------------------------------------------------^
The payload may consist of arbitary data but may have strict alignment
and formatting rules depening on the actual netlink protocol.
Message AttributesMost netlink protocols use netlink attributes. It not only makes the
protocol self documenting but also gives flexibility in expanding the
protocol at a later point. New attributes can be added at any time and
older attributes can be obsoleted by newer ones without breaking
binary compatibility of the protocol.
<---------------------- payload ------------------------->
<----- hdrlen ----> <- nlmsg_attrlen(nlh, hdrlen) ->
+-------------------+- - -+----- ------------+- - -+--------------------------------+- - -+
| struct nlmsghdr | Pad | Protocol Header | Pad | Attributes | Pad |
+-------------------+- - -+-------------------+- - -+--------------------------------+- - -+
nlmsg_attrdata(nlh, hdrlen) -----------------------------^
The function nlmsg_attrdata() returns a pointer to the begin of the
attributes section. The length of the attributes section is returned
by the function nlmsg_attrlen().
#include <netlink/msg.h>
struct nlattr *nlmsg_attrdata(const struct nlmsghdr *hdr, int hdrlen);
int nlmsg_attrlen(const struct nlmsghdr *hdr, int hdrlen);
See Attributes for more information on how to use netlink attributes.
Parsing a Message the Easy WayThe function nlmsg_parse() validate a complete netlink message in one
step. If hdrlen > 0
it will first call nlmsg_valid_hdr() to check
if the protocol header fits into the message. If there is more payload
to parse, it will assume it to be attributes and parse the payload
accordingly. The function behaves exactly like nla_parse() when
parsing attributes, see [core_attr_parse_easy].
int nlmsg_parse(struct nlmsghdr *hdr, int hdrlen, struct nlattr **attrs,
int maxtype, struct nla_policy *policy);
The function nlmsg_validate() is based on nla_validate() and behaves
exactly the same as nlmsg_parse() except that it only validates and
will not fill a array with pointers to each attribute.
int nlmsg_validate(struct nlmsghdr *hdr, int hdrlen, intmaxtype,
struct nla_policy *policy);
See [core_attr_parse_easy] for an example and more information on
attribute parsing.
5.3. Construction of a Message
See Message Format for information on the netlink message format
and alignment requirements.
Message construction is based on struct nl_msg which uses an internal
buffer to store the actual netlink message. struct nl_msg does not
point to the netlink message header. Use nlmsg_hdr() to retrieve a
pointer to the netlink message header.
At allocation time, a maximum message size is specified. It defaults
to a page (PAGE_SIZE). The application constructing the message will
reserve space out of this maximum message size repeatedly for each
header or attribute added. This allows construction of messages across
various layers of code where lower layers do not need to know about
the space requirements of upper layers.
Why is setting the maximum message size necessary?
This
question is often raised in combination with the proposed solution of
reallocating the message payload buffer on the fly using realloc().
While it is possible to reallocate the buffer during construction
using nlmsg_expand() it will make all pointers into the message buffer
become stale. This breaks usage of nlmsg_hdr(), nla_nest_start(), and
nla_nest_end() and is therefore not acceptable as default behaviour.
Allocating struct nl_msgThe first step in constructing a new netlink message it to allocate a
struct nl_msg
to hold the message header and payload. Several
functions exist to simplify various tasks.
#include <netlink/msg.h>
struct nl_msg *nlmsg_alloc(void);
void nlmsg_free(struct nl_msg *msg);
The function nlmsg_alloc() is the default message allocation function.
It allocates a new message using the default maximum message size which
equals to one page (PAGE_SIZE). The application can change the default
size for messages by calling nlmsg_set_default_size():
void nlmsg_set_default_size(size_t);
Instead of changing the default message size, the function
nlmsg_alloc_size() can be used to allocate a message with a individual
maximum message size.
If the netlink message header is already known at allocation time, the
application may sue nlmsg_inherit(). It will allocate a message using
the default maximum message size and copy the header into the message.
Calling nlmsg_inherit with set
to NULL is equivalent to calling
nlmsg_alloc().
struct nl_msg *nlmsg_inherit(struct nlmsghdr *hdr);
Alternatively nlmsg_alloc_simple() takes a netlink message type and
netlink message flags. It is equivalent to nlmsg_inherit() except that it
takes the two common header fields as arguments instead of a complete
header.
#include <netlink/msg.h>
struct nl_msg *nlmsg_alloc_simple(int nlmsg_type, int flags);
Appending the netlink message headerAfter allocating struct nl_msg, the netlink message header needs to be
added unless one of the function nlmsg_alloc_simple() or nlmsg_inherit()
have been used for allocation in which case this step will replace the
netlink message header already in place.
#include <netlink/msg.h>
struct nlmsghdr *nlmsg_put(struct nl_msg *msg, uint32_t port, uint32_t seqnr,
int nlmsg_type, int payload, int nlmsg_flags);
The function nlmsg_put() will build a netlink message header out of
nlmsg_type
, nlmsg_flags
, seqnr
, and port
and copy it into the
netlink message. seqnr
can be set to NL_AUTO_SEQ
to indiciate
that the next possible sequence number should be used automatically.
To use this feature, the message must be sent using the function
nl_send_auto(). Like port
, the argument seqnr
can be set to
NL_AUTO_PORT
indicating that the local port assigned to the socket
should be used as source port. This is generally a good idea unless
you are replying to a request. See Netlink Protocol Fundamentals
for more information on how to fill the header.
The argument payload
can be used by the application to reserve
room for additional data after the header. A value of > 0 is
equivalent to calling nlmsg_reserve(msg, payload, NLMSG_ALIGNTO)
.
See [core_msg_reserve] for more information on reserving room for
data.
* Add header with message type MY_MSGTYPE, the flag NLM_F_CREATE,
* let library fill port and sequence number, and reserve room for
* struct myhdr
hdr = nlmsg_put(msg, NL_AUTO_PORT, NL_AUTO_SEQ, MY_MSGTYPE, sizeof(hdr), NLM_F_CREATE);
/* Copy own header into newly reserved payload section */
memcpy(nlmsg_data(hdr), &hdr, sizeof(hdr));
* The message will now look like this:
* +-------------------+- - -+----------------+- - -+
* | struct nlmsghdr | Pad | struct myhdr | Pad |
* +-------------------+-----+----------------+- - -+
* nlh -^ / \
* +--------+---------+
* | foo1 | foo2 |
* +--------+---------+
Reserving room at the end of the messageMost functions described later on will automatically take care of
reserving room for the data that is added to the end of the netlink
message. In some situations it may be requried for the application
to reserve room directly though.
#include <netlink/msg.h>
void *nlmsg_reserve(struct nl_msg *msg, size_t len, int pad);
The function nlmsg_reserve() reserves len
bytes at the end of the
netlink message and returns a pointer to the start of the reserved area.
The pad
argument can be used to request len
to be aligned to any
number of bytes prior to reservation.
The following example requests to reserve a 17 bytes area at the end of
message aligned to 4 bytes. Therefore a total of 20 bytes will be
reserved.
#include <netlink/msg.h>
void *buf = nlmsg_reserve(msg, 17, 4);
nlmsg_reserve()
will not align the start of the buffer. Any
alignment requirements must be provided by the owner of the
previous message section.
Appending data at the end of the messageThe function nlmsg_append()
appends len
bytes at the end of the
message, padding it if requested and necessary.
#include <netlink/msg.h>
int nlmsg_append(struct nl_msg *msg, void *data, size_t len, int pad);
It is equivalent to calling nlmsg_reserve()
and `memcpy()`ing the
data into the freshly reserved data section.
nlmsg_append()
will not align the start of the data. Any
alignment requirements must be provided by the owner of the
previous message section.
Adding attribtues to a messageConstruction of attributes and addition of attribtues to the message is
covereted in section Attributes.
Any form of payload should be encoded as netlink attributes whenever
possible. Use of attributes allows to extend any netlink protocol in
the future without breaking binary compatibility. F.e. Suppose your
device may currently be using 32 bit counters for statistics but years
later the device switches to maintaining 64 bit counters to account
for faster network hardware. If your protocol is using attributes the
move to 64 bit counters is trivial and only involves in sending an
additional attribute containing the 64 bit variants while still
providing the old legacy 32 bit counters. If your protocol is not using
attributes you will not be able to switch data types without breaking
all existing users of the protocol.
The concept of nested attributes also allows for subsystems of your
protocol to implement and maintain their own attribute schemas. Suppose
a new generation of network device is introduced which requires a
completely new set of configuration settings which was unthinkable when
the netlink protocol was initially designed. Using attributes the new
generation of devices may define a new attribute and fill it with its
own new structure of attributes which extend or even obsolete the old
attributes.
Therefore, always use attributes even if you are almost certain that
the message format will never ever change in the future.
6.1. Attribute Format
Netlink attributes allow for any number of data chunks of arbitary
length to be attached to a netlink message. See [core_msg_attr]
for more information on where attributes are stored in the message.
The format of the attributes data returned by nlmsg_attrdata() is as
follows:
<----------- nla_total_size(payload) ----------->
<---------- nla_size(payload) ----------->
+-----------------+- - -+- - - - - - - - - +- - -+-----------------+- - -
| struct nlattr | Pad | Payload | Pad | struct nlattr |
+-----------------+- - -+- - - - - - - - - +- - -+-----------------+- - -
<---- NLA_HDRLEN -----> <--- NLA_ALIGN(len) ---> <---- NLA_HDRLEN ---
Every attribute must start at an offset which is a multiple of
NLA_ALIGNTO
(4 bytes). If you need to know whether an attribute needs
to be padded at the end, the function nla_padlen() returns the number
of padding bytes that will or need to be added.
Every attribute is encoded with a type and length field, both 16 bits,
stored in the attribute header (struct nlattr) preceding the attribute
payload. The length of an attribute is used to calculate the offset to
the next attribute.
6.2. Parsing Attributes
Splitting an Attributes Stream into AttributesAlthough most applications will use one of the functions from the
nlmsg_parse() family (See [core_attr_parse_easy]) an interface exists
to split the attributes stream manually.
As described in Attribute Format the attributes section contains a
infinite sequence or stream of attributes. The pointer returned by
nlmsg_attrdata() (See [core_msg_attr]) points to the first attribute
header. Any subsequent attribute is accessed with the function nla_next()
based on the previous header.
#include <netlink/attr.h>
struct nlattr *nla_next(const struct nlattr *attr, int *remaining);
The semantics are equivalent to nlmsg_next() and thus nla_next() will also
subtract the size of the previous attribute from the remaining number of
bytes in the attributes stream.
Like messages, attributes do not contain an indicator whether another
attribute follows or not. The only indication is the number of bytes left
in the attribute stream. The function nla_ok() exists to determine whether
another attribute fits into the remaining number of bytes or not.
#include <netlink/attr.h>
int nla_ok(const struct nlattr *attr, int remaining);
#include <netlink/msg.h>
#include <netlink/attr.h>
struct nlattr *hdr = nlmsg_attrdata(msg, 0);
int remaining = nlmsg_attrlen(msg, 0);
while (nla_ok(hdr, remaining)) {
/* parse attribute here */
hdr = nla_next(hdr, &remaining);
nla_ok()
only returns true if the complete attributes
including the attribute payload fits into the remaining number
of bytes.
Accessing Attribute Header and Payload
Once the individual attributes have been sorted out by either splitting
the attributes stream or using another interface the attribute header
and payload can be accessed.
<- nla_len(hdr) ->
+-----------------+- - -+- - - - - - - - - +- - -+
| struct nlattr | Pad | Payload | Pad |
+-----------------+- - -+- - - - - - - - - +- - -+
nla_data(hdr) ---------------^
The functions nla_len() and nla_type() can be used to access the attribute
header. nla_len() will return the length of the payload not including
eventual padding bytes. nla_type returns the attribute type.
#include <netlink/attr.h>
int nla_len(const struct nlattr *hdr);
int nla_type(const struct nlattr *hdr);
The function nla_data() will return a pointer to the attribute
payload. Please note that due to NLA_ALIGNTO
being 4 bytes it may
not be safe to cast and dereference the pointer for any datatype
larger than 32 bit depending on the architecture the application is
run on.
#include <netlink/attr.h>
void *nla_data(const struct nlattr *hdr);
Never rely on the size of a payload being what you expect it to be.
Always verify the payload size and make sure that it matches your
expectations. See [core_attr_validation]
Attribute ValidationWhen receiving netlink attributes, the receiver has certain expections
on how the attributes should look like. These expectations must be
defined to make sure the sending side meets our expecations. For this
purpose, a attribute validation interface exists which must be used
prior to accessing any payload.
All functions providing attribute validation functionality are based
on struct nla_policy:
struct nla_policy {
uint16_t type;
uint16_t minlen;
uint16_t maxlen;
The type
member specifies the datatype of the attribute, e.g.
NLA_U32
, NLA_STRING
, NLA_FLAG
. The default is NLA_UNSPEC
. The
minlen
member defines the minmum payload length of an attribute to
be considered a valid attribute. The value for minlen
is implicit
for most basic datatypes such as integers or flags. The maxlen
member can be used to define a maximum payload length for an
attribute to still be considered valid.
Specyfing a maximum payload length is not recommended when
encoding structures in an attribute as it will prevent any
extension of the structure in the future. Something that is
frequently done in netlink protocols and does not break
backwards compatibility.
One of the functions which use struct nla_policy is nla_validate().
The function expects an array of struct nla_policy and will access the
array using the attribute type as index. If an attribute type is out
of bounds the attribute is assumed to be valid. This is intentional
behaviour to allow older applications not yet aware of recently
introduced attributes to continue functioning.
#include <netlink/attr.h>
int nla_validate(struct nlattr *head, int len, int maxtype, struct nla_policy *policy);
The function nla_validate() returns 0 if all attributes are valid,
otherwise a validation failure specific error code is returned.
Most applications will rarely use nla_validate() directly but use
nla_parse() instead which takes care of validation in the same way but
also parses the the attributes in the same step. See
[core_attr_parse_easy] for an example and more information.
The validation process in detail:
Parsing Attributes the Easy WayMost applications will not want to deal with splitting attribute
streams themselves as described in [core_attr_parse_split]
A much easier method is to use nla_parse().
#include <netlink/attr.h>
int nla_parse(struct nlattr **attrs, int maxtype, struct nlattr *head,
int len, struct nla_policy *policy);
The function nla_parse() will iterate over a stream of attributes,
validate each attribute as described in [core_attr_validation]
If the validation of all attributes succeeds, a pointer to each attribute
is stored in the attrs
array at attrs[nla_type(attr)]
.
As an alernative to nla_parse() the function nlmsg_parse() can be used
to parse the message and its attributes in one step. See
[core_attr_parse_easy] for information on how to use these functions.
Example:The following example demonstrates how to parse a netlink message sent
over a netlink protocol which does not use protocol headers. The example
does enforce a attribute policy however, the attribute MY_ATTR_FOO must
be a 32 bit integer, and the attribute MY_ATTR_BAR must be a string with
a maximum length of 16 characters.
#include <netlink/msg.h>
#include <netlink/attr.h>
enum {
MY_ATTR_FOO = 1,
MY_ATTR_BAR,
__MY_ATTR_MAX,
#define MY_ATTR_MAX (__MY_ATTR_MAX - 1)
static struct nla_policy my_policy[MY_ATTR_MAX+1] = {
[MY_ATTR_FOO] = { .type = NLA_U32 },
[MY_ATTR_BAR] = { .type = NLA_STRING,
.maxlen = 16 },
void parse_msg(struct nlmsghdr *nlh)
struct nlattr *attrs[MY_ATTR_MAX+1];
if (nlmsg_parse(nlh, 0, attrs, MY_ATTR_MAX, my_policy) < 0)
/* error */
if (attrs[MY_ATTR_FOO]) {
/* MY_ATTR_FOO is present in message */
printf("value: %u\n", nla_get_u32(attrs[MY_ATTR_FOO]));
Locating a Single AttributeAn application only interested in a single attribute can use one of the
functions nla_find() or nlmsg_find_attr(). These function will iterate
over all attributes, search for a matching attribute and return a pointer
to the corresponding attribute header.
#include <netlink/attr.h>
struct nlattr *nla_find(struct nlattr *head, int len, int attrtype);
6.2.1. Iterating over a Stream of Attributes
In some situations it does not make sense to assign a unique attribute
type to each attribute in the attribute stream. For example a list may
be transferd using a stream of attributes and even if the attribute type
is incremented for each attribute it may not make sense to use the
nlmsg_parse() or nla_parse() function to fill an array.
Therefore methods exist to iterate over a stream of attributes:
#include <netlink/attr.h>
nla_for_each_attr(attr, head, len, remaining)
nla_for_each_attr() is a macro which can be used in front of a code
block:
#include <netlink/attr.h>
struct nalttr *nla;
int rem;
nla_for_each_attr(nla, attrstream, streamlen, rem) {
/* validate & parse attribute */
if (rem > 0)
/* unparsed attribute data */
6.3. Attribute Construction
The interface to add attributes to a netlink message is based on the
regular message construction interface. It assumes that the message
header and an eventual protocol header has been added to the message
already.
struct nlattr *nla_reserve(struct nl_msg *msg, int attrtype, int len);
The function nla_reserve() adds an attribute header at the end of the
message and reserves room for len
bytes of payload. The function
returns a pointer to the attribute payload section inside the message.
Padding is added at the end of the attribute to ensure the next
attribute is properly aligned.
int nla_put(struct nl_msg *msg, int attrtype, int attrlen, const void *data);
The function nla_put() is base don nla_reserve() but takes an additional
pointer data
pointing to a buffer containing the attribute payload.
It will copy the buffer into the message automatically.
Example:
struct my_attr_struct {
uint32_t a;
uint32_t b;
int my_put(struct nl_msg *msg)
struct my_attr_struct obj = {
.a = 10,
.b = 20,
return nla_put(msg, ATTR_MY_STRUCT, sizeof(obj), &obj);
See Attribute Data Types for datatype specific attribute construction
functions.
Exception Based Attribute ConstructionLike in the kernel API an exception based construction interface is
provided. The behaviour of the macros is identical to their regular
function counterparts except that in case of an error, the target
nla_put_failure
is jumped.
Example:
#include <netlink/msg.h>
#include <netlink/attr.h>
void construct_attrs(struct nl_msg *msg)
NLA_PUT_STRING(msg, MY_ATTR_FOO1, "some text");
NLA_PUT_U32(msg, MY_ATTR_FOO1, 0x1010);
NLA_PUT_FLAG(msg, MY_ATTR_FOO3, 1);
return 0;
nla_put_failure:
/* NLA_PUT* macros jump here in case of an error */
return -EMSGSIZE;
See Attribute Data Types for more information on the datatype specific
exception based variants.
6.4. Attribute Data Types
A number of basic data types have been defined to simplify access and
validation of attributes. The datatype is not encoded in the
attribute, therefore bthe sender and receiver are required to use the
same definition on what attribute is of what type.
Besides simplified access to the payload of such datatypes, the major
advantage is the automatic validation of each attribute based on a
policy. The validation ensures safe access to the payload by checking
for minimal payload size and can also be used to enforce maximum
payload size for some datatypes.
6.4.1. Integer Attributes
The most frequently used datatypes are integers. Integers come in four
different sizes:
Note that due to the alignment requirements of attributes the integer
attribtue NLA_u8
and NLA_U16
will not result in space savings in
the netlink message. Their use is intended to limit the range of
values.
Parsing Integer Attributes
#include <netlink/attr.h>
uint8_t nla_get_u8(struct nlattr *hdr);
uint16_t nla_get_u16(struct nlattr *hdr);
uint32_t nla_get_u32(struct nlattr *hdr);
uint64_t nla_get_u64(struct nlattr *hdr);
Example:
if (attrs[MY_ATTR_FOO])
uint32_t val = nla_get_u32(attrs[MY_ATTR_FOO]);
int nla_put_u8(struct nl_msg *msg, int attrtype, uint8_t value);
int nla_put_u16(struct nl_msg *msg, int attrtype, uint16_t value);
int nla_put_u32(struct nl_msg *msg, int attrtype, uint32_t value);
int nla_put_u64(struct nl_msg *msg, int attrtype, uint64_t value);
Exception based:
NLA_PUT_U8(msg, attrtype, value)
NLA_PUT_U16(msg, attrtype, value)
NLA_PUT_U32(msg, attrtype, value)
NLA_PUT_U64(msg, attrtype, value)
ValidationUse NLA_U8
, NLA_U16
, NLA_U32
, or NLA_U64
to define the type of
integer when filling out a struct nla_policy array. It will
automatically enforce the correct minimum payload length policy.
Validation does not differ between signed and unsigned integers, only
the size matters. If the appliaction wishes to enforce particular value
ranges it must do so itself.
static struct nla_policy my_policy[ATTR_MAX+1] = {
[ATTR_FOO] = { .type = NLA_U32 },
[ATTR_BAR] = { .type = NLA_U8 },
The above is equivalent to:
static struct nla_policy my_policy[ATTR_MAX+1] = {
[ATTR_FOO] = { .minlen = sizeof(uint32_t) },
[ATTR_BAR] = { .minlen = sizeof(uint8_t) },
6.4.2. String Attributes
The string datatype represents a NUL termianted character string of
variable length. It is not intended for binary data streams.
The payload of string attributes can be accessed with the function
nla_get_string(). nla_strdup() calls strdup() on the payload and returns
the newly allocated string.
#include <netlink/attr.h>
char *nla_get_string(struct nlattr *hdr);
char *nla_strdup(struct nlattr *hdr);
String attributes are constructed with the function nla_put_string()
respectively NLA_PUT_STRING()
. The length of the payload will be
strlen()+1, the trailing NUL byte is included.
int nla_put_string(struct nl_msg *msg, int attrtype, const char *data);
NLA_PUT_STRING(msg, attrtype, data)
For validation purposes the type NLA_STRING
can be used in
struct nla_policy
definitions. It implies a minimum payload length
of 1 byte and checks for a trailing NUL byte. Optionally the maxlen
member defines the maximum length of a character string (including the
trailing NUL byte).
static struct nla_policy my_policy[] = {
[ATTR_FOO] = { .type = NLA_STRING,
.maxlen = IFNAMSIZ },
6.4.3. Flag Attributes
The flag attribute represents a boolean datatype. The presence of the
attribute implies a value of true
, the absence of the attribute
implies the value false
. Therefore the payload length of flag
attributes is always 0.
int nla_get_flag(struct nlattr *hdr);
int nla_put_flag(struct nl_msg *msg, int attrtype);
The type NLA_FLAG
is used for validation purposes. It implies a
maxlen
value of 0 and thus enforces a maximum payload length of 0.
Example:
/* nla_put_flag() appends a zero sized attribute to the message. */
nla_put_flag(msg, ATTR_FLAG);
/* There is no need for a receival function, the presence is the value. */
if (attrs[ATTR_FLAG])
/* flag is present */
6.4.4. Nested Attributes
As described in Attributes, attributes can be nested allowing for
complex tree structures of attributes. It is commonly used to delegate
the responsibility of a subsection of the message to a subsystem.
Nested attributes are also commonly used for transmitting list of objects.
When nesting attributes, the nested attributes are included as payload
of a container attribute.
When validating the attributes using nlmsg_validate(),
nlmsg_parse(), nla_validate(), or nla_parse() only the
attributes on the first level are being validated. None of these
functions will validate attributes recursively. Therefore you
must explicitely call nla_validate() or use nla_parse_nested()
for each level of nested attributes.
The type NLA_NESTED
should be used when defining nested attributes
in a struct nla_policy definition. It will not enforce any minimum
payload length unless minlen
is specified explicitely. This is
because some netlink protocols implicitely allow empty container
attributes.
static struct nla_policy my_policy[] = {
[ATTR_OPTS] = { .type =