virtio-net-pci specific properties and their types according to QEMU: tx=<str> ioeventfd=<bool> - on/off (default: true) event_idx=<bool> - on/off (default: true) csum=<bool> - on/off (default: true) gso=<bool> - on/off (default: true) host_tso4=<bool> - on/off (default: true) host_tso6=<bool> - on/off (default: true) host_ecn=<bool> - on/off (default: true) host_ufo=<bool> - on/off (default: true) mrg_rxbuf=<bool> - on/off (default: true) guest_csum=<bool> - on/off (default: true) guest_tso4=<bool> - on/off (default: true) guest_tso6=<bool> - on/off (default: true) guest_ecn=<bool> - on/off (default: true) guest_ufo=<bool> - on/off (default: true) mq=<bool> - on/off (default: false) vectors=<uint32> - (default: 4294967295) rx_queue_size=<uint16> - (default: 256) tx_queue_size=<uint16> - (default: 256) host_mtu=<uint16> - (default: 0) failover=<bool> - (default: false) properties common for all network interfaces: netdev=<str> - ID of a netdev to use as a backend mac=<str> - Ethernet 6-byte MAC Address, example: 52:54:00:12:34:56 bootindex=<int32> Signed-off-by: Peter Krempa <pkrempa@xxxxxxxxxx> --- src/qemu/qemu_command.c | 166 +++++++++++++++++----------------------- src/qemu/qemu_command.h | 9 ++- src/qemu/qemu_hotplug.c | 6 +- 3 files changed, 78 insertions(+), 103 deletions(-) diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index a8a93274c6..54f50c9a5e 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -3859,37 +3859,29 @@ qemuBuildLegacyNicStr(virDomainNetDef *net) } -char * -qemuBuildNicDevStr(virDomainDef *def, - virDomainNetDef *net, - size_t vhostfdSize, - virQEMUCaps *qemuCaps) +virJSONValue * +qemuBuildNicDevProps(virDomainDef *def, + virDomainNetDef *net, + size_t vhostfdSize, + virQEMUCaps *qemuCaps) { - g_auto(virBuffer) buf = VIR_BUFFER_INITIALIZER; - bool usingVirtio = false; + g_autoptr(virJSONValue) props = NULL; char macaddr[VIR_MAC_STRING_BUFLEN]; if (virDomainNetIsVirtioModel(net)) { - if (qemuBuildVirtioDevStr(&buf, qemuCaps, VIR_DOMAIN_DEVICE_NET, net) < 0) { - return NULL; - } - - usingVirtio = true; - } else { - virBufferAddStr(&buf, virDomainNetGetModelString(net)); - } + const char *tx = NULL; + virTristateSwitch mq = VIR_TRISTATE_SWITCH_ABSENT; + unsigned long long vectors = 0; + virTristateSwitch failover = VIR_TRISTATE_SWITCH_ABSENT; - if (usingVirtio) { - if (net->driver.virtio.txmode && - virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_TX_ALG)) { - virBufferAddLit(&buf, ",tx="); + if (virQEMUCapsGet(qemuCaps, QEMU_CAPS_VIRTIO_TX_ALG)) { switch (net->driver.virtio.txmode) { case VIR_DOMAIN_NET_VIRTIO_TX_MODE_IOTHREAD: - virBufferAddLit(&buf, "bh"); + tx = "bh"; break; case VIR_DOMAIN_NET_VIRTIO_TX_MODE_TIMER: - virBufferAddLit(&buf, "timer"); + tx = "timer"; break; case VIR_DOMAIN_NET_VIRTIO_TX_MODE_DEFAULT: @@ -3905,100 +3897,80 @@ qemuBuildNicDevStr(virDomainDef *def, return NULL; } } - qemuBuildIoEventFdStr(&buf, net->driver.virtio.ioeventfd, qemuCaps); - if (net->driver.virtio.event_idx) { - virBufferAsprintf(&buf, ",event_idx=%s", - virTristateSwitchTypeToString(net->driver.virtio.event_idx)); - } - if (net->driver.virtio.host.csum) { - virBufferAsprintf(&buf, ",csum=%s", - virTristateSwitchTypeToString(net->driver.virtio.host.csum)); - } - if (net->driver.virtio.host.gso) { - virBufferAsprintf(&buf, ",gso=%s", - virTristateSwitchTypeToString(net->driver.virtio.host.gso)); - } - if (net->driver.virtio.host.tso4) { - virBufferAsprintf(&buf, ",host_tso4=%s", - virTristateSwitchTypeToString(net->driver.virtio.host.tso4)); - } - if (net->driver.virtio.host.tso6) { - virBufferAsprintf(&buf, ",host_tso6=%s", - virTristateSwitchTypeToString(net->driver.virtio.host.tso6)); - } - if (net->driver.virtio.host.ecn) { - virBufferAsprintf(&buf, ",host_ecn=%s", - virTristateSwitchTypeToString(net->driver.virtio.host.ecn)); - } - if (net->driver.virtio.host.ufo) { - virBufferAsprintf(&buf, ",host_ufo=%s", - virTristateSwitchTypeToString(net->driver.virtio.host.ufo)); - } - if (net->driver.virtio.host.mrg_rxbuf) { - virBufferAsprintf(&buf, ",mrg_rxbuf=%s", - virTristateSwitchTypeToString(net->driver.virtio.host.mrg_rxbuf)); - } - if (net->driver.virtio.guest.csum) { - virBufferAsprintf(&buf, ",guest_csum=%s", - virTristateSwitchTypeToString(net->driver.virtio.guest.csum)); - } - if (net->driver.virtio.guest.tso4) { - virBufferAsprintf(&buf, ",guest_tso4=%s", - virTristateSwitchTypeToString(net->driver.virtio.guest.tso4)); - } - if (net->driver.virtio.guest.tso6) { - virBufferAsprintf(&buf, ",guest_tso6=%s", - virTristateSwitchTypeToString(net->driver.virtio.guest.tso6)); - } - if (net->driver.virtio.guest.ecn) { - virBufferAsprintf(&buf, ",guest_ecn=%s", - virTristateSwitchTypeToString(net->driver.virtio.guest.ecn)); - } - if (net->driver.virtio.guest.ufo) { - virBufferAsprintf(&buf, ",guest_ufo=%s", - virTristateSwitchTypeToString(net->driver.virtio.guest.ufo)); - } if (vhostfdSize > 1) { if (net->info.type == VIR_DOMAIN_DEVICE_ADDRESS_TYPE_CCW) { /* ccw provides a one to one relation of fds to queues and * does not support the vectors option */ - virBufferAddLit(&buf, ",mq=on"); + mq = VIR_TRISTATE_SWITCH_ON; } else { /* As advised at https://www.linux-kvm.org/page/Multiqueue * we should add vectors=2*N+2 where N is the vhostfdSize */ - virBufferAsprintf(&buf, ",mq=on,vectors=%zu", 2 * vhostfdSize + 2); + mq = VIR_TRISTATE_SWITCH_ON; + vectors = 2 * vhostfdSize + 2; } } - if (net->driver.virtio.rx_queue_size) - virBufferAsprintf(&buf, ",rx_queue_size=%u", net->driver.virtio.rx_queue_size); - - if (net->driver.virtio.tx_queue_size) - virBufferAsprintf(&buf, ",tx_queue_size=%u", net->driver.virtio.tx_queue_size); + if (net->teaming && net->teaming->type == VIR_DOMAIN_NET_TEAMING_TYPE_PERSISTENT) + failover = VIR_TRISTATE_SWITCH_ON; - if (net->mtu) - virBufferAsprintf(&buf, ",host_mtu=%u", net->mtu); + if (!(props = qemuBuildVirtioDevProps(VIR_DOMAIN_DEVICE_NET, net, qemuCaps))) + return NULL; - if (net->teaming && net->teaming->type == VIR_DOMAIN_NET_TEAMING_TYPE_PERSISTENT) - virBufferAddLit(&buf, ",failover=on"); + if (virJSONValueObjectAdd(props, + "S:tx", tx, + "T:ioeventfd", net->driver.virtio.ioeventfd, + "T:event_idx", net->driver.virtio.event_idx, + "T:csum", net->driver.virtio.host.csum, + "T:gso", net->driver.virtio.host.gso, + "T:host_tso4", net->driver.virtio.host.tso4, + "T:host_tso6", net->driver.virtio.host.tso6, + "T:host_ecn", net->driver.virtio.host.ecn, + "T:host_ufo", net->driver.virtio.host.ufo, + "T:mrg_rxbuf", net->driver.virtio.host.mrg_rxbuf, + "T:guest_csum", net->driver.virtio.guest.csum, + "T:guest_tso4", net->driver.virtio.guest.tso4, + "T:guest_tso6", net->driver.virtio.guest.tso6, + "T:guest_ecn", net->driver.virtio.guest.ecn, + "T:guest_ufo", net->driver.virtio.guest.ufo, + "T:mq", mq, + "P:vectors", vectors, + "p:rx_queue_size", net->driver.virtio.rx_queue_size, + "p:tx_queue_size", net->driver.virtio.tx_queue_size, + "p:host_mtu", net->mtu, + "T:failover", failover, + NULL) < 0) + return NULL; + } else { + if (virJSONValueObjectCreate(&props, + "s:driver", virDomainNetGetModelString(net), + NULL) < 0) + return NULL; } - virBufferAsprintf(&buf, ",netdev=host%s", net->info.alias); - virBufferAsprintf(&buf, ",id=%s", net->info.alias); - virBufferAsprintf(&buf, ",mac=%s", - virMacAddrFormat(&net->mac, macaddr)); + virMacAddrFormat(&net->mac, macaddr); - if (qemuBuildDeviceAddressStr(&buf, def, &net->info) < 0) + if (virJSONValueObjectAdd(props, + "f:netdev", g_strdup_printf("host%s", net->info.alias), + "s:id", net->info.alias, + "s:mac", macaddr, + NULL) < 0) return NULL; - if (qemuBuildRomStr(&buf, &net->info) < 0) + + if (qemuBuildDeviceAddressProps(props, def, &net->info) < 0) return NULL; - if (net->info.effectiveBootIndex > 0) - virBufferAsprintf(&buf, ",bootindex=%u", net->info.effectiveBootIndex); - return virBufferContentAndReset(&buf); + if (qemuBuildRomProps(props, &net->info) < 0) + return NULL; + + if (virJSONValueObjectAdd(props, + "p:bootindex", net->info.effectiveBootIndex, + NULL) < 0) + return NULL; + + return g_steal_pointer(&props); } @@ -8747,6 +8719,7 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver, { virDomainDef *def = vm->def; int ret = -1; + g_autoptr(virJSONValue) nicprops = NULL; g_autofree char *nic = NULL; g_autofree char *chardev = NULL; int *tapfd = NULL; @@ -9010,9 +8983,10 @@ qemuBuildInterfaceCommandLine(virQEMUDriver *driver, if (qemuCommandAddExtDevice(cmd, &net->info, qemuCaps) < 0) goto cleanup; - if (!(nic = qemuBuildNicDevStr(def, net, net->driver.virtio.queues, qemuCaps))) + if (!(nicprops = qemuBuildNicDevProps(def, net, net->driver.virtio.queues, qemuCaps))) + goto cleanup; + if (qemuBuildDeviceCommandlineFromJSON(cmd, nicprops, qemuCaps) < 0) goto cleanup; - virCommandAddArgList(cmd, "-device", nic, NULL); } else if (!requireNicdev) { if (qemuCommandAddExtDevice(cmd, &net->info, qemuCaps) < 0) goto cleanup; diff --git a/src/qemu/qemu_command.h b/src/qemu/qemu_command.h index 18d4c4130b..29db16e729 100644 --- a/src/qemu/qemu_command.h +++ b/src/qemu/qemu_command.h @@ -98,10 +98,11 @@ virJSONValue *qemuBuildHostNetStr(virDomainNetDef *net, const char *vdpadev); /* Current, best practice */ -char *qemuBuildNicDevStr(virDomainDef *def, - virDomainNetDef *net, - size_t vhostfdSize, - virQEMUCaps *qemuCaps); +virJSONValue * +qemuBuildNicDevProps(virDomainDef *def, + virDomainNetDef *net, + size_t vhostfdSize, + virQEMUCaps *qemuCaps); char *qemuDeviceDriveHostAlias(virDomainDiskDef *disk); bool qemuDiskBusIsSD(int bus); diff --git a/src/qemu/qemu_hotplug.c b/src/qemu/qemu_hotplug.c index 1b5f63f271..1c0056da16 100644 --- a/src/qemu/qemu_hotplug.c +++ b/src/qemu/qemu_hotplug.c @@ -1175,7 +1175,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver, int *vhostfd = NULL; size_t vhostfdSize = 0; size_t queueSize = 0; - g_autofree char *nicstr = NULL; + g_autoptr(virJSONValue) nicprops = NULL; g_autoptr(virJSONValue) netprops = NULL; int ret = -1; bool releaseaddr = false; @@ -1484,7 +1484,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver, for (i = 0; i < vhostfdSize; i++) VIR_FORCE_CLOSE(vhostfd[i]); - if (!(nicstr = qemuBuildNicDevStr(vm->def, net, queueSize, priv->qemuCaps))) + if (!(nicprops = qemuBuildNicDevProps(vm->def, net, queueSize, priv->qemuCaps))) goto try_remove; qemuDomainObjEnterMonitor(driver, vm); @@ -1495,7 +1495,7 @@ qemuDomainAttachNetDevice(virQEMUDriver *driver, goto try_remove; } - if (qemuMonitorAddDevice(priv->mon, nicstr) < 0) { + if (qemuMonitorAddDeviceProps(priv->mon, &nicprops) < 0) { ignore_value(qemuDomainDetachExtensionDevice(priv->mon, &net->info)); ignore_value(qemuDomainObjExitMonitor(driver, vm)); virDomainAuditNet(vm, NULL, net, "attach", false); -- 2.31.1