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:
Laine Stump 2011-01-12 14:38:01 -05:00
parent 175077fd70
commit fe053dbea7
4 changed files with 64 additions and 4 deletions

View File

@ -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">

View File

@ -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;

View File

@ -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;

View File

@ -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;
} }
} }