* [PATCH 0/2] Introducing QMP query-netdevs command
@ 2019-11-13 21:25 Alexey Kirillov
2019-11-13 21:25 ` [PATCH 1/2] qapi: net: Add " Alexey Kirillov
` (2 more replies)
0 siblings, 3 replies; 7+ messages in thread
From: Alexey Kirillov @ 2019-11-13 21:25 UTC (permalink / raw)
To: Jason Wang, Samuel Thibault, Markus Armbruster
Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Vincenzo Maffione,
yc-core, Alexey Kirillov, Giuseppe Lettieri, Luigi Rizzo
This patch introduces a new QMP command "query-netdevs" to get information
about currently attached network devices.
Potentially, this patch makes the "info_str" field of "struct NetClientState"
and HMP command "info network" obsolete as new command gives out more
information in a structured way.
Usage example:
{ "execute": "x-query-netdevs" }
{ "return": [
{
"peer": "netdev0",
"netdev": "netdev0",
"model": "virtio-net-pci",
"macaddr": "52:54:00:12:34:56",
"queues_count": 1,
"type": "nic",
"id": "net0"
},
{
"peer": "net0",
"ipv6": true,
"ipv4": true,
"host": "10.0.2.2",
"queues_count": 1,
"ipv6-dns": "fec0::3",
"ipv6-prefix": "fec0::",
"net": "10.0.2.0/255.255.255.0",
"ipv6-host": "fec0::2",
"type": "user",
"dns": "10.0.2.3",
"hostfwd": [
{
"str": "tcp::20004-:22"
}
],
"ipv6-prefixlen": 64,
"id": "netdev0",
"restrict": false
}
]
}
Alexey Kirillov (2):
qapi: net: Add query-netdevs command
tests: Add tests for query-netdevs command
include/net/net.h | 1 +
net/hub.c | 8 +++
net/l2tpv3.c | 19 ++++++
net/net.c | 80 +++++++++++++++++++++++
net/netmap.c | 13 ++++
net/slirp.c | 126 +++++++++++++++++++++++++++++++++++++
net/socket.c | 71 +++++++++++++++++++++
net/tap-win32.c | 9 +++
net/tap.c | 103 ++++++++++++++++++++++++++++--
net/vde.c | 26 ++++++++
net/vhost-user.c | 18 +++++-
qapi/net.json | 85 +++++++++++++++++++++++++
tests/Makefile.include | 2 +
tests/test-query-netdevs.c | 114 +++++++++++++++++++++++++++++++++
14 files changed, 667 insertions(+), 8 deletions(-)
create mode 100644 tests/test-query-netdevs.c
--
2.17.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/2] qapi: net: Add query-netdevs command
2019-11-13 21:25 [PATCH 0/2] Introducing QMP query-netdevs command Alexey Kirillov
@ 2019-11-13 21:25 ` Alexey Kirillov
2019-11-13 21:31 ` Eric Blake
2019-11-13 21:25 ` [PATCH 2/2] tests: Add tests for " Alexey Kirillov
2019-11-13 21:32 ` [PATCH 0/2] Introducing QMP " Eric Blake
2 siblings, 1 reply; 7+ messages in thread
From: Alexey Kirillov @ 2019-11-13 21:25 UTC (permalink / raw)
To: Jason Wang, Samuel Thibault, Markus Armbruster
Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Vincenzo Maffione,
yc-core, Alexey Kirillov, Giuseppe Lettieri, Luigi Rizzo
Add a qmp command that provides information about currently attached
network devices and their configuration.
Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru>
---
include/net/net.h | 1 +
net/hub.c | 8 +++
net/l2tpv3.c | 19 +++++++
net/net.c | 80 +++++++++++++++++++++++++++++
net/netmap.c | 13 +++++
net/slirp.c | 126 ++++++++++++++++++++++++++++++++++++++++++++++
net/socket.c | 71 ++++++++++++++++++++++++++
net/tap-win32.c | 9 ++++
net/tap.c | 103 +++++++++++++++++++++++++++++++++++--
net/vde.c | 26 ++++++++++
net/vhost-user.c | 18 +++++--
qapi/net.json | 85 +++++++++++++++++++++++++++++++
12 files changed, 551 insertions(+), 8 deletions(-)
diff --git a/include/net/net.h b/include/net/net.h
index e175ba9677..2c8956c0b3 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -92,6 +92,7 @@ struct NetClientState {
char *model;
char *name;
char info_str[256];
+ NetdevInfo *stored_config;
unsigned receive_disabled : 1;
NetClientDestructor *destructor;
unsigned int queue_index;
diff --git a/net/hub.c b/net/hub.c
index 5795a678ed..37995b5517 100644
--- a/net/hub.c
+++ b/net/hub.c
@@ -148,6 +148,7 @@ static NetHubPort *net_hub_port_new(NetHub *hub, const char *name,
NetHubPort *port;
int id = hub->num_ports++;
char default_name[128];
+ NetdevHubPortOptions *stored;
if (!name) {
snprintf(default_name, sizeof(default_name),
@@ -160,6 +161,13 @@ static NetHubPort *net_hub_port_new(NetHub *hub, const char *name,
port->id = id;
port->hub = hub;
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_HUBPORT;
+ stored = &nc->stored_config->u.hubport;
+
+ stored->hubid = hub->id;
+
QLIST_INSERT_HEAD(&hub->ports, port, next);
return port;
diff --git a/net/l2tpv3.c b/net/l2tpv3.c
index 55fea17c0f..f4e45e7b28 100644
--- a/net/l2tpv3.c
+++ b/net/l2tpv3.c
@@ -535,6 +535,7 @@ int net_init_l2tpv3(const Netdev *netdev,
struct addrinfo hints;
struct addrinfo *result = NULL;
char *srcport, *dstport;
+ NetdevL2TPv3Options *stored;
nc = qemu_new_net_client(&net_l2tpv3_info, peer, "l2tpv3", name);
@@ -726,6 +727,24 @@ int net_init_l2tpv3(const Netdev *netdev,
l2tpv3_read_poll(s, true);
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_L2TPV3;
+ stored = &nc->stored_config->u.l2tpv3;
+
+ memcpy(stored, l2tpv3, sizeof(NetdevL2TPv3Options));
+
+ stored->src = g_strdup(l2tpv3->src);
+ stored->dst = g_strdup(l2tpv3->dst);
+
+ if (l2tpv3->has_srcport) {
+ stored->srcport = g_strdup(l2tpv3->srcport);
+ }
+
+ if (l2tpv3->has_dstport) {
+ stored->dstport = g_strdup(l2tpv3->dstport);
+ }
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str),
"l2tpv3: connected");
return 0;
diff --git a/net/net.c b/net/net.c
index 84aa6d8d00..08bf78a668 100644
--- a/net/net.c
+++ b/net/net.c
@@ -54,6 +54,7 @@
#include "sysemu/sysemu.h"
#include "net/filter.h"
#include "qapi/string-output-visitor.h"
+#include "qapi/clone-visitor.h"
/* Net bridge is currently not supported for W32. */
#if !defined(_WIN32)
@@ -283,6 +284,7 @@ NICState *qemu_new_nic(NetClientInfo *info,
NetClientState **peers = conf->peers.ncs;
NICState *nic;
int i, queues = MAX(1, conf->peers.queues);
+ NetLegacyNicOptions *stored;
assert(info->type == NET_CLIENT_DRIVER_NIC);
assert(info->size >= sizeof(NICState));
@@ -298,6 +300,22 @@ NICState *qemu_new_nic(NetClientInfo *info,
nic->ncs[i].queue_index = i;
}
+ /* Store startup parameters */
+ nic->ncs[0].stored_config = g_new0(NetdevInfo, 1);
+ nic->ncs[0].stored_config->type = NET_CLIENT_DRIVER_NIC;
+ stored = &nic->ncs[0].stored_config->u.nic;
+
+ if (peers[0]) {
+ stored->has_netdev = true;
+ stored->netdev = g_strdup(peers[0]->name);
+ }
+
+ stored->has_macaddr = true;
+ stored->macaddr = g_strdup_printf(MAC_FMT, MAC_ARG(conf->macaddr.a));
+
+ stored->has_model = true;
+ stored->model = g_strdup(model);
+
return nic;
}
@@ -344,6 +362,7 @@ static void qemu_free_net_client(NetClientState *nc)
}
g_free(nc->name);
g_free(nc->model);
+ qapi_free_NetdevInfo(nc->stored_config);
if (nc->destructor) {
nc->destructor(nc);
}
@@ -1323,6 +1342,67 @@ RxFilterInfoList *qmp_query_rx_filter(bool has_name, const char *name,
return filter_list;
}
+NetdevInfoList *qmp_x_query_netdevs(Error **errp)
+{
+ NetdevInfoList *list = NULL;
+ NetClientState *nc;
+
+ QTAILQ_FOREACH(nc, &net_clients, next) {
+ /* Only look at netdevs, not for each queue */
+ if (nc->stored_config) {
+ NetdevInfoList *node = g_new0(NetdevInfoList, 1);
+
+ node->value = QAPI_CLONE(NetdevInfo, nc->stored_config);
+ g_free(node->value->id); /* Need to dealloc default empty id */
+ node->value->id = g_strdup(nc->name);
+
+ if (nc->info->type == NET_CLIENT_DRIVER_NIC) {
+ NICState *state = qemu_get_nic(nc);
+ assert(state);
+
+ /* NIC have explicit number of queues */
+ assert(state->conf);
+ node->value->queues_count = state->conf->peers.queues;
+ } else {
+ /* Not a NIC, but can have queues */
+ NetClientState *nc_iterable;
+
+ QTAILQ_FOREACH(nc_iterable, &net_clients, next) {
+ if (strcmp(nc_iterable->name, nc->name) == 0) {
+ node->value->queues_count++;
+ }
+ }
+ }
+
+ node->value->has_peer = nc->peer != NULL;
+ if (node->value->has_peer) {
+ node->value->peer = g_strdup(nc->peer->name);
+ }
+
+ node->value->has_hub =
+ net_hub_id_for_client(nc, (int *)&node->value->hub) == 0;
+
+ /*
+ * Copy the current hubport peer id to connected netdev id,
+ * because it could have been changed at runtime
+ */
+ if (nc->info->type == NET_CLIENT_DRIVER_HUBPORT) {
+ if (node->value->has_peer) {
+ g_free(node->value->u.hubport.netdev);
+
+ node->value->u.hubport.has_netdev = true;
+ node->value->u.hubport.netdev = g_strdup(nc->peer->name);
+ }
+ }
+
+ node->next = list;
+ list = node;
+ }
+ }
+
+ return list;
+}
+
void hmp_info_network(Monitor *mon, const QDict *qdict)
{
NetClientState *nc, *peer;
diff --git a/net/netmap.c b/net/netmap.c
index 350f097f91..71feacb92c 100644
--- a/net/netmap.c
+++ b/net/netmap.c
@@ -411,6 +411,7 @@ int net_init_netmap(const Netdev *netdev,
NetClientState *nc;
Error *err = NULL;
NetmapState *s;
+ NetdevNetmapOptions *stored;
nmd = netmap_open(netmap_opts, &err);
if (err) {
@@ -427,6 +428,18 @@ int net_init_netmap(const Netdev *netdev,
pstrcpy(s->ifname, sizeof(s->ifname), netmap_opts->ifname);
netmap_read_poll(s, true); /* Initially only poll for reads. */
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_NETMAP;
+ stored = &nc->stored_config->u.netmap;
+
+ stored->ifname = g_strdup(netmap_opts->ifname);
+
+ if (netmap_opts->has_devname) {
+ stored->has_devname = true;
+ stored->devname = g_strdup(netmap_opts->devname);
+ }
+
return 0;
}
diff --git a/net/slirp.c b/net/slirp.c
index c4334ee876..fb5b87ebed 100644
--- a/net/slirp.c
+++ b/net/slirp.c
@@ -346,6 +346,14 @@ static SaveVMHandlers savevm_slirp_state = {
.load_state = net_slirp_state_load,
};
+#define APPEND_STRINGLIST(tail, new_val) \
+ do { \
+ *(tail) = g_new0(StringList, 1); \
+ (*(tail))->value = g_new0(String, 1); \
+ (*(tail))->value->str = g_strdup((new_val)); \
+ (tail) = &((*(tail))->next); \
+ } while (0)
+
static int net_slirp_init(NetClientState *peer, const char *model,
const char *name, int restricted,
bool ipv4, const char *vnetwork, const char *vhost,
@@ -378,6 +386,9 @@ static int net_slirp_init(NetClientState *peer, const char *model,
int shift;
char *end;
struct slirp_config_str *config;
+ NetdevUserOptions *stored;
+ StringList **stored_hostfwd;
+ StringList **stored_guestfwd;
if (!ipv4 && (vnetwork || vhost || vnameserver)) {
error_setg(errp, "IPv4 disabled but netmask/host/dns provided");
@@ -553,6 +564,112 @@ static int net_slirp_init(NetClientState *peer, const char *model,
nc = qemu_new_net_client(&net_slirp_info, peer, model, name);
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_USER;
+ stored = &nc->stored_config->u.user;
+
+ if (vhostname) {
+ stored->has_hostname = true;
+ stored->hostname = g_strdup(vhostname);
+ }
+
+ stored->has_q_restrict = true;
+ stored->q_restrict = restricted;
+
+ stored->has_ipv4 = true;
+ stored->ipv4 = ipv4;
+
+ stored->has_ipv6 = true;
+ stored->ipv6 = ipv6;
+
+ if (ipv4) {
+ uint8_t *net_bytes = (uint8_t *)&net;
+ uint8_t *mask_bytes = (uint8_t *)&mask;
+
+ stored->has_net = true;
+ stored->net = g_strdup_printf("%d.%d.%d.%d/%d.%d.%d.%d",
+ net_bytes[0], net_bytes[1],
+ net_bytes[2], net_bytes[3],
+ mask_bytes[0], mask_bytes[1],
+ mask_bytes[2], mask_bytes[3]);
+
+ stored->has_host = true;
+ stored->host = g_strdup(inet_ntoa(host));
+ }
+
+ if (tftp_export) {
+ stored->has_tftp = true;
+ stored->tftp = g_strdup(tftp_export);
+ }
+
+ if (bootfile) {
+ stored->has_bootfile = true;
+ stored->bootfile = g_strdup(bootfile);
+ }
+
+ if (vdhcp_start) {
+ stored->has_dhcpstart = true;
+ stored->dhcpstart = g_strdup(vdhcp_start);
+ }
+
+ if (ipv4) {
+ stored->has_dns = true;
+ stored->dns = g_strdup(inet_ntoa(dns));
+ }
+
+ if (dnssearch) {
+ stored->has_dnssearch = true;
+ StringList **stored_list = &stored->dnssearch;
+
+ for (int i = 0; dnssearch[i]; i++) {
+ APPEND_STRINGLIST(stored_list, dnssearch[i]);
+ }
+ }
+
+ if (vdomainname) {
+ stored->has_domainname = true;
+ stored->domainname = g_strdup(vdomainname);
+ }
+
+ if (ipv6) {
+ char addrstr[INET6_ADDRSTRLEN];
+ const char *res;
+
+ stored->has_ipv6_prefix = true;
+ stored->ipv6_prefix = g_strdup(vprefix6);
+
+ stored->has_ipv6_prefixlen = true;
+ stored->ipv6_prefixlen = vprefix6_len;
+
+ res = inet_ntop(AF_INET6, &ip6_host,
+ addrstr, sizeof(addrstr));
+
+ stored->has_ipv6_host = true;
+ stored->ipv6_host = g_strdup(res);
+
+ res = inet_ntop(AF_INET6, &ip6_dns,
+ addrstr, sizeof(addrstr));
+
+ stored->has_ipv6_dns = true;
+ stored->ipv6_dns = g_strdup(res);
+ }
+
+ if (smb_export) {
+ stored->has_smb = true;
+ stored->smb = g_strdup(smb_export);
+ }
+
+ if (vsmbserver) {
+ stored->has_smbserver = true;
+ stored->smbserver = g_strdup(vsmbserver);
+ }
+
+ if (tftp_server_name) {
+ stored->has_tftp_server_name = true;
+ stored->tftp_server_name = g_strdup(tftp_server_name);
+ }
+
snprintf(nc->info_str, sizeof(nc->info_str),
"net=%s,restrict=%s", inet_ntoa(net),
restricted ? "on" : "off");
@@ -582,14 +699,23 @@ static int net_slirp_init(NetClientState *peer, const char *model,
s->poll_notifier.notify = net_slirp_poll_notify;
main_loop_poll_add_notifier(&s->poll_notifier);
+ stored_hostfwd = &stored->hostfwd;
+ stored_guestfwd = &stored->guestfwd;
+
for (config = slirp_configs; config; config = config->next) {
if (config->flags & SLIRP_CFG_HOSTFWD) {
if (slirp_hostfwd(s, config->str, errp) < 0) {
goto error;
+ } else {
+ stored->has_hostfwd = true;
+ APPEND_STRINGLIST(stored_hostfwd, config->str);
}
} else {
if (slirp_guestfwd(s, config->str, errp) < 0) {
goto error;
+ } else {
+ stored->has_guestfwd = true;
+ APPEND_STRINGLIST(stored_guestfwd, config->str);
}
}
}
diff --git a/net/socket.c b/net/socket.c
index c92354049b..2d2d5419ca 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -342,6 +342,7 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
NetSocketState *s;
SocketAddress *sa;
SocketAddressType sa_type;
+ NetdevSocketOptions *stored;
sa = socket_local_address(fd, errp);
if (!sa) {
@@ -385,8 +386,19 @@ static NetSocketState *net_socket_fd_init_dgram(NetClientState *peer,
net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
net_socket_read_poll(s, true);
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_SOCKET;
+ stored = &nc->stored_config->u.socket;
+
+ stored->has_fd = true;
+ stored->fd = g_strdup_printf("%d", fd);
+
/* mcast: save bound address as dst */
if (is_connected && mcast != NULL) {
+ stored->has_mcast = true;
+ stored->mcast = g_strdup(mcast);
+
s->dgram_dst = saddr;
snprintf(nc->info_str, sizeof(nc->info_str),
"socket: fd=%d (cloned mcast=%s:%d)",
@@ -428,6 +440,7 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
{
NetClientState *nc;
NetSocketState *s;
+ NetdevSocketOptions *stored;
nc = qemu_new_net_client(&net_socket_info, peer, model, name);
@@ -447,6 +460,15 @@ static NetSocketState *net_socket_fd_init_stream(NetClientState *peer,
} else {
qemu_set_fd_handler(s->fd, NULL, net_socket_connect, s);
}
+
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_SOCKET;
+ stored = &nc->stored_config->u.socket;
+
+ stored->has_fd = true;
+ stored->fd = g_strdup_printf("%d", fd);
+
return s;
}
@@ -483,6 +505,7 @@ static void net_socket_accept(void *opaque)
struct sockaddr_in saddr;
socklen_t len;
int fd;
+ NetdevSocketOptions *stored;
for(;;) {
len = sizeof(saddr);
@@ -498,6 +521,13 @@ static void net_socket_accept(void *opaque)
s->fd = fd;
s->nc.link_down = false;
net_socket_connect(s);
+
+ /* Store additional startup parameters (extend net_socket_listen_init) */
+ stored = &s->nc.stored_config->u.socket;
+
+ stored->has_fd = true;
+ stored->fd = g_strdup_printf("%d", fd);
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str),
"socket: connection from %s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
@@ -513,6 +543,7 @@ static int net_socket_listen_init(NetClientState *peer,
NetSocketState *s;
struct sockaddr_in saddr;
int fd, ret;
+ NetdevSocketOptions *stored;
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
@@ -549,6 +580,15 @@ static int net_socket_listen_init(NetClientState *peer,
net_socket_rs_init(&s->rs, net_socket_rs_finalize, false);
qemu_set_fd_handler(s->listen_fd, net_socket_accept, NULL, s);
+
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_SOCKET;
+ stored = &nc->stored_config->u.socket;
+
+ stored->has_listen = true;
+ stored->listen = g_strdup(host_str);
+
return 0;
}
@@ -561,6 +601,7 @@ static int net_socket_connect_init(NetClientState *peer,
NetSocketState *s;
int fd, connected, ret;
struct sockaddr_in saddr;
+ NetdevSocketOptions *stored;
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
@@ -598,6 +639,12 @@ static int net_socket_connect_init(NetClientState *peer,
return -1;
}
+ /* Store additional startup parameters (extend net_socket_fd_init) */
+ stored = &s->nc.stored_config->u.socket;
+
+ stored->has_connect = true;
+ stored->connect = g_strdup(host_str);
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str),
"socket: connect to %s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
@@ -615,6 +662,7 @@ static int net_socket_mcast_init(NetClientState *peer,
int fd;
struct sockaddr_in saddr;
struct in_addr localaddr, *param_localaddr;
+ NetdevSocketOptions *stored;
if (parse_host_port(&saddr, host_str, errp) < 0) {
return -1;
@@ -643,6 +691,19 @@ static int net_socket_mcast_init(NetClientState *peer,
s->dgram_dst = saddr;
+ /* Store additional startup parameters (extend net_socket_fd_init) */
+ stored = &s->nc.stored_config->u.socket;
+
+ if (!stored->has_mcast) {
+ stored->has_mcast = true;
+ stored->mcast = g_strdup(host_str);
+ }
+
+ if (localaddr_str) {
+ stored->has_localaddr = true;
+ stored->localaddr = g_strdup(localaddr_str);
+ }
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str),
"socket: mcast=%s:%d",
inet_ntoa(saddr.sin_addr), ntohs(saddr.sin_port));
@@ -660,6 +721,7 @@ static int net_socket_udp_init(NetClientState *peer,
NetSocketState *s;
int fd, ret;
struct sockaddr_in laddr, raddr;
+ NetdevSocketOptions *stored;
if (parse_host_port(&laddr, lhost, errp) < 0) {
return -1;
@@ -698,6 +760,15 @@ static int net_socket_udp_init(NetClientState *peer,
s->dgram_dst = raddr;
+ /* Store additional startup parameters (extend net_socket_fd_init) */
+ stored = &s->nc.stored_config->u.socket;
+
+ stored->has_localaddr = true;
+ stored->localaddr = g_strdup(lhost);
+
+ stored->has_udp = true;
+ stored->udp = g_strdup(rhost);
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str),
"socket: udp=%s:%d",
inet_ntoa(raddr.sin_addr), ntohs(raddr.sin_port));
diff --git a/net/tap-win32.c b/net/tap-win32.c
index 2b5dcda36e..20ba0b1dc8 100644
--- a/net/tap-win32.c
+++ b/net/tap-win32.c
@@ -768,6 +768,7 @@ static int tap_win32_init(NetClientState *peer, const char *model,
NetClientState *nc;
TAPState *s;
tap_win32_overlapped_t *handle;
+ NetdevTapOptions *stored;
if (tap_win32_open(&handle, ifname) < 0) {
printf("tap: Could not open '%s'\n", ifname);
@@ -778,6 +779,14 @@ static int tap_win32_init(NetClientState *peer, const char *model,
s = DO_UPCAST(TAPState, nc, nc);
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_TAP;
+ stored = &nc->stored_config->u.tap;
+
+ stored->has_ifname = true;
+ stored->ifname = g_strdup(ifname);
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str),
"tap: ifname=%s", ifname);
diff --git a/net/tap.c b/net/tap.c
index 6207f61f84..fb2631ce5e 100644
--- a/net/tap.c
+++ b/net/tap.c
@@ -584,6 +584,7 @@ int net_init_bridge(const Netdev *netdev, const char *name,
const char *helper, *br;
TAPState *s;
int fd, vnet_hdr;
+ NetdevBridgeOptions *stored;
assert(netdev->type == NET_CLIENT_DRIVER_BRIDGE);
bridge = &netdev->u.bridge;
@@ -600,6 +601,21 @@ int net_init_bridge(const Netdev *netdev, const char *name,
vnet_hdr = tap_probe_vnet_hdr(fd);
s = net_tap_fd_init(peer, "bridge", name, fd, vnet_hdr);
+ /* Store startup parameters */
+ s->nc.stored_config = g_new0(NetdevInfo, 1);
+ s->nc.stored_config->type = NET_CLIENT_DRIVER_BRIDGE;
+ stored = &s->nc.stored_config->u.bridge;
+
+ if (br) {
+ stored->has_br = true;
+ stored->br = g_strdup(br);
+ }
+
+ if (helper) {
+ stored->has_helper = true;
+ stored->helper = g_strdup(helper);
+ }
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s,br=%s", helper,
br);
@@ -647,11 +663,13 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
const char *model, const char *name,
const char *ifname, const char *script,
const char *downscript, const char *vhostfdname,
- int vnet_hdr, int fd, Error **errp)
+ int vnet_hdr, int fd, NetdevInfo **common_stored,
+ Error **errp)
{
Error *err = NULL;
TAPState *s = net_tap_fd_init(peer, model, name, fd, vnet_hdr);
int vhostfd;
+ NetdevTapOptions *stored;
tap_set_sndbuf(s->fd, tap, &err);
if (err) {
@@ -659,12 +677,65 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
return;
}
+ /* Store startup parameters */
+ if (!*common_stored) {
+ *common_stored = g_new0(NetdevInfo, 1);
+ (*common_stored)->type = NET_CLIENT_DRIVER_TAP;
+ s->nc.stored_config = *common_stored;
+ }
+ stored = &(*common_stored)->u.tap;
+
+ if (tap->has_sndbuf && !stored->has_sndbuf) {
+ stored->has_sndbuf = true;
+ stored->sndbuf = tap->sndbuf;
+ }
+
+ if (vnet_hdr && !stored->has_vnet_hdr) {
+ stored->has_vnet_hdr = true;
+ stored->vnet_hdr = true;
+ }
+
if (tap->has_fd || tap->has_fds) {
+ if (!stored->has_fds) {
+ stored->has_fds = true;
+ stored->fds = g_strdup_printf("%d", fd);
+ } else {
+ char *tmp_s = stored->fds;
+ stored->fds = g_strdup_printf("%s:%d", stored->fds, fd);
+ g_free(tmp_s);
+ }
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str), "fd=%d", fd);
} else if (tap->has_helper) {
+ if (!stored->has_helper) {
+ stored->has_helper = true;
+ stored->helper = g_strdup(tap->helper);
+ }
+
+ if (!stored->has_br) {
+ stored->has_br = true;
+ stored->br = tap->has_br ? g_strdup(tap->br) :
+ g_strdup(DEFAULT_BRIDGE_INTERFACE);
+ }
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str), "helper=%s",
tap->helper);
} else {
+ if (tap->has_ifname && !stored->has_ifname) {
+ stored->has_ifname = true;
+ stored->ifname = g_strdup(ifname);
+ }
+
+ if (tap->has_script && !stored->has_script) {
+ stored->has_script = true;
+ stored->script = g_strdup(script);
+ }
+
+ if (tap->has_downscript && !stored->has_downscript) {
+ stored->has_downscript = true;
+ stored->downscript = g_strdup(downscript);
+ }
+
snprintf(s->nc.info_str, sizeof(s->nc.info_str),
"ifname=%s,script=%s,downscript=%s", ifname, script,
downscript);
@@ -680,9 +751,20 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
vhostfdname || (tap->has_vhostforce && tap->vhostforce)) {
VhostNetOptions options;
+ stored->has_vhost = true;
+ stored->vhost = true;
+
+ if (tap->has_vhostforce && tap->vhostforce) {
+ stored->has_vhostforce = true;
+ stored->vhostforce = true;
+ }
+
options.backend_type = VHOST_BACKEND_TYPE_KERNEL;
options.net_backend = &s->nc;
if (tap->has_poll_us) {
+ stored->has_poll_us = true;
+ stored->poll_us = tap->poll_us;
+
options.busyloop_timeout = tap->poll_us;
} else {
options.busyloop_timeout = 0;
@@ -715,6 +797,15 @@ static void net_init_tap_one(const NetdevTapOptions *tap, NetClientState *peer,
}
options.opaque = (void *)(uintptr_t)vhostfd;
+ if (!stored->has_vhostfds) {
+ stored->has_vhostfds = true;
+ stored->vhostfds = g_strdup_printf("%d", vhostfd);
+ } else {
+ char *tmp_s = stored->vhostfds;
+ stored->vhostfds = g_strdup_printf("%s:%d", stored->fds, vhostfd);
+ g_free(tmp_s);
+ }
+
s->vhost_net = vhost_net_init(&options);
if (!s->vhost_net) {
if (tap->has_vhostforce && tap->vhostforce) {
@@ -766,6 +857,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
Error *err = NULL;
const char *vhostfdname;
char ifname[128];
+ NetdevInfo *common_stored = NULL; /* will store configuration */
assert(netdev->type == NET_CLIENT_DRIVER_TAP);
tap = &netdev->u.tap;
@@ -801,7 +893,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
net_init_tap_one(tap, peer, "tap", name, NULL,
script, downscript,
- vhostfdname, vnet_hdr, fd, &err);
+ vhostfdname, vnet_hdr, fd, &common_stored, &err);
if (err) {
error_propagate(errp, err);
return -1;
@@ -857,7 +949,7 @@ int net_init_tap(const Netdev *netdev, const char *name,
net_init_tap_one(tap, peer, "tap", name, ifname,
script, downscript,
tap->has_vhostfds ? vhost_fds[i] : NULL,
- vnet_hdr, fd, &err);
+ vnet_hdr, fd, &common_stored, &err);
if (err) {
error_propagate(errp, err);
ret = -1;
@@ -896,7 +988,7 @@ free_fail:
net_init_tap_one(tap, peer, "bridge", name, ifname,
script, downscript, vhostfdname,
- vnet_hdr, fd, &err);
+ vnet_hdr, fd, &common_stored, &err);
if (err) {
error_propagate(errp, err);
close(fd);
@@ -935,7 +1027,8 @@ free_fail:
net_init_tap_one(tap, peer, "tap", name, ifname,
i >= 1 ? "no" : script,
i >= 1 ? "no" : downscript,
- vhostfdname, vnet_hdr, fd, &err);
+ vhostfdname, vnet_hdr, fd,
+ &common_stored, &err);
if (err) {
error_propagate(errp, err);
close(fd);
diff --git a/net/vde.c b/net/vde.c
index 99189cccb6..c0ab2bb65c 100644
--- a/net/vde.c
+++ b/net/vde.c
@@ -84,6 +84,7 @@ static int net_vde_init(NetClientState *peer, const char *model,
VDECONN *vde;
char *init_group = (char *)group;
char *init_sock = (char *)sock;
+ NetdevVdeOptions *stored;
struct vde_open_args args = {
.port = port,
@@ -108,6 +109,31 @@ static int net_vde_init(NetClientState *peer, const char *model,
qemu_set_fd_handler(vde_datafd(s->vde), vde_to_qemu, NULL, s);
+ /* Store startup parameters */
+ nc->stored_config = g_new0(NetdevInfo, 1);
+ nc->stored_config->type = NET_CLIENT_DRIVER_VDE;
+ stored = &nc->stored_config->u.vde;
+
+ if (sock) {
+ stored->has_sock = true;
+ stored->sock = g_strdup(sock);
+ }
+
+ if (port) {
+ stored->has_port = true;
+ stored->port = port;
+ }
+
+ if (group) {
+ stored->has_group = true;
+ stored->group = g_strdup(group);
+ }
+
+ if (mode) {
+ stored->has_mode = true;
+ stored->mode = mode;
+ }
+
return 0;
}
diff --git a/net/vhost-user.c b/net/vhost-user.c
index 014199d600..ce476e096a 100644
--- a/net/vhost-user.c
+++ b/net/vhost-user.c
@@ -302,14 +302,15 @@ static void net_vhost_user_event(void *opaque, int event)
}
static int net_vhost_user_init(NetClientState *peer, const char *device,
- const char *name, Chardev *chr,
- int queues)
+ const char *name, const char *chardev,
+ Chardev *chr, int queues)
{
Error *err = NULL;
NetClientState *nc, *nc0 = NULL;
NetVhostUserState *s = NULL;
VhostUserState *user;
int i;
+ NetdevVhostUserOptions *stored;
assert(name);
assert(queues > 0);
@@ -346,6 +347,16 @@ static int net_vhost_user_init(NetClientState *peer, const char *device,
assert(s->vhost_net);
+ /* Store startup parameters */
+ nc0->stored_config = g_new0(NetdevInfo, 1);
+ nc0->stored_config->type = NET_CLIENT_DRIVER_VHOST_USER;
+ stored = &nc0->stored_config->u.vhost_user;
+
+ stored->chardev = g_strdup(chardev);
+
+ stored->has_queues = true;
+ stored->queues = queues;
+
return 0;
err:
@@ -437,5 +448,6 @@ int net_init_vhost_user(const Netdev *netdev, const char *name,
return -1;
}
- return net_vhost_user_init(peer, "vhost_user", name, chr, queues);
+ return net_vhost_user_init(peer, "vhost_user", name,
+ vhost_user_opts->chardev, chr, queues);
}
diff --git a/qapi/net.json b/qapi/net.json
index 335295be50..7ceb00cd8f 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -754,3 +754,88 @@
##
{ 'event': 'FAILOVER_NEGOTIATED',
'data': {'device-id': 'str'} }
+
+##
+# @NetdevInfo:
+#
+# Configuration of a network device.
+#
+# @id: Device identifier.
+#
+# @type: Specify the driver used for interpreting remaining arguments.
+#
+# @peer: Connected network device.
+#
+# @queues_count: Number of queues.
+#
+# @hub: hubid of hub, if connected to.
+#
+# Since: 4.2
+##
+{ 'union': 'NetdevInfo',
+ 'base': { 'id': 'str',
+ 'type': 'NetClientDriver',
+ '*peer': 'str',
+ 'queues_count': 'int',
+ '*hub': 'int' },
+ 'discriminator': 'type',
+ 'data': {
+ 'nic': 'NetLegacyNicOptions',
+ 'user': 'NetdevUserOptions',
+ 'tap': 'NetdevTapOptions',
+ 'l2tpv3': 'NetdevL2TPv3Options',
+ 'socket': 'NetdevSocketOptions',
+ 'vde': 'NetdevVdeOptions',
+ 'bridge': 'NetdevBridgeOptions',
+ 'hubport': 'NetdevHubPortOptions',
+ 'netmap': 'NetdevNetmapOptions',
+ 'vhost-user': 'NetdevVhostUserOptions' } }
+
+##
+# @x-query-netdevs:
+#
+# Get a list of @NetdevInfo for all virtual network devices.
+#
+# Returns: a list of @NetdevInfo describing each virtual network device.
+#
+# Since: 4.2
+#
+# Example:
+#
+# -> { "execute": "x-query-netdevs" }
+# <- { "return": [
+# {
+# "peer": "netdev0",
+# "netdev": "netdev0",
+# "model": "virtio-net-pci",
+# "macaddr": "52:54:00:12:34:56",
+# "queues_count": 1,
+# "type": "nic",
+# "id": "net0"
+# },
+# {
+# "peer": "net0",
+# "ipv6": true,
+# "ipv4": true,
+# "host": "10.0.2.2",
+# "queues_count": 1,
+# "ipv6-dns": "fec0::3",
+# "ipv6-prefix": "fec0::",
+# "net": "10.0.2.0/255.255.255.0",
+# "ipv6-host": "fec0::2",
+# "type": "user",
+# "dns": "10.0.2.3",
+# "hostfwd": [
+# {
+# "str": "tcp::20004-:22"
+# }
+# ],
+# "ipv6-prefixlen": 64,
+# "id": "netdev0",
+# "restrict": false
+# }
+# ]
+# }
+#
+##
+{ 'command': 'x-query-netdevs', 'returns': ['NetdevInfo'] }
--
2.17.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/2] tests: Add tests for query-netdevs command
2019-11-13 21:25 [PATCH 0/2] Introducing QMP query-netdevs command Alexey Kirillov
2019-11-13 21:25 ` [PATCH 1/2] qapi: net: Add " Alexey Kirillov
@ 2019-11-13 21:25 ` Alexey Kirillov
2019-11-14 11:28 ` Thomas Huth
2019-11-13 21:32 ` [PATCH 0/2] Introducing QMP " Eric Blake
2 siblings, 1 reply; 7+ messages in thread
From: Alexey Kirillov @ 2019-11-13 21:25 UTC (permalink / raw)
To: Jason Wang, Samuel Thibault, Markus Armbruster
Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Vincenzo Maffione,
yc-core, Alexey Kirillov, Giuseppe Lettieri, Luigi Rizzo
Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru>
---
tests/Makefile.include | 2 +
tests/test-query-netdevs.c | 114 +++++++++++++++++++++++++++++++++++++
2 files changed, 116 insertions(+)
create mode 100644 tests/test-query-netdevs.c
diff --git a/tests/Makefile.include b/tests/Makefile.include
index 534ee48743..4d199e463b 100644
--- a/tests/Makefile.include
+++ b/tests/Makefile.include
@@ -297,6 +297,7 @@ check-qtest-s390x-y += tests/migration-test$(EXESUF)
check-qtest-generic-y += tests/machine-none-test$(EXESUF)
check-qtest-generic-y += tests/qom-test$(EXESUF)
check-qtest-generic-y += tests/test-hmp$(EXESUF)
+check-qtest-generic-y += tests/test-query-netdevs$(EXESUF)
qapi-schema += alternate-any.json
qapi-schema += alternate-array.json
@@ -844,6 +845,7 @@ tests/numa-test$(EXESUF): tests/numa-test.o
tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos-obj-y)
tests/arm-cpu-features$(EXESUF): tests/arm-cpu-features.o
+tests/test-query-netdevs$(EXESUF): tests/test-query-netdevs.o
tests/migration/stress$(EXESUF): tests/migration/stress.o
$(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
diff --git a/tests/test-query-netdevs.c b/tests/test-query-netdevs.c
new file mode 100644
index 0000000000..2afde36114
--- /dev/null
+++ b/tests/test-query-netdevs.c
@@ -0,0 +1,114 @@
+/*
+ * QTest testcase for the query-netdevs
+ *
+ * Copyright Yandex N.V., 2019
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2. See
+ * the COPYING file in the top-level directory.
+ *
+ */
+
+#include "qemu/osdep.h"
+
+#include "libqtest.h"
+#include "qapi/qmp/qdict.h"
+#include "qapi/qmp/qlist.h"
+
+/*
+ * Events can get in the way of responses we are actually waiting for.
+ */
+GCC_FMT_ATTR(2, 3)
+static QObject *wait_command(QTestState *who, const char *command, ...)
+{
+ va_list ap;
+ QDict *response;
+ QObject *result;
+
+ va_start(ap, command);
+ qtest_qmp_vsend(who, command, ap);
+ va_end(ap);
+
+ response = qtest_qmp_receive(who);
+
+ result = qdict_get(response, "return");
+ g_assert(result);
+ qobject_ref(result);
+ qobject_unref(response);
+
+ return result;
+}
+
+static void qmp_query_netdevs_no_error(QTestState *qts,
+ size_t netdevs_count)
+{
+ QObject *resp;
+ QList *netdevs;
+
+ resp = wait_command(qts, "{'execute': 'x-query-netdevs'}");
+
+ netdevs = qobject_to(QList, resp);
+ g_assert(netdevs);
+ g_assert(qlist_size(netdevs) == netdevs_count);
+
+ qobject_unref(resp);
+}
+
+static void test_query_netdevs(void)
+{
+ const char *arch = qtest_get_arch();
+ size_t correction = 0;
+ QObject *resp;
+ QTestState *state;
+
+ if (strcmp(arch, "arm") == 0 ||
+ strcmp(arch, "aarch64") == 0 ||
+ strcmp(arch, "tricore") == 0) {
+ g_test_skip("Not supported without machine type");
+ return;
+ }
+
+ /* Archs with default not unpluggable netdev */
+ if (strcmp(arch, "cris") == 0 ||
+ strcmp(arch, "microblaze") == 0 ||
+ strcmp(arch, "microblazeel") == 0 ||
+ strcmp(arch, "sparc") == 0) {
+ correction = 1;
+ }
+
+ state = qtest_init(
+ "-nodefaults "
+ "-netdev user,id=slirp0");
+ g_assert(state);
+
+ qmp_query_netdevs_no_error(state, 1 + correction);
+
+ resp = wait_command(state,
+ "{'execute': 'netdev_add', 'arguments': {"
+ " 'id': 'slirp1',"
+ " 'type': 'user'}}");
+ qobject_unref(resp);
+
+ qmp_query_netdevs_no_error(state, 2 + correction);
+
+ resp = wait_command(state,
+ "{'execute': 'netdev_del', 'arguments': {"
+ " 'id': 'slirp1'}}");
+ qobject_unref(resp);
+
+ qmp_query_netdevs_no_error(state, 1 + correction);
+
+ qtest_quit(state);
+}
+
+int main(int argc, char **argv)
+{
+ int ret = 0;
+ g_test_init(&argc, &argv, NULL);
+
+ qtest_add_func("/net/qapi/query_netdevs",
+ test_query_netdevs);
+
+ ret = g_test_run();
+
+ return ret;
+}
--
2.17.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 1/2] qapi: net: Add query-netdevs command
2019-11-13 21:25 ` [PATCH 1/2] qapi: net: Add " Alexey Kirillov
@ 2019-11-13 21:31 ` Eric Blake
0 siblings, 0 replies; 7+ messages in thread
From: Eric Blake @ 2019-11-13 21:31 UTC (permalink / raw)
To: Alexey Kirillov, Jason Wang, Samuel Thibault, Markus Armbruster
Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Vincenzo Maffione,
yc-core, Giuseppe Lettieri, Luigi Rizzo
On 11/13/19 3:25 PM, Alexey Kirillov wrote:
> Add a qmp command that provides information about currently attached
> network devices and their configuration.
>
> Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru>
> ---
> +++ b/qapi/net.json
> @@ -754,3 +754,88 @@
> ##
> { 'event': 'FAILOVER_NEGOTIATED',
> 'data': {'device-id': 'str'} }
> +
> +##
> +# @NetdevInfo:
> +#
> +# Configuration of a network device.
> +#
> +# @id: Device identifier.
> +#
> +# @type: Specify the driver used for interpreting remaining arguments.
> +#
> +# @peer: Connected network device.
> +#
> +# @queues_count: Number of queues.
Unless there is a strong reason otherwise, this should be 'queues-count'.
> +#
> +# @hub: hubid of hub, if connected to.
> +#
> +# Since: 4.2
> +##
> +{ 'union': 'NetdevInfo',
> + 'base': { 'id': 'str',
> + 'type': 'NetClientDriver',
> + '*peer': 'str',
> + 'queues_count': 'int',
> + '*hub': 'int' },
> + 'discriminator': 'type',
> + 'data': {
> + 'nic': 'NetLegacyNicOptions',
> + 'user': 'NetdevUserOptions',
> + 'tap': 'NetdevTapOptions',
> + 'l2tpv3': 'NetdevL2TPv3Options',
> + 'socket': 'NetdevSocketOptions',
> + 'vde': 'NetdevVdeOptions',
> + 'bridge': 'NetdevBridgeOptions',
> + 'hubport': 'NetdevHubPortOptions',
> + 'netmap': 'NetdevNetmapOptions',
> + 'vhost-user': 'NetdevVhostUserOptions' } }
> +
> +##
> +# @x-query-netdevs:
What are the reasons for the x- prefix? Are we planning on changing
this interface down the road? If so, what changes might we make?
> +#
> +# Get a list of @NetdevInfo for all virtual network devices.
> +#
> +# Returns: a list of @NetdevInfo describing each virtual network device.
> +#
> +# Since: 4.2
This is a new feature; as such, it's too late to make it into 4.2;
you'll want to change this to 5.0.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/2] Introducing QMP query-netdevs command
2019-11-13 21:25 [PATCH 0/2] Introducing QMP query-netdevs command Alexey Kirillov
2019-11-13 21:25 ` [PATCH 1/2] qapi: net: Add " Alexey Kirillov
2019-11-13 21:25 ` [PATCH 2/2] tests: Add tests for " Alexey Kirillov
@ 2019-11-13 21:32 ` Eric Blake
2019-11-13 21:48 ` Alexey Kirillov
2 siblings, 1 reply; 7+ messages in thread
From: Eric Blake @ 2019-11-13 21:32 UTC (permalink / raw)
To: Alexey Kirillov, Jason Wang, Samuel Thibault, Markus Armbruster
Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Vincenzo Maffione,
yc-core, Giuseppe Lettieri, Luigi Rizzo
On 11/13/19 3:25 PM, Alexey Kirillov wrote:
> This patch introduces a new QMP command "query-netdevs" to get information
> about currently attached network devices.
> Potentially, this patch makes the "info_str" field of "struct NetClientState"
> and HMP command "info network" obsolete as new command gives out more
> information in a structured way.
Can we rewrite the existing HMP command to call into the new QMP command?
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3226
Virtualization: qemu.org | libvirt.org
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 0/2] Introducing QMP query-netdevs command
2019-11-13 21:32 ` [PATCH 0/2] Introducing QMP " Eric Blake
@ 2019-11-13 21:48 ` Alexey Kirillov
0 siblings, 0 replies; 7+ messages in thread
From: Alexey Kirillov @ 2019-11-13 21:48 UTC (permalink / raw)
To: Eric Blake, Jason Wang, Samuel Thibault, Markus Armbruster
Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Vincenzo Maffione,
yc-core, Giuseppe Lettieri, Luigi Rizzo
That's a good idea, thanks! I'll do this in V2.
14.11.2019, 00:32, "Eric Blake" <eblake@redhat.com>:
>
> Can we rewrite the existing HMP command to call into the new QMP command?
>
--
Alex Kirillov
Yandex.Cloud
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH 2/2] tests: Add tests for query-netdevs command
2019-11-13 21:25 ` [PATCH 2/2] tests: Add tests for " Alexey Kirillov
@ 2019-11-14 11:28 ` Thomas Huth
0 siblings, 0 replies; 7+ messages in thread
From: Thomas Huth @ 2019-11-14 11:28 UTC (permalink / raw)
To: Alexey Kirillov, Jason Wang, Samuel Thibault, Markus Armbruster
Cc: Michael S. Tsirkin, Jan Kiszka, qemu-devel, Vincenzo Maffione,
yc-core, Giuseppe Lettieri, Luigi Rizzo
On 13/11/2019 22.25, Alexey Kirillov wrote:
> Signed-off-by: Alexey Kirillov <lekiravi@yandex-team.ru>
> ---
> tests/Makefile.include | 2 +
> tests/test-query-netdevs.c | 114 +++++++++++++++++++++++++++++++++++++
> 2 files changed, 116 insertions(+)
> create mode 100644 tests/test-query-netdevs.c
>
> diff --git a/tests/Makefile.include b/tests/Makefile.include
> index 534ee48743..4d199e463b 100644
> --- a/tests/Makefile.include
> +++ b/tests/Makefile.include
> @@ -297,6 +297,7 @@ check-qtest-s390x-y += tests/migration-test$(EXESUF)
> check-qtest-generic-y += tests/machine-none-test$(EXESUF)
> check-qtest-generic-y += tests/qom-test$(EXESUF)
> check-qtest-generic-y += tests/test-hmp$(EXESUF)
> +check-qtest-generic-y += tests/test-query-netdevs$(EXESUF)
Please use -$(CONFIG_SLIRP) instead of "-y" here.
> qapi-schema += alternate-any.json
> qapi-schema += alternate-array.json
> @@ -844,6 +845,7 @@ tests/numa-test$(EXESUF): tests/numa-test.o
> tests/vmgenid-test$(EXESUF): tests/vmgenid-test.o tests/boot-sector.o tests/acpi-utils.o
> tests/cdrom-test$(EXESUF): tests/cdrom-test.o tests/boot-sector.o $(libqos-obj-y)
> tests/arm-cpu-features$(EXESUF): tests/arm-cpu-features.o
> +tests/test-query-netdevs$(EXESUF): tests/test-query-netdevs.o
>
> tests/migration/stress$(EXESUF): tests/migration/stress.o
> $(call quiet-command, $(LINKPROG) -static -O3 $(PTHREAD_LIB) -o $@ $< ,"LINK","$(TARGET_DIR)$@")
> diff --git a/tests/test-query-netdevs.c b/tests/test-query-netdevs.c
> new file mode 100644
> index 0000000000..2afde36114
> --- /dev/null
> +++ b/tests/test-query-netdevs.c
> @@ -0,0 +1,114 @@
> +/*
> + * QTest testcase for the query-netdevs
> + *
> + * Copyright Yandex N.V., 2019
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. See
Please use "GNU GPL, version 2 or later" for new code (as described in
the bottom part of the LICENSE file in the top directory).
> + * the COPYING file in the top-level directory.
> + *
> + */
[...]
> +static void test_query_netdevs(void)
> +{
> + const char *arch = qtest_get_arch();
> + size_t correction = 0;
> + QObject *resp;
> + QTestState *state;
> +
> + if (strcmp(arch, "arm") == 0 ||
> + strcmp(arch, "aarch64") == 0 ||
> + strcmp(arch, "tricore") == 0) {
> + g_test_skip("Not supported without machine type");
Since you're doing the check for the target architecture anyway, you
could also use "-M virt" for arm/aarch64 and "-M tricore_testboard" for
tricore, I think.
> + return;
> + }
> +
> + /* Archs with default not unpluggable netdev */
maybe better: "Archs which still have a netdev despite of -nodefaults" ?
> + if (strcmp(arch, "cris") == 0 ||
> + strcmp(arch, "microblaze") == 0 ||
> + strcmp(arch, "microblazeel") == 0 ||
> + strcmp(arch, "sparc") == 0) {
> + correction = 1;
> + }
Just a matter of taste, but I like "g_str_equal()" more than the
old-fashioned "strcmp() == 0".
Thomas
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2019-11-14 11:30 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-11-13 21:25 [PATCH 0/2] Introducing QMP query-netdevs command Alexey Kirillov
2019-11-13 21:25 ` [PATCH 1/2] qapi: net: Add " Alexey Kirillov
2019-11-13 21:31 ` Eric Blake
2019-11-13 21:25 ` [PATCH 2/2] tests: Add tests for " Alexey Kirillov
2019-11-14 11:28 ` Thomas Huth
2019-11-13 21:32 ` [PATCH 0/2] Introducing QMP " Eric Blake
2019-11-13 21:48 ` Alexey Kirillov
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).