The branch main has been updated by melifaro:

URL: 
https://cgit.FreeBSD.org/src/commit/?id=c344eff91070ccb15e81baf7897224882b417ae4

commit c344eff91070ccb15e81baf7897224882b417ae4
Author:     Alexander V. Chernikov <[email protected]>
AuthorDate: 2023-06-16 14:56:39 +0000
Commit:     Alexander V. Chernikov <[email protected]>
CommitDate: 2023-06-16 15:33:49 +0000

    netlink: dump interface capabilities with other interface data.
    
    This change exports interface capabilities using the standard
    Netlink attribute type, bitset, and switches `ifconfig(8)` to use
    it when displaying interface data.
    Bitset comes in two representations. The first one is "compact",
    where the bits are exported via two arrays - "mask" listing the
    "valid" bits and "values, providing the values for those bits.
    The second one is more verbose, listing each bit as a separate item,
    with its name, id and value. The latter option is handy when submitting
    update requests.
    
    The support for setting capabilities will be added in the upcoming diffs.
    
    Differential Revision: https://reviews.freebsd.org/D40331
---
 sbin/ifconfig/ifconfig.c                |   6 +-
 sbin/ifconfig/ifconfig.h                |   1 -
 sbin/ifconfig/ifconfig_netlink.c        |  26 +++++-
 sys/net/if.c                            |   1 +
 sys/net/if.h                            | 146 +++++++++++++++++---------------
 sys/net/if_strings.h                    | 106 +++++++++++++++++++++++
 sys/netlink/netlink_bitset.h            |  57 +++++++++++++
 sys/netlink/netlink_route.h             |   1 +
 sys/netlink/netlink_snl.h               |  88 ++++++++++++++++++-
 sys/netlink/netlink_snl_route_parsers.h |   2 +
 sys/netlink/route/iface.c               |  28 ++++++
 sys/netlink/route/interface.h           |   1 +
 12 files changed, 390 insertions(+), 73 deletions(-)

diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index f3d16fc052f6..fa22f09f8100 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -55,6 +55,7 @@ static const char rcsid[] =
 #include <net/ethernet.h>
 #include <net/if.h>
 #include <net/if_dl.h>
+#include <net/if_strings.h>
 #include <net/if_types.h>
 #include <net/route.h>
 
@@ -1585,6 +1586,8 @@ unsetifdescr(if_ctx *ctx, const char *val __unused, int 
value __unused)
        setifdescr(ctx, "", 0);
 }
 
+#ifdef WITHOUT_NETLINK
+
 #define        IFFBITS \
 "\020\1UP\2BROADCAST\3DEBUG\4LOOPBACK\5POINTOPOINT\7RUNNING" \
 "\10NOARP\11PROMISC\12ALLMULTI\13OACTIVE\14SIMPLEX\15LINK0\16LINK1\17LINK2" \
@@ -1656,7 +1659,7 @@ print_ifcap_nv(if_ctx *ctx)
                Perror("ioctl (SIOCGIFCAP)");
 }
 
-void
+static void
 print_ifcap(if_ctx *ctx)
 {
        struct ifreq ifr = {};
@@ -1675,6 +1678,7 @@ print_ifcap(if_ctx *ctx)
                }
        }
 }
+#endif
 
 void
 print_ifstatus(if_ctx *ctx)
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index c97ef447a3b3..e33a2c63aec1 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -275,7 +275,6 @@ bool        match_ether(const struct sockaddr_dl *sdl);
 bool   match_if_flags(struct ifconfig_args *args, int if_flags);
 int    ifconfig_ioctl(if_ctx *ctx, int iscreate, const struct afswtch *uafp);
 bool   group_member(const char *ifname, const char *match, const char 
*nomatch);
-void   print_ifcap(if_ctx *ctx);
 void   tunnel_status(if_ctx *ctx);
 struct afswtch *af_getbyfamily(int af);
 void   af_other_status(if_ctx *ctx);
diff --git a/sbin/ifconfig/ifconfig_netlink.c b/sbin/ifconfig/ifconfig_netlink.c
index 2460d8c60109..f09023c1477c 100644
--- a/sbin/ifconfig/ifconfig_netlink.c
+++ b/sbin/ifconfig/ifconfig_netlink.c
@@ -48,6 +48,7 @@
 #include <net/ethernet.h>
 #include <net/if.h>
 #include <net/if_dl.h>
+#include <net/if_strings.h>
 #include <net/if_types.h>
 #include "ifconfig.h"
 #include "ifconfig_netlink.h"
@@ -343,6 +344,28 @@ sort_iface_ifaddrs(struct snl_state *ss, struct iface 
*iface)
        }
 }
 
+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)
 {
@@ -360,8 +383,7 @@ status_nl(if_ctx *ctx, struct iface *iface)
        if (link->ifla_ifalias != NULL)
                printf("\tdescription: %s\n", link->ifla_ifalias);
 
-       /* TODO: convert to netlink */
-       print_ifcap(ctx);
+       print_ifcaps(ctx, link);
        tunnel_status(ctx);
 
        if (args->allfamilies | (args->afp != NULL && args->afp->af_af == 
AF_LINK)) {
diff --git a/sys/net/if.c b/sys/net/if.c
index 975f4498073e..c5f0a65721fc 100644
--- a/sys/net/if.c
+++ b/sys/net/if.c
@@ -82,6 +82,7 @@
 #include <net/if_arp.h>
 #include <net/if_clone.h>
 #include <net/if_dl.h>
+#include <net/if_strings.h>
 #include <net/if_types.h>
 #include <net/if_var.h>
 #include <net/if_media.h>
diff --git a/sys/net/if.h b/sys/net/if.h
index 4003b33e5de4..bd2787516f01 100644
--- a/sys/net/if.h
+++ b/sys/net/if.h
@@ -221,42 +221,86 @@ struct if_data {
  * 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 @@ struct if_data {
 #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_strings.h b/sys/net/if_strings.h
new file mode 100644
index 000000000000..95d85f5370ed
--- /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_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 <[email protected]>
+ *
+ * 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)

Reply via email to