Patchwork [RFC,1/2] Implement netdev_set command

login
register
mail settings
Submitter Vasilis Liaskovitis
Date May 2, 2012, 4:06 p.m.
Message ID <1335974802-12984-2-git-send-email-vasilis.liaskovitis@profitbricks.com>
Download mbox | patch
Permalink /patch/156491/
State New
Headers show

Comments

Vasilis Liaskovitis - May 2, 2012, 4:06 p.m.
This command can be used to attach a host backend network device (netdev) to a
guest nic. Syntax is:
netdev_set nicid netdevid

This patch adds qmp and hmp support for the command.

Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
---
 hmp-commands.hx  |   14 +++++++++++++
 hmp.c            |   10 +++++++++
 hmp.h            |    1 +
 net.c            |   58 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 net.h            |    1 +
 qapi-schema.json |   16 ++++++++++++++
 qmp-commands.hx  |   25 +++++++++++++++++++++++
 7 files changed, 125 insertions(+), 0 deletions(-)

Patch

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 54b8592..65ae0bf 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1032,6 +1032,20 @@  STEXI
 Remove host network device.
 ETEXI
 
+    {
+        .name       = "netdev_set",
+        .args_type  = "nicid:s,netdevid:s",
+        .params     = "nicid netdevid",
+        .help       = "attach host network device to nic",
+        .mhandler.cmd = hmp_netdev_set,
+    },
+
+STEXI
+@item netdev_del
+@findex netdev_del
+Attach host network device to nic.
+ETEXI
+
 #ifdef CONFIG_SLIRP
     {
         .name       = "hostfwd_add",
diff --git a/hmp.c b/hmp.c
index 17fddb9..2a817ee 100644
--- a/hmp.c
+++ b/hmp.c
@@ -973,3 +973,13 @@  void hmp_netdev_del(Monitor *mon, const QDict *qdict)
     qmp_netdev_del(id, &err);
     hmp_handle_error(mon, &err);
 }
+
+void hmp_netdev_set(Monitor *mon, const QDict *qdict)
+{
+    const char *nicid = qdict_get_str(qdict, "nicid");
+    const char *netdevid = qdict_get_str(qdict, "netdevid");
+    Error *err = NULL;
+
+    qmp_netdev_set(nicid, netdevid, &err);
+    hmp_handle_error(mon, &err);
+}
diff --git a/hmp.h b/hmp.h
index ca005df..90b12cd 100644
--- a/hmp.h
+++ b/hmp.h
@@ -63,5 +63,6 @@  void hmp_migrate(Monitor *mon, const QDict *qdict);
 void hmp_device_del(Monitor *mon, const QDict *qdict);
 void hmp_netdev_add(Monitor *mon, const QDict *qdict);
 void hmp_netdev_del(Monitor *mon, const QDict *qdict);
+void hmp_netdev_set(Monitor *mon, const QDict *qdict);
 
 #endif
diff --git a/net.c b/net.c
index 4aa416c..a8358a7 100644
--- a/net.c
+++ b/net.c
@@ -674,6 +674,21 @@  VLANClientState *qemu_find_netdev(const char *id)
     return NULL;
 }
 
+VLANClientState *qemu_find_nic(const char *id)
+{
+    VLANClientState *vc;
+
+    QTAILQ_FOREACH(vc, &non_vlan_clients, next) {
+        if (vc->info->type != NET_CLIENT_TYPE_NIC)
+            continue;
+        if (!strcmp(vc->name, id)) {
+            return vc;
+        }
+    }
+
+    return NULL;
+}
+
 static int nic_get_free_idx(void)
 {
     int index;
@@ -1283,6 +1298,49 @@  void qmp_netdev_del(const char *id, Error **errp)
     qemu_opts_del(qemu_opts_find(qemu_find_opts_err("netdev", errp), id));
 }
 
+void qmp_netdev_set(const char *nicid, const char *netdevid, Error **errp)
+{
+    VLANClientState *vc, *nic;
+    NICState *nicstate;
+    DeviceState *qdev;
+
+    nic = qemu_find_nic(nicid);
+    if (!nic) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, nicid);
+    }
+
+    qdev = qdev_find_recursive(sysbus_get_default(), nicid);
+    if (!qdev) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, nicid);
+    }
+
+    vc = qemu_find_netdev(netdevid);
+    if (!vc) {
+        error_set(errp, QERR_DEVICE_NOT_FOUND, netdevid);
+        return;
+    }
+
+    /* for now, only allow tap device assignment*/
+    if (vc->info->type != NET_CLIENT_TYPE_TAP) {
+        error_set(errp, QERR_INVALID_PARAMETER, netdevid);
+        return;
+    }    
+
+    vc->peer = nic;
+    if (nic->peer)
+        nic->peer->peer = NULL;
+    nic->peer = vc;
+
+    nicstate = DO_UPCAST(NICState, nc, nic);
+    if (nicstate->peer_deleted == true)
+        nicstate->peer_deleted = false;
+    nicstate->conf->peer = vc;
+
+    /* this is a hack, qdev properties should not be set after nic
+     * initialization */
+    qdev_prop_parse(qdev, "netdev", netdevid);
+}
+
 static void print_net_client(Monitor *mon, VLANClientState *vc)
 {
     monitor_printf(mon, "%s: type=%s,%s\n", vc->name,
diff --git a/net.h b/net.h
index bdc2a06..c8abf17 100644
--- a/net.h
+++ b/net.h
@@ -90,6 +90,7 @@  struct VLANState {
 
 VLANState *qemu_find_vlan(int id, int allocate);
 VLANClientState *qemu_find_netdev(const char *id);
+VLANClientState *qemu_find_nic(const char *id);
 VLANClientState *qemu_new_net_client(NetClientInfo *info,
                                      VLANState *vlan,
                                      VLANClientState *peer,
diff --git a/qapi-schema.json b/qapi-schema.json
index 5b4ba12..9127238 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -1765,3 +1765,19 @@ 
 # Since: 0.14.0
 ##
 { 'command': 'netdev_del', 'data': {'id': 'str'} }
+
+##
+# @netdev_set:
+#
+# Attach a network backend to a network device.
+#
+# @id: the name of the network device to attach to
+# @netdev: the name of the network backend to attach
+#
+# Returns: Nothing on success
+#          If @id is not a valid network device, DeviceNotFound
+#          If @netdev is not a valid network backend, DeviceNotFound
+#
+# Since: 0.14.0
+##
+{ 'command': 'netdev_set', 'data': {'nicid': 'str', 'netdevid': 'str'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 7a68cad..ee278e4 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -657,6 +657,31 @@  Example:
 EQMP
 
     {
+        .name       = "netdev_set",
+        .args_type  = "nicid:s,netdevid:s",
+        .mhandler.cmd_new = qmp_marshal_input_netdev_set,
+    },
+
+SQMP
+netdev_set
+----------
+
+Attach host network device to guest nic.
+
+Arguments:
+
+- "nicid": the nic device's ID, must be unique (json-string)
+- "netdevid": the host network device's ID, must be unique (json-string)
+
+Example:
+
+-> { "execute": "netdev_set", "arguments": { "nicid": "nic1", "netdevid": "netdev1" } }
+<- { "return": {} }
+
+
+EQMP
+
+    {
         .name       = "block_resize",
         .args_type  = "device:B,size:o",
         .mhandler.cmd_new = qmp_marshal_input_block_resize,