Quoting lu.zhip...@zte.com.cn (2017-10-25 20:42:10)
> 
> >> +    if (NO_ERROR == GetIfEntry(&aMib_ifrow)) {
> 
> 
> thanks,
> 
> I found may be overflow using GetIfEntry,thus GetIfEntry2 instead of 
> GetIfEntry.

I tried your fix-up patch at:
 https://patch-diff.githubusercontent.com/raw/mdroth/qemu/pull/5.patch

but ran into the compile issue below in a Fedora 20 mingw64 build environment.
It looks like you need MIB_IF_ROW2 instead of MIB_IFROW2, and even then it
looks like the struct fields are different and need to be fixed up.

I'll keep the current patch as it stands, but please send a tested
standalone fix against the qga tree to the list so we can get this case
addressed before rc0. I would also suggest we disable w32 stats completely
if GetIfEntry2() isn't available, since dealing with overflows is painful
from a management perspective.


x86_64-w64-mingw32-gcc -I/home/mdroth/qemu-build-w64/qga -Iqga 
-I/home/mdroth/w/qemu4.git/tcg -I/home/mdroth/w/qemu4.git/tcg/i386 -I. 
-I/home/mdroth/w/qemu4.git -I/home/mdroth/w/qemu4.git/accel/tcg 
-I/home/mdroth/w/qemu4.git/include 
-I/usr/x86_64-w64-mingw32/sys-root/mingw/include/pixman-1  
-I/home/mdroth/w/qemu4.git/dtc/libfdt -Werror -mms-bitfields 
-I/usr/x86_64-w64-mingw32/sys-root/mingw/include/glib-2.0 
-I/usr/x86_64-w64-mingw32/sys-root/mingw/lib/glib-2.0/include  -m64 -mcx16 
-mthreads -D__USE_MINGW_ANSI_STDIO=1 -DWIN32_LEAN_AND_MEAN -DWINVER=0x501 
-D_GNU_SOURCE -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wstrict-prototypes 
-Wredundant-decls -Wall -Wundef -Wwrite-strings -Wmissing-prototypes 
-fno-strict-aliasing -fno-common -fwrapv  -Wall -Wendif-labels 
-Wno-missing-include-dirs -Wempty-body -Wnested-externs -Wformat-security 
-Wformat-y2k -Winit-self -Wignored-qualifiers -Wold-style-declaration 
-Wold-style-definition -Wtype-limits -fstack-protector-all -isystem 
/home/mdroth/w/vss-win32/ -I/home/mdroth/w/qemu4.git/tests -I 
qga/qapi-generated -MMD -MP -MT qga/service-win32.o -MF qga/service-win32.d -O2 
-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 -g   -c -o qga/service-win32.o 
/home/mdroth/w/qemu4.git/qga/service-win32.c
/home/mdroth/w/qemu4.git/qga/commands-win32.c: In function 
'guest_get_network_stats':
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1200:20: error: 'MIB_IF_ROW2' has 
no member named 'dwIndex'
         a_mid_ifrow.dwIndex = if_index;
                    ^
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1202:42: error: 'MIB_IF_ROW2' has 
no member named 'dwInOctets'
             stats->rx_bytes = a_mid_ifrow.dwInOctets;
                                          ^
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1203:44: error: 'MIB_IF_ROW2' has 
no member named 'dwInUcastPkts'
             stats->rx_packets = a_mid_ifrow.dwInUcastPkts;
                                            ^
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1204:41: error: 'MIB_IF_ROW2' has 
no member named 'dwInErrors'
             stats->rx_errs = a_mid_ifrow.dwInErrors;
                                         ^
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1205:44: error: 'MIB_IF_ROW2' has 
no member named 'dwInDiscards'
             stats->rx_dropped = a_mid_ifrow.dwInDiscards;
                                            ^
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1206:42: error: 'MIB_IF_ROW2' has 
no member named 'dwOutOctets'
             stats->tx_bytes = a_mid_ifrow.dwOutOctets;
                                          ^
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1207:44: error: 'MIB_IF_ROW2' has 
no member named 'dwOutUcastPkts'
             stats->tx_packets = a_mid_ifrow.dwOutUcastPkts;
                                            ^
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1208:41: error: 'MIB_IF_ROW2' has 
no member named 'dwOutErrors'
             stats->tx_errs = a_mid_ifrow.dwOutErrors;
                                         ^
/home/mdroth/w/qemu4.git/qga/commands-win32.c:1209:44: error: 'MIB_IF_ROW2' has 
no member named 'dwOutDiscards'
             stats->tx_dropped = a_mid_ifrow.dwOutDiscards;
                                            ^
make: *** [qga/commands-win32.o] Error 1
make: *** Waiting for unfinished jobs....

> 
> 
> 为了让您的VPlat虚拟机故障和docker故障得到高效的处理,请上报故障到: $VPlat技术支
> 持。
> 
> 芦志朋 luzhipeng
> 
> 
> IT开发工程师 IT Development Engineer
> 操作系统产品部/中心研究院/系统产品 OS Product Dept./Central R&D Institute/
> System Product
> 
> 
> [cid]          [cid]
>                四川省成都市天府大道中段800号
>                E: lu.zhip...@zte.com.cn
>                www.zte.com.cn
> 
> 原始邮件
> 发件人: <mdr...@linux.vnet.ibm.com>;
> 收件人:芦志朋10108272;
> 抄送人: <qemu-devel@nongnu.org>;芦志朋10108272;
> 日期:2017年10月26日 09:00
> 主题:Re: [PATCH v7 RESEND] qga: Add support network interface statistics
> inguest-network-get-interfaces command
> 
> 
> Quoting ZhiPeng Lu (2017-09-12 03:54:26)
> > we can get the network interface statistics inside a virtual machine by
> > guest-network-get-interfaces command. it is very useful for us to monitor
> > and analyze network traffic.
> > 
> > Signed-off-by: ZhiPeng Lu <lu.zhip...@zte.com.cn>
> 
> Thanks, applied to qga tree:
>   https://github.com/mdroth/qemu/commits/qga
> 
> There were a few issues that I noted below, but I tested on linux/windows
> and things seem to be working well so I fixed them up in my tree.
> 
> > 
> > ---
> > v1->v2:
> >  - correct some spelling mistake and add the stats data to the
> >    guest-network-get-interfaces command instead of adding a new command.
> > v2-v3:
> >  - optimize function implementation
> > v3->v4:
> >  - modify compile error
> > v4->v5:
> >  - rename some temporary variables and add str_trim_off function for
> >
>     calculating the space num in front of the string in 
> guest_get_network_stats
> > v5->v6:
> >  - use g_strchug instead of str_trim_off implemented by myself
> > v6->v7:
> >  - add implementation for windows
> > ---
> >  qga/commands-posix.c |
>  72 +++++++++++++++++++++++++++++++++++++++++++++++++++-
> >  qga/commands-win32.c | 48 +++++++++++++++++++++++++++++++++++
> >  qga/qapi-schema.json | 38 ++++++++++++++++++++++++++-
> >  3 files changed, 156 insertions(+), 2 deletions(-)
> > 
> > diff --git a/qga/commands-posix.c b/qga/commands-posix.c
> > index ab0c63d..da5dba0 100644
> > --- a/qga/commands-posix.c
> > +++ b/qga/commands-posix.c
> > @@ -1643,6 +1643,65 @@ guest_find_interface(GuestNetworkInterfaceList *head,
> >      return head;
> >  }
> > 
> > +static int guest_get_network_stats(const char *name,
> > +                       GuestNetworkInterfaceStat *stats)
> > +{
> > +    int name_len;
> > +    char const *devinfo = "/proc/net/dev";
> > +    FILE *fp;
> > +    char *line = NULL, *colon;
> > +    size_t n;
> 
> Not sure if it affects behavior in practice, but getline() documentation
> states that *line is only allocated if *line == NULL *and* n == 0. So we
> should set n to 0 before each call to be safe.
> 
> > +    fp = fopen(devinfo, "r");
> > +    if (!fp) {
> > +        return -1;
> > +    }
> > +    name_len = strlen(name);
> > +    while (getline(&line, &n, fp) != -1) {
> 
> Since 'line' is being allocated by getline(), we need to free it after
> each call, or rely on it to realloc and then free that value before
> returning. The latter seems simpler in this case.
> 
> > +        long long dummy;
> > +        long long rx_bytes;
> > +        long long rx_packets;
> > +        long long rx_errs;
> > +        long long rx_dropped;
> > +        long long tx_bytes;
> > +        long long tx_packets;
> > +        long long tx_errs;
> > +        long long tx_dropped;
> > +        char *trim_line;
> > +        trim_line = g_strchug(line);
> > +        if (trim_line[0] == '\0') {
> > +            continue;
> > +        }
> > +        colon = strchr(trim_line, ':');
> > +        if (!colon) {
> > +            continue;
> > +        }
> > +        if (colon - name_len  == trim_line &&
> > +           strncmp(trim_line, name, name_len) == 0) {
> > +            if (sscanf(colon + 1,
> >
>  +                "%lld %lld %lld %lld %lld %lld %lld %lld %lld %lld %lld 
> %lld %lld %lld %lld %lld",
> > +                  &rx_bytes, &rx_packets, &rx_errs, &rx_dropped,
> > +                  &dummy, &dummy, &dummy, &dummy,
> > +                  &tx_bytes, &tx_packets, &tx_errs, &tx_dropped,
> > +                  &dummy, &dummy, &dummy, &dummy) != 16) {
> > +                continue;
> > +            }
> > +            stats->rx_bytes = rx_bytes;
> > +            stats->rx_packets = rx_packets;
> > +            stats->rx_errs = rx_errs;
> > +            stats->rx_dropped = rx_dropped;
> > +            stats->tx_bytes = tx_bytes;
> > +            stats->tx_packets = tx_packets;
> > +            stats->tx_errs = tx_errs;
> > +            stats->tx_dropped = tx_dropped;
> > +            fclose(fp);
> > +            return 0;
> > +        }
> > +    }
> > +    fclose(fp);
> > +    g_debug("/proc/net/dev: Interface not found");
> 
> Reporting the specific interface name might be useful here.
> 
> > +    return -1;
> > +}
> > +
> >  /*
> >   * Build information about guest interfaces
> >   */
> >
>  @@ -1659,6 +1718,7 @@ GuestNetworkInterfaceList 
> *qmp_guest_network_get_interfaces
> (Error **errp)
> >      for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
> >          GuestNetworkInterfaceList *info;
> >          GuestIpAddressList **address_list = NULL, *address_item = NULL;
> > +        GuestNetworkInterfaceStat  *interface_stat = NULL;
> >          char addr4[INET_ADDRSTRLEN];
> >          char addr6[INET6_ADDRSTRLEN];
> >          int sock;
> >
>  @@ -1778,7 +1838,17 @@ GuestNetworkInterfaceList 
> *qmp_guest_network_get_interfaces
> (Error **errp)
> > 
> >          info->value->has_ip_addresses = true;
> > 
> > -
> > +        if (!info->value->has_statistics) {
> > +            interface_stat = g_malloc0(sizeof(*interface_stat));
> > +            if (guest_get_network_stats(info->value->name,
> > +                interface_stat) == -1) {
> > +                info->value->has_statistics = false;
> > +                g_free(interface_stat);
> > +            } else {
> > +                info->value->statistics = interface_stat;
> > +                info->value->has_statistics = true;
> > +            }
> > +        }
> >      }
> > 
> >      freeifaddrs(ifap);
> > diff --git a/qga/commands-win32.c b/qga/commands-win32.c
> > index 619dbd2..e891253 100644
> > --- a/qga/commands-win32.c
> > +++ b/qga/commands-win32.c
> > @@ -1152,6 +1152,42 @@ out:
> >  }
> >  #endif
> > 
> > +static DWORD get_interface_index(const char *guid)
> > +{
> > +    ULONG index;
> > +    DWORD status;
> > +    wchar_t wbuf[512];
> > +    snwprintf(wbuf, sizeof(wbuf), L"\\device\\tcpip_%s", guid);
> > +    wbuf[sizeof(wbuf) - 1] = 0;
> 
> wchar_t can be larger than 1 byte, so using sizeof(wchar_t[]) as an
> index into a wchar_t[] can cause an overrun.
> 
> > +    status = GetAdapterIndex (wbuf, &index);
> > +    if (status != NO_ERROR) {
> > +        return (DWORD)~0;
> > +    } else {
> > +        return index;
> > +    }
> > +}
> > +static int guest_get_network_stats(const char *name,
> > +                       GuestNetworkInterfaceStat *stats)
> > +{
> > +    DWORD IfIndex = 0;
> > +    MIB_IFROW aMib_ifrow;
> > +    memset(&aMib_ifrow, 0, sizeof(aMib_ifrow));
> > +    IfIndex = get_interface_index(name);
> 
> Per CODING_STYLE variable names should be lowercase with "_" for
> separating words
> 
> > +    aMib_ifrow.dwIndex = IfIndex;
> > +    if (NO_ERROR == GetIfEntry(&aMib_ifrow)) {
> > +        stats->rx_bytes = aMib_ifrow.dwInOctets;
> > +        stats->rx_packets = aMib_ifrow.dwInUcastPkts;
> > +        stats->rx_errs = aMib_ifrow.dwInErrors;
> > +        stats->rx_dropped = aMib_ifrow.dwInDiscards;
> > +        stats->tx_bytes = aMib_ifrow.dwOutOctets;
> > +        stats->tx_packets = aMib_ifrow.dwOutUcastPkts;
> > +        stats->tx_errs = aMib_ifrow.dwOutErrors;
> > +        stats->tx_dropped = aMib_ifrow.dwOutDiscards;
> > +        return 0;
> > +    }
> > +    return -1;
> > +}
> > +
> >  GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
> >  {
> >      IP_ADAPTER_ADDRESSES *adptr_addrs, *addr;
> >
>  @@ -1159,6 +1195,7 @@ GuestNetworkInterfaceList 
> *qmp_guest_network_get_interfaces
> (Error **errp)
> >      GuestNetworkInterfaceList *head = NULL, *cur_item = NULL;
> >      GuestIpAddressList *head_addr, *cur_addr;
> >      GuestNetworkInterfaceList *info;
> > +    GuestNetworkInterfaceStat *interface_stat = NULL;
> >      GuestIpAddressList *address_item = NULL;
> >      unsigned char *mac_addr;
> >      char *addr_str;
> >
>  @@ -1238,6 +1275,17 @@ GuestNetworkInterfaceList 
> *qmp_guest_network_get_interfaces
> (Error **errp)
> >              info->value->has_ip_addresses = true;
> >              info->value->ip_addresses = head_addr;
> >          }
> > +        if (!info->value->has_statistics) {
> > +            interface_stat = g_malloc0(sizeof(*interface_stat));
> > +            if (guest_get_network_stats(addr->AdapterName,
> > +                interface_stat) == -1) {
> > +                info->value->has_statistics = false;
> > +                g_free(interface_stat);
> > +            } else {
> > +                info->value->statistics = interface_stat;
> > +                info->value->has_statistics = true;
> > +            }
> > +        }
> >      }
> >      WSACleanup();
> >  out:
> > diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
> > index 90a0c86..17884c7 100644
> > --- a/qga/qapi-schema.json
> > +++ b/qga/qapi-schema.json
> > @@ -643,6 +643,38 @@
> >             'prefix': 'int'} }
> > 
> >  ##
> > +# @GuestNetworkInterfaceStat:
> > +#
> > +# @rx-bytes: total bytes received
> > +#
> > +# @rx-packets: total packets received
> > +#
> > +# @rx-errs: bad packets received
> > +#
> > +# @rx-dropped: receiver dropped packets
> > +#
> > +# @tx-bytes: total bytes transmitted
> > +#
> > +# @tx-packets: total packets transmitted
> > +#
> > +# @tx-errs: packet transmit problems
> > +#
> > +# @tx-dropped: dropped packets transmitted
> > +#
> > +# Since: 2.11
> > +##
> > +{ 'struct': 'GuestNetworkInterfaceStat',
> > +  'data': {'rx-bytes': 'uint64',
> > +            'rx-packets': 'uint64',
> > +            'rx-errs': 'uint64',
> > +            'rx-dropped': 'uint64',
> > +            'tx-bytes': 'uint64',
> > +            'tx-packets': 'uint64',
> > +            'tx-errs': 'uint64',
> > +            'tx-dropped': 'uint64'
> > +           } }
> > +
> > +##
> >  # @GuestNetworkInterface:
> >  #
> >  # @name: The name of interface for which info are being delivered
> > @@ -651,12 +683,16 @@
> >  #
> >  # @ip-addresses: List of addresses assigned to @name
> >  #
> > +# @statistics: various statistic counters related to @name
> > +# (since 2.11)
> > +#
> >  # Since: 1.1
> >  ##
> >  { 'struct': 'GuestNetworkInterface',
> >    'data': {'name': 'str',
> >             '*hardware-address': 'str',
> > -           '*ip-addresses': ['GuestIpAddress'] } }
> > +           '*ip-addresses': ['GuestIpAddress'],
> > +           '*statistics': 'GuestNetworkInterfaceStat' } }
> > 
> >  ##
> >  # @guest-network-get-interfaces:
> > -- 
> > 1.8.3.1
> > 
> 
> 


Reply via email to