Re: git: d15f2551b25f - main - rtnetlink: Report SR-IOV VF status
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 10 Aug 2026 19:50:44 UTC
On 8/10/26 22:56, Kevin Bowling wrote:
> On Mon, Aug 10, 2026 at 12:18 PM Pouria Mousavizadeh Tehrani
> <pouria@freebsd.org> wrote:
>>
>> Hi
>>
>> On 8/9/26 10:17, Kevin Bowling wrote:
>>> The branch main has been updated by kbowling:
>>>
>>> URL: https://cgit.FreeBSD.org/src/commit/?id=d15f2551b25f79ddcbe289faa95e655100b952da
>>>
>>> commit d15f2551b25f79ddcbe289faa95e655100b952da
>>> Author: Kevin Bowling <kbowling@FreeBSD.org>
>>> AuthorDate: 2026-08-09 02:04:11 +0000
>>> Commit: Kevin Bowling <kbowling@FreeBSD.org>
>>> 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_<NEW|DEL|GET>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 <sys/kernel.h>
>>> #include <sys/jail.h>
>>> #include <sys/malloc.h>
>>> +#include <sys/nv.h>
>>> #include <sys/socket.h>
>>> #include <sys/sockio.h>
>>> #include <sys/syslog.h>
>>> @@ -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 ***
>>>
>>
>> I think we should minimize our use of nvlist(9) in the new code,
>> especially under netlink.
>> IMO, Using nvlist under netlink defeats the purpose.
>
> Hi,
>
> Is there a better way to do something like this
> https://reviews.freebsd.org/D58739#change-0sX8k3Z9eTKs?
I see, I had the same problem on geneve implementation.
I asked on the mailing list and kp@ gave me some advice on it.
See this thread:
https://mail-archive.freebsd.org/cgi/getmsg.cgi?fetch=270856+0+archive/2025/freebsd-net/20251020.freebsd-net
Somehow, I managed to implement it directly with netlink:
https://reviews.freebsd.org/D54172?vs=174551&id=175142#toc
Hope it helps!
>> looI don't think snl_attr_get_parray is appropriate for parser-only
>> attributes.
>> We should use multi-attr instead to avoid too many nested netlink
>> attributes. (e.g. /* nested, IFLAF_VF_*; repeated */)
>> https://docs.kernel.org/userspace-api/netlink/genetlink-legacy.html
>>
>> We might also want to use snl_attr_get_bool or snl_attr_get_flag for
>> many of the data structures above.
>>
>> I wish there were a phabricator review for this change.
>>
>> --
>> Pouria
>>
>
--
Pouria