提交 c9a641f1 编写于 作者: C Cédric Bosdonnat

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.
上级 7100be40
...@@ -4328,14 +4328,18 @@ qemu-kvm -net nic,model=? /dev/null ...@@ -4328,14 +4328,18 @@ qemu-kvm -net nic,model=? /dev/null
&lt;interface type='network'&gt; &lt;interface type='network'&gt;
&lt;source network='default'/&gt; &lt;source network='default'/&gt;
&lt;target dev='vnet0'/&gt; &lt;target dev='vnet0'/&gt;
<b>&lt;ip family='ipv4' address='192.168.122.5' prefix='24'/&gt;</b> <b>&lt;ip address='192.168.122.5' prefix='24'/&gt;</b>
<b>&lt;route family='ipv4' address='192.168.122.0' prefix='24' via='192.168.122.1'/&gt;</b>
<b>&lt;route family='ipv4' via='192.168.122.1'/&gt;</b>
&lt;/interface&gt; &lt;/interface&gt;
... ...
&lt;hostdev mode='capabilities' type='net'&gt; &lt;hostdev mode='capabilities' type='net'&gt;
&lt;source&gt; &lt;source&gt;
&lt;interface&gt;eth0&lt;/interface&gt; &lt;interface&gt;eth0&lt;/interface&gt;
&lt;/source&gt; &lt;/source&gt;
<b>&lt;ip family='ipv4' address='192.168.122.6' prefix='24'/&gt;</b> <b>&lt;ip address='192.168.122.6' prefix='24'/&gt;</b>
<b>&lt;route family='ipv4' address='192.168.122.0' prefix='24' via='192.168.122.1'/&gt;</b>
<b>&lt;route family='ipv4' via='192.168.122.1'/&gt;</b>
&lt;/hostdev&gt; &lt;/hostdev&gt;
&lt;/devices&gt; &lt;/devices&gt;
...@@ -4352,6 +4356,17 @@ qemu-kvm -net nic,model=? /dev/null ...@@ -4352,6 +4356,17 @@ qemu-kvm -net nic,model=? /dev/null
is not mandatory since some hypervisors do not handle it. is not mandatory since some hypervisors do not handle it.
</p> </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> <h5><a name="elementVhostuser">vhost-user interface</a></h5>
<p> <p>
......
...@@ -2329,6 +2329,11 @@ ...@@ -2329,6 +2329,11 @@
<empty/> <empty/>
</element> </element>
</zeroOrMore> </zeroOrMore>
<zeroOrMore>
<element name="route">
<ref name="route"/>
</element>
</zeroOrMore>
<optional> <optional>
<element name="script"> <element name="script">
<attribute name="path"> <attribute name="path">
...@@ -3597,6 +3602,27 @@ ...@@ -3597,6 +3602,27 @@
</element> </element>
</define> </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"> <define name="hostdev">
<element name="hostdev"> <element name="hostdev">
<interleave> <interleave>
...@@ -3832,6 +3858,11 @@ ...@@ -3832,6 +3858,11 @@
<empty/> <empty/>
</element> </element>
</zeroOrMore> </zeroOrMore>
<zeroOrMore>
<element name="route">
<ref name="route"/>
</element>
</zeroOrMore>
</interleave> </interleave>
</define> </define>
......
...@@ -1475,7 +1475,11 @@ void virDomainNetDefFree(virDomainNetDefPtr def) ...@@ -1475,7 +1475,11 @@ void virDomainNetDefFree(virDomainNetDefPtr def)
VIR_FREE(def->ips[i]); VIR_FREE(def->ips[i]);
VIR_FREE(def->ips); 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); VIR_FREE(def->filter);
virNWFilterHashTableFree(def->filterparams); virNWFilterHashTableFree(def->filterparams);
...@@ -1847,6 +1851,9 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def) ...@@ -1847,6 +1851,9 @@ void virDomainHostdevDefClear(virDomainHostdevDefPtr def)
for (i = 0; i < def->source.caps.u.net.nips; i++) 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[i]);
VIR_FREE(def->source.caps.u.net.ips); 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;
} }
break; break;
...@@ -4831,6 +4838,64 @@ virDomainNetIpParseXML(xmlNodePtr node) ...@@ -4831,6 +4838,64 @@ virDomainNetIpParseXML(xmlNodePtr node)
return NULL; 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 static int
virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED, virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
xmlXPathContextPtr ctxt, xmlXPathContextPtr ctxt,
...@@ -4840,6 +4905,8 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED, ...@@ -4840,6 +4905,8 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
xmlNodePtr sourcenode; xmlNodePtr sourcenode;
xmlNodePtr *ipnodes = NULL; xmlNodePtr *ipnodes = NULL;
int nipnodes; int nipnodes;
xmlNodePtr *routenodes = NULL;
int nroutenodes;
int ret = -1; int ret = -1;
/* @type is passed in from the caller rather than read from the /* @type is passed in from the caller rather than read from the
...@@ -4914,6 +4981,26 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED, ...@@ -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; break;
default: default:
virReportError(VIR_ERR_CONFIG_UNSUPPORTED, virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
...@@ -4924,6 +5011,7 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED, ...@@ -4924,6 +5011,7 @@ virDomainHostdevDefParseXMLCaps(xmlNodePtr node ATTRIBUTE_UNUSED,
ret = 0; ret = 0;
error: error:
VIR_FREE(ipnodes); VIR_FREE(ipnodes);
VIR_FREE(routenodes);
return ret; return ret;
} }
...@@ -7367,6 +7455,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, ...@@ -7367,6 +7455,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
size_t i; size_t i;
size_t nips = 0; size_t nips = 0;
virDomainNetIpDefPtr *ips = NULL; virDomainNetIpDefPtr *ips = NULL;
size_t nroutes = 0;
virDomainNetRouteDefPtr *routes = NULL;
if (VIR_ALLOC(def) < 0) if (VIR_ALLOC(def) < 0)
return NULL; return NULL;
...@@ -7463,6 +7553,13 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, ...@@ -7463,6 +7553,13 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
if (VIR_APPEND_ELEMENT(ips, nips, ip) < 0) if (VIR_APPEND_ELEMENT(ips, nips, ip) < 0)
goto error; 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 && } else if (!ifname &&
xmlStrEqual(cur->name, BAD_CAST "target")) { xmlStrEqual(cur->name, BAD_CAST "target")) {
ifname = virXMLPropString(cur, "dev"); ifname = virXMLPropString(cur, "dev");
...@@ -7773,6 +7870,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt, ...@@ -7773,6 +7870,8 @@ virDomainNetDefParseXML(virDomainXMLOptionPtr xmlopt,
if (VIR_APPEND_ELEMENT(def->ips, def->nips, ips[i]) < 0) if (VIR_APPEND_ELEMENT(def->ips, def->nips, ips[i]) < 0)
goto error; goto error;
} }
def->nroutes = nroutes;
def->routes = routes;
if (script != NULL) { if (script != NULL) {
def->script = script; def->script = script;
...@@ -17179,6 +17278,37 @@ virDomainNetIpsFormat(virBufferPtr buf, virDomainNetIpDefPtr *ips, size_t nips) ...@@ -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 static int
virDomainHostdevDefFormatSubsys(virBufferPtr buf, virDomainHostdevDefFormatSubsys(virBufferPtr buf,
virDomainHostdevDefPtr def, virDomainHostdevDefPtr def,
...@@ -17334,6 +17464,8 @@ virDomainHostdevDefFormatCaps(virBufferPtr buf, ...@@ -17334,6 +17464,8 @@ virDomainHostdevDefFormatCaps(virBufferPtr buf,
if (def->source.caps.type == VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET) { if (def->source.caps.type == VIR_DOMAIN_HOSTDEV_CAPS_TYPE_NET) {
virDomainNetIpsFormat(buf, def->source.caps.u.net.ips, virDomainNetIpsFormat(buf, def->source.caps.u.net.ips,
def->source.caps.u.net.nips); def->source.caps.u.net.nips);
virDomainNetRoutesFormat(buf, def->source.caps.u.net.routes,
def->source.caps.u.net.nroutes);
} }
return 0; return 0;
...@@ -17718,6 +17850,7 @@ virDomainNetDefFormat(virBufferPtr buf, ...@@ -17718,6 +17850,7 @@ virDomainNetDefFormat(virBufferPtr buf,
} }
virDomainNetIpsFormat(buf, def->ips, def->nips); virDomainNetIpsFormat(buf, def->ips, def->nips);
virDomainNetRoutesFormat(buf, def->routes, def->nroutes);
virBufferEscapeString(buf, "<script path='%s'/>\n", virBufferEscapeString(buf, "<script path='%s'/>\n",
def->script); def->script);
......
...@@ -485,6 +485,14 @@ struct _virDomainNetIpDef { ...@@ -485,6 +485,14 @@ struct _virDomainNetIpDef {
unsigned int prefix; /* number of 1 bits in the net mask */ 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 struct _virDomainHostdevCaps virDomainHostdevCaps;
typedef virDomainHostdevCaps *virDomainHostdevCapsPtr; typedef virDomainHostdevCaps *virDomainHostdevCapsPtr;
struct _virDomainHostdevCaps { struct _virDomainHostdevCaps {
...@@ -500,6 +508,8 @@ struct _virDomainHostdevCaps { ...@@ -500,6 +508,8 @@ struct _virDomainHostdevCaps {
char *iface; char *iface;
size_t nips; size_t nips;
virDomainNetIpDefPtr *ips; virDomainNetIpDefPtr *ips;
size_t nroutes;
virDomainNetRouteDefPtr *routes;
} net; } net;
} u; } u;
}; };
...@@ -1002,6 +1012,8 @@ struct _virDomainNetDef { ...@@ -1002,6 +1012,8 @@ struct _virDomainNetDef {
int linkstate; int linkstate;
size_t nips; size_t nips;
virDomainNetIpDefPtr *ips; virDomainNetIpDefPtr *ips;
size_t nroutes;
virDomainNetRouteDefPtr *routes;
}; };
/* Used for prefix of ifname of any network name generated dynamically /* Used for prefix of ifname of any network name generated dynamically
......
...@@ -992,8 +992,33 @@ virNetDevAddRoute(const char *ifname, ...@@ -992,8 +992,33 @@ virNetDevAddRoute(const char *ifname,
void *addrData = NULL; void *addrData = NULL;
size_t addrDataLen; size_t addrDataLen;
int errCode; 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) virNetDevGetIPAddressBinary(gateway, &gatewayData, &addrDataLen) < 0)
goto cleanup; goto cleanup;
...@@ -1010,7 +1035,7 @@ virNetDevAddRoute(const char *ifname, ...@@ -1010,7 +1035,7 @@ virNetDevAddRoute(const char *ifname,
memset(&rtmsg, 0, sizeof(rtmsg)); 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_table = RT_TABLE_MAIN;
rtmsg.rtm_scope = RT_SCOPE_UNIVERSE; rtmsg.rtm_scope = RT_SCOPE_UNIVERSE;
rtmsg.rtm_protocol = RTPROT_BOOT; rtmsg.rtm_protocol = RTPROT_BOOT;
...@@ -1043,6 +1068,8 @@ virNetDevAddRoute(const char *ifname, ...@@ -1043,6 +1068,8 @@ virNetDevAddRoute(const char *ifname,
ret = 0; ret = 0;
cleanup: cleanup:
VIR_FREE(toStr);
VIR_FREE(viaStr);
nlmsg_free(nlmsg); nlmsg_free(nlmsg);
return ret; return ret;
......
...@@ -96,7 +96,7 @@ int virNetDevAddRoute(const char *ifname, ...@@ -96,7 +96,7 @@ int virNetDevAddRoute(const char *ifname,
unsigned int prefix, unsigned int prefix,
virSocketAddrPtr gateway, virSocketAddrPtr gateway,
unsigned int metric) unsigned int metric)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(4) ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(4)
ATTRIBUTE_RETURN_CHECK; ATTRIBUTE_RETURN_CHECK;
int virNetDevClearIPAddress(const char *ifname, int virNetDevClearIPAddress(const char *ifname,
virSocketAddr *addr, virSocketAddr *addr,
......
...@@ -55,6 +55,8 @@ typedef struct { ...@@ -55,6 +55,8 @@ typedef struct {
((s)->data.sa.sa_family) ((s)->data.sa.sa_family)
# define VIR_SOCKET_ADDR_DEFAULT_PREFIX 24 # 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; typedef virSocketAddr *virSocketAddrPtr;
......
...@@ -37,6 +37,8 @@ ...@@ -37,6 +37,8 @@
</source> </source>
<ip address='192.168.122.2' family='ipv4'/> <ip address='192.168.122.2' family='ipv4'/>
<ip address='2003:db8:1:0:214:1234:fe0b:3596' family='ipv6' prefix='24'/> <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> </hostdev>
</devices> </devices>
</domain> </domain>
...@@ -30,6 +30,8 @@ ...@@ -30,6 +30,8 @@
<source bridge='bri0'/> <source bridge='bri0'/>
<ip address='192.168.122.12' family='ipv4' prefix='24'/> <ip address='192.168.122.12' family='ipv4' prefix='24'/>
<ip address='192.168.122.13' 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'/> <target dev='veth0'/>
<guest dev='eth2'/> <guest dev='eth2'/>
</interface> </interface>
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册