mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 11:35:19 +00:00
Enable tuning of qemu network tap device "sndbuf" size
This is in response to a request in: https://bugzilla.redhat.com/show_bug.cgi?id=665293 In short, under heavy load, it's possible for qemu's networking to lock up due to the tap device's default 1MB sndbuf being inadequate. adding "sndbuf=0" to the qemu commandline -netdevice option will alleviate this problem (sndbuf=0 actually sets it to 0xffffffff). Because we must be able to explicitly specify "0" as a value, the standard practice of "0 means not specified" won't work here. Instead, virDomainNetDef also has a sndbuf_specified, which defaults to 0, but is set to 1 if some value was given. The sndbuf value is put inside a <tune> element of each <interface> in the domain. The intent is that further tunable settings will also be placed inside this element. <interface type='network'> ... <tune> <sndbuf>0</sndbuf> ... </tune> </interface>
This commit is contained in:
parent
175077fd70
commit
fe053dbea7
@ -1025,6 +1025,16 @@
|
|||||||
<ref name="filterref-node-attributes"/>
|
<ref name="filterref-node-attributes"/>
|
||||||
</element>
|
</element>
|
||||||
</optional>
|
</optional>
|
||||||
|
<optional>
|
||||||
|
<element name="tune">
|
||||||
|
<optional>
|
||||||
|
<!-- size of send buffer for network tap devices -->
|
||||||
|
<element name="sndbuf">
|
||||||
|
<ref name="unsignedInt"/>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
|
</element>
|
||||||
|
</optional>
|
||||||
</interleave>
|
</interleave>
|
||||||
</define>
|
</define>
|
||||||
<define name="virtualPortProfile">
|
<define name="virtualPortProfile">
|
||||||
|
@ -2296,6 +2296,7 @@ err_exit:
|
|||||||
static virDomainNetDefPtr
|
static virDomainNetDefPtr
|
||||||
virDomainNetDefParseXML(virCapsPtr caps,
|
virDomainNetDefParseXML(virCapsPtr caps,
|
||||||
xmlNodePtr node,
|
xmlNodePtr node,
|
||||||
|
xmlXPathContextPtr ctxt,
|
||||||
int flags ATTRIBUTE_UNUSED) {
|
int flags ATTRIBUTE_UNUSED) {
|
||||||
virDomainNetDefPtr def;
|
virDomainNetDefPtr def;
|
||||||
xmlNodePtr cur;
|
xmlNodePtr cur;
|
||||||
@ -2317,12 +2318,16 @@ virDomainNetDefParseXML(virCapsPtr caps,
|
|||||||
virNWFilterHashTablePtr filterparams = NULL;
|
virNWFilterHashTablePtr filterparams = NULL;
|
||||||
virVirtualPortProfileParams virtPort;
|
virVirtualPortProfileParams virtPort;
|
||||||
bool virtPortParsed = false;
|
bool virtPortParsed = false;
|
||||||
|
xmlNodePtr oldnode = ctxt->node;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (VIR_ALLOC(def) < 0) {
|
if (VIR_ALLOC(def) < 0) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctxt->node = node;
|
||||||
|
|
||||||
type = virXMLPropString(node, "type");
|
type = virXMLPropString(node, "type");
|
||||||
if (type != NULL) {
|
if (type != NULL) {
|
||||||
if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
|
if ((int)(def->type = virDomainNetTypeFromString(type)) < 0) {
|
||||||
@ -2610,7 +2615,17 @@ virDomainNetDefParseXML(virCapsPtr caps,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ret = virXPathULong("string(./tune/sndbuf)", ctxt, &def->tune.sndbuf);
|
||||||
|
if (ret >= 0) {
|
||||||
|
def->tune.sndbuf_specified = true;
|
||||||
|
} else if (ret == -2) {
|
||||||
|
virDomainReportError(VIR_ERR_XML_ERROR, "%s",
|
||||||
|
_("sndbuf must be a positive integer"));
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
|
ctxt->node = oldnode;
|
||||||
VIR_FREE(macaddr);
|
VIR_FREE(macaddr);
|
||||||
VIR_FREE(network);
|
VIR_FREE(network);
|
||||||
VIR_FREE(address);
|
VIR_FREE(address);
|
||||||
@ -4348,6 +4363,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
|
|||||||
{
|
{
|
||||||
xmlDocPtr xml;
|
xmlDocPtr xml;
|
||||||
xmlNodePtr node;
|
xmlNodePtr node;
|
||||||
|
xmlXPathContextPtr ctxt = NULL;
|
||||||
virDomainDeviceDefPtr dev = NULL;
|
virDomainDeviceDefPtr dev = NULL;
|
||||||
|
|
||||||
if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "device.xml", NULL,
|
if (!(xml = xmlReadDoc(BAD_CAST xmlStr, "device.xml", NULL,
|
||||||
@ -4364,6 +4380,13 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ctxt = xmlXPathNewContext(xml);
|
||||||
|
if (ctxt == NULL) {
|
||||||
|
virReportOOMError();
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
ctxt->node = node;
|
||||||
|
|
||||||
if (VIR_ALLOC(dev) < 0) {
|
if (VIR_ALLOC(dev) < 0) {
|
||||||
virReportOOMError();
|
virReportOOMError();
|
||||||
goto error;
|
goto error;
|
||||||
@ -4379,7 +4402,7 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
|
|||||||
goto error;
|
goto error;
|
||||||
} else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
|
} else if (xmlStrEqual(node->name, BAD_CAST "interface")) {
|
||||||
dev->type = VIR_DOMAIN_DEVICE_NET;
|
dev->type = VIR_DOMAIN_DEVICE_NET;
|
||||||
if (!(dev->data.net = virDomainNetDefParseXML(caps, node, flags)))
|
if (!(dev->data.net = virDomainNetDefParseXML(caps, node, ctxt, flags)))
|
||||||
goto error;
|
goto error;
|
||||||
} else if (xmlStrEqual(node->name, BAD_CAST "input")) {
|
} else if (xmlStrEqual(node->name, BAD_CAST "input")) {
|
||||||
dev->type = VIR_DOMAIN_DEVICE_INPUT;
|
dev->type = VIR_DOMAIN_DEVICE_INPUT;
|
||||||
@ -4417,11 +4440,12 @@ virDomainDeviceDefPtr virDomainDeviceDefParse(virCapsPtr caps,
|
|||||||
}
|
}
|
||||||
|
|
||||||
xmlFreeDoc(xml);
|
xmlFreeDoc(xml);
|
||||||
|
xmlXPathFreeContext(ctxt);
|
||||||
return dev;
|
return dev;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
xmlFreeDoc(xml);
|
xmlFreeDoc(xml);
|
||||||
|
xmlXPathFreeContext(ctxt);
|
||||||
VIR_FREE(dev);
|
VIR_FREE(dev);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
@ -5092,6 +5116,7 @@ static virDomainDefPtr virDomainDefParseXML(virCapsPtr caps,
|
|||||||
for (i = 0 ; i < n ; i++) {
|
for (i = 0 ; i < n ; i++) {
|
||||||
virDomainNetDefPtr net = virDomainNetDefParseXML(caps,
|
virDomainNetDefPtr net = virDomainNetDefParseXML(caps,
|
||||||
nodes[i],
|
nodes[i],
|
||||||
|
ctxt,
|
||||||
flags);
|
flags);
|
||||||
if (!net)
|
if (!net)
|
||||||
goto error;
|
goto error;
|
||||||
@ -6360,6 +6385,12 @@ virDomainNetDefFormat(virBufferPtr buf,
|
|||||||
VIR_FREE(attrs);
|
VIR_FREE(attrs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (def->tune.sndbuf_specified) {
|
||||||
|
virBufferAddLit(buf, " <tune>\n");
|
||||||
|
virBufferVSprintf(buf, " <sndbuf>%lu</sndbuf>\n", def->tune.sndbuf);
|
||||||
|
virBufferAddLit(buf, " </tune>\n");
|
||||||
|
}
|
||||||
|
|
||||||
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
if (virDomainDeviceInfoFormat(buf, &def->info, flags) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
@ -346,6 +346,10 @@ struct _virDomainNetDef {
|
|||||||
virVirtualPortProfileParams virtPortProfile;
|
virVirtualPortProfileParams virtPortProfile;
|
||||||
} direct;
|
} direct;
|
||||||
} data;
|
} data;
|
||||||
|
struct {
|
||||||
|
bool sndbuf_specified;
|
||||||
|
unsigned long sndbuf;
|
||||||
|
} tune;
|
||||||
char *ifname;
|
char *ifname;
|
||||||
virDomainDeviceInfo info;
|
virDomainDeviceInfo info;
|
||||||
char *filter;
|
char *filter;
|
||||||
|
@ -1584,6 +1584,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
const char *tapfd,
|
const char *tapfd,
|
||||||
const char *vhostfd)
|
const char *vhostfd)
|
||||||
{
|
{
|
||||||
|
bool is_tap = false;
|
||||||
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
virBuffer buf = VIR_BUFFER_INITIALIZER;
|
||||||
|
|
||||||
switch (net->type) {
|
switch (net->type) {
|
||||||
@ -1593,6 +1594,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
virBufferAddLit(&buf, "tap");
|
virBufferAddLit(&buf, "tap");
|
||||||
virBufferVSprintf(&buf, "%cfd=%s", type_sep, tapfd);
|
virBufferVSprintf(&buf, "%cfd=%s", type_sep, tapfd);
|
||||||
type_sep = ',';
|
type_sep = ',';
|
||||||
|
is_tap = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
case VIR_DOMAIN_NET_TYPE_ETHERNET:
|
||||||
@ -1606,6 +1608,7 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
net->data.ethernet.script);
|
net->data.ethernet.script);
|
||||||
type_sep = ',';
|
type_sep = ',';
|
||||||
}
|
}
|
||||||
|
is_tap = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
case VIR_DOMAIN_NET_TYPE_CLIENT:
|
||||||
@ -1659,8 +1662,11 @@ qemuBuildHostNetStr(virDomainNetDefPtr net,
|
|||||||
type_sep, net->info.alias);
|
type_sep, net->info.alias);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (vhostfd && *vhostfd) {
|
if (is_tap) {
|
||||||
virBufferVSprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd);
|
if (vhostfd && *vhostfd)
|
||||||
|
virBufferVSprintf(&buf, ",vhost=on,vhostfd=%s", vhostfd);
|
||||||
|
if (net->tune.sndbuf_specified)
|
||||||
|
virBufferVSprintf(&buf, ",sndbuf=%lu", net->tune.sndbuf);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (virBufferError(&buf)) {
|
if (virBufferError(&buf)) {
|
||||||
@ -4669,6 +4675,15 @@ qemuParseCommandLineNet(virCapsPtr caps,
|
|||||||
} else if (STREQ(keywords[i], "off")) {
|
} else if (STREQ(keywords[i], "off")) {
|
||||||
def->backend = VIR_DOMAIN_NET_BACKEND_TYPE_QEMU;
|
def->backend = VIR_DOMAIN_NET_BACKEND_TYPE_QEMU;
|
||||||
}
|
}
|
||||||
|
} else if (STREQ(keywords[i], "sndbuf") && values[i]) {
|
||||||
|
if (virStrToLong_ul(values[i], NULL, 10, &def->tune.sndbuf) < 0) {
|
||||||
|
qemuReportError(VIR_ERR_INTERNAL_ERROR,
|
||||||
|
_("cannot parse sndbuf size in '%s'"), val);
|
||||||
|
virDomainNetDefFree(def);
|
||||||
|
def = NULL;
|
||||||
|
goto cleanup;
|
||||||
|
}
|
||||||
|
def->tune.sndbuf_specified = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user