[PATCH v9 1/9] net: introduce backend-connect concept

Vladimir Sementsov-Ogievskiy posted 9 patches 2 weeks ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, "Daniel P. Berrangé" <berrange@redhat.com>, Eduardo Habkost <eduardo@habkost.net>, Jason Wang <jasowang@redhat.com>
[PATCH v9 1/9] net: introduce backend-connect concept
Posted by Vladimir Sementsov-Ogievskiy 2 weeks ago
To implement in future backend-transfer migration for virtio-net,
i.e. we are going to migrate TAP fd and some other TAP properties,
we'll need a possibility to postpone opening TAP device until the
point where we are know what user wants: open TAP device, or wait
from fd coming in migration stream.

So, new interface is here: since this commit, net backends may
postpone some initialization actions (like opening or connecting)
up to call of .backend_connect() handler.

Currently, for all net drivers, .backend_connect() is called
during set of netdev property, so drivers continue to work with
already "connected" backends.

Still, we add a possibility for drivers to use new
DEFINE_NIC_PROPERTIES_NO_CONNECT() instead of
DEFINE_NIC_PROPERTIES(). This way, driver take responsibility
to call net_backend_connect() in its own. So, in future we'll
use it in vritio-net, to finally implement backand-transfer
migration fot TAP backend.

Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@yandex-team.ru>
---
 hw/core/qdev-properties-system.c    | 29 +++++++++++++++++++++++++++--
 include/hw/qdev-properties-system.h |  2 ++
 include/net/net.h                   |  6 ++++++
 net/net.c                           | 15 +++++++++++++++
 4 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/hw/core/qdev-properties-system.c b/hw/core/qdev-properties-system.c
index 13cc91680b..0b2668a45f 100644
--- a/hw/core/qdev-properties-system.c
+++ b/hw/core/qdev-properties-system.c
@@ -415,8 +415,8 @@ static void get_netdev(Object *obj, Visitor *v, const char *name,
     g_free(p);
 }
 
-static void set_netdev(Object *obj, Visitor *v, const char *name,
-                       void *opaque, Error **errp)
+static void do_set_netdev(Object *obj, Visitor *v, const char *name,
+                          void *opaque, bool connect, Error **errp)
 {
     const Property *prop = opaque;
     NICPeers *peers_ptr = object_field_prop_ptr(obj, prop);
@@ -463,6 +463,12 @@ static void set_netdev(Object *obj, Visitor *v, const char *name,
             }
         }
 
+        if (connect) {
+            if (!net_backend_connect(peers[i], errp)) {
+                goto out;
+            }
+        }
+
         ncs[i] = peers[i];
         ncs[i]->queue_index = i;
     }
@@ -474,6 +480,18 @@ out:
     g_free(str);
 }
 
