From nobody Sun Feb 8 20:13:24 2026 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