[libvirt] QEMU/KVM support for non zero PCI domain
by Charles Peri
Hi,
I am trying to run Virt-Manager, using KVM on a SGIUV100 system with RHEL 6.1. I am trying to enable PCI pass-thorugh for the Mellanox, but the PCI domain for the device is 0001.
0001:01:00.0 Ethernet controller: Mellanox Technologies MT26448 [ConnectX EN 10GigE, PCIe 2.0 5GT/s] (rev b0)
0001:02:00.0 InfiniBand: Mellanox Technologies MT26428 [ConnectX VPI PCIe 2.0 5GT/s - IB QDR / 10GigE] (rev b0)
When I try to add the device, I get an error stating that "Can't assign device inside non- zero PCI segment, as this KVM module doesn't support it". Is there a version of KVM module that supports non zero PCI segment?
Sorry, if this is not the right email list to ask this question, I checked on the KVM IRC, but haven't got any answer.
Thanks,
Charles
11 years, 7 months
[libvirt] [PATCHv3] Support for static routes on a virtual bridge
by Gene Czarcinski
This patch adds support for adding a static route for
a network. The "gateway" sub-element specifies
the gateway's IP address. Both IPv4 and IPv6
static routes are supported although it is
expected that this functionality will have
more use with IPv6.
This updates add the <route> element to define a
static route. The gateway= subelement species the
gateway address which is to receive the packets
forwarded to the network specified on the
<route> definition.
Tests are done to validate that the input definitions are
correct. For example, for a static route ip definition,
the address must be a network address and not a host address.
Additional checks are added to ensure that the specified gateway
has a network defined on this bridge.
Whan a static route is added to a bridge, there is a slight
possibility that the gateway address will be incorrect. If
this is handled as an error, that bridge becomes unusable and
can only be recovered by rebooting. If the error is
ignored, then that network can be destroyed and the network
definition file edited to correct the problem. Unfortunately,
the error message only appears in syslog. However, with
the checks performed when the network definition file is parsed,
it is unlikely that this condition will ever occur.
The command used is of the following form:
ip route add <address>/<prefix> via <gateway> dev <virbr-bridge> \
proto static metric 1
.
Signed-off-by: Gene Czarcinski <gene(a)czarc.net>
---
docs/formatnetwork.html.in | 90 ++++++
docs/schemas/network.rng | 22 ++
src/conf/network_conf.c | 329 ++++++++++++++++++++-
src/conf/network_conf.h | 8 +
src/libvirt_private.syms | 1 +
src/network/bridge_driver.c | 40 +++
src/util/virnetdev.c | 46 +++
src/util/virnetdev.h | 5 +
.../networkxml2xmlin/dhcp6host-routed-network.xml | 4 +
.../networkxml2xmlout/dhcp6host-routed-network.xml | 4 +
10 files changed, 548 insertions(+), 1 deletion(-)
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 4dd0415..9f9304a 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -529,6 +529,63 @@
starting.
</p>
+ <h5><a name="elementsStaticroute">Static Routes</a></h5>
+ <p>
+ It has been possible to define static routes on a virtual bridge
+ device <span class="since">Since 1.0.5</span>. Static route
+ definitions are used to provide routing information to the
+ virtualization host for networks which are not defined as a
+ network on one of the virtual bridges on the virtualization host.
+ </p>
+
+ <p>
+ As shown in this example <a href="formatnetwork.html#examplesNoGateway">here</a>,
+ it is possible to define a virtual bridge interface with no
+ IPv4 or IPv6 networks. Such interfaces are useful in supporting
+ networks which have no visibility or direct connectivity with the
+ virtualization host. However, such interfaces can be used to support
+ virtual networks which only have guest connectivity. A guest
+ with connectivity to the internal-only network and another network
+ with with regular connectivity can act as a gateway between the
+ networks. A static route is used provide the routing information
+ so that IP packets (and especially response packets) can be sent from
+ the virtualization host to guests on the hidden network. While
+ static routes can be useful with IPv4 networks, they are essential
+ in supporting IPv6 on seconday/hidden networks.
+ </p>
+
+ <p>
+ Here is a fragment of a definition which shows the static
+ route specification as well as the IPv4 and IPv6 definitions
+ for network addresses which are referred to in the
+ <code>gateway</code> gateway address specifications.
+ </p>
+
+ <pre>
+ ...
+ <ip address="192.168.122.1" netmask="255.255.255.0">
+ <dhcp>
+ <range start="192.168.122.128" end="192.168.122.254" />
+ </dhcp>
+ </ip>
+ <route address="192.168.222.0" prefix="24" gateway="192.168.122.2">
+ </route>
+ <ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" />
+ <route family="ipv6" address="2001:db8:ca2:3::" prefix="64" gateway="2001:db8:ca2:2::2">
+ </route>
+ ...
+ </pre>
+
+ <p>
+ Notice that the <code>route</code> elements look very similar to
+ the <code>ip</code> address specification. Although parts are the same,
+ the meaning and effects of the two definitions are very different. The
+ <code>ip</code> address specification results in an address being defined
+ on the virtual bridge whereas the <code>route</code> definition is used
+ to create the static route for the specified network via the gateway address
+ on the virtual bridge device.
+ </p>
+
<h3><a name="elementsAddress">Addressing</a></h3>
<p>
@@ -540,6 +597,13 @@
a forward mode of 'route' or 'nat'.
</p>
+ <p>
+ Another optional element can add a static route definition to
+ the bridge device. The static route is specified by the
+ <code>route</code> element with <code>gateway</code> used to
+ specify the gateway. <span class="since">Since 1.0.5</span>
+ </p>
+
<pre>
...
<mac address='00:16:3E:5D:C7:9E'/>
@@ -560,6 +624,7 @@
</dhcp>
</ip>
<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" />
+ <route family="ipv6" address="2001:db9:ca1:1::" prefix="64" gateway="2001:db8:ca2:2::2" />
</network></pre>
<dl>
@@ -809,6 +874,31 @@
</ip>
</network></pre>
+ <p>
+ Below is yet another IPv6 variation. This variation has only IPv6
+ defined with DHCPv6 on the primary IPv6 network. A static link
+ if defined for a second IPv6 network which will not be visable on
+ the bridge interface but rill have a static route defined for this
+ network via the specified gateway. Note that the gateway address
+ must be valid for the networks supported on the bridge interface.
+ <span class="since">Since 1.0.5</span>
+ </p>
+
+ <pre>
+ <network>
+ <name>net7</name>
+ <bridge name="virbr7" />
+ <forward mode="route"/>
+ <ip family="ipv6" address="2001:db8:ca2:7::1" prefix="64" >
+ <dhcp>
+ <range start="2001:db8:ca2:7::100" end="2001:db8:ca2::1ff" />
+ <host id="0:4:7e:7d:f0:7d:a8:bc:c5:d2:13:32:11:ed:16:ea:84:63" name="lucas" ip="2001:db8:ca2:2:3::4" />
+ </dhcp>
+ </ip>
+ <route family="ipv6" address="2001:db8:ca2:8::" prefix="64" gateway="2001:db8:ca2:7::4" >
+ </route>
+ </network></pre>
+
<h3><a name="examplesPrivate">Isolated network config</a></h3>
<p>
diff --git a/docs/schemas/network.rng b/docs/schemas/network.rng
index 6c3fae2..5bcba32 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -305,6 +305,28 @@
</optional>
</element>
</zeroOrMore>
+ <!-- <route> element -->
+ <zeroOrMore>
+ <!-- The (static) route element specifies a network address and gateway
+ address to access that network. -->
+ <element name="route">
+ <optional>
+ <attribute name="family"><ref name="addr-family"/></attribute>
+ </optional>
+ <optional>
+ <attribute name="address"><ref name="ipAddr"/></attribute>
+ </optional>
+ <optional>
+ <choice>
+ <attribute name="netmask"><ref name="ipv4Addr"/></attribute>
+ <attribute name="prefix"><ref name="ipPrefix"/></attribute>
+ </choice>
+ </optional>
+ <optional>
+ <attribute name="gateway"><ref name="ipAddr"/></attribute>
+ </optional>
+ </element>
+ </zeroOrMore>
</interleave>
</element>
</define>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index c5535e6..15e0ed0 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1280,6 +1280,208 @@ cleanup:
}
static int
+virNetworkRouteDefParseXML(const char *networkName,
+ xmlNodePtr node,
+ xmlXPathContextPtr ctxt,
+ virNetworkIpDefPtr def)
+{
+ /*
+ * virNetworkRouteDef (reall a virNetworkIpDef) object is already
+ * allocated as part of an array.
+ * On failure clear it out, but don't free it.
+ */
+
+ xmlNodePtr save;
+ char *address = NULL, *netmask = NULL;
+ char *gateway = NULL;
+ unsigned long prefix;
+ int result = -1;
+ virSocketAddr testAddr;
+
+ save = ctxt->node;
+ ctxt->node = node;
+
+ /* grab raw data from XML */
+ def->family = virXPathString("string(./@family)", ctxt);
+ address = virXPathString("string(./@address)", ctxt);
+ if (virXPathULong("string(./@prefix)", ctxt, &prefix) < 0)
+ def->prefix = 0;
+ else
+ def->prefix = prefix;
+
+ netmask = virXPathString("string(./@netmask)", ctxt);
+
+ gateway = virXPathString("string(./@gateway)", ctxt);
+
+ if (address) {
+ if (virSocketAddrParse(&def->address, address, AF_UNSPEC) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Bad network address '%s' in route definition of network '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+
+ }
+
+ if (gateway) {
+ if (virSocketAddrParse(&def->gateway, gateway, AF_UNSPEC) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Bad gateway address '%s' in route definition of network '%s'"),
+ gateway, networkName);
+ goto cleanup;
+ }
+
+ }
+
+ /* validate family vs. address and gateway address too*/
+ if (def->family == NULL) {
+ if (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET) ||
+ VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_UNSPEC))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("no family specified for non-IPv4 address '%s' in network '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+ if (gateway &&
+ (!(VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET) ||
+ VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_UNSPEC)))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("no family specified for non-IPv4 gateway address '%s' in network '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+ if (def->prefix > 0 && def->prefix > 32) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid prefix=%u specified for IPv4 address '%s' in network '%s'"),
+ def->prefix, address, networkName);
+ goto cleanup;
+ }
+ } else if (STREQ(def->family, "ipv4")) {
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("family 'ipv4' specified for non-IPv4 address '%s' in network '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+ if (gateway && (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("family 'ipv4' specified for non-IPv4 gateway address '%s' in network '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+ if (def->prefix > 0 && def->prefix > 32) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid prefix=%u specified for IPv4 address '%s' in network '%s'"),
+ def->prefix, address, networkName);
+ goto cleanup;
+ }
+ } else if (STREQ(def->family, "ipv6")) {
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET6)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("family 'ipv6' specified for non-IPv6 address '%s' in network '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+ if (def->prefix == 0 || def->prefix > 64) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid prefix=%u specified for IPv6 address '%s' in network '%s'"),
+ def->prefix, address, networkName);
+ goto cleanup;
+ }
+ if (netmask) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("specifying netmask invalid for IPv6 address '%s' in network '%s'"),
+ address, networkName);
+ goto cleanup;
+ }
+ if (gateway && (!VIR_SOCKET_ADDR_IS_FAMILY(&def->gateway, AF_INET6))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("family 'ipv6' specified for non-IPv6 gateway address '%s' in network '%s'"),
+ gateway, networkName);
+ goto cleanup;
+ }
+ } else {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Unrecognized family '%s' in definition of network '%s'"),
+ def->family, networkName);
+ goto cleanup;
+ }
+
+ /* parse/validate netmask */
+ if (netmask) {
+ if (address == NULL) {
+ /* netmask is meaningless without an address */
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("netmask specified without address in network '%s'"),
+ networkName);
+ goto cleanup;
+ }
+
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("netmask not supported for address '%s' in network '%s' (IPv4 only)"),
+ address, networkName);
+ goto cleanup;
+ }
+
+ if (def->prefix > 0) {
+ /* can't have both netmask and prefix at the same time */
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("network '%s' cannot have both prefix='%u' and a netmask"),
+ networkName, def->prefix);
+ goto cleanup;
+ }
+
+ if (virSocketAddrParse(&def->netmask, netmask, AF_UNSPEC) < 0)
+ goto cleanup;
+
+ if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->netmask, AF_INET)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("network '%s' has invalid netmask '%s' for address '%s' (both must be IPv4)"),
+ networkName, netmask, address);
+ goto cleanup;
+ }
+ }
+
+ /* if static route gateway specified, make sure the address is a network address */
+ if (def->prefix > 0) {
+ if (virSocketAddrMaskByPrefix(&def->address, def->prefix, &testAddr) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("error converting address '%s' with prefix=%u to network-address in network '%s'"),
+ address, def->prefix, networkName);
+ goto cleanup;
+ }
+ }
+ if (netmask) {
+ if (virSocketAddrMask(&def->address, &def->netmask, &testAddr) < 0) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("error converting address '%s' with netmask '%s' to network-address in network '%s'"),
+ address, netmask, networkName);
+ goto cleanup;
+ }
+ }
+ if (!virSocketAddrEqual(&def->address, &testAddr)) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("address '%s' in network '%s' is not a network-address"),
+ address, networkName);
+ goto cleanup;
+ }
+
+ result = 0;
+
+cleanup:
+ if (result < 0) {
+ virNetworkIpDefClear(def);
+ }
+ VIR_FREE(address);
+ VIR_FREE(netmask);
+ VIR_FREE(gateway);
+
+ ctxt->node = save;
+ return result;
+}
+
+static int
virNetworkPortGroupParseXML(virPortGroupDefPtr def,
xmlNodePtr node,
xmlXPathContextPtr ctxt)
@@ -1676,8 +1878,9 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
char *tmp;
char *stp = NULL;
xmlNodePtr *ipNodes = NULL;
+ xmlNodePtr *routeNodes = NULL;
xmlNodePtr *portGroupNodes = NULL;
- int nIps, nPortGroups;
+ int nIps, nPortGroups, nRoutes;
xmlNodePtr dnsNode = NULL;
xmlNodePtr virtPortNode = NULL;
xmlNodePtr forwardNode = NULL;
@@ -1831,6 +2034,82 @@ virNetworkDefParseXML(xmlXPathContextPtr ctxt)
}
VIR_FREE(ipNodes);
+ nRoutes = virXPathNodeSet("./route", ctxt, &routeNodes);
+ if (nRoutes < 0)
+ goto error;
+
+ if (nRoutes > 0) {
+ int ii;
+
+ /* allocate array to hold all the route definitions */
+ if (VIR_ALLOC_N(def->routes, nRoutes) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ /* parse each definition */
+ for (ii = 0; ii < nRoutes; ii++) {
+ int ret = virNetworkRouteDefParseXML(def->name, routeNodes[ii],
+ ctxt, &def->routes[ii]);
+ if (ret < 0)
+ goto error;
+ def->nroutes++;
+ }
+
+ /* now validate the correctness of any static route gateways specified
+ *
+ * note: the parameters within each definition are varified/assumed valid;
+ * the question being asked and answered here is if the specified gateway
+ * address has a network definition on this bridge
+ */
+ nRoutes = def->nroutes;
+ nIps = def->nips;
+ for (ii = 0; ii < nRoutes; ii++) {
+ int jj;
+ virSocketAddr testAddr, testGw;
+ bool addrMatch;
+ virNetworkIpDefPtr gwdef = &def->routes[ii];
+ if (VIR_SOCKET_ADDR_VALID(&gwdef->gateway)) {
+ addrMatch = false;
+ for (jj = 0; jj < nIps; jj++) {
+ virNetworkIpDefPtr def2 = &def->ips[jj];
+ if ((VIR_SOCKET_ADDR_IS_FAMILY(&gwdef->gateway, AF_INET6)) &&
+ (!VIR_SOCKET_ADDR_IS_FAMILY(&def2->address, AF_INET6)))
+ continue;
+ if ((VIR_SOCKET_ADDR_IS_FAMILY(&def2->address, AF_INET6)) &&
+ (!VIR_SOCKET_ADDR_IS_FAMILY(&gwdef->gateway, AF_INET6)))
+ continue;
+ if ((VIR_SOCKET_ADDR_IS_FAMILY(&gwdef->gateway, AF_INET) ||
+ VIR_SOCKET_ADDR_IS_FAMILY(&gwdef->gateway, AF_UNSPEC)) &&
+ VIR_SOCKET_ADDR_IS_FAMILY(&def2->address, AF_INET6))
+ continue;
+ if (def2->prefix > 0) {
+ virSocketAddrMaskByPrefix(&def2->address, def2->prefix, &testAddr);
+ virSocketAddrMaskByPrefix(&gwdef->gateway, def2->prefix, &testGw);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&def2->netmask)) {
+ virSocketAddrMask(&def2->address, &def2->netmask, &testAddr);
+ virSocketAddrMask(&gwdef->gateway, &def2->netmask, &testGw);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&testAddr) &&
+ VIR_SOCKET_ADDR_VALID(&testGw) &&
+ virSocketAddrEqual(&testAddr, &testGw)) {
+ addrMatch = true;
+ break;
+ }
+ }
+ if (!addrMatch) {
+ char *gw = virSocketAddrFormat(&gwdef->gateway);
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("invalid static route gateway specified: '%s'"),
+ gw);
+ VIR_FREE(gw);
+ goto error;
+ }
+ }
+ }
+ }
+ VIR_FREE(routeNodes);
+
forwardNode = virXPathNode("./forward", ctxt);
if (forwardNode &&
virNetworkForwardDefParseXML(def->name, forwardNode, ctxt, &def->forward) < 0) {
@@ -2203,6 +2482,49 @@ error:
}
static int
+virNetworkRouteDefFormat(virBufferPtr buf,
+ const virNetworkIpDefPtr def)
+{
+ int result = -1;
+
+ virBufferAddLit(buf, "<route");
+
+ if (def->family) {
+ virBufferAsprintf(buf, " family='%s'", def->family);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&def->address)) {
+ char *addr = virSocketAddrFormat(&def->address);
+ if (!addr)
+ goto error;
+ virBufferAsprintf(buf, " address='%s'", addr);
+ VIR_FREE(addr);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&def->netmask)) {
+ char *addr = virSocketAddrFormat(&def->netmask);
+ if (!addr)
+ goto error;
+ virBufferAsprintf(buf, " netmask='%s'", addr);
+ VIR_FREE(addr);
+ }
+ if (def->prefix > 0) {
+ virBufferAsprintf(buf," prefix='%u'", def->prefix);
+ }
+ if (VIR_SOCKET_ADDR_VALID(&def->gateway)) {
+ char *addr = virSocketAddrFormat(&def->gateway);
+ if (!addr)
+ goto error;
+ virBufferAsprintf(buf, " gateway='%s'", addr);
+ VIR_FREE(addr);
+ }
+ virBufferAddLit(buf, ">\n");
+ virBufferAddLit(buf, "</route>\n");
+
+ result = 0;
+error:
+ return result;
+}
+
+static int
virPortGroupDefFormat(virBufferPtr buf,
const virPortGroupDefPtr def)
{
@@ -2400,6 +2722,11 @@ virNetworkDefFormatInternal(virBufferPtr buf,
goto error;
}
+ for (ii = 0; ii < def->nroutes; ii++) {
+ if (virNetworkRouteDefFormat(buf, &def->routes[ii]) < 0)
+ goto error;
+ }
+
if (virNetDevVPortProfileFormat(def->virtPortProfile, buf) < 0)
goto error;
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 6ce9a00..39aec7e 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -109,6 +109,8 @@ struct _virNetworkDNSDef {
virNetworkDNSSrvDefPtr srvs;
};
+/* NOTE: The folowing structure is used for both IP address
+ * definitions and for static route definitions */
typedef struct _virNetworkIpDef virNetworkIpDef;
typedef virNetworkIpDef *virNetworkIpDefPtr;
struct _virNetworkIpDef {
@@ -124,6 +126,9 @@ struct _virNetworkIpDef {
unsigned int prefix; /* ipv6 - only prefix allowed */
virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */
+ virSocketAddr gateway; /* gateway IP address for ip-route */
+
+ /* the following has no meaning if this is a static route definition */
size_t nranges; /* Zero or more dhcp ranges */
virSocketAddrRangePtr ranges;
@@ -209,6 +214,9 @@ struct _virNetworkDef {
size_t nips;
virNetworkIpDefPtr ips; /* ptr to array of IP addresses on this network */
+ size_t nroutes;
+ virNetworkIpDefPtr routes; /* ptr to array of static routes on this interface */
+
virNetworkDNSDef dns; /* dns related configuration */
virNetDevVPortProfilePtr virtPortProfile;
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 96eea0a..c51ba36 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1466,6 +1466,7 @@ virNetDevReplaceMacAddress;
virNetDevReplaceNetConfig;
virNetDevRestoreMacAddress;
virNetDevRestoreNetConfig;
+virNetDevSetGateway;
virNetDevSetIPv4Address;
virNetDevSetMAC;
virNetDevSetMTU;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index e8b314a..2d4102e 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -2360,6 +2360,7 @@ out:
return ret;
}
+/* add an IP address to a bridge */
static int
networkAddAddrToBridge(virNetworkObjPtr network,
virNetworkIpDefPtr ipdef)
@@ -2380,6 +2381,28 @@ networkAddAddrToBridge(virNetworkObjPtr network,
return 0;
}
+/* add an IP (static) route to a bridge */
+static int
+networkAddRouteToBridge(virNetworkObjPtr network,
+ virNetworkIpDefPtr ipdef)
+{
+ int prefix = virNetworkIpDefPrefix(ipdef);
+
+ if (prefix < 0) {
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("bridge '%s' has an invalid netmask or IP address"),
+ network->def->bridge);
+ return -1;
+ }
+
+ if (virNetDevSetGateway(network->def->bridge,
+ &ipdef->address,
+ prefix,
+ &ipdef->gateway) < 0)
+ return -1;
+ return 0;
+}
+
static int
networkStartNetworkVirtual(struct network_driver *driver,
virNetworkObjPtr network)
@@ -2446,6 +2469,7 @@ networkStartNetworkVirtual(struct network_driver *driver,
if (networkAddIptablesRules(driver, network) < 0)
goto err1;
+ /* first, do all of the real addresses */
for (ii = 0;
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
ii++) {
@@ -2464,6 +2488,22 @@ networkStartNetworkVirtual(struct network_driver *driver,
if (virNetDevSetOnline(network->def->bridge, 1) < 0)
goto err2;
+ /* now, do all of the static routes */
+ if (network->def->nroutes > 0) {
+ for (ii = 0; ii < network->def->nroutes; ii++) {
+ ipdef = &network->def->routes[ii];
+ /* Add the IP route to the bridge */
+ /* ignore errors, error msg will be generated */
+ /* but libvirt will not know and net-destroy will work. */
+ if (VIR_SOCKET_ADDR_VALID(&ipdef->gateway)) {
+ if (networkAddRouteToBridge(network, ipdef) < 0) {
+ /* an error occurred adding the static route */
+ continue; /* for now, do nothing */
+ }
+ }
+ }
+ }
+
/* If forward.type != NONE, turn on global IP forwarding */
if (network->def->forward.type != VIR_NETWORK_FORWARD_NONE &&
networkEnableIpForwarding(v4present, v6present) < 0) {
diff --git a/src/util/virnetdev.c b/src/util/virnetdev.c
index 00e0f94..6ac9d9d 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -769,6 +769,52 @@ cleanup:
}
/**
+ * virNetDevSetGateway:
+ * @ifname: the interface name
+ * @addr: the IP network address (IPv4 or IPv6)
+ * @prefix: number of 1 bits in the netmask
+ * @gateway: via address for route (same as @addr)
+ *
+ * Add a route for a network IP address to an interface. This function
+ * *does not* remove any previously added IP static routes.
+ *
+ * Returns 0 in case of success or -1 in case of error.
+ */
+
+int virNetDevSetGateway(const char *ifname,
+ virSocketAddr *addr,
+ unsigned int prefix,
+ virSocketAddr *gateway)
+{
+ virCommandPtr cmd = NULL;
+ char *addrstr = NULL, *gatewaystr = NULL;
+ int ret = -1;
+
+ if (!(addrstr = virSocketAddrFormat(addr)))
+ goto cleanup;
+ if (!(gatewaystr = virSocketAddrFormat(gateway)))
+ goto cleanup;
+ cmd = virCommandNew(IP_PATH);
+ virCommandAddArgList(cmd, "route", "add", NULL);
+ virCommandAddArgFormat(cmd, "%s/%u", addrstr, prefix);
+ virCommandAddArgList(cmd, "via", NULL);
+ virCommandAddArgFormat(cmd, "%s", gatewaystr);
+ virCommandAddArgList(cmd, "dev", ifname, NULL);
+ virCommandAddArgList(cmd, "proto", "static", "metric", NULL);
+ virCommandAddArgFormat(cmd, "%u", 1);
+
+ if (virCommandRun(cmd, NULL) < 0)
+ goto cleanup;
+
+ ret = 0;
+cleanup:
+ VIR_FREE(addrstr);
+ VIR_FREE(gatewaystr);
+ virCommandFree(cmd);
+ return ret;
+}
+
+/**
* virNetDevClearIPv4Address:
* @ifname: the interface name
* @addr: the IP address (IPv4 or IPv6)
diff --git a/src/util/virnetdev.h b/src/util/virnetdev.h
index 06d0650..8b94ea8 100644
--- a/src/util/virnetdev.h
+++ b/src/util/virnetdev.h
@@ -42,6 +42,11 @@ int virNetDevSetIPv4Address(const char *ifname,
virSocketAddr *addr,
unsigned int prefix)
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
+int virNetDevSetGateway(const char *ifname,
+ virSocketAddr *addr,
+ unsigned int prefix,
+ virSocketAddr *gateway)
+ ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
int virNetDevClearIPv4Address(const char *ifname,
virSocketAddr *addr,
unsigned int prefix)
diff --git a/tests/networkxml2xmlin/dhcp6host-routed-network.xml b/tests/networkxml2xmlin/dhcp6host-routed-network.xml
index 2693d87..29e9561 100644
--- a/tests/networkxml2xmlin/dhcp6host-routed-network.xml
+++ b/tests/networkxml2xmlin/dhcp6host-routed-network.xml
@@ -19,4 +19,8 @@
<host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
</dhcp>
</ip>
+ <route address="192.168.222.0" netmask="255.255.255.0" gateway="192.168.122.10">
+ </route>
+ <route family="ipv6" address="2001:db8:ac10:fc00::" prefix="64" gateway="2001:db8:ac10:fd01::1:24">
+ </route>
</network>
diff --git a/tests/networkxml2xmlout/dhcp6host-routed-network.xml b/tests/networkxml2xmlout/dhcp6host-routed-network.xml
index 7305043..39af583 100644
--- a/tests/networkxml2xmlout/dhcp6host-routed-network.xml
+++ b/tests/networkxml2xmlout/dhcp6host-routed-network.xml
@@ -21,4 +21,8 @@
<host id='0:1:0:1:18:aa:62:fe:0:16:3e:44:55:66' name='badbob' ip='2001:db8:ac10:fd01::1:24' />
</dhcp>
</ip>
+ <route address='192.168.222.0' netmask='255.255.255.0' gateway='192.168.122.10'>
+ </route>
+ <route family='ipv6' address='2001:db8:ac10:fc00::' prefix='64' gateway='2001:db8:ac10:fd01::1:24'>
+ </route>
</network>
--
1.8.1.4
11 years, 7 months
[libvirt] need help: what should be supported?
by Gene Czarcinski
I need some help/guidance as to what networking characteristics should
be supported by libvirt. Mostly, I am asking what should be valid for a
prefix.
For IPv4:
The prefix can theoretically range from 0 to 32. Typically, the values
of 8, 16 or 24 is used. For an IP specification, should I be able to
specify prefix=32 (netmask 255.255.255.255)? This is not a network
specification but one for a specific guest-host ... but, what will the
virtualization host have for the address on this interface?
Proposed: prefix (or equivalent netmask) must be
8 < prefix < 29
For IPv6: Similar to IPv4 but the range is (theoretically) 0 to 128.
However, DHCPv6 and RA will **ONLY** work for prefix=64 ... nothing
greater and nothing less. For an network on an interface which is
visible to the virtualization host, it must have an address for the
host; therefore, prefix <127. I am not sure what an IP definition with
prefix=0 means for a libvirt virtual network.
Proposed: Prefix=64 for DHCPv6 and/or RA support. For other network
addresses (such as static route),
7 < prefix <= 64.
Most IPv6 software does not appear to handle subnets where prefix > 64
except for prefix=128 for a specific host address.
That is not to say that prefix <64 prefix < 128 could not have a meaning
and be useful. But, if supported, how should it be specified so that
user problems are minimized ... or do we just support it and what
happens is a user problem?
Comments? Suggestions??
Gene
11 years, 7 months
[libvirt] [PATCHv2] Configure native vlan modes on Open vSwitch ports
by james robson
This patch adds functionality to allow libvirt to configure the
'native-tagged' and 'native-untagged' modes on openvswitch networks.
v2 changes:
Fix problems reported by Eric Blake
---
diff --git a/docs/formatdomain.html.in b/docs/formatdomain.html.in
index ffcc33e..a5054cc 100644
--- a/docs/formatdomain.html.in
+++ b/docs/formatdomain.html.in
@@ -3209,6 +3209,12 @@ qemu-kvm -net nic,model=? /dev/null
<parameters
interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
</virtualport>
</interface>
+ <interface type='bridge'>
+ <b><vlan trunk='yes' native_mode='tagged'
native_tag='123'></b>
+ <b><tag id='42'/></b>
+ <b></vlan></b>
+ ...
+ </interface>
<devices>
...</pre>
@@ -3234,7 +3240,17 @@ qemu-kvm -net nic,model=? /dev/null
attribute <code>trunk='yes'</code> can be added to the toplevel
vlan element.
</p>
-
+ <p>
+ For network connections using openvswitch it is possible to
+ configure the 'native-tagged' and 'native-untagged' vlan modes
+ <span class="since">(Since 1.0.3).</span> This uses the optional
+ <code>native_mode</code> and <code>native_tag</code> attributes
+ on the <code><vlan></code> element:
<code>native_mode</code>
+ may be set to 'tagged' or 'untagged', <code>native_tag</code>
+ sets the id of the native vlan. Setting a native vlan implies
+ this is a trunk port, so <code>trunk='yes'</code> will be added
if not
+ explicitly set.
+ </p>
<h5><a name="elementLink">Modifying virtual link state</a></h5>
<pre>
...
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 7b42529..68c562b 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -396,6 +396,12 @@
<parameters
interfaceid='09b11c53-8b5c-4eeb-8f00-d84eaa0aaa4f'/>
</virtualport>
</interface>
+ <interface type='bridge'>
+ <b><vlan trunk='yes' native_mode='tagged'
native_tag='123'></b>
+ <b><tag id='42'/></b>
+ <b></vlan></b>
+ ...
+ </interface>
<devices>
...</pre>
diff --git a/docs/schemas/networkcommon.rng
b/docs/schemas/networkcommon.rng
index 51ff759..4696f43 100644
--- a/docs/schemas/networkcommon.rng
+++ b/docs/schemas/networkcommon.rng
@@ -197,6 +197,21 @@
<value>yes</value>
</attribute>
</optional>
+ <optional>
+ <attribute name="native_mode">
+ <choice>
+ <value>tagged</value>
+ <value>untagged</value>
+ </choice>
+ </attribute>
+ </optional>
+ <optional>
+ <attribute name="native_tag">
+ <data type="unsignedInt">
+ <param name="maxInclusive">4095</param>
+ </data>
+ </attribute>
+ </optional>
<oneOrMore>
<element name="tag">
<attribute name="id">
diff --git a/src/conf/netdev_vlan_conf.c b/src/conf/netdev_vlan_conf.c
index 13ba8c6..618eb4c 100644
--- a/src/conf/netdev_vlan_conf.c
+++ b/src/conf/netdev_vlan_conf.c
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -33,6 +34,8 @@ virNetDevVlanParse(xmlNodePtr node, xmlXPathContextPtr
ctxt, virNetDevVlanPtr de
int ret = -1;
xmlNodePtr save = ctxt->node;
const char *trunk = NULL;
+ const char *nativeMode;
+ unsigned int nativeTag;
xmlNodePtr *tagNodes = NULL;
int nTags, ii;
@@ -73,16 +76,44 @@ virNetDevVlanParse(xmlNodePtr node,
xmlXPathContextPtr ctxt, virNetDevVlanPtr de
def->nTags = nTags;
- /* now that we know how many tags there are, look for an explicit
- * trunk setting.
- */
- if (nTags > 1)
- def->trunk = true;
+ def->nativeMode = 0;
+ def->nativeTag = 0;
ctxt->node = node;
+ if ((nativeMode = virXPathString("string(./@native_mode)", ctxt)) !
= NULL) {
+ if (STRCASENEQ(nativeMode, "tagged") && STRCASENEQ(nativeMode,
"untagged")) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("invalid \"native_mode='%s'\" in <vlan> -
"
+ "native_mode must be 'tagged' or
'untagged'"), nativeMode);
+ goto error;
+ }
+ if (virXPathUInt("string(./@native_tag)", ctxt, &nativeTag) <
0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("missing or invalid native_tag
attribute"));
+ goto error;
+ }
+ if (nativeTag > 4095) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("native_tag %u too large (maximum 4095)"),
nativeTag);
+ goto error;
+ }
+ def->nativeMode = STRCASEEQ(nativeMode, "tagged") ? 1 : 2;
+ def->nativeTag = nativeTag;
+ }
+
+ /* def->trunk will be set to true if:
+ * "trunk='yes'" is set in xml
+ * a native-* vlan mode has been set
+ * >1 tag has been set */
if ((trunk = virXPathString("string(./@trunk)", ctxt)) != NULL) {
def->trunk = STRCASEEQ(trunk, "yes");
if (!def->trunk) {
+ if (def->nativeMode > 0) {
+ virReportError(VIR_ERR_XML_ERROR, "%s",
+ _("invalid configuration in <vlan> -
\"trunk='no'\" is "
+ "not allowed with native_mode"));
+ goto error;
+ }
if (nTags > 1) {
virReportError(VIR_ERR_XML_ERROR,
_("invalid \"trunk='%s'\" in <vlan> -
trunk='yes' "
@@ -97,6 +128,8 @@ virNetDevVlanParse(xmlNodePtr node,
xmlXPathContextPtr ctxt, virNetDevVlanPtr de
goto error;
}
}
+ } else if (nTags > 1 || def->nativeMode > 0) {
+ def->trunk = true;
}
ret = 0;
@@ -122,8 +155,11 @@ virNetDevVlanFormat(virNetDevVlanPtr def,
virBufferPtr buf)
_("missing vlan tag data"));
return -1;
}
-
- virBufferAsprintf(buf, "<vlan%s>\n", def->trunk ? " trunk='yes'" :
"");
+ if (def->nativeMode == 0) {
+ virBufferAsprintf(buf, "<vlan%s>\n", def->trunk ? "
trunk='yes'" : "");
+ } else {
+ virBufferAsprintf(buf, "<vlan trunk='yes' native_mode='%s'
native_tag='%u'>\n", def->nativeMode == 1 ? "tagged" : "untagged",
def->nativeTag);
+ }
for (ii = 0; ii < def->nTags; ii++) {
virBufferAsprintf(buf, " <tag id='%u'/>\n", def->tag[ii]);
}
diff --git a/src/util/virnetdevopenvswitch.c
b/src/util/virnetdevopenvswitch.c
index 4fe077a..87122b0 100644
--- a/src/util/virnetdevopenvswitch.c
+++ b/src/util/virnetdevopenvswitch.c
@@ -19,6 +19,7 @@
* Dan Wendlandt <dan(a)nicira.com>
* Kyle Mestery <kmestery(a)cisco.com>
* Ansis Atteka <aatteka(a)nicira.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -108,9 +109,13 @@ int virNetDevOpenvswitchAddPort(const char *brname,
const char *ifname,
virCommandAddArgList(cmd, "--timeout=5", "--", "--may-exist",
"add-port",
brname, ifname, NULL);
- if (virBufferUse(&buf) != 0)
+ if (virBufferUse(&buf) != 0) {
+ if (virtVlan->nativeMode > 0) {
+ virCommandAddArgFormat(cmd, "vlan_mode=%s",
virtVlan->nativeMode == 1 ? "native-tagged" : "native-untagged");
+ virCommandAddArgFormat(cmd, "tag=%d", virtVlan->nativeTag);
+ }
virCommandAddArgList(cmd, virBufferCurrentContent(&buf), NULL);
-
+ }
if (ovsport->profileID[0] == '\0') {
virCommandAddArgList(cmd,
"--", "set", "Interface", ifname,
attachedmac_ex_id,
diff --git a/src/util/virnetdevvlan.c b/src/util/virnetdevvlan.c
index 2fe2017..298673d 100644
--- a/src/util/virnetdevvlan.c
+++ b/src/util/virnetdevvlan.c
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#include <config.h>
@@ -33,6 +34,8 @@ virNetDevVlanClear(virNetDevVlanPtr vlan)
{
VIR_FREE(vlan->tag);
vlan->nTags = 0;
+ vlan->nativeMode = 0;
+ vlan->nativeTag = -1;
}
void
@@ -54,7 +57,9 @@ virNetDevVlanEqual(const virNetDevVlanPtr a, const
virNetDevVlanPtr b)
return false;
if (a->trunk != b->trunk ||
- a->nTags != b->nTags) {
+ a->nTags != b->nTags ||
+ a->nativeMode != b->nativeMode ||
+ a->nativeTag != b->nativeTag) {
return false;
}
@@ -89,6 +94,8 @@ virNetDevVlanCopy(virNetDevVlanPtr dst, const
virNetDevVlanPtr src)
dst->trunk = src->trunk;
dst->nTags = src->nTags;
+ dst->nativeMode = src->nativeMode;
+ dst->nativeTag = src->nativeTag;
memcpy(dst->tag, src->tag, src->nTags * sizeof(*src->tag));
return 0;
}
diff --git a/src/util/virnetdevvlan.h b/src/util/virnetdevvlan.h
index c6b16ef..f0f78f0 100644
--- a/src/util/virnetdevvlan.h
+++ b/src/util/virnetdevvlan.h
@@ -17,6 +17,7 @@
*
* Authors:
* Laine Stump <laine(a)redhat.com>
+ * James Robson <jrobson(a)websense.com>
*/
#ifndef __VIR_NETDEV_VLAN_H__
@@ -25,6 +26,8 @@
typedef struct _virNetDevVlan virNetDevVlan;
typedef virNetDevVlan *virNetDevVlanPtr;
struct _virNetDevVlan {
+ short int nativeMode; /* 0=off, 1=tagged, 2=untagged */
+ unsigned int nativeTag;
bool trunk; /* true if this is a trunk */
int nTags; /* number of tags in array */
unsigned int *tag; /* pointer to array of tags */
diff --git a/tests/networkxml2xmlin/openvswitch-net.xml
b/tests/networkxml2xmlin/openvswitch-net.xml
index a3d82b1..93c49d5 100644
--- a/tests/networkxml2xmlin/openvswitch-net.xml
+++ b/tests/networkxml2xmlin/openvswitch-net.xml
@@ -21,4 +21,13 @@
<parameters profileid='alice-profile'/>
</virtualport>
</portgroup>
+ <portgroup name='tagged'>
+ <vlan native_mode='tagged' native_tag='123'>
+ <tag id='555'/>
+ <tag id='444'/>
+ </vlan>
+ <virtualport>
+ <parameters profileid='tagged-profile'/>
+ </virtualport>
+ </portgroup>
</network>
diff --git a/tests/networkxml2xmlout/openvswitch-net.xml
b/tests/networkxml2xmlout/openvswitch-net.xml
index a3d82b1..ab3d797 100644
--- a/tests/networkxml2xmlout/openvswitch-net.xml
+++ b/tests/networkxml2xmlout/openvswitch-net.xml
@@ -21,4 +21,13 @@
<parameters profileid='alice-profile'/>
</virtualport>
</portgroup>
+ <portgroup name='tagged'>
+ <vlan trunk='yes' native_mode='tagged' native_tag='123'>
+ <tag id='555'/>
+ <tag id='444'/>
+ </vlan>
+ <virtualport>
+ <parameters profileid='tagged-profile'/>
+ </virtualport>
+ </portgroup>
</network>
Protected by Websense Hosted Email Security -- www.websense.com
11 years, 7 months
[libvirt] [libvirt-glib] vapi: Get rid of redundant LibvirtGObject-1.0.metadata
by Zeeshan Ali (Khattak)
From: "Zeeshan Ali (Khattak)" <zeeshanak(a)gnome.org>
Achieve the same through GIR annotations, just like we already do for
libvirt-glib.
---
libvirt-gobject/libvirt-gobject-main.c | 8 ++++++--
vapi/LibvirtGObject-1.0.metadata | 2 --
vapi/Makefile.am | 2 +-
3 files changed, 7 insertions(+), 5 deletions(-)
delete mode 100644 vapi/LibvirtGObject-1.0.metadata
diff --git a/libvirt-gobject/libvirt-gobject-main.c b/libvirt-gobject/libvirt-gobject-main.c
index 31d2514..f9f6e2d 100644
--- a/libvirt-gobject/libvirt-gobject-main.c
+++ b/libvirt-gobject/libvirt-gobject-main.c
@@ -33,7 +33,9 @@
/**
* gvir_init_object:
* @argc: (inout): pointer to application's argc
- * @argv: (inout) (array length=argc) (allow-none): pointer to application's argv
+ * @argv: (array length=argc) (inout) (allow-none) (transfer none): Address of the
+ * <parameter>argv</parameter> parameter of main(), or %NULL. Any options
+ * understood by GTK+ are stripped before return.
*/
void gvir_init_object(int *argc,
char ***argv)
@@ -58,7 +60,9 @@ static void gvir_log_handler(const gchar *log_domain G_GNUC_UNUSED,
/**
* gvir_init_object_check:
* @argc: (inout): pointer to application's argc
- * @argv: (inout) (array length=argc) (allow-none): pointer to application's argv
+ * @argv: (array length=argc) (inout) (allow-none) (transfer none): Address of the
+ * <parameter>argv</parameter> parameter of main(), or %NULL. Any options
+ * understood by GTK+ are stripped before return.
* @err: pointer to a #GError to which a message will be posted on error
*/
gboolean gvir_init_object_check(int *argc,
diff --git a/vapi/LibvirtGObject-1.0.metadata b/vapi/LibvirtGObject-1.0.metadata
deleted file mode 100644
index 90e5197..0000000
--- a/vapi/LibvirtGObject-1.0.metadata
+++ /dev/null
@@ -1,2 +0,0 @@
-init_object.argv unowned
-init_object_check.argv unowned
diff --git a/vapi/Makefile.am b/vapi/Makefile.am
index 2ecc3e3..0154104 100644
--- a/vapi/Makefile.am
+++ b/vapi/Makefile.am
@@ -44,4 +44,4 @@ CLEANFILES = \
libvirt-gobject-1.0.vapi \
$(NULL)
-EXTRA_DIST = LibvirtGObject-1.0.metadata libvirt-gobject-1.0.deps
+EXTRA_DIST = libvirt-gobject-1.0.deps
--
1.8.1.4
11 years, 7 months
[libvirt] [libvirt-designer 0/9] Handle more devices in GVirDesignerDomain
by Christophe Fergeau
This series builds on the previous one (the one adding
gvir_designer_domain_get_supported_devices()). It adds methods
to add more devices disks/network interfaces to GVirDesignDomain.
Some parts like 'Automatically add SPICE channel with SPICE graphics'
may not be what we want, but I've tried to make the external API as
easy as possible.
Christophe
11 years, 7 months
[libvirt] Improve disk bus type generation
by Christophe Fergeau
This is mostly an excuse to add a _get_supported_devices() method
used in fallback cases (when the deployment does not specify
a disk driver to be used) as this will be useful later.
The list of supported devices is generated with
- devices supported both by the OS and the platform (hypervisor)
- devices for which we have a OS driver, and which are supported
by the platform
When doing this work, I realized a few things were missing
from libosinfo:
- to properly guess the bus to use for a disk (sata, ide,
scsi, ...) from a libosinfo device, we'd need to have the
PCI subclass in libosinfo. This will probably need to be
added at some point
- something that would be nice for easier fallback when the
deployment does not specify a device would be a way for
OS/platforms to indicate that their preferred disk device
is virtio-disk, then sata device XXX, ...
I also think deployments would be more flexible if a deployment
meant for qemu-1.2.0 could be used with qemu-1.3.0. Currently,
osinfo_db_find_deployment does not follow 'upgrades' relations
on platforms, but I think it would be more convenient if it did.
Christophe
11 years, 7 months
[libvirt] [libvirt-designer PATCHv2] Add support for floppies and CDROMs
by Christophe Fergeau
This mirrors disk_file/disk_device API so that it's possible to
add CDROMs and floppies to a GVirDesignerDomain.
This also adds the corresponding -C/-F options to virtxml
---
Here is a reworked version of my patch to add support for CDROMs which
does not override the 'format' parameter this time.
Christophe
examples/virtxml.c | 108 +++++++++++++++++++++---
libvirt-designer/libvirt-designer-domain.c | 127 +++++++++++++++++++++++++++++
libvirt-designer/libvirt-designer-domain.h | 14 ++++
libvirt-designer/libvirt-designer.sym | 4 +
4 files changed, 240 insertions(+), 13 deletions(-)
diff --git a/examples/virtxml.c b/examples/virtxml.c
index 49a7b4e..d4c5967 100644
--- a/examples/virtxml.c
+++ b/examples/virtxml.c
@@ -33,7 +33,9 @@
#include <unistd.h>
#include <glib/gprintf.h>
+GList *cdrom_str_list = NULL;
GList *disk_str_list = NULL;
+GList *floppy_str_list = NULL;
GList *iface_str_list = NULL;
OsinfoDb *db = NULL;
@@ -173,16 +175,17 @@ cleanup:
return TRUE;
}
+
static void
-add_disk(gpointer data,
- gpointer user_data)
+add_disk_generic(GVirDesignerDomain *domain,
+ const char *path,
+ GVirConfigDomainDiskGuestDeviceType type)
{
- GVirDesignerDomain *domain = (GVirDesignerDomain *) user_data;
GVirConfigDomainDisk *disk;
- char *path = (char *) data;
char *format = NULL;
struct stat buf;
GError *error = NULL;
+ gboolean is_device;
format = strchr(path, ',');
if (format) {
@@ -195,12 +198,30 @@ add_disk(gpointer data,
exit(EXIT_FAILURE);
}
- if (!stat(path, &buf) &&
- !S_ISREG(buf.st_mode)) {
- disk = gvir_designer_domain_add_disk_device(domain, path, &error);
- } else {
- disk = gvir_designer_domain_add_disk_file(domain, path, format, &error);
+ is_device = (!stat(path, &buf) && !S_ISREG(buf.st_mode));
+ switch(type) {
+ case GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_CDROM:
+ if (is_device)
+ disk = gvir_designer_domain_add_cdrom_device(domain, path, &error);
+ else
+ disk = gvir_designer_domain_add_cdrom_file(domain, path, format, &error);
+ break;
+ case GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_DISK:
+ if (is_device)
+ disk = gvir_designer_domain_add_disk_device(domain, path, &error);
+ else
+ disk = gvir_designer_domain_add_disk_file(domain, path, format, &error);
+ break;
+ case GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_FLOPPY:
+ if (is_device)
+ disk = gvir_designer_domain_add_floppy_device(domain, path, &error);
+ else
+ disk = gvir_designer_domain_add_floppy_file(domain, path, format, &error);
+ break;
+ default:
+ g_return_if_reached();
}
+
if (disk)
g_object_unref(G_OBJECT(disk));
@@ -210,6 +231,42 @@ add_disk(gpointer data,
}
}
+
+static void add_cdrom(gpointer data, gpointer user_data)
+{
+ add_disk_generic(GVIR_DESIGNER_DOMAIN(user_data),
+ (const char *)data,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_CDROM);
+}
+
+
+static void add_disk(gpointer data, gpointer user_data)
+{
+ add_disk_generic(GVIR_DESIGNER_DOMAIN(user_data),
+ (const char *)data,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_DISK);
+}
+
+
+static void add_floppy(gpointer data, gpointer user_data)
+{
+ add_disk_generic(GVIR_DESIGNER_DOMAIN(user_data),
+ (const char *)data,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_FLOPPY);
+}
+
+
+static gboolean
+add_cdrom_str(const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ cdrom_str_list = g_list_append(cdrom_str_list, g_strdup(value));
+ return TRUE;
+}
+
+
static gboolean
add_disk_str(const gchar *option_name,
const gchar *value,
@@ -220,6 +277,18 @@ add_disk_str(const gchar *option_name,
return TRUE;
}
+
+static gboolean
+add_floppy_str(const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ floppy_str_list = g_list_append(floppy_str_list, g_strdup(value));
+ return TRUE;
+}
+
+
static void
add_iface(gpointer data,
gpointer user_data)
@@ -357,7 +426,7 @@ cleanup:
}
static OsinfoOs *
-guess_os_from_disk(GList *disk_list)
+guess_os_from_cdrom(GList *disk_list)
{
OsinfoOs *ret = NULL;
GList *list_it = NULL;
@@ -512,8 +581,12 @@ main(int argc, char *argv[])
"set hypervisor under which domain will be running", "PLATFORM"},
{"architecture", 'a', 0, G_OPTION_ARG_STRING, &arch_str,
"set domain architecture", "ARCH"},
+ {"cdrom", 'C', 0, G_OPTION_ARG_CALLBACK, add_cdrom_str,
+ "add CDROM to domain with PATH being source and FORMAT its format", "PATH[,FORMAT]"},
{"disk", 'd', 0, G_OPTION_ARG_CALLBACK, add_disk_str,
"add disk to domain with PATH being source and FORMAT its format", "PATH[,FORMAT]"},
+ {"floppy", 'F', 0, G_OPTION_ARG_CALLBACK, add_floppy_str,
+ "add floppy to domain with PATH being source and FORMAT its format", "PATH[,FORMAT]"},
{"interface", 'i', 0, G_OPTION_ARG_CALLBACK, add_iface_str,
"add interface with NETWORK source. Possible ARGs: mac, link={up,down}", "NETWORK[,ARG=VAL]"},
{"resources", 'r', 0, G_OPTION_ARG_STRING, &resources_str,
@@ -543,7 +616,7 @@ main(int argc, char *argv[])
if (!os)
os = find_os_by_short_id(os_str);
} else {
- os = guess_os_from_disk(disk_str_list);
+ os = guess_os_from_cdrom(cdrom_str_list);
}
if (!os) {
@@ -593,8 +666,12 @@ main(int argc, char *argv[])
NULL);
}
+ g_list_foreach(cdrom_str_list, add_cdrom, domain);
+
g_list_foreach(disk_str_list, add_disk, domain);
+ g_list_foreach(floppy_str_list, add_floppy, domain);
+
g_list_foreach(iface_str_list, add_iface, domain);
config = gvir_designer_domain_get_config(domain);
@@ -683,6 +760,11 @@ is and ID which can be obtained via I<--list-platform>.
Set domain's architecture
+=item -C PATH[,FORMAT] --cdrom=PATH[,FORMAT]
+
+Add I<PATH> as a CDROM to the domain. To specify its format (e.g. raw,
+qcow2, phy) use I<FORMAT>.
+
=item -d PATH[,FORMAT] --disk=PATH[,FORMAT]
Add I<PATH> as a disk to the domain. To specify its format (e.g. raw,
@@ -712,12 +794,12 @@ platform. Usually, the platform is guessed from the connection URI.
Domain with Fedora 17 from locally stored ISO and one NIC with mac
00:11:22:33:44:55 and link set down:
- # virtxml -d Fedora-17-x86_64-Live-KDE.iso \
+ # virtxml -C Fedora-17-x86_64-Live-KDE.iso \
-i default,mac=00:11:22:33:44:55,link=down
To add multiple devices just use appropriate argument multiple times:
- # virtxml -d /tmp/Fedora-17-x86_64-Live-KDE.iso,raw \
+ # virtxml -d /tmp/home.img,qcow2 \
-d /var/lib/libvirt/images/f17.img,qcow2 \
-i default,mac=00:11:22:33:44:55,link=down \
-i blue_network \
diff --git a/libvirt-designer/libvirt-designer-domain.c b/libvirt-designer/libvirt-designer-domain.c
index 0d47d3c..2226d39 100644
--- a/libvirt-designer/libvirt-designer-domain.c
+++ b/libvirt-designer/libvirt-designer-domain.c
@@ -841,6 +841,7 @@ gvir_designer_domain_next_disk_target(GVirDesignerDomain *design,
static GVirConfigDomainDisk *
gvir_designer_domain_add_disk_full(GVirDesignerDomain *design,
GVirConfigDomainDiskType type,
+ GVirConfigDomainDiskGuestDeviceType guest_type,
const char *path,
const char *format,
gchar *target,
@@ -960,6 +961,7 @@ GVirConfigDomainDisk *gvir_designer_domain_add_disk_file(GVirDesignerDomain *des
ret = gvir_designer_domain_add_disk_full(design,
GVIR_CONFIG_DOMAIN_DISK_FILE,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_DISK,
filepath,
format,
NULL,
@@ -989,6 +991,7 @@ GVirConfigDomainDisk *gvir_designer_domain_add_disk_device(GVirDesignerDomain *d
ret = gvir_designer_domain_add_disk_full(design,
GVIR_CONFIG_DOMAIN_DISK_BLOCK,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_DISK,
devpath,
"raw",
NULL,
@@ -996,6 +999,130 @@ GVirConfigDomainDisk *gvir_designer_domain_add_disk_device(GVirDesignerDomain *d
return ret;
}
+/**
+ * gvir_designer_domain_add_cdrom_file:
+ * @design: (transfer none): the domain designer instance
+ * @filepath: (transfer none): the path to a file
+ * @format: (transfer none): file format
+ * @error: return location for a #GError, or NULL
+ *
+ * Add a new disk to the domain.
+ *
+ * Returns: (transfer full): the pointer to new cdrom.
+ * If something fails NULL is returned and @error is set.
+ */
+GVirConfigDomainDisk *gvir_designer_domain_add_cdrom_file(GVirDesignerDomain *design,
+ const char *filepath,
+ const char *format,
+ GError **error)
+{
+ g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL);
+
+ GVirConfigDomainDisk *ret = NULL;
+
+ ret = gvir_designer_domain_add_disk_full(design,
+ GVIR_CONFIG_DOMAIN_DISK_FILE,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_CDROM,
+ filepath,
+ format,
+ NULL,
+ error);
+ return ret;
+}
+
+
+/**
+ * gvir_designer_domain_add_cdrom_device:
+ * @design: (transfer none): the domain designer instance
+ * @devpath: (transfer none): path to the device
+ * @error: return location for a #GError, or NULL
+ *
+ * Add given device as a new cdrom to the domain designer instance.
+ *
+ * Returns: (transfer full): the pointer to the new cdrom.
+ * If something fails NULL is returned and @error is set.
+ */
+GVirConfigDomainDisk *gvir_designer_domain_add_cdrom_device(GVirDesignerDomain *design,
+ const char *devpath,
+ GError **error)
+{
+ g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL);
+
+ GVirConfigDomainDisk *ret = NULL;
+
+ ret = gvir_designer_domain_add_disk_full(design,
+ GVIR_CONFIG_DOMAIN_DISK_BLOCK,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_CDROM,
+ devpath,
+ "raw",
+ NULL,
+ error);
+ return ret;
+}
+
+
+/**
+ * gvir_designer_domain_add_floppy_file:
+ * @design: (transfer none): the domain designer instance
+ * @filepath: (transfer none): the path to a file
+ * @format: (transfer none): file format
+ * @error: return location for a #GError, or NULL
+ *
+ * Add a new disk to the domain.
+ *
+ * Returns: (transfer full): the pointer to new floppy.
+ * If something fails NULL is returned and @error is set.
+ */
+GVirConfigDomainDisk *gvir_designer_domain_add_floppy_file(GVirDesignerDomain *design,
+ const char *filepath,
+ const char *format,
+ GError **error)
+{
+ g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL);
+
+ GVirConfigDomainDisk *ret = NULL;
+
+ ret = gvir_designer_domain_add_disk_full(design,
+ GVIR_CONFIG_DOMAIN_DISK_FILE,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_FLOPPY,
+ filepath,
+ format,
+ NULL,
+ error);
+ return ret;
+}
+
+
+/**
+ * gvir_designer_domain_add_floppy_device:
+ * @design: (transfer none): the domain designer instance
+ * @devpath: (transfer none): path to the device
+ * @error: return location for a #GError, or NULL
+ *
+ * Add given device as a new floppy to the domain designer instance.
+ *
+ * Returns: (transfer full): the pointer to the new floppy.
+ * If something fails NULL is returned and @error is set.
+ */
+GVirConfigDomainDisk *gvir_designer_domain_add_floppy_device(GVirDesignerDomain *design,
+ const char *devpath,
+ GError **error)
+{
+ g_return_val_if_fail(GVIR_DESIGNER_IS_DOMAIN(design), NULL);
+
+ GVirConfigDomainDisk *ret = NULL;
+
+ ret = gvir_designer_domain_add_disk_full(design,
+ GVIR_CONFIG_DOMAIN_DISK_BLOCK,
+ GVIR_CONFIG_DOMAIN_DISK_GUEST_DEVICE_FLOPPY,
+ devpath,
+ "raw",
+ NULL,
+ error);
+ return ret;
+}
+
+
static const gchar *
gvir_designer_domain_get_preferred_nic_model(GVirDesignerDomain *design,
diff --git a/libvirt-designer/libvirt-designer-domain.h b/libvirt-designer/libvirt-designer-domain.h
index 4d68ff6..99c280b 100644
--- a/libvirt-designer/libvirt-designer-domain.h
+++ b/libvirt-designer/libvirt-designer-domain.h
@@ -99,6 +99,13 @@ gboolean gvir_designer_domain_setup_container_full(GVirDesignerDomain *design,
const char *arch,
GError **error);
+GVirConfigDomainDisk *gvir_designer_domain_add_cdrom_file(GVirDesignerDomain *design,
+ const char *filepath,
+ const char *format,
+ GError **error);
+GVirConfigDomainDisk *gvir_designer_domain_add_cdrom_device(GVirDesignerDomain *design,
+ const char *devpath,
+ GError **error);
GVirConfigDomainDisk *gvir_designer_domain_add_disk_file(GVirDesignerDomain *design,
const char *filepath,
const char *format,
@@ -106,6 +113,13 @@ GVirConfigDomainDisk *gvir_designer_domain_add_disk_file(GVirDesignerDomain *des
GVirConfigDomainDisk *gvir_designer_domain_add_disk_device(GVirDesignerDomain *design,
const char *devpath,
GError **error);
+GVirConfigDomainDisk *gvir_designer_domain_add_floppy_file(GVirDesignerDomain *design,
+ const char *filepath,
+ const char *format,
+ GError **error);
+GVirConfigDomainDisk *gvir_designer_domain_add_floppy_device(GVirDesignerDomain *design,
+ const char *devpath,
+ GError **error);
GVirConfigDomainInterface *gvir_designer_domain_add_interface_network(GVirDesignerDomain *design,
const char *network,
diff --git a/libvirt-designer/libvirt-designer.sym b/libvirt-designer/libvirt-designer.sym
index 79db09f..7a24f2c 100644
--- a/libvirt-designer/libvirt-designer.sym
+++ b/libvirt-designer/libvirt-designer.sym
@@ -10,8 +10,12 @@ LIBVIRT_DESIGNER_0.0.1 {
gvir_designer_domain_get_platform;
gvir_designer_domain_get_capabilities;
+ gvir_designer_domain_add_cdrom_file;
+ gvir_designer_domain_add_cdrom_device;
gvir_designer_domain_add_disk_file;
gvir_designer_domain_add_disk_device;
+ gvir_designer_domain_add_floppy_file;
+ gvir_designer_domain_add_floppy_device;
gvir_designer_domain_add_interface_network;
gvir_designer_domain_setup_resources;
gvir_designer_domain_resources_get_type;
--
1.8.1.4
11 years, 7 months
Re: [libvirt] [PATCH 2/3][ocaml] Add event callback implementation based on virConnectDomainEventRegisterAny
by David Scott
Hi,
I just spotted a flaw in my OCaml event callback patch. I was hoping to
ensure the ocaml bindings build against libvirt 0.9.1 and later. For
functions, I remembered to include the usual symbol detection magic.
However I forgot that there are also some enums which were added later than
0.9.1 i.e. all of these:
On Wed, Apr 17, 2013 at 11:16 AM, David Scott <scott.dj(a)gmail.com> wrote:
[snip]
> + case VIR_DOMAIN_EVENT_ID_IO_ERROR_REASON:
>
+ cb = VIR_DOMAIN_EVENT_CALLBACK(s_s_i_s_callback);
> + break;
> + case VIR_DOMAIN_EVENT_ID_CONTROL_ERROR:
> + cb = VIR_DOMAIN_EVENT_CALLBACK(u_callback);
> + break;
> + case VIR_DOMAIN_EVENT_ID_BLOCK_JOB:
> + cb = VIR_DOMAIN_EVENT_CALLBACK(s_i_i_callback);
> + break;
> + case VIR_DOMAIN_EVENT_ID_DISK_CHANGE:
> + cb = VIR_DOMAIN_EVENT_CALLBACK(s_s_s_i_callback);
> + break;
> + case VIR_DOMAIN_EVENT_ID_TRAY_CHANGE:
> + cb = VIR_DOMAIN_EVENT_CALLBACK(s_i_callback);
> + break;
> + case VIR_DOMAIN_EVENT_ID_PMWAKEUP:
> + cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
> + break;
> + case VIR_DOMAIN_EVENT_ID_PMSUSPEND:
> + cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
> + break;
> + case VIR_DOMAIN_EVENT_ID_BALLOON_CHANGE:
> + cb = VIR_DOMAIN_EVENT_CALLBACK(i64_callback);
> + break;
> + case VIR_DOMAIN_EVENT_ID_PMSUSPEND_DISK:
> + cb = VIR_DOMAIN_EVENT_CALLBACK(i_callback);
> + break;
>
These currently cause the build to break against older libvirts.
I'll rework this and resubmit once I've verified it definitely does work
against an older version.
Sorry for the noise!
Cheers,
Dave
11 years, 7 months
[libvirt] [PATCH] Change default resource partition to /machine
by Daniel P. Berrange
From: "Daniel P. Berrange" <berrange(a)redhat.com>
After discussions with systemd developers it was decided that
a better default policy for resource partitions is to have
3 default partitions at the top level
/system - system services
/machine - virtual machines / containers
/user - user login session
This ensures that the default policy isolates guest from
user login sessions & system services, so a mis-behaving
guest can't consume 100% of CPU usage if other things are
contending for it.
Thus we change the default partition from /system to
/machine
Signed-off-by: Daniel P. Berrange <berrange(a)redhat.com>
---
src/lxc/lxc_cgroup.c | 2 +-
src/qemu/qemu_cgroup.c | 2 +-
2 files changed, 2 insertions(+), 2 deletions(-)
diff --git a/src/lxc/lxc_cgroup.c b/src/lxc/lxc_cgroup.c
index 0a43b61..7311489 100644
--- a/src/lxc/lxc_cgroup.c
+++ b/src/lxc/lxc_cgroup.c
@@ -537,7 +537,7 @@ virCgroupPtr virLXCCgroupCreate(virDomainDefPtr def, bool startup)
goto cleanup;
}
- if (!(res->partition = strdup("/system"))) {
+ if (!(res->partition = strdup("/machine"))) {
virReportOOMError();
VIR_FREE(res);
goto cleanup;
diff --git a/src/qemu/qemu_cgroup.c b/src/qemu/qemu_cgroup.c
index 9a7bffb..3a58f24 100644
--- a/src/qemu/qemu_cgroup.c
+++ b/src/qemu/qemu_cgroup.c
@@ -236,7 +236,7 @@ int qemuInitCgroup(virQEMUDriverPtr driver,
goto cleanup;
}
- if (!(res->partition = strdup("/system"))) {
+ if (!(res->partition = strdup("/machine"))) {
virReportOOMError();
VIR_FREE(res);
goto cleanup;
--
1.7.11.7
11 years, 7 months