On Mon, Aug 10, 2026 at 12:18 PM Pouria Mousavizadeh Tehrani <[email protected]> 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 <[email protected]> > > AuthorDate: 2026-08-09 02:04:11 +0000 > > Commit: Kevin Bowling <[email protected]> > > 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? > 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 >
