From nobody Sun Aug 9 06:47:48 2026 X-Original-To: dev-commits-src-all@mlmmj.nyi.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2610:1c1:1:606c::19:1]) by mlmmj.nyi.freebsd.org (Postfix) with ESMTP id 4hHpNj36Vpz6n8bx for ; Sun, 09 Aug 2026 06:47:49 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from mxrelay.nyi.freebsd.org (mxrelay.nyi.freebsd.org [IPv6:2610:1c1:1:606c::19:3]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (4096 bits) client-digest SHA256) (Client CN "mxrelay.nyi.freebsd.org", Issuer "YR1" (not verified)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hHpNj0VFxz3TkT for ; Sun, 09 Aug 2026 06:47:49 +0000 (UTC) (envelope-from git@FreeBSD.org) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786258069; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=03qQ33gwQQsSYwZeR7h4TuHnQs7AcNH6AMjvwptOzn8=; b=l89b/OufWCarMR84vfigNQB+ZVdidi4th8AGRJj53Jg88AjBY+kRFkhSY5Au7GnRNZLmAj Hda1GwyQg3uc7MqHsoCyLIlNhIAG3WHUdq3o8MMMEhL/klHwN19Y+0P8bH4FbwjURq1hdK L055zoh9AjGgRScjgLW6H/yxpKPItCniOXkS3Q5fpmbjyn6RWjLKGTJ23W4TZ4BmJFyMio GF+3kDIHIewoCsUsJGgqtu82rOPy1aFIsdHk/sMTYKxX/vLARJKcfllYsgDG5a6B3e+pQ9 NbQz09yOiccM1jvhRoL2Hfo3bxFS0UltQ3zK7ANp6OaskCzulYuBHwxhrMdE1A== ARC-Seal: i=1; s=dkim; d=freebsd.org; t=1786258069; a=rsa-sha256; cv=none; b=c4RHMVb3guvbalyZu3fs0uXydVrXyQujR7HolHAkgvU/55gXA800STaXoB6CJqlfUYMlG1 A44cGhvwAge3GeqoXzmMmOr/rmbE1CNCAJhqJQ7c0dqUksB671E/8zq3hOTseR7+oitlBV 79QLFga6ppqP6pZ+qqpeIl5/Zci3SENvs4tUSqZiunzdZYpZdAfk7CUUgzr+z68bqKeywF cxsyQUW5tqZNozNtv993GKD/2brMcMgIhL/RxE4n0RRh7qqXDqVUs+0ih56vrEaNWPuItf UQusUNtlPBCfa49HCENgrXOCTjZhkWbYm/5/zU8IVtSLmJ8UuCQFKZcPq8/gUw== ARC-Authentication-Results: i=1; mx1.freebsd.org; none ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=freebsd.org; s=dkim; t=1786258069; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=03qQ33gwQQsSYwZeR7h4TuHnQs7AcNH6AMjvwptOzn8=; b=b/DReIiOpmMyjQ2gmlnNkWI+9z7Nlo0AUbb+amS0TfheMFiVFCwzteUtpjsxrFB0tmfssR DcdqKC3k4LHTQwBOn0LrznAaLrcQnhu15JBIA1JNoptRunm9Xn1LD3ps4KuTsVheswE2nY SjtRHUVyJi7J1RDLVEt/qWkaxRq8NQWrwTXM8FqBP696Fj0sivEEWcc5GYyQjjdEoPAogB QZyHLCQV5hzlcHGqRqLKN2YEzcR4+yexTGOg/kb/wPNzqLHeZVwt4LzGajD113gQWdXce5 Aso48UH95jC9E8XlVpzHm6maD/UnKTgZxoz6j+FIpL7HsJ4fxZnH1qD+WMttcA== Received: from gitrepo.freebsd.org (gitrepo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:5]) by mxrelay.nyi.freebsd.org (Postfix) with ESMTP id 4hHpNh6FJPz1BXw for ; Sun, 09 Aug 2026 06:47:48 +0000 (UTC) (envelope-from git@FreeBSD.org) Received: from git (uid 1279) (envelope-from git@FreeBSD.org) id 3e4e1 by gitrepo.freebsd.org (DragonFly Mail Agent v0.13+ on gitrepo.freebsd.org); Sun, 09 Aug 2026 06:47:48 +0000 To: src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org From: Kevin Bowling Subject: git: d15f2551b25f - main - rtnetlink: Report SR-IOV VF status List-Id: Commit messages for all branches of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-all List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-all@freebsd.org Sender: owner-dev-commits-src-all@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: 8bit X-Git-Committer: kbowling X-Git-Repository: src X-Git-Refname: refs/heads/main X-Git-Reftype: branch X-Git-Commit: d15f2551b25f79ddcbe289faa95e655100b952da Auto-Submitted: auto-generated Date: Sun, 09 Aug 2026 06:47:48 +0000 Message-Id: <6a782294.3e4e1.77fae9fb@gitrepo.freebsd.org> The branch main has been updated by kbowling: URL: https://cgit.FreeBSD.org/src/commit/?id=d15f2551b25f79ddcbe289faa95e655100b952da commit d15f2551b25f79ddcbe289faa95e655100b952da Author: Kevin Bowling AuthorDate: 2026-08-09 02:04:11 +0000 Commit: Kevin Bowling CommitDate: 2026-08-09 06:46:57 +0000 rtnetlink: Report SR-IOV VF status Honor RTEXT_FILTER_VF on RTM_GETLINK requests and expose the versioned SR-IOV VF status through typed nested FreeBSD attributes. Report IFLA_NUM_VF with a successful requested query and preserve per-provider errors in the status container. Map the common nvlist schema to native integer, boolean, string, and binary attributes. Carry namespaced driver extensions as packed versioned nvlists so adding a driver-specific field does not expand the common netlink ABI. Add SNL parsers, parser verification, a constructed nested-status test, and an RTM_GETLINK test for an interface without SR-IOV support. Document the query contract and every attribute. --- share/man/man4/rtnetlink.4 | 118 ++++++++++- sys/netlink/netlink_snl_route_parsers.h | 112 ++++++++++ sys/netlink/route/iface.c | 284 +++++++++++++++++++++++++- sys/netlink/route/interface.h | 82 +++++++- sys/netlink/route/route_var.h | 1 + tests/atf_python/sys/netlink/attrs.py | 28 +++ tests/atf_python/sys/netlink/netlink_route.py | 117 +++++++++++ tests/sys/netlink/test_rtnl_iface.py | 13 +- tests/sys/netlink/test_snl.c | 89 ++++++++ 9 files changed, 835 insertions(+), 9 deletions(-) diff --git a/share/man/man4/rtnetlink.4 b/share/man/man4/rtnetlink.4 index 3d76c66c1917..5d5e69cdbbf0 100644 --- a/share/man/man4/rtnetlink.4 +++ b/share/man/man4/rtnetlink.4 @@ -22,7 +22,7 @@ .\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF .\" SUCH DAMAGE. .\" -.Dd July 28, 2026 +.Dd August 8, 2026 .Dt RTNETLINK 4 .Os .Sh NAME @@ -325,7 +325,17 @@ The following filters are recognised by the kernel: ifi_index interface index IFLA_IFNAME interface name IFLA_ALT_IFNAME interface name +IFLA_EXT_MASK extended information selection bitmap .Ed +.Pp +Setting the +.Dv RTEXT_FILTER_VF +bit in +.Dv IFLA_EXT_MASK +requests SR-IOV VF status. +The query is opt-in because obtaining status can require entering the PF +driver. +VF status is not included in unsolicited link notifications. .Ss TLVs .Bl -tag -width indent .It Dv IFLA_ADDRESS @@ -340,6 +350,112 @@ IFLA_ALT_IFNAME interface name (uint32_t) (readonly) Interface index. .It Dv IFLA_MASTER (uint32_t) Parent interface index. +.It Dv IFLA_NUM_VF +(uint32_t) (readonly) Number of active VFs. +This attribute is returned with a successful +.Dv RTEXT_FILTER_VF +query. +.It Dv IFLA_FREEBSD +(nested) Local interface attributes. +When requested, +.Dv IFLAF_VF_STATUS +contains the following nested attributes: +.Bd -literal -offset indent -compact +IFLAF_VFS_VERSION (uint32_t) VF status schema version +IFLAF_VFS_ERROR (uint32_t) errno if the PF query failed +IFLAF_VFS_PF_LINK_STATE (uint8_t) IFLAF_VF_LINK_* +IFLAF_VFS_PF_LINK_SPEED (uint64_t) bits per second +IFLAF_VFS_LIST (nested) repeated IFLAF_VF_LIST_ENTRY +.Ed +.Pp +On a successful query, +.Dv IFLAF_VFS_VERSION +and +.Dv IFLAF_VFS_LIST +are present. +If the PF status query fails, +.Dv IFLAF_VFS_ERROR +contains the errno value and the other status attributes are omitted. +.Pp +Each +.Dv IFLAF_VF_LIST_ENTRY +may contain the following attributes: +.Bd -literal -offset indent -compact +IFLAF_VF_INDEX (uint32_t) PF-local VF index +IFLAF_VF_CONFIGURED (uint8_t) PF accepted configuration +IFLAF_VF_INITIALIZED (uint8_t) VF handshake completed +IFLAF_VF_MAC (binary) PF-known primary MAC address +IFLAF_VF_VLAN_MODE (uint8_t) IFLAF_VF_VLAN_* +IFLAF_VF_VLAN (uint16_t) access VLAN identifier +IFLAF_VF_VLAN_COUNT (uint32_t) explicit VLAN filters +IFLAF_VF_VLAN_LIMIT (uint32_t) explicit VLAN-filter limit +IFLAF_VF_NUM_QUEUES (uint32_t) allocated RX/TX queue pairs +IFLAF_VF_ALLOW_SET_MAC (uint8_t) administrative permission +IFLAF_VF_ALLOW_SET_VLAN (uint8_t) administrative permission +IFLAF_VF_MAC_ANTI_SPOOF (uint8_t) MAC anti-spoofing enabled +IFLAF_VF_ALLOW_PROMISC (uint8_t) administrative permission +IFLAF_VF_TRAFFIC_ENABLED (uint8_t) VF traffic enabled +IFLAF_VF_MDD_BLOCKED (uint8_t) malicious-driver block active +IFLAF_VF_QUARANTINED (uint8_t) persistent quarantine active +IFLAF_VF_API_VERSION (string) negotiated mailbox API +IFLAF_VF_LINK_STATE_POLICY (uint8_t) IFLAF_VF_LINK_* +IFLAF_VF_EXTENSIONS (nested) driver-specific namespaces +.Ed +.Pp +.Dv IFLAF_VF_INDEX +is required in every list entry. +Other fields are optional and are omitted when the PF driver cannot observe +them; omission does not mean false or zero. +Boolean attributes contain zero or one. +.Dv IFLAF_VF_CONFIGURED +means that the PF accepted the VF configuration, while +.Dv IFLAF_VF_INITIALIZED +means that the VF completed its driver or mailbox handshake since its last +reset. +.Pp +.Dv IFLAF_VF_NUM_QUEUES +is the number of allocated symmetric RX/TX queue pairs, not necessarily the +number currently used by the VF driver. +Access VLAN mode means that the PF imposes +.Dv IFLAF_VF_VLAN ; +trunk mode means that no access VLAN is imposed and does not promise unlimited +filter capacity. +.Dv IFLAF_VF_VLAN_COUNT +counts explicit filters recorded by the PF and excludes implicit untagged and +priority-tag membership. +The permission attributes describe requests the VF may make, not requests it +has made. +The top-level PF link state and speed are values normally advertised to VFs, +not evidence that a VF driver is operational. +.Pp +Link-state values are: +.Bd -literal -offset indent -compact +IFLAF_VF_LINK_UNKNOWN state is unavailable +IFLAF_VF_LINK_DOWN link is forced or observed down +IFLAF_VF_LINK_UP link is forced or observed up +IFLAF_VF_LINK_AUTO VF follows PF link state +.Ed +.Pp +VLAN-mode values are: +.Bd -literal -offset indent -compact +IFLAF_VF_VLAN_UNKNOWN mode is unavailable +IFLAF_VF_VLAN_ACCESS PF imposes an access VLAN +IFLAF_VF_VLAN_TRUNK no access VLAN is imposed +.Ed +.Pp +Driver-specific data is returned under +.Dv IFLAF_VF_EXTENSIONS +as repeated +.Dv IFLAF_VF_EXT_LIST_ENTRY +objects. +Each object contains a stable namespace string in +.Dv IFLAF_VF_EXT_NAME +and its packed, versioned +.Xr nvlist 9 +in +.Dv IFLAF_VF_EXT_DATA . +Each namespace contains a version number. +Consumers must ignore unknown namespaces and fields. .It Dv IFLA_LINKINFO (nested) Interface type-specific attributes: .Bd -literal -offset indent -compact diff --git a/sys/netlink/netlink_snl_route_parsers.h b/sys/netlink/netlink_snl_route_parsers.h index f0849884ec97..9f699ef528a3 100644 --- a/sys/netlink/netlink_snl_route_parsers.h +++ b/sys/netlink/netlink_snl_route_parsers.h @@ -178,6 +178,113 @@ SNL_DECLARE_PARSER_EXT(snl_rtm_route_parser, sizeof(struct rtmsg), _cb_p_route); /* RTM_LINK message parser */ +struct snl_parsed_vf_extension { + char *name; + struct nlattr *data; +}; + +#define _OUT(_field) offsetof(struct snl_parsed_vf_extension, _field) +static const struct snl_attr_parser _nla_p_vf_extension[] = { + { .type = IFLAF_VF_EXT_NAME, .off = _OUT(name), + .cb = snl_attr_dup_string }, + { .type = IFLAF_VF_EXT_DATA, .off = _OUT(data), + .cb = snl_attr_dup_nla }, +}; +#undef _OUT +SNL_DECLARE_ATTR_PARSER_EXT(_vf_extension_parser, + sizeof(struct snl_parsed_vf_extension), _nla_p_vf_extension, NULL); + +struct snl_parsed_vf { + uint32_t index; + uint32_t vlan_count; + uint32_t vlan_limit; + uint32_t num_queues; + uint16_t vlan; + uint8_t configured; + uint8_t initialized; + uint8_t vlan_mode; + uint8_t allow_set_mac; + uint8_t allow_set_vlan; + uint8_t mac_anti_spoof; + uint8_t allow_promisc; + uint8_t traffic_enabled; + uint8_t mdd_blocked; + uint8_t quarantined; + uint8_t link_state_policy; + char *api_version; + struct nlattr *mac; + struct snl_parray extensions; +}; + +#define _OUT(_field) offsetof(struct snl_parsed_vf, _field) +static const struct snl_attr_parser _nla_p_vf[] = { + { .type = IFLAF_VF_INDEX, .off = _OUT(index), + .cb = snl_attr_get_uint32 }, + { .type = IFLAF_VF_CONFIGURED, .off = _OUT(configured), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_INITIALIZED, .off = _OUT(initialized), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_MAC, .off = _OUT(mac), .cb = snl_attr_dup_nla }, + { .type = IFLAF_VF_VLAN_MODE, .off = _OUT(vlan_mode), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_VLAN, .off = _OUT(vlan), + .cb = snl_attr_get_uint16 }, + { .type = IFLAF_VF_VLAN_COUNT, .off = _OUT(vlan_count), + .cb = snl_attr_get_uint32 }, + { .type = IFLAF_VF_VLAN_LIMIT, .off = _OUT(vlan_limit), + .cb = snl_attr_get_uint32 }, + { .type = IFLAF_VF_NUM_QUEUES, .off = _OUT(num_queues), + .cb = snl_attr_get_uint32 }, + { .type = IFLAF_VF_ALLOW_SET_MAC, .off = _OUT(allow_set_mac), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_ALLOW_SET_VLAN, .off = _OUT(allow_set_vlan), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_MAC_ANTI_SPOOF, .off = _OUT(mac_anti_spoof), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_ALLOW_PROMISC, .off = _OUT(allow_promisc), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_TRAFFIC_ENABLED, .off = _OUT(traffic_enabled), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_MDD_BLOCKED, .off = _OUT(mdd_blocked), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_QUARANTINED, .off = _OUT(quarantined), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_API_VERSION, .off = _OUT(api_version), + .cb = snl_attr_dup_string }, + { .type = IFLAF_VF_LINK_STATE_POLICY, + .off = _OUT(link_state_policy), .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VF_EXTENSIONS, .off = _OUT(extensions), + .arg = &_vf_extension_parser, .cb = snl_attr_get_parray }, +}; +#undef _OUT +SNL_DECLARE_ATTR_PARSER_EXT(_vf_parser, sizeof(struct snl_parsed_vf), + _nla_p_vf, NULL); + +struct snl_parsed_vf_status { + uint64_t pf_link_speed; + uint32_t version; + uint32_t error; + uint8_t pf_link_state; + struct snl_parray vfs; +}; + +#define _OUT(_field) offsetof(struct snl_parsed_vf_status, _field) +static const struct snl_attr_parser _nla_p_vf_status[] = { + { .type = IFLAF_VFS_VERSION, .off = _OUT(version), + .cb = snl_attr_get_uint32 }, + { .type = IFLAF_VFS_ERROR, .off = _OUT(error), + .cb = snl_attr_get_uint32 }, + { .type = IFLAF_VFS_PF_LINK_STATE, .off = _OUT(pf_link_state), + .cb = snl_attr_get_uint8 }, + { .type = IFLAF_VFS_PF_LINK_SPEED, .off = _OUT(pf_link_speed), + .cb = snl_attr_get_uint64 }, + { .type = IFLAF_VFS_LIST, .off = _OUT(vfs), + .arg = &_vf_parser, .cb = snl_attr_get_parray }, +}; +#undef _OUT +SNL_DECLARE_ATTR_PARSER_EXT(_vf_status_parser, + sizeof(struct snl_parsed_vf_status), _nla_p_vf_status, NULL); + struct snl_parsed_link { uint32_t ifi_index; uint32_t ifi_flags; @@ -191,9 +298,11 @@ struct snl_parsed_link { struct nlattr *ifla_broadcast; char *ifla_ifalias; uint32_t ifla_promiscuity; + uint32_t ifla_num_vf; struct rtnl_link_stats64 *ifla_stats64; struct nlattr *iflaf_orig_hwaddr; struct snl_attr_bitset iflaf_caps; + struct snl_parsed_vf_status iflaf_vf_status; }; #define _IN(_field) offsetof(struct ifinfomsg, _field) @@ -201,6 +310,8 @@ struct snl_parsed_link { 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 }, + { .type = IFLAF_VF_STATUS, .off = _OUT(iflaf_vf_status), + .arg = &_vf_status_parser, .cb = snl_attr_get_nested }, }; SNL_DECLARE_ATTR_PARSER(_link_fbsd_parser, _nla_p_link_fbsd); @@ -211,6 +322,7 @@ static const struct snl_attr_parser _nla_p_link[] = { { .type = IFLA_MTU, .off = _OUT(ifla_mtu), .cb = snl_attr_get_uint32 }, { .type = IFLA_OPERSTATE, .off = _OUT(ifla_operstate), .cb = snl_attr_get_uint8 }, { .type = IFLA_IFALIAS, .off = _OUT(ifla_ifalias), .cb = snl_attr_dup_string }, + { .type = IFLA_NUM_VF, .off = _OUT(ifla_num_vf), .cb = snl_attr_get_uint32 }, { .type = IFLA_STATS64, .off = _OUT(ifla_stats64), .cb = snl_attr_dup_struct }, { .type = IFLA_PROMISCUITY, .off = _OUT(ifla_promiscuity), .cb = snl_attr_get_uint32 }, { .type = IFLA_CARRIER, .off = _OUT(ifla_carrier), .cb = snl_attr_get_uint8 }, diff --git a/sys/netlink/route/iface.c b/sys/netlink/route/iface.c index 5b6e58a598aa..bb04c2a94c1e 100644 --- a/sys/netlink/route/iface.c +++ b/sys/netlink/route/iface.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include #include @@ -65,6 +66,7 @@ struct netlink_walkargs { struct nlpcb *so; struct ucred *cred; uint32_t fibnum; + uint32_t ext_mask; int family; int error; int count; @@ -279,6 +281,245 @@ dump_iface_caps(struct nl_writer *nw, struct ifnet *ifp) return (true); } +static uint8_t +vf_link_state(const char *state) +{ + + if (strcmp(state, IFVF_LINK_STATE_DOWN) == 0) + return (IFLAF_VF_LINK_DOWN); + if (strcmp(state, IFVF_LINK_STATE_UP) == 0) + return (IFLAF_VF_LINK_UP); + if (strcmp(state, IFVF_LINK_STATE_AUTO) == 0) + return (IFLAF_VF_LINK_AUTO); + return (IFLAF_VF_LINK_UNKNOWN); +} + +static bool +dump_vf_bool(struct nl_writer *nw, const nvlist_t *vf, const char *name, + uint16_t attr) +{ + + if (!nvlist_exists_bool(vf, name)) + return (true); + return (nlattr_add_u8(nw, attr, nvlist_get_bool(vf, name) ? 1 : 0)); +} + +static bool +dump_vf_u16(struct nl_writer *nw, const nvlist_t *vf, const char *name, + uint16_t attr) +{ + uint64_t value; + + if (!nvlist_exists_number(vf, name)) + return (true); + value = nvlist_get_number(vf, name); + if (value > UINT16_MAX) + return (false); + return (nlattr_add_u16(nw, attr, (uint16_t)value)); +} + +static bool +dump_vf_u32(struct nl_writer *nw, const nvlist_t *vf, const char *name, + uint16_t attr) +{ + uint64_t value; + + if (!nvlist_exists_number(vf, name)) + return (true); + value = nvlist_get_number(vf, name); + if (value > UINT32_MAX) + return (false); + return (nlattr_add_u32(nw, attr, (uint32_t)value)); +} + +static bool +dump_vf_string(struct nl_writer *nw, const nvlist_t *vf, const char *name, + uint16_t attr) +{ + + if (!nvlist_exists_string(vf, name)) + return (true); + return (nlattr_add_string(nw, attr, nvlist_get_string(vf, name))); +} + +static bool +dump_vf_extensions(struct nl_writer *nw, const nvlist_t *vf) +{ + const nvlist_t *extension, *extensions; + const char *name; + void *buf, *cookie; + size_t buflen; + int entry_off, extensions_off, type; + bool ok; + + if (!nvlist_exists(vf, IFVF_STATUS_EXTENSIONS)) + return (true); + if (!nvlist_exists_nvlist(vf, IFVF_STATUS_EXTENSIONS)) + return (false); + + extensions = nvlist_get_nvlist(vf, IFVF_STATUS_EXTENSIONS); + extensions_off = nlattr_add_nested(nw, IFLAF_VF_EXTENSIONS); + if (extensions_off == 0) + return (false); + cookie = NULL; + while ((name = nvlist_next(extensions, &type, &cookie)) != NULL) { + if (type != NV_TYPE_NVLIST) + return (false); + extension = nvlist_get_nvlist(extensions, name); + if (!nvlist_exists_number(extension, + IFVF_STATUS_EXT_VERSION)) + return (false); + buf = nvlist_pack(extension, &buflen); + if (buf == NULL) + return (false); + if (buflen > UINT16_MAX - sizeof(struct nlattr)) { + free(buf, M_NVLIST); + return (false); + } + entry_off = nlattr_add_nested(nw, + IFLAF_VF_EXT_LIST_ENTRY); + if (entry_off == 0) { + free(buf, M_NVLIST); + return (false); + } + ok = nlattr_add_string(nw, IFLAF_VF_EXT_NAME, name) && + nlattr_add(nw, IFLAF_VF_EXT_DATA, (uint16_t)buflen, buf); + free(buf, M_NVLIST); + if (!ok) + return (false); + nlattr_set_len(nw, entry_off); + } + nlattr_set_len(nw, extensions_off); + return (true); +} + +static bool +dump_vf_entry(struct nl_writer *nw, const nvlist_t *vf) +{ + const void *mac; + const char *mode, *policy; + size_t maclen; + uint8_t vlan_mode; + int off; + bool ok; + + off = nlattr_add_nested(nw, IFLAF_VF_LIST_ENTRY); + if (off == 0) + return (false); + ok = dump_vf_u32(nw, vf, IFVF_STATUS_INDEX, IFLAF_VF_INDEX) && + dump_vf_bool(nw, vf, IFVF_STATUS_CONFIGURED, + IFLAF_VF_CONFIGURED) && + dump_vf_bool(nw, vf, IFVF_STATUS_INITIALIZED, + IFLAF_VF_INITIALIZED); + if (!ok) + return (false); + + if (nvlist_exists_binary(vf, IFVF_STATUS_MAC)) { + mac = nvlist_get_binary(vf, IFVF_STATUS_MAC, &maclen); + if (maclen > UINT16_MAX - sizeof(struct nlattr) || + !nlattr_add(nw, IFLAF_VF_MAC, (uint16_t)maclen, mac)) + return (false); + } + if (nvlist_exists_string(vf, IFVF_STATUS_VLAN_MODE)) { + mode = nvlist_get_string(vf, IFVF_STATUS_VLAN_MODE); + if (strcmp(mode, IFVF_VLAN_MODE_ACCESS) == 0) + vlan_mode = IFLAF_VF_VLAN_ACCESS; + else if (strcmp(mode, IFVF_VLAN_MODE_TRUNK) == 0) + vlan_mode = IFLAF_VF_VLAN_TRUNK; + else + vlan_mode = IFLAF_VF_VLAN_UNKNOWN; + if (!nlattr_add_u8(nw, IFLAF_VF_VLAN_MODE, vlan_mode)) + return (false); + } + ok = dump_vf_u16(nw, vf, IFVF_STATUS_VLAN, IFLAF_VF_VLAN) && + dump_vf_u32(nw, vf, IFVF_STATUS_VLAN_COUNT, + IFLAF_VF_VLAN_COUNT) && + dump_vf_u32(nw, vf, IFVF_STATUS_VLAN_LIMIT, + IFLAF_VF_VLAN_LIMIT) && + dump_vf_u32(nw, vf, IFVF_STATUS_NUM_QUEUES, + IFLAF_VF_NUM_QUEUES) && + dump_vf_bool(nw, vf, IFVF_STATUS_ALLOW_SET_MAC, + IFLAF_VF_ALLOW_SET_MAC) && + dump_vf_bool(nw, vf, IFVF_STATUS_ALLOW_SET_VLAN, + IFLAF_VF_ALLOW_SET_VLAN) && + dump_vf_bool(nw, vf, IFVF_STATUS_MAC_ANTI_SPOOF, + IFLAF_VF_MAC_ANTI_SPOOF) && + dump_vf_bool(nw, vf, IFVF_STATUS_ALLOW_PROMISC, + IFLAF_VF_ALLOW_PROMISC) && + dump_vf_bool(nw, vf, IFVF_STATUS_TRAFFIC_ENABLED, + IFLAF_VF_TRAFFIC_ENABLED) && + dump_vf_bool(nw, vf, IFVF_STATUS_MDD_BLOCKED, + IFLAF_VF_MDD_BLOCKED) && + dump_vf_bool(nw, vf, IFVF_STATUS_QUARANTINED, + IFLAF_VF_QUARANTINED) && + dump_vf_string(nw, vf, IFVF_STATUS_API_VERSION, + IFLAF_VF_API_VERSION); + if (!ok) + return (false); + if (nvlist_exists_string(vf, IFVF_STATUS_LINK_STATE_POLICY)) { + policy = nvlist_get_string(vf, + IFVF_STATUS_LINK_STATE_POLICY); + if (!nlattr_add_u8(nw, IFLAF_VF_LINK_STATE_POLICY, + vf_link_state(policy))) + return (false); + } + if (!dump_vf_extensions(nw, vf)) + return (false); + nlattr_set_len(nw, off); + return (true); +} + +static bool +dump_vf_status(struct nl_writer *nw, const nvlist_t *status, int error) +{ + const nvlist_t * const *vfs; + const char *state; + size_t i, num_vfs; + uint64_t version; + int list_off, off; + + off = nlattr_add_nested(nw, IFLAF_VF_STATUS); + if (off == 0) + return (false); + if (error != 0) { + if (!nlattr_add_u32(nw, IFLAF_VFS_ERROR, (uint32_t)error)) + return (false); + nlattr_set_len(nw, off); + return (true); + } + + if (!nvlist_exists_number(status, IFVF_STATUS_VERSION_KEY)) + return (false); + version = nvlist_get_number(status, IFVF_STATUS_VERSION_KEY); + if (version > UINT32_MAX || + !nlattr_add_u32(nw, IFLAF_VFS_VERSION, (uint32_t)version)) + return (false); + if (nvlist_exists_string(status, IFVF_STATUS_PF_LINK_STATE)) { + state = nvlist_get_string(status, IFVF_STATUS_PF_LINK_STATE); + if (!nlattr_add_u8(nw, IFLAF_VFS_PF_LINK_STATE, + vf_link_state(state))) + return (false); + } + if (nvlist_exists_number(status, IFVF_STATUS_PF_LINK_SPEED) && + !nlattr_add_u64(nw, IFLAF_VFS_PF_LINK_SPEED, + nvlist_get_number(status, IFVF_STATUS_PF_LINK_SPEED))) + return (false); + if (!nvlist_exists_nvlist_array(status, IFVF_STATUS_VFS)) + return (false); + + vfs = nvlist_get_nvlist_array(status, IFVF_STATUS_VFS, &num_vfs); + list_off = nlattr_add_nested(nw, IFLAF_VFS_LIST); + if (list_off == 0) + return (false); + for (i = 0; i < num_vfs; i++) { + if (!dump_vf_entry(nw, vfs[i])) + return (false); + } + nlattr_set_len(nw, list_off); + nlattr_set_len(nw, off); + return (true); +} + /* * Dumps interface state, properties and metrics. * @nw: message writer @@ -290,12 +531,26 @@ dump_iface_caps(struct nl_writer *nw, struct ifnet *ifp) */ static bool dump_iface(struct nl_writer *nw, if_t ifp, const struct nlmsghdr *hdr, - int if_flags_mask, const char *ifname) + int if_flags_mask, const char *ifname, uint32_t ext_mask) { struct epoch_tracker et; + nvlist_t *vf_status; + size_t num_vfs; struct ifinfomsg *ifinfo; + bool include_vf_status; + int vf_error; NL_LOG(LOG_DEBUG3, "dumping interface %s data", if_name(ifp)); + vf_status = NULL; + vf_error = 0; + include_vf_status = (ext_mask & RTEXT_FILTER_VF) != 0; + if (include_vf_status) { + vf_error = if_get_vf_status(ifp, &vf_status); + if (vf_error == EINVAL || vf_error == ENOTTY || + vf_error == ENXIO || vf_error == ENOTSUP || + vf_error == EOPNOTSUPP) + include_vf_status = false; + } if (!nlmsg_reply(nw, hdr, sizeof(struct ifinfomsg))) goto enomem; @@ -341,6 +596,14 @@ dump_iface(struct nl_writer *nw, if_t ifp, const struct nlmsghdr *hdr, } nlattr_add_u32(nw, IFLA_MTU, if_getmtu(ifp)); + if (vf_status != NULL && + nvlist_exists_nvlist_array(vf_status, IFVF_STATUS_VFS)) { + (void)nvlist_get_nvlist_array(vf_status, IFVF_STATUS_VFS, + &num_vfs); + if (num_vfs > UINT32_MAX || + !nlattr_add_u32(nw, IFLA_NUM_VF, (uint32_t)num_vfs)) + goto enomem; + } /* nlattr_add_u32(nw, IFLA_MIN_MTU, 60); nlattr_add_u32(nw, IFLA_MAX_MTU, 9000); @@ -355,6 +618,9 @@ dump_iface(struct nl_writer *nw, if_t ifp, const struct nlmsghdr *hdr, if (off != 0) { get_hwaddr(nw, ifp); dump_iface_caps(nw, ifp); + if (include_vf_status && + !dump_vf_status(nw, vf_status, vf_error)) + goto enomem; nlattr_set_len(nw, off); } @@ -368,11 +634,14 @@ dump_iface(struct nl_writer *nw, if_t ifp, const struct nlmsghdr *hdr, nw->ifp = ifp; - if (nlmsg_end(nw)) + if (nlmsg_end(nw)) { + nvlist_destroy(vf_status); return (true); + } enomem: - NL_LOG(LOG_DEBUG, "unable to dump interface %s state (ENOMEM)", if_name(ifp)); + nvlist_destroy(vf_status); + NL_LOG(LOG_DEBUG, "unable to dump interface %s state", if_name(ifp)); nlmsg_abort(nw); return (false); } @@ -415,6 +684,7 @@ static const struct nlattr_parser nla_p_if[] = { { .type = IFLA_LINKINFO, .arg = &linfo_parser, .cb = nlattr_get_nested }, { .type = IFLA_IFALIAS, .off = _OUT(ifla_ifalias), .cb = nlattr_get_string }, { .type = IFLA_GROUP, .off = _OUT(ifla_group), .cb = nlattr_get_string }, + { .type = IFLA_EXT_MASK, .off = _OUT(ifla_ext_mask), .cb = nlattr_get_uint32 }, { .type = IFLA_ALT_IFNAME, .off = _OUT(ifla_ifname), .cb = nlattr_get_string }, }; #undef _IN @@ -441,7 +711,7 @@ static int dump_cb(if_t ifp, void *_arg) { struct netlink_walkargs *wa = (struct netlink_walkargs *)_arg; - if (!dump_iface(wa->nw, ifp, &wa->hdr, 0, NULL)) + if (!dump_iface(wa->nw, ifp, &wa->hdr, 0, NULL, wa->ext_mask)) return (ENOMEM); return (0); } @@ -473,6 +743,7 @@ rtnl_handle_getlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *n .hdr.nlmsg_seq = hdr->nlmsg_seq, .hdr.nlmsg_flags = hdr->nlmsg_flags, .hdr.nlmsg_type = NL_RTM_NEWLINK, + .ext_mask = attrs.ifla_ext_mask, }; /* Fast track for an interface w/ explicit name or index match */ @@ -491,7 +762,8 @@ rtnl_handle_getlink(struct nlmsghdr *hdr, struct nlpcb *nlp, struct nl_pstate *n if (ifp != NULL) { if (match_iface(ifp, &attrs)) { - if (!dump_iface(wa.nw, ifp, &wa.hdr, 0, NULL)) + if (!dump_iface(wa.nw, ifp, &wa.hdr, 0, NULL, + wa.ext_mask)) error = ENOMEM; } else error = ENODEV; @@ -1418,7 +1690,7 @@ rtnl_handle_ifevent(if_t ifp, int nlmsg_type, int if_flags_mask, NL_LOG(LOG_DEBUG, "error allocating group writer"); return; } - dump_iface(&nw, ifp, &hdr, if_flags_mask, ifname); + dump_iface(&nw, ifp, &hdr, if_flags_mask, ifname, 0); nlmsg_flush(&nw); } diff --git a/sys/netlink/route/interface.h b/sys/netlink/route/interface.h index c018a0adb20d..66bab24067df 100644 --- a/sys/netlink/route/interface.h +++ b/sys/netlink/route/interface.h @@ -94,7 +94,7 @@ enum { #define IFLA_NET_NS_PID IFLA_NET_NS_PID IFLA_IFALIAS = 20, /* string: interface description */ #define IFLA_IFALIAS IFLA_IFALIAS - IFLA_NUM_VF = 21, /* not supported */ + IFLA_NUM_VF = 21, /* u32: active VFs, when requested */ #define IFLA_NUM_VF IFLA_NUM_VF IFLA_VFINFO_LIST= 22, /* not supported */ #define IFLA_VFINFO_LIST IFLA_VFINFO_LIST @@ -147,15 +147,95 @@ enum { }; #define IFLA_MAX (__IFLA_MAX - 1) +/* IFLA_EXT_MASK values. */ +#define RTEXT_FILTER_VF (1U << 0) + 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_VF_STATUS = 4, /* nested, IFLAF_VFS_* */ __IFLAF_MAX }; #define IFLAF_MAX (__IFLAF_MAX - 1) +/* IFLAF_VF_STATUS attributes. */ +enum { + IFLAF_VFS_UNSPEC = 0, + IFLAF_VFS_VERSION = 1, /* u32: IFVF_STATUS_VERSION */ + IFLAF_VFS_ERROR = 2, /* u32: errno from requested query */ + IFLAF_VFS_PF_LINK_STATE = 3, /* u8: IFLAF_VF_LINK_* */ + IFLAF_VFS_PF_LINK_SPEED = 4, /* u64: bits per second */ + IFLAF_VFS_LIST = 5, /* nested, IFLAF_VF_LIST_* */ + __IFLAF_VFS_MAX +}; +#define IFLAF_VFS_MAX (__IFLAF_VFS_MAX - 1) + +/* IFLAF_VFS_LIST attributes. */ +enum { + IFLAF_VF_LIST_UNSPEC = 0, + IFLAF_VF_LIST_ENTRY = 1, /* nested, IFLAF_VF_*; repeated */ + __IFLAF_VF_LIST_MAX +}; +#define IFLAF_VF_LIST_MAX (__IFLAF_VF_LIST_MAX - 1) + +/* IFLAF_VF_LIST_ENTRY attributes. */ +enum { + IFLAF_VF_UNSPEC = 0, + IFLAF_VF_INDEX = 1, /* u32 */ + IFLAF_VF_CONFIGURED = 2, /* u8 boolean */ + IFLAF_VF_INITIALIZED = 3, /* u8 boolean */ + IFLAF_VF_MAC = 4, /* binary */ + IFLAF_VF_VLAN_MODE = 5, /* u8: IFLAF_VF_VLAN_* */ + IFLAF_VF_VLAN = 6, /* u16 */ + IFLAF_VF_VLAN_COUNT = 7, /* u32 */ + IFLAF_VF_VLAN_LIMIT = 8, /* u32 */ + IFLAF_VF_NUM_QUEUES = 9, /* u32 */ + IFLAF_VF_ALLOW_SET_MAC = 10, /* u8 boolean */ + IFLAF_VF_ALLOW_SET_VLAN = 11, /* u8 boolean */ + IFLAF_VF_MAC_ANTI_SPOOF = 12, /* u8 boolean */ + IFLAF_VF_ALLOW_PROMISC = 13, /* u8 boolean */ + IFLAF_VF_TRAFFIC_ENABLED = 14, /* u8 boolean */ + IFLAF_VF_MDD_BLOCKED = 15, /* u8 boolean */ + IFLAF_VF_QUARANTINED = 16, /* u8 boolean */ + IFLAF_VF_API_VERSION = 17, /* string */ + IFLAF_VF_LINK_STATE_POLICY = 18, /* u8: IFLAF_VF_LINK_* */ + IFLAF_VF_EXTENSIONS = 19, /* nested, IFLAF_VF_EXT_LIST_* */ + __IFLAF_VF_MAX +}; +#define IFLAF_VF_MAX (__IFLAF_VF_MAX - 1) + +/* IFLAF_VF_EXTENSIONS attributes. */ +enum { + IFLAF_VF_EXT_LIST_UNSPEC = 0, + IFLAF_VF_EXT_LIST_ENTRY = 1, /* nested; repeated */ + __IFLAF_VF_EXT_LIST_MAX +}; +#define IFLAF_VF_EXT_LIST_MAX (__IFLAF_VF_EXT_LIST_MAX - 1) + +/* IFLAF_VF_EXT_LIST_ENTRY attributes. */ +enum { + IFLAF_VF_EXT_UNSPEC = 0, + IFLAF_VF_EXT_NAME = 1, /* string: stable namespace */ + IFLAF_VF_EXT_DATA = 2, /* binary: packed namespace nvlist */ + __IFLAF_VF_EXT_MAX +}; +#define IFLAF_VF_EXT_MAX (__IFLAF_VF_EXT_MAX - 1) + +enum { + IFLAF_VF_LINK_UNKNOWN = 0, + IFLAF_VF_LINK_DOWN = 1, + IFLAF_VF_LINK_UP = 2, + IFLAF_VF_LINK_AUTO = 3, +}; + +enum { + IFLAF_VF_VLAN_UNKNOWN = 0, + IFLAF_VF_VLAN_ACCESS = 1, + IFLAF_VF_VLAN_TRUNK = 2, +}; + /* * Attributes that can be used as filters: * IFLA_IFNAME, IFLA_GROUP, IFLA_ALT_IFNAME diff --git a/sys/netlink/route/route_var.h b/sys/netlink/route/route_var.h index 012dc5ad0594..23adf012733f 100644 --- a/sys/netlink/route/route_var.h +++ b/sys/netlink/route/route_var.h @@ -74,6 +74,7 @@ struct nl_parsed_link { int ifi_index; uint32_t ifla_link; uint32_t ifla_mtu; + uint32_t ifla_ext_mask; uint32_t ifi_flags; uint32_t ifi_change; }; diff --git a/tests/atf_python/sys/netlink/attrs.py b/tests/atf_python/sys/netlink/attrs.py index 36dd8191df1c..b0e03e50258e 100644 --- a/tests/atf_python/sys/netlink/attrs.py +++ b/tests/atf_python/sys/netlink/attrs.py @@ -137,6 +137,34 @@ class NlAttrU32(NlAttr): return self._to_bytes(struct.pack("@I", self.u32)) +class NlAttrU64(NlAttr): + def __init__(self, nla_type, val): + self.u64 = enum_or_int(val) + super().__init__(nla_type, b"") + + @property + def nla_len(self): + return 12 + + def _print_attr_value(self): + return " val={}".format(self.u64) + + @staticmethod + def _validate(data): + assert len(data) == 12 + nla_len, nla_type = struct.unpack("@HH", data[:4]) + assert nla_len == 12 + + @classmethod + def _parse(cls, data): + nla_len, nla_type = struct.unpack("@HH", data[:4]) + val = struct.unpack("@Q", data[4:])[0] + return cls(nla_type, val) + + def __bytes__(self): + return self._to_bytes(struct.pack("@Q", self.u64)) + + class NlAttrS32(NlAttr): def __init__(self, nla_type, val): self.s32 = enum_or_int(val) diff --git a/tests/atf_python/sys/netlink/netlink_route.py b/tests/atf_python/sys/netlink/netlink_route.py index 2cfeb57da13f..d6edc6ad875d 100644 --- a/tests/atf_python/sys/netlink/netlink_route.py +++ b/tests/atf_python/sys/netlink/netlink_route.py @@ -13,7 +13,9 @@ from atf_python.sys.netlink.attrs import NlAttr from atf_python.sys.netlink.attrs import NlAttrIp from atf_python.sys.netlink.attrs import NlAttrNested from atf_python.sys.netlink.attrs import NlAttrStr +from atf_python.sys.netlink.attrs import NlAttrU16 from atf_python.sys.netlink.attrs import NlAttrU32 +from atf_python.sys.netlink.attrs import NlAttrU64 from atf_python.sys.netlink.attrs import NlAttrU8 from atf_python.sys.netlink.message import StdNetlinkMessage from atf_python.sys.netlink.message import NlMsgProps @@ -361,6 +363,56 @@ class IflafAttrType(Enum): IFLAF_UNSPEC = 0 IFLAF_ORIG_IFNAME = 1 IFLAF_ORIG_HWADDR = 2 + IFLAF_CAPS = 3 + IFLAF_VF_STATUS = 4 + + +class IflafVfStatusType(Enum): + IFLAF_VFS_UNSPEC = 0 + IFLAF_VFS_VERSION = 1 + IFLAF_VFS_ERROR = 2 + IFLAF_VFS_PF_LINK_STATE = 3 + IFLAF_VFS_PF_LINK_SPEED = 4 + IFLAF_VFS_LIST = 5 + + +class IflafVfListType(Enum): + IFLAF_VF_LIST_UNSPEC = 0 + IFLAF_VF_LIST_ENTRY = 1 + + +class IflafVfType(Enum): + IFLAF_VF_UNSPEC = 0 + IFLAF_VF_INDEX = 1 + IFLAF_VF_CONFIGURED = 2 + IFLAF_VF_INITIALIZED = 3 + IFLAF_VF_MAC = 4 + IFLAF_VF_VLAN_MODE = 5 + IFLAF_VF_VLAN = 6 + IFLAF_VF_VLAN_COUNT = 7 + IFLAF_VF_VLAN_LIMIT = 8 + IFLAF_VF_NUM_QUEUES = 9 + IFLAF_VF_ALLOW_SET_MAC = 10 + IFLAF_VF_ALLOW_SET_VLAN = 11 + IFLAF_VF_MAC_ANTI_SPOOF = 12 + IFLAF_VF_ALLOW_PROMISC = 13 + IFLAF_VF_TRAFFIC_ENABLED = 14 + IFLAF_VF_MDD_BLOCKED = 15 + IFLAF_VF_QUARANTINED = 16 + IFLAF_VF_API_VERSION = 17 + IFLAF_VF_LINK_STATE_POLICY = 18 + IFLAF_VF_EXTENSIONS = 19 + + +class IflafVfExtListType(Enum): + IFLAF_VF_EXT_LIST_UNSPEC = 0 + IFLAF_VF_EXT_LIST_ENTRY = 1 + + +class IflafVfExtType(Enum): + IFLAF_VF_EXT_UNSPEC = 0 + IFLAF_VF_EXT_NAME = 1 + IFLAF_VF_EXT_DATA = 2 class IflinkInfo(Enum): @@ -621,6 +673,65 @@ rtnl_route_attrs = prepare_attrs_map( ] ) +rtnl_iflaf_vf_ext_attrs = [ + AttrDescr(IflafVfExtType.IFLAF_VF_EXT_NAME, NlAttrStr), + AttrDescr(IflafVfExtType.IFLAF_VF_EXT_DATA, NlAttr), +] + +rtnl_iflaf_vf_ext_list_attrs = [ + AttrDescr( + IflafVfExtListType.IFLAF_VF_EXT_LIST_ENTRY, + NlAttrNested, + rtnl_iflaf_vf_ext_attrs, + ), +] + +rtnl_iflaf_vf_attrs = [ + AttrDescr(IflafVfType.IFLAF_VF_INDEX, NlAttrU32), + AttrDescr(IflafVfType.IFLAF_VF_CONFIGURED, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_INITIALIZED, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_MAC, NlAttrMac), + AttrDescr(IflafVfType.IFLAF_VF_VLAN_MODE, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_VLAN, NlAttrU16), + AttrDescr(IflafVfType.IFLAF_VF_VLAN_COUNT, NlAttrU32), + AttrDescr(IflafVfType.IFLAF_VF_VLAN_LIMIT, NlAttrU32), + AttrDescr(IflafVfType.IFLAF_VF_NUM_QUEUES, NlAttrU32), + AttrDescr(IflafVfType.IFLAF_VF_ALLOW_SET_MAC, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_ALLOW_SET_VLAN, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_MAC_ANTI_SPOOF, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_ALLOW_PROMISC, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_TRAFFIC_ENABLED, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_MDD_BLOCKED, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_QUARANTINED, NlAttrU8), + AttrDescr(IflafVfType.IFLAF_VF_API_VERSION, NlAttrStr), + AttrDescr(IflafVfType.IFLAF_VF_LINK_STATE_POLICY, NlAttrU8), + AttrDescr( + IflafVfType.IFLAF_VF_EXTENSIONS, + NlAttrNested, + rtnl_iflaf_vf_ext_list_attrs, + ), +] + +rtnl_iflaf_vf_list_attrs = [ + AttrDescr( + IflafVfListType.IFLAF_VF_LIST_ENTRY, + NlAttrNested, + rtnl_iflaf_vf_attrs, *** 195 LINES SKIPPED ***