From nobody Fri Apr 26 14:13:27 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=canonical.com Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1637255848469462.57397461322216; Thu, 18 Nov 2021 09:17:28 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-384-RZyPsFrmP4ypZNM874Hivg-1; Thu, 18 Nov 2021 12:17:25 -0500 Received: from smtp.corp.redhat.com (int-mx08.intmail.prod.int.phx2.redhat.com [10.5.11.23]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 721091808323; Thu, 18 Nov 2021 17:17:20 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.20]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0299C9324; Thu, 18 Nov 2021 17:17:20 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 9EA85180BAD1; Thu, 18 Nov 2021 17:17:18 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.rdu2.redhat.com [10.11.54.4]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 1AIHFUDk000766 for ; Thu, 18 Nov 2021 12:15:30 -0500 Received: by smtp.corp.redhat.com (Postfix) id 080CD2026D60; Thu, 18 Nov 2021 17:15:30 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast06.extmail.prod.ext.rdu2.redhat.com [10.11.55.22]) by smtp.corp.redhat.com (Postfix) with ESMTPS id F38F32026D67 for ; Thu, 18 Nov 2021 17:15:26 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [205.139.110.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id C5B2618A01A9 for ; Thu, 18 Nov 2021 17:15:26 +0000 (UTC) Received: from smtp-relay-internal-1.canonical.com (smtp-relay-internal-1.canonical.com [185.125.188.123]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-558-0JVGBlOLONi7MIHu9KzFWw-1; Thu, 18 Nov 2021 12:15:24 -0500 Received: from mail-lf1-f72.google.com (mail-lf1-f72.google.com [209.85.167.72]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 7069E4000A for ; Thu, 18 Nov 2021 17:15:23 +0000 (UTC) Received: by mail-lf1-f72.google.com with SMTP id i1-20020a056512318100b003ffd4e89eb9so4576141lfe.19 for ; Thu, 18 Nov 2021 09:15:23 -0800 (PST) Received: from ws.lan.d-node.is ([95.165.29.203]) by smtp.gmail.com with ESMTPSA id c6sm34499ljn.84.2021.11.18.09.15.21 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Nov 2021 09:15:22 -0800 (PST) X-MC-Unique: RZyPsFrmP4ypZNM874Hivg-1 X-MC-Unique: 0JVGBlOLONi7MIHu9KzFWw-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=S76JrF/u/bq4fhIagP6sqfchyWRhVXQsYQn/BWQf1VE=; b=iuAiNy4A67PrhtpCWPJ7fz3Z899LeeMMk+rB/42R0I7zyGL1KhpBGZi75Q6EjfHwR2 JwAqdB0eczMoLmBDQaFqdjWCW2NsxcgIzrxpsyZcc3Zn4e6kaUF25TsrQcFPOduolhuj 8kCr5NSevrRbrsEqlG87tv2EdQuFrenll8FENHeT8UY6Tl+/05XUi84Xl+0/fOqg6yrb sIr5+1WUc+Nctp6xhzNxllSI5HtFCjLc9P9k1NY5S1SxMdxVuSQg85AXvvp1p1u7gxGc bzKGe3Ms5KFPg35J/XidV9o3TiVh/tj+JdsPmDq8drGcUhxYpnirMOw/YA/3JphiFetA yeRw== X-Gm-Message-State: AOAM530zf2kfbeSQRHIV1+RxXq14e9avinJoY0VOCGhcWM7f5ZfIZmBo qWsZ0xmH2TBxbcPYXQBYB/KdbS+4lLndwWPccCSxFdLa4clnlIWSc/Tio1tVBgTNRowfCC2VMnc Eu4jR4+WNzsM+Xy5rrSwmnjpuhAAPDSKlmw== X-Received: by 2002:a05:6512:31ce:: with SMTP id j14mr25537462lfe.247.1637255722702; Thu, 18 Nov 2021 09:15:22 -0800 (PST) X-Google-Smtp-Source: ABdhPJzM96IHhKbdi3D6JdGuEALE20Zz7OJThVnB8/pPf6bm9RKJh83sthivQol9936zyf7HrOrBjA== X-Received: by 2002:a05:6512:31ce:: with SMTP id j14mr25537421lfe.247.1637255722321; Thu, 18 Nov 2021 09:15:22 -0800 (PST) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v6 1/3] Set VF MAC and VLAN ID in two different operations Date: Thu, 18 Nov 2021 20:15:18 +0300 Message-Id: <20211118171520.84703-2-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20211118171520.84703-1-dmitrii.shcherbakov@canonical.com> References: <20211118171520.84703-1-dmitrii.shcherbakov@canonical.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.78 on 10.11.54.4 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 1AIHFUDk000766 X-loop: libvir-list@redhat.com Cc: laine@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1637255850383100001 Content-Type: text/plain; charset="utf-8" This has a benefit of being able to handle error codes for those operations separately which is useful when drivers allow setting a MAC address but do not allow setting a VLAN (which is the case with some SmartNIC DPUs). Signed-off-by: Dmitrii Shcherbakov --- src/libvirt_private.syms | 7 ++ src/util/virnetdev.c | 188 ++++++++++++++++++++------------- src/util/virnetdevpriv.h | 44 ++++++++ tests/virnetdevtest.c | 222 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 388 insertions(+), 73 deletions(-) create mode 100644 src/util/virnetdevpriv.h diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index a7bc50a4d1..e681e69d77 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2849,6 +2849,13 @@ virNetDevOpenvswitchSetTimeout; virNetDevOpenvswitchUpdateVlan; =20 =20 +#util/virnetdevpriv.h +virNetDevSendVfSetLinkRequest; +virNetDevSetVfConfig; +virNetDevSetVfMac; +virNetDevSetVfVlan; + + # util/virnetdevtap.h virNetDevTapAttachBridge; virNetDevTapCreate; diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index 58f7360a0f..f2f5fa2d95 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -19,7 +19,9 @@ #include #include =20 -#include "virnetdev.h" +#define LIBVIRT_VIRNETDEVPRIV_H_ALLOW + +#include "virnetdevpriv.h" #include "viralloc.h" #include "virnetlink.h" #include "virmacaddr.h" @@ -1527,16 +1529,12 @@ static struct nla_policy ifla_vfstats_policy[IFLA_V= F_STATS_MAX+1] =3D { [IFLA_VF_STATS_MULTICAST] =3D { .type =3D NLA_U64 }, }; =20 - -static int -virNetDevSetVfConfig(const char *ifname, int vf, - const virMacAddr *macaddr, int vlanid, - bool *allowRetry) +int +virNetDevSendVfSetLinkRequest(const char *ifname, int vfInfoType, + const void *payload, const size_t payloadLen) { - int rc =3D -1; - char macstr[VIR_MAC_STRING_BUFLEN]; g_autofree struct nlmsghdr *resp =3D NULL; - struct nlmsgerr *err; + struct nlmsgerr *err =3D NULL; unsigned int recvbuflen =3D 0; struct nl_msg *nl_msg; struct nlattr *vfinfolist, *vfinfo; @@ -1544,9 +1542,11 @@ virNetDevSetVfConfig(const char *ifname, int vf, .ifi_family =3D AF_UNSPEC, .ifi_index =3D -1, }; + int rc =3D 0; =20 - if (!macaddr && vlanid < 0) + if (payload =3D=3D NULL || payloadLen =3D=3D 0) { return -1; + } =20 nl_msg =3D virNetlinkMsgNew(RTM_SETLINK, NLM_F_REQUEST); =20 @@ -1564,30 +1564,8 @@ virNetDevSetVfConfig(const char *ifname, int vf, if (!(vfinfo =3D nla_nest_start(nl_msg, IFLA_VF_INFO))) goto buffer_too_small; =20 - if (macaddr) { - struct ifla_vf_mac ifla_vf_mac =3D { - .vf =3D vf, - .mac =3D { 0, }, - }; - - virMacAddrGetRaw(macaddr, ifla_vf_mac.mac); - - if (nla_put(nl_msg, IFLA_VF_MAC, sizeof(ifla_vf_mac), - &ifla_vf_mac) < 0) - goto buffer_too_small; - } - - if (vlanid >=3D 0) { - struct ifla_vf_vlan ifla_vf_vlan =3D { - .vf =3D vf, - .vlan =3D vlanid, - .qos =3D 0, - }; - - if (nla_put(nl_msg, IFLA_VF_VLAN, sizeof(ifla_vf_vlan), - &ifla_vf_vlan) < 0) - goto buffer_too_small; - } + if (nla_put(nl_msg, vfInfoType, payloadLen, payload) < 0) + goto buffer_too_small; =20 nla_nest_end(nl_msg, vfinfo); nla_nest_end(nl_msg, vfinfolist); @@ -1600,48 +1578,20 @@ virNetDevSetVfConfig(const char *ifname, int vf, goto malformed_resp; =20 switch (resp->nlmsg_type) { - case NLMSG_ERROR: - err =3D (struct nlmsgerr *)NLMSG_DATA(resp); - if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) + case NLMSG_ERROR: + err =3D (struct nlmsgerr *)NLMSG_DATA(resp); + if (resp->nlmsg_len < NLMSG_LENGTH(sizeof(*err))) + goto malformed_resp; + rc =3D err->error; + break; + case NLMSG_DONE: + rc =3D 0; + break; + default: goto malformed_resp; - - /* if allowRetry is true and the error was EINVAL, then - * silently return a failure so the caller can retry with a - * different MAC address - */ - if (err->error =3D=3D -EINVAL && *allowRetry && - macaddr && !virMacAddrCmp(macaddr, &zeroMAC)) { - goto cleanup; - } else if (err->error) { - /* other errors are permanent */ - virReportSystemError(-err->error, - _("Cannot set interface MAC/vlanid to %s/= %d " - "for ifname %s vf %d"), - (macaddr - ? virMacAddrFormat(macaddr, macstr) - : "(unchanged)"), - vlanid, - ifname ? ifname : "(unspecified)", - vf); - *allowRetry =3D false; /* no use retrying */ - goto cleanup; - } - break; - - case NLMSG_DONE: - break; - - default: - goto malformed_resp; } =20 - rc =3D 0; cleanup: - VIR_DEBUG("RTM_SETLINK %s vf %d MAC=3D%s vlanid=3D%d - %s", - ifname, vf, - macaddr ? virMacAddrFormat(macaddr, macstr) : "(unchanged)", - vlanid, rc < 0 ? "Fail" : "Success"); - nlmsg_free(nl_msg); return rc; =20 @@ -1656,6 +1606,100 @@ virNetDevSetVfConfig(const char *ifname, int vf, goto cleanup; } =20 +int +virNetDevSetVfVlan(const char *ifname, int vf, int vlanid) +{ + int rc =3D 0; + int requestError =3D 0; + + struct ifla_vf_vlan ifla_vf_vlan =3D { + .vf =3D vf, + .vlan =3D vlanid, + .qos =3D 0, + }; + + /* VLAN ids 0 and 4095 are reserved per 802.1Q but are valid values. */ + if ((vlanid < 0 || vlanid > 4095)) { + return -ERANGE; + } + + requestError =3D virNetDevSendVfSetLinkRequest(ifname, IFLA_VF_VLAN, + &ifla_vf_vlan, sizeof(ifl= a_vf_vlan)); + + if (requestError) { + virReportSystemError(-requestError, + _("Cannot set interface vlanid to %d " + "for ifname %s vf %d"), + vlanid, ifname ? ifname : "(unspecified)", vf= ); + rc =3D requestError; + } + VIR_DEBUG("RTM_SETLINK %s vf %d vlanid=3D%d - %s", + ifname, vf, + vlanid, rc < 0 ? "Fail" : "Success"); + return rc; +} + +int +virNetDevSetVfMac(const char *ifname, int vf, + const virMacAddr *macaddr, + bool *allowRetry) +{ + int rc =3D 0; + int requestError =3D 0; + char macstr[VIR_MAC_STRING_BUFLEN]; + + struct ifla_vf_mac ifla_vf_mac =3D { + .vf =3D vf, + .mac =3D { 0, }, + }; + + if (macaddr =3D=3D NULL || allowRetry =3D=3D NULL) + return -EINVAL; + + virMacAddrGetRaw(macaddr, ifla_vf_mac.mac); + + requestError =3D virNetDevSendVfSetLinkRequest(ifname, IFLA_VF_MAC, + &ifla_vf_mac, sizeof(ifla= _vf_mac)); + /* if allowRetry is true and the error was EINVAL, then + * silently return a failure so the caller can retry with a + * different MAC address. */ + if (requestError =3D=3D -EINVAL && *allowRetry && !virMacAddrCmp(macad= dr, &zeroMAC)) { + rc =3D requestError; + } else if (requestError) { + /* other errors are permanent */ + virReportSystemError(-requestError, + _("Cannot set interface MAC to %s " + "for ifname %s vf %d"), + (macaddr + ? virMacAddrFormat(macaddr, macstr) + : "(unchanged)"), + ifname ? ifname : "(unspecified)", + vf); + *allowRetry =3D false; /* no use retrying */ + rc =3D requestError; + } else { + rc =3D 0; + } + VIR_DEBUG("RTM_SETLINK %s vf %d MAC=3D%s - %s", + ifname, vf, + macaddr ? virMacAddrFormat(macaddr, macstr) : "(unchanged)", + rc < 0 ? "Fail" : "Success"); + return rc; +} + +int +virNetDevSetVfConfig(const char *ifname, int vf, + const virMacAddr *macaddr, int vlanid, + bool *allowRetry) +{ + int rc =3D 0; + if ((rc =3D virNetDevSetVfMac(ifname, vf, macaddr, allowRetry)) < 0) + return rc; + if ((rc =3D virNetDevSetVfVlan(ifname, vf, vlanid)) < 0) + return rc; + return rc; +} + /** * virNetDevParseVfInfo: * Get the VF interface information from kernel by netlink, To make netlink diff --git a/src/util/virnetdevpriv.h b/src/util/virnetdevpriv.h new file mode 100644 index 0000000000..7990bf5269 --- /dev/null +++ b/src/util/virnetdevpriv.h @@ -0,0 +1,44 @@ +/* + * virnetdevpriv.h: private virnetdev header for unit testing + * + * Copyright (C) 2021 Canonical Ltd. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; If not, see + * . + */ + +#ifndef LIBVIRT_VIRNETDEVPRIV_H_ALLOW +# error "virnetdevpriv.h may only be included by virnetdev.c or test suite= s" +#endif /* LIBVIRT_VIRNETDEVPRIV_H_ALLOW */ + +#pragma once + +#include "virnetdev.h" + +int +virNetDevSendVfSetLinkRequest(const char *ifname, int vfInfoType, + const void *payload, const size_t payloadLen= ); + +int +virNetDevSetVfVlan(const char *ifname, int vf, int vlanid); + +int +virNetDevSetVfMac(const char *ifname, int vf, + const virMacAddr *macaddr, + bool *allowRetry); + +int +virNetDevSetVfConfig(const char *ifname, int vf, + const virMacAddr *macaddr, int vlanid, + bool *allowRetry); diff --git a/tests/virnetdevtest.c b/tests/virnetdevtest.c index aadbeb1ef4..15e8f75d8b 100644 --- a/tests/virnetdevtest.c +++ b/tests/virnetdevtest.c @@ -18,11 +18,17 @@ =20 #include =20 +#include "internal.h" #include "testutils.h" =20 +#include "virnetlink.h" + +#define LIBVIRT_VIRNETDEVPRIV_H_ALLOW + #ifdef __linux__ =20 -# include "virnetdev.h" +# include "virmock.h" +# include "virnetdevpriv.h" =20 # define VIR_FROM_THIS VIR_FROM_NONE =20 @@ -59,6 +65,211 @@ testVirNetDevGetLinkInfo(const void *opaque) return 0; } =20 +int +(*real_virNetDevSendVfSetLinkRequest)(const char *ifname, int vfInfoType, + const void *payload, const size_t pa= yloadLen); + +int +(*real_virNetDevSetVfMac)(const char *ifname, int vf, const virMacAddr *ma= caddr, bool *allowRetry); + +int +(*real_virNetDevSetVfVlan)(const char *ifname, int vf, int vlanid); + +static void +init_syms(void) +{ + VIR_MOCK_REAL_INIT(virNetDevSendVfSetLinkRequest); + VIR_MOCK_REAL_INIT(virNetDevSetVfMac); + VIR_MOCK_REAL_INIT(virNetDevSetVfVlan); +} + +int +virNetDevSetVfMac(const char *ifname, int vf, + const virMacAddr *macaddr, + bool *allowRetry) +{ + init_syms(); + + if (STREQ_NULLABLE(ifname, "fakeiface-macerror")) { + return -EBUSY; + } else if (STREQ_NULLABLE(ifname, "fakeiface-altmacerror")) { + return -EINVAL; + } else if (STREQ_NULLABLE(ifname, "fakeiface-macerror-novlanerror")) { + return -EAGAIN; + } else if (STREQ_NULLABLE(ifname, "fakeiface-macerror-vlanerror")) { + return -ENODEV; + } else if (STREQ_NULLABLE(ifname, "fakeiface-nomacerror-vlanerror")) { + return 0; + } else if (STREQ_NULLABLE(ifname, "fakeiface-nomacerror-novlanerror"))= { + return 0; + } + return real_virNetDevSetVfMac(ifname, vf, macaddr, allowRetry); +} + +int +virNetDevSetVfVlan(const char *ifname, int vf, int vlanid) +{ + init_syms(); + + if (STREQ_NULLABLE(ifname, "fakeiface-macerror-vlanerror")) { + return -EPERM; + } else if (STREQ_NULLABLE(ifname, "fakeiface-nomacerror-vlanerror")) { + return -EPERM; + } else if (STREQ_NULLABLE(ifname, "fakeiface-macerror-novlanerror")) { + return 0; + } else if (STREQ_NULLABLE(ifname, "fakeiface-nomacerror-novlanerror"))= { + return 0; + } + return real_virNetDevSetVfVlan(ifname, vf, vlanid); +} + +int +virNetDevSendVfSetLinkRequest(const char *ifname, int vfInfoType, + const void *payload, const size_t payloadLen) +{ + init_syms(); + + if (STREQ_NULLABLE(ifname, "fakeiface-eperm")) { + return -EPERM; + } else if (STREQ_NULLABLE(ifname, "fakeiface-eagain")) { + return -EAGAIN; + } else if (STREQ_NULLABLE(ifname, "fakeiface-einval")) { + return -EINVAL; + } else if (STREQ_NULLABLE(ifname, "fakeiface-ok")) { + return 0; + } + return real_virNetDevSendVfSetLinkRequest(ifname, vfInfoType, payload,= payloadLen); +} + +static int +testVirNetDevSetVfMac(const void *opaque G_GNUC_UNUSED) +{ + struct testCase { + const char *ifname; + const int vf_num; + const virMacAddr macaddr; + bool allow_retry; + const int rc; + }; + size_t i =3D 0; + int rc =3D 0; + struct testCase testCases[] =3D { + { .ifname =3D "fakeiface-ok", .vf_num =3D 1, + .macaddr =3D { .addr =3D { 0, 0, 0, 0, 0, 0 } }, .allow_retry = =3D false, .rc =3D 0 }, + { .ifname =3D "fakeiface-ok", .vf_num =3D 2, + .macaddr =3D { .addr =3D { 0, 0, 0, 7, 7, 7 } }, .allow_retry = =3D false, .rc =3D 0 }, + { .ifname =3D "fakeiface-ok", .vf_num =3D 3, + .macaddr =3D { .addr =3D { 0, 0, 0, 0, 0, 0 } }, .allow_retry = =3D true, .rc =3D 0 }, + { .ifname =3D "fakeiface-ok", .vf_num =3D 4, + .macaddr =3D { .addr =3D { 0, 0, 0, 7, 7, 7 } }, .allow_retry = =3D true, .rc =3D 0 }, + { .ifname =3D "fakeiface-eperm", .vf_num =3D 5, + .macaddr =3D { .addr =3D { 0, 0, 0, 0, 0, 0 } }, .allow_retry = =3D false, .rc =3D -EPERM }, + { .ifname =3D "fakeiface-einval", .vf_num =3D 6, + .macaddr =3D { .addr =3D { 0, 0, 0, 0, 0, 0 } }, .allow_retry = =3D false, .rc =3D -EINVAL }, + { .ifname =3D "fakeiface-einval", .vf_num =3D 7, + .macaddr =3D { .addr =3D { 0, 0, 0, 0, 0, 0 } }, .allow_retry = =3D true, .rc =3D -EINVAL }, + { .ifname =3D "fakeiface-einval", .vf_num =3D 8, + .macaddr =3D { .addr =3D { 0, 0, 0, 7, 7, 7 } }, .allow_retry = =3D false, .rc =3D -EINVAL }, + { .ifname =3D "fakeiface-einval", .vf_num =3D 9, + .macaddr =3D { .addr =3D { 0, 0, 0, 7, 7, 7 } }, .allow_retry = =3D true, .rc =3D -EINVAL }, + }; + + for (i =3D 0; i < sizeof(testCases) / sizeof(struct testCase); ++i) { + rc =3D virNetDevSetVfMac(testCases[i].ifname, testCases[i].vf_num, + &testCases[i].macaddr, &testCases[i].allow_r= etry); + if (rc !=3D testCases[i].rc) { + return -1; + } + } + return 0; +} + +static int +testVirNetDevSetVfMissingMac(const void *opaque G_GNUC_UNUSED) +{ + bool allowRetry =3D false; + /* NULL MAC pointer. */ + if (virNetDevSetVfMac("fakeiface-ok", 1, NULL, &allowRetry) !=3D -EINV= AL) { + return -1; + } + allowRetry =3D true; + if (virNetDevSetVfMac("fakeiface-ok", 1, NULL, &allowRetry) !=3D -EINV= AL) { + return -1; + } + return 0; +} + +static int +testVirNetDevSetVfVlan(const void *opaque G_GNUC_UNUSED) +{ + struct testCase { + const char *ifname; + const int vf_num; + const int vlan_id; + const int rc; + }; + size_t i =3D 0; + int rc =3D 0; + const struct testCase testCases[] =3D { + /* VLAN ID is out of range of valid values (0-4095). */ + { .ifname =3D "enxdeadbeefcafe", .vf_num =3D 1, .vlan_id =3D 4096,= .rc =3D -ERANGE }, + { .ifname =3D "enxdeadbeefcafe", .vf_num =3D 1, .vlan_id =3D -1, .= rc =3D -ERANGE }, + { .ifname =3D "fakeiface-eperm", .vf_num =3D 1, .vlan_id =3D 0, .r= c =3D -EPERM }, + { .ifname =3D "fakeiface-eagain", .vf_num =3D 1, .vlan_id =3D 0, .= rc =3D -EAGAIN }, + /* Successful requests with vlan id 0 need to have a zero return c= ode. */ + { .ifname =3D "fakeiface-ok", .vf_num =3D 1, .vlan_id =3D 0, .rc = =3D 0 }, + /* Requests with a non-zero VLAN ID that result in an EPERM need t= o result in failures. + * failures. */ + { .ifname =3D "fakeiface-eperm", .vf_num =3D 1, .vlan_id =3D 42, .= rc =3D -EPERM }, + /* Requests with a non-zero VLAN ID that result in some other erro= rs need to result in + * failures. */ + { .ifname =3D "fakeiface-eagain", .vf_num =3D 1, .vlan_id =3D 42, = .rc =3D -EAGAIN }, + /* Successful requests with a non-zero VLAN ID */ + { .ifname =3D "fakeiface-ok", .vf_num =3D 1, .vlan_id =3D 42, .rc = =3D 0 }, + }; + + for (i =3D 0; i < sizeof(testCases) / sizeof(struct testCase); ++i) { + rc =3D virNetDevSetVfVlan(testCases[i].ifname, testCases[i].vf_num,= testCases[i].vlan_id); + if (rc !=3D testCases[i].rc) { + return -1; + } + } + + return 0; +} + +static int +testVirNetDevSetVfConfig(const void *opaque G_GNUC_UNUSED) +{ + struct testCase { + const char *ifname; + const int rc; + }; + int rc =3D 0; + size_t i =3D 0; + /* Nested functions are mocked so dummy values are used. */ + const virMacAddr mac =3D { .addr =3D { 0xDE, 0xAD, 0xBE, 0xEF, 0xCA, 0= xFE }}; + const int vfNum =3D 1; + const int vlanid =3D 0; + bool *allowRetry =3D NULL; + + const struct testCase testCases[] =3D { + { .ifname =3D "fakeiface-macerror", .rc =3D -EBUSY }, + { .ifname =3D "fakeiface-altmacerror", .rc =3D -EINVAL }, + { .ifname =3D "fakeiface-macerror-novlanerror", .rc =3D -EAGAIN }, + { .ifname =3D "fakeiface-macerror-vlanerror", .rc =3D -ENODEV }, + { .ifname =3D "fakeiface-nomacerror-novlanerror", .rc =3D 0 }, + }; + + for (i =3D 0; i < sizeof(testCases) / sizeof(struct testCase); ++i) { + rc =3D virNetDevSetVfConfig(testCases[i].ifname, vfNum, &mac, vlani= d, allowRetry); + if (rc !=3D testCases[i].rc) { + return -1; + } + } + return 0; +} + static int mymain(void) { @@ -76,6 +287,15 @@ mymain(void) DO_TEST_LINK("lo", VIR_NETDEV_IF_STATE_UNKNOWN, 0); DO_TEST_LINK("eth0-broken", VIR_NETDEV_IF_STATE_DOWN, 0); =20 + if (virTestRun("Set VF MAC", testVirNetDevSetVfMac, NULL) < 0) + ret =3D -1; + if (virTestRun("Set VF MAC: missing MAC pointer", testVirNetDevSetVfMi= ssingMac, NULL) < 0) + ret =3D -1; + if (virTestRun("Set VF VLAN", testVirNetDevSetVfVlan, NULL) < 0) + ret =3D -1; + if (virTestRun("Set VF Config", testVirNetDevSetVfConfig, NULL) < 0) + ret =3D -1; + return ret =3D=3D 0 ? EXIT_SUCCESS : EXIT_FAILURE; } =20 --=20 2.32.0 From nobody Fri Apr 26 14:13:27 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=canonical.com Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1637255963362667.2596901295541; Thu, 18 Nov 2021 09:19:23 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-448-jbj4yb0YNyemxPFdntc6RA-1; Thu, 18 Nov 2021 12:19:15 -0500 Received: from smtp.corp.redhat.com (int-mx04.intmail.prod.int.phx2.redhat.com [10.5.11.14]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id A92B557058; Thu, 18 Nov 2021 17:19:09 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 89EFD5DAA5; Thu, 18 Nov 2021 17:19:09 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 2DC884EA31; Thu, 18 Nov 2021 17:19:08 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.rdu2.redhat.com [10.11.54.1]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 1AIHFSgw000756 for ; Thu, 18 Nov 2021 12:15:29 -0500 Received: by smtp.corp.redhat.com (Postfix) id D5CAC40CFD11; Thu, 18 Nov 2021 17:15:28 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast03.extmail.prod.ext.rdu2.redhat.com [10.11.55.19]) by smtp.corp.redhat.com (Postfix) with ESMTPS id CFF7440CFD10 for ; Thu, 18 Nov 2021 17:15:28 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-1.mimecast.com [207.211.31.81]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id B0D8EA09A55 for ; Thu, 18 Nov 2021 17:15:28 +0000 (UTC) Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-17-ZQuN1XkbO6exSLbwh2Suxg-1; Thu, 18 Nov 2021 12:15:27 -0500 Received: from mail-lf1-f71.google.com (mail-lf1-f71.google.com [209.85.167.71]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id B57024001C for ; Thu, 18 Nov 2021 17:15:23 +0000 (UTC) Received: by mail-lf1-f71.google.com with SMTP id q26-20020ac2515a000000b0040adfeb8132so4577999lfd.9 for ; Thu, 18 Nov 2021 09:15:23 -0800 (PST) Received: from ws.lan.d-node.is ([95.165.29.203]) by smtp.gmail.com with ESMTPSA id c6sm34499ljn.84.2021.11.18.09.15.22 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Nov 2021 09:15:22 -0800 (PST) X-MC-Unique: jbj4yb0YNyemxPFdntc6RA-1 X-MC-Unique: ZQuN1XkbO6exSLbwh2Suxg-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=wM/jDn92d53dUj6edcJ6HJprDzQJLHMOU8yQN204e+c=; b=0+lbZFjrXEJclKpw/zRU1sB30Th77BwwuTnbV8hSmUnvJDED+FWUOrVRzZp1BjSw66 fITfdfk4L1YoBDiQauKR+h3gjhW+9ahFcf1Ckf3sIUNCwBVQ+sNovZqVRU1mSk5/cz/c HWkJRp5G1N5NRK7x66Cz9ShPUHqw6iFDqU+i6relll3nCD4648U3UkjzsBp06yMFAQQ5 Qn/oUfcG5Osz3+VI13ZV/WcP0dqhIqEOgb1JnNe1udtgTT3id/5DCpfN3JUfstz9CEM+ biZ4wNwmCgZ4HIKDfj5Oe/fL//FC+YOlicEX2jJAta3edq3Ri0Mq9NJ1IWVs7YM+Rw/i VhCA== X-Gm-Message-State: AOAM533C3Q18tcK518VQ6AZIrhpmoDqT7XFlsht9MSCb5cs9l1YVhIWo u6fXxUsa2lSZwLggFElBDTYJx7tjUXm7+Xcd6l6OywDKcN5GhdFieQHzhEV0ddGMwPBY1FuKbrz p+sj7YpYmL3BzP9B2pXXvJmYDMIHVzok8tg== X-Received: by 2002:a05:6512:3d16:: with SMTP id d22mr24874681lfv.523.1637255723133; Thu, 18 Nov 2021 09:15:23 -0800 (PST) X-Google-Smtp-Source: ABdhPJyU+s0jLoZ2QVeq6f6S+LQRADEsFxSRFqHU5lQoVNoPFO1hctroRouc2G8S9qW7U85mqet8rw== X-Received: by 2002:a05:6512:3d16:: with SMTP id d22mr24874658lfv.523.1637255722942; Thu, 18 Nov 2021 09:15:22 -0800 (PST) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v6 2/3] Allow VF vlanid to be passed as a pointer Date: Thu, 18 Nov 2021 20:15:19 +0300 Message-Id: <20211118171520.84703-3-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20211118171520.84703-1-dmitrii.shcherbakov@canonical.com> References: <20211118171520.84703-1-dmitrii.shcherbakov@canonical.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.84 on 10.11.54.1 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 1AIHFSgw000756 X-loop: libvir-list@redhat.com Cc: laine@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.14 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1637255964763100004 Content-Type: text/plain; charset="utf-8" There should be a way to show no intent in programming a VLAN at all (including clearing it). This allows handling error conditions differently when VLAN clearing is explicit (vlan id =3D=3D 0) vs implicit (vlanid =3D=3D NULL - try to clear it if possible). Signed-off-by: Dmitrii Shcherbakov --- src/hypervisor/virhostdev.c | 4 +++- src/util/virnetdev.c | 36 ++++++++++++++++++++++++------------ src/util/virnetdevpriv.h | 4 ++-- tests/virnetdevtest.c | 27 +++++++++++++++++++++++---- 4 files changed, 52 insertions(+), 19 deletions(-) diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c index 14ea560309..515663222c 100644 --- a/src/hypervisor/virhostdev.c +++ b/src/hypervisor/virhostdev.c @@ -463,6 +463,7 @@ virHostdevSetNetConfig(virDomainHostdevDef *hostdev, const virNetDevVPortProfile *virtPort; int vf =3D -1; bool port_profile_associate =3D true; + bool setVlan =3D false; =20 if (!virHostdevIsPCINetDevice(hostdev)) return 0; @@ -471,6 +472,7 @@ virHostdevSetNetConfig(virDomainHostdevDef *hostdev, return -1; =20 vlan =3D virDomainNetGetActualVlan(hostdev->parentnet); + setVlan =3D vlan !=3D NULL; virtPort =3D virDomainNetGetActualVirtPortProfile(hostdev->parentnet); if (virtPort) { if (vlan) { @@ -486,7 +488,7 @@ virHostdevSetNetConfig(virDomainHostdevDef *hostdev, return -1; } else { if (virNetDevSetNetConfig(linkdev, vf, &hostdev->parentnet->mac, - vlan, NULL, true) < 0) + vlan, NULL, setVlan) < 0) return -1; } =20 diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index f2f5fa2d95..d3b72c8f0b 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1607,20 +1607,25 @@ virNetDevSendVfSetLinkRequest(const char *ifname, i= nt vfInfoType, } =20 int -virNetDevSetVfVlan(const char *ifname, int vf, int vlanid) +virNetDevSetVfVlan(const char *ifname, int vf, const int *vlanid) { int rc =3D 0; int requestError =3D 0; =20 struct ifla_vf_vlan ifla_vf_vlan =3D { .vf =3D vf, - .vlan =3D vlanid, .qos =3D 0, + /* If vlanid is NULL, assume it needs to be cleared. */ + .vlan =3D 0, }; =20 - /* VLAN ids 0 and 4095 are reserved per 802.1Q but are valid values. */ - if ((vlanid < 0 || vlanid > 4095)) { - return -ERANGE; + if (vlanid !=3D NULL) { + /* VLAN ids 0 and 4095 are reserved per 802.1Q but are valid value= s. */ + if ((*vlanid < 0 || *vlanid > 4095)) { + return -ERANGE; + } else { + ifla_vf_vlan.vlan =3D *vlanid; + } } =20 requestError =3D virNetDevSendVfSetLinkRequest(ifname, IFLA_VF_VLAN, @@ -1630,12 +1635,12 @@ virNetDevSetVfVlan(const char *ifname, int vf, int = vlanid) virReportSystemError(-requestError, _("Cannot set interface vlanid to %d " "for ifname %s vf %d"), - vlanid, ifname ? ifname : "(unspecified)", vf= ); + ifla_vf_vlan.vlan, ifname ? ifname : "(unspec= ified)", vf); rc =3D requestError; } VIR_DEBUG("RTM_SETLINK %s vf %d vlanid=3D%d - %s", ifname, vf, - vlanid, rc < 0 ? "Fail" : "Success"); + ifla_vf_vlan.vlan, rc < 0 ? "Fail" : "Success"); return rc; } =20 @@ -1689,7 +1694,7 @@ virNetDevSetVfMac(const char *ifname, int vf, =20 int virNetDevSetVfConfig(const char *ifname, int vf, - const virMacAddr *macaddr, int vlanid, + const virMacAddr *macaddr, const int *vlanid, bool *allowRetry) { int rc =3D 0; @@ -2225,7 +2230,7 @@ virNetDevSetNetConfig(const char *linkdev, int vf, const char *pfDevName =3D NULL; g_autofree char *pfDevOrig =3D NULL; g_autofree char *vfDevOrig =3D NULL; - int vlanTag =3D -1; + g_autofree int *vlanTag =3D NULL; g_autoptr(virPCIDevice) vfPCIDevice =3D NULL; =20 if (vf >=3D 0) { @@ -2284,10 +2289,17 @@ virNetDevSetNetConfig(const char *linkdev, int vf, return -1; } =20 - vlanTag =3D vlan->tag[0]; + vlanTag =3D g_new0(int, 1); + *vlanTag =3D vlan->tag[0]; =20 } else if (setVlan) { - vlanTag =3D 0; /* assure any existing vlan tag is reset */ + vlanTag =3D g_new0(int, 1); + /* Assure any existing vlan tag is reset. */ + *vlanTag =3D 0; + } else { + /* Indicate that setting a VLAN has not been explicitly reques= ted. + * This allows selected errors in clearing a VF VLAN to be ign= ored. */ + vlanTag =3D NULL; } } =20 @@ -2369,7 +2381,7 @@ virNetDevSetNetConfig(const char *linkdev, int vf, } } =20 - if (adminMAC || vlanTag >=3D 0) { + if (adminMAC) { /* Set vlanTag and admin MAC using an RTM_SETLINK request sent to * PFdevname+VF#, if mac !=3D NULL this will set the "admin MAC" v= ia * the PF, *not* the actual VF MAC - the admin MAC only takes diff --git a/src/util/virnetdevpriv.h b/src/util/virnetdevpriv.h index 7990bf5269..84a42fb747 100644 --- a/src/util/virnetdevpriv.h +++ b/src/util/virnetdevpriv.h @@ -31,7 +31,7 @@ virNetDevSendVfSetLinkRequest(const char *ifname, int vfI= nfoType, const void *payload, const size_t payloadLen= ); =20 int -virNetDevSetVfVlan(const char *ifname, int vf, int vlanid); +virNetDevSetVfVlan(const char *ifname, int vf, const int *vlanid); =20 int virNetDevSetVfMac(const char *ifname, int vf, @@ -40,5 +40,5 @@ virNetDevSetVfMac(const char *ifname, int vf, =20 int virNetDevSetVfConfig(const char *ifname, int vf, - const virMacAddr *macaddr, int vlanid, + const virMacAddr *macaddr, const int *vlanid, bool *allowRetry); diff --git a/tests/virnetdevtest.c b/tests/virnetdevtest.c index 15e8f75d8b..5a787fa0f1 100644 --- a/tests/virnetdevtest.c +++ b/tests/virnetdevtest.c @@ -73,7 +73,7 @@ int (*real_virNetDevSetVfMac)(const char *ifname, int vf, const virMacAddr *ma= caddr, bool *allowRetry); =20 int -(*real_virNetDevSetVfVlan)(const char *ifname, int vf, int vlanid); +(*real_virNetDevSetVfVlan)(const char *ifname, int vf, const int *vlanid); =20 static void init_syms(void) @@ -107,7 +107,7 @@ virNetDevSetVfMac(const char *ifname, int vf, } =20 int -virNetDevSetVfVlan(const char *ifname, int vf, int vlanid) +virNetDevSetVfVlan(const char *ifname, int vf, const int *vlanid) { init_syms(); =20 @@ -208,6 +208,11 @@ testVirNetDevSetVfVlan(const void *opaque G_GNUC_UNUSE= D) const int vlan_id; const int rc; }; + struct nullVlanTestCase { + const char *ifname; + const int vf_num; + const int rc; + }; size_t i =3D 0; int rc =3D 0; const struct testCase testCases[] =3D { @@ -228,13 +233,27 @@ testVirNetDevSetVfVlan(const void *opaque G_GNUC_UNUS= ED) { .ifname =3D "fakeiface-ok", .vf_num =3D 1, .vlan_id =3D 42, .rc = =3D 0 }, }; =20 + const struct nullVlanTestCase nullVLANTestCases[] =3D { + { .ifname =3D "fakeiface-eperm", .vf_num =3D 1, .rc =3D -EPERM }, + { .ifname =3D "fakeiface-eagain", .vf_num =3D 1, .rc =3D -EAGAIN }, + /* Successful requests with vlan id 0 need to have a zero return c= ode. */ + { .ifname =3D "fakeiface-ok", .vf_num =3D 1, .rc =3D 0 }, + }; + for (i =3D 0; i < sizeof(testCases) / sizeof(struct testCase); ++i) { - rc =3D virNetDevSetVfVlan(testCases[i].ifname, testCases[i].vf_num,= testCases[i].vlan_id); + rc =3D virNetDevSetVfVlan(testCases[i].ifname, testCases[i].vf_num,= &testCases[i].vlan_id); if (rc !=3D testCases[i].rc) { return -1; } } =20 + for (i =3D 0; i < sizeof(nullVLANTestCases) / sizeof(struct nullVlanTe= stCase); ++i) { + rc =3D virNetDevSetVfVlan(nullVLANTestCases[i].ifname, nullVLANTest= Cases[i].vf_num, NULL); + if (rc !=3D nullVLANTestCases[i].rc) { + return -1; + } + } + return 0; } =20 @@ -262,7 +281,7 @@ testVirNetDevSetVfConfig(const void *opaque G_GNUC_UNUS= ED) }; =20 for (i =3D 0; i < sizeof(testCases) / sizeof(struct testCase); ++i) { - rc =3D virNetDevSetVfConfig(testCases[i].ifname, vfNum, &mac, vlani= d, allowRetry); + rc =3D virNetDevSetVfConfig(testCases[i].ifname, vfNum, &mac, &vlan= id, allowRetry); if (rc !=3D testCases[i].rc) { return -1; } --=20 2.32.0 From nobody Fri Apr 26 14:13:27 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) client-ip=170.10.133.124; envelope-from=libvir-list-bounces@redhat.com; helo=us-smtp-delivery-124.mimecast.com; Authentication-Results: mx.zohomail.com; spf=pass (zohomail.com: domain of redhat.com designates 170.10.133.124 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=fail(p=none dis=none) header.from=canonical.com Return-Path: Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.133.124]) by mx.zohomail.com with SMTPS id 1637255961062605.4144221784836; Thu, 18 Nov 2021 09:19:21 -0800 (PST) Received: from mimecast-mx01.redhat.com (mimecast-mx01.redhat.com [209.132.183.4]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-604-8UpQuQkeOLqwlOSRg3hZYQ-1; Thu, 18 Nov 2021 12:19:18 -0500 Received: from smtp.corp.redhat.com (int-mx01.intmail.prod.int.phx2.redhat.com [10.5.11.11]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id C7C8019057C4; Thu, 18 Nov 2021 17:19:12 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id AC092197FC; Thu, 18 Nov 2021 17:19:12 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id 7B7C24EA37; Thu, 18 Nov 2021 17:19:12 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.rdu2.redhat.com [10.11.54.5]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 1AIHFYHn000790 for ; Thu, 18 Nov 2021 12:15:34 -0500 Received: by smtp.corp.redhat.com (Postfix) id 72CE251DD; Thu, 18 Nov 2021 17:15:34 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast01.extmail.prod.ext.rdu2.redhat.com [10.11.55.17]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 6D0ED51DC for ; Thu, 18 Nov 2021 17:15:28 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-2.mimecast.com [205.139.110.61]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mimecast-mx02.redhat.com (Postfix) with ESMTPS id ACE2D8061CA for ; Thu, 18 Nov 2021 17:15:28 +0000 (UTC) Received: from smtp-relay-internal-0.canonical.com (smtp-relay-internal-0.canonical.com [185.125.188.122]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id us-mta-328-5tIhUeZ-PwaE_qLsOmbIaQ-1; Thu, 18 Nov 2021 12:15:27 -0500 Received: from mail-lf1-f69.google.com (mail-lf1-f69.google.com [209.85.167.69]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-0.canonical.com (Postfix) with ESMTPS id 3DDE840024 for ; Thu, 18 Nov 2021 17:15:24 +0000 (UTC) Received: by mail-lf1-f69.google.com with SMTP id j9-20020a05651231c900b004037efe9fddso4603062lfe.18 for ; Thu, 18 Nov 2021 09:15:24 -0800 (PST) Received: from ws.lan.d-node.is ([95.165.29.203]) by smtp.gmail.com with ESMTPSA id c6sm34499ljn.84.2021.11.18.09.15.23 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 18 Nov 2021 09:15:23 -0800 (PST) X-MC-Unique: 8UpQuQkeOLqwlOSRg3hZYQ-1 X-MC-Unique: 5tIhUeZ-PwaE_qLsOmbIaQ-1 X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=BrcgNvoDvIrF8ys3cZZK5i9Bh6HalK3Jn3tYE4x6jK4=; b=H5OAHo7WWrmvBpUcwbsBgKQiAL5jfZEFSEvB84zowl7PCWkni3Qz98uVJf5fIfafbp 7ucNJKS0HDWjl6zkhoVfNVCQc4CUhyapQSZxdO+jTyCJt/6YjMq5mGB0a2afCWwT0d5u 6iZmkC9bmXGCi97Hx2COR0fr8xy+GE2Y/b3uSThojzLTJhM3l2s98s2deR/9w9WlE4oK jbiMcnjhD4ZxG7FoGNCr3FqkQUS3p4kDlMLHJ65Xvkr17ySeCi0KNT97J5sGgP7uPYsM CwvAvGiqd/Qg2P1O6vy6PufJkNQjuXzVy3p6XQsJIyC613F2xr+IJf+7Q26cOvdQJo0N 6emg== X-Gm-Message-State: AOAM530DbmbJzs4dSgxQUegXBHhibwNqU97vJRbYp5klc3q4TS862pF9 S8n+l4m1uoAgyE16thV1TdtNLisq3TJcGw0Cpy0hiO+nZ+k8XmCQF52cM2Poa55pO/d9O/3SGU9 6+IpGUuNrwZplqvtaJ7xzRrgcFtu5t3j+0g== X-Received: by 2002:a2e:3c13:: with SMTP id j19mr18583651lja.311.1637255723677; Thu, 18 Nov 2021 09:15:23 -0800 (PST) X-Google-Smtp-Source: ABdhPJyy34se23opa+rNMtN312fBSr0eVDlD+GkdmlArw9egyS19jiJpbJ4+PIPZrFXMINzNvnA5gw== X-Received: by 2002:a2e:3c13:: with SMTP id j19mr18583611lja.311.1637255723447; Thu, 18 Nov 2021 09:15:23 -0800 (PST) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v6 3/3] Ignore EPERM on implicit clearing of VF VLAN ID Date: Thu, 18 Nov 2021 20:15:20 +0300 Message-Id: <20211118171520.84703-4-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20211118171520.84703-1-dmitrii.shcherbakov@canonical.com> References: <20211118171520.84703-1-dmitrii.shcherbakov@canonical.com> MIME-Version: 1.0 X-Mimecast-Impersonation-Protect: Policy=CLT - Impersonation Protection Definition; Similar Internal Domain=false; Similar Monitored External Domain=false; Custom External Domain=false; Mimecast External Domain=false; Newly Observed Domain=false; Internal User Name=false; Custom Display Name List=false; Reply-to Address Mismatch=false; Targeted Threat Dictionary=false; Mimecast Threat Dictionary=false; Custom Threat Dictionary=false X-Scanned-By: MIMEDefang 2.79 on 10.11.54.5 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 1AIHFYHn000790 X-loop: libvir-list@redhat.com Cc: laine@redhat.com X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.11 Authentication-Results: relay.mimecast.com; auth=pass smtp.auth=CUSA124A263 smtp.mailfrom=libvir-list-bounces@redhat.com X-Mimecast-Spam-Score: 0 X-Mimecast-Originator: redhat.com Content-Transfer-Encoding: quoted-printable X-ZM-MESSAGEID: 1637255962516100001 Content-Type: text/plain; charset="utf-8" SmartNIC DPUs may not expose some privileged eswitch operations to the hypervisor hosts. For example, this happens with Bluefield devices running in the ECPF (default) mode for security reasons. While VF MAC address programming is possible via an RTM_SETLINK operation, trying to set a VLAN ID in the same operation will fail with EPERM. The equivalent ip link commands below provide an illustration: 1. This works: sudo ip link set enp130s0f0 vf 2 mac de:ad:be:ef:ca:fe 2. Setting (or clearing) a VLAN fails with EPERM: sudo ip link set enp130s0f0 vf 2 vlan 0 RTNETLINK answers: Operation not permitted 3. This is what Libvirt attempts to do today (when trying to clear a VF VLAN at the same time as programming a VF MAC). sudo ip link set enp130s0f0 vf 2 vlan 0 mac de:ad:be:ef:ca:fe RTNETLINK answers: Operation not permitted If setting an explicit VLAN ID results in an EPERM, clearing a VLAN (setting a VLAN ID to 0) can be handled gracefully by ignoring the EPERM error with the rationale being that if we cannot set this state in the first place, we cannot clear it either. In order to keep explicit clearing of VLAN ID working as it used to be passing a NULL pointer for VLAN ID is used. Signed-off-by: Dmitrii Shcherbakov --- NEWS.rst | 15 +++++++++++++++ src/util/virnetdev.c | 11 ++++++++++- tests/virnetdevtest.c | 2 +- 3 files changed, 26 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index a71b84c363..f12f8deea1 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -30,6 +30,21 @@ v7.10.0 (unreleased) Libvirt is now able to report interface information from the guest's perspective (using guest agent). =20 + * virnetdev: Ignore EPERM on implicit clearing of VF VLAN ID + + Libvirt will now ignore EPERM errors on attempts to implicitly clear a + VLAN ID (when a VLAN is not explicitly provided via an interface XML + using a 0 or a non-zero value) as SmartNIC DPUs do not expose VLAN + programming capabilities to the hypervisor host. This allows Libvirt + clients to avoid specifying a VLAN and expect VF configuration to work + since Libvirt tries to clear a VLAN in the same operation + as setting a MAC address for VIR_DOMAIN_NET_TYPE_HOSTDEV devices which + is now split into two distinct operations. EPERM errors received while + trying to program a non-zero VLAN ID or explicitly program a VLAN ID 0 + will still cause errors as before so there is no change in behavior + in those cases. + + * **Bug fixes** =20 =20 diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c index d3b72c8f0b..533d49b83f 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1631,12 +1631,21 @@ virNetDevSetVfVlan(const char *ifname, int vf, cons= t int *vlanid) requestError =3D virNetDevSendVfSetLinkRequest(ifname, IFLA_VF_VLAN, &ifla_vf_vlan, sizeof(ifl= a_vf_vlan)); =20 - if (requestError) { + /* If vlanid is NULL - we are attempting to implicitly clear an existi= ng VLAN id. + * An EPERM received at this stage is an indicator that the embedded + * switch is not exposed to this host and the network driver is not + * able to set a VLAN for a VF, whereas the Libvirt client has not + * explicitly configured a VLAN or requested it to be cleared via vid = 0. */ + if (requestError =3D=3D -EPERM && vlanid =3D=3D NULL) { + rc =3D 0; + } else if (requestError) { virReportSystemError(-requestError, _("Cannot set interface vlanid to %d " "for ifname %s vf %d"), ifla_vf_vlan.vlan, ifname ? ifname : "(unspec= ified)", vf); rc =3D requestError; + } else { + rc =3D 0; } VIR_DEBUG("RTM_SETLINK %s vf %d vlanid=3D%d - %s", ifname, vf, diff --git a/tests/virnetdevtest.c b/tests/virnetdevtest.c index 5a787fa0f1..f969898b94 100644 --- a/tests/virnetdevtest.c +++ b/tests/virnetdevtest.c @@ -234,7 +234,7 @@ testVirNetDevSetVfVlan(const void *opaque G_GNUC_UNUSED) }; =20 const struct nullVlanTestCase nullVLANTestCases[] =3D { - { .ifname =3D "fakeiface-eperm", .vf_num =3D 1, .rc =3D -EPERM }, + { .ifname =3D "fakeiface-eperm", .vf_num =3D 1, .rc =3D 0 }, { .ifname =3D "fakeiface-eagain", .vf_num =3D 1, .rc =3D -EAGAIN }, /* Successful requests with vlan id 0 need to have a zero return c= ode. */ { .ifname =3D "fakeiface-ok", .vf_num =3D 1, .rc =3D 0 }, --=20 2.32.0