net/qapi: add x-query-usernet command
Add a QMP command to query user-mode network stack (slirp) connection states, providing a structured alternative to "info usernet" HMP. The new command returns a list of UsernetInfo, with hub-id, hub-name, and connection info for each slirp stack. It is marked unstable as it is meant for debugging. Rewrite hmp_info_usernet() as a thin wrapper over qmp_x_query_usernet() so the HMP and QMP paths share the same implementation. This is part of the effort to decouple HMP from QEMU core. Reviewed-by: Daniel P. Berrangé <berrange@redhat.com> Signed-off-by: Marc-Andre Lureau <marcandre.lureau@redhat.com> Message-ID: <20260828-qemu-no-hmp-v5-10-9227de146347@redhat.com>
Marc-André Lureau committed
Aug 28, 2026 at 16:04 UTC
8cb95c6126d6e72a73e983eed47ecb5a95e3248e
2 files changed
+72
-6
net/slirp.c
+28
-6
@@ -43,6 +43,7 @@
43
#include "system/system.h"
44
#include "qemu/cutils.h"
45
#include "qapi/error.h"
46
+#include "qapi/qapi-commands-net.h"
47
#include "qobject/qdict.h"
48
#include "util.h"
49
#include "migration/register.h"
@@ -1200,18 +1201,39 @@ static int slirp_guestfwd(SlirpState *s, const char *config_str, Error **errp)
1201
return -1;
1202
}
1203
1203
-void hmp_info_usernet(Monitor *mon, const QDict *qdict)
1204
+UsernetInfoList *qmp_x_query_usernet(Error **errp)
1205
{
1206
+ UsernetInfoList *head = NULL, **tail = &head;
1207
SlirpState *s;
1208
1209
QTAILQ_FOREACH(s, &slirp_stacks, entry) {
1210
+ UsernetInfo *ui = g_new0(UsernetInfo, 1);
1211
int id;
1209
- bool got_hub_id = net_hub_id_for_client(&s->nc, &id) == 0;
1210
- char *info = slirp_connection_info(s->slirp);
1212
+
1213
+ if (net_hub_id_for_client(&s->nc, &id) == 0) {
1214
+ ui->has_hub_id = true;
1215
+ ui->hub_id = id;
1216
+ }
1217
+ ui->hub_name = g_strdup(s->nc.name);
1218
+ ui->info = slirp_connection_info(s->slirp);
1219
+
1220
+ QAPI_LIST_APPEND(tail, ui);
1221
+ }
1222
+
1223
+ return head;
1224
+}
1225
+
1226
+void hmp_info_usernet(Monitor *mon, const QDict *qdict)
1227
+{
1228
+ g_autoptr(UsernetInfoList) list = NULL;
1229
+ UsernetInfoList *entry;
1230
+
1231
+ list = qmp_x_query_usernet(&error_abort);
1232
+ for (entry = list; entry; entry = entry->next) {
1233
+ UsernetInfo *ui = entry->value;
1234
monitor_printf(mon, "Hub %d (%s):\n%s",
1212
- got_hub_id ? id : -1,
1213
- s->nc.name, info);
1214
- g_free(info);
1235
+ ui->has_hub_id ? (int)ui->hub_id : -1,
1236
+ ui->hub_name, ui->info);
1237
}
1238
}
1239
qapi/net.json
+44
@@ -1261,3 +1261,47 @@
1261
##
1262
{ 'event': 'NETDEV_VHOST_USER_DISCONNECTED',
1263
'data': { 'netdev-id': 'str' } }
1264
+
1265
+##
1266
+# @UsernetInfo:
1267
+#
1268
+# Information about a user-mode network stack (slirp).
1269
+#
1270
+# @hub-id: The hub id, if available.
1271
+#
1272
+# @hub-name: The name of the hub.
1273
+#
1274
+# @info: Network information from slirp.
1275
+#
1276
+# Since: 11.2
1277
+##
1278
+{ 'struct': 'UsernetInfo',
1279
+ 'data': {
1280
+ '*hub-id': 'int',
1281
+ 'hub-name': 'str',
1282
+ 'info': 'str' },
1283
+ 'if': 'CONFIG_SLIRP' }
1284
+
1285
+##
1286
+# @x-query-usernet:
1287
+#
1288
+# Query user-mode network stack connection states.
1289
+#
1290
+# Features:
1291
+#
1292
+# @unstable: This command is meant for debugging.
1293
+#
1294
+# Returns: list of user-mode network stack information.
1295
+#
1296
+# Since: 11.2
1297
+#
1298
+# .. qmp-example::
1299
+#
1300
+# -> { "execute": "x-query-usernet" }
1301
+# <- { "return": [ { "hub-id": 0, "hub-name": "vnet",
1302
+# "info": "..." } ] }
1303
+##
1304
+{ 'command': 'x-query-usernet',
1305
+ 'returns': ['UsernetInfo'],
1306
+ 'if': 'CONFIG_SLIRP',
1307
+ 'features': [ 'unstable' ] }