On 01/07/2025 03:46, Jason Wang wrote:
On Wed, Jun 18, 2025 at 11:58 PM Laurent Vivier <lviv...@redhat.com> wrote:

This commit introduces support for passt as a new network backend.
passt is an unprivileged, user-mode networking solution that provides
connectivity for virtual machines by launching an external helper process.

The implementation reuses the generic stream data handling logic. It
launches the passt binary using GSubprocess, passing it a file
descriptor from a socketpair() for communication. QEMU connects to
the other end of the socket pair to establish the network data stream.

The PID of the passt daemon is tracked via a temporary file to
ensure it is terminated when QEMU exits.

Signed-off-by: Laurent Vivier <lviv...@redhat.com>
---
  hmp-commands.hx   |   3 +
  meson.build       |   6 +
  meson_options.txt |   2 +
  net/clients.h     |   4 +
  net/hub.c         |   3 +
  net/meson.build   |   3 +
  net/net.c         |   4 +
  net/passt.c       | 434 ++++++++++++++++++++++++++++++++++++++++++++++
  qapi/net.json     | 124 +++++++++++++
  qemu-options.hx   |  18 ++
  10 files changed, 601 insertions(+)
  create mode 100644 net/passt.c

...
+static int net_passt_start_daemon(NetPasstState *s, int sock, Error **errp)
+{
+    g_autoptr(GSubprocess) daemon = NULL;
+    g_autofree gchar *contents = NULL;
+    g_autoptr(GError) error = NULL;
+    GSubprocessLauncher *launcher;
+
+    qemu_set_info_str(&s->data.nc, "launching passt");
+
+    launcher = g_subprocess_launcher_new(G_SUBPROCESS_FLAGS_NONE);
+    g_subprocess_launcher_take_fd(launcher, sock, 3);
+
+    daemon =  g_subprocess_launcher_spawnv(launcher,
+                                           (const gchar *const 
*)s->args->pdata,
+                                           &error);

I wonder if such launching is a must or at least we should allow
accepting fd from the management layer (e.g in the case that execve()
is restricted)?

In this case, the user should use the existing interface: externally start passt and use "-netdev vhost-user" or '-netdev stream'. It's already managed by libvirt. I think this is a case we shouldn't manage here.

+    g_object_unref(launcher);
+
+    if (!daemon) {
+        error_setg(errp, "Error creating daemon: %s", error->message);
+        return -1;
+    }
+
+    if (!g_subprocess_wait(daemon, NULL, &error)) {
+        error_setg(errp, "Error waiting for daemon: %s", error->message);
+        return -1;
+    }
+
+    if (g_subprocess_get_if_exited(daemon) &&
+        g_subprocess_get_exit_status(daemon)) {
+        return -1;
+    }
+
+    if (!g_file_get_contents(s->pidfile, &contents, NULL, &error)) {
+        error_setg(errp, "Cannot read passt pid: %s", error->message);
+        return -1;
+    }
+
+    s->pid = (pid_t)g_ascii_strtoll(contents, NULL, 10);
+    if (s->pid <= 0) {
+        error_setg(errp, "File '%s' did not contain a valid PID.", s->pidfile);
+        return -1;
+    }
+
+    return 0;
+}
+

...

+    if (net_passt_stream_start(s, errp) == -1) {
+        qemu_del_net_client(nc);
+        return -1;
+    }
+
+    return 0;
+}
diff --git a/qapi/net.json b/qapi/net.json
index 97ea1839813b..76d7654414f7 100644
--- a/qapi/net.json
+++ b/qapi/net.json
@@ -112,6 +112,125 @@
    'data': {
      'str': 'str' } }

