<interface type='network'>
<source network='default'/>
<target dev='vnet0'/>
- <b><ip family='ipv4' address='192.168.122.5' prefix='24'/></b>
+ <b><ip address='192.168.122.5' prefix='24'/></b>
+ <b><route family='ipv4' address='192.168.122.0' prefix='24' via='192.168.122.1'/></b>
+ <b><route family='ipv4' via='192.168.122.1'/></b>
</interface>
...
<hostdev mode='capabilities' type='net'>
<source>
<interface>eth0</interface>
</source>
- <b><ip family='ipv4' address='192.168.122.6' prefix='24'/></b>
+ <b><ip address='192.168.122.6' prefix='24'/></b>
+ <b><route family='ipv4' address='192.168.122.0' prefix='24' via='192.168.122.1'/></b>
+ <b><route family='ipv4' via='192.168.122.1'/></b>
</hostdev>
</devices>
is not mandatory since some hypervisors do not handle it.
</p>
+ <p>
+ <span class="since">Since 1.2.12</span> route elements can also be added
+ to define the network routes to use for the network device. This element
+ has a <code>family</code> attribute set either to <code>ipv4</code> or
+ <code>ipv6</code>, a mandatory <code>via</code> attribute defining the
+ IP address to route throught and optional <code>address</code> and <code>prefix</code>
+ attributes defining the target network range. If those aren't given, then
+ a default route will be set.
+ This is only used by the LXC driver.
+ </p>
+
<h5><a name="elementVhostuser">vhost-user interface</a></h5>
<p>
VIR_FREE(def->ips[i]);
VIR_FREE(def->ips);
- virDomainDeviceInfoClear(&def->info);
+ for (i = 0; i < def->nroutes; i++)
+ VIR_FREE(def->routes[i]);
+ VIR_FREE(def->routes);
+
+ virDomainDeviceInfoClear(&def->info);
VIR_FREE(def->filter);
virNWFilterHashTableFree(def->filterparams);
for (i = 0; i < def->source.caps.u.net.nips; i++)
VIR_FREE(def->source.caps.u.net.ips[i]);
VIR_FREE(def->source.caps.u.net.ips);
+ for (i = 0; i < def->source.caps.u.net.nroutes; i++)
+ VIR_FREE(def->source.caps.u.net.routes[i]);
+ VIR_FREE(def->source.caps.u.net.routes);
break;
}
break;
return NULL;
}
+static virDomainNetRouteDefPtr
+virDomainNetRouteParse(xmlNodePtr node)
+{
+ virDomainNetRouteDefPtr route = NULL;
+ char *familyStr = NULL;
+ int family = AF_UNSPEC;
+ char *via = NULL;
+ char *to = NULL;
+ char *prefixStr = NULL;
+
+ to = virXMLPropString(node, "address");
+ if (!(via = virXMLPropString(node, "via"))) {
+ virReportError(VIR_ERR_INVALID_ARG, "%s",
+ _("Missing route address"));
+ goto error;
+ }
+
+ familyStr = virXMLPropString(node, "family");
+ if (familyStr && STREQ(familyStr, "ipv4"))
+ family = AF_INET;
+ else if (familyStr && STREQ(familyStr, "ipv6"))
+ family = AF_INET6;
+ else
+ family = virSocketAddrNumericFamily(via);
+
+ if (VIR_ALLOC(route) < 0)
+ goto error;
+
+ if (virSocketAddrParse(&route->via, via, family) < 0) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("Failed to parse IP address: '%s'"),
+ via);
+ goto error;
+ }
+
+ if (to && virSocketAddrParse(&route->to, to, family) < 0) {
+ virReportError(VIR_ERR_INVALID_ARG,
+ _("Failed to parse IP address: '%s'"),
+ to);
+ goto error;
+ }
+
+ if (!(prefixStr = virXMLPropString(node, "prefix")) ||
+ (virStrToLong_ui(prefixStr, NULL, 10, &route->prefix) < 0)) {
+ }
+
+ return route;
+
+ error:
+ VIR_FREE(familyStr);
+ VIR_FREE(via);
+ VIR_FREE(to);
+ VIR_FREE(prefixStr);
+ VIR_FREE(route);
+
+ return NULL;
+}
+
static int
virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
xmlXPathContextPtr ctxt,
xmlNodePtr sourcenode;
xmlNodePtr *ipnodes = NULL;
int nipnodes;
+ xmlNodePtr *routenodes = NULL;
+ int nroutenodes;
int ret = -1;
/* @type is passed in from the caller rather than read from the
}
}
}
+
+ /* Look for possible gateways */
+ if ((nroutenodes = virXPathNodeSet("./route", ctxt, &routenodes)) < 0)
+ goto error;
+
+ if (nroutenodes) {
+ size_t i;
+ for (i = 0; i < nroutenodes; i++) {
+ virDomainNetRouteDefPtr route = virDomainNetRouteParse(routenodes[i]);
+
+ if (!route)
+ goto error;
+
+ if (VIR_APPEND_ELEMENT(def->source.caps.u.net.routes,
+ def->source.caps.u.net.nroutes, route) < 0) {
+ VIR_FREE(route);
+ goto error;
+ }
+ }
+ }
break;
default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
ret = 0;
error:
VIR_FREE(ipnodes);
+ VIR_FREE(routenodes);
return ret;
}
size_t i;
size_t nips = 0;
virDomainNetIpDefPtr *ips = NULL;
+ size_t nroutes = 0;
+ virDomainNetRouteDefPtr *routes = NULL;
if (VIR_ALLOC(def) < 0)
return NULL;
if (VIR_APPEND_ELEMENT(ips, nips, ip) < 0)
goto error;
+ } else if (xmlStrEqual(cur->name, BAD_CAST "route")) {
+ virDomainNetRouteDefPtr route = NULL;
+ if (!(route = virDomainNetRouteParse(cur)))
+ goto error;
+
+ if (VIR_APPEND_ELEMENT(routes, nroutes, route) < 0)
+ goto error;
} else if (!ifname &&
xmlStrEqual(cur->name, BAD_CAST "target")) {
ifname = virXMLPropString(cur, "dev");
if (VIR_APPEND_ELEMENT(def->ips, def->nips, ips[i]) < 0)
goto error;
}
+ def->nroutes = nroutes;
+ def->routes = routes;
if (script != NULL) {
def->script = script;
}
}
+static void
+virDomainNetRoutesFormat(virBufferPtr buf,
+ virDomainNetRouteDefPtr *routes,
+ size_t nroutes)
+{
+ size_t i;
+
+ for (i = 0; i < nroutes; i++) {
+ virDomainNetRouteDefPtr route = routes[i];
+ const char *familyStr = NULL;
+ char *via = virSocketAddrFormat(&route->via);
+ char *to = NULL;
+
+ if (VIR_SOCKET_ADDR_IS_FAMILY(&route->via, AF_INET6))
+ familyStr = "ipv6";
+ else if (VIR_SOCKET_ADDR_IS_FAMILY(&route->via, AF_INET))
+ familyStr = "ipv4";
+ virBufferAsprintf(buf, "<route family='%s' via='%s'", familyStr, via);
+
+ if (VIR_SOCKET_ADDR_VALID(&route->to)) {
+ to = virSocketAddrFormat(&route->to);
+ virBufferAsprintf(buf, " address='%s'", to);
+ }
+
+ if (route->prefix > 0)
+ virBufferAsprintf(buf, " prefix='%d'", route->prefix);
+
+ virBufferAddLit(buf, "/>\n");
+ }
+}
+
static int
virDomainHostdevDefFormatSubsys(virBufferPtr buf,
virDomainHostdevDefPtr def,
if (def->source.caps.type == VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET) {
virDomainNetIpsFormat(buf, def->source.caps.u.net.ips,
def->source.caps.u.net.nips);
+ virDomainNetRoutesFormat(buf, def->source.caps.u.net.routes,
+ def->source.caps.u.net.nroutes);
}
return 0;
}
virDomainNetIpsFormat(buf, def->ips, def->nips);
+ virDomainNetRoutesFormat(buf, def->routes, def->nroutes);
virBufferEscapeString(buf, "<script path='%s'/>\n",
def->script);
void *addrData = NULL;
size_t addrDataLen;
int errCode;
+ virSocketAddr defaultAddr;
+ virSocketAddrPtr actualAddr;
+ char *toStr = NULL;
+ char *viaStr = NULL;
+
+ actualAddr = addr;
+
+ /* If we have no valid network address, then use the default one */
+ if (!addr || !VIR_SOCKET_ADDR_VALID(addr)) {
+ VIR_DEBUG("computing default address");
+ int family = VIR_SOCKET_ADDR_FAMILY(gateway);
+ if (family == AF_INET) {
+ if (virSocketAddrParseIPv4(&defaultAddr, VIR_SOCKET_ADDR_IPV4_ALL) < 0)
+ goto cleanup;
+ } else {
+ if (virSocketAddrParseIPv6(&defaultAddr, VIR_SOCKET_ADDR_IPV6_ALL) < 0)
+ goto cleanup;
+ }
+
+ actualAddr = &defaultAddr;
+ }
+
+ toStr = virSocketAddrFormat(actualAddr);
+ viaStr = virSocketAddrFormat(gateway);
+ VIR_DEBUG("Adding route %s/%d via %s", toStr, prefix, viaStr);
- if (virNetDevGetIPAddressBinary(addr, &addrData, &addrDataLen) < 0 ||
+ if (virNetDevGetIPAddressBinary(actualAddr, &addrData, &addrDataLen) < 0 ||
virNetDevGetIPAddressBinary(gateway, &gatewayData, &addrDataLen) < 0)
goto cleanup;
memset(&rtmsg, 0, sizeof(rtmsg));
- rtmsg.rtm_family = VIR_SOCKET_ADDR_FAMILY(addr);
+ rtmsg.rtm_family = VIR_SOCKET_ADDR_FAMILY(gateway);
rtmsg.rtm_table = RT_TABLE_MAIN;
rtmsg.rtm_scope = RT_SCOPE_UNIVERSE;
rtmsg.rtm_protocol = RTPROT_BOOT;
ret = 0;
cleanup:
+ VIR_FREE(toStr);
+ VIR_FREE(viaStr);
nlmsg_free(nlmsg);
return ret;