From nobody Tue May 7 04:06:06 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1563267305; cv=none; d=zoho.com; s=zohoarc; b=ZT4N5U9PRXVQbhq4xM8tVQomTP2CqviAPG0ikio8HgZ9UotugkabYyJjhsnsu5LxFK6OL+rDyTCikmi6WBA1q4VdzgXyCnSNRUtRkYXxfunTt0DuSv7AfhaihQ4SCN42LMfYL6YAsK9bqK+cLevVuQisJlxzFAVzfuVngupRwQo= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1563267305; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=K1ACnfu5YX5LECRoPeLov8h1jcFbmNHTDLgbFTNpJFU=; b=ljIu/A05ZRHd0lwsZroTKgrfYL0aZvox2lrL3VN7d29LHRJ7StXh7Xix7AEbjfb7Ffy6MuIeJRCNmHIyXQiIZGCg2/RWKzAEnNLzIuCJ0pBF7K6ZBtziocBp4PHGg7p8Vd0uYVeTCsaV5xxGIV4Z9xpQtD18DBEREBcAJniQkw8= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1563267305098667.0164962389027; Tue, 16 Jul 2019 01:55:05 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 361C5335C8; Tue, 16 Jul 2019 08:55:03 +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 03CA8101E1D2; Tue, 16 Jul 2019 08:55:03 +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 96BB7180BACE; Tue, 16 Jul 2019 08:55:02 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x6G8shJ4004066 for ; Tue, 16 Jul 2019 04:54:44 -0400 Received: by smtp.corp.redhat.com (Postfix) id EE0631001DD7; Tue, 16 Jul 2019 08:54:43 +0000 (UTC) Received: from moe.brq.redhat.com (unknown [10.43.2.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id 793E51001DC3 for ; Tue, 16 Jul 2019 08:54:43 +0000 (UTC) From: Michal Privoznik To: libvir-list@redhat.com Date: Tue, 16 Jul 2019 10:54:33 +0200 Message-Id: <61902217e0524bb39819e781337974aaddb5165c.1563267063.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v2 1/4] virNetDevOpenvswitchInterfaceStats: Optimize for speed 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: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 16 Jul 2019 08:55:03 +0000 (UTC) Content-Type: text/plain; charset="utf-8" We run 'ovs-vsctl' nine times (first to find if interface is there and then eight times =3D for each stats member separately). This is very inefficient. I've found a way to run it once and with a bit of help from virJSON module we can parse out stats we need. Signed-off-by: Michal Privoznik Reviewed-by: J=C3=A1n Tomko --- src/util/virnetdevopenvswitch.c | 111 +++++++++++++++++++++----------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitc= h.c index c99ecfbf15..0fe64bedab 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -28,6 +28,7 @@ #include "virmacaddr.h" #include "virstring.h" #include "virlog.h" +#include "virjson.h" =20 #define VIR_FROM_THIS VIR_FROM_NONE =20 @@ -311,58 +312,94 @@ int virNetDevOpenvswitchInterfaceStats(const char *ifname, virDomainInterfaceStatsPtr stats) { - char *tmp; - bool gotStats =3D false; VIR_AUTOPTR(virCommand) cmd =3D NULL; VIR_AUTOFREE(char *) output =3D NULL; + VIR_AUTOPTR(virJSONValue) jsonStats =3D NULL; + virJSONValuePtr jsonMap =3D NULL; + size_t i; =20 - /* Just ensure the interface exists in ovs */ cmd =3D virCommandNew(OVSVSCTL); virNetDevOpenvswitchAddTimeout(cmd); - virCommandAddArgList(cmd, "get", "Interface", ifname, "name", NULL); + virCommandAddArgList(cmd, "--if-exists", "--format=3Dlist", "--data=3D= json", + "--no-headings", "--columns=3Dstatistics", "list", + "Interface", ifname, NULL); virCommandSetOutputBuffer(cmd, &output); =20 - if (virCommandRun(cmd, NULL) < 0) { + /* The above command returns either: + * 1) empty string if @ifname doesn't exist, or + * 2) a JSON array, for instance: + * ["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dr= opped",0], + * ["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packet= s",0], + * ["tx_bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets= ",173]]] + */ + + if (virCommandRun(cmd, NULL) < 0 || + STREQ_NULLABLE(output, "")) { /* no ovs-vsctl or interface 'ifname' doesn't exists in ovs */ virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Interface not found")); return -1; } =20 -#define GET_STAT(name, member) \ - do { \ - VIR_FREE(output); \ - virCommandFree(cmd); \ - cmd =3D virCommandNew(OVSVSCTL); \ - virNetDevOpenvswitchAddTimeout(cmd); \ - virCommandAddArgList(cmd, "--if-exists", "get", "Interface", \ - ifname, "statistics:" name, NULL); \ - virCommandSetOutputBuffer(cmd, &output); \ - if (virCommandRun(cmd, NULL) < 0 || !output || !*output || *output= =3D=3D '\n') { \ - stats->member =3D -1; \ - } else { \ - if (virStrToLong_ll(output, &tmp, 10, &stats->member) < 0 || \ - *tmp !=3D '\n') { \ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", \ - _("Fail to parse ovs-vsctl output")); \ - return -1; \ - } \ - gotStats =3D true; \ - } \ - } while (0) + if (!(jsonStats =3D virJSONValueFromString(output)) || + !virJSONValueIsArray(jsonStats) || + !(jsonMap =3D virJSONValueArrayGet(jsonStats, 1))) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Unable to parse ovs-vsctl output")); + return -1; + } =20 - /* The TX/RX fields appear to be swapped here - * because this is the host view. */ - GET_STAT("rx_bytes", tx_bytes); - GET_STAT("rx_packets", tx_packets); - GET_STAT("rx_errors", tx_errs); - GET_STAT("rx_dropped", tx_drop); - GET_STAT("tx_bytes", rx_bytes); - GET_STAT("tx_packets", rx_packets); - GET_STAT("tx_errors", rx_errs); - GET_STAT("tx_dropped", rx_drop); + stats->rx_bytes =3D stats->rx_packets =3D stats->rx_errs =3D stats->rx= _drop =3D -1; + stats->tx_bytes =3D stats->tx_packets =3D stats->tx_errs =3D stats->tx= _drop =3D -1; =20 - if (!gotStats) { + for (i =3D 0; i < virJSONValueArraySize(jsonMap); i++) { + virJSONValuePtr item =3D virJSONValueArrayGet(jsonMap, i); + virJSONValuePtr jsonKey; + virJSONValuePtr jsonVal; + const char *key; + long long val; + + if (!item || + (!(jsonKey =3D virJSONValueArrayGet(item, 0))) || + (!(jsonVal =3D virJSONValueArrayGet(item, 1))) || + (!(key =3D virJSONValueGetString(jsonKey))) || + (virJSONValueGetNumberLong(jsonVal, &val) < 0)) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Malformed ovs-vsctl output")); + return -1; + } + + /* The TX/RX fields appear to be swapped here + * because this is the host view. */ + if (STREQ(key, "rx_bytes")) { + stats->tx_bytes =3D val; + } else if (STREQ(key, "rx_packets")) { + stats->tx_packets =3D val; + } else if (STREQ(key, "rx_errors")) { + stats->tx_errs =3D val; + } else if (STREQ(key, "rx_dropped")) { + stats->tx_drop =3D val; + } else if (STREQ(key, "tx_bytes")) { + stats->rx_bytes =3D val; + } else if (STREQ(key, "tx_packets")) { + stats->rx_packets =3D val; + } else if (STREQ(key, "tx_errors")) { + stats->rx_errs =3D val; + } else if (STREQ(key, "tx_dropped")) { + stats->rx_drop =3D val; + } else { + VIR_DEBUG("Unused ovs-vsctl stat key=3D%s val=3D%lld", key, va= l); + } + } + + if (stats->rx_bytes =3D=3D -1 && + stats->rx_packets =3D=3D -1 && + stats->rx_errs =3D=3D -1 && + stats->rx_drop =3D=3D -1 && + stats->tx_bytes =3D=3D -1 && + stats->tx_packets =3D=3D -1 && + stats->tx_errs =3D=3D -1 && + stats->tx_drop =3D=3D -1) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", _("Interface doesn't have any statistics")); return -1; --=20 2.21.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Tue May 7 04:06:06 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1563267310; cv=none; d=zoho.com; s=zohoarc; b=Fo0RYZzLjQ564cQ0mp4VakN7Lfd6poLt8mr8h1rmIOMZ2hku0mptMLhxs2eBxOcTIw9lZvvnSNNiOvJcpzzNmBA/phHS70Xs3dInAG85r08KCoj03E65rMZvWBER13mn5V3766CCH0pKjKExPZuWsQWvvYrFKR4d5srqtavDwzs= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1563267310; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=KTKjLduZbNPTez+vX+OZ7hzxO+k0bxU5yeiJk3yxcwo=; b=N3h/5uFhf8jk8nlF2kKeUdfB1QDJKHEmXuzaCnUsKEriTmXkMa9pdL5hFreqKLbar8DL6mk/huVNaKEooiX7K9JcbLa6n8xH3LrUCKTarN4bijo2obDGkW5UU4uF4oEY4Uir7B6Jz+5yGTS0dHq6Wh/DdDW0QX7+v9z6PKCnVLE= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1563267310251544.3865561002633; Tue, 16 Jul 2019 01:55:10 -0700 (PDT) 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 mx1.redhat.com (Postfix) with ESMTPS id C7382B2DC7; Tue, 16 Jul 2019 08:55:07 +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 9DE1E5D784; Tue, 16 Jul 2019 08:55: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 4F13A4E590; Tue, 16 Jul 2019 08:55:07 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x6G8siUt004073 for ; Tue, 16 Jul 2019 04:54:44 -0400 Received: by smtp.corp.redhat.com (Postfix) id BA8C01001DDE; Tue, 16 Jul 2019 08:54:44 +0000 (UTC) Received: from moe.brq.redhat.com (unknown [10.43.2.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id 4693B1001DC3 for ; Tue, 16 Jul 2019 08:54:44 +0000 (UTC) From: Michal Privoznik To: libvir-list@redhat.com Date: Tue, 16 Jul 2019 10:54:34 +0200 Message-Id: <7b411c692ceb64d906644a48e062bed88d406be0.1563267063.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v2 2/4] test: Introduce virnetdevopenvswitchtest 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: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.26]); Tue, 16 Jul 2019 08:55:08 +0000 (UTC) Content-Type: text/plain; charset="utf-8" Test if our parsing of interface stats as returned by ovs-vsctl works as expected. To achieve this without having to mock virCommand* I'm separating parsing of stats into a separate function. Signed-off-by: Michal Privoznik Reviewed-by: J=C3=A1n Tomko --- src/libvirt_private.syms | 1 + src/util/virnetdevopenvswitch.c | 93 ++++++++++++------- src/util/virnetdevopenvswitch.h | 4 + tests/Makefile.am | 13 ++- tests/virnetdevopenvswitchdata/stats1.json | 1 + tests/virnetdevopenvswitchdata/stats2.json | 1 + tests/virnetdevopenvswitchtest.c | 101 +++++++++++++++++++++ 7 files changed, 177 insertions(+), 37 deletions(-) create mode 100644 tests/virnetdevopenvswitchdata/stats1.json create mode 100644 tests/virnetdevopenvswitchdata/stats2.json create mode 100644 tests/virnetdevopenvswitchtest.c diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 7dfa5af3b3..4e77cf53ea 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -2501,6 +2501,7 @@ virNetDevOpenvswitchAddPort; virNetDevOpenvswitchGetMigrateData; virNetDevOpenvswitchGetVhostuserIfname; virNetDevOpenvswitchInterfaceGetMaster; +virNetDevOpenvswitchInterfaceParseStats; virNetDevOpenvswitchInterfaceStats; virNetDevOpenvswitchRemovePort; virNetDevOpenvswitchSetMigrateData; diff --git a/src/util/virnetdevopenvswitch.c b/src/util/virnetdevopenvswitc= h.c index 0fe64bedab..2afc30f485 100644 --- a/src/util/virnetdevopenvswitch.c +++ b/src/util/virnetdevopenvswitch.c @@ -299,49 +299,30 @@ int virNetDevOpenvswitchSetMigrateData(char *migrate,= const char *ifname) return 0; } =20 + /** - * virNetDevOpenvswitchInterfaceStats: - * @ifname: the name of the interface - * @stats: the retrieved domain interface stat + * virNetDevOpenvswitchInterfaceParseStats: + * @json: Input string in JSON format + * @stats: parsed stats * - * Retrieves the OVS interfaces stats + * For given input string @json parse interface statistics and store them = into + * @stats. * - * Returns 0 in case of success or -1 in case of failure + * Returns: 0 on success, + * -1 otherwise (with error reported). */ int -virNetDevOpenvswitchInterfaceStats(const char *ifname, - virDomainInterfaceStatsPtr stats) +virNetDevOpenvswitchInterfaceParseStats(const char *json, + virDomainInterfaceStatsPtr stats) { - VIR_AUTOPTR(virCommand) cmd =3D NULL; - VIR_AUTOFREE(char *) output =3D NULL; VIR_AUTOPTR(virJSONValue) jsonStats =3D NULL; virJSONValuePtr jsonMap =3D NULL; size_t i; =20 - cmd =3D virCommandNew(OVSVSCTL); - virNetDevOpenvswitchAddTimeout(cmd); - virCommandAddArgList(cmd, "--if-exists", "--format=3Dlist", "--data=3D= json", - "--no-headings", "--columns=3Dstatistics", "list", - "Interface", ifname, NULL); - virCommandSetOutputBuffer(cmd, &output); + stats->rx_bytes =3D stats->rx_packets =3D stats->rx_errs =3D stats->rx= _drop =3D -1; + stats->tx_bytes =3D stats->tx_packets =3D stats->tx_errs =3D stats->tx= _drop =3D -1; =20 - /* The above command returns either: - * 1) empty string if @ifname doesn't exist, or - * 2) a JSON array, for instance: - * ["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dr= opped",0], - * ["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packet= s",0], - * ["tx_bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets= ",173]]] - */ - - if (virCommandRun(cmd, NULL) < 0 || - STREQ_NULLABLE(output, "")) { - /* no ovs-vsctl or interface 'ifname' doesn't exists in ovs */ - virReportError(VIR_ERR_INTERNAL_ERROR, "%s", - _("Interface not found")); - return -1; - } - - if (!(jsonStats =3D virJSONValueFromString(output)) || + if (!(jsonStats =3D virJSONValueFromString(json)) || !virJSONValueIsArray(jsonStats) || !(jsonMap =3D virJSONValueArrayGet(jsonStats, 1))) { virReportError(VIR_ERR_INTERNAL_ERROR, "%s", @@ -349,9 +330,6 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname, return -1; } =20 - stats->rx_bytes =3D stats->rx_packets =3D stats->rx_errs =3D stats->rx= _drop =3D -1; - stats->tx_bytes =3D stats->tx_packets =3D stats->tx_errs =3D stats->tx= _drop =3D -1; - for (i =3D 0; i < virJSONValueArraySize(jsonMap); i++) { virJSONValuePtr item =3D virJSONValueArrayGet(jsonMap, i); virJSONValuePtr jsonKey; @@ -392,6 +370,51 @@ virNetDevOpenvswitchInterfaceStats(const char *ifname, } } =20 + return 0; +} + +/** + * virNetDevOpenvswitchInterfaceStats: + * @ifname: the name of the interface + * @stats: the retrieved domain interface stat + * + * Retrieves the OVS interfaces stats + * + * Returns 0 in case of success or -1 in case of failure + */ +int +virNetDevOpenvswitchInterfaceStats(const char *ifname, + virDomainInterfaceStatsPtr stats) +{ + VIR_AUTOPTR(virCommand) cmd =3D NULL; + VIR_AUTOFREE(char *) output =3D NULL; + + cmd =3D virCommandNew(OVSVSCTL); + virNetDevOpenvswitchAddTimeout(cmd); + virCommandAddArgList(cmd, "--if-exists", "--format=3Dlist", "--data=3D= json", + "--no-headings", "--columns=3Dstatistics", "list", + "Interface", ifname, NULL); + virCommandSetOutputBuffer(cmd, &output); + + /* The above command returns either: + * 1) empty string if @ifname doesn't exist, or + * 2) a JSON array, for instance: + * ["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dr= opped",0], + * ["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packet= s",0], + * ["tx_bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets= ",173]]] + */ + + if (virCommandRun(cmd, NULL) < 0 || + STREQ_NULLABLE(output, "")) { + /* no ovs-vsctl or interface 'ifname' doesn't exists in ovs */ + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Interface not found")); + return -1; + } + + if (virNetDevOpenvswitchInterfaceParseStats(output, stats) < 0) + return -1; + if (stats->rx_bytes =3D=3D -1 && stats->rx_packets =3D=3D -1 && stats->rx_errs =3D=3D -1 && diff --git a/src/util/virnetdevopenvswitch.h b/src/util/virnetdevopenvswitc= h.h index 07496fb07d..5bc18f851f 100644 --- a/src/util/virnetdevopenvswitch.h +++ b/src/util/virnetdevopenvswitch.h @@ -49,6 +49,10 @@ int virNetDevOpenvswitchGetMigrateData(char **migrate, c= onst char *ifname) int virNetDevOpenvswitchSetMigrateData(char *migrate, const char *ifname) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK; =20 +int virNetDevOpenvswitchInterfaceParseStats(const char *json, + virDomainInterfaceStatsPtr sta= ts) + ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; + int virNetDevOpenvswitchInterfaceStats(const char *ifname, virDomainInterfaceStatsPtr stats) ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK; diff --git a/tests/Makefile.am b/tests/Makefile.am index 107f2de859..2cb78c1310 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -147,6 +147,7 @@ EXTRA_DIST =3D \ virmockstathelpers.c \ virnetdaemondata \ virnetdevtestdata \ + virnetdevopenvswitchdata \ virnetworkportxml2xmldata \ virnwfilterbindingxml2xmldata \ virpcitestdata \ @@ -1271,9 +1272,17 @@ virmacmaptest_SOURCES =3D \ virmacmaptest.c testutils.h testutils.c virmacmaptest_LDADD =3D $(LDADDS) =20 -test_programs +=3D virmacmaptest +virnetdevopenvswitchtest_SOURCES =3D \ + virnetdevopenvswitchtest.c testutils.h testutils.c +virnetdevopenvswitchtest_LDADD =3D $(LDADDS) + +test_programs +=3D \ + virmacmaptest \ + virnetdevopenvswitchtest else ! WITH_YAJL -EXTRA_DIST +=3D virmacmaptest.c +EXTRA_DIST +=3D \ + virmacmaptest.c \ + virnetdevopenvswitchtest.c endif ! WITH_YAJL =20 virnetdevtest_SOURCES =3D \ diff --git a/tests/virnetdevopenvswitchdata/stats1.json b/tests/virnetdevop= envswitchdata/stats1.json new file mode 100644 index 0000000000..1138c6271e --- /dev/null +++ b/tests/virnetdevopenvswitchdata/stats1.json @@ -0,0 +1 @@ +["map",[["collisions",1],["rx_bytes",2],["rx_crc_err",3],["rx_dropped",4],= ["rx_errors",5],["rx_frame_err",6],["rx_over_err",7],["rx_packets",8],["tx_= bytes",9],["tx_dropped",10],["tx_errors",11],["tx_packets",12]]] diff --git a/tests/virnetdevopenvswitchdata/stats2.json b/tests/virnetdevop= envswitchdata/stats2.json new file mode 100644 index 0000000000..d84be7e011 --- /dev/null +++ b/tests/virnetdevopenvswitchdata/stats2.json @@ -0,0 +1 @@ +["map",[["collisions",0],["rx_bytes",0],["rx_crc_err",0],["rx_dropped",0],= ["rx_errors",0],["rx_frame_err",0],["rx_over_err",0],["rx_packets",0],["tx_= bytes",12406],["tx_dropped",0],["tx_errors",0],["tx_packets",173]]] diff --git a/tests/virnetdevopenvswitchtest.c b/tests/virnetdevopenvswitcht= est.c new file mode 100644 index 0000000000..f01e77cbba --- /dev/null +++ b/tests/virnetdevopenvswitchtest.c @@ -0,0 +1,101 @@ +/* + * Copyright (C) 2019 Red Hat, Inc. + * + * 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 + * . + */ + +#include + +#include "testutils.h" +#include "virnetdevopenvswitch.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +typedef struct _InterfaceParseStatsData InterfaceParseStatsData; +struct _InterfaceParseStatsData { + const char *filename; + const virDomainInterfaceStatsStruct stats; +}; + + +static int +testInterfaceParseStats(const void *opaque) +{ + const InterfaceParseStatsData *data =3D opaque; + VIR_AUTOFREE(char *) filename =3D NULL; + VIR_AUTOFREE(char *) buf =3D NULL; + virDomainInterfaceStatsStruct actual; + + if (virAsprintf(&filename, "%s/virnetdevopenvswitchdata/%s", + abs_srcdir, data->filename) < 0) + return -1; + + if (virFileReadAll(filename, 1024, &buf) < 0) + return -1; + + if (virNetDevOpenvswitchInterfaceParseStats(buf, &actual) < 0) + return -1; + + if (memcmp(&actual, &data->stats, sizeof(actual)) !=3D 0) { + fprintf(stderr, + "Expected stats: %lld %lld %lld %lld %lld %lld %lld %lld\n" + "Actual stats: %lld %lld %lld %lld %lld %lld %lld %lld", + data->stats.rx_bytes, + data->stats.rx_packets, + data->stats.rx_errs, + data->stats.rx_drop, + data->stats.tx_bytes, + data->stats.tx_packets, + data->stats.tx_errs, + data->stats.tx_drop, + actual.rx_bytes, + actual.rx_packets, + actual.rx_errs, + actual.rx_drop, + actual.tx_bytes, + actual.tx_packets, + actual.tx_errs, + actual.tx_drop); + + return -1; + } + + return 0; +} + + +static int +mymain(void) +{ + int ret =3D 0; + +#define TEST_INTERFACE_STATS(file, \ + rxBytes, rxPackets, rxErrs, rxDrop, \ + txBytes, txPackets, txErrs, txDrop) \ + do { \ + const InterfaceParseStatsData data =3D {.filename =3D file, .stats= =3D { \ + rxBytes, rxPackets, rxErrs, rxDrop, \ + txBytes, txPackets, txErrs, txDrop}}; \ + if (virTestRun("Interface stats " file, testInterfaceParseStats, &= data) < 0) \ + ret =3D -1; \ + } while (0) + + TEST_INTERFACE_STATS("stats1.json", 9, 12, 11, 10, 2, 8, 5, 4); + TEST_INTERFACE_STATS("stats2.json", 12406, 173, 0, 0, 0, 0, 0, 0); + + return ret =3D=3D 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIR_TEST_MAIN(mymain); --=20 2.21.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Tue May 7 04:06:06 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1563267291; cv=none; d=zoho.com; s=zohoarc; b=HayTVgqWJZ0A8esLKqVMmmFsX3M2h1RTHjHPcupHgeVask3VVOwC4hv6PzwGtFsL2geQNHnjeCGTm5WmEX7dsvXUBkBMvxU5gHy6YhxTx3WPaWE/vbwdweqwmkvaINwAJWTgQTthaG3/vhTu6MYJNp8vyqfSNSvbGT2M6elqOF0= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1563267291; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=QTsN1VSU2Xd6f49pNEdxH39Q1pvJtpGu38MnGewPlts=; b=jPp+R1wLX4KuwHaYT6Jv7xXCVoN966gVeqCCFRp/C59wKJMRD2G1G4bhf71GlMCVpO4S33s/CSkTpDhzHTLX2+Y96Z0fnOA2DHaFMdQi1hQ82vWpkZL7NKlwj2gE0zZW26uz6vQMcsaOhKqueAYLwCPRUvV0h0k4kV4d2JeK+nE= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1563267291849164.74449257002902; Tue, 16 Jul 2019 01:54:51 -0700 (PDT) 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 mx1.redhat.com (Postfix) with ESMTPS id 60087308FEC0; Tue, 16 Jul 2019 08:54:49 +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 222CA5D71B; Tue, 16 Jul 2019 08:54:49 +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 482784E58F; Tue, 16 Jul 2019 08:54:48 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x6G8sj7Q004082 for ; Tue, 16 Jul 2019 04:54:45 -0400 Received: by smtp.corp.redhat.com (Postfix) id 8C3F010A33D1; Tue, 16 Jul 2019 08:54:45 +0000 (UTC) Received: from moe.brq.redhat.com (unknown [10.43.2.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id 12C4E108418D for ; Tue, 16 Jul 2019 08:54:44 +0000 (UTC) From: Michal Privoznik To: libvir-list@redhat.com Date: Tue, 16 Jul 2019 10:54:35 +0200 Message-Id: <7880f10a1805f0d98feb24ac6b4c7fb77ae9edf2.1563267063.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v2 3/4] vircommand: Separate mass FD closing into a function 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: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.49]); Tue, 16 Jul 2019 08:54:50 +0000 (UTC) I will optimize this code a bit in the next commit. But for that it is better if the code lives in a separate function. Signed-off-by: Michal Privoznik Reviewed-by: J=C3=A1n Tomko --- src/util/vircommand.c | 52 ++++++++++++++++++++++++++++--------------- 1 file changed, 34 insertions(+), 18 deletions(-) diff --git a/src/util/vircommand.c b/src/util/vircommand.c index c81ddfc0d0..6cd7cbe065 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -418,6 +418,37 @@ virExecCommon(virCommandPtr cmd, gid_t *groups, int ng= roups) return ret; } =20 +static int +virCommandMassClose(virCommandPtr cmd, + int childin, + int childout, + int childerr) +{ + int openmax =3D sysconf(_SC_OPEN_MAX); + int fd; + int tmpfd; + + if (openmax < 0) { + virReportSystemError(errno, "%s", + _("sysconf(_SC_OPEN_MAX) failed")); + return -1; + } + + for (fd =3D 3; fd < openmax; fd++) { + if (fd =3D=3D childin || fd =3D=3D childout || fd =3D=3D childerr) + continue; + if (!virCommandFDIsSet(cmd, fd)) { + tmpfd =3D fd; + VIR_MASS_CLOSE(tmpfd); + } else if (virSetInherit(fd, true) < 0) { + virReportSystemError(errno, _("failed to preserve fd %d"), fd); + return -1; + } + } + + return 0; +} + /* * virExec: * @cmd virCommandPtr containing all information about the program to @@ -427,13 +458,12 @@ static int virExec(virCommandPtr cmd) { pid_t pid; - int null =3D -1, fd, openmax; + int null =3D -1; int pipeout[2] =3D {-1, -1}; int pipeerr[2] =3D {-1, -1}; int childin =3D cmd->infd; int childout =3D -1; int childerr =3D -1; - int tmpfd; VIR_AUTOFREE(char *) binarystr =3D NULL; const char *binary =3D NULL; int ret; @@ -539,23 +569,9 @@ virExec(virCommandPtr cmd) if (cmd->mask) umask(cmd->mask); ret =3D EXIT_CANCELED; - openmax =3D sysconf(_SC_OPEN_MAX); - if (openmax < 0) { - virReportSystemError(errno, "%s", - _("sysconf(_SC_OPEN_MAX) failed")); + + if (virCommandMassClose(cmd, childin, childout, childerr) < 0) goto fork_error; - } - for (fd =3D 3; fd < openmax; fd++) { - if (fd =3D=3D childin || fd =3D=3D childout || fd =3D=3D childerr) - continue; - if (!virCommandFDIsSet(cmd, fd)) { - tmpfd =3D fd; - VIR_MASS_CLOSE(tmpfd); - } else if (virSetInherit(fd, true) < 0) { - virReportSystemError(errno, _("failed to preserve fd %d"), fd); - goto fork_error; - } - } =20 if (prepareStdFd(childin, STDIN_FILENO) < 0) { virReportSystemError(errno, --=20 2.21.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Tue May 7 04:06:06 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com ARC-Seal: i=1; a=rsa-sha256; t=1563267313; cv=none; d=zoho.com; s=zohoarc; b=efW0qzjPgr29DgPrUjpceafnYcsZcYBEP2whpxWWksYxh9fc8Iam1mpwWjDOGO0gUrnfu7Eul9pSzEACuDYpb/1Guw4PW/oR54XgmYS6OFl5QzoqcAysPuUcYDJlWf+bm5ulGDBzmM7LjaiZCJX2fACzQSdnSfij49B1pdwlKpM= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zoho.com; s=zohoarc; t=1563267313; h=Content-Type:Content-Transfer-Encoding:Date:From:In-Reply-To:List-Subscribe:List-Post:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:References:Sender:Subject:To:ARC-Authentication-Results; bh=8tgvsf2p548pS1RqornRYI3lhN9scJ4wm3m5qsciKPQ=; b=WYJsUR/W6zz66xbtKdn/QVhwQ5MuvpzDFGaUP+Xz3HBRs4uTub8/iGfkhcHiUav03aXaWU/HVZBDNpA/0RKP6v5HxC8K5kNG6KADnGoDmmssEKJ/iqGsEgODu8sM50qvEWV4eIevd1vRxjCCqeoJt1nI17qQV4SVczUibo/ugXE= ARC-Authentication-Results: i=1; mx.zoho.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass header.from= (p=none dis=none) header.from= Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1563267313649631.9297314307465; Tue, 16 Jul 2019 01:55:13 -0700 (PDT) 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 mx1.redhat.com (Postfix) with ESMTPS id 0C75B3082134; Tue, 16 Jul 2019 08:55: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 D06C219C71; Tue, 16 Jul 2019 08:55:11 +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 8BEF24EA32; Tue, 16 Jul 2019 08:55:11 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx07.intmail.prod.int.phx2.redhat.com [10.5.11.22]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id x6G8sk9M004089 for ; Tue, 16 Jul 2019 04:54:46 -0400 Received: by smtp.corp.redhat.com (Postfix) id 587FC108418D; Tue, 16 Jul 2019 08:54:46 +0000 (UTC) Received: from moe.brq.redhat.com (unknown [10.43.2.30]) by smtp.corp.redhat.com (Postfix) with ESMTP id D81DD10A402C for ; Tue, 16 Jul 2019 08:54:45 +0000 (UTC) From: Michal Privoznik To: libvir-list@redhat.com Date: Tue, 16 Jul 2019 10:54:36 +0200 Message-Id: <0d01b55f8270f60f27150c3d3e928df2745dbf01.1563267063.git.mprivozn@redhat.com> In-Reply-To: References: MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.84 on 10.5.11.22 X-loop: libvir-list@redhat.com Subject: [libvirt] [PATCH v2 4/4] virCommand: use procfs to learn opened FDs 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: , Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.23 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.42]); Tue, 16 Jul 2019 08:55:12 +0000 (UTC) Content-Type: text/plain; charset="utf-8" When spawning a child process, between fork() and exec() we close all file descriptors and keep only those the caller wants us to pass onto the child. The problem is how we do that. Currently, we get the limit of opened files and then iterate through each one of them and either close() it or make it survive exec(). This approach is suboptimal (although, not that much in default configurations where the limit is pretty low - 1024). We have /proc where we can learn what FDs we hold open and thus we can selectively close only those. Signed-off-by: Michal Privoznik Reviewed-by: J=C3=A1n Tomko --- src/util/vircommand.c | 86 +++++++++++++++++++++++++++++++++++++++---- 1 file changed, 78 insertions(+), 8 deletions(-) diff --git a/src/util/vircommand.c b/src/util/vircommand.c index 6cd7cbe065..bfc6c15cfb 100644 --- a/src/util/vircommand.c +++ b/src/util/vircommand.c @@ -418,27 +418,97 @@ virExecCommon(virCommandPtr cmd, gid_t *groups, int n= groups) return ret; } =20 +# ifdef __linux__ +/* On Linux, we can utilize procfs and read the table of opened + * FDs and selectively close only those FDs we don't want to pass + * onto child process (well, the one we will exec soon since this + * is called from the child). */ +static int +virCommandMassCloseGetFDsLinux(virCommandPtr cmd ATTRIBUTE_UNUSED, + virBitmapPtr fds) +{ + DIR *dp =3D NULL; + struct dirent *entry; + const char *dirName =3D "/proc/self/fd"; + int rc; + int ret =3D -1; + + if (virDirOpen(&dp, dirName) < 0) + return -1; + + while ((rc =3D virDirRead(dp, &entry, dirName)) > 0) { + int fd; + + if (virStrToLong_i(entry->d_name, NULL, 10, &fd) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to parse FD: %s"), + entry->d_name); + goto cleanup; + } + + if (virBitmapSetBit(fds, fd) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("unable to set FD as open: %d"), + fd); + goto cleanup; + } + } + + if (rc < 0) + goto cleanup; + + ret =3D 0; + cleanup: + VIR_DIR_CLOSE(dp); + return ret; +} + +# else /* !__linux__ */ + +static int +virCommandMassCloseGetFDsGeneric(virCommandPtr cmd ATTRIBUTE_UNUSED, + virBitmapPtr fds) +{ + virBitmapSetAll(fds); + return 0; +} +# endif /* !__linux__ */ + static int virCommandMassClose(virCommandPtr cmd, int childin, int childout, int childerr) { + VIR_AUTOPTR(virBitmap) fds =3D NULL; int openmax =3D sysconf(_SC_OPEN_MAX); - int fd; - int tmpfd; + int fd =3D -1; =20 - if (openmax < 0) { - virReportSystemError(errno, "%s", - _("sysconf(_SC_OPEN_MAX) failed")); + /* In general, it is not save to call malloc() between fork() and exec= () + * because the child might have forked at the worst possible time, i.e. + * when another thread was in malloc() and thus held its lock. That is= to + * say, POSIX does not mandate malloc() to be async-safe. Fortunately, + * glibc developers are aware of this and made malloc() async-safe. + * Therefore we can safely allocate memory here (and transitively call + * opendir/readdir) without a deadlock. */ + + if (!(fds =3D virBitmapNew(openmax))) + return -1; + +# ifdef __linux__ + if (virCommandMassCloseGetFDsLinux(cmd, fds) < 0) + return -1; +# else + if (virCommandMassCloseGetFDsGeneric(cmd, fds) < 0) return -1; - } +# endif =20 - for (fd =3D 3; fd < openmax; fd++) { + fd =3D virBitmapNextSetBit(fds, -1); + for (; fd >=3D 0; fd =3D virBitmapNextSetBit(fds, fd)) { if (fd =3D=3D childin || fd =3D=3D childout || fd =3D=3D childerr) continue; if (!virCommandFDIsSet(cmd, fd)) { - tmpfd =3D fd; + int tmpfd =3D fd; VIR_MASS_CLOSE(tmpfd); } else if (virSetInherit(fd, true) < 0) { virReportSystemError(errno, _("failed to preserve fd %d"), fd); --=20 2.21.0 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list