From nobody Mon Aug 10 20:15:55 2026 X-Original-To: dev-commits-src-main@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 4hJmGy3HfHz6jtKV for ; Mon, 10 Aug 2026 20:16:10 +0000 (UTC) (envelope-from kevin.bowling@kev009.com) Received: from mail-qk1-x732.google.com (mail-qk1-x732.google.com [IPv6:2607:f8b0:4864:20::732]) (using TLSv1.3 with cipher TLS_AES_128_GCM_SHA256 (128/128 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256 client-signature RSA-PSS (2048 bits) client-digest SHA256) (Client CN "smtp.gmail.com", Issuer "WR4" (verified OK)) by mx1.freebsd.org (Postfix) with ESMTPS id 4hJmGx6Ck7z3P36 for ; Mon, 10 Aug 2026 20:16:09 +0000 (UTC) (envelope-from kevin.bowling@kev009.com) Authentication-Results: mx1.freebsd.org; none Received: by mail-qk1-x732.google.com with SMTP id af79cd13be357-92e6391b114so172062685a.3 for ; Mon, 10 Aug 2026 13:16:09 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1786392968; cv=none; d=google.com; s=arc-20260327; b=TbegERpHKtIZvEzWm2CkXmTOX7O5zLWnMcvfda0LS300Z4i9ziYXkuGnA5OdfbFXbG I98+wpFCjECehcfyKqwcAKIQBH0b7GojJawEn9wfyFk09xtvfp225OjQGOPaM7DHfXSS chNz/UnB+/x0OSSEMSMaC6QCDpH18n9DaS22JMyWQm2OPgv7cOKiaatn4EILb0LS2ql7 T1OGIK8AGcv5yD/4EewSwdD3/HhaendwivUQ3dXcl85KqJ45VM5ckBiFvs2gsvU6xzCB KvbvWCpEdAU5qYmdVFb10ZDrjvgDKR2CfUiv75X5w/zAg7+lGYGCNcODPIyqDTDX0VVy p72w== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=content-transfer-encoding:cc:to:subject:message-id:date:from :in-reply-to:references:mime-version:dkim-signature; bh=yqj2FjDCI3VrWgJxxYVf/wS9/gPWGz6FtJeGZCbnD5U=; fh=E2KH7jzGd47fa8deOeiV/QIhtygCCcXZZiUEihCJhUs=; b=UAedN3TI7N8+Ez2bpyTLwyuSe0Fb88HhF6HUoSaDcqOKINodr/ZERSV1NA52bJle+P 9l4JEAjW+1el+NCC0cgTb8YCekVrB1hN6BvQgc53awm5cvMlw/c9Sn5wiXarh4oCoJbw br1zK4V6J0lfsTSdgo+e7qC7rbihluWMgrFpqRSlgWsM7TYdxxVSImXzLdwTRvCjlfc3 j8jH4er0LsFTniWNrpK7kOJcMzT5gvSVD0qjCduY/20vgzVFW01PHOfQ5U71c9jUv0e4 I7NNEEOlBP6cU/o7+igGPJ2OtbHOVOBBXIQmX0nwSKlRcHobnJvxDASx7UuLo+EM7Wjq 8+NA==; darn=freebsd.org ARC-Authentication-Results: i=1; mx.google.com; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kev009.com; s=google; t=1786392968; x=1786997768; darn=freebsd.org; h=content-transfer-encoding:content-type:cc:to:subject:message-id :date:from:in-reply-to:references:mime-version:from:to:cc:subject :date:message-id:reply-to:content-type; bh=yqj2FjDCI3VrWgJxxYVf/wS9/gPWGz6FtJeGZCbnD5U=; b=F4eS2vmK3iI63fS1Gc8+RPTzEQlXKXrdNaB61ocSObM/XFOZvAXhJzhCt96FocEl7y lwh1YqOIh/qTyUKPDA6RbQvj0dGKxMAPOBBI5ua5t6wcO2jhESJHFmsG8/dboTKdMwQk t7XNo5RVDncRUvt7K/oXILuY2NrGNeH8oxIt8= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20251104; t=1786392968; x=1786997768; h=content-transfer-encoding:content-type:cc:to:subject:message-id :date:from:in-reply-to:references:mime-version:x-gm-gg :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to :content-type; bh=yqj2FjDCI3VrWgJxxYVf/wS9/gPWGz6FtJeGZCbnD5U=; b=BojXlwFfR31OV99QkpUe48fzf1kh8tGQzYkcTzCjaNQ/Lk0eHhT9T2vLUu2erEjQmU vuIR25/KSr3aFALwSNgyoOLcz5+B3C+QATmgG5ig7+wAZdWUZG9tNLzlX26W8R1QtVZR uu/OG9i8D9aTKGq7JC1f8llWRmoDMLrnhXG1mR4ntHUOIGwnk6MDvB16NNsvus4/zRtV Wa+BAMa6AZej4pg0FmlxT1eLuWj/sxjSfptvXjG/c4ypD5b0wGun0JyY8zcDmjROGljb Rmw7ZJWWOimnKAzkH/MxkDQYfkSkNt+yz7llJg9PgnmB7/CMh3RRQJ3mxCXlsHenkYX+ FNlQ== X-Forwarded-Encrypted: i=1; AHgh+Rr5WbbBFDl2x7KCGPx/BDGH4624RgQi1Rj7GlKi1uZJ2tWkKYBZWg1IOfCVtdoulvnh4zIL3MRj/qDbNvIWxslUgicyZA==@freebsd.org X-Gm-Message-State: AOJu0YyYSb/rxzNcVq5vbnMNuJSbhgd+m4HGOAkeVYuJtlbXO9OI5QIR gSNl3qW+gWOVfQ850VmXdtkMfv5ld9FZFHvpCrW2WmARJgNQHjNwRNHybltwYjR7aMrrddNmxtg XtpdWXaQeWBX3i8PtMcY5WwMLasKfch1oeQyokOra X-Gm-Gg: AR+sD114olEvfTlJse/PgO7c0ZKIRR2m6+8u8nmdHlUjQFq5Z+sYjUOxlzKY0iGemvv EtbGT9+MsqSfEmIs68w4Ivntg64yIa9EOmF+AMkuodnSDTriL4A+UaU7VNnaPpbozvrvovGh+jl DJcqqY07NEb7BztpWCkWq93+y5BGgSZIA1xAPThQgDWmEMqQI1+NTuE75JNUsKE99O0RANQ7ddf enGiMksN3niM4HtfC3X2+CDGPuZMvyJd0FpzoH4cjwUJkVoZb9JXX95ZqWYz60MqGDcZwbRouwH OyP3EEBJh0DpawYXx4E0/W+ivga45Z20RPcOuBOCLOsV1pvh7U3OQzRSSWsWJ51wDjxCFcjceQ+ A/qOeI15UeToCntaXp4V2IlRYV2i85QlcUNRt6a6sFu1wAm5ZYq605h/1pSeSeJ3hqAq2QvHOtG 4QzKkBODIl0w== X-Received: by 2002:a05:622a:2595:b0:51c:2068:a9f8 with SMTP id d75a77b69052e-52d0b00401emr392940051cf.5.1786392967312; Mon, 10 Aug 2026 13:16:07 -0700 (PDT) List-Id: Commit messages for the main branch of the src repository List-Archive: https://lists.freebsd.org/archives/dev-commits-src-main List-Help: List-Post: List-Subscribe: List-Unsubscribe: X-BeenThere: dev-commits-src-main@freebsd.org Sender: owner-dev-commits-src-main@FreeBSD.org List-Id: List-Post: List-Help: List-Subscribe: List-Unsubscribe: List-Owner: Precedence: list MIME-Version: 1.0 References: <6a782294.3e4e1.77fae9fb@gitrepo.freebsd.org> <41b8cda3-9e4f-49f1-af9b-18c04e215ab1@FreeBSD.org> <4a403b6d-e725-48de-accb-4ef89a18d55c@FreeBSD.org> In-Reply-To: <4a403b6d-e725-48de-accb-4ef89a18d55c@FreeBSD.org> From: Kevin Bowling Date: Mon, 10 Aug 2026 13:15:55 -0700 X-Gm-Features: AUfX_mx9gR0C7s4u3gaBYHqnPORZzjH3k3RHNdIy8B_WMML25Lo_f75WtYGnMK0 Message-ID: Subject: Re: git: d15f2551b25f - main - rtnetlink: Report SR-IOV VF status To: Pouria Mousavizadeh Tehrani Cc: Kevin Bowling , dev-commits-src-main@freebsd.org, src-committers@freebsd.org, dev-commits-src-all@freebsd.org Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Rspamd-Queue-Id: 4hJmGx6Ck7z3P36 X-Rspamd-Pre-Result: action=no action; module=replies; Message is reply to one we originated X-Spamd-Result: default: False [-4.00 / 15.00]; REPLY(-4.00)[]; ASN(0.00)[asn:15169, ipnet:2607:f8b0::/32, country:US] X-Spamd-Bar: ---- On Mon, Aug 10, 2026 at 12:52=E2=80=AFPM Pouria Mousavizadeh Tehrani wrote: > > On 8/10/26 22:56, Kevin Bowling wrote: > > On Mon, Aug 10, 2026 at 12:18=E2=80=AFPM Pouria Mousavizadeh Tehrani > > 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=3Dd15f2551b25f79ddcbe289= faa95e655100b952da > >>> > >>> 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 ve= rsioned > >>> SR-IOV VF status through typed nested FreeBSD attributes. Repo= rt > >>> 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 packe= d > >>> versioned nvlists so adding a driver-specific field does not ex= pand the > >>> common netlink ABI. > >>> > >>> Add SNL parsers, parser verification, a constructed nested-stat= us 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 POSSIB= ILITY 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 kern= el: > >>> 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 th= e 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 identifi= er > >>> +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 permis= sion > >>> +IFLAF_VF_ALLOW_SET_VLAN (uint8_t) administrative permis= sion > >>> +IFLAF_VF_MAC_ANTI_SPOOF (uint8_t) MAC anti-spoofing ena= bled > >>> +IFLAF_VF_ALLOW_PROMISC (uint8_t) administrative permis= sion > >>> +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 it= s last > >>> +reset. > >>> +.Pp > >>> +.Dv IFLAF_VF_NUM_QUEUES > >>> +is the number of allocated symmetric RX/TX queue pairs, not necessar= ily 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 unt= agged and > >>> +priority-tag membership. > >>> +The permission attributes describe requests the VF may make, not req= uests 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/ne= tlink_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, si= zeof(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[] =3D { > >>> + { .type =3D IFLAF_VF_EXT_NAME, .off =3D _OUT(name), > >>> + .cb =3D snl_attr_dup_string }, > >>> + { .type =3D IFLAF_VF_EXT_DATA, .off =3D _OUT(data), > >>> + .cb =3D 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[] =3D { > >>> + { .type =3D IFLAF_VF_INDEX, .off =3D _OUT(index), > >>> + .cb =3D snl_attr_get_uint32 }, > >>> + { .type =3D IFLAF_VF_CONFIGURED, .off =3D _OUT(configured), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_INITIALIZED, .off =3D _OUT(initialized), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_MAC, .off =3D _OUT(mac), .cb =3D snl_attr_= dup_nla }, > >>> + { .type =3D IFLAF_VF_VLAN_MODE, .off =3D _OUT(vlan_mode), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_VLAN, .off =3D _OUT(vlan), > >>> + .cb =3D snl_attr_get_uint16 }, > >>> + { .type =3D IFLAF_VF_VLAN_COUNT, .off =3D _OUT(vlan_count), > >>> + .cb =3D snl_attr_get_uint32 }, > >>> + { .type =3D IFLAF_VF_VLAN_LIMIT, .off =3D _OUT(vlan_limit), > >>> + .cb =3D snl_attr_get_uint32 }, > >>> + { .type =3D IFLAF_VF_NUM_QUEUES, .off =3D _OUT(num_queues), > >>> + .cb =3D snl_attr_get_uint32 }, > >>> + { .type =3D IFLAF_VF_ALLOW_SET_MAC, .off =3D _OUT(allow_set_mac= ), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_ALLOW_SET_VLAN, .off =3D _OUT(allow_set_vl= an), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_MAC_ANTI_SPOOF, .off =3D _OUT(mac_anti_spo= of), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_ALLOW_PROMISC, .off =3D _OUT(allow_promisc= ), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_TRAFFIC_ENABLED, .off =3D _OUT(traffic_ena= bled), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_MDD_BLOCKED, .off =3D _OUT(mdd_blocked), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_QUARANTINED, .off =3D _OUT(quarantined), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VF_API_VERSION, .off =3D _OUT(api_version), > >>> + .cb =3D snl_attr_dup_string }, > >>> + { .type =3D IFLAF_VF_LINK_STATE_POLICY, > >>> + .off =3D _OUT(link_state_policy), .cb =3D snl_attr_get_uint= 8 }, > >>> + { .type =3D IFLAF_VF_EXTENSIONS, .off =3D _OUT(extensions), > >>> + .arg =3D &_vf_extension_parser, .cb =3D 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[] =3D { > >>> + { .type =3D IFLAF_VFS_VERSION, .off =3D _OUT(version), > >>> + .cb =3D snl_attr_get_uint32 }, > >>> + { .type =3D IFLAF_VFS_ERROR, .off =3D _OUT(error), > >>> + .cb =3D snl_attr_get_uint32 }, > >>> + { .type =3D IFLAF_VFS_PF_LINK_STATE, .off =3D _OUT(pf_link_stat= e), > >>> + .cb =3D snl_attr_get_uint8 }, > >>> + { .type =3D IFLAF_VFS_PF_LINK_SPEED, .off =3D _OUT(pf_link_spee= d), > >>> + .cb =3D snl_attr_get_uint64 }, > >>> + { .type =3D IFLAF_VFS_LIST, .off =3D _OUT(vfs), > >>> + .arg =3D &_vf_parser, .cb =3D 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[] =3D { > >>> { .type =3D IFLAF_ORIG_HWADDR, .off =3D _OUT(iflaf_orig_hwaddr= ), .cb =3D snl_attr_dup_nla }, > >>> { .type =3D IFLAF_CAPS, .off =3D _OUT(iflaf_caps), .cb =3D snl= _attr_get_bitset_c }, > >>> + { .type =3D IFLAF_VF_STATUS, .off =3D _OUT(iflaf_vf_status), > >>> + .arg =3D &_vf_status_parser, .cb =3D 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[]= =3D { > >>> { .type =3D IFLA_MTU, .off =3D _OUT(ifla_mtu), .cb =3D snl_att= r_get_uint32 }, > >>> { .type =3D IFLA_OPERSTATE, .off =3D _OUT(ifla_operstate), .cb= =3D snl_attr_get_uint8 }, > >>> { .type =3D IFLA_IFALIAS, .off =3D _OUT(ifla_ifalias), .cb =3D= snl_attr_dup_string }, > >>> + { .type =3D IFLA_NUM_VF, .off =3D _OUT(ifla_num_vf), .cb =3D sn= l_attr_get_uint32 }, > >>> { .type =3D IFLA_STATS64, .off =3D _OUT(ifla_stats64), .cb =3D= snl_attr_dup_struct }, > >>> { .type =3D IFLA_PROMISCUITY, .off =3D _OUT(ifla_promiscuity),= .cb =3D snl_attr_get_uint32 }, > >>> { .type =3D IFLA_CARRIER, .off =3D _OUT(ifla_carrier), .cb =3D= 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 if= net *ifp) > >>> return (true); > >>> } > >>> > >>> +static uint8_t > >>> +vf_link_state(const char *state) > >>> +{ > >>> + > >>> + if (strcmp(state, IFVF_LINK_STATE_DOWN) =3D=3D 0) > >>> + return (IFLAF_VF_LINK_DOWN); > >>> + if (strcmp(state, IFVF_LINK_STATE_UP) =3D=3D 0) > >>> + return (IFLAF_VF_LINK_UP); > >>> + if (strcmp(state, IFVF_LINK_STATE_AUTO) =3D=3D 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 *n= ame, > >>> + 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 *na= me, > >>> + uint16_t attr) > >>> +{ > >>> + uint64_t value; > >>> + > >>> + if (!nvlist_exists_number(vf, name)) > >>> + return (true); > >>> + value =3D 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 *na= me, > >>> + uint16_t attr) > >>> +{ > >>> + uint64_t value; > >>> + > >>> + if (!nvlist_exists_number(vf, name)) > >>> + return (true); > >>> + value =3D 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 =3D nvlist_get_nvlist(vf, IFVF_STATUS_EXTENSIONS); > >>> + extensions_off =3D nlattr_add_nested(nw, IFLAF_VF_EXTENSIONS); > >>> + if (extensions_off =3D=3D 0) > >>> + return (false); > >>> + cookie =3D NULL; > >>> + while ((name =3D nvlist_next(extensions, &type, &cookie)) !=3D = NULL) { > >>> + if (type !=3D NV_TYPE_NVLIST) > >>> + return (false); > >>> + extension =3D nvlist_get_nvlist(extensions, name); > >>> + if (!nvlist_exists_number(extension, > >>> + IFVF_STATUS_EXT_VERSION)) > >>> + return (false); > >>> + buf =3D nvlist_pack(extension, &buflen); > >>> + if (buf =3D=3D NULL) > >>> + return (false); > >>> + if (buflen > UINT16_MAX - sizeof(struct nlattr)) { > >>> + free(buf, M_NVLIST); > >>> + return (false); > >>> + } > >>> + entry_off =3D nlattr_add_nested(nw, > >>> + IFLAF_VF_EXT_LIST_ENTRY); > >>> + if (entry_off =3D=3D 0) { > >>> + free(buf, M_NVLIST); > >>> + return (false); > >>> + } > >>> + ok =3D 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 =3D nlattr_add_nested(nw, IFLAF_VF_LIST_ENTRY); > >>> + if (off =3D=3D 0) > >>> + return (false); > >>> + ok =3D 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 =3D 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 =3D nvlist_get_string(vf, IFVF_STATUS_VLAN_MODE); > >>> + if (strcmp(mode, IFVF_VLAN_MODE_ACCESS) =3D=3D 0) > >>> + vlan_mode =3D IFLAF_VF_VLAN_ACCESS; > >>> + else if (strcmp(mode, IFVF_VLAN_MODE_TRUNK) =3D=3D 0) > >>> + vlan_mode =3D IFLAF_VF_VLAN_TRUNK; > >>> + else > >>> + vlan_mode =3D IFLAF_VF_VLAN_UNKNOWN; > >>> + if (!nlattr_add_u8(nw, IFLAF_VF_VLAN_MODE, vlan_mode)) > >>> + return (false); > >>> + } > >>> + ok =3D 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 =3D 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 err= or) > >>> +{ > >>> + const nvlist_t * const *vfs; > >>> + const char *state; > >>> + size_t i, num_vfs; > >>> + uint64_t version; > >>> + int list_off, off; > >>> + > >>> + off =3D nlattr_add_nested(nw, IFLAF_VF_STATUS); > >>> + if (off =3D=3D 0) > >>> + return (false); > >>> + if (error !=3D 0) { > >>> + if (!nlattr_add_u32(nw, IFLAF_VFS_ERROR, (uint32_t)erro= r)) > >>> + return (false); > >>> + nlattr_set_len(nw, off); > >>> + return (true); > >>> + } > >>> + > >>> + if (!nvlist_exists_number(status, IFVF_STATUS_VERSION_KEY)) > >>> + return (false); > >>> + version =3D 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 =3D 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 =3D nvlist_get_nvlist_array(status, IFVF_STATUS_VFS, &num_v= fs); > >>> + list_off =3D nlattr_add_nested(nw, IFLAF_VFS_LIST); > >>> + if (list_off =3D=3D 0) > >>> + return (false); > >>> + for (i =3D 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 if= net *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(if= p)); > >>> + vf_status =3D NULL; > >>> + vf_error =3D 0; > >>> + include_vf_status =3D (ext_mask & RTEXT_FILTER_VF) !=3D 0; > >>> + if (include_vf_status) { > >>> + vf_error =3D if_get_vf_status(ifp, &vf_status); > >>> + if (vf_error =3D=3D EINVAL || vf_error =3D=3D ENOTTY || > >>> + vf_error =3D=3D ENXIO || vf_error =3D=3D ENOTSUP || > >>> + vf_error =3D=3D EOPNOTSUPP) > >>> + include_vf_status =3D 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 !=3D NULL && > >>> + nvlist_exists_nvlist_array(vf_status, IFVF_STATUS_VFS)) { > >>> + (void)nvlist_get_nvlist_array(vf_status, IFVF_STATUS_VF= S, > >>> + &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 !=3D 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, cons= t struct nlmsghdr *hdr, > >>> > >>> nw->ifp =3D 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[] =3D = { > >>> { .type =3D IFLA_LINKINFO, .arg =3D &linfo_parser, .cb =3D nla= ttr_get_nested }, > >>> { .type =3D IFLA_IFALIAS, .off =3D _OUT(ifla_ifalias), .cb =3D= nlattr_get_string }, > >>> { .type =3D IFLA_GROUP, .off =3D _OUT(ifla_group), .cb =3D nla= ttr_get_string }, > >>> + { .type =3D IFLA_EXT_MASK, .off =3D _OUT(ifla_ext_mask), .cb = =3D nlattr_get_uint32 }, > >>> { .type =3D IFLA_ALT_IFNAME, .off =3D _OUT(ifla_ifname), .cb = =3D nlattr_get_string }, > >>> }; > >>> #undef _IN > >>> @@ -441,7 +711,7 @@ static int > >>> dump_cb(if_t ifp, void *_arg) > >>> { > >>> struct netlink_walkargs *wa =3D (struct netlink_walkargs *)_ar= g; > >>> - 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 =3D hdr->nlmsg_seq, > >>> .hdr.nlmsg_flags =3D hdr->nlmsg_flags, > >>> .hdr.nlmsg_type =3D NL_RTM_NEWLINK, > >>> + .ext_mask =3D 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 !=3D 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 =3D ENOMEM; > >>> } else > >>> error =3D ENODEV; > >>> @@ -1418,7 +1690,7 @@ rtnl_handle_ifevent(if_t ifp, int nlmsg_type, i= nt 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/interf= ace.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 =3D 20, /* string: interface description */ > >>> #define IFLA_IFALIAS IFLA_IFALIAS > >>> - IFLA_NUM_VF =3D 21, /* not supported */ > >>> + IFLA_NUM_VF =3D 21, /* u32: active VFs, when requested */ > >>> #define IFLA_NUM_VF IFLA_NUM_VF > >>> IFLA_VFINFO_LIST=3D 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 =3D 0, > >>> IFLAF_ORIG_IFNAME =3D 1, /* string, original interfac= e name at creation */ > >>> IFLAF_ORIG_HWADDR =3D 2, /* binary, original hardware= address */ > >>> IFLAF_CAPS =3D 3, /* bitset, interface capabil= ities */ > >>> + IFLAF_VF_STATUS =3D 4, /* nested, IFLAF_VFS_* */ > >>> __IFLAF_MAX > >>> }; > >>> #define IFLAF_MAX (__IFLAF_MAX - 1) > >>> > >>> +/* IFLAF_VF_STATUS attributes. */ > >>> +enum { > >>> + IFLAF_VFS_UNSPEC =3D 0, > >>> + IFLAF_VFS_VERSION =3D 1, /* u32: IFVF_STATUS_VERSION *= / > >>> + IFLAF_VFS_ERROR =3D 2, /* u32: errno from requested = query */ > >>> + IFLAF_VFS_PF_LINK_STATE =3D 3, /* u8: IFLAF_VF_LINK_* */ > >>> + IFLAF_VFS_PF_LINK_SPEED =3D 4, /* u64: bits per second */ > >>> + IFLAF_VFS_LIST =3D 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 =3D 0, > >>> + IFLAF_VF_LIST_ENTRY =3D 1, /* nested, IFLAF_VF_*; repeat= ed */ > >>> + __IFLAF_VF_LIST_MAX > >>> +}; > >>> +#define IFLAF_VF_LIST_MAX (__IFLAF_VF_LIST_MAX - 1) > >>> + > >>> +/* IFLAF_VF_LIST_ENTRY attributes. */ > >>> +enum { > >>> + IFLAF_VF_UNSPEC =3D 0, > >>> + IFLAF_VF_INDEX =3D 1, /* u32 */ > >>> + IFLAF_VF_CONFIGURED =3D 2, /* u8 boolean */ > >>> + IFLAF_VF_INITIALIZED =3D 3, /* u8 boolean */ > >>> + IFLAF_VF_MAC =3D 4, /* binary */ > >>> + IFLAF_VF_VLAN_MODE =3D 5, /* u8: IFLAF_VF_VLAN_= * */ > >>> + IFLAF_VF_VLAN =3D 6, /* u16 */ > >>> + IFLAF_VF_VLAN_COUNT =3D 7, /* u32 */ > >>> + IFLAF_VF_VLAN_LIMIT =3D 8, /* u32 */ > >>> + IFLAF_VF_NUM_QUEUES =3D 9, /* u32 */ > >>> + IFLAF_VF_ALLOW_SET_MAC =3D 10, /* u8 boolean */ > >>> + IFLAF_VF_ALLOW_SET_VLAN =3D 11, /* u8 boolean */ > >>> + IFLAF_VF_MAC_ANTI_SPOOF =3D 12, /* u8 boolean */ > >>> + IFLAF_VF_ALLOW_PROMISC =3D 13, /* u8 boolean */ > >>> + IFLAF_VF_TRAFFIC_ENABLED =3D 14, /* u8 boolean */ > >>> + IFLAF_VF_MDD_BLOCKED =3D 15, /* u8 boolean */ > >>> + IFLAF_VF_QUARANTINED =3D 16, /* u8 boolean */ > >>> + IFLAF_VF_API_VERSION =3D 17, /* string */ > >>> + IFLAF_VF_LINK_STATE_POLICY =3D 18, /* u8: IFLAF_VF_LINK_= * */ > >>> + IFLAF_VF_EXTENSIONS =3D 19, /* nested, IFLAF_VF_E= XT_LIST_* */ > >>> + __IFLAF_VF_MAX > >>> +}; > >>> +#define IFLAF_VF_MAX (__IFLAF_VF_MAX - 1) > >>> + > >>> +/* IFLAF_VF_EXTENSIONS attributes. */ > >>> +enum { > >>> + IFLAF_VF_EXT_LIST_UNSPEC =3D 0, > >>> + IFLAF_VF_EXT_LIST_ENTRY =3D 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 =3D 0, > >>> + IFLAF_VF_EXT_NAME =3D 1, /* string: stable namespace *= / > >>> + IFLAF_VF_EXT_DATA =3D 2, /* binary: packed namespace n= vlist */ > >>> + __IFLAF_VF_EXT_MAX > >>> +}; > >>> +#define IFLAF_VF_EXT_MAX (__IFLAF_VF_EXT_MAX - 1) > >>> + > >>> +enum { > >>> + IFLAF_VF_LINK_UNKNOWN =3D 0, > >>> + IFLAF_VF_LINK_DOWN =3D 1, > >>> + IFLAF_VF_LINK_UP =3D 2, > >>> + IFLAF_VF_LINK_AUTO =3D 3, > >>> +}; > >>> + > >>> +enum { > >>> + IFLAF_VF_VLAN_UNKNOWN =3D 0, > >>> + IFLAF_VF_VLAN_ACCESS =3D 1, > >>> + IFLAF_VF_VLAN_TRUNK =3D 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 =3D enum_or_int(val) > >>> + super().__init__(nla_type, b"") > >>> + > >>> + @property > >>> + def nla_len(self): > >>> + return 12 > >>> + > >>> + def _print_attr_value(self): > >>> + return " val=3D{}".format(self.u64) > >>> + > >>> + @staticmethod > >>> + def _validate(data): > >>> + assert len(data) =3D=3D 12 > >>> + nla_len, nla_type =3D struct.unpack("@HH", data[:4]) > >>> + assert nla_len =3D=3D 12 > >>> + > >>> + @classmethod > >>> + def _parse(cls, data): > >>> + nla_len, nla_type =3D struct.unpack("@HH", data[:4]) > >>> + val =3D 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 =3D enum_or_int(val) > >>> diff --git a/tests/atf_python/sys/netlink/netlink_route.py b/tests/at= f_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 =3D 0 > >>> IFLAF_ORIG_IFNAME =3D 1 > >>> IFLAF_ORIG_HWADDR =3D 2 > >>> + IFLAF_CAPS =3D 3 > >>> + IFLAF_VF_STATUS =3D 4 > >>> + > >>> + > >>> +class IflafVfStatusType(Enum): > >>> + IFLAF_VFS_UNSPEC =3D 0 > >>> + IFLAF_VFS_VERSION =3D 1 > >>> + IFLAF_VFS_ERROR =3D 2 > >>> + IFLAF_VFS_PF_LINK_STATE =3D 3 > >>> + IFLAF_VFS_PF_LINK_SPEED =3D 4 > >>> + IFLAF_VFS_LIST =3D 5 > >>> + > >>> + > >>> +class IflafVfListType(Enum): > >>> + IFLAF_VF_LIST_UNSPEC =3D 0 > >>> + IFLAF_VF_LIST_ENTRY =3D 1 > >>> + > >>> + > >>> +class IflafVfType(Enum): > >>> + IFLAF_VF_UNSPEC =3D 0 > >>> + IFLAF_VF_INDEX =3D 1 > >>> + IFLAF_VF_CONFIGURED =3D 2 > >>> + IFLAF_VF_INITIALIZED =3D 3 > >>> + IFLAF_VF_MAC =3D 4 > >>> + IFLAF_VF_VLAN_MODE =3D 5 > >>> + IFLAF_VF_VLAN =3D 6 > >>> + IFLAF_VF_VLAN_COUNT =3D 7 > >>> + IFLAF_VF_VLAN_LIMIT =3D 8 > >>> + IFLAF_VF_NUM_QUEUES =3D 9 > >>> + IFLAF_VF_ALLOW_SET_MAC =3D 10 > >>> + IFLAF_VF_ALLOW_SET_VLAN =3D 11 > >>> + IFLAF_VF_MAC_ANTI_SPOOF =3D 12 > >>> + IFLAF_VF_ALLOW_PROMISC =3D 13 > >>> + IFLAF_VF_TRAFFIC_ENABLED =3D 14 > >>> + IFLAF_VF_MDD_BLOCKED =3D 15 > >>> + IFLAF_VF_QUARANTINED =3D 16 > >>> + IFLAF_VF_API_VERSION =3D 17 > >>> + IFLAF_VF_LINK_STATE_POLICY =3D 18 > >>> + IFLAF_VF_EXTENSIONS =3D 19 > >>> + > >>> + > >>> +class IflafVfExtListType(Enum): > >>> + IFLAF_VF_EXT_LIST_UNSPEC =3D 0 > >>> + IFLAF_VF_EXT_LIST_ENTRY =3D 1 > >>> + > >>> + > >>> +class IflafVfExtType(Enum): > >>> + IFLAF_VF_EXT_UNSPEC =3D 0 > >>> + IFLAF_VF_EXT_NAME =3D 1 > >>> + IFLAF_VF_EXT_DATA =3D 2 > >>> > >>> > >>> class IflinkInfo(Enum): > >>> @@ -621,6 +673,65 @@ rtnl_route_attrs =3D prepare_attrs_map( > >>> ] > >>> ) > >>> > >>> +rtnl_iflaf_vf_ext_attrs =3D [ > >>> + AttrDescr(IflafVfExtType.IFLAF_VF_EXT_NAME, NlAttrStr), > >>> + AttrDescr(IflafVfExtType.IFLAF_VF_EXT_DATA, NlAttr), > >>> +] > >>> + > >>> +rtnl_iflaf_vf_ext_list_attrs =3D [ > >>> + AttrDescr( > >>> + IflafVfExtListType.IFLAF_VF_EXT_LIST_ENTRY, > >>> + NlAttrNested, > >>> + rtnl_iflaf_vf_ext_attrs, > >>> + ), > >>> +] > >>> + > >>> +rtnl_iflaf_vf_attrs =3D [ > >>> + 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 =3D [ > >>> + 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=3D270856+0+archive/= 2025/freebsd-net/20251020.freebsd-net > > Somehow, I managed to implement it directly with netlink: > https://reviews.freebsd.org/D54172?vs=3D174551&id=3D175142#toc > > Hope it helps! I will ponder the links. I'm not sure if the anchor I sent works as intended on Phabricator, it was supposed to jump near "/* Render scalar extension fields without coupling ifconfig to a driver. */" The idea is to let the driver itself own whatever custom ontology (which could theoretically live in ports or some external package like Intel provides). > >> 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 >