mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-12-22 17:34:18 +03:00
Domain network devices can now have a <route> element
Network interfaces devices and host devices with net capabilities can now have IPv4 and/or an IPv6 routes configured.
This commit is contained in:
parent
7100be40a5
commit
c9a641f1e5
@ -4328,14 +4328,18 @@ qemu-kvm -net nic,model=? /dev/null
|
||||
<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>
|
||||
@ -4352,6 +4356,17 @@ qemu-kvm -net nic,model=? /dev/null
|
||||
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>
|
||||
|
@ -2329,6 +2329,11 @@
|
||||
<empty/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<zeroOrMore>
|
||||
<element name="route">
|
||||
<ref name="route"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<optional>
|
||||
<element name="script">
|
||||
<attribute name="path">
|
||||
@ -3597,6 +3602,27 @@
|
||||
</element>
|
||||
</define>
|
||||
|
||||
<define name="route">
|
||||
<interleave>
|
||||
<attribute name="family">
|
||||
<ref name="addr-family"/>
|
||||
</attribute>
|
||||
<attribute name="via">
|
||||
<ref name="ipAddr"/>
|
||||
</attribute>
|
||||
<optional>
|
||||
<attribute name="address">
|
||||
<ref name="ipAddr"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
<optional>
|
||||
<attribute name="prefix">
|
||||
<ref name="ipPrefix"/>
|
||||
</attribute>
|
||||
</optional>
|
||||
</interleave>
|
||||
</define>
|
||||
|
||||
<define name="hostdev">
|
||||
<element name="hostdev">
|
||||
<interleave>
|
||||
@ -3832,6 +3858,11 @@
|
||||
<empty/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
<zeroOrMore>
|
||||
<element name="route">
|
||||
<ref name="route"/>
|
||||
</element>
|
||||
</zeroOrMore>
|
||||
</interleave>
|
||||
</define>
|
||||
|
||||
|
@ -1475,7 +1475,11 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
|
||||
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);
|
||||
@ -1847,6 +1851,9 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
|
||||
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;
|
||||
@ -4831,6 +4838,64 @@ virDomainNetIpParseXML(xmlNodePtr node)
|
||||
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,
|
||||
@ -4840,6 +4905,8 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
|
||||
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
|
||||
@ -4914,6 +4981,26 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* 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,
|
||||
@ -4924,6 +5011,7 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
|
||||
ret = 0;
|
||||
error:
|
||||
VIR_FREE(ipnodes);
|
||||
VIR_FREE(routenodes);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -7367,6 +7455,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
||||
size_t i;
|
||||
size_t nips = 0;
|
||||
virDomainNetIpDefPtr *ips = NULL;
|
||||
size_t nroutes = 0;
|
||||
virDomainNetRouteDefPtr *routes = NULL;
|
||||
|
||||
if (VIR_ALLOC(def) < 0)
|
||||
return NULL;
|
||||
@ -7463,6 +7553,13 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
||||
|
||||
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");
|
||||
@ -7773,6 +7870,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
|
||||
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;
|
||||
@ -17179,6 +17278,37 @@ virDomainNetIpsFormat(virBufferPtr buf, virDomainNetIpDefPtr *ips, size_t nips)
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
@ -17334,6 +17464,8 @@ virDomainHostdevDefFormatCaps(virBufferPtr buf,
|
||||
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;
|
||||
@ -17718,6 +17850,7 @@ virDomainNetDefFormat(virBufferPtr buf,
|
||||
}
|
||||
|
||||
virDomainNetIpsFormat(buf, def->ips, def->nips);
|
||||
virDomainNetRoutesFormat(buf, def->routes, def->nroutes);
|
||||
|
||||
virBufferEscapeString(buf, "<script path='%s'/>\n",
|
||||
def->script);
|
||||
|
@ -485,6 +485,14 @@ struct _virDomainNetIpDef {
|
||||
unsigned int prefix; /* number of 1 bits in the net mask */
|
||||
};
|
||||
|
||||
typedef struct _virDomainNetRouteDef virDomainNetRouteDef;
|
||||
typedef virDomainNetRouteDef *virDomainNetRouteDefPtr;
|
||||
struct _virDomainNetRouteDef {
|
||||
virSocketAddr via;
|
||||
virSocketAddr to;
|
||||
unsigned int prefix;
|
||||
};
|
||||
|
||||
typedef struct _virDomainHostdevCaps virDomainHostdevCaps;
|
||||
typedef virDomainHostdevCaps *virDomainHostdevCapsPtr;
|
||||
struct _virDomainHostdevCaps {
|
||||
@ -500,6 +508,8 @@ struct _virDomainHostdevCaps {
|
||||
char *iface;
|
||||
size_t nips;
|
||||
virDomainNetIpDefPtr *ips;
|
||||
size_t nroutes;
|
||||
virDomainNetRouteDefPtr *routes;
|
||||
} net;
|
||||
} u;
|
||||
};
|
||||
@ -1002,6 +1012,8 @@ struct _virDomainNetDef {
|
||||
int linkstate;
|
||||
size_t nips;
|
||||
virDomainNetIpDefPtr *ips;
|
||||
size_t nroutes;
|
||||
virDomainNetRouteDefPtr *routes;
|
||||
};
|
||||
|
||||
/* Used for prefix of ifname of any network name generated dynamically
|
||||
|
@ -992,8 +992,33 @@ virNetDevAddRoute(const char *ifname,
|
||||
void *addrData = NULL;
|
||||
size_t addrDataLen;
|
||||
int errCode;
|
||||
virSocketAddr defaultAddr;
|
||||
virSocketAddrPtr actualAddr;
|
||||
char *toStr = NULL;
|
||||
char *viaStr = NULL;
|
||||
|
||||
if (virNetDevGetIPAddressBinary(addr, &addrData, &addrDataLen) < 0 ||
|
||||
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(actualAddr, &addrData, &addrDataLen) < 0 ||
|
||||
virNetDevGetIPAddressBinary(gateway, &gatewayData, &addrDataLen) < 0)
|
||||
goto cleanup;
|
||||
|
||||
@ -1010,7 +1035,7 @@ virNetDevAddRoute(const char *ifname,
|
||||
|
||||
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;
|
||||
@ -1043,6 +1068,8 @@ virNetDevAddRoute(const char *ifname,
|
||||
|
||||
ret = 0;
|
||||
cleanup:
|
||||
VIR_FREE(toStr);
|
||||
VIR_FREE(viaStr);
|
||||
nlmsg_free(nlmsg);
|
||||
return ret;
|
||||
|
||||
|
@ -96,7 +96,7 @@ int virNetDevAddRoute(const char *ifname,
|
||||
unsigned int prefix,
|
||||
virSocketAddrPtr gateway,
|
||||
unsigned int metric)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4)
|
||||
ATTRIBUTE_RETURN_CHECK;
|
||||
int virNetDevClearIPAddress(const char *ifname,
|
||||
virSocketAddr *addr,
|
||||
|
@ -55,6 +55,8 @@ typedef struct {
|
||||
((s)->data.sa.sa_family)
|
||||
|
||||
# define VIR_SOCKET_ADDR_DEFAULT_PREFIX 24
|
||||
# define VIR_SOCKET_ADDR_IPV4_ALL "0.0.0.0"
|
||||
# define VIR_SOCKET_ADDR_IPV6_ALL "::"
|
||||
|
||||
typedef virSocketAddr *virSocketAddrPtr;
|
||||
|
||||
|
@ -37,6 +37,8 @@
|
||||
</source>
|
||||
<ip address='192.168.122.2' family='ipv4'/>
|
||||
<ip address='2003:db8:1:0:214:1234:fe0b:3596' family='ipv6' prefix='24'/>
|
||||
<route family='ipv4' via='192.168.122.1'/>
|
||||
<route family='ipv6' via='2003:db8:1:0:214:1234:fe0b:3595'/>
|
||||
</hostdev>
|
||||
</devices>
|
||||
</domain>
|
||||
|
@ -30,6 +30,8 @@
|
||||
<source bridge='bri0'/>
|
||||
<ip address='192.168.122.12' family='ipv4' prefix='24'/>
|
||||
<ip address='192.168.122.13' family='ipv4' prefix='24'/>
|
||||
<route family='ipv4' via='192.168.122.1'/>
|
||||
<route family='ipv4' via='192.168.124.1' address='192.168.124.0' prefix='24'/>
|
||||
<target dev='veth0'/>
|
||||
<guest dev='eth2'/>
|
||||
</interface>
|
||||
|
Loading…
Reference in New Issue
Block a user