mirror of
https://gitlab.com/qemu-project/qemu
synced 2024-07-21 18:34:33 +00:00
qga/commands-posix: Use getifaddrs when available
Currently, commands-posix.c assumes that getifaddrs() is only available on Linux, and so the related guest agent command guest-network-get-interfaces is only implemented for #ifdef __linux__. This function does exist on other platforms, though, such as Solaris. So, add a meson check for getifaddrs(), and move the code for guest-network-get-interfaces to be built whenever getifaddrs() is available. The implementation for guest-network-get-interfaces still has some Linux-specific code, which is not fixed in this commit. This commit moves the relevant big chunks of code around without changing them, so a future commit can change the code in place. Signed-off-by: Andrew Deason <adeason@sinenomine.net> Reviewed-by: Michal Privoznik <mprivozn@redhat.com> Message-Id: <20220426195526.7699-2-adeason@sinenomine.net>
This commit is contained in:
parent
2e3408b3cc
commit
59e35c7b65
|
@ -1687,6 +1687,7 @@ config_host_data.set('CONFIG_SYNCFS', cc.has_function('syncfs'))
|
||||||
config_host_data.set('CONFIG_SYNC_FILE_RANGE', cc.has_function('sync_file_range'))
|
config_host_data.set('CONFIG_SYNC_FILE_RANGE', cc.has_function('sync_file_range'))
|
||||||
config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create'))
|
config_host_data.set('CONFIG_TIMERFD', cc.has_function('timerfd_create'))
|
||||||
config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
|
config_host_data.set('HAVE_COPY_FILE_RANGE', cc.has_function('copy_file_range'))
|
||||||
|
config_host_data.set('HAVE_GETIFADDRS', cc.has_function('getifaddrs'))
|
||||||
config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
|
config_host_data.set('HAVE_OPENPTY', cc.has_function('openpty', dependencies: util))
|
||||||
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
|
config_host_data.set('HAVE_STRCHRNUL', cc.has_function('strchrnul'))
|
||||||
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
|
config_host_data.set('HAVE_SYSTEM_FUNCTION', cc.has_function('system', prefix: '#include <stdlib.h>'))
|
||||||
|
|
|
@ -34,10 +34,6 @@
|
||||||
#if defined(__linux__)
|
#if defined(__linux__)
|
||||||
#include <mntent.h>
|
#include <mntent.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
#include <ifaddrs.h>
|
|
||||||
#include <arpa/inet.h>
|
|
||||||
#include <sys/socket.h>
|
|
||||||
#include <net/if.h>
|
|
||||||
#include <sys/statvfs.h>
|
#include <sys/statvfs.h>
|
||||||
|
|
||||||
#ifdef CONFIG_LIBUDEV
|
#ifdef CONFIG_LIBUDEV
|
||||||
|
@ -52,6 +48,17 @@
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_GETIFADDRS
|
||||||
|
#include <arpa/inet.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <net/if.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <ifaddrs.h>
|
||||||
|
#ifdef CONFIG_SOLARIS
|
||||||
|
#include <sys/sockio.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
static void ga_wait_child(pid_t pid, int *status, Error **errp)
|
static void ga_wait_child(pid_t pid, int *status, Error **errp)
|
||||||
{
|
{
|
||||||
pid_t rpid;
|
pid_t rpid;
|
||||||
|
@ -2133,223 +2140,6 @@ void qmp_guest_suspend_hybrid(Error **errp)
|
||||||
guest_suspend(SUSPEND_MODE_HYBRID, errp);
|
guest_suspend(SUSPEND_MODE_HYBRID, errp);
|
||||||
}
|
}
|
||||||
|
|
||||||
static GuestNetworkInterface *
|
|
||||||
guest_find_interface(GuestNetworkInterfaceList *head,
|
|
||||||
const char *name)
|
|
||||||
{
|
|
||||||
for (; head; head = head->next) {
|
|
||||||
if (strcmp(head->value->name, name) == 0) {
|
|
||||||
return head->value;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
*/
|
|
||||||
GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
|
||||||
{
|
|
||||||
GuestNetworkInterfaceList *head = NULL, **tail = &head;
|
|
||||||
struct ifaddrs *ifap, *ifa;
|
|
||||||
|
|
||||||
if (getifaddrs(&ifap) < 0) {
|
|
||||||
error_setg_errno(errp, errno, "getifaddrs failed");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
|
||||||
GuestNetworkInterface *info;
|
|
||||||
GuestIpAddressList **address_tail;
|
|
||||||
GuestIpAddress *address_item = NULL;
|
|
||||||
GuestNetworkInterfaceStat *interface_stat = NULL;
|
|
||||||
char addr4[INET_ADDRSTRLEN];
|
|
||||||
char addr6[INET6_ADDRSTRLEN];
|
|
||||||
int sock;
|
|
||||||
struct ifreq ifr;
|
|
||||||
unsigned char *mac_addr;
|
|
||||||
void *p;
|
|
||||||
|
|
||||||
g_debug("Processing %s interface", ifa->ifa_name);
|
|
||||||
|
|
||||||
info = guest_find_interface(head, ifa->ifa_name);
|
|
||||||
|
|
||||||
if (!info) {
|
|
||||||
info = g_malloc0(sizeof(*info));
|
|
||||||
info->name = g_strdup(ifa->ifa_name);
|
|
||||||
|
|
||||||
QAPI_LIST_APPEND(tail, info);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!info->has_hardware_address && ifa->ifa_flags & SIOCGIFHWADDR) {
|
|
||||||
/* we haven't obtained HW address yet */
|
|
||||||
sock = socket(PF_INET, SOCK_STREAM, 0);
|
|
||||||
if (sock == -1) {
|
|
||||||
error_setg_errno(errp, errno, "failed to create socket");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
memset(&ifr, 0, sizeof(ifr));
|
|
||||||
pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->name);
|
|
||||||
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
|
|
||||||
error_setg_errno(errp, errno,
|
|
||||||
"failed to get MAC address of %s",
|
|
||||||
ifa->ifa_name);
|
|
||||||
close(sock);
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
close(sock);
|
|
||||||
mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
|
|
||||||
|
|
||||||
info->hardware_address =
|
|
||||||
g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
|
|
||||||
(int) mac_addr[0], (int) mac_addr[1],
|
|
||||||
(int) mac_addr[2], (int) mac_addr[3],
|
|
||||||
(int) mac_addr[4], (int) mac_addr[5]);
|
|
||||||
|
|
||||||
info->has_hardware_address = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ifa->ifa_addr &&
|
|
||||||
ifa->ifa_addr->sa_family == AF_INET) {
|
|
||||||
/* interface with IPv4 address */
|
|
||||||
p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
|
|
||||||
if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
|
|
||||||
error_setg_errno(errp, errno, "inet_ntop failed");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
address_item = g_malloc0(sizeof(*address_item));
|
|
||||||
address_item->ip_address = g_strdup(addr4);
|
|
||||||
address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
|
|
||||||
|
|
||||||
if (ifa->ifa_netmask) {
|
|
||||||
/* Count the number of set bits in netmask.
|
|
||||||
* This is safe as '1' and '0' cannot be shuffled in netmask. */
|
|
||||||
p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
|
|
||||||
address_item->prefix = ctpop32(((uint32_t *) p)[0]);
|
|
||||||
}
|
|
||||||
} else if (ifa->ifa_addr &&
|
|
||||||
ifa->ifa_addr->sa_family == AF_INET6) {
|
|
||||||
/* interface with IPv6 address */
|
|
||||||
p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
|
|
||||||
if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
|
|
||||||
error_setg_errno(errp, errno, "inet_ntop failed");
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
address_item = g_malloc0(sizeof(*address_item));
|
|
||||||
address_item->ip_address = g_strdup(addr6);
|
|
||||||
address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
|
|
||||||
|
|
||||||
if (ifa->ifa_netmask) {
|
|
||||||
/* Count the number of set bits in netmask.
|
|
||||||
* This is safe as '1' and '0' cannot be shuffled in netmask. */
|
|
||||||
p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
|
|
||||||
address_item->prefix =
|
|
||||||
ctpop32(((uint32_t *) p)[0]) +
|
|
||||||
ctpop32(((uint32_t *) p)[1]) +
|
|
||||||
ctpop32(((uint32_t *) p)[2]) +
|
|
||||||
ctpop32(((uint32_t *) p)[3]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!address_item) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
address_tail = &info->ip_addresses;
|
|
||||||
while (*address_tail) {
|
|
||||||
address_tail = &(*address_tail)->next;
|
|
||||||
}
|
|
||||||
QAPI_LIST_APPEND(address_tail, address_item);
|
|
||||||
|
|
||||||
info->has_ip_addresses = true;
|
|
||||||
|
|
||||||
if (!info->has_statistics) {
|
|
||||||
interface_stat = g_malloc0(sizeof(*interface_stat));
|
|
||||||
if (guest_get_network_stats(info->name, interface_stat) == -1) {
|
|
||||||
info->has_statistics = false;
|
|
||||||
g_free(interface_stat);
|
|
||||||
} else {
|
|
||||||
info->statistics = interface_stat;
|
|
||||||
info->has_statistics = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
freeifaddrs(ifap);
|
|
||||||
return head;
|
|
||||||
|
|
||||||
error:
|
|
||||||
freeifaddrs(ifap);
|
|
||||||
qapi_free_GuestNetworkInterfaceList(head);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Transfer online/offline status between @vcpu and the guest system.
|
/* Transfer online/offline status between @vcpu and the guest system.
|
||||||
*
|
*
|
||||||
* On input either @errp or *@errp must be NULL.
|
* On input either @errp or *@errp must be NULL.
|
||||||
|
@ -2919,12 +2709,6 @@ void qmp_guest_suspend_hybrid(Error **errp)
|
||||||
error_setg(errp, QERR_UNSUPPORTED);
|
error_setg(errp, QERR_UNSUPPORTED);
|
||||||
}
|
}
|
||||||
|
|
||||||
GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
|
||||||
{
|
|
||||||
error_setg(errp, QERR_UNSUPPORTED);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
|
GuestLogicalProcessorList *qmp_guest_get_vcpus(Error **errp)
|
||||||
{
|
{
|
||||||
error_setg(errp, QERR_UNSUPPORTED);
|
error_setg(errp, QERR_UNSUPPORTED);
|
||||||
|
@ -2966,6 +2750,234 @@ GuestMemoryBlockInfo *qmp_guest_get_memory_block_info(Error **errp)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef HAVE_GETIFADDRS
|
||||||
|
static GuestNetworkInterface *
|
||||||
|
guest_find_interface(GuestNetworkInterfaceList *head,
|
||||||
|
const char *name)
|
||||||
|
{
|
||||||
|
for (; head; head = head->next) {
|
||||||
|
if (strcmp(head->value->name, name) == 0) {
|
||||||
|
return head->value;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
*/
|
||||||
|
GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
||||||
|
{
|
||||||
|
GuestNetworkInterfaceList *head = NULL, **tail = &head;
|
||||||
|
struct ifaddrs *ifap, *ifa;
|
||||||
|
|
||||||
|
if (getifaddrs(&ifap) < 0) {
|
||||||
|
error_setg_errno(errp, errno, "getifaddrs failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (ifa = ifap; ifa; ifa = ifa->ifa_next) {
|
||||||
|
GuestNetworkInterface *info;
|
||||||
|
GuestIpAddressList **address_tail;
|
||||||
|
GuestIpAddress *address_item = NULL;
|
||||||
|
GuestNetworkInterfaceStat *interface_stat = NULL;
|
||||||
|
char addr4[INET_ADDRSTRLEN];
|
||||||
|
char addr6[INET6_ADDRSTRLEN];
|
||||||
|
int sock;
|
||||||
|
struct ifreq ifr;
|
||||||
|
unsigned char *mac_addr;
|
||||||
|
void *p;
|
||||||
|
|
||||||
|
g_debug("Processing %s interface", ifa->ifa_name);
|
||||||
|
|
||||||
|
info = guest_find_interface(head, ifa->ifa_name);
|
||||||
|
|
||||||
|
if (!info) {
|
||||||
|
info = g_malloc0(sizeof(*info));
|
||||||
|
info->name = g_strdup(ifa->ifa_name);
|
||||||
|
|
||||||
|
QAPI_LIST_APPEND(tail, info);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!info->has_hardware_address && ifa->ifa_flags & SIOCGIFHWADDR) {
|
||||||
|
/* we haven't obtained HW address yet */
|
||||||
|
sock = socket(PF_INET, SOCK_STREAM, 0);
|
||||||
|
if (sock == -1) {
|
||||||
|
error_setg_errno(errp, errno, "failed to create socket");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&ifr, 0, sizeof(ifr));
|
||||||
|
pstrcpy(ifr.ifr_name, IF_NAMESIZE, info->name);
|
||||||
|
if (ioctl(sock, SIOCGIFHWADDR, &ifr) == -1) {
|
||||||
|
error_setg_errno(errp, errno,
|
||||||
|
"failed to get MAC address of %s",
|
||||||
|
ifa->ifa_name);
|
||||||
|
close(sock);
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(sock);
|
||||||
|
mac_addr = (unsigned char *) &ifr.ifr_hwaddr.sa_data;
|
||||||
|
|
||||||
|
info->hardware_address =
|
||||||
|
g_strdup_printf("%02x:%02x:%02x:%02x:%02x:%02x",
|
||||||
|
(int) mac_addr[0], (int) mac_addr[1],
|
||||||
|
(int) mac_addr[2], (int) mac_addr[3],
|
||||||
|
(int) mac_addr[4], (int) mac_addr[5]);
|
||||||
|
|
||||||
|
info->has_hardware_address = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ifa->ifa_addr &&
|
||||||
|
ifa->ifa_addr->sa_family == AF_INET) {
|
||||||
|
/* interface with IPv4 address */
|
||||||
|
p = &((struct sockaddr_in *)ifa->ifa_addr)->sin_addr;
|
||||||
|
if (!inet_ntop(AF_INET, p, addr4, sizeof(addr4))) {
|
||||||
|
error_setg_errno(errp, errno, "inet_ntop failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
address_item = g_malloc0(sizeof(*address_item));
|
||||||
|
address_item->ip_address = g_strdup(addr4);
|
||||||
|
address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV4;
|
||||||
|
|
||||||
|
if (ifa->ifa_netmask) {
|
||||||
|
/* Count the number of set bits in netmask.
|
||||||
|
* This is safe as '1' and '0' cannot be shuffled in netmask. */
|
||||||
|
p = &((struct sockaddr_in *)ifa->ifa_netmask)->sin_addr;
|
||||||
|
address_item->prefix = ctpop32(((uint32_t *) p)[0]);
|
||||||
|
}
|
||||||
|
} else if (ifa->ifa_addr &&
|
||||||
|
ifa->ifa_addr->sa_family == AF_INET6) {
|
||||||
|
/* interface with IPv6 address */
|
||||||
|
p = &((struct sockaddr_in6 *)ifa->ifa_addr)->sin6_addr;
|
||||||
|
if (!inet_ntop(AF_INET6, p, addr6, sizeof(addr6))) {
|
||||||
|
error_setg_errno(errp, errno, "inet_ntop failed");
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
address_item = g_malloc0(sizeof(*address_item));
|
||||||
|
address_item->ip_address = g_strdup(addr6);
|
||||||
|
address_item->ip_address_type = GUEST_IP_ADDRESS_TYPE_IPV6;
|
||||||
|
|
||||||
|
if (ifa->ifa_netmask) {
|
||||||
|
/* Count the number of set bits in netmask.
|
||||||
|
* This is safe as '1' and '0' cannot be shuffled in netmask. */
|
||||||
|
p = &((struct sockaddr_in6 *)ifa->ifa_netmask)->sin6_addr;
|
||||||
|
address_item->prefix =
|
||||||
|
ctpop32(((uint32_t *) p)[0]) +
|
||||||
|
ctpop32(((uint32_t *) p)[1]) +
|
||||||
|
ctpop32(((uint32_t *) p)[2]) +
|
||||||
|
ctpop32(((uint32_t *) p)[3]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!address_item) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
address_tail = &info->ip_addresses;
|
||||||
|
while (*address_tail) {
|
||||||
|
address_tail = &(*address_tail)->next;
|
||||||
|
}
|
||||||
|
QAPI_LIST_APPEND(address_tail, address_item);
|
||||||
|
|
||||||
|
info->has_ip_addresses = true;
|
||||||
|
|
||||||
|
if (!info->has_statistics) {
|
||||||
|
interface_stat = g_malloc0(sizeof(*interface_stat));
|
||||||
|
if (guest_get_network_stats(info->name, interface_stat) == -1) {
|
||||||
|
info->has_statistics = false;
|
||||||
|
g_free(interface_stat);
|
||||||
|
} else {
|
||||||
|
info->statistics = interface_stat;
|
||||||
|
info->has_statistics = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
return head;
|
||||||
|
|
||||||
|
error:
|
||||||
|
freeifaddrs(ifap);
|
||||||
|
qapi_free_GuestNetworkInterfaceList(head);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
GuestNetworkInterfaceList *qmp_guest_network_get_interfaces(Error **errp)
|
||||||
|
{
|
||||||
|
error_setg(errp, QERR_UNSUPPORTED);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* HAVE_GETIFADDRS */
|
||||||
|
|
||||||
#if !defined(CONFIG_FSFREEZE)
|
#if !defined(CONFIG_FSFREEZE)
|
||||||
|
|
||||||
GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
|
GuestFilesystemInfoList *qmp_guest_get_fsinfo(Error **errp)
|
||||||
|
@ -3028,8 +3040,7 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
||||||
{
|
{
|
||||||
const char *list[] = {
|
const char *list[] = {
|
||||||
"guest-suspend-disk", "guest-suspend-ram",
|
"guest-suspend-disk", "guest-suspend-ram",
|
||||||
"guest-suspend-hybrid", "guest-network-get-interfaces",
|
"guest-suspend-hybrid", "guest-get-vcpus", "guest-set-vcpus",
|
||||||
"guest-get-vcpus", "guest-set-vcpus",
|
|
||||||
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
"guest-get-memory-blocks", "guest-set-memory-blocks",
|
||||||
"guest-get-memory-block-size", "guest-get-memory-block-info",
|
"guest-get-memory-block-size", "guest-get-memory-block-info",
|
||||||
NULL};
|
NULL};
|
||||||
|
@ -3041,6 +3052,11 @@ GList *ga_command_blacklist_init(GList *blacklist)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(HAVE_GETIFADDRS)
|
||||||
|
blacklist = g_list_append(blacklist,
|
||||||
|
g_strdup("guest-network-get-interfaces"));
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(CONFIG_FSFREEZE)
|
#if !defined(CONFIG_FSFREEZE)
|
||||||
{
|
{
|
||||||
const char *list[] = {
|
const char *list[] = {
|
||||||
|
|
Loading…
Reference in a new issue