Logo Search packages:      
Sourcecode: libnl2 version File versions  Download package

Attributes
[Messages]


Detailed Description

Netlink Attributes Construction/Parsing Interface

Netlink Attributes

Netlink attributes allow for data chunks of arbitary length to be attached to a netlink message. Each attribute is encoded with a type and length field, both 16 bits, stored in the attribute header preceding the attribute data. The main advantage of using attributes over packing everything into the family header is that the interface stays extendable as new attributes can supersede old attributes while remaining backwards compatible. Also attributes can be defined optional thus avoiding the transmission of unnecessary empty data blocks. Special nested attributes allow for more complex data structures to be transmitted, e.g. trees, lists, etc.

While not required, netlink attributes typically follow the family header of a netlink message and must be properly aligned to NLA_ALIGNTO:

   +----------------+- - -+---------------+- - -+------------+- - -+
   | Netlink Header | Pad | Family Header | Pad | Attributes | Pad |
   +----------------+- - -+---------------+- - -+------------+- - -+

The actual attributes are chained together each separately aligned to NLA_ALIGNTO. The position of an attribute is defined based on the length field of the preceding attributes:

   +-------------+- - -+-------------+- - -+------
   | Attribute 1 | Pad | Attribute 2 | Pad | ...
   +-------------+- - -+-------------+- - -+------
   nla_next(attr1)------^

The attribute itself consists of the attribute header followed by the actual payload also aligned to NLA_ALIGNTO. The function nla_data() returns a pointer to the start of the payload while nla_len() returns the length of the payload in bytes.

Note: Be aware, NLA_ALIGNTO equals to 4 bytes, therefore it is not safe to dereference any 64 bit data types directly.

    <----------- nla_total_size(payload) ----------->
    <-------- nla_attr_size(payload) --------->
   +------------------+- - -+- - - - - - - - - +- - -+
   | Attribute Header | Pad |     Payload      | Pad |
   +------------------+- - -+- - - - - - - - - +- - -+
   nla_data(nla)-------------^
                             <- nla_len(nla) ->

Attribute Data Types

A number of basic data types are supported to simplify access and validation of netlink attributes. This data type information is not encoded in the attribute, both the kernel and userspace part are required to share this information on their own.

One of the major advantages of these basic types is the automatic validation of each attribute based on an attribute policy. The validation covers most of the checks required to safely use attributes and thus keeps the individual sanity check to a minimum.

Never access attribute payload without ensuring basic validation first, attributes may:

Policies are defined as array of the struct nla_policy. The array is indexed with the attribute type, therefore the array must be sized accordingly.

 static struct nla_policy my_policy[ATTR_MAX+1] = {
      [ATTR_FOO] = { .type = ..., .minlen = ..., .maxlen = ... },
 };

 err = nla_validate(attrs, attrlen, ATTR_MAX, &my_policy);

Some basic validations are performed on every attribute, regardless of type.

