diff options
Diffstat (limited to 'sys/netlink')
| -rw-r--r-- | sys/netlink/netlink_bitset.h | 57 | ||||
| -rw-r--r-- | sys/netlink/netlink_route.h | 1 | ||||
| -rw-r--r-- | sys/netlink/netlink_snl.h | 88 | ||||
| -rw-r--r-- | sys/netlink/netlink_snl_route_parsers.h | 2 | ||||
| -rw-r--r-- | sys/netlink/route/iface.c | 28 | ||||
| -rw-r--r-- | sys/netlink/route/interface.h | 1 |
6 files changed, 176 insertions, 1 deletions
diff --git a/sys/netlink/netlink_bitset.h b/sys/netlink/netlink_bitset.h new file mode 100644 index 000000000000..9a918bd20997 --- /dev/null +++ b/sys/netlink/netlink_bitset.h @@ -0,0 +1,57 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * Copyright (c) 2023 Alexander V. 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. + */ + +/* + * Generic netlink message header and attributes + */ +#ifndef _NETLINK_NETLINK_BITSET_H_ +#define _NETLINK_NETLINK_BITSET_H_ + +#include <netlink/netlink.h> + +/* Bitset type nested attributes */ +enum { + NLA_BITSET_UNSPEC, + NLA_BITSET_NOMASK = 1, /* flag: mask of valid bits not provided */ + NLA_BITSET_SIZE = 2, /* u32: max valid bit # */ + NLA_BITSET_BITS = 3, /* nested: array of NLA_BITSET_BIT */ + NLA_BITSET_VALUE = 4, /* binary: array of bit values */ + NLA_BITSET_MASK = 5, /* binary: array of valid bits */ + __NLA_BITSET_MAX, +}; +#define NLA_BITSET_MAX (__NLA_BITSET_MAX - 1) + +enum { + NLA_BITSET_BIT_UNSPEC, + NLA_BITSET_BIT_INDEX = 1, /* u32: index of the bit */ + NLA_BITSET_BIT_NAME = 2, /* string: bit description */ + NLA_BITSET_BIT_VALUE = 3, /* flag: provided if bit is set */ + __NLA_BITSET_BIT_MAX, +}; +#define NLA_BITSET_BIT_MAX (__NLA_BITSET_BIT_MAX - 1) + +#endif diff --git a/sys/netlink/netlink_route.h b/sys/netlink/netlink_route.h index 0c328d941bd5..ecdad83312de 100644 --- a/sys/netlink/netlink_route.h +++ b/sys/netlink/netlink_route.h @@ -33,6 +33,7 @@ #include <net/if_types.h> #include <net/if_var.h> +#include <netlink/netlink_bitset.h> #include <netlink/route/common.h> #include <netlink/route/ifaddrs.h> #include <netlink/route/interface.h> diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h index 6d97c1afd4ee..0292725bd135 100644 --- a/sys/netlink/netlink_snl.h +++ b/sys/netlink/netlink_snl.h @@ -43,6 +43,7 @@ #include <sys/types.h> #include <sys/socket.h> #include <netlink/netlink.h> +#include <netlink/netlink_bitset.h> #define _roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) @@ -732,7 +733,7 @@ snl_attr_get_nla(struct snl_state *ss __unused, struct nlattr *nla, } static inline bool -snl_attr_dup_nla(struct snl_state *ss __unused, struct nlattr *nla, +snl_attr_dup_nla(struct snl_state *ss, struct nlattr *nla, const void *arg __unused, void *target) { void *ptr = snl_allocz(ss, nla->nla_len); @@ -773,6 +774,90 @@ snl_attr_dup_struct(struct snl_state *ss, struct nlattr *nla, return (false); } +struct snl_attr_bit { + uint32_t bit_index; + char *bit_name; + int bit_value; +}; + +struct snl_attr_bits { + uint32_t num_bits; + struct snl_attr_bit **bits; +}; + +#define _OUT(_field) offsetof(struct snl_attr_bit, _field) +static const struct snl_attr_parser _nla_p_bit[] = { + { .type = NLA_BITSET_BIT_INDEX, .off = _OUT(bit_index), .cb = snl_attr_get_uint32 }, + { .type = NLA_BITSET_BIT_NAME, .off = _OUT(bit_name), .cb = snl_attr_dup_string }, + { .type = NLA_BITSET_BIT_VALUE, .off = _OUT(bit_value), .cb = snl_attr_get_flag }, +}; +#undef _OUT +SNL_DECLARE_ATTR_PARSER_EXT(_nla_bit_parser, sizeof(struct snl_attr_bit), _nla_p_bit, NULL); + +struct snl_attr_bitset { + uint32_t nla_bitset_size; + uint32_t *nla_bitset_mask; + uint32_t *nla_bitset_value; + struct snl_attr_bits bits; +}; + +#define _OUT(_field) offsetof(struct snl_attr_bitset, _field) +static const struct snl_attr_parser _nla_p_bitset[] = { + { .type = NLA_BITSET_SIZE, .off = _OUT(nla_bitset_size), .cb = snl_attr_get_uint32 }, + { .type = NLA_BITSET_BITS, .off = _OUT(bits), .cb = snl_attr_get_parray, .arg = &_nla_bit_parser }, + { .type = NLA_BITSET_VALUE, .off = _OUT(nla_bitset_mask), .cb = snl_attr_dup_nla }, + { .type = NLA_BITSET_MASK, .off = _OUT(nla_bitset_value), .cb = snl_attr_dup_nla }, +}; + +static inline bool +_cb_p_bitset(struct snl_state *ss __unused, void *_target) +{ + struct snl_attr_bitset *target = _target; + + uint32_t sz_bytes = _roundup2(target->nla_bitset_size, 32) / 8; + + if (target->nla_bitset_mask != NULL) { + struct nlattr *nla = (struct nlattr *)target->nla_bitset_mask; + uint32_t data_len = NLA_DATA_LEN(nla); + + if (data_len != sz_bytes || _roundup2(data_len, 4) != data_len) + return (false); + target->nla_bitset_mask = (uint32_t *)NLA_DATA(nla); + } + + if (target->nla_bitset_value != NULL) { + struct nlattr *nla = (struct nlattr *)target->nla_bitset_value; + uint32_t data_len = NLA_DATA_LEN(nla); + + if (data_len != sz_bytes || _roundup2(data_len, 4) != data_len) + return (false); + target->nla_bitset_value = (uint32_t *)NLA_DATA(nla); + } + return (true); +} +#undef _OUT +SNL_DECLARE_ATTR_PARSER_EXT(_nla_bitset_parser, + sizeof(struct snl_attr_bitset), + _nla_p_bitset, _cb_p_bitset); + +/* + * Parses the compact bitset representation. + */ +static inline bool +snl_attr_get_bitset_c(struct snl_state *ss, struct nlattr *nla, + const void *arg __unused, void *_target) +{ + const struct snl_hdr_parser *p = &_nla_bitset_parser; + struct snl_attr_bitset *target = _target; + + /* Assumes target points to the beginning of the structure */ + if (!snl_parse_header(ss, NLA_DATA(nla), NLA_DATA_LEN(nla), p, _target)) + return (false); + if (target->nla_bitset_mask == NULL || target->nla_bitset_value == NULL) + return (false); + return (true); +} + static inline void snl_field_get_uint8(struct snl_state *ss __unused, void *src, void *target) { @@ -1184,6 +1269,7 @@ snl_send_msgs(struct snl_writer *nw) static const struct snl_hdr_parser *snl_all_core_parsers[] = { &snl_errmsg_parser, &snl_donemsg_parser, + &_nla_bit_parser, &_nla_bitset_parser, }; #endif diff --git a/sys/netlink/netlink_snl_route_parsers.h b/sys/netlink/netlink_snl_route_parsers.h index 1e9320a4559e..7e4bcad4010b 100644 --- a/sys/netlink/netlink_snl_route_parsers.h +++ b/sys/netlink/netlink_snl_route_parsers.h @@ -186,12 +186,14 @@ struct snl_parsed_link { uint32_t ifla_promiscuity; struct rtnl_link_stats64 *ifla_stats64; struct nlattr *iflaf_orig_hwaddr; + struct snl_attr_bitset iflaf_caps; }; #define _IN(_field) offsetof(struct ifinfomsg, _field) #define _OUT(_field) offsetof(struct snl_parsed_link, _field) static const struct snl_attr_parser _nla_p_link_fbsd[] = { { .type = IFLAF_ORIG_HWADDR, .off = _OUT(iflaf_orig_hwaddr), .cb = snl_attr_dup_nla }, + { .type = IFLAF_CAPS, .off = _OUT(iflaf_caps), .cb = snl_attr_get_bitset_c }, }; SNL_DECLARE_ATTR_PARSER(_link_fbsd_parser, _nla_p_link_fbsd); diff --git a/sys/netlink/route/iface.c b/sys/netlink/route/iface.c index 16bbe4d000cc..3d7f752fa613 100644 --- a/sys/netlink/route/iface.c +++ b/sys/netlink/route/iface.c @@ -253,6 +253,33 @@ dump_sa(struct nl_writer *nw, int attr, const struct sockaddr *sa) return (nlattr_add(nw, attr, addr_len, addr_data)); } +static bool +dump_iface_caps(struct nl_writer *nw, struct ifnet *ifp) +{ + int off = nlattr_add_nested(nw, IFLAF_CAPS); + uint32_t active_caps[roundup2(IFCAP_B_SIZE, 32) / 32] = {}; + uint32_t all_caps[roundup2(IFCAP_B_SIZE, 32) / 32] = {}; + + MPASS(sizeof(active_caps) >= 8); + MPASS(sizeof(all_caps) >= 8); + + if (off == 0) + return (false); + + active_caps[0] = (uint32_t)if_getcapabilities(ifp); + all_caps[0] = (uint32_t)if_getcapenable(ifp); + active_caps[1] = (uint32_t)if_getcapabilities2(ifp); + all_caps[1] = (uint32_t)if_getcapenable2(ifp); + + nlattr_add_u32(nw, NLA_BITSET_SIZE, IFCAP_B_SIZE); + nlattr_add(nw, NLA_BITSET_MASK, sizeof(all_caps), all_caps); + nlattr_add(nw, NLA_BITSET_VALUE, sizeof(active_caps), active_caps); + + nlattr_set_len(nw, off); + + return (true); +} + /* * Dumps interface state, properties and metrics. * @nw: message writer @@ -320,6 +347,7 @@ dump_iface(struct nl_writer *nw, struct ifnet *ifp, const struct nlmsghdr *hdr, int off = nlattr_add_nested(nw, IFLA_FREEBSD); if (off != 0) { get_hwaddr(nw, ifp); + dump_iface_caps(nw, ifp); nlattr_set_len(nw, off); } diff --git a/sys/netlink/route/interface.h b/sys/netlink/route/interface.h index 97270d8234a1..667bf2c96151 100644 --- a/sys/netlink/route/interface.h +++ b/sys/netlink/route/interface.h @@ -151,6 +151,7 @@ enum { IFLAF_UNSPEC = 0, IFLAF_ORIG_IFNAME = 1, /* string, original interface name at creation */ IFLAF_ORIG_HWADDR = 2, /* binary, original hardware address */ + IFLAF_CAPS = 3, /* bitset, interface capabilities */ __IFLAF_MAX }; #define IFLAF_MAX (__IFLAF_MAX - 1) |
