[libvirt] [PATCH v2 1/2] json: add stream parser
by Dmitry Guryanov
Add function virJSONValueFromStream, which reads data from
a stream and passes it to json parser. When end of the object
is reached, it returns this object.
To avoid reading from the stream by single bytes it reads to
a buffer (in a structure virJSONStreamParserState), which should
be passed to a consequent call of this function. So if the end
of one object and the beginning of the next object have been
read by a single system call - virJSONValueFromStream handle
it correctly.
example of usage:
virJSONValuePtr v;
virJSONStreamParserState state;
memset(&state, 0, sizeof(state));
while (1) {
v = virJSONValueFromStream(mon->fd, &state);
if (v == (void *)-1)
/* error */
break;
if (v == NULL)
/* file descriptor has been closed */
break;
/* handle object 'v' */
}
I need such function for the parallels driver. It caches info
about domains and needs some mechanism to update this cache.
There is a "prlsrvctl monitor" command which waits for events
forever and prints info about events to stdout in json format.
So parallels driver could start separate thread which will
read from prlsrvctl's stdout and update cache accordingly.
There is the same task in qemu_monitor_json, but each json object
is printed in a separate line there. It's not possible in my case,
because some fields could have line endings.
Signed-off-by: Dmitry Guryanov <dguryanov(a)parallels.com>
---
Changes:
* add function to virJSONValueFromStream
* fix bug with returning object which ends just
before end of file
* fix bug with handling objects without any characters
between then, when each read returns data for one entire
object.
src/libvirt_private.syms | 1 +
src/util/virjson.c | 110 ++++++++++++++++++++++++++++++++++++++++++++++
src/util/virjson.h | 8 +++
3 files changed, 119 insertions(+), 0 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 5cad990..567055c 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1320,6 +1320,7 @@ virJSONValueArrayGet;
virJSONValueArraySize;
virJSONValueFree;
virJSONValueFromString;
+virJSONValueFromStream;
virJSONValueGetBoolean;
virJSONValueGetNumberDouble;
virJSONValueGetNumberInt;
diff --git a/src/util/virjson.c b/src/util/virjson.c
index e6a3b1b..731293f 100644
--- a/src/util/virjson.c
+++ b/src/util/virjson.c
@@ -990,6 +990,116 @@ cleanup:
return ret;
}
+/*
+ * Read single JSON object from the stream. Store data, which
+ * have already been read from the stream, but belongs to the
+ * next object to the virJSONStreamParserState structure. So that
+ * consequent call to this function will parse it and return that
+ * object.
+ *
+ * @fd: file descriptor, opened for reading
+ * @state: pointer to the structure with buffer for data, read from fd.
+ *
+ * Return (void *)-1 in case of error, NULL when eof reached,
+ * pointer to the virJSONValuePtr in case of success.
+ */
+
+virJSONValuePtr virJSONValueFromStream(int fd, virJSONStreamParserStatePtr state)
+{
+ yajl_handle hand;
+ virJSONParser parser = { NULL, NULL, 0 };
+ virJSONValuePtr value = (void *)-1;
+# ifndef WITH_YAJL2
+ yajl_parser_config cfg = { 1, 1 };
+# endif
+ ssize_t len;
+ int ret = 0;
+ bool done = false;
+
+# ifdef WITH_YAJL2
+ hand = yajl_alloc(&parserCallbacks, NULL, &parser);
+ if (hand) {
+ yajl_config(hand, yajl_allow_comments, 1);
+ yajl_config(hand, yajl_dont_validate_strings, 0);
+ yajl_config(hand, yajl_allow_trailing_garbage, 1);
+ }
+# else
+ hand = yajl_alloc(&parserCallbacks, &cfg, NULL, &parser);
+# endif
+ if (!hand) {
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ _("Unable to create JSON parser"));
+ goto cleanup;
+ }
+
+ do {
+ if (strlen(&state->buf[state->pos]) == 0) {
+ state->pos = 0;
+ memset(state->buf, 0, sizeof(state->buf));
+ len = read(fd, state->buf, sizeof(state->buf) - 1);
+
+ if (len < 0) {
+ virReportSystemError(errno, _("cannot read from fd '%d'"), fd);
+ virJSONValueFree(parser.head);
+ goto cleanup;
+ }
+
+ if (len == 0) {
+ value = parser.head;
+ goto cleanup;
+ }
+ }
+
+ for (;state->pos < strlen(state->buf); state->pos++) {
+ unsigned char *buf = (unsigned char *)&state->buf[state->pos];
+ /*
+ * New yaml library has useful function yajl_get_bytes_consumed
+ * which allows parsing by larger chunks. But rhel-6 has 1.0.7
+ * version, which doesn't have it.
+ */
+ ret = yajl_parse(hand, buf, 1);
+# ifdef WITH_YAJL2
+ if (ret == 0 && yajl_get_bytes_consumed(hand) == 0) {
+ done = true;
+ /* state->pos points to the first symbol after current
+ * object */
+ break;
+ } else if (ret != 0) {
+# else
+ if (ret == 0) {
+ done = true;
+ /* state->pos points to the last symbol of the
+ * current object */
+ state->pos++;
+ break;
+ } else if (ret != yajl_status_insufficient_data) {
+# endif
+ unsigned char *errstr = yajl_get_error(hand, 1, buf, 1);
+ virReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse json: %s"),
+ (const char*) errstr);
+ VIR_FREE(errstr);
+ virJSONValueFree(parser.head);
+ goto cleanup;
+ }
+ }
+ } while (!done);
+
+ value = parser.head;
+
+cleanup:
+ yajl_free(hand);
+
+ if (parser.nstate) {
+ int i;
+ for (i = 0 ; i < parser.nstate ; i++) {
+ VIR_FREE(parser.state[i].key);
+ }
+ }
+
+ VIR_DEBUG("result=%p", parser.head);
+ return value;
+}
static int virJSONValueToStringOne(virJSONValuePtr object,
yajl_gen g)
diff --git a/src/util/virjson.h b/src/util/virjson.h
index 67f4398..aeb25ef 100644
--- a/src/util/virjson.h
+++ b/src/util/virjson.h
@@ -48,6 +48,8 @@ typedef virJSONObjectPair *virJSONObjectPairPtr;
typedef struct _virJSONArray virJSONArray;
typedef virJSONArray *virJSONArrayPtr;
+typedef struct _virJSONStreamParserState virJSONStreamParserState;
+typedef virJSONStreamParserState *virJSONStreamParserStatePtr;
struct _virJSONObjectPair {
char *key;
@@ -77,6 +79,11 @@ struct _virJSONValue {
} data;
};
+struct _virJSONStreamParserState {
+ char buf[1024];
+ size_t pos;
+};
+
void virJSONValueFree(virJSONValuePtr value);
virJSONValuePtr virJSONValueNewString(const char *data);
@@ -134,5 +141,6 @@ int virJSONValueObjectAppendNull(virJSONValuePtr object, const char *key);
virJSONValuePtr virJSONValueFromString(const char *jsonstring);
char *virJSONValueToString(virJSONValuePtr object,
bool pretty);
+virJSONValuePtr virJSONValueFromStream(int fd, virJSONStreamParserStatePtr state);
#endif /* __VIR_JSON_H_ */
--
1.7.1
11 years, 9 months
[libvirt] [PATCH] Fix a copy&paste error for virsh dump help
by Yanbing Du
Signed-off-by: Yanbing Du <ydu(a)redhat.com>
---
tools/virsh-domain.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/tools/virsh-domain.c b/tools/virsh-domain.c
index ab90f58..aa45e72 100644
--- a/tools/virsh-domain.c
+++ b/tools/virsh-domain.c
@@ -4358,7 +4358,7 @@ static const vshCmdOptDef opts_dump[] = {
{.name = "bypass-cache",
.type = VSH_OT_BOOL,
.flags = 0,
- .help = N_("avoid file system cache when saving")
+ .help = N_("avoid file system cache when dumping")
},
{.name = "reset",
.type = VSH_OT_BOOL,
--
1.7.1
11 years, 9 months
[libvirt] [libvirt-sandbox][PATCH] Avoid segfault if broadcast address is NULL
by Alex Jia
It seems the broadcast address parameter is not optional now, if users haven't
specified the broadcast address to the network interface then a segfault will
be raised.
This patch is just a temporary solution to avoid segfault, and with the patch,
users will get a expected error "Unable to parse networks: Unable to parse
broadcast address (null)", of course, a better patch should automatically
generate a broadcast address according to actual ip address. But AFAIK,
the IPv6 hasn't defined broadcast address, so it needs to do address protocol
judgement firstly, I will try to implement it later.
* How to reproduce?
# virt-sandbox -c lxc:/// --network address=192.168.122.1 /bin/sh
or
# virt-sandbox -c lxc:/// --network address=192.168.122.1/24 /bin/sh
Signed-off-by: Alex Jia <ajia(a)redhat.com>
---
libvirt-sandbox/libvirt-sandbox-config.c | 8 ++++++++
1 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/libvirt-sandbox/libvirt-sandbox-config.c b/libvirt-sandbox/libvirt-sandbox-config.c
index 3dc453a..f392f4b 100644
--- a/libvirt-sandbox/libvirt-sandbox-config.c
+++ b/libvirt-sandbox/libvirt-sandbox-config.c
@@ -873,6 +873,14 @@ gboolean gvir_sandbox_config_add_network_strv(GVirSandboxConfig *config,
goto cleanup;
}
+ if (!bcast) {
+ g_set_error(error, GVIR_SANDBOX_CONFIG_ERROR, 0,
+ "Unable to parse broadcast address %s", bcast);
+ g_free(primary);
+ goto cleanup;
+
+ }
+
if (!(bcastaddr = g_inet_address_new_from_string(bcast))) {
g_set_error(error, GVIR_SANDBOX_CONFIG_ERROR, 0,
"Unable to parse address %s", bcast);
--
1.7.1
11 years, 9 months
[libvirt] [PATCH v6 0/3] DEVICE_DELETED event
by Michael S. Tsirkin
libvirt has a long-standing bug: when removing the device,
it can request removal but does not know when the
removal completes. Add an event so we can fix this in a robust way.
First patch only adds the event with ID, second patch adds a path field.
Split this way for ease of backport (stable downstreams without QOM
would want to only take the first patch).
Event without fields is still useful as management can use it to
poll device list to figure out which device was removed.
Signed-off-by: Michael S. Tsirkin <mst(a)redhat.com>
Changes from v5:
- Emit an empty event on unnamed devices in patch 1/3, as suggested by Markus
Changes from v4:
- Add extra triggers and extra fields as requested by Markus
Changes from v3:
- Document that we only emit events for devices with
and ID, as suggested by Markus
Changes from v2:
- move event toward the end of device_unparent,
so that parents are reported after their children,
as suggested by Paolo
Changes from v1:
- move to device_unparent
- address comments by Andreas and Eric
--
Anthony Liguori
Michael S. Tsirkin (3):
qdev: DEVICE_DELETED event
qom: pass original path to unparent method
qmp: add path to device_deleted event
QMP/qmp-events.txt | 18 ++++++++++++++++++
hw/qdev.c | 15 +++++++++++++--
include/monitor/monitor.h | 1 +
include/qom/object.h | 3 ++-
monitor.c | 1 +
qapi-schema.json | 4 +++-
qom/object.c | 4 +++-
7 files changed, 41 insertions(+), 5 deletions(-)
--
MST
11 years, 9 months
[libvirt] [PATCH] util: fix clear_emulator_capabilities=0
by Laine Stump
My commit 7a2e845a865dc7fa82d2393ea2a770cfc8cf00b4 (and its
prerequisites) managed to effectively ignore the
clear_emulator_capabilities setting in qemu.conf (visible in the code
as the VIR_EXEC_CLEAR_CAPS flag when qemu is being exec'ed), with the
result that the capabilities are always cleared regardless of the
qemu.conf setting. This patch fixes it by passing the flag through to
virSetUIDGIDWithCaps(), which uses it to decide whether or not to
clear existing capabilities before adding in those that were
requested.
Note that the existing capabilities are *always* cleared if the new
process is going to run as non-root, since the whole point of running
non-root is to have the capabilities removed (it's still possible to
add back individual capabilities as needed though).
---
This will need to be backported to v1.0.3-maint.
src/util/vircommand.c | 4 +++-
src/util/virutil.c | 16 ++++++++++------
src/util/virutil.h | 3 ++-
3 files changed, 15 insertions(+), 8 deletions(-)
diff --git a/src/util/vircommand.c b/src/util/vircommand.c
index f672101..08d3d29 100644
--- a/src/util/vircommand.c
+++ b/src/util/vircommand.c
@@ -639,8 +639,10 @@ virExec(virCommandPtr cmd)
cmd->capabilities || (cmd->flags & VIR_EXEC_CLEAR_CAPS)) {
VIR_DEBUG("Setting child uid:gid to %d:%d with caps %llx",
(int)cmd->uid, (int)cmd->gid, cmd->capabilities);
- if (virSetUIDGIDWithCaps(cmd->uid, cmd->gid, cmd->capabilities) < 0)
+ if (virSetUIDGIDWithCaps(cmd->uid, cmd->gid, cmd->capabilities,
+ (cmd->flags & VIR_EXEC_CLEAR_CAPS)) < 0) {
goto fork_error;
+ }
}
if (cmd->pwd) {
diff --git a/src/util/virutil.c b/src/util/virutil.c
index 4605c78..634b7e3 100644
--- a/src/util/virutil.c
+++ b/src/util/virutil.c
@@ -2998,18 +2998,21 @@ virGetGroupName(gid_t gid ATTRIBUTE_UNUSED)
* errno).
*/
int
-virSetUIDGIDWithCaps(uid_t uid, gid_t gid, unsigned long long capBits)
+virSetUIDGIDWithCaps(uid_t uid, gid_t gid, unsigned long long capBits,
+ bool clearExistingCaps)
{
int ii, capng_ret, ret = -1;
bool need_setgid = false, need_setuid = false;
bool need_prctl = false, need_setpcap = false;
- /* First drop all caps except those in capBits + the extra ones we
- * need to change uid/gid and change the capabilities bounding
- * set.
+ /* First drop all caps (unless the requested uid is "unchanged" or
+ * root and clearExistingCaps wasn't requested), then add back
+ * those in capBits + the extra ones we need to change uid/gid and
+ * change the capabilities bounding set.
*/
- capng_clear(CAPNG_SELECT_BOTH);
+ if (clearExistingCaps || (uid != 1 && uid != 0))
+ capng_clear(CAPNG_SELECT_BOTH);
for (ii = 0; ii <= CAP_LAST_CAP; ii++) {
if (capBits & (1ULL << ii)) {
@@ -3095,7 +3098,8 @@ cleanup:
int
virSetUIDGIDWithCaps(uid_t uid, gid_t gid,
- unsigned long long capBits ATTRIBUTE_UNUSED)
+ unsigned long long capBits ATTRIBUTE_UNUSED,
+ bool clearExistingCaps ATTRIBUTE_UNUSED)
{
return virSetUIDGID(uid, gid);
}
diff --git a/src/util/virutil.h b/src/util/virutil.h
index 2dc3403..665ad78 100644
--- a/src/util/virutil.h
+++ b/src/util/virutil.h
@@ -54,7 +54,8 @@ int virPipeReadUntilEOF(int outfd, int errfd,
char **outbuf, char **errbuf);
int virSetUIDGID(uid_t uid, gid_t gid);
-int virSetUIDGIDWithCaps(uid_t uid, gid_t gid, unsigned long long capBits);
+int virSetUIDGIDWithCaps(uid_t uid, gid_t gid, unsigned long long capBits,
+ bool clearExistingCaps);
int virFileReadLimFD(int fd, int maxlen, char **buf) ATTRIBUTE_RETURN_CHECK;
--
1.8.1.4
11 years, 9 months
[libvirt] [PATCHv2 0/2] Enable virtio-scsi and virtio-rng for s390
by Viktor Mihajlovski
Early QEMU versions did not support virtio-scsi or virtio-rng
for s390 machines. This series enables libvirt to exploit the
capabilities provided by newer QEMUs.
V2 Changes:
- Dropped 1/3, the rename of virtio-scsi-pci capability,
we will keep it for compatibility reasons.
- Add a new generic virtio-scsi capability for non-pci busses
Viktor Mihajlovski (2):
S390: Enable virtio-scsi and virtio-rng
S390: Testcases for virtio-scsi and virtio-rng
src/qemu/qemu_capabilities.c | 7 ++++-
src/qemu/qemu_capabilities.h | 1 +
src/qemu/qemu_command.c | 32 ++++++++++++++++----
.../qemuxml2argv-disk-virtio-scsi-ccw.args | 9 ++++++
.../qemuxml2argv-disk-virtio-scsi-ccw.xml | 31 +++++++++++++++++++
.../qemuxml2argv-virtio-rng-ccw.args | 12 ++++++++
.../qemuxml2argv-virtio-rng-ccw.xml | 30 ++++++++++++++++++
tests/qemuxml2argvtest.c | 7 +++++
8 files changed, 122 insertions(+), 7 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-virtio-scsi-ccw.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-virtio-scsi-ccw.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-virtio-rng-ccw.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-virtio-rng-ccw.xml
--
1.7.9.5
11 years, 9 months
[libvirt] [PATCH] v1:Support for adding a static route to a bridge
by Gene Czarcinski
This patch adds support for adding a static route for
a network. The "via" 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.
Extensive tests are done to validate that the input
definitions are correct. For example, for a static
route ip definition, the address must be for a network
and not a host.
Signed-off-by: Gene Czarcinski <gene(a)czarc.net>
---
docs/formatnetwork.html.in | 32 ++++++-
docs/schemas/network.rng | 3 +
src/conf/network_conf.c | 104 ++++++++++++++++++++-
src/conf/network_conf.h | 2 +
src/libvirt_private.syms | 1 +
src/network/bridge_driver.c | 38 ++++++++
src/util/virnetdev.c | 47 ++++++++++
src/util/virnetdev.h | 5 +
.../networkxml2xmlin/dhcp6host-routed-network.xml | 4 +
.../networkxml2xmlout/dhcp6host-routed-network.xml | 4 +
10 files changed, 236 insertions(+), 4 deletions(-)
diff --git a/docs/formatnetwork.html.in b/docs/formatnetwork.html.in
index 4dd0415..f0cadf0 100644
--- a/docs/formatnetwork.html.in
+++ b/docs/formatnetwork.html.in
@@ -537,7 +537,9 @@
associated with the virtual network, and optionally enable DHCP
services. These elements are only valid for isolated networks
(no <code>forward</code> element specified), and for those with
- a forward mode of 'route' or 'nat'.
+ a forward mode of 'route' or 'nat'. Another optional addressing
+ element <code>via</code> can be used to establish a static
+ route for IPv4 or IPv6 networks.
</p>
<pre>
@@ -560,6 +562,7 @@
</dhcp>
</ip>
<ip family="ipv6" address="2001:db8:ca2:2::1" prefix="64" />
+ <ip family="ipv6" address="2001:db9:ca1:1::" prefix="64" via="2001:db8:ca2:2::2" />
</network></pre>
<dl>
@@ -633,7 +636,10 @@
IPv6, multiple addresses on a single network, <code>family</code>, and
<code>prefix</code> are support <span class="since">Since 0.8.7</span>.
Similar to IPv4, one IPv6 address per network can also have
- a <code>dhcp</code> definition. <span class="since">Since 1.0.1</span>
+ a <code>dhcp</code> definition. <span class="since">Since 1.0.1</span> The <code>via</code>
+ can be used to establish a static route for IPv4 or IPv6 networks. It is an error
+ to specify <code>via</code> and <code>dhcp</code> for the same IP address.
+ <span class="since">Since 1.0.4</span>
<dl>
<dt><code>tftp</code></dt>
@@ -809,6 +815,28 @@
</ip>
</network></pre>
+ <p>
+ Below is yet another IPv6 variation. This variation has only IPv6
+ defined with DHCPv6 on the primary IPv6 network. A second IPv6
+ network has a static link to a host on the first (virtual) IPv6
+ network. <span class="since">Since 1.0.4</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>
+ <ip family="ipv6" address="2001:db8:ca2:8::" prefix="64" via="2001:db8:ca2::4" >
+ </ip>
+ </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..c1cca23 100644
--- a/docs/schemas/network.rng
+++ b/docs/schemas/network.rng
@@ -262,6 +262,9 @@
<attribute name="family"><ref name="addr-family"/></attribute>
</optional>
<optional>
+ <attribute name="via"><ref name="ipAddr"/></attribute>
+ </optional>
+ <optional>
<element name="tftp">
<attribute name="root"><text/></attribute>
</element>
diff --git a/src/conf/network_conf.c b/src/conf/network_conf.c
index c022fe4..a5f7be2 100644
--- a/src/conf/network_conf.c
+++ b/src/conf/network_conf.c
@@ -1149,8 +1149,10 @@ virNetworkIPDefParseXML(const char *networkName,
xmlNodePtr cur, save;
char *address = NULL, *netmask = NULL;
- unsigned long prefix;
+ char *gateway = NULL;
+ unsigned long prefix = 0;
int result = -1;
+ virSocketAddr testAddr;
save = ctxt->node;
ctxt->node = node;
@@ -1162,6 +1164,7 @@ virNetworkIPDefParseXML(const char *networkName,
def->prefix = 0;
else
def->prefix = prefix;
+ gateway = virXPathString("string(./@via)", ctxt);
netmask = virXPathString("string(./@netmask)", ctxt);
@@ -1175,7 +1178,17 @@ virNetworkIPDefParseXML(const char *networkName,
}
- /* validate family vs. address */
+ if (gateway) {
+ if (virSocketAddrParse(&def->gateway, gateway, AF_UNSPEC) < 0) {
+ virReportError(VIR_ERR_XML_ERROR,
+ _("Bad gateway address '%s' in 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))) {
@@ -1184,6 +1197,14 @@ virNetworkIPDefParseXML(const char *networkName,
address, networkName);
goto cleanup;
}
+ if (gateway &&
+ (!(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 gateway address '%s' in network '%s'"),
+ 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,
@@ -1191,6 +1212,12 @@ virNetworkIPDefParseXML(const char *networkName,
address, networkName);
goto cleanup;
}
+ if (gateway && (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET))) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("family 'ipv4' specified for non-IPv4 gateway address '%s' in network '%s'"),
+ 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,
@@ -1198,6 +1225,24 @@ virNetworkIPDefParseXML(const char *networkName,
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'"),
@@ -1241,16 +1286,55 @@ virNetworkIPDefParseXML(const char *networkName,
}
}
+ /* if static route gateway specified, make sure the address is a network address */
+ if (gateway) {
+ 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;
+ }
+ }
+
cur = node->children;
while (cur != NULL) {
if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "dhcp")) {
+ if (gateway) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("<dhcp> element unsupported when static route (via) previously defined in network '%s'"),
+ networkName);
+ goto cleanup;
+ }
if (virNetworkDHCPDefParseXML(networkName, cur, def) < 0)
goto cleanup;
} else if (cur->type == XML_ELEMENT_NODE &&
xmlStrEqual(cur->name, BAD_CAST "tftp")) {
char *root;
+ if (gateway) {
+ virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
+ _("<tftp> element unsupported when static route (via) previously defined in network '%s'"),
+ networkName);
+ goto cleanup;
+ }
+
if (!VIR_SOCKET_ADDR_IS_FAMILY(&def->address, AF_INET)) {
virReportError(VIR_ERR_CONFIG_UNSUPPORTED,
_("Unsupported <tftp> element in an IPv6 element in network '%s'"),
@@ -1274,6 +1358,7 @@ cleanup:
}
VIR_FREE(address);
VIR_FREE(netmask);
+ VIR_FREE(gateway);
ctxt->node = save;
return result;
@@ -2108,6 +2193,7 @@ virNetworkIpDefFormat(virBufferPtr buf,
const virNetworkIpDefPtr def)
{
int result = -1;
+ bool routeFlg = false;
virBufferAddLit(buf, "<ip");
@@ -2131,15 +2217,29 @@ virNetworkIpDefFormat(virBufferPtr buf,
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;
+ routeFlg = true;
+ virBufferAsprintf(buf, " via='%s'", addr);
+ VIR_FREE(addr);
+ }
virBufferAddLit(buf, ">\n");
virBufferAdjustIndent(buf, 2);
if (def->tftproot) {
+ if (routeFlg) /* this should not occur */
+ goto error; /* but in case it does, better to error out */
virBufferEscapeString(buf, "<tftp root='%s' />\n",
def->tftproot);
}
if ((def->nranges || def->nhosts)) {
int ii;
+
+ if (routeFlg) /* this should not occur */
+ goto error; /* but in case it does, better to error out */
+
virBufferAddLit(buf, "<dhcp>\n");
virBufferAdjustIndent(buf, 2);
diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h
index 6ce9a00..91aff5f 100644
--- a/src/conf/network_conf.h
+++ b/src/conf/network_conf.h
@@ -115,6 +115,8 @@ struct _virNetworkIpDef {
char *family; /* ipv4 or ipv6 - default is ipv4 */
virSocketAddr address; /* Bridge IP address */
+ virSocketAddr gateway; /* gateway IP address for ip-route */
+
/* One or the other of the following two will be used for a given
* IP address, but never both. The parser guarantees this.
* Use virNetworkIpDefPrefix/virNetworkIpDefNetmask rather
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index ed46479..988b97a 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1470,6 +1470,7 @@ virNetDevReplaceMacAddress;
virNetDevReplaceNetConfig;
virNetDevRestoreMacAddress;
virNetDevRestoreNetConfig;
+virNetDevSetGateway;
virNetDevSetIPv4Address;
virNetDevSetMAC;
virNetDevSetMTU;
diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 31c8585..646a480 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 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,9 +2469,12 @@ networkStartNetworkVirtual(struct network_driver *driver,
if (networkAddIptablesRules(driver, network) < 0)
goto err1;
+ /* first, do all of the addresses */
for (ii = 0;
(ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
ii++) {
+ if (VIR_SOCKET_ADDR_VALID(&ipdef->gateway))
+ continue; /* this is a static route specification */
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET))
v4present = true;
if (VIR_SOCKET_ADDR_IS_FAMILY(&ipdef->address, AF_INET6))
@@ -2464,6 +2490,18 @@ networkStartNetworkVirtual(struct network_driver *driver,
if (virNetDevSetOnline(network->def->bridge, 1) < 0)
goto err2;
+ /* then do all of the static routes */
+ for (ii = 0;
+ (ipdef = virNetworkDefGetIpByIndex(network->def, AF_UNSPEC, ii));
+ ii++) {
+
+ /* Add the IP route to the bridge */
+ if (VIR_SOCKET_ADDR_VALID(&ipdef->gateway)) {
+ if (networkAddRouteToBridge(network, ipdef) < 0)
+ goto err2;
+ }
+ }
+
/* 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 296871c..c90b3d2 100644
--- a/src/util/virnetdev.c
+++ b/src/util/virnetdev.c
@@ -729,6 +729,7 @@ int virNetDevGetVLanID(const char *ifname ATTRIBUTE_UNUSED,
* Add an IP address to an interface. This function *does not* remove
* any previously added IP addresses - that must be done separately with
* brDelInetAddress.
+ * TODO: what is "brDelInetAddress"?
*
* Returns 0 in case of success or -1 in case of error.
*/
@@ -769,6 +770,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..dcad62d 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>
+ <ip address="192.168.222.0" netmask="255.255.255.0" via="192.168.122.10">
+ </ip>
+ <ip family="ipv6" address="2001:db8:ac10:fc00::" prefix="64" via="2001:db8:ac10:fd01::1:24">
+ </ip>
</network>
diff --git a/tests/networkxml2xmlout/dhcp6host-routed-network.xml b/tests/networkxml2xmlout/dhcp6host-routed-network.xml
index 7305043..880c2dd 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>
+ <ip address='192.168.222.0' netmask='255.255.255.0' via='192.168.122.10'>
+ </ip>
+ <ip family='ipv6' address='2001:db8:ac10:fc00::' prefix='64' via='2001:db8:ac10:fd01::1:24'>
+ </ip>
</network>
--
1.8.1.4
11 years, 9 months
[libvirt] when define NAT network, assign what kind of forward dev is better
by yue
hi all:
in my case, my physical machine has one ethernet, i want to use both bridge and nat network.
i create a bridge outbr0(addif eth0), when creating NAT network, there are 3 options for forward-dev
1.<forward mode="nat" />
2.<forward mode="nat" dev="outbr0"/>
3.<forward mode="nat" dev="eth0"/>
i do not know which one is the best?
thanks
11 years, 9 months
[libvirt] Adding and Clearing bridge addresses
by Gene Czarcinski
I have been working on this patch to have libvirt optionally set static
routes.
So I found the function that adds both IPv4 and IPv6 addresses to the
bridge in virnetdev.c. I found that besides the
virNetDevAddIPv4Address() there is also virNetDevCleanIPv4Address(). I
patterned my virNetDevAddGateway() after the virNetDevAddIPv4Address()
function.
What I am puzzled about is that it appears that nobody calls the Clear
function. What don't I understand?
It appears to me that the addresses and routes assigned to a bridge are
all removed when the network is destroyed but otherwise remain.
Gene
11 years, 9 months
[libvirt] [PATCH 0/3] Enable virtio-scsi and virtio-rng for s390
by Viktor Mihajlovski
Early QEMU versions did not support virtio-scsi or virtio-rng
for s390 machines. This series enables libvirt to exploit the
capabilities provided by newer QEMUs.
Viktor Mihajlovski (3):
qemu: rename virtio-scsi capability
S390: Enable virtio-scsi and virtio-rng
S390: Testcases for virtio-scsi and virtio-rng
src/qemu/qemu_capabilities.c | 8 +++--
src/qemu/qemu_capabilities.h | 2 +-
src/qemu/qemu_command.c | 31 ++++++++++++++++----
tests/qemuhelptest.c | 6 ++--
.../qemuxml2argv-disk-virtio-scsi-ccw.args | 9 ++++++
.../qemuxml2argv-disk-virtio-scsi-ccw.xml | 31 ++++++++++++++++++++
.../qemuxml2argv-virtio-rng-ccw.args | 12 ++++++++
.../qemuxml2argv-virtio-rng-ccw.xml | 30 +++++++++++++++++++
tests/qemuxml2argvtest.c | 19 ++++++++----
9 files changed, 130 insertions(+), 18 deletions(-)
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-virtio-scsi-ccw.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-disk-virtio-scsi-ccw.xml
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-virtio-rng-ccw.args
create mode 100644 tests/qemuxml2argvdata/qemuxml2argv-virtio-rng-ccw.xml
--
1.7.9.5
11 years, 9 months