diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h --- a/sbin/ifconfig/ifconfig.h +++ b/sbin/ifconfig/ifconfig.h @@ -282,7 +282,6 @@ bool match_if_flags(struct ifconfig_args *args, int if_flags); int ifconfig(if_ctx *ctx, int iscreate, const struct afswtch *uafp); bool group_member(const char *ifname, const char *match, const char *nomatch); -void print_ifcap(struct ifconfig_args *args, int s); void tunnel_status(int s); struct afswtch *af_getbyfamily(int af); void af_other_status(if_ctx *ctx); diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c --- a/sbin/ifconfig/ifconfig.c +++ b/sbin/ifconfig/ifconfig.c @@ -55,6 +55,7 @@ #include #include #include +#include #include #include @@ -1633,7 +1634,7 @@ Perror("ioctl (SIOCGIFCAP)"); } -void +static void print_ifcap(struct ifconfig_args *args, int s) { if (ioctl(s, SIOCGIFCAP, (caddr_t)&ifr) != 0) diff --git a/sbin/ifconfig/ifconfig_netlink.c b/sbin/ifconfig/ifconfig_netlink.c --- a/sbin/ifconfig/ifconfig_netlink.c +++ b/sbin/ifconfig/ifconfig_netlink.c @@ -48,6 +48,7 @@ #include #include #include +#include #include #include "ifconfig.h" #include "ifconfig_netlink.h" @@ -346,6 +347,28 @@ } } +static void +print_ifcaps(if_ctx *ctx, if_link_t *link) +{ + uint32_t sz_u32 = roundup2(link->iflaf_caps.nla_bitset_size, 32) / 32; + + if (sz_u32 > 0) { + uint32_t *caps = link->iflaf_caps.nla_bitset_value; + + printf("\toptions=%x", caps[0]); + print_bits("IFCAPS", caps, sz_u32, ifcap_bit_names, nitems(ifcap_bit_names)); + putchar('\n'); + } + + if (ctx->args->supmedia && sz_u32 > 0) { + uint32_t *caps = link->iflaf_caps.nla_bitset_mask; + + printf("\tcapabilities=%x", caps[0]); + print_bits("IFCAPS", caps, sz_u32, ifcap_bit_names, nitems(ifcap_bit_names)); + putchar('\n'); + } +} + static void status_nl(if_ctx *ctx, struct iface *iface) { @@ -363,9 +386,7 @@ if (link->ifla_ifalias != NULL) printf("\tdescription: %s\n", link->ifla_ifalias); - /* TODO: convert to netlink */ - strlcpy(ifr.ifr_name, link->ifla_ifname, sizeof(ifr.ifr_name)); - print_ifcap(args, ctx->io_s); + print_ifcaps(ctx, link); tunnel_status(ctx->io_s); if (args->allfamilies | (args->afp != NULL && args->afp->af_af == AF_LINK)) { diff --git a/sys/net/if.h b/sys/net/if.h --- a/sys/net/if.h +++ b/sys/net/if.h @@ -221,42 +221,86 @@ * to do the right thing. However, having the filter here * avoids replication of the same code in all individual drivers. */ -#define IFCAP_RXCSUM 0x00001 /* can offload checksum on RX */ -#define IFCAP_TXCSUM 0x00002 /* can offload checksum on TX */ -#define IFCAP_NETCONS 0x00004 /* can be a network console */ -#define IFCAP_VLAN_MTU 0x00008 /* VLAN-compatible MTU */ -#define IFCAP_VLAN_HWTAGGING 0x00010 /* hardware VLAN tag support */ -#define IFCAP_JUMBO_MTU 0x00020 /* 9000 byte MTU supported */ -#define IFCAP_POLLING 0x00040 /* driver supports polling */ -#define IFCAP_VLAN_HWCSUM 0x00080 /* can do IFCAP_HWCSUM on VLANs */ -#define IFCAP_TSO4 0x00100 /* can do TCP Segmentation Offload */ -#define IFCAP_TSO6 0x00200 /* can do TCP6 Segmentation Offload */ -#define IFCAP_LRO 0x00400 /* can do Large Receive Offload */ -#define IFCAP_WOL_UCAST 0x00800 /* wake on any unicast frame */ -#define IFCAP_WOL_MCAST 0x01000 /* wake on any multicast frame */ -#define IFCAP_WOL_MAGIC 0x02000 /* wake on any Magic Packet */ -#define IFCAP_TOE4 0x04000 /* interface can offload TCP */ -#define IFCAP_TOE6 0x08000 /* interface can offload TCP6 */ -#define IFCAP_VLAN_HWFILTER 0x10000 /* interface hw can filter vlan tag */ -#define IFCAP_NV 0x20000 /* can do SIOCGIFCAPNV/SIOCSIFCAPNV */ -#define IFCAP_VLAN_HWTSO 0x40000 /* can do IFCAP_TSO on VLANs */ -#define IFCAP_LINKSTATE 0x80000 /* the runtime link state is dynamic */ -#define IFCAP_NETMAP 0x100000 /* netmap mode supported/enabled */ -#define IFCAP_RXCSUM_IPV6 0x200000 /* can offload checksum on IPv6 RX */ -#define IFCAP_TXCSUM_IPV6 0x400000 /* can offload checksum on IPv6 TX */ -#define IFCAP_HWSTATS 0x800000 /* manages counters internally */ -#define IFCAP_TXRTLMT 0x1000000 /* hardware supports TX rate limiting */ -#define IFCAP_HWRXTSTMP 0x2000000 /* hardware rx timestamping */ -#define IFCAP_MEXTPG 0x4000000 /* understands M_EXTPG mbufs */ -#define IFCAP_TXTLS4 0x8000000 /* can do TLS encryption and segmentation for TCP */ -#define IFCAP_TXTLS6 0x10000000 /* can do TLS encryption and segmentation for TCP6 */ -#define IFCAP_VXLAN_HWCSUM 0x20000000 /* can do IFCAN_HWCSUM on VXLANs */ -#define IFCAP_VXLAN_HWTSO 0x40000000 /* can do IFCAP_TSO on VXLANs */ -#define IFCAP_TXTLS_RTLMT 0x80000000 /* can do TLS with rate limiting */ + +/* IFCAP values as bit indexes */ + +#define IFCAP_B_RXCSUM 0 /* can offload checksum on RX */ +#define IFCAP_B_TXCSUM 1 /* can offload checksum on TX */ +#define IFCAP_B_NETCONS 2 /* can be a network console */ +#define IFCAP_B_VLAN_MTU 3 /* VLAN-compatible MTU */ +#define IFCAP_B_VLAN_HWTAGGING 4 /* hardware VLAN tag support */ +#define IFCAP_B_JUMBO_MTU 5 /* 9000 byte MTU supported */ +#define IFCAP_B_POLLING 6 /* driver supports polling */ +#define IFCAP_B_VLAN_HWCSUM 7 /* can do IFCAP_HWCSUM on VLANs */ +#define IFCAP_B_TSO4 8 /* can do TCP Segmentation Offload */ +#define IFCAP_B_TSO6 9 /* can do TCP6 Segmentation Offload */ +#define IFCAP_B_LRO 10 /* can do Large Receive Offload */ +#define IFCAP_B_WOL_UCAST 11 /* wake on any unicast frame */ +#define IFCAP_B_WOL_MCAST 12 /* wake on any multicast frame */ +#define IFCAP_B_WOL_MAGIC 13 /* wake on any Magic Packet */ +#define IFCAP_B_TOE4 14 /* interface can offload TCP */ +#define IFCAP_B_TOE6 15 /* interface can offload TCP6 */ +#define IFCAP_B_VLAN_HWFILTER 16 /* interface hw can filter vlan tag */ +#define IFCAP_B_NV 17 /* can do SIOCGIFCAPNV/SIOCSIFCAPNV */ +#define IFCAP_B_VLAN_HWTSO 18 /* can do IFCAP_TSO on VLANs */ +#define IFCAP_B_LINKSTATE 19 /* the runtime link state is dynamic */ +#define IFCAP_B_NETMAP 20 /* netmap mode supported/enabled */ +#define IFCAP_B_RXCSUM_IPV6 21 /* can offload checksum on IPv6 RX */ +#define IFCAP_B_TXCSUM_IPV6 22 /* can offload checksum on IPv6 TX */ +#define IFCAP_B_HWSTATS 23 /* manages counters internally */ +#define IFCAP_B_TXRTLMT 24 /* hardware supports TX rate limiting */ +#define IFCAP_B_HWRXTSTMP 25 /* hardware rx timestamping */ +#define IFCAP_B_MEXTPG 26 /* understands M_EXTPG mbufs */ +#define IFCAP_B_TXTLS4 27 /* can do TLS encryption and segmentation for TCP */ +#define IFCAP_B_TXTLS6 28 /* can do TLS encryption and segmentation for TCP6 */ +#define IFCAP_B_VXLAN_HWCSUM 29 /* can do IFCAN_HWCSUM on VXLANs */ +#define IFCAP_B_VXLAN_HWTSO 30 /* can do IFCAP_TSO on VXLANs */ +#define IFCAP_B_TXTLS_RTLMT 31 /* can do TLS with rate limiting */ +#define IFCAP_B_RXTLS4 32 /* can to TLS receive for TCP */ +#define IFCAP_B_RXTLS6 33 /* can to TLS receive for TCP6 */ +#define __IFCAP_B_SIZE 34 + +#define IFCAP_B_MAX (__IFCAP_B_MAX - 1) +#define IFCAP_B_SIZE (__IFCAP_B_SIZE) + +#define IFCAP_BIT(x) (1 << (x)) + +#define IFCAP_RXCSUM IFCAP_BIT(IFCAP_B_RXCSUM) +#define IFCAP_TXCSUM IFCAP_BIT(IFCAP_B_TXCSUM) +#define IFCAP_NETCONS IFCAP_BIT(IFCAP_B_NETCONS) +#define IFCAP_VLAN_MTU IFCAP_BIT(IFCAP_B_VLAN_MTU) +#define IFCAP_VLAN_HWTAGGING IFCAP_BIT(IFCAP_B_VLAN_HWTAGGING) +#define IFCAP_JUMBO_MTU IFCAP_BIT(IFCAP_B_JUMBO_MTU) +#define IFCAP_POLLING IFCAP_BIT(IFCAP_B_POLLING) +#define IFCAP_VLAN_HWCSUM IFCAP_BIT(IFCAP_B_VLAN_HWCSUM) +#define IFCAP_TSO4 IFCAP_BIT(IFCAP_B_TSO4) +#define IFCAP_TSO6 IFCAP_BIT(IFCAP_B_TSO6) +#define IFCAP_LRO IFCAP_BIT(IFCAP_B_LRO) +#define IFCAP_WOL_UCAST IFCAP_BIT(IFCAP_B_WOL_UCAST) +#define IFCAP_WOL_MCAST IFCAP_BIT(IFCAP_B_WOL_MCAST) +#define IFCAP_WOL_MAGIC IFCAP_BIT(IFCAP_B_WOL_MAGIC) +#define IFCAP_TOE4 IFCAP_BIT(IFCAP_B_TOE4) +#define IFCAP_TOE6 IFCAP_BIT(IFCAP_B_TOE6) +#define IFCAP_VLAN_HWFILTER IFCAP_BIT(IFCAP_B_VLAN_HWFILTER) +#define IFCAP_NV IFCAP_BIT(IFCAP_B_NV) +#define IFCAP_VLAN_HWTSO IFCAP_BIT(IFCAP_B_VLAN_HWTSO) +#define IFCAP_LINKSTATE IFCAP_BIT(IFCAP_B_LINKSTATE) +#define IFCAP_NETMAP IFCAP_BIT(IFCAP_B_NETMAP) +#define IFCAP_RXCSUM_IPV6 IFCAP_BIT(IFCAP_B_RXCSUM_IPV6) +#define IFCAP_TXCSUM_IPV6 IFCAP_BIT(IFCAP_B_TXCSUM_IPV6) +#define IFCAP_HWSTATS IFCAP_BIT(IFCAP_B_HWSTATS) +#define IFCAP_TXRTLMT IFCAP_BIT(IFCAP_B_TXRTLMT) +#define IFCAP_HWRXTSTMP IFCAP_BIT(IFCAP_B_HWRXTSTMP) +#define IFCAP_MEXTPG IFCAP_BIT(IFCAP_B_MEXTPG) +#define IFCAP_TXTLS4 IFCAP_BIT(IFCAP_B_TXTLS4) +#define IFCAP_TXTLS6 IFCAP_BIT(IFCAP_B_TXTLS6) +#define IFCAP_VXLAN_HWCSUM IFCAP_BIT(IFCAP_B_VXLAN_HWCSUM) +#define IFCAP_VXLAN_HWTSO IFCAP_BIT(IFCAP_B_VXLAN_HWTSO) +#define IFCAP_TXTLS_RTLMT IFCAP_BIT(IFCAP_B_TXTLS_RTLMT) /* IFCAP2_* are integers, not bits. */ -#define IFCAP2_RXTLS4 0 -#define IFCAP2_RXTLS6 1 +#define IFCAP2_RXTLS4 (IFCAP_B_RXTLS4 - 32) +#define IFCAP2_RXTLS6 (IFCAP_B_RXTLS6 - 32) #define IFCAP2_BIT(x) (1UL << (x)) @@ -271,40 +315,6 @@ #define IFCAP_CANTCHANGE (IFCAP_NETMAP | IFCAP_NV) #define IFCAP_ALLCAPS 0xffffffff -#define IFCAP_RXCSUM_NAME "RXCSUM" -#define IFCAP_TXCSUM_NAME "TXCSUM" -#define IFCAP_NETCONS_NAME "NETCONS" -#define IFCAP_VLAN_MTU_NAME "VLAN_MTU" -#define IFCAP_VLAN_HWTAGGING_NAME "VLAN_HWTAGGING" -#define IFCAP_JUMBO_MTU_NAME "JUMBO_MTU" -#define IFCAP_POLLING_NAME "POLLING" -#define IFCAP_VLAN_HWCSUM_NAME "VLAN_HWCSUM" -#define IFCAP_TSO4_NAME "TSO4" -#define IFCAP_TSO6_NAME "TSO6" -#define IFCAP_LRO_NAME "LRO" -#define IFCAP_WOL_UCAST_NAME "WOL_UCAST" -#define IFCAP_WOL_MCAST_NAME "WOL_MCAST" -#define IFCAP_WOL_MAGIC_NAME "WOL_MAGIC" -#define IFCAP_TOE4_NAME "TOE4" -#define IFCAP_TOE6_NAME "TOE6" -#define IFCAP_VLAN_HWFILTER_NAME "VLAN_HWFILTER" -#define IFCAP_VLAN_HWTSO_NAME "VLAN_HWTSO" -#define IFCAP_LINKSTATE_NAME "LINKSTATE" -#define IFCAP_NETMAP_NAME "NETMAP" -#define IFCAP_RXCSUM_IPV6_NAME "RXCSUM_IPV6" -#define IFCAP_TXCSUM_IPV6_NAME "TXCSUM_IPV6" -#define IFCAP_HWSTATS_NAME "HWSTATS" -#define IFCAP_TXRTLMT_NAME "TXRTLMT" -#define IFCAP_HWRXTSTMP_NAME "HWRXTSTMP" -#define IFCAP_MEXTPG_NAME "MEXTPG" -#define IFCAP_TXTLS4_NAME "TXTLS4" -#define IFCAP_TXTLS6_NAME "TXTLS6" -#define IFCAP_VXLAN_HWCSUM_NAME "VXLAN_HWCSUM" -#define IFCAP_VXLAN_HWTSO_NAME "VXLAN_HWTSO" -#define IFCAP_TXTLS_RTLMT_NAME "TXTLS_RTLMT" -#define IFCAP2_RXTLS4_NAME "RXTLS4" -#define IFCAP2_RXTLS6_NAME "RXTLS6" - #define IFQ_MAXLEN 50 #define IFNET_SLOWHZ 1 /* granularity is 1 second */ diff --git a/sys/net/if.c b/sys/net/if.c --- a/sys/net/if.c +++ b/sys/net/if.c @@ -82,6 +82,7 @@ #include #include #include +#include #include #include #include diff --git a/sys/net/if_strings.h b/sys/net/if_strings.h new file mode 100644 --- /dev/null +++ b/sys/net/if_strings.h @@ -0,0 +1,106 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause + * + * 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. + */ + +#ifndef _NET_IF_STRINGS_H_ +#define _NET_IF_STRINGS_H_ + +#define IFCAP_RXCSUM_NAME "RXCSUM" +#define IFCAP_TXCSUM_NAME "TXCSUM" +#define IFCAP_NETCONS_NAME "NETCONS" +#define IFCAP_VLAN_MTU_NAME "VLAN_MTU" +#define IFCAP_VLAN_HWTAGGING_NAME "VLAN_HWTAGGING" +#define IFCAP_JUMBO_MTU_NAME "JUMBO_MTU" +#define IFCAP_POLLING_NAME "POLLING" +#define IFCAP_VLAN_HWCSUM_NAME "VLAN_HWCSUM" +#define IFCAP_TSO4_NAME "TSO4" +#define IFCAP_TSO6_NAME "TSO6" +#define IFCAP_LRO_NAME "LRO" +#define IFCAP_WOL_UCAST_NAME "WOL_UCAST" +#define IFCAP_WOL_MCAST_NAME "WOL_MCAST" +#define IFCAP_WOL_MAGIC_NAME "WOL_MAGIC" +#define IFCAP_TOE4_NAME "TOE4" +#define IFCAP_TOE6_NAME "TOE6" +#define IFCAP_VLAN_HWFILTER_NAME "VLAN_HWFILTER" +#define IFCAP_NV_NAME "NV" +#define IFCAP_VLAN_HWTSO_NAME "VLAN_HWTSO" +#define IFCAP_LINKSTATE_NAME "LINKSTATE" +#define IFCAP_NETMAP_NAME "NETMAP" +#define IFCAP_RXCSUM_IPV6_NAME "RXCSUM_IPV6" +#define IFCAP_TXCSUM_IPV6_NAME "TXCSUM_IPV6" +#define IFCAP_HWSTATS_NAME "HWSTATS" +#define IFCAP_TXRTLMT_NAME "TXRTLMT" +#define IFCAP_HWRXTSTMP_NAME "HWRXTSTMP" +#define IFCAP_MEXTPG_NAME "MEXTPG" +#define IFCAP_TXTLS4_NAME "TXTLS4" +#define IFCAP_TXTLS6_NAME "TXTLS6" +#define IFCAP_VXLAN_HWCSUM_NAME "VXLAN_HWCSUM" +#define IFCAP_VXLAN_HWTSO_NAME "VXLAN_HWTSO" +#define IFCAP_TXTLS_RTLMT_NAME "TXTLS_RTLMT" +#define IFCAP_RXTLS4_NAME "RXTLS4" +#define IFCAP_RXTLS6_NAME "RXTLS6" + +#define IFCAP2_RXTLS4_NAME IFCAP_RXTLS4_NAME +#define IFCAP2_RXTLS6_NAME IFCAP_RXTLS6_NAME + +static const char *ifcap_bit_names[] = { + IFCAP_RXCSUM_NAME, + IFCAP_TXCSUM_NAME, + IFCAP_NETCONS_NAME, + IFCAP_VLAN_MTU_NAME, + IFCAP_VLAN_HWTAGGING_NAME, + IFCAP_JUMBO_MTU_NAME, + IFCAP_POLLING_NAME, + IFCAP_VLAN_HWCSUM_NAME, + IFCAP_TSO4_NAME, + IFCAP_TSO6_NAME, + IFCAP_LRO_NAME, + IFCAP_WOL_UCAST_NAME, + IFCAP_WOL_MCAST_NAME, + IFCAP_WOL_MAGIC_NAME, + IFCAP_TOE4_NAME, + IFCAP_TOE6_NAME, + IFCAP_VLAN_HWFILTER_NAME, + IFCAP_NV_NAME, + IFCAP_VLAN_HWTSO_NAME, + IFCAP_LINKSTATE_NAME, + IFCAP_NETMAP_NAME, + IFCAP_RXCSUM_IPV6_NAME, + IFCAP_TXCSUM_IPV6_NAME, + IFCAP_HWSTATS_NAME, + IFCAP_TXRTLMT_NAME, + IFCAP_HWRXTSTMP_NAME, + IFCAP_MEXTPG_NAME, + IFCAP_TXTLS4_NAME, + IFCAP_TXTLS6_NAME, + IFCAP_VXLAN_HWCSUM_NAME, + IFCAP_VXLAN_HWTSO_NAME, + IFCAP_TXTLS_RTLMT_NAME, + IFCAP_RXTLS4_NAME, + IFCAP_RXTLS6_NAME, +}; +_Static_assert(sizeof(ifcap_bit_names) >= IFCAP_B_SIZE * sizeof(char *), + "ifcap bit names missing from ifcap_bit_names"); + +#endif diff --git a/sys/netlink/netlink_route.h b/sys/netlink/netlink_bitset.h copy from sys/netlink/netlink_route.h copy to sys/netlink/netlink_bitset.h --- a/sys/netlink/netlink_route.h +++ b/sys/netlink/netlink_bitset.h @@ -1,7 +1,7 @@ /*- * SPDX-License-Identifier: BSD-2-Clause * - * Copyright (c) 2022 Alexander V. Chernikov + * Copyright (c) 2023 Alexander V. Chernikov * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -24,20 +24,34 @@ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ -#ifndef _NETLINK_NETLINK_ROUTE_H_ -#define _NETLINK_NETLINK_ROUTE_H_ -#include +/* + * Generic netlink message header and attributes + */ +#ifndef _NETLINK_NETLINK_BITSET_H_ +#define _NETLINK_NETLINK_BITSET_H_ + +#include -#include -#include -#include +/* 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) -#include -#include -#include -#include -#include -#include +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 --- a/sys/netlink/netlink_route.h +++ b/sys/netlink/netlink_route.h @@ -33,6 +33,7 @@ #include #include +#include #include #include #include diff --git a/sys/netlink/netlink_snl.h b/sys/netlink/netlink_snl.h --- a/sys/netlink/netlink_snl.h +++ b/sys/netlink/netlink_snl.h @@ -43,6 +43,7 @@ #include #include #include +#include #define _roundup2(x, y) (((x)+((y)-1))&(~((y)-1))) @@ -732,7 +733,7 @@ } 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,89 @@ 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, 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 +1268,7 @@ 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 --- a/sys/netlink/netlink_snl_route_parsers.h +++ b/sys/netlink/netlink_snl_route_parsers.h @@ -186,12 +186,14 @@ 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 --- a/sys/netlink/route/iface.c +++ b/sys/netlink/route/iface.c @@ -253,6 +253,33 @@ 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 @@ 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 --- a/sys/netlink/route/interface.h +++ b/sys/netlink/route/interface.h @@ -151,6 +151,7 @@ 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)