VIR_ENUM_IMPL(virNetworkForward,
VIR_NETWORK_FORWARD_LAST,
- "none", "nat", "route" )
+ "none", "nat", "route", "bridge", "private", "vepa", "passthrough" )
#define virNetworkReportError(code, ...) \
virReportErrorHelper(VIR_FROM_NETWORK, code, __FILE__, \
}
+static void
+virPortGroupDefClear(virPortGroupDefPtr def)
+{
+ VIR_FREE(def->name);
+ VIR_FREE(def->virtPortProfile);
+}
+
+static void
+virNetworkForwardIfDefClear(virNetworkForwardIfDefPtr def)
+{
+ VIR_FREE(def->dev);
+}
+
static void virNetworkIpDefClear(virNetworkIpDefPtr def)
{
int ii;
VIR_FREE(def->name);
VIR_FREE(def->bridge);
- VIR_FREE(def->forwardDev);
VIR_FREE(def->domain);
+ for (ii = 0 ; ii < def->nForwardIfs && def->forwardIfs ; ii++) {
+ virNetworkForwardIfDefClear(&def->forwardIfs[ii]);
+ }
+ VIR_FREE(def->forwardIfs);
+
for (ii = 0 ; ii < def->nips && def->ips ; ii++) {
virNetworkIpDefClear(&def->ips[ii]);
}
VIR_FREE(def->ips);
+ for (ii = 0; ii < def->nPortGroups && def->portGroups; ii++) {
+ virPortGroupDefClear(&def->portGroups[ii]);
+ }
+ VIR_FREE(def->portGroups);
+
virNetworkDNSDefFree(def->dns);
VIR_FREE(def);
return result;
}
+static int
+virNetworkPortGroupParseXML(virPortGroupDefPtr def,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt)
+{
+ /*
+ * virPortGroupDef object is already allocated as part of an array.
+ * On failure clear it out, but don't free it.
+ */
+
+ xmlNodePtr save;
+ xmlNodePtr virtPortNode;
+ char *isDefault = NULL;
+
+ int result = -1;
+
+ save = ctxt->node;
+ ctxt->node = node;
+
+ /* grab raw data from XML */
+ def->name = virXPathString("string(./@name)", ctxt);
+ isDefault = virXPathString("string(./@default)", ctxt);
+ def->isDefault = isDefault && STRCASEEQ(isDefault, "yes");
+
+ virtPortNode = virXPathNode("./virtualport", ctxt);
+ if (virtPortNode &&
+ (virVirtualPortProfileParseXML(virtPortNode,
+ &def->virtPortProfile) < 0)) {
+ goto error;
+ }
+
+ result = 0;
+error:
+ if (result < 0) {
+ virPortGroupDefClear(def);
+ }
+ VIR_FREE(isDefault);
+
+ ctxt->node = save;
+ return result;
+}
+
static virNetworkDefPtr
virNetworkDefParseXML(xmlXPathContextPtr ctxt)
{
virNetworkDefPtr def;
char *tmp;
+ char *stp = NULL;
xmlNodePtr *ipNodes = NULL;
+ xmlNodePtr *portGroupNodes = NULL;
+ xmlNodePtr *forwardIfNodes = NULL;
xmlNodePtr dnsNode = NULL;
- int nIps;
+ xmlNodePtr virtPortNode = NULL;
+ xmlNodePtr forwardNode = NULL;
+ int nIps, nPortGroups, nForwardIfs;
+ char *forwardDev = NULL;
+ xmlNodePtr save = ctxt->node;
if (VIR_ALLOC(def) < 0) {
virReportOOMError();
/* Parse bridge information */
def->bridge = virXPathString("string(./bridge[1]/@name)", ctxt);
- tmp = virXPathString("string(./bridge[1]/@stp)", ctxt);
- def->stp = (tmp && STREQ(tmp, "off")) ? 0 : 1;
- VIR_FREE(tmp);
+ stp = virXPathString("string(./bridge[1]/@stp)", ctxt);
if (virXPathULong("string(./bridge[1]/@delay)", ctxt, &def->delay) < 0)
def->delay = 0;
goto error;
}
+ virtPortNode = virXPathNode("./virtualport", ctxt);
+ if (virtPortNode &&
+ (virVirtualPortProfileParseXML(virtPortNode,
+ &def->virtPortProfile) < 0)) {
+ goto error;
+ }
+
+ nPortGroups = virXPathNodeSet("./portgroup", ctxt, &portGroupNodes);
+ if (nPortGroups < 0)
+ goto error;
+
+ if (nPortGroups > 0) {
+ int ii;
+
+ /* allocate array to hold all the portgroups */
+ if (VIR_ALLOC_N(def->portGroups, nPortGroups) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ /* parse each portgroup */
+ for (ii = 0; ii < nPortGroups; ii++) {
+ int ret = virNetworkPortGroupParseXML(&def->portGroups[ii],
+ portGroupNodes[ii], ctxt);
+ if (ret < 0)
+ goto error;
+ def->nPortGroups++;
+ }
+ }
+ VIR_FREE(portGroupNodes);
+
nIps = virXPathNodeSet("./ip", ctxt, &ipNodes);
if (nIps < 0)
goto error;
}
VIR_FREE(ipNodes);
- /* IPv4 forwarding setup */
- if (virXPathBoolean("count(./forward) > 0", ctxt)) {
- if (def->nips == 0) {
- virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
- "%s", _("Forwarding requested, but no IP address provided"));
- goto error;
- }
- tmp = virXPathString("string(./forward[1]/@mode)", ctxt);
+ forwardNode = virXPathNode("./forward", ctxt);
+ if (!forwardNode) {
+ def->forwardType = VIR_NETWORK_FORWARD_NONE;
+ def->stp = (stp && STREQ(stp, "off")) ? 0 : 1;
+ } else {
+ ctxt->node = forwardNode;
+ tmp = virXPathString("string(./@mode)", ctxt);
if (tmp) {
if ((def->forwardType = virNetworkForwardTypeFromString(tmp)) < 0) {
- virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
+ virNetworkReportError(VIR_ERR_XML_ERROR,
_("unknown forwarding type '%s'"), tmp);
VIR_FREE(tmp);
goto error;
def->forwardType = VIR_NETWORK_FORWARD_NAT;
}
+ forwardDev = virXPathString("string(./@dev)", ctxt);
- def->forwardDev = virXPathString("string(./forward[1]/@dev)", ctxt);
- } else {
- def->forwardType = VIR_NETWORK_FORWARD_NONE;
- }
+ /* all of these modes can use a pool of physical interfaces */
+ nForwardIfs = virXPathNodeSet("./interface", ctxt, &forwardIfNodes);
+ if (nForwardIfs < 0)
+ goto error;
+
+ if ((nForwardIfs > 0) || forwardDev) {
+ int ii;
+ /* allocate array to hold all the portgroups */
+ if (VIR_ALLOC_N(def->forwardIfs, MAX(nForwardIfs, 1)) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+
+ if (forwardDev) {
+ def->forwardIfs[0].usageCount = 0;
+ def->forwardIfs[0].dev = forwardDev;
+ forwardDev = NULL;
+ def->nForwardIfs++;
+ }
+
+ /* parse each forwardIf */
+ for (ii = 0; ii < nForwardIfs; ii++) {
+ forwardDev = virXMLPropString(forwardIfNodes[ii], "dev");
+ if (!forwardDev) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("Missing required dev attribute in network '%s' forward interface element"),
+ def->name);
+ goto error;
+ }
+
+ if ((ii == 0) && (def->nForwardIfs == 1)) {
+ /* both forwardDev and an interface element are present.
+ * If they don't match, it's an error. */
+ if (STRNEQ(forwardDev, def->forwardIfs[0].dev)) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("forward dev '%s' must match first interface element dev '%s' in network '%s'"),
+ def->forwardIfs[0].dev,
+ forwardDev, def->name);
+ goto error;
+ }
+ VIR_FREE(forwardDev);
+ continue;
+ }
+
+ def->forwardIfs[ii].dev = forwardDev;
+ forwardDev = NULL;
+ def->forwardIfs[ii].usageCount = 0;
+ def->nForwardIfs++;
+ }
+ }
+ VIR_FREE(forwardIfNodes);
+
+ switch (def->forwardType) {
+ case VIR_NETWORK_FORWARD_ROUTE:
+ case VIR_NETWORK_FORWARD_NAT:
+ /* It's pointless to specify L3 forwarding without specifying
+ * the network we're on.
+ */
+ if (def->nips == 0) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("%s forwarding requested, but no IP address provided for network '%s'"),
+ virNetworkForwardTypeToString(def->forwardType),
+ def->name);
+ goto error;
+ }
+ if (def->nForwardIfs > 1) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("multiple forwarding interfaces specified for network '%s', only one is supported"),
+ def->name);
+ goto error;
+ }
+ def->stp = (stp && STREQ(stp, "off")) ? 0 : 1;
+ break;
+ case VIR_NETWORK_FORWARD_PRIVATE:
+ case VIR_NETWORK_FORWARD_VEPA:
+ case VIR_NETWORK_FORWARD_PASSTHROUGH:
+ if (def->bridge) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("bridge name not allowed in %s mode (network '%s'"),
+ virNetworkForwardTypeToString(def->forwardType),
+ def->name);
+ goto error;
+ }
+ /* fall through to next case */
+ case VIR_NETWORK_FORWARD_BRIDGE:
+ if (def->delay || stp) {
+ virNetworkReportError(VIR_ERR_XML_ERROR,
+ _("bridge delay/stp options only allowed in route, nat, and isolated mode, not in %s (network '%s')"),
+ virNetworkForwardTypeToString(def->forwardType),
+ def->name);
+ goto error;
+ }
+ break;
+ }
+ }
+ VIR_FREE(stp);
+ ctxt->node = save;
return def;
error:
+ VIR_FREE(stp);
virNetworkDefFree(def);
VIR_FREE(ipNodes);
+ VIR_FREE(portGroupNodes);
+ VIR_FREE(forwardIfNodes);
+ VIR_FREE(forwardDev);
+ ctxt->node = save;
return NULL;
}
return result;
}
+static void
+virPortGroupDefFormat(virBufferPtr buf,
+ const virPortGroupDefPtr def)
+{
+ virBufferAsprintf(buf, " <portgroup name='%s'", def->name);
+ if (def->isDefault) {
+ virBufferAddLit(buf, " default='yes'");
+ }
+ virBufferAddLit(buf, ">\n");
+ virVirtualPortProfileFormat(buf, def->virtPortProfile, " ");
+ virBufferAddLit(buf, " </portgroup>\n");
+}
+
char *virNetworkDefFormat(const virNetworkDefPtr def)
{
virBuffer buf = VIR_BUFFER_INITIALIZER;
virBufferAsprintf(&buf, " <uuid>%s</uuid>\n", uuidstr);
if (def->forwardType != VIR_NETWORK_FORWARD_NONE) {
+ const char *dev = virNetworkDefForwardIf(def, 0);
const char *mode = virNetworkForwardTypeToString(def->forwardType);
- if (mode) {
- if (def->forwardDev) {
- virBufferEscapeString(&buf, " <forward dev='%s'",
- def->forwardDev);
- } else {
- virBufferAddLit(&buf, " <forward");
+
+ if (!mode) {
+ virNetworkReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Unknown forward type %d in network '%s'"),
+ def->forwardType, def->name);
+ goto error;
+ }
+ virBufferAddLit(&buf, " <forward");
+ if (dev)
+ virBufferEscapeString(&buf, " dev='%s'", dev);
+ virBufferAsprintf(&buf, " mode='%s'%s>\n", mode,
+ def->nForwardIfs ? "" : "/");
+
+ if (def->nForwardIfs) {
+ for (ii = 0; ii < def->nForwardIfs; ii++) {
+ if (def->forwardIfs[ii].dev) {
+ virBufferEscapeString(&buf, " <interface dev='%s'/>\n",
+ def->forwardIfs[ii].dev);
+ }
}
- virBufferAsprintf(&buf, " mode='%s'/>\n", mode);
+ virBufferAddLit(&buf, " </forward>\n");
}
}
- virBufferAddLit(&buf, " <bridge");
- if (def->bridge)
- virBufferEscapeString(&buf, " name='%s'", def->bridge);
- virBufferAsprintf(&buf, " stp='%s' delay='%ld' />\n",
- def->stp ? "on" : "off",
- def->delay);
+ if (def->forwardType == VIR_NETWORK_FORWARD_NONE ||
+ def->forwardType == VIR_NETWORK_FORWARD_NAT ||
+ def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
+
+ virBufferAddLit(&buf, " <bridge");
+ if (def->bridge)
+ virBufferEscapeString(&buf, " name='%s'", def->bridge);
+ virBufferAsprintf(&buf, " stp='%s' delay='%ld' />\n",
+ def->stp ? "on" : "off",
+ def->delay);
+ } else if (def->forwardType == VIR_NETWORK_FORWARD_BRIDGE &&
+ def->bridge) {
+ virBufferEscapeString(&buf, " <bridge name='%s' />\n", def->bridge);
+ }
+
+
if (def->mac_specified) {
char macaddr[VIR_MAC_STRING_BUFLEN];
virFormatMacAddr(def->mac, macaddr);
goto error;
}
+ virVirtualPortProfileFormat(&buf, def->virtPortProfile, " ");
+
+ for (ii = 0; ii < def->nPortGroups; ii++)
+ virPortGroupDefFormat(&buf, &def->portGroups[ii]);
+
virBufferAddLit(&buf, "</network>\n");
if (virBufferError(&buf))
return NULL;
}
+virPortGroupDefPtr virPortGroupFindByName(virNetworkDefPtr net,
+ const char *portgroup)
+{
+ int ii;
+ for (ii = 0; ii < net->nPortGroups; ii++) {
+ if (portgroup) {
+ if (STREQ(portgroup, net->portGroups[ii].name))
+ return &net->portGroups[ii];
+ } else {
+ if (net->portGroups[ii].isDefault)
+ return &net->portGroups[ii];
+ }
+ }
+ return NULL;
+}
+
int virNetworkSaveXML(const char *configDir,
virNetworkDefPtr def,
const char *xml)
goto error;
}
- /* Generate a bridge if none is specified, but don't check for collisions
- * if a bridge is hardcoded, so the network is at least defined
- */
- if (virNetworkSetBridgeName(nets, def, 0))
- goto error;
+ if (def->forwardType == VIR_NETWORK_FORWARD_NONE ||
+ def->forwardType == VIR_NETWORK_FORWARD_NAT ||
+ def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
+
+ /* Generate a bridge if none is specified, but don't check for collisions
+ * if a bridge is hardcoded, so the network is at least defined.
+ */
+ if (virNetworkSetBridgeName(nets, def, 0))
+ goto error;
+ }
if (!(net = virNetworkAssignDef(nets, def)))
goto error;
virNetworkIpDefPtr ipdef)
{
int prefix = virNetworkIpDefPrefix(ipdef);
+ const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
if (prefix < 0) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev) < 0) {
+ forwardIf) < 0) {
networkReportError(VIR_ERR_SYSTEM_ERROR,
_("failed to add iptables rule to allow forwarding from '%s'"),
network->def->bridge);
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev) < 0) {
+ forwardIf) < 0) {
networkReportError(VIR_ERR_SYSTEM_ERROR,
_("failed to add iptables rule to allow forwarding to '%s'"),
network->def->bridge);
if (iptablesAddForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
- network->def->forwardDev,
+ forwardIf,
NULL) < 0) {
networkReportError(VIR_ERR_SYSTEM_ERROR,
- _("failed to add iptables rule to enable masquerading to '%s'"),
- network->def->forwardDev ? network->def->forwardDev : NULL);
+ forwardIf ?
+ _("failed to add iptables rule to enable masquerading to %s") :
+ _("failed to add iptables rule to enable masquerading"),
+ forwardIf);
goto masqerr3;
}
if (iptablesAddForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
- network->def->forwardDev,
+ forwardIf,
"udp") < 0) {
networkReportError(VIR_ERR_SYSTEM_ERROR,
- _("failed to add iptables rule to enable UDP masquerading to '%s'"),
- network->def->forwardDev ? network->def->forwardDev : NULL);
+ forwardIf ?
+ _("failed to add iptables rule to enable UDP masquerading to %s") :
+ _("failed to add iptables rule to enable UDP masquerading"),
+ forwardIf);
goto masqerr4;
}
if (iptablesAddForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
- network->def->forwardDev,
+ forwardIf,
"tcp") < 0) {
networkReportError(VIR_ERR_SYSTEM_ERROR,
- _("failed to add iptables rule to enable TCP masquerading to '%s'"),
- network->def->forwardDev ? network->def->forwardDev : NULL);
+ forwardIf ?
+ _("failed to add iptables rule to enable TCP masquerading to %s") :
+ _("failed to add iptables rule to enable TCP masquerading"),
+ forwardIf);
goto masqerr5;
}
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
- network->def->forwardDev,
+ forwardIf,
"udp");
masqerr4:
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
- network->def->forwardDev,
+ forwardIf,
NULL);
masqerr3:
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev);
+ forwardIf);
masqerr2:
iptablesRemoveForwardAllowOut(driver->iptables,
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev);
+ forwardIf);
masqerr1:
return -1;
}
virNetworkIpDefPtr ipdef)
{
int prefix = virNetworkIpDefPrefix(ipdef);
+ const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
if (prefix >= 0) {
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
- network->def->forwardDev,
+ forwardIf,
"tcp");
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
- network->def->forwardDev,
+ forwardIf,
"udp");
iptablesRemoveForwardMasquerade(driver->iptables,
&ipdef->address,
prefix,
- network->def->forwardDev,
+ forwardIf,
NULL);
iptablesRemoveForwardAllowRelatedIn(driver->iptables,
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev);
+ forwardIf);
iptablesRemoveForwardAllowOut(driver->iptables,
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev);
+ forwardIf);
}
}
virNetworkIpDefPtr ipdef)
{
int prefix = virNetworkIpDefPrefix(ipdef);
+ const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
if (prefix < 0) {
networkReportError(VIR_ERR_INTERNAL_ERROR,
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev) < 0) {
+ forwardIf) < 0) {
networkReportError(VIR_ERR_SYSTEM_ERROR,
_("failed to add iptables rule to allow routing from '%s'"),
network->def->bridge);
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev) < 0) {
+ forwardIf) < 0) {
networkReportError(VIR_ERR_SYSTEM_ERROR,
_("failed to add iptables rule to allow routing to '%s'"),
network->def->bridge);
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev);
+ forwardIf);
routeerr1:
return -1;
}
virNetworkIpDefPtr ipdef)
{
int prefix = virNetworkIpDefPrefix(ipdef);
+ const char *forwardIf = virNetworkDefForwardIf(network->def, 0);
if (prefix >= 0) {
iptablesRemoveForwardAllowIn(driver->iptables,
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev);
+ forwardIf);
iptablesRemoveForwardAllowOut(driver->iptables,
&ipdef->address,
prefix,
network->def->bridge,
- network->def->forwardDev);
+ forwardIf);
}
}
if (virNetworkObjIsDuplicate(&driver->networks, def, 1) < 0)
goto cleanup;
- if (virNetworkSetBridgeName(&driver->networks, def, 1))
- goto cleanup;
+ /* Only the three L3 network types that are configured by libvirt
+ * need to have a bridge device name / mac address provided
+ */
+ if (def->forwardType == VIR_NETWORK_FORWARD_NONE ||
+ def->forwardType == VIR_NETWORK_FORWARD_NAT ||
+ def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
- virNetworkSetBridgeMacAddr(def);
+ if (virNetworkSetBridgeName(&driver->networks, def, 1))
+ goto cleanup;
+
+ virNetworkSetBridgeMacAddr(def);
+ }
if (!(network = virNetworkAssignDef(&driver->networks,
def)))
if (virNetworkObjIsDuplicate(&driver->networks, def, 0) < 0)
goto cleanup;
- if (virNetworkSetBridgeName(&driver->networks, def, 1))
- goto cleanup;
+ /* Only the three L3 network types that are configured by libvirt
+ * need to have a bridge device name / mac address provided
+ */
+ if (def->forwardType == VIR_NETWORK_FORWARD_NONE ||
+ def->forwardType == VIR_NETWORK_FORWARD_NAT ||
+ def->forwardType == VIR_NETWORK_FORWARD_ROUTE) {
- virNetworkSetBridgeMacAddr(def);
+ if (virNetworkSetBridgeName(&driver->networks, def, 1))
+ goto cleanup;
+
+ virNetworkSetBridgeMacAddr(def);
+ }
if (!(network = virNetworkAssignDef(&driver->networks,
def)))