qemu-devel.nongnu.org archive mirror
 help / color / mirror / Atom feed
* [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).