Unspecific Attribute (NLA_UNSPEC)
This is the standard type if no type is specified. It is used for binary data of arbitary length. Typically this attribute carries a binary structure or a stream of bytes.
 // In this example, we will assume a binary structure requires to
 // be transmitted. The definition of the structure will typically
 // go into a header file available to both the kernel and userspace
 // side.
 //
 // Note: Be careful when putting 64 bit data types into a structure.
 // The attribute payload is only aligned to 4 bytes, dereferencing
 // the member may fail.
 struct my_struct {
     int a;
     int b;
 };

 // The validation function will not enforce an exact length match to
 // allow structures to grow as required. Note: While it is allowed
 // to add members to the end of the structure, changing the order or
 // inserting members in the middle of the structure will break your
 // binary interface.
 static struct nla_policy my_policy[ATTR_MAX+1] = {
     [ATTR_MY_STRICT] = { .type = NLA_UNSPEC,
                          .minlen = sizeof(struct my_struct) },

 // The binary structure is appened to the message using nla_put()
 struct my_struct foo = { .a = 1, .b = 2 };
 nla_put(msg, ATTR_MY_STRUCT, sizeof(foo), &foo);

 // On the receiving side, a pointer to the structure pointing inside
 // the message payload is returned by nla_get().
 if (attrs[ATTR_MY_STRUCT])
     struct my_struct *foo = nla_get(attrs[ATTR_MY_STRUCT]);
Integers (NLA_U8, NLA_U16, NLA_U32, NLA_U64)
Integers come in different sizes from 8 bit to 64 bit. However, since the payload length is aligned to 4 bytes, integers smaller than 32 bit are only useful to enforce the maximum range of values.
Note: There is no difference made between signed and unsigned integers. The validation only enforces the minimal payload length required to store an integer of specified type.
 // Even though possible, it does not make sense to specify .minlen or
 // .maxlen for integer types. The data types implies the corresponding
 // minimal payload length.
 static struct nla_policy my_policy[ATTR_MAX+1] = {
     [ATTR_FOO] = { .type = NLA_U32 },

 // Numeric values can be appended directly using the respective
 // nla_put_uxxx() function
 nla_put_u32(msg, ATTR_FOO, 123);

 // Same for the receiving side.
 if (attrs[ATTR_FOO])
     uint32_t foo = nla_get_u32(attrs[ATTR_FOO]);
Character string (NLA_STRING)
This data type represents a NUL terminated character string of variable length. For binary data streams the type NLA_UNSPEC is recommended.
 // Enforce a NUL terminated character string of at most 4 characters
 // including the NUL termination.
 static struct nla_policy my_policy[ATTR_MAX+1] = {
     [ATTR_BAR] = { .type = NLA_STRING, maxlen = 4 },

 // nla_put_string() creates a string attribute of the necessary length
 // and appends it to the message including the NUL termination.
 nla_put_string(msg, ATTR_BAR, "some text");

 // It is safe to use the returned character string directly if the
 // attribute has been validated as the validation enforces the proper
 // termination of the string.
 if (attrs[ATTR_BAR])
     char *text = nla_get_string(attrs[ATTR_BAR]);
Flag (NLA_FLAG)
This attribute type may be used to indicate the presence of a flag. The attribute is only valid if the payload length is zero. The presence of the attribute header indicates the presence of the flag.
 // This attribute type is special as .minlen and .maxlen have no effect.
 static struct nla_policy my_policy[ATTR_MAX+1] = {
     [ATTR_FLAG] = { .type = NLA_FLAG },

 // 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
Micro Seconds (NLA_MSECS)
Nested Attribute (NLA_NESTED)
Attributes can be nested and put into a container to create groups, lists or to construct trees of attributes. Nested attributes are often used to pass attributes to a subsystem where the top layer has no knowledge of the configuration possibilities of each subsystem.
Note: When validating the attributes using nlmsg_validate() or nlmsg_parse() it will only affect the top level attributes. Each level of nested attributes must be validated seperately using nla_parse_nested() or nla_validate().
 // The minimal length policy may be used to enforce the presence of at
 // least one attribute.
 static struct nla_policy my_policy[ATTR_MAX+1] = {
     [ATTR_OPTS] = { .type = NLA_NESTED, minlen = NLA_HDRLEN },

 // Nested attributes are constructed by enclosing the attributes
 // to be nested with calls to nla_nest_start() respetively nla_nest_end().
 struct nlattr *opts = nla_nest_start(msg, ATTR_OPTS);
 nla_put_u32(msg, ATTR_FOO, 123);
 nla_put_string(msg, ATTR_BAR, "some text");
 nla_nest_end(msg, opts);

 // Various methods exist to parse nested attributes, the easiest being
 // nla_parse_nested() which also allows validation in the same step.
 if (attrs[ATTR_OPTS]) {
     struct nlattr *nested[ATTR_MAX+1];

     nla_parse_nested(nested, ATTR_MAX, attrs[ATTR_OPTS], &policy);

     if (nested[ATTR_FOO])
         uint32_t foo = nla_get_u32(nested[ATTR_FOO]);
 }

Exception Based Attribute Construction

Often a large number of attributes are added to a message in a single function. In order to simplify error handling, a second set of construction functions exist which jump to a error label when they fail instead of returning an error code. This second set consists of macros which are named after their error code based counterpart except that the name is written all uppercase.

All of the macros jump to the target nla_put_failure if they fail.

 void my_func(struct nl_msg *msg)
 {
     NLA_PUT_U32(msg, ATTR_FOO, 10);
     NLA_PUT_STRING(msg, ATTR_BAR, "bar");

     return 0;

 nla_put_failure:
     return -NLE_NOMEM;
 }

Examples

Example 1.1 Constructing a netlink message with attributes.
 struct nl_msg *build_msg(int ifindex, struct nl_addr *lladdr, int mtu)
 {
     struct nl_msg *msg;
     struct nlattr *info, *vlan;
     struct ifinfomsg ifi = {
         .ifi_family = AF_INET,
         .ifi_index = ifindex,
     };

     // Allocate a new netlink message, type=RTM_SETLINK, flags=NLM_F_ECHO
     if (!(msg = nlmsg_alloc_simple(RTM_SETLINK, NLM_F_ECHO)))
         return NULL;

     // Append the family specific header (struct ifinfomsg)
     if (nlmsg_append(msg, &ifi, sizeof(ifi), NLMSG_ALIGNTO) < 0)
         goto nla_put_failure

     // Append a 32 bit integer attribute to carry the MTU
     NLA_PUT_U32(msg, IFLA_MTU, mtu);

     // Append a unspecific attribute to carry the link layer address
     NLA_PUT_ADDR(msg, IFLA_ADDRESS, lladdr);

     // Append a container for nested attributes to carry link information
     if (!(info = nla_nest_start(msg, IFLA_LINKINFO)))
         goto nla_put_failure;

     // Put a string attribute into the container
     NLA_PUT_STRING(msg, IFLA_INFO_KIND, "vlan");

     // Append another container inside the open container to carry
     // vlan specific attributes
     if (!(vlan = nla_nest_start(msg, IFLA_INFO_DATA)))
         goto nla_put_failure;

     // add vlan specific info attributes here...

     // Finish nesting the vlan attributes and close the second container.
     nla_nest_end(msg, vlan);

     // Finish nesting the link info attribute and close the first container.
     nla_nest_end(msg, info);

     return msg;

 // If any of the construction macros fails, we end up here.
 nla_put_failure:
     nlmsg_free(msg);
     return NULL;
 }
Example 2.1 Parsing a netlink message with attributes.
 int parse_message(struct nl_msg *msg)
 {
     // The policy defines two attributes: a 32 bit integer and a container
     // for nested attributes.
     struct nla_policy attr_policy[ATTR_MAX+1] = {
         [ATTR_FOO] = { .type = NLA_U32 },
         [ATTR_BAR] = { .type = NLA_NESTED },
     };
     struct nlattr *attrs[ATTR_MAX+1];
     int err;

     // The nlmsg_parse() function will make sure that the message contains
     // enough payload to hold the header (struct my_hdr), validates any
     // attributes attached to the messages and stores a pointer to each
     // attribute in the attrs[] array accessable by attribute type.
     if ((err = nlmsg_parse(nlmsg_hdr(msg), sizeof(struct my_hdr), attrs,
                            ATTR_MAX, attr_policy)) < 0)
         goto errout;

     if (attrs[ATTR_FOO]) {
         // It is safe to directly access the attribute payload without
         // any further checks since nlmsg_parse() enforced the policy.
         uint32_t foo = nla_get_u32(attrs[ATTR_FOO]);
     }

     if (attrs[ATTR_BAR]) {
         struct nlattr *nested[NESTED_MAX+1];

         // Attributes nested in a container can be parsed the same way
         // as top level attributes.
         if ((err = nla_parse_nested(nested, NESTED_MAX, attrs[ATTR_BAR],
                                     nested_policy)) < 0)
             goto errout;

         // Process nested attributes here.
     }

     err = 0;
 errout:
     return err;
 }


Classes

struct  nla_policy

Basic Attribute Data Types

enum  {
  NLA_UNSPEC, NLA_U8, NLA_U16, NLA_U32,
  NLA_U64, NLA_STRING, NLA_FLAG, NLA_MSECS,
  NLA_NESTED, __NLA_TYPE_MAX
}

Parsing Attributes

static uint16_t nla_attr_minlen [NLA_TYPE_MAX+1]
void * nla_data (const struct nlattr *nla)
struct nlattr * nla_find (struct nlattr *head, int len, int attrtype)
int nla_len (const struct nlattr *nla)
struct nlattr * nla_next (const struct nlattr *nla, int *remaining)
int nla_ok (const struct nlattr *nla, int remaining)
int nla_parse (struct nlattr *tb[], int maxtype, struct nlattr *head, int len, struct nla_policy *policy)
int nla_type (const struct nlattr *nla)
int nla_validate (struct nlattr *head, int len, int maxtype, struct nla_policy *policy)
static int validate_nla (struct nlattr *nla, int maxtype, struct nla_policy *policy)

Attribute Size Calculation

int nla_attr_size (int payload)
int nla_padlen (int payload)
int nla_total_size (int payload)

Flag Attribute

int nla_get_flag (struct nlattr *nla)
int nla_put_flag (struct nl_msg *msg, int attrtype)

Microseconds Attribute

unsigned long nla_get_msecs (struct nlattr *nla)
int nla_put_msecs (struct nl_msg *n, int attrtype, unsigned long msecs)

String Attribute

char * nla_get_string (struct nlattr *nla)
int nla_put_string (struct nl_msg *msg, int attrtype, const char *str)
char * nla_strdup (struct nlattr *nla)

Integer Attributes

uint16_t nla_get_u16 (struct nlattr *nla)
uint32_t nla_get_u32 (struct nlattr *nla)
uint64_t nla_get_u64 (struct nlattr *nla)
uint8_t nla_get_u8 (struct nlattr *nla)
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)
int nla_put_u8 (struct nl_msg *msg, int attrtype, uint8_t value)

Helper Functions

int nla_memcmp (const struct nlattr *nla, const void *data, size_t size)
int nla_memcpy (void *dest, struct nlattr *src, int count)
int nla_strcmp (const struct nlattr *nla, const char *str)
size_t nla_strlcpy (char *dst, const struct nlattr *nla, size_t dstsize)

Nested Attribute

int nla_nest_end (struct nl_msg *msg, struct nlattr *start)
struct nlattr * nla_nest_start (struct nl_msg *msg, int attrtype)
int nla_parse_nested (struct nlattr *tb[], int maxtype, struct nlattr *nla, struct nla_policy *policy)
int nla_put_nested (struct nl_msg *msg, int attrtype, struct nl_msg *nested)

Unspecific Attribute

int nla_put (struct nl_msg *msg, int attrtype, int datalen, const void *data)
int nla_put_addr (struct nl_msg *msg, int attrtype, struct nl_addr *addr)
int nla_put_data (struct nl_msg *msg, int attrtype, struct nl_data *data)
struct nlattr * nla_reserve (struct nl_msg *msg, int attrtype, int attrlen)

Iterators

#define nla_for_each_attr(pos, head, len, rem)
#define nla_for_each_nested(pos, nla, rem)

Attribute Construction (Exception Based)

#define NLA_PUT(msg, attrtype, attrlen, data)
#define NLA_PUT_ADDR(msg, attrtype, addr)
#define NLA_PUT_DATA(msg, attrtype, data)
#define NLA_PUT_FLAG(msg, attrtype)   NLA_PUT(msg, attrtype, 0, NULL)
#define NLA_PUT_MSECS(msg, attrtype, msecs)   NLA_PUT_U64(msg, attrtype, msecs)
#define NLA_PUT_STRING(msg, attrtype, value)   NLA_PUT(msg, attrtype, strlen(value) + 1, value)
#define NLA_PUT_TYPE(msg, type, attrtype, value)
#define NLA_PUT_U16(msg, attrtype, value)   NLA_PUT_TYPE(msg, uint16_t, attrtype, value)
#define NLA_PUT_U32(msg, attrtype, value)   NLA_PUT_TYPE(msg, uint32_t, attrtype, value)
#define NLA_PUT_U64(msg, attrtype, value)   NLA_PUT_TYPE(msg, uint64_t, attrtype, value)
#define NLA_PUT_U8(msg, attrtype, value)   NLA_PUT_TYPE(msg, uint8_t, attrtype, value)


Generated by  Doxygen 1.6.0   Back to index