qga: add network stats to guest-network-get-interfaces
we can get the network interface statistics inside a virtual machine by guest-network-get-interfaces command. it is very useful for us tomonitor and analyze network traffic. Signed-off-by: ZhiPeng Lu <lu.zhipeng@zte.com.cn> * don't rely on sizeof(wchar[]) for wchar[] indexing * avoid camelCase variable names * fix up getline() usage * condensed commit subject line Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
This commit is contained in:
		
							parent
							
								
									105fad6bb2
								
							
						
					
					
						commit
						53f9fcb263
					
				| @ -1643,6 +1643,67 @@ 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 = 0; | ||||
|     fp = fopen(devinfo, "r"); | ||||
|     if (!fp) { | ||||
|         return -1; | ||||
|     } | ||||
|     name_len = strlen(name); | ||||
|     while (getline(&line, &n, fp) != -1) { | ||||
|         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); | ||||
|             g_free(line); | ||||
|             return 0; | ||||
|         } | ||||
|     } | ||||
|     fclose(fp); | ||||
|     g_free(line); | ||||
|     g_debug("/proc/net/dev: Interface '%s' not found", name); | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| /*
 | ||||
|  * Build information about guest interfaces | ||||
|  */ | ||||
| @ -1659,6 +1720,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 +1840,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); | ||||
|  | ||||
| @ -1153,6 +1153,44 @@ out: | ||||
| } | ||||
| #endif | ||||
| 
 | ||||
| #define INTERFACE_PATH_BUF_SZ 512 | ||||
| 
 | ||||
| static DWORD get_interface_index(const char *guid) | ||||
| { | ||||
|     ULONG index; | ||||
|     DWORD status; | ||||
|     wchar_t wbuf[INTERFACE_PATH_BUF_SZ]; | ||||
|     snwprintf(wbuf, INTERFACE_PATH_BUF_SZ, L"\\device\\tcpip_%s", guid); | ||||
|     wbuf[INTERFACE_PATH_BUF_SZ - 1] = 0; | ||||
|     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 if_index = 0; | ||||
|     MIB_IFROW a_mid_ifrow; | ||||
|     memset(&a_mid_ifrow, 0, sizeof(a_mid_ifrow)); | ||||
|     if_index = get_interface_index(name); | ||||
|     a_mid_ifrow.dwIndex = if_index; | ||||
|     if (NO_ERROR == GetIfEntry(&a_mid_ifrow)) { | ||||
|         stats->rx_bytes = a_mid_ifrow.dwInOctets; | ||||
|         stats->rx_packets = a_mid_ifrow.dwInUcastPkts; | ||||
|         stats->rx_errs = a_mid_ifrow.dwInErrors; | ||||
|         stats->rx_dropped = a_mid_ifrow.dwInDiscards; | ||||
|         stats->tx_bytes = a_mid_ifrow.dwOutOctets; | ||||
|         stats->tx_packets = a_mid_ifrow.dwOutUcastPkts; | ||||
|         stats->tx_errs = a_mid_ifrow.dwOutErrors; | ||||
|         stats->tx_dropped = a_mid_ifrow.dwOutDiscards; | ||||
|         return 0; | ||||
|     } | ||||
|     return -1; | ||||
| } | ||||
| 
 | ||||
| GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp) | ||||
| { | ||||
|     IP_ADAPTER_ADDRESSES *adptr_addrs, *addr; | ||||
| @ -1160,6 +1198,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; | ||||
| @ -1239,6 +1278,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: | ||||
|  | ||||
| @ -642,6 +642,38 @@ | ||||
|            'ip-address-type': 'GuestIpAddressType', | ||||
|            '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: | ||||
| # | ||||
| @ -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: | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user
	 ZhiPeng Lu
						ZhiPeng Lu