From nobody Sun May 5 19:06:02 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zoho.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1492592715261478.5502531666565; Wed, 19 Apr 2017 02:05:15 -0700 (PDT) Received: from localhost ([::1]:46518 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d0lY1-0000aW-UB for importer@patchew.org; Wed, 19 Apr 2017 05:05:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:37525) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d0lWr-0008My-08 for qemu-devel@nongnu.org; Wed, 19 Apr 2017 05:04:02 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1d0lWk-0003mw-Ni for qemu-devel@nongnu.org; Wed, 19 Apr 2017 05:04:01 -0400 Received: from mx7.zte.com.cn ([202.103.147.169]:46939) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1d0lWj-0003m5-SZ for qemu-devel@nongnu.org; Wed, 19 Apr 2017 05:03:54 -0400 Received: from unknown (HELO mse01.zte.com.cn) (10.30.3.20) by localhost with (AES256-SHA encrypted) SMTP; 19 Apr 2017 08:58:50 -0000 Received: from notes_smtp.zte.com.cn ([10.30.1.239]) by mse01.zte.com.cn with ESMTP id v3J92dsm030885; Wed, 19 Apr 2017 17:02:39 +0800 (GMT-8) (envelope-from lu.zhipeng@zte.com.cn) Received: from ceshi.localdomain ([10.74.120.130]) by szsmtp06.zte.com.cn (Lotus Domino Release 8.5.3FP6) with ESMTP id 2017041917024382-961026 ; Wed, 19 Apr 2017 17:02:43 +0800 X-scanvirus: By SEG_CYREN AntiVirus Engine X-scanresult: CLEAN X-MAILFROM: X-RCPTTO: X-FROMIP: 10.30.3.20 X-SEG-Scaned: 1 X-Received: unknown,10.30.3.20,20170419165850 From: ZhiPeng Lu To: mdroth@linux.vnet.ibm.com Date: Thu, 20 Apr 2017 00:57:08 +0800 Message-Id: <1492621028-16280-1-git-send-email-lu.zhipeng@zte.com.cn> X-Mailer: git-send-email 1.8.3.1 X-MIMETrack: Itemize by SMTP Server on SZSMTP06/server/zte_ltd(Release 8.5.3FP6|November 21, 2013) at 2017-04-19 17:02:43, Serialize by Router on notes_smtp/zte_ltd(Release 8.5.3FP6|November 21, 2013) at 2017-04-19 17:02:20, Serialize complete at 2017-04-19 17:02:20 X-MAIL: mse01.zte.com.cn v3J92dsm030885 X-HQIP: 127.0.0.1 X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.6.x [fuzzy] X-Received-From: 202.103.147.169 Subject: [Qemu-devel] [PATCH] qemu-ga: add guest-network-get-interface-stat command X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: ZhiPeng Lu , qemu-devel@nongnu.org Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" we can get the network card statistics inside a virtual machine by guest-= network-get-interface-stat command. it is very userful for us to monitor and analyze network traff. Signed-off-by: ZhiPeng Lu --- qga/commands-posix.c | 166 +++++++++++++++++++++++++++++++++++++++++++++++= +++- qga/commands-win32.c | 6 ++ qga/qapi-schema.json | 34 +++++++++++ 3 files changed, 205 insertions(+), 1 deletion(-) diff --git a/qga/commands-posix.c b/qga/commands-posix.c index 915df9e..3166bf4 100644 --- a/qga/commands-posix.c +++ b/qga/commands-posix.c @@ -2357,6 +2357,163 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_in= fo(Error **errp) =20 return info; } +static int ga_get_netname(int bus, int dev, int func, char *netname, + int name_len) +{ + int cnt =3D 0; + int result =3D -1; + + FILE *pfilein =3D NULL; + + bool findnet =3D false; + char *netpos =3D NULL; + + char netstr[32] =3D {0}; + char buffer[1024] =3D {0}; + + if (NULL =3D=3D netname) { + return -1; + } + snprintf(netstr, 31, "%02x:%02x.%01x", bus, dev, func); + g_debug("qga net pci is : %s ", netstr); + + pfilein =3D popen("ls -l /sys/class/net", "r"); + if (NULL =3D=3D pfilein) { + g_debug("failed to do shell command for [%s] getting net name", ne= tstr); + return -1; + } + + while (fgets(buffer, 1023, pfilein) !=3D NULL) { + if (strstr(buffer, netstr)) { + findnet =3D true; + g_debug("find pci [%s] net string: %s", netstr, buffer); + break; + } + } + + result =3D ferror(pfilein); + if (pclose(pfilein) || result) { + g_debug("error happened while finding pci [%s] net string", netstr= ); + return -1; + } + + if (!findnet) { + g_debug("didn't finding bdf [%s] block string", netstr); + return -1; + } + + netpos =3D strrchr(buffer, '/'); + if (NULL =3D=3D netpos) { + g_debug("can't get net name for [%s]", netstr); + return -1; + } + + netpos++; + if (name_len < strlen(netpos)) { + g_debug("net name buffer of [%s] is not enough", netstr); + return -1; + } + + cnt =3D 0; + while (('\0' !=3D *netpos) && ('\n' !=3D *netpos)) { + netname[cnt] =3D *netpos; + cnt++; + netpos++; + } + netname[cnt] =3D '\0'; + + if ('\0' =3D=3D netname[0]) { + g_debug("net name for pci [%s] is invalid", netstr); + return -1; + } + + g_debug("succeed to get pci [%s] actual net name: %s", netstr, netname= ); + return 0; +} + + +static int ga_get_net_stats(const char *path, + GuestNetworkInterfaceStat *stats) +{ + int path_len; + FILE *fp; + char line[256], *colon; + + fp =3D fopen("/proc/net/dev", "r"); + if (!fp) { + slog("Could not open /proc/net/dev"); + return -1; + } + path_len =3D strlen(path); + while (fgets(line, sizeof(line), fp)) { + long long dummy; + long long rx_bytes; + long long rx_packets; + long long rx_errs; + long long rx_drop; + long long tx_bytes; + long long tx_packets; + long long tx_errs; + long long tx_drop; + + /* The line looks like: + * * " eth0:..." + * * Split it at the colon. + * */ + colon =3D strchr(line, ':'); + if (!colon) { + continue; + } + *colon =3D '\0'; + if (colon - path_len >=3D line && strcmp(colon - path_len, path) = =3D=3D 0) { + if (sscanf(colon + 1, + "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %l= ld %lld %lld %lld %lld", + &rx_bytes, &rx_packets, &rx_errs, &rx_drop, + &dummy, &dummy, &dummy, &dummy, + &tx_bytes, &tx_packets, &tx_errs, &tx_drop, + &dummy, &dummy, &dummy, &dummy) !=3D 16) { + continue; + } + stats->rx_bytes =3D rx_bytes; + stats->rx_packets =3D rx_packets; + stats->rx_errs =3D rx_errs; + stats->rx_drop =3D rx_drop; + stats->tx_bytes =3D tx_bytes; + stats->tx_packets =3D tx_packets; + stats->tx_errs =3D tx_errs; + stats->tx_drop =3D tx_drop; + fclose(fp); + return 0; + } + } + fclose(fp); + + g_debug("/proc/net/dev: Interface not found"); + return -1; +} + +GuestNetworkInterfaceStatList *qmp_guest_network_get_interface_stat(int64_= t bus, + int64_t slot, int64_t function, const char *netname, Error **errp) +{ + char guestnetname[14] =3D {0}; + GuestNetworkInterfaceStat *info =3D NULL; + GuestNetworkInterfaceStatList *new, *ret =3D NULL; + if (ga_get_netname(bus, slot, + function, guestnetname, sizeof(guestnetname))) { + return NULL; + } + info =3D g_malloc0(sizeof(*info)); + if (ga_get_net_stats(guestnetname, info)) { + g_free(info); + return NULL; + } + + new =3D g_malloc(sizeof(*ret)); + new->value =3D info; + new->next =3D ret; + ret =3D new; + return ret; +} =20 #else /* defined(__linux__) */ =20 @@ -2419,6 +2576,12 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_inf= o(Error **errp) error_setg(errp, QERR_UNSUPPORTED); return NULL; } +GuestNetworkInterfaceStatList *qmp_guest_network_get_interface_stat(int64_= t bus, + int64_t slot, int64_t function, const char *netname, Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} =20 #endif =20 @@ -2480,7 +2643,8 @@ GList *ga_command_blacklist_init(GList *blacklist) "guest-suspend-hybrid", "guest-network-get-interfaces", "guest-get-vcpus", "guest-set-vcpus", "guest-get-memory-blocks", "guest-set-memory-blocks", - "guest-get-memory-block-size", NULL}; + "guest-get-memory-block-size", + "guest-network-get-interfaces-stat", NULL}; char **p =3D (char **)list; =20 while (*p) { diff --git a/qga/commands-win32.c b/qga/commands-win32.c index 19d72b2..dee939c 100644 --- a/qga/commands-win32.c +++ b/qga/commands-win32.c @@ -1497,6 +1497,12 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_inf= o(Error **errp) error_setg(errp, QERR_UNSUPPORTED); return NULL; } +GuestNetworkInterfaceStatList *qmp_guest_network_get_interface_stat(int64_= t bus, + int64_t slot, int64_t function, const char *netname, Error **errp) +{ + error_setg(errp, QERR_UNSUPPORTED); + return NULL; +} =20 /* add unsupported commands to the blacklist */ GList *ga_command_blacklist_init(GList *blacklist) diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json index a02dbf2..60111dc 100644 --- a/qga/qapi-schema.json +++ b/qga/qapi-schema.json @@ -1042,3 +1042,37 @@ 'data': { 'path': 'str', '*arg': ['str'], '*env': ['str'], '*input-data': 'str', '*capture-output': 'bool' }, 'returns': 'GuestExec' } +## +# @GuestNetworkInterfaceStat: +# +# @rx_bytes: received bytes of interface +# +# @rx_packets: received packets of interface +# +# @rx_errs: received error packets of interface +# @rx_drop: received drop packets of interface +# +# Since: 2.10 +## +{ 'struct': 'GuestNetworkInterfaceStat', + 'data': {'rx_bytes': 'uint64', + 'rx_packets': 'uint64', + 'rx_errs': 'uint64', + 'rx_drop': 'uint64', + 'tx_bytes': 'uint64', + 'tx_packets': 'uint64', + 'tx_errs': 'uint64', + 'tx_drop': 'uint64' + } } +## +# @guest-network-get-interface-stat: +# +# Get list of interface stat +# +# Returns: List of GuestNetworkInterfaceStat on success. +# +# Since: 2.10 +## +{ 'command': 'guest-network-get-interface-stat', + 'data': {'bus': 'int64', 'slot': 'int64', 'function': 'int64','netnam= e':'str'}, + 'returns': ['GuestNetworkInterfaceStat'] } --=20 1.8.3.1