From nobody Thu May 9 12:14:45 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 1643704747893386.2861500130475; Tue, 1 Feb 2022 00:39:07 -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-280-klIF02CrMhqRR9M9JIjdKQ-1; Tue, 01 Feb 2022 03:39:05 -0500 Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.phx2.redhat.com [10.5.11.16]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id AD3CB1091DA0; Tue, 1 Feb 2022 08:38:59 +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 796307AB68; Tue, 1 Feb 2022 08:38:59 +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 828F44BB7C; Tue, 1 Feb 2022 08:38:57 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx10.intmail.prod.int.rdu2.redhat.com [10.11.54.10]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id 2118ct9u018794 for ; Tue, 1 Feb 2022 03:38:56 -0500 Received: by smtp.corp.redhat.com (Postfix) id B9088401E77; Tue, 1 Feb 2022 08:38:55 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast08.extmail.prod.ext.rdu2.redhat.com [10.11.55.24]) by smtp.corp.redhat.com (Postfix) with ESMTPS id B4AA2401E38 for ; Tue, 1 Feb 2022 08:38:55 +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 9797B3804062 for ; Tue, 1 Feb 2022 08:38:55 +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-558-oZz7B9ixORaOdp_7gH3IwA-1; Tue, 01 Feb 2022 03:38:54 -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-0.canonical.com (Postfix) with ESMTPS id 4182A3F32B for ; Tue, 1 Feb 2022 08:28:56 +0000 (UTC) Received: by mail-lf1-f72.google.com with SMTP id f13-20020a19ae0d000000b00436e91bb4b6so5643752lfc.0 for ; Tue, 01 Feb 2022 00:28:56 -0800 (PST) Received: from ws.lan.d-node.is ([95.165.29.203]) by smtp.gmail.com with ESMTPSA id l5sm1074586lje.21.2022.02.01.00.28.54 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Feb 2022 00:28:54 -0800 (PST) X-MC-Unique: klIF02CrMhqRR9M9JIjdKQ-1 X-MC-Unique: oZz7B9ixORaOdp_7gH3IwA-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=u1vbA4DlSKMw0/knhFHlItPICBDG0BAXdqVvUPpgbFg=; b=nX5Yn5jEw+7nd/CLlnV0DkSjFNEeHxOgY4WOmJhDxXQqpRTxI2d/wh14SUs+l0QaJA pvXzbZyR4c87xGIXHxDrFrdkQQCL6+YVJyQZBsQcFMu6+MubnRygxIId6qPKzBHOlTLX QqleC469ntyOw0wLP1z6+e5GLETD7WX73SYIcGLSXRIYCWyhzLHpsAgSMutneh8R3n6j HqMij0iY+gTUTPunnfGYWm0ulxUG+oXsqzHEycI/rPYmYwKLhzHuIElH3EEzrvvHXZnO u7ZRCYYQCo8dqp3VGc9PS2LlGAz7zGELngGeLv4smztK5VV8UMxmdzgPigYA6rP8qNXF HXOw== X-Gm-Message-State: AOAM532I1xVEL94YrCZMiXGSrDwP2uBsmlMw3PN0VgEwDMMfvfUc9UWV Oz3OSUXw/6kK2E4l1Wa8L4BAmmi6yzy5mvL6ruuAiPvb/uGxbv4bVGNTsNu687C2CnRKWC61ySb N3AVLuBF/K8hTWjOu1vHZORKUMBnFNSfFiA== X-Received: by 2002:a05:6512:3e2a:: with SMTP id i42mr17755266lfv.636.1643704135520; Tue, 01 Feb 2022 00:28:55 -0800 (PST) X-Google-Smtp-Source: ABdhPJzcyJETyQ/PhZCtKqy+h08GFJdMTD18PFVgmNodHwyQTz3Ph8tSzXycxJQ+iQQKRyYZg1pDMQ== X-Received: by 2002:a05:6512:3e2a:: with SMTP id i42mr17755253lfv.636.1643704135125; Tue, 01 Feb 2022 00:28:55 -0800 (PST) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v8 1/3] Set VF MAC and VLAN ID in two different operations Date: Tue, 1 Feb 2022 11:28:51 +0300 Message-Id: <20220201082853.147209-2-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20220201082853.147209-1-dmitrii.shcherbakov@canonical.com> References: <20220201082853.147209-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.85 on 10.11.54.10 X-MIME-Autoconverted: from quoted-printable to 8bit by lists01.pubmisc.prod.ext.phx2.redhat.com id 2118ct9u018794 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.16 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: 1643704749620100001 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 | 226 ++++++++++++++++++++++++++------------ src/util/virnetdevpriv.h | 44 ++++++++ tests/virnetdevtest.c | 230 ++++++++++++++++++++++++++++++++++++++- 4 files changed, 434 insertions(+), 73 deletions(-) create mode 100644 src/util/virnetdevpriv.h diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index bc6fa191bf..e6493c2176 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2847,6 +2847,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 d93b2c6a83..043225d31f 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" @@ -1509,16 +1511,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; @@ -1526,9 +1524,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 @@ -1546,30 +1546,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); @@ -1582,48 +1560,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 @@ -1638,6 +1588,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 @@ -2391,6 +2435,44 @@ virNetDevVFInterfaceStats(virPCIDeviceAddress *vfAdd= r G_GNUC_UNUSED, return -1; } =20 +int +virNetDevSendVfSetLinkRequest(const char *ifname G_GNUC_UNUSED, int vfInfo= Type G_GNUC_UNUSED, + const void *payload G_GNUC_UNUSED, + const size_t payloadLen G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to send a VF SETLINK request on this pl= atform")); + return -1; +} + +int +virNetDevSetVfVlan(const char *ifname G_GNUC_UNUSED, int vf G_GNUC_UNUSED,= int vlanid G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to set a VF VLAN on this platform")); + return -1; +} + +int +virNetDevSetVfMac(const char *ifname G_GNUC_UNUSED, int vf G_GNUC_UNUSED, + const virMacAddr *macaddr G_GNUC_UNUSED, + bool *allowRetry G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to set a VF MAC on this platform")); + return -1; +} + +int +virNetDevSetVfConfig(const char *ifname G_GNUC_UNUSED, int vf G_GNUC_UNUSE= D, + const virMacAddr *macaddr G_GNUC_UNUSED, int vlanid G= _GNUC_UNUSED, + bool *allowRetry G_GNUC_UNUSED) +{ + virReportSystemError(ENOSYS, "%s", + _("Unable to set a VF config on this platform")); + return -1; +} + =20 #endif /* defined(WITH_LIBNL) */ =20 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..c8dba05c31 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,215 @@ testVirNetDevGetLinkInfo(const void *opaque) return 0; } =20 +# if defined(WITH_LIBNL) + +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; +} + +# endif /* defined(WITH_LIBNL) */ + static int mymain(void) { @@ -76,6 +291,19 @@ 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 defined(WITH_LIBNL) + + 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; + +# endif /* defined(WITH_LIBNL) */ + return ret =3D=3D 0 ? EXIT_SUCCESS : EXIT_FAILURE; } =20 --=20 2.32.0 From nobody Thu May 9 12:14:45 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 1643704751007779.5155203844294; Tue, 1 Feb 2022 00:39:11 -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-578-YSbbgbnTP6u8hQHBcY24Og-1; Tue, 01 Feb 2022 03:39:06 -0500 Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mimecast-mx01.redhat.com (Postfix) with ESMTPS id 0A5B510B7440; Tue, 1 Feb 2022 08:39:02 +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 DF5764F863; Tue, 1 Feb 2022 08:39:01 +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 AFD421809CBA; Tue, 1 Feb 2022 08:39:01 +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 2118d0vT018827 for ; Tue, 1 Feb 2022 03:39:00 -0500 Received: by smtp.corp.redhat.com (Postfix) id 06098202698A; Tue, 1 Feb 2022 08:39:00 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast09.extmail.prod.ext.rdu2.redhat.com [10.11.55.25]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 0117E2026980 for ; Tue, 1 Feb 2022 08:38:57 +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 E343028F4864 for ; Tue, 1 Feb 2022 08:38:56 +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-86-kQz0EInXMmGi96AXz8PNyg-1; Tue, 01 Feb 2022 03:38:55 -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 01D9B3FFD6 for ; Tue, 1 Feb 2022 08:28:57 +0000 (UTC) Received: by mail-lf1-f71.google.com with SMTP id p24-20020ac24ed8000000b0043b35f327bdso5063090lfr.20 for ; Tue, 01 Feb 2022 00:28:57 -0800 (PST) Received: from ws.lan.d-node.is ([95.165.29.203]) by smtp.gmail.com with ESMTPSA id l5sm1074586lje.21.2022.02.01.00.28.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Feb 2022 00:28:55 -0800 (PST) X-MC-Unique: YSbbgbnTP6u8hQHBcY24Og-1 X-MC-Unique: kQz0EInXMmGi96AXz8PNyg-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=FreYAeTmbIgV+D+0ySPWivxHwF3/46V45ZosoPx+Gxg=; b=bQGhzcM3nn9P9VzTr/nhpBe6y3GLmUXlBTq4DdYesFskuX5iIQlpCYXVLjqjb0gdkN fnmx8PF3J2OU3wyTSMzb8ydg9SPUIPz8CAPziODwIckLD47Nwch4lxByz2aQbeL9A6pA pEKgKFOI78nu/TtaZ+/ZZCsro9/79JvGxKe6RNfzVgDE/b8iEultwDxTqL2hXBb4Z+Ne PP42ZuWIuEDbSG0VwXCVcjYUxZVki6wu6nKe/Q7CEyCtDZcw+t2JG3vSwlbKzQK9/NUz PxJQMe/UVwzyEIKETn626emOBkWRrjaF/c07FbQXUvAXfztDwYl4zswbHiwqTjgB+4MQ MBQw== X-Gm-Message-State: AOAM530YWxjtYZD/R4NaRvMoMPsnwdkxZMOcu8cLvc+Kvf00HPmKi40L FOZak/X3BYbXKKol1jJ9YJt45ITQqEogM3XmWW5YmZ2pnEf0gHGvsZ+2yYmQOa7JpKV4cyzWeH+ mr5SpzBoXgs6tdh2n56XbZdRQWJvSPDDwGA== X-Received: by 2002:a05:6512:4021:: with SMTP id br33mr18567164lfb.145.1643704135932; Tue, 01 Feb 2022 00:28:55 -0800 (PST) X-Google-Smtp-Source: ABdhPJwnRL02B0/TOZNMfLmeKd/+AlI+0W7Tdb7KAFFxZkNtpAldcurqBayMqYdRzHyad6JIR3Cinw== X-Received: by 2002:a05:6512:4021:: with SMTP id br33mr18567149lfb.145.1643704135676; Tue, 01 Feb 2022 00:28:55 -0800 (PST) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v8 2/3] Allow VF vlanid to be passed as a pointer Date: Tue, 1 Feb 2022 11:28:52 +0300 Message-Id: <20220201082853.147209-3-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20220201082853.147209-1-dmitrii.shcherbakov@canonical.com> References: <20220201082853.147209-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 2118d0vT018827 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.15 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: 1643704753963100001 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 | 41 ++++++++++++++++++++++++------------- src/util/virnetdevpriv.h | 4 ++-- tests/virnetdevtest.c | 27 ++++++++++++++++++++---- 4 files changed, 55 insertions(+), 21 deletions(-) diff --git a/src/hypervisor/virhostdev.c b/src/hypervisor/virhostdev.c index e44eb7f1d3..929b0a0805 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 043225d31f..eacdc3bf1f 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1589,20 +1589,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, @@ -1612,12 +1617,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 @@ -1671,7 +1676,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; @@ -2207,7 +2212,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) { @@ -2266,10 +2271,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 @@ -2351,7 +2363,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 @@ -2446,7 +2458,8 @@ virNetDevSendVfSetLinkRequest(const char *ifname G_GN= UC_UNUSED, int vfInfoType G } =20 int -virNetDevSetVfVlan(const char *ifname G_GNUC_UNUSED, int vf G_GNUC_UNUSED,= int vlanid G_GNUC_UNUSED) +virNetDevSetVfVlan(const char *ifname G_GNUC_UNUSED, int vf G_GNUC_UNUSED, + const int *vlanid G_GNUC_UNUSED) { virReportSystemError(ENOSYS, "%s", _("Unable to set a VF VLAN on this platform")); @@ -2465,7 +2478,7 @@ virNetDevSetVfMac(const char *ifname G_GNUC_UNUSED, i= nt vf G_GNUC_UNUSED, =20 int virNetDevSetVfConfig(const char *ifname G_GNUC_UNUSED, int vf G_GNUC_UNUSE= D, - const virMacAddr *macaddr G_GNUC_UNUSED, int vlanid G= _GNUC_UNUSED, + const virMacAddr *macaddr G_GNUC_UNUSED, const int *v= lanid G_GNUC_UNUSED, bool *allowRetry G_GNUC_UNUSED) { virReportSystemError(ENOSYS, "%s", 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 c8dba05c31..f5f54653bb 100644 --- a/tests/virnetdevtest.c +++ b/tests/virnetdevtest.c @@ -75,7 +75,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) @@ -109,7 +109,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 @@ -210,6 +210,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 { @@ -230,13 +235,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 @@ -264,7 +283,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 Thu May 9 12:14:45 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of redhat.com designates 170.10.129.124 as permitted sender) client-ip=170.10.129.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.129.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.129.124]) by mx.zohomail.com with SMTPS id 1643704579579846.8079674774763; Tue, 1 Feb 2022 00:36:19 -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-623-EiVHTrSVM-y_zDjnO2aocA-1; Tue, 01 Feb 2022 03:36: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 17D361083F61; Tue, 1 Feb 2022 08:36: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 A51F15ED50; Tue, 1 Feb 2022 08:36:07 +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 9FFBB4BB7C; Tue, 1 Feb 2022 08:36:03 +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 2118Ymu3018487 for ; Tue, 1 Feb 2022 03:34:49 -0500 Received: by smtp.corp.redhat.com (Postfix) id AFF5740CFD20; Tue, 1 Feb 2022 08:34:48 +0000 (UTC) Received: from mimecast-mx02.redhat.com (mimecast08.extmail.prod.ext.rdu2.redhat.com [10.11.55.24]) by smtp.corp.redhat.com (Postfix) with ESMTPS id ABB8340CFD07 for ; Tue, 1 Feb 2022 08:34:48 +0000 (UTC) Received: from us-smtp-1.mimecast.com (us-smtp-delivery-1.mimecast.com [205.139.110.120]) (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 93B253806723 for ; Tue, 1 Feb 2022 08:34:48 +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-320-IKqHE_hKNmCPTLzTd2x1zw-1; Tue, 01 Feb 2022 03:34:47 -0500 Received: from mail-lj1-f197.google.com (mail-lj1-f197.google.com [209.85.208.197]) (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 171443F1A3 for ; Tue, 1 Feb 2022 08:28:57 +0000 (UTC) Received: by mail-lj1-f197.google.com with SMTP id u18-20020a2ea172000000b002393f377a13so5112851ljl.13 for ; Tue, 01 Feb 2022 00:28:57 -0800 (PST) Received: from ws.lan.d-node.is ([95.165.29.203]) by smtp.gmail.com with ESMTPSA id l5sm1074586lje.21.2022.02.01.00.28.55 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 01 Feb 2022 00:28:55 -0800 (PST) X-MC-Unique: EiVHTrSVM-y_zDjnO2aocA-1 X-MC-Unique: IKqHE_hKNmCPTLzTd2x1zw-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=YfEkvpPX3805UiZLC0AmTGUhJkrgH+UsgwoyDL7kSgk=; b=VWGsr6mBkEZOrYH0gY/o7SPQHIAObH8EXSMe4t8wzzt0v8MiSB0Rjx4TwjRAzqmAMC vtFGzyQFX0rG1RjRry2XsQqnyL+a0lAKf7u+74f+i5qm5wRnPE5eywUDL4ufyPio4nDh Byri7Qie0gvoq6wZeDz8JjKgsZwuoDalWPufrjf+i8EkgwmxH2o0Czw0ussJ7qKdMhlX 1lKrf4hw0KTQpeIVA9s/P40zEJh5vSJKcCIgn3iPANGW8C1YP6fLHydADksxFSa6Wrvi 6H6UpjDZZDYQ1nph5j3LdE4YsiLtMem3cfj0l3eLVSe6yr5wCXxGvN5h5REQWHnW7QRc Lp6w== X-Gm-Message-State: AOAM532Zkt257PhOIdJPwgOs1fMMgXhwHZhNFdyR8Du1z1VcVih531m2 xoreXrWJcYU7EU3pXyUXn8Wm3+/yxPA6Qw8D5NMK5GvSMKuyP2Qxe9yymg4v1LdLgDr2jJWYVIY k4eTDWiHaUPMAAH7Afs4AMvH5tw6us4d/vA== X-Received: by 2002:a05:6512:344a:: with SMTP id j10mr18580989lfr.467.1643704136507; Tue, 01 Feb 2022 00:28:56 -0800 (PST) X-Google-Smtp-Source: ABdhPJxug5bfC0UrIcs2evXObbRu5WYnXaww23+3IZGJ9hIzK3QlJhjxns55/QfrgI7xy1HlD+vwSg== X-Received: by 2002:a05:6512:344a:: with SMTP id j10mr18580978lfr.467.1643704136258; Tue, 01 Feb 2022 00:28:56 -0800 (PST) From: Dmitrii Shcherbakov To: dmitrii.shcherbakov@canonical.com, libvir-list@redhat.com Subject: [libvirt PATCH v8 3/3] Ignore EPERM on implicit clearing of VF VLAN ID Date: Tue, 1 Feb 2022 11:28:53 +0300 Message-Id: <20220201082853.147209-4-dmitrii.shcherbakov@canonical.com> In-Reply-To: <20220201082853.147209-1-dmitrii.shcherbakov@canonical.com> References: <20220201082853.147209-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 2118Ymu3018487 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: 1643704591967100001 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 | 14 ++++++++++++++ src/util/virnetdev.c | 11 ++++++++++- tests/virnetdevtest.c | 2 +- 3 files changed, 25 insertions(+), 2 deletions(-) diff --git a/NEWS.rst b/NEWS.rst index 666a593b58..f5453257ab 100644 --- a/NEWS.rst +++ b/NEWS.rst @@ -34,6 +34,20 @@ v8.1.0 (unreleased) to parse sysconfig files, in case they are created by the admin and fi= lled with the desired key=3Dvalue pairs. =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 eacdc3bf1f..cf9056f1bd 100644 --- a/src/util/virnetdev.c +++ b/src/util/virnetdev.c @@ -1613,12 +1613,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 f5f54653bb..d73eaec817 100644 --- a/tests/virnetdevtest.c +++ b/tests/virnetdevtest.c @@ -236,7 +236,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