+##
+# @NetDevPasstOptions:
+#
+# Unprivileged user-mode network connectivity using passt
+#
+# @path: path to passt binary
+#
+# @quiet: don't print informational messages
+#
+# @debug: be verbose
+#
+# @trace: extra verbose
+#
+# @vhost-user: enable vhost-user
+#
+# @pcap-file: log traffic to pcap file
+#
+# @mtu: assign MTU via DHCP/NDP
+#
+# @address: IPv4 or IPv6 address
+#
+# @netmask: IPv4 mask
+#
+# @mac: source MAC address
+#
+# @gateway: IPv4 or IPv6 address as gateway
+#
+# @interface: interface for addresses and routes
+#
+# @outbound: bind to address as outbound source
+#
+# @outbound-if4: bind to outbound interface for IPv4
+#
+# @outbound-if6: bind to outbound interface for IPv6
+#
+# @dns: IPv4 or IPv6 address as DNS
+#
+# @search: search domains
+#
+# @fqdn: FQDN to configure client with
+#
+# @dhcp-dns: enable/disable DNS list in DHCP/DHCPv6/NDP
+#
+# @dhcp-search: enable/disable list in DHCP/DHCPv6/NDP
+#
+# @map-host-loopback: addresse to refer to host
+#
+# @map-guest-addr: addr to translate to guest's address
+#
+# @dns-forward: forward DNS queries sent to
+#
+# @dns-host: host nameserver to direct queries to
+#
+# @tcp: enable/disable TCP
+#
+# @udp: enable/disable UDP
+#
+# @icmp: enable/disable ICMP
+#
+# @dhcp: enable/disable DHCP
+#
+# @ndp: enable/disable NDP
+#
+# @dhcpv6: enable/disable DHCPv6
+#
+# @ra: enable/disable route advertisements
+#
+# @freebind: bind to any address for forwarding
+#
+# @ipv4: enable/disable IPv4
+#
+# @ipv6: enable/disable IPv6
+#
+# @tcp-ports: TCP ports to forward
+#
+# @udp-ports: UDP ports to forward
+#
+# Since: 10.1
+##
+{ 'struct': 'NetDevPasstOptions',
+  'data': {
+    '*path':               'str',
+    '*quiet':              'bool',
+    '*debug':              'bool',
+    '*trace':              'bool',
+    '*vhost-user':         'bool',
+    '*pcap-file':          'str',
+    '*mtu':                'int',
+    '*address':            'str',
+    '*netmask':            'str',
+    '*mac':                'str',
+    '*gateway':            'str',
+    '*interface':          'str',
+    '*outbound':           'str',
+    '*outbound-if4':       'str',
+    '*outbound-if6':       'str',
+    '*dns':                'str',
+    '*search':             ['String'],
+    '*fqdn':               'str',
+    '*dhcp-dns':           'bool',
+    '*dhcp-search':        'bool',
+    '*map-host-loopback':  'str',
+    '*map-guest-addr':     'str',
+    '*dns-forward':        'str',
+    '*dns-host':           'str',
+    '*tcp':                'bool',
+    '*udp':                'bool',
+    '*icmp':               'bool',
+    '*dhcp':               'bool',
+    '*ndp':                'bool',
+    '*dhcpv6':             'bool',
+    '*ra':                 'bool',
+    '*freebind':           'bool',
+    '*ipv4':               'bool',
+    '*ipv6':               'bool',
+    '*tcp-ports':          ['String'],
+    '*udp-ports':          ['String'] },
+    'if': 'CONFIG_PASST' }

I would like to know the plan to support migration and its
compatibility for passt.

As I said, the goal of this series is to be able to use '-nic passt' as we can use '-nic user'. '-nic user' supports migration but TCP connections are lost.

With this series '-nic passt' supports migration but TCP connections are lost.

But we can improve '-nic passt' because we can migrate TCP connections too, for that we need to launch passt-repair and to use vhost-user, if we really want to do this it can be added (with a 'migration=on' parameter?)... but it's also already managed by '-netdev vhost-user' and passt started manually or by libvirt.

Thanks,
Laurent


Reply via email to