diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in index 2466df735d..bb1c0792b9 100644 --- a/docs/formatdomain.html.in +++ b/docs/formatdomain.html.in @@ -5012,6 +5012,32 @@ qemu-kvm -net nic,model=? /dev/null definitions. This is used by the LXC driver.

+
+  ...
+  <devices>
+    <interface type='ethernet'>
+      <source/>
+        <ip address='192.168.123.1' prefix='24'/>
+        <ip address='10.0.0.10' prefix='24' peer='192.168.122.5'/>
+        <route family='ipv4' address='192.168.42.0' prefix='24' gateway='192.168.123.4'/>
+      <source/>
+      ...
+    </interface>
+    ...
+  </devices>
+  ...
+
+ +

+ Since 2.0.0 network devices of type + "ethernet" can optionally be provided one or more IP addresses + and one or more routes to set on the host side of the + network device. These are configured as subelements of + the <source> element of the interface, and + have the same attributes as the similarly named elements used to + configure the guest side of the interface (described above). +

+
vhost-user interface

diff --git a/docs/schemas/domaincommon.rng b/docs/schemas/domaincommon.rng index 2d12da95e3..964ff92215 100644 --- a/docs/schemas/domaincommon.rng +++ b/docs/schemas/domaincommon.rng @@ -2142,7 +2142,7 @@ - + @@ -2392,7 +2392,6 @@ - diff --git a/src/conf/domain_conf.c b/src/conf/domain_conf.c index 3a81f7e2aa..90d2eaa7cc 100644 --- a/src/conf/domain_conf.c +++ b/src/conf/domain_conf.c @@ -1798,6 +1798,7 @@ virDomainNetDefClear(virDomainNetDefPtr def) VIR_FREE(def->ifname_guest_actual); virNetDevIPInfoClear(&def->guestIP); + virNetDevIPInfoClear(&def->hostIP); virDomainDeviceInfoClear(&def->info); VIR_FREE(def->filter); @@ -4607,6 +4608,23 @@ virDomainRedirdevDefValidate(const virDomainDef *def, } +static int +virDomainNetDefValidate(const virDomainNetDef *net) +{ + if ((net->hostIP.nroutes || net->hostIP.nips) && + net->type != VIR_DOMAIN_NET_TYPE_ETHERNET) { + virReportError(VIR_ERR_CONFIG_UNSUPPORTED, + _("Invalid attempt to set network interface " + "host-side IP route and/or address info on " + "interface of type '%s'. This is only supported " + "on interfaces of type 'ethernet'"), + virDomainNetTypeToString(net->type)); + return -1; + } + return 0; +} + + static int virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev, const virDomainDef *def) @@ -4618,9 +4636,11 @@ virDomainDeviceDefValidateInternal(const virDomainDeviceDef *dev, case VIR_DOMAIN_DEVICE_REDIRDEV: return virDomainRedirdevDefValidate(def, dev->data.redirdev); + case VIR_DOMAIN_DEVICE_NET: + return virDomainNetDefValidate(dev->data.net); + case VIR_DOMAIN_DEVICE_LEASE: case VIR_DOMAIN_DEVICE_FS: - case VIR_DOMAIN_DEVICE_NET: case VIR_DOMAIN_DEVICE_INPUT: case VIR_DOMAIN_DEVICE_SOUND: case VIR_DOMAIN_DEVICE_VIDEO: @@ -8989,6 +9009,15 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, cur = node->children; while (cur != NULL) { if (cur->type == XML_ELEMENT_NODE) { + if (xmlStrEqual(cur->name, BAD_CAST "source")) { + xmlNodePtr tmpnode = ctxt->node; + + ctxt->node = cur; + if (virDomainNetIPInfoParseXML(_("interface host IP"), + ctxt, &def->hostIP) < 0) + goto error; + ctxt->node = tmpnode; + } if (!macaddr && xmlStrEqual(cur->name, BAD_CAST "mac")) { macaddr = virXMLPropString(cur, "address"); } else if (!network && @@ -20692,6 +20721,7 @@ virDomainNetDefFormat(virBufferPtr buf, { unsigned int actualType = virDomainNetGetActualType(def); bool publicActual = false; + int sourceLines = 0; const char *typeStr; virDomainHostdevDefPtr hostdef = NULL; char macstr[VIR_MAC_STRING_BUFLEN]; @@ -20761,15 +20791,7 @@ virDomainNetDefFormat(virBufferPtr buf, def->data.network.name); virBufferEscapeString(buf, " portgroup='%s'", def->data.network.portgroup); - virBufferAddLit(buf, "/>\n"); - - /* ONLY for internal status storage - format the ActualNetDef - * as a subelement of so that no persistent config - * data is overwritten. - */ - if ((flags & VIR_DOMAIN_DEF_FORMAT_ACTUAL_NET) && - (virDomainActualNetDefFormat(buf, def, flags) < 0)) - return -1; + sourceLines++; break; case VIR_DOMAIN_NET_TYPE_ETHERNET: @@ -20783,13 +20805,16 @@ virDomainNetDefFormat(virBufferPtr buf, virBufferAsprintf(buf, " mode='%s'", def->data.vhostuser->data.nix.listen ? "server" : "client"); - virBufferAddLit(buf, "/>\n"); + sourceLines++; } break; case VIR_DOMAIN_NET_TYPE_BRIDGE: - virBufferEscapeString(buf, "\n", - def->data.bridge.brname); + if (def->data.bridge.brname) { + virBufferEscapeString(buf, "data.bridge.brname); + sourceLines++; + } break; case VIR_DOMAIN_NET_TYPE_SERVER: @@ -20804,25 +20829,27 @@ virDomainNetDefFormat(virBufferPtr buf, virBufferAsprintf(buf, "data.socket.port); } + sourceLines++; - if (def->type != VIR_DOMAIN_NET_TYPE_UDP) { - virBufferAddLit(buf, "/>\n"); + if (def->type != VIR_DOMAIN_NET_TYPE_UDP) break; - } virBufferAddLit(buf, ">\n"); + sourceLines++; virBufferAdjustIndent(buf, 2); virBufferAsprintf(buf, "\n", def->data.socket.localaddr, def->data.socket.localport); virBufferAdjustIndent(buf, -2); - virBufferAddLit(buf, "\n"); break; case VIR_DOMAIN_NET_TYPE_INTERNAL: - virBufferEscapeString(buf, "\n", - def->data.internal.name); + if (def->data.internal.name) { + virBufferEscapeString(buf, "data.internal.name); + sourceLines++; + } break; case VIR_DOMAIN_NET_TYPE_DIRECT: @@ -20830,7 +20857,7 @@ virDomainNetDefFormat(virBufferPtr buf, def->data.direct.linkdev); virBufferAsprintf(buf, " mode='%s'", virNetDevMacVLanModeTypeToString(def->data.direct.mode)); - virBufferAddLit(buf, "/>\n"); + sourceLines++; break; case VIR_DOMAIN_NET_TYPE_HOSTDEV: @@ -20845,12 +20872,44 @@ virDomainNetDefFormat(virBufferPtr buf, break; } + /* if sourceLines == 0 - no info at all so far + * sourceLines == 1 - first line written, no terminating ">" + * sourceLines > 1 - multiple lines, including subelements + */ + if (def->hostIP.nips || def->hostIP.nroutes) { + if (sourceLines == 0) { + virBufferAddLit(buf, "\n"); + sourceLines += 2; + } else if (sourceLines == 1) { + virBufferAddLit(buf, ">\n"); + sourceLines++; + } + virBufferAdjustIndent(buf, 2); + if (virDomainNetIPInfoFormat(buf, &def->hostIP) < 0) + return -1; + virBufferAdjustIndent(buf, -2); + } + if (sourceLines == 1) + virBufferAddLit(buf, "/>\n"); + else if (sourceLines > 1) + virBufferAddLit(buf, "\n"); + if (virNetDevVlanFormat(&def->vlan, buf) < 0) return -1; if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0) return -1; if (virNetDevBandwidthFormat(def->bandwidth, buf) < 0) return -1; + + /* ONLY for internal status storage - format the ActualNetDef + * as a subelement of so that no persistent config + * data is overwritten. + */ + if (def->type == VIR_DOMAIN_NET_TYPE_NETWORK && + (flags & VIR_DOMAIN_DEF_FORMAT_ACTUAL_NET) && + (virDomainActualNetDefFormat(buf, def, flags) < 0)) + return -1; + } if (virDomainNetIPInfoFormat(buf, &def->guestIP) < 0) @@ -20859,6 +20918,7 @@ virDomainNetDefFormat(virBufferPtr buf, virBufferEscapeString(buf, "