generic_netlink_howto 桃扇骨 2022-11-15 14:29 191阅读 0赞 # generic\_netlink\_howto # This document gives a brief introduction to Generic Netlink, some simple examples on how to use it and some recommendations on how to make the most of the Generic Netlink communications interface. While this document does not require that the reader has a detailed understanding of what Netlink is and how it works, some basic Netlink knowledge is assumed. As usual, the kernel source code is your best friend here. While this document talks briefly about Generic Netlink from a userspace point of view, its primary focus is on the kernel's Generic Netlink API. It is recommended that application developers who are interested in using Generic Netlink make use of the libnl library\[1\]. ## Contents ## * [1 Generic Netlink By Example][] * [1.1 Registering A Family][] * [1.2 Kernel Communication][] * [1.2.1 Sending Messages][] * [1.2.2 Receiving Messages][] * [1.3 Userspace Communication][] * [2 Architectural Overview][] * [3 Implementation Details][] * [3.1 Message Format][] * [3.2 Data Structures][] * [3.2.1 The genl\_family Structure][3.2.1 The genl_family Structure] * [3.2.2 The genl\_ops Structure][3.2.2 The genl_ops Structure] * [3.2.3 The genl\_info Structure][3.2.3 The genl_info Structure] * [3.2.4 The nla\_policy Structure][3.2.4 The nla_policy Structure] * [4 Recommendations][] * [4.1 Attributes And Message Payloads][] * [4.2 Operation Granularity][] * [4.3 Acknowledgment and Error Reporting][] * [5 References][] ## Generic Netlink By Example ## This section deals with the Generic Netlink subsystem in the Linux kernel and provides a simple example of how in-kernel users can make use of the Generic Netlink API. Don't forget to review section \#4, “Recommendations”, before writing any code as it can save you, and the people who review your code, lots of time! The first section explains how to register a Generic Netlink family which is required for Generic Netlink users who wish to act as servers, listening over the Generic Netlink bus. The second section explains how to send and receive Generic Netlink messages in the kernel. Finally, the third section provides a brief introduction to using Generic Netlink in userspace. ### Registering A Family ### Registering a Generic Netlink family is a simple four step process: define the family, define the operations, register the family, register the operations. In order to help demonstrate these steps below is a simple example broken down and explained in detail. The first step is to define the family itself, which we do by creating an instance of the genl\_family structure. In our simple example we are going to create a new Generic Netlink family named “DOC\_EXMPL”. /* attributes */ enum { DOC_EXMPL_A_UNSPEC, DOC_EXMPL_A_MSG, __DOC_EXMPL_A_MAX, }; #define DOC_EXMPL_A_MAX (__DOC_EXMPL_A_MAX - 1) /* attribute policy */ static struct nla_policy doc_exmpl_genl_policy[DOC_EXMPL_A_MAX + 1] = { [DOC_EXMPL_A_MSG] = { .type = NLA_NUL_STRING }, }; /* family definition */ static struct genl_family doc_exmpl_gnl_family = { .id = GENL_ID_GENERATE, .hdrsize = 0, .name = "DOC_EXMPL", .version = 1, .maxattr = DOC_EXMPL_A_MAX, }; Figure 1: The DOC\_EXMPL family, attributes and policy You can see above that we defined a new family and the family recognizes a single attribute, DOC\_EXMPL\_A\_MSG, which is a NULL terminated string. The GENL\_ID\_GENERATE macro/constant is really just the value 0x0 and it signifies that we want the Generic Netlink controller to assign the channel number when we register the family. The second step is to define the operations for the family, which we do by creating at least one instance of the genl\_ops structure. In this example we are only going to define one operation but you can define up to 255 unique operations for each family. /* handler */ static int doc_exmpl_echo(struct sk_buff *skb, struct genl_info *info) { /* message handling code goes here; return 0 on success, negative * values on failure */ } /* commands */ enum { DOC_EXMPL_C_UNSPEC, DOC_EXMPL_C_ECHO, __DOC_EXMPL_C_MAX, }; #define DOC_EXMPL_C_MAX (__DOC_EXMPL_C_MAX - 1) /* operation definition */ static struct genl_ops doc_exmpl_gnl_ops_echo = { .cmd = DOC_EXMPL_C_ECHO, .flags = 0, .policy = doc_exmpl_genl_policy, .doit = doc_exmpl_echo, .dumpit = NULL, }; Figure 2: The DOC\_EXMPL\_C\_ECHO operation Here we have defined a single operation, DOC\_EXMPL\_C\_ECHO, which uses the Netlink attribute policy we defined above. Once registered, this particular operation would call the doc\_exmpl\_echo() function whenever a DOC\_EXMPL\_C\_ECHO message is sent to the DOC\_EXMPL family over the Generic Netlink bus. The third step is to register the DOC\_EXMPL family with the Generic Netlink operation. We do this with a single function call: int rc; rc = genl_register_family(&doc_exmpl_gnl_family); if (rc != 0) goto failure; This call registers the new family name with the Generic Netlink mechanism and requests a new channel number which is stored in the genl\_family struct, replacing the GENL\_ID\_GENERATE value. It is important to remember to unregister Generic Netlink families when done as the kernel does allocate resources for each registered family. The fourth and final step is to register the operations for the family. Once again this is a simple function call: int rc; rc = genl_register_ops(&doc_exmpl_gnl_family, &doc_exmpl_gnl_ops_echo); if (rc != 0) goto failure; NOTE: This function doesn't exist past linux 3.12. Up to linux 4.10, use genl\_register\_family\_with\_ops(). On 4.10 and later, include a reference to your genl\_ops struct as an element in the genl\_family struct (element .ops), as well as the number of commands (element .n\_ops). This call registers the DOC\_EXMPL\_C\_ECHO operation in association with the DOC\_EXMPL family. The process is now complete. Other Generic Netlink users can now issue DOC\_EXMPL\_C\_ECHO commands and they will be handled as desired. ### Kernel Communication ### The kernel provides two sets of interfaces for sending, receiving and processing Generic Netlink messages. The majority of the API consists of the general purpose Netlink interfaces, however, there are a small number of interfaces specific to Generic Netlink. The following two “include” files define the Netlink and Generic Netlink API for the kernel: * include/net/netlink.h * include/net/genetlink.h Sending Messages Sending Generic Netlink messages is a three step process: allocate memory for the message buffer, create the message, send the message. In order to help demonstrate these steps, below is a simple example using the DOC\_EXMPL family. The first step is to allocate a Netlink message buffer; the easiest way to do this is with the nlsmsg\_new() function. struct sk_buff *skb; skb = genlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL); if (skb == NULL) goto failure; Figure 3: Allocating a Generic Netlink message buffer The NLMSG\_GOODSIZE macro/constant is a good value to use when you do not know the size of the message buffer at the time of allocation. Don't forget that the genlmsg\_new() function automatically adds space for the Netlink and Generic Netlink message headers. The second step is to actually create the message payload. This is obviously something which is very specific to each service, but a simple example is shown below. int rc; void *msg_head; /* create the message headers */ msg_head = genlmsg_put(skb, pid, seq, type, 0, flags, DOC_EXMPL_C_ECHO, 1); if (msg_head == NULL) { rc = -ENOMEM; goto failure; } /* add a DOC_EXMPL_A_MSG attribute */ rc = nla_put_string(skb, DOC_EXMPL_A_MSG, "Generic Netlink Rocks"); if (rc != 0) goto failure; /* finalize the message */ genlmsg_end(skb, msg_head); Figure 4: Creating a Generic Netlink message payload The genlmsg\_put() function creates the required Netlink and Generic Netlink message headers, populating them with the given values; see the Generic Netlink header file for a description of the parameters. The nla\_put\_string() function is a standard Netlink attribute function which adds a string attribute to the end of the Netlink message; see the Netlink header file for a description of the parameters. The genlmsg\_end() function updates the Netlink message header once the message payload has been finalized. This function should be called before sending the message. The third and final step is to send the Generic Netlink message which can be done with a single function call. The example below is for a unicast send, but interfaces exist for doing a multicast send of Generic Netlink message. int rc; rc = genlmsg_unicast(skb, pid); if (rc != 0) goto failure; Figure 5: Sending Generic Netlink messages Receiving Messages Typically, kernel modules act as Generic Netlink servers which means that the act of receiving messages is handled automatically by the Generic Netlink bus. Once the bus receives the message and determines the correct routing, the message is passed directly to the family specific operation callback for processing. If the kernel is acting as a Generic Netlink client, server response messages can be received over the Generic Netlink socket using standard kernel socket interfaces. ### Userspace Communication ### While Generic Netlink messages can be sent and received using the standard socket API it is recommended that user space applications use the libnl library\[1\]. The libnl library insulates applications from many of the low level Netlink tasks and uses an API which is very similar to the kernel API shown above. ## Architectural Overview ## Figure \#6 illustrates the basic Generic Netlink architecture which is composed of five different types of components: 1. The Netlink subsystem which serves as the underlying transport layer for all of the Generic Netlink communications. 2. The Generic Netlink bus which is implemented inside the kernel, but which is available to userspace through the socket API and inside the kernel via the normal Netlink and Generic Netlink APIs. 3. The Generic Netlink users who communicate with each other over the Generic Netlink bus; users can exist both in kernel and user space. 4. The Generic Netlink controller which is part of the kernel and is responsible for dynamically allocating Generic Netlink communication channels and other management tasks. The Generic Netlink controller is implemented as a standard Generic Netlink user, however, it listens on a special, pre-allocated Generic Netlink channel. 5. The kernel socket API. Generic Netlink sockets are created with the PF\_NETLINK domain and the NETLINK\_GENERIC protocol values. +---------------------+ +---------------------+ | (3) application "A" | | (3) application "B" | +------+--------------+ +--------------+------+ | | \ / \ / | | +-------+--------------------------------+-------+ | : : | user-space =====+ : (5) kernel socket API : +================ | : : | kernel-space +--------+-------------------------------+-------+ | | +-----+-------------------------------+----+ | (1) Netlink subsystem | +---------------------+--------------------+ | +---------------------+--------------------+ | (2) Generic Netlink bus | +--+--------------------------+-------+----+ | | | +-------+---------+ | | | (4) controller | / \ +-----------------+ / \ | | +------------------+--+ +--+------------------+ | (3) kernel user "X" | | (3) kernel user "Y" | +---------------------+ +---------------------+ Figure 6: Generic Netlink Architecture When looking at figure \#6 it is important to note that any Generic Netlink user can communicate with any other user over the bus using the same API regardless of where the user resides in relation to the kernel/userspace boundary. Generic Netlink communications are essentially a series of different communication channels which are multiplexed on a single Netlink family. Communication channels are uniquely identified by channel numbers which are dynamically allocated by the Generic Netlink controller. The controller is a special Generic Netlink user which listens on a fixed communication channel, number 0x10, which is always present. Kernel or userspace users which provide services over the Generic Netlink bus establish new communication channels by registering their services with the Generic Netlink controller. Users who want to use a service query the controller to see if the service exists and to determine the correct channel number. ## Implementation Details ## This section provides a more in-depth explanation of the Generic Netlink message formats and data structures. ### Message Format ### Generic Netlink uses the standard Netlink subsystem as a transport layer which means that the foundation of the Generic Netlink message is the standard Netlink message format - the only difference is the inclusion of a Generic Netlink message header. The format of the message is defined as shown below: 0 1 2 3 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Netlink message header (nlmsghdr) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Generic Netlink message header (genlmsghdr) | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Optional user specific message header | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ | Optional Generic Netlink message payload | +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ Figure 7: Generic Netlink message format Figure \#7 is included only to give you a rough idea of how Generic Netlink messages are formatted and sent “on the wire”. In practice the Netlink and Generic Netlink API should insulate most users from the details of the message format and the Netlink message headers. ### Data Structures ### This section focuses on the Generic Netlink data structures as they are defined in the kernel. A similar API exists for userspace applications using the libnl library\[1\]. The genl\_family Structure Generic Netlink families are defined by the genl\_family structure, which is shown below: struct genl_family { unsigned int id; unsigned int hdrsize; char name[GENL_NAMSIZ]; unsigned int version; unsigned int maxattr; struct nlattr ** attrbuf; struct list_head ops_list; struct list_head family_list; }; Figure 8: The genl\_family structure The genl\_family structure fields are used in the following manner: * unsigned int id This is the dynamically allocated channel number. A value of 0x0 signifies that the channel number should be assigned by the controller and the 0x10 value is reserved for use by the controller. Users should always use GENL\_ID\_GENERATE macro/constant (value 0x0) when registering a new family. * unsigned int hdrsize If the family makes use of a family specific header, its size is stored here. If there is no family specific header this value should be zero. * char name\[GENL\_NAMSIZ\] This string should be unique to the family as it is the key that the controller uses to lookup channel numbers when requested. * unsigned int version Family specific version number. * unsigned int maxattr Generic Netlink makes use of the standard Netlink attributes; this value holds the maximum number of attributes defined for the Generic Netlink family. * struct nlattr \*\*attrbuf This is a private field and should not be modified. * struct list\_head ops\_list This is a private field and should not be modified. * struct list\_head family\_list This is a private field and should not be modified. The genl\_ops Structure Generic Netlink operations are defined by the genl\_ops structure, which is shown below: struct genl_ops { u8 cmd; unsigned int flags; struct nla_policy *policy; int (*doit)(struct sk_buff *skb, struct genl_info *info); int (*dumpit)(struct sk_buff *skb, struct netlink_callback *cb); struct list_head ops_list; }; Figure 9: The genl\_ops structure The genl\_ops structure fields are used in the following manner: * u8 cmd This value is unique across the corresponding Generic Netlink family and is used to reference the operation. * unsigned int flags This field is used to specify any special attributes of the operation. The following flags may be used (multiple flags can be OR'd together): * GENL\_ADMIN\_PERM The operation requires the CAP\_NET\_ADMIN privilege * struct nla\_policy policy This field defines the Netlink attribute policy for the operation request message. If specified, the Generic Netlink mechanism uses this policy to verify all of the attributes in the operation request message before calling the operation handler. The attribute policy is defined as an array of nla\_policy structures indexed by the attribute number. The nla\_policy structure is defined as shown in figure \#11. * int (\*doit)(struct skbuff \*skb, struct genl\_info \*info) This callback is similar in use to the standard Netlink doit() callback, the primary difference being the change in parameters. The doit() handler receives two parameters: the first is the message buffer which triggered the handler and the second is a Generic Netlink genl\_info structure which is defined as shown in figure \#10. * int (\*dumpit)(struct sk\_buff \*skb, struct netlink\_callback \*cb) This callback is similar in use to the standard Netlink dumpit() callback. The dumpit() callback is invoked when the Generic Netlink message is received with the NLM\_F\_DUMP flag set. The main difference between the dumpit() handler and the doit() handler is that the dumpit() handler does not allocate a message buffer for a response; a pre-allocated sk\_buff is passed to the dumpit() handler as the first parameter. The dumpit() handler should fill the message buffer with the appropriate response message and return the size of the sk\_buff, i.e. sk\_buff→len, and the message buffer will automatically be sent to the Generic Netlink client that initiated the request. As long as the dumpit() handler returns a value greater than zero it will be called again with a newly allocated message buffer to fill. When the handler has no more data to send it should return zero; error conditions are indicated by returning a negative value. If necessary, state can be preserved in the netlink\_callback parameter which is passed to the dumpit() handler; the netlink\_callback parameter values will be preserved across handler calls for a single request. * struct list\_head ops\_list This is a private field and should not be modified. The genl\_info Structure Generic Netlink message information is passed by the genl\_info structure, which is shown below: struct genl_info { u32 snd_seq; u32 snd_pid; struct nlmsghdr * nlhdr; struct genlmsghdr * genlhdr; void * userhdr; struct nlattr ** attrs; }; Figure 10: The genl\_info structure The fields are populated in the following manner: * u32 snd\_seq This is the Netlink sequence number of the request. * u32 snd\_pid This is the Netlink PID of the client which issued the request; it is important to note that the Netlink PID is not the same as the standard kernel PID. * struct nlmsghdr \*nlhdr This is set to point to the Netlink message header of the request. * struct genlmsghdr \*genlhdr This is set to point to the Generic Netlink message header of the request. * void \*userhdr If the Generic Netlink family makes use of a family specific header, this pointer will be set to point to the start of the family specific header. * struct nlattr \*\*attrs The parsed Netlink attributes from the request; if the Generic Netlink family definition specified a Netlink attribute policy then the attributes would have already been validated. The doit() handler should do whatever processing is necessary and return zero on success or a negative value on failure. Negative return values will cause an NLMSG\_ERROR message to be sent while a zero return value will only cause the NLMSG\_ERROR message to be sent if the request is received with the NLM\_F\_ACK flag set. The nla\_policy Structure Generic Netlink attribute policy is defined by the nla\_policy structure, which is shown below: struct nla_policy { u16 type; u16 len; }; Figure 11: The nla\_policy structure The fields are used in the following manner: * u16 type This specifies the type of the attribute; presently the following types are defined for general use: * NLA\_UNSPEC Undefined type * NLA\_U8 An 8-bit unsigned integer * NLA\_U16 A 16-bit unsigned integer * NLA\_U32 A 32-bit unsigned integer * NLA\_U64 A 64-bit unsigned integer * NLA\_FLAG A simple boolean flag * NLA\_MSECS A 64-bit time value in msecs * NLA\_STRING A variable length string * NLA\_NUL\_STRING A variable length NULL terminated string * NLA\_NESTED A stream of attributes * u16 len When the attribute type is one of the string types then this field should be set to the maximum length of the string, not including the terminal NULL byte. If the attribute type is unknown or NLA\_UNSPEC then this field should be set to the exact length of the attribute's payload. Unless the attribute type is one of the fixed-length types above, a value of zero indicates that no validation of the attribute should be performed. ## Recommendations ## The Generic Netlink mechanism is a very flexible communications mechanism and as a result there are many different ways it can be used. The following recommendations are based on conventions within the Linux kernel and should be followed whenever possible. While not all existing kernel code follows the recommendations outlined here, all new code should consider these recommendations as requirements. ### Attributes And Message Payloads ### When defining new Generic Netlink message formats you must make use of the Netlink attributes wherever possible. The Netlink attribute mechanism has been carefully designed to allow for future message expansion while preserving backward compatibility. There are also additional benefits from using Netlink attributes which include developer familiarity and basic input checking. Most common data structures can be represented with Netlink attributes: * scalar values ; Most scalar values already have well-defined attribute types; see section 4 for details. * structures ; Structures can be represented using a nested attribute with the structure fields represented as attributes in the payload of the container attribute. * arrays ; Arrays can be represented by using a single nested attribute as a container with several of the same attribute type inside each representing a spot in the array. It is also important to use unique attributes as much as possible. This helps make the most of the Netlink attribute mechanisms and provides for easy changes to the message format in the future. ### Operation Granularity ### While it may be tempting to register a single operation for a Generic Netlink family and multiplex multiple sub-commands on the single operation, this is strongly discouraged for security reasons. Combining multiple behaviors into one operation makes it difficult to restrict the operations using the existing Linux kernel security mechanisms. ### Acknowledgment and Error Reporting ### It is often necessary for Generic Netlink services to return an ACK or error code to the client. It is not necessary to implement an explicit acknowledgment message as Netlink already provides a flexible acknowledgment and error reporting message type called NLMSG\_ERROR. When an error occurs an NLMSG\_ERROR message is returned to the client with the error code returned by the Generic Netlink operation handler. Clients can also request the NLMSG\_ERROR message when no error has occurred by setting the NLM\_F\_ACK flag on requests. ## References ## 1. [http://people.suug.ch/~tgr/libnl][http_people.suug.ch_tgr_libnl] NOTE: This link is no longer valid. Try [http://www.infradead.org/~tgr/libnl][http_www.infradead.org_tgr_libnl] [1 Generic Netlink By Example]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#generic_netlink_by_example [1.1 Registering A Family]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#registering_a_family [1.2 Kernel Communication]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#kernel_communication [1.2.1 Sending Messages]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#sending_messages [1.2.2 Receiving Messages]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#receiving_messages [1.3 Userspace Communication]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#userspace_communication [2 Architectural Overview]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#architectural_overview [3 Implementation Details]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#implementation_details [3.1 Message Format]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#message_format [3.2 Data Structures]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#data_structures [3.2.1 The genl_family Structure]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#the_genl_family_structure [3.2.2 The genl_ops Structure]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#the_genl_ops_structure [3.2.3 The genl_info Structure]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#the_genl_info_structure [3.2.4 The nla_policy Structure]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#the_nla_policy_structure [4 Recommendations]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#recommendations [4.1 Attributes And Message Payloads]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#attributes_and_message_payloads [4.2 Operation Granularity]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#operation_granularity [4.3 Acknowledgment and Error Reporting]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#acknowledgment_and_error_reporting [5 References]: https://wiki.linuxfoundation.org/networking/generic_netlink_howto#references [http_people.suug.ch_tgr_libnl]: http://people.suug.ch/~tgr/libnl [http_www.infradead.org_tgr_libnl]: http://www.infradead.org/~tgr/libnl
还没有评论,来说两句吧...