8

I am new in netlink programming. I am writing a generic netlink program for creating a netlink protocol family. I have searched many documents on the internet and I found something "Attributes and Policies" like things for defining a netlink family.

I am totally confused with these things.

I found something like bellow about attributes in linux/netlink.h

 <------- NLA_HDRLEN ------> <-- NLA_ALIGN(payload)-->
+---------------------------+- - -+- - - - - - - - - -+- - -+
|        Header             | Pad |    Payload        | Pad | 
|   (struct nlattr)         | ing |                   | ing |
+---------------------------+- - -+- - - - - - - - - -+- - -+
 <-------------------- nlattr->nla_len -------------->

And policy is an array of nla_policy structures. My questions are:

  1. What is the relation between header and attribute? Please explain "Attributes".
  2. What is policy, what is need of it and why do we use an array for this?

I found something about policies like "it defines types of attributes",
what does this mean? I mean "what is the meaning of type of attribute?"

It may be a nonsense question, but I am totally confused. I have been trying to understand these things for more than three days, please help me.

Thanks..

tijko
  • 7,599
  • 11
  • 44
  • 64
Nishant
  • 267
  • 3
  • 11
  • Not sure if this is still an issue but, I made a couple of edits if you were still interested. – tijko Sep 04 '14 at 02:47
  • Thanks @tijko for responding. Actually I had already got these things. I wanted to know some literal meaning of the things like, "future extensibility", "family", "policy" etc. I am writing a module with generic netlink and I found packet structure like: | NLMSGHDR | GENLMSGHDR | TYPE | LENGTH | ACTUAL DATA......| So, my question is, what is the need of type and length and how these things are going to help us in future. Can we avoid this? If you have time please help me... – Nishant Sep 04 '14 at 11:57
  • I've expanded on the points you mention in your comment above. – tijko Sep 05 '14 at 18:27

1 Answers1

6

When creating/using netlink protocols, netlink attributes are intended to give the protocol a clean self documenting layout that allows for future extensibility. Meaning if you were wanting to use a different data type in addition to the ones that already exist in your current protocol, the code would be compatible without breaking the operations that already exist.

The "attributes" are protocol dependent, and relate to a specific message being sent using said protocol.

Using the taskstats interface as an example:

taskstat attributes:

enum {
    TASKSTATS_CMD_ATTR_UNSPEC = 0,
    TASKSTATS_CMD_ATTR_PID,
    TASKSTATS_CMD_ATTR_TGID,
    TASKSTATS_CMD_ATTR_REGISTER_CPUMASK,
    TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK,
    __TASKSTATS_CMD_ATTR_MAX,
};

In these attributes you could easily "extend" them by adding in a custom attribute between UNSPEC and MAX mapping that attribute to a specific function or operation needed.

kernel-space taskstat policy:

static const struct nla_policy taskstats_cmd_get_policy[TASKSTATS_CMD_ATTR_MAX+1] = {
    [TASKSTATS_CMD_ATTR_PID]  = { .type = NLA_U32 },
    [TASKSTATS_CMD_ATTR_TGID] = { .type = NLA_U32 },
    [TASKSTATS_CMD_ATTR_REGISTER_CPUMASK] = { .type = NLA_STRING },
    [TASKSTATS_CMD_ATTR_DEREGISTER_CPUMASK] = { .type = NLA_STRING },};

I believe you've already come across the definition for struct nlattr, an example of loading this struct's fields using the NETLINK_GENERIC protocol and the taskstats interface:

struct nlattr na;
na.nla_type = CTRL_ATTR_FAMILY_NAME;         // defined in linux/genetlink.h 
na.nla_len = strlen(TASKSTATS_GENL_NAME) + 1 // defined in linux/taskstats.h

// note: you will need to copy/access nlattr data in the same way the NLMSG_DATA
//       macro operates.

Now on the kernel side when parsing these attributes the associated functions will be called and intended actions on how to proceed.

I'm not sure if the diagram you posted is throwing you off but, to zoom out a bit to give you a larger perspective:

As per the kernel source v3.16 include/net/netlink.h:

/* ========================================================================
 *         Netlink Messages and Attributes Interface (As Seen On TV)
 * ------------------------------------------------------------------------
 *                          Messages Interface
 * ------------------------------------------------------------------------
 *
 * Message Format:
 *    <--- nlmsg_total_size(payload)  --->
 *    <-- nlmsg_msg_size(payload) ->
 *   +----------+- - -+-------------+- - -+-------- - -
 *   | nlmsghdr | Pad |   Payload   | Pad | nlmsghdr
 *   +----------+- - -+-------------+- - -+-------- - -
 *   nlmsg_data(nlh)---^                   ^
 *   nlmsg_next(nlh)-----------------------+
 *
 * Payload Format:
 *    <---------------------- nlmsg_len(nlh) --------------------->
 *    <------ hdrlen ------>       <- nlmsg_attrlen(nlh, hdrlen) ->
 *   +----------------------+- - -+--------------------------------+
 *   |     Family Header    | Pad |           Attributes           |
 *   +----------------------+- - -+--------------------------------+
 *   nlmsg_attrdata(nlh, hdrlen)---^

Here you can see that the header and payload diagram you posted are but parts of a larger payload. That segment goes along with a struct nlmsghdr in the message format.

Now on policy, when sending netlink messages the sender needs to adhere to the protocol format. The receiver of the message will use struct nla_policy to validate the attributes before the payload is accessed.

The "family" or identifier is used by the kernel to keep track of the appropriate protocol interface to be communicating with, whether standard protocol or custom as with Generic Netlink.

When you ask "Can we avoid this?", if you're extending netlink by writing your own custom generic netlink protocol these exist to allow that protocol to be easily adjusted and maintained without going through and changing/fixing all operations associated with it or flat-out having the protocol break down. How else would you suggest parsing through nested messages with different data-types without an associated length or type? The type and length are there to allow parsing of the message on the correct alignments and allow the desired actions to take place. Without the attributes type giving the payload a label how would you interpret it, "what is" the payload? Without the length how would you know "how large" the payload is? There could be multiple payloads all with different lengths without something to distinguish their sizes there is no way to be able to tell where one starts and the other ends.

Here is a link to the libnl (a library for working with netlink sockets, and is highly recommended) documentation attributes.

tijko
  • 7,599
  • 11
  • 44
  • 64
  • Why is there a `Pad` between the headers and the payloads? From the documentation, the nlmsghdr is alawys 16 bytes, while the attribute header is always 4 bytes. Shouldn't this mean there's no need for any padding between the header and the payload since the alignment is always set to 4 bytes? – CMCDragonkai Apr 07 '19 at 10:55
  • @CMCDragonkai Its been quite a few years since I've worked with this protocol but I can re-read some of the documentation and get back to you if I find anything of relevance. – tijko Apr 08 '19 at 14:54
  • did you find out? The diagram says that a Pad exists between Message Header and Payload and Family Header and its payload as well. I'm wondering if the broken up dashes means that this padding is optional and only required if the headers themselves are not aligned. – CMCDragonkai Apr 13 '19 at 07:22