* [Qemu-devel] [RFC PATCH 1/2] Implement netdev_set command
2012-05-02 16:06 [Qemu-devel] [RFC PATCH 0/2] Decouple netdev from nic Vasilis Liaskovitis
@ 2012-05-02 16:06 ` Vasilis Liaskovitis
2012-05-02 16:06 ` [Qemu-devel] [RFC PATCH 2/2] virtio-net: re-initialize tap device for new netdev Vasilis Liaskovitis
1 sibling, 0 replies; 3+ messages in thread
From: Vasilis Liaskovitis @ 2012-05-02 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, armbru, lcapitulino, Vasilis Liaskovitis, snaiksat
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(-)
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,
--
1.7.9
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [Qemu-devel] [RFC PATCH 2/2] virtio-net: re-initialize tap device for new netdev
2012-05-02 16:06 [Qemu-devel] [RFC PATCH 0/2] Decouple netdev from nic Vasilis Liaskovitis
2012-05-02 16:06 ` [Qemu-devel] [RFC PATCH 1/2] Implement netdev_set command Vasilis Liaskovitis
@ 2012-05-02 16:06 ` Vasilis Liaskovitis
1 sibling, 0 replies; 3+ messages in thread
From: Vasilis Liaskovitis @ 2012-05-02 16:06 UTC (permalink / raw)
To: qemu-devel; +Cc: aliguori, armbru, lcapitulino, Vasilis Liaskovitis, snaiksat
When a nic's backend netdev device is changed, the tap device needs to be
re-initialized for vnet_hdr and offload features. Also, vhost will have to
be re-initialized. This is currently implemented in the virtio set_status
callback function.
Signed-off-by: Vasilis Liaskovitis <vasilis.liaskovitis@profitbricks.com>
---
hw/virtio-net.c | 30 ++++++++++++++++++++++++++++++
1 files changed, 30 insertions(+), 0 deletions(-)
diff --git a/hw/virtio-net.c b/hw/virtio-net.c
index bc5e3a8..858434a 100644
--- a/hw/virtio-net.c
+++ b/hw/virtio-net.c
@@ -63,6 +63,7 @@ typedef struct VirtIONet
} mac_table;
uint32_t *vlans;
DeviceState *qdev;
+ VLANClientState *old_peer;
} VirtIONet;
/* TODO
@@ -137,10 +138,38 @@ static void virtio_net_vhost_status(VirtIONet *n, uint8_t status)
}
}
+static int peer_has_vnet_hdr(VirtIONet *n);
+
static void virtio_net_set_status(struct VirtIODevice *vdev, uint8_t status)
{
VirtIONet *n = to_virtio_net(vdev);
+ uint32_t features;
+
+ /* re-initialize backend netdev if it is has been changed */
+ if (n->old_peer != n->nic->nc.peer) {
+ features = vdev->guest_features;
+
+ if (peer_has_vnet_hdr(n))
+ tap_using_vnet_hdr(n->nic->nc.peer, 1);
+
+ if (n->has_vnet_hdr) {
+ tap_set_offload(n->nic->nc.peer,
+ (features >> VIRTIO_NET_F_GUEST_CSUM) & 1,
+ (features >> VIRTIO_NET_F_GUEST_TSO4) & 1,
+ (features >> VIRTIO_NET_F_GUEST_TSO6) & 1,
+ (features >> VIRTIO_NET_F_GUEST_ECN) & 1,
+ (features >> VIRTIO_NET_F_GUEST_UFO) & 1);
+ }
+ if ((n->nic->nc.peer->info->type == NET_CLIENT_TYPE_TAP) &&
+ tap_get_vhost_net(n->nic->nc.peer)) {
+ vhost_net_ack_features(tap_get_vhost_net(n->nic->nc.peer), features);
+ }
+ /* vhost will have to be restarted */
+ if (n->vhost_started)
+ n->vhost_started = 0;
+ n->old_peer = n->nic->nc.peer;
+ }
virtio_net_vhost_status(n, status);
if (!n->tx_waiting) {
@@ -1044,6 +1073,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf *conf,
n->vlans = g_malloc0(MAX_VLAN >> 3);
n->qdev = dev;
+ n->old_peer = conf->peer;
register_savevm(dev, "virtio-net", -1, VIRTIO_NET_VM_VERSION,
virtio_net_save, virtio_net_load, n);
--
1.7.9
^ permalink raw reply related [flat|nested] 3+ messages in thread