qemu's virtio-net-pci driver allows setting the algorithm used for tx packets to either "bh" or "timer". I don't know exactly how these algorithms differ, but someone has requested the ability to choose between them in libvirt's domain XML. See: https://bugzilla.redhat.com/show_bug.cgi?id=629662 This patch provides that knob, by adding a new attribute "tx_alg" to the <driver> element that can be placed inside any <interface> element in a domain definition. It's use would be something like this: <interface ...> ... <model type='virtio'/> <driver tx_alg='bh'/> ... </interface> I chose to put this setting as an attribute to <driver> rather than as a sub-element to <tune> because it is specific to the virtio-net driver, not something that is generally usable by all network drivers. (note that this is the same placement as the "driver name=..." attribute used to choose kernel vs. userland backend for the virtio-net driver.) This is a bit troublesome to me, because I can see lots of new virtio options that could potentially be requested (just run "qemu-kvm -device virtio-net-pci,?" on a qemu that's version 0.13.0 or newer, and compare that output to potential tunable items in "-device e1000,?" or "-net tap,..."), so the attribute list could potentially get quite long (which is something I was concerned about when I first added the option to select kernel vs. userland backend, but didn't realize just how many virtio-specific options there were). Actually adding the tx=xxx option to the qemu commandline is only done if the version of qemu being used advertises it in the output of qemu -device virtio-net-pci,? If the option isn't listed there, the config item is ignored (should it instead generate a warning log? error out and prevent the domain from starting?) --- src/conf/domain_conf.c | 26 +++++++++++++++++++++++++- src/conf/domain_conf.h | 11 +++++++++++ src/libvirt_private.syms | 1 + src/qemu/qemu_capabilities.c | 3 +++ src/qemu/qemu_capabilities.h | 1 + src/qemu/qemu_command.c | 13 +++++++++++++ 6 files changed, 54 insertions(+), 1 deletions(-) diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 84b866b..8f0f057 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -198,6 +198,11 @@ VIR_ENUM_IMPL(virDomainNetBackend, VIR_DOMAIN_NET_BACKEND_TYPE_LAST, "qemu", "vhost") +VIR_ENUM_IMPL(virDomainNetVirtioTxAlg, VIR_DOMAIN_NET_BACKEND_TYPE_LAST, + "default", + "bh", + "timer") + VIR_ENUM_IMPL(virDomainChrChannelTarget, VIR_DOMAIN_CHR_CHANNEL_TARGET_TYPE_LAST, "guestfwd", @@ -2477,6 +2482,7 @@ virDomainNetDefParseXML(virCapsPtr caps, char *port = NULL; char *model = NULL; char *backend = NULL; + char *tx_alg = NULL; char *filter = NULL; char *internal = NULL; char *devaddr = NULL; @@ -2565,6 +2571,7 @@ virDomainNetDefParseXML(virCapsPtr caps, model = virXMLPropString(cur, "type"); } else if (xmlStrEqual (cur->name, BAD_CAST "driver")) { backend = virXMLPropString(cur, "name"); + tx_alg = virXMLPropString(cur, "tx_alg"); } else if (xmlStrEqual (cur->name, BAD_CAST "filterref")) { filter = virXMLPropString(cur, "filter"); VIR_FREE(filterparams); @@ -2769,6 +2776,18 @@ virDomainNetDefParseXML(virCapsPtr caps, } def->driver.virtio.name = name; } + if (tx_alg != NULL) { + int alg; + if (((alg = virDomainNetVirtioTxAlgTypeFromString(tx_alg)) < 0) || + (alg == VIR_DOMAIN_NET_VIRTIO_TX_ALG_DEFAULT)) { + virDomainReportError(VIR_ERR_INTERNAL_ERROR, + _("Unknown interface <driver tx_alg='%s'> " + "has been specified"), + tx_alg); + goto error; + } + def->driver.virtio.tx_alg = alg; + } } if (filter != NULL) { @@ -2808,6 +2827,7 @@ cleanup: VIR_FREE(bridge); VIR_FREE(model); VIR_FREE(backend); + VIR_FREE(tx_alg); VIR_FREE(filter); VIR_FREE(type); VIR_FREE(internal); @@ -6808,12 +6828,16 @@ virDomainNetDefFormat(virBufferPtr buf, virBufferEscapeString(buf, " <model type='%s'/>\n", def->model); if (STREQ(def->model, "virtio") && - def->driver.virtio.name) { + (def->driver.virtio.name || def->driver.virtio.tx_alg)) { virBufferAddLit(buf, " <driver"); if (def->driver.virtio.name) { virBufferVSprintf(buf, " name='%s'", virDomainNetBackendTypeToString(def->driver.virtio.name)); } + if (def->driver.virtio.tx_alg) { + virBufferVSprintf(buf, " tx_alg='%s'", + virDomainNetVirtioTxAlgTypeToString(def->driver.virtio.tx_alg)); + } virBufferAddLit(buf, "/>\n"); } } diff --git a/src/conf/domain_conf.h b/src/conf/domain_conf.h index 44d0a4b..b3a02f4 100644 --- a/src/conf/domain_conf.h +++ b/src/conf/domain_conf.h @@ -321,6 +321,15 @@ enum virDomainNetBackendType { VIR_DOMAIN_NET_BACKEND_TYPE_LAST, }; +/* the TX algorithm used for virtio interfaces */ +enum virDomainNetVirtioTxAlgType { + VIR_DOMAIN_NET_VIRTIO_TX_ALG_DEFAULT, /* default for this version of qemu */ + VIR_DOMAIN_NET_VIRTIO_TX_ALG_BH, + VIR_DOMAIN_NET_VIRTIO_TX_ALG_TIMER, + + VIR_DOMAIN_NET_VIRTIO_TX_ALG_LAST, +}; + /* the mode type for macvtap devices */ enum virDomainNetdevMacvtapType { VIR_DOMAIN_NETDEV_MACVTAP_MODE_VEPA, @@ -341,6 +350,7 @@ struct _virDomainNetDef { union { struct { enum virDomainNetBackendType name; /* which driver backend to use */ + enum virDomainNetVirtioTxAlgType tx_alg; } virtio; } driver; union { @@ -1367,6 +1377,7 @@ VIR_ENUM_DECL(virDomainFS) VIR_ENUM_DECL(virDomainFSAccessMode) VIR_ENUM_DECL(virDomainNet) VIR_ENUM_DECL(virDomainNetBackend) +VIR_ENUM_DECL(virDomainNetVirtioTxAlg) VIR_ENUM_DECL(virDomainChrDevice) VIR_ENUM_DECL(virDomainChrChannelTarget) VIR_ENUM_DECL(virDomainChrConsoleTarget) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 88e270c..dd44749 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -268,6 +268,7 @@ virDomainMemballoonModelTypeFromString; virDomainMemballoonModelTypeToString; virDomainNetDefFree; virDomainNetTypeToString; +virDomainNetVirtioTxAlgTypeToString; virDomainObjAssignDef; virDomainObjSetDefTransient; virDomainObjGetPersistentDef; diff --git a/src/qemu/qemu_capabilities.c b/src/qemu/qemu_capabilities.c index 0e1f79c..935c669 100644 --- a/src/qemu/qemu_capabilities.c +++ b/src/qemu/qemu_capabilities.c @@ -1063,6 +1063,7 @@ qemuCapsExtractDeviceStr(const char *qemu, "-device", "?", "-device", "pci-assign,?", "-device", "virtio-blk-pci,?", + "-device", "virtio-net-pci,?", NULL); virCommandAddEnvPassCommon(cmd); /* qemu -help goes to stdout, but qemu -device ? goes to stderr. */ @@ -1104,6 +1105,8 @@ qemuCapsParseDeviceStr(const char *str, unsigned long long *flags) if (strstr(str, "pci-assign.bootindex")) *flags |= QEMUD_CMD_FLAG_PCI_BOOTINDEX; } + if (strstr(str, "virtio-net-pci.tx=")) + *flags |= QEMUD_CMD_FLAG_VIRTIO_TX_ALG; return 0; } diff --git a/src/qemu/qemu_capabilities.h b/src/qemu/qemu_capabilities.h index dd39b3b..c29d914 100644 --- a/src/qemu/qemu_capabilities.h +++ b/src/qemu/qemu_capabilities.h @@ -92,6 +92,7 @@ enum qemuCapsFlags { QEMUD_CMD_FLAG_CCID_PASSTHRU = (1LL << 55), /* -device ccid-card-passthru */ QEMUD_CMD_FLAG_CHARDEV_SPICEVMC = (1LL << 56), /* newer -chardev spicevmc */ QEMUD_CMD_FLAG_DEVICE_SPICEVMC = (1LL << 57), /* older -device spicevmc*/ + QEMUD_CMD_FLAG_VIRTIO_TX_ALG = (1LL << 58), /* -device virtio-net-pci,tx=string */ }; virCapsPtr qemuCapsInit(virCapsPtr old_caps); diff --git a/src/qemu/qemu_command.c b/src/qemu/qemu_command.c index 1b213da..1d6f20c 100644 --- a/src/qemu/qemu_command.c +++ b/src/qemu/qemu_command.c @@ -1577,16 +1577,29 @@ qemuBuildNicDevStr(virDomainNetDefPtr net, { virBuffer buf = VIR_BUFFER_INITIALIZER; const char *nic; + bool usingVirtio = false; if (!net->model) { nic = "rtl8139"; } else if (STREQ(net->model, "virtio")) { nic = "virtio-net-pci"; + usingVirtio = true; } else { nic = net->model; } virBufferAdd(&buf, nic, strlen(nic)); + if (usingVirtio && net->driver.virtio.tx_alg) { + if (qemuCmdFlags & QEMUD_CMD_FLAG_VIRTIO_TX_ALG) { + virBufferVSprintf(&buf, ",tx=%s", + virDomainNetVirtioTxAlgTypeToString(net->driver.virtio.tx_alg)); + } else { + /* What should we do if the option isn't available? log a + * warning? prevent the domain from starting? Ignore it? + * Right now we're ignoring it. + */ + } + } if (vlan == -1) virBufferVSprintf(&buf, ",netdev=host%s", net->info.alias); else -- 1.7.3.4 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list