+static void set_netdev(Object *obj, Visitor *v, const char *name,
+                          void *opaque, Error **errp)
+{
+    return do_set_netdev(obj, v, name, opaque, true, errp);
+}
+
+static void set_netdev_no_connect(Object *obj, Visitor *v, const char *name,
+                                  void *opaque, Error **errp)
+{
+    return do_set_netdev(obj, v, name, opaque, false, errp);
+}
+
 const PropertyInfo qdev_prop_netdev = {
     .type  = "str",
     .description = "ID of a netdev to use as a backend",
@@ -481,6 +499,13 @@ const PropertyInfo qdev_prop_netdev = {
     .set   = set_netdev,
 };
 
+const PropertyInfo qdev_prop_netdev_no_connect = {
+    .type  = "str",
+    .description = "ID of a netdev to use as a backend",
+    .get   = get_netdev,
+    .set   = set_netdev_no_connect,
+};
+
 
 /* --- audiodev --- */
 static void get_audiodev(Object *obj, Visitor *v, const char* name,
diff --git a/include/hw/qdev-properties-system.h b/include/hw/qdev-properties-system.h
index 5c6cc5eae8..f41b5edadc 100644
--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -41,6 +41,8 @@ extern const PropertyInfo qdev_prop_virtio_gpu_output_list;
     DEFINE_PROP(_n, _s, _f, qdev_prop_chr, CharFrontend)
 #define DEFINE_PROP_NETDEV(_n, _s, _f)             \
     DEFINE_PROP(_n, _s, _f, qdev_prop_netdev, NICPeers)
+#define DEFINE_PROP_NETDEV_NO_CONNECT(_n, _s, _f) \
+    DEFINE_PROP(_n, _s, _f, qdev_prop_netdev_no_connect, NICPeers)
 #define DEFINE_PROP_DRIVE(_n, _s, _f) \
     DEFINE_PROP(_n, _s, _f, qdev_prop_drive, BlockBackend *)
 #define DEFINE_PROP_DRIVE_IOTHREAD(_n, _s, _f) \
diff --git a/include/net/net.h b/include/net/net.h
index 72b476ee1d..3aa67db57c 100644
--- a/include/net/net.h
+++ b/include/net/net.h
@@ -51,6 +51,9 @@ typedef struct NetOffloads {
     DEFINE_PROP_MACADDR("mac",   _state, _conf.macaddr),                \
     DEFINE_PROP_NETDEV("netdev", _state, _conf.peers)
 
+#define DEFINE_NIC_PROPERTIES_NO_CONNECT(_state, _conf)                 \
+    DEFINE_PROP_MACADDR("mac",   _state, _conf.macaddr),                \
+    DEFINE_PROP_NETDEV_NO_CONNECT("netdev", _state, _conf.peers)
 
 /* Net clients */
 
@@ -82,6 +85,7 @@ typedef void (NetAnnounce)(NetClientState *);
 typedef bool (SetSteeringEBPF)(NetClientState *, int);
 typedef bool (NetCheckPeerType)(NetClientState *, ObjectClass *, Error **);
 typedef struct vhost_net *(GetVHostNet)(NetClientState *nc);
+typedef bool (NetBackendConnect)(NetClientState *, Error **);
 
 typedef struct NetClientInfo {
     NetClientDriver type;
@@ -110,6 +114,7 @@ typedef struct NetClientInfo {
     SetSteeringEBPF *set_steering_ebpf;
     NetCheckPeerType *check_peer_type;
     GetVHostNet *get_vhost_net;
+    NetBackendConnect *backend_connect;
 } NetClientInfo;
 
 struct NetClientState {
@@ -322,6 +327,7 @@ void net_cleanup(void);
 void hmp_host_net_add(Monitor *mon, const QDict *qdict);
 void hmp_host_net_remove(Monitor *mon, const QDict *qdict);
 void netdev_add(QemuOpts *opts, Error **errp);
+bool net_backend_connect(NetClientState *nc, Error **errp);
 
 int net_hub_id_for_client(NetClientState *nc, int *id);
 
diff --git a/net/net.c b/net/net.c
index 27e0d27807..4fc6b1d0a6 100644
--- a/net/net.c
+++ b/net/net.c
@@ -2162,3 +2162,18 @@ int net_fill_rstate(SocketReadState *rs, const uint8_t *buf, int size)
     assert(size == 0);
     return 0;
 }
+
+bool net_backend_connect(NetClientState *nc, Error **errp)
+{
+    if (!nc->info->backend_connect) {
+        /*
+         * For most net backends from net/, the connection with
+         * some external entity is don in init function, defined
+         * in net_client_init_fun[] list. They don't have separate
+         * .backend_connect.
+         */
+        return true;
+    }
+
+    return nc->info->backend_connect(nc, errp);
+}
-- 
2.48.1
Re: [PATCH v9 1/9] net: introduce backend-connect concept
Posted by Vladimir Sementsov-Ogievskiy 2 weeks ago
On 30.10.25 20:19, Vladimir Sementsov-Ogievskiy wrote:
> To implement in future backend-transfer migration for virtio-net,
> i.e. we are going to migrate TAP fd and some other TAP properties,
> we'll need a possibility to postpone opening TAP device until the
> point where we are know what user wants: open TAP device, or wait
> from fd coming in migration stream.
> 
> So, new interface is here: since this commit, net backends may
> postpone some initialization actions (like opening or connecting)
> up to call of .backend_connect() handler.
> 
> Currently, for all net drivers, .backend_connect() is called
> during set of netdev property, so drivers continue to work with
> already "connected" backends.
> 
> Still, we add a possibility for drivers to use new
> DEFINE_NIC_PROPERTIES_NO_CONNECT() instead of
> DEFINE_NIC_PROPERTIES(). This way, driver take responsibility
> to call net_backend_connect() in its own. So, in future we'll
> use it in vritio-net, to finally implement backand-transfer
> migration fot TAP backend.
> 
> Signed-off-by: Vladimir Sementsov-Ogievskiy<vsementsov@yandex-team.ru>


fixup for this commit (otherwise new macro is impossible to use):

--- a/include/hw/qdev-properties-system.h
+++ b/include/hw/qdev-properties-system.h
@@ -20,6 +20,7 @@ extern const PropertyInfo qdev_prop_fdc_drive_type;
  extern const PropertyInfo qdev_prop_drive;
  extern const PropertyInfo qdev_prop_drive_iothread;
  extern const PropertyInfo qdev_prop_netdev;
+extern const PropertyInfo qdev_prop_netdev_no_connect;
  extern const PropertyInfo qdev_prop_pci_devfn;
  extern const PropertyInfo qdev_prop_blocksize;
  extern const PropertyInfo qdev_prop_pci_host_devaddr;

-- 
Best regards,
Vladimir