diff options
Diffstat (limited to 'share/man/man3/snl.3')
-rw-r--r-- | share/man/man3/snl.3 | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/share/man/man3/snl.3 b/share/man/man3/snl.3 new file mode 100644 index 000000000000..9a6eceb66a32 --- /dev/null +++ b/share/man/man3/snl.3 @@ -0,0 +1,309 @@ +.\" +.\" Copyright (C) 2022 Alexander Chernikov <melifaro@FreeBSD.org>. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.Dd December 16, 2022 +.Dt SNL 3 +.Os +.Sh NAME +.Nm snl_init , +.Nm snl_free , +.Nm snl_read_message , +.Nm snl_send , +.Nm snl_get_seq , +.Nm snl_allocz , +.Nm snl_clear_lb , +.Nm snl_parse_nlmsg , +.Nm snl_parse_header , +.Nm snl_parse_attrs , +.Nm snl_parse_attrs_raw , +.Nm snl_attr_get_flag , +.Nm snl_attr_get_ip , +.Nm snl_attr_get_uint16 , +.Nm snl_attr_get_uint32 , +.Nm snl_attr_get_string , +.Nm snl_attr_get_stringn , +.Nm snl_attr_get_nla , +.Nm snl_field_get_uint8 , +.Nm snl_field_get_uint16 , +.Nm snl_field_get_uint32 +.Nd "simple netlink library" +.Sh SYNOPSIS +.In netlink/netlink_snl.h +.In netlink/netlink_snl_route.h +.Ft "bool" +.Fn snl_init "struct snl_state *ss" "int netlink_family" +.Fn snl_free "struct snl_state *ss" +.Ft "struct nlmsghdr *" +.Fn snl_read_message "struct snl_state *ss" +.Ft "bool" +.Fn snl_send "struct snl_state *ss" "void *data" "int sz" +.Ft "uint32_t" +.Fn snl_get_seq "struct snl_state *ss" +.Ft "void *" +.Fn snl_allocz "struct snl_state *ss" "int len" +.Fn snl_clear_lb "struct snl_state *ss" +.Ft "bool" +.Fn snl_parse_nlmsg "struct snl_state *ss" "struct nlmsghdr *hdr" "const struct snl_hdr_parser *ps" "void *target" +.Ft "bool" +.Fn snl_parse_header "struct snl_state *ss" "void *hdr" "int len" "const struct snl_hdr_parser *ps" "int pslen" "void *target" +.Ft "bool" +.Fn snl_parse_attrs "struct snl_state *ss" "struct nlmsghdr *hdr" "int hdrlen" "const struct snl_attr_parser *ps" "int pslen" "void *target" +.Ft "bool" +.Fn snl_parse_attrs_raw "struct snl_state *ss" "struct nlattr *nla_head" "int len" "const struct snl_attr_parser *ps" "int pslen" "void *target" +.Ft "bool" +.Fn snl_attr_get_flag "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_uint8 "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_uint16 "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_uint32 "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_uint64 "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_string "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_stringn "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_nla "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_ip "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Ft "bool" +.Fn snl_attr_get_ipvia "struct snl_state *ss" "struct nlattr *nla" "void *target" +.Sh DESCRIPTION +The +.Xr snl 3 +library provides an easy way of sending and receiving Netlink messages, +taking care of serialisation and deserialisation. +.Ss INITIALISATION +Call +.Fn snl_init +with a pointer to the +.Dv struct snl_state +and the desired Netlink family to initialise the library instance. +To free the library instance, call +.Fn snl_free . +.Pp +The library functions are NOT multithread-safe. +If multithreading is desired, consider initializing an instance +per thread. +.Ss MEMORY ALLOCATION +The library uses pre-allocated extendable memory buffers to handle message parsing. +The typical usage pattern is to allocate the necessary data structures during the +message parsing or writing process via +.Fn snl_allocz +and free all allocated data at once using +.Fn snl_clear_lb +after handling the message. +.Ss COMPOSING AND SENDING MESSAGES +The library does not currently offer any wrappers for writing netlink messages. +Simple request messages can be composed by filling in all needed fields directly. +Example for constructing an interface dump request: +.Bd -literal + struct { + struct nlmsghdr hdr; + struct ifinfomsg ifmsg; + } msg = { + .hdr.nlmsg_type = RTM_GETLINK, + .hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .hdr.nlmsg_seq = snl_get_seq(ss), + }; + msg.hdr.nlmsg_len = sizeof(msg); +.Ed +.Fn snl_get_seq +can be used to generate a unique message number. +To send the resulting message, +.Fn snl_send +can be used. +.Ss RECEIVING AND PARSING MESSAGES +To receive a message, use +.Fn snl_read_message . +Currently, this call is blocking. +.Pp +The library provides an easy way to convert the message to the pre-defined C +structure. +For each message type, one needs to define rules, converting the protocol header +fields and the desired attributes to the specified structure. +It can be accomplished by using message parsers. +Each message parser consists of an array of attribute getters and an array of +header field getters. +The former array needs to be sorted by the attribute type. +There is a +.Fn SNL_VERIFY_PARSERS +macro to check if the order is correct. +.Fn SNL_DECLARE_PARSER "parser_name" "family header type" "struct snl_field_parser[]" "struct snl_attr_parser[]" +can be used to create a new parser. +.Fn SNL_DECLARE_ATTR_PARSER "parser_name" "struct snl_field_parser[]" +can be used to create an attribute-only message parser. +.Pp +Each attribute getter needs to be embedded in the following structure: +.Bd -literal +typedef bool snl_parse_attr_f(struct snl_state *ss, struct nlattr *attr, const void *arg, void *target); +struct snl_attr_parser { + uint16_t type; /* Attribute type */ + uint16_t off; /* field offset in the target structure */ + snl_parse_attr_f *cb; /* getter function to call */ + const void *arg; /* getter function custom argument */ +}; +.Ed +The generic attribute getter has the following signature: +.Ft "bool" +.Fn snl_attr_get_<type> "struct snl_state *ss" "struct nlattr *nla" "const void *arg" "void *target" . +nla contains the pointer of the attribute to use as the datasource. +The target field is the pointer to the field in the target structure. +It is up to the getter to know the type of the target field. +The getter must check the input attribute and return +false if the attribute is not formed correctly. +Otherwise, the getter fetches the attribute value and stores it in the target, +then returns true. +It is possible to use +.Fn snl_allocz +to create the desired data structure . +A number of predefined getters for the common data types exist. +.Fn snl_attr_get_flag +converts a flag-type attribute to an uint8_t value of 1 or 0, depending on the +attribute presence. +.Fn snl_attr_get_uint8 +stores a uint8_t type attribute into the uint8_t target field. +.Fn snl_attr_get_uint16 +stores a uint16_t type attribute into the uint16_t target field. +.Fn snl_attr_get_uint32 +stores a uint32_t type attribute into the uint32_t target field. +.Fn snl_attr_get_uint64 +stores a uint64_t type attribute into the uint64_t target field. +.Fn snl_attr_get_ip +and +.Fn snl_attr_get_ipvia +stores a pointer to the sockaddr structure with the IPv4/IPv6 address contained +in the attribute. +Sockaddr is allocated using +.Fn snl_allocz . +.Fn snl_attr_get_string +stores a pointer to the NULL-terminated string. +The string itself is allocated using +.Fn snl_allocz . +.Fn snl_attr_get_nla +stores a pointer to the specified attribute. +.Fn snl_attr_get_stringn +stores a pointer to the non-NULL-terminated string. +.Pp +Similarly, each family header getter needs to be embedded in the following structure: +.Bd -literal +typedef void snl_parse_field_f(struct snl_state *ss, void *hdr, void *target); +struct snl_field_parser { + uint16_t off_in; /* field offset in the input structure */ + uint16_t off_out;/* field offset in the target structure */ + snl_parse_field_f *cb; /* getter function to call */ +}; +.Ed +The generic field getter has the following signature: +.Ft "void" +snl_field_get_<type> "struct snl_state *ss" "void *src" "void *target" . +A number of pre-defined getters for the common data types exist. +.Fn "snl_field_get_uint8" +fetches an uint8_t value and stores it in the target. +.Fn "snl_field_get_uint16" +fetches an uint8_t value and stores it in the target. +.Fn "snl_field_get_uint32" +fetches an uint32_t value and stores it in the target. +.Sh EXAMPLES +The following example demonstrates how to list all system interfaces +using netlink. +.Bd -literal +#include <stdio.h> + +#include <netlink/netlink.h> +#include <netlink/netlink_route.h> +#include "netlink/netlink_snl.h" +#include "netlink/netlink_snl_route.h" + +struct nl_parsed_link { + uint32_t ifi_index; + uint32_t ifla_mtu; + char *ifla_ifname; +}; + +#define _IN(_field) offsetof(struct ifinfomsg, _field) +#define _OUT(_field) offsetof(struct nl_parsed_link, _field) +static const struct snl_attr_parser ap_link[] = { + { .type = IFLA_IFNAME, .off = _OUT(ifla_ifname), .cb = snl_attr_get_string }, + { .type = IFLA_MTU, .off = _OUT(ifla_mtu), .cb = snl_attr_get_uint32 }, +}; +static const struct snl_field_parser fp_link[] = { + {.off_in = _IN(ifi_index), .off_out = _OUT(ifi_index), .cb = snl_field_get_uint32 }, +}; +#undef _IN +#undef _OUT +SNL_DECLARE_PARSER(link_parser, struct ifinfomsg, fp_link, ap_link); + + +int +main(int ac, char *argv[]) +{ + struct snl_state ss; + + if (!snl_init(&ss, NETLINK_ROUTE)) + return (1); + + struct { + struct nlmsghdr hdr; + struct ifinfomsg ifmsg; + } msg = { + .hdr.nlmsg_type = RTM_GETLINK, + .hdr.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST, + .hdr.nlmsg_seq = snl_get_seq(&ss), + }; + msg.hdr.nlmsg_len = sizeof(msg); + + if (!snl_send(&ss, &msg, sizeof(msg))) { + snl_free(&ss); + return (1); + } + + struct nlmsghdr *hdr; + while ((hdr = snl_read_message(&ss)) != NULL && hdr->nlmsg_type != NLMSG_DONE) { + if (hdr->nlmsg_seq != msg.hdr.nlmsg_seq) + break; + + struct nl_parsed_link link = {}; + if (!snl_parse_nlmsg(&ss, hdr, &link_parser, &link)) + continue; + printf("Link#%u %s mtu %u\n", link.ifi_index, link.ifla_ifname, link.ifla_mtu); + } + + return (0); +} +.Ed +.Sh SEE ALSO +.Xr genetlink 4 , +.Xr netlink 4 , +and +.Xr rtnetlink 4 +.Sh HISTORY +The +.Dv SNL +library appeared in +.Fx 13.2 . +.Sh AUTHORS +This library was implemented by +.An Alexander Chernikov Aq Mt melifaro@FreeBSD.org . |