[libvirt] [PATCH 0/8] parallels: add networking support

The goal of this patch series is to add initial support of networking to Parallels Cloud Server driver. Parallels driver will be able to show read-only list of virtual networks and manage network adapters of virtual machines (list, add, remove, change properties, switch to another virtual network). Dmitry Guryanov (8): parallels: parse information about network interfaces parallels: add support of network interfaces to parallelsDomainDefineXML parallels: move parallelsParseError to parallels_utils.h parallels: add network driver Use size_t for virNetworkIpDef structure parallels: parse virtual network properties parallels: add routed pseudo network parallels: handle network adapters of type 'routed' po/POTFILES.in | 2 + src/Makefile.am | 3 +- src/conf/network_conf.h | 4 +- src/parallels/parallels_driver.c | 314 ++++++++++++++++++- src/parallels/parallels_network.c | 639 +++++++++++++++++++++++++++++++++++++ src/parallels/parallels_utils.h | 9 + 6 files changed, 963 insertions(+), 8 deletions(-) create mode 100644 src/parallels/parallels_network.c -- 1.7.7.6

Parse network interfaces info from prlctl output. Parallels Cloud Server uses virtual networks model for network configuration: You can add network adapter to VM and connect it to some predefined virtual network. Fill type, mac, network name and linkstate fields of virDomainNetDef structure. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 111 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 111 insertions(+), 0 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 118dc13..755816e 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -50,6 +50,7 @@ #include "configmake.h" #include "storage_file.h" #include "nodeinfo.h" +#include "c-ctype.h" #include "parallels_driver.h" #include "parallels_utils.h" @@ -426,6 +427,113 @@ error: return -1; } +static inline unsigned char hex2int(char c) +{ + if (c <= '9') + return c - '0'; + else + return 10 + c - 'A'; +} + +/* + * Parse MAC address in format XXXXXXXXXXXX. + */ +static int +parallelsMacAddrParse(const char *str, virMacAddrPtr addr) +{ + int i; + + if (strlen(str) != 12) + goto error; + + for (i = 0; i < 6; i++) { + if (!c_isxdigit(str[2 * i]) || !c_isxdigit(str[2 * i + 1])) + goto error; + + addr->addr[i] = (hex2int(str[2 * i]) << 4) + hex2int(str[2 * i + 1]); + } + + return 0; +error: + virReportError(VIR_ERR_INVALID_ARG, + _("Invalid MAC address format '%s'"), str); + return -1; +} + +static int +parallelsGetNetInfo(virDomainNetDefPtr net, + const char *key, + virJSONValuePtr value) +{ + const char *tmp; + + /* use device name, shown by prlctl as target device + * for identifying network adapter in virDomainDefineXML */ + if (!(net->ifname = strdup(key))) { + virReportOOMError(); + goto error; + } + + net->type = VIR_DOMAIN_NET_TYPE_NETWORK; + + if (!(tmp = virJSONValueObjectGetString(value, "mac"))) { + parallelsParseError(); + return -1; + } + + if (parallelsMacAddrParse(tmp, &net->mac) < 0) { + parallelsParseError(); + goto error; + } + + if (!(tmp = virJSONValueObjectGetString(value, "network"))) { + parallelsParseError(); + goto error; + } + + if (!(net->data.network.name = strdup(tmp))) { + virReportOOMError(); + goto error; + } + + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + if (virJSONValueObjectHasKey(value, "state")) { + tmp = virJSONValueObjectGetString(value, "state"); + if STREQ(tmp, "disconnected") + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; + } + + return 0; + +error: + return -1; +} + +static int +parallelsAddNetInfo(virDomainDefPtr def, const char *key, virJSONValuePtr value) +{ + virDomainNetDefPtr net = NULL; + + if (VIR_ALLOC(net) < 0) + goto no_memory; + + if (parallelsGetNetInfo(net, key, value)) + goto error; + + if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) + goto no_memory; + + def->nets[def->nnets - 1] = net; + + return 0; + +no_memory: + virReportOOMError(); +error: + virDomainNetDefFree(net); + return -1; +} + static int parallelsAddDomainHardware(virDomainDefPtr def, virJSONValuePtr jobj) { @@ -457,6 +565,9 @@ parallelsAddDomainHardware(virDomainDefPtr def, virJSONValuePtr jobj) } else if (STRPREFIX(key, "hdd")) { if (parallelsAddHddInfo(def, key, value)) goto cleanup; + } else if (STRPREFIX(key, "net")) { + if (parallelsAddNetInfo(def, key, value)) + goto cleanup; } } -- 1.7.7.6

On Tue, Dec 11, 2012 at 02:59:42PM +0400, Dmitry Guryanov wrote:
Parse network interfaces info from prlctl output.
Parallels Cloud Server uses virtual networks model for network configuration: You can add network adapter to VM and connect it to some predefined virtual network.
Fill type, mac, network name and linkstate fields of virDomainNetDef structure.
Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 111 ++++++++++++++++++++++++++++++++++++++ 1 files changed, 111 insertions(+), 0 deletions(-)
diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 118dc13..755816e 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -50,6 +50,7 @@ #include "configmake.h" #include "storage_file.h" #include "nodeinfo.h" +#include "c-ctype.h"
#include "parallels_driver.h" #include "parallels_utils.h" @@ -426,6 +427,113 @@ error: return -1; }
+static inline unsigned char hex2int(char c) +{ + if (c <= '9') + return c - '0'; + else + return 10 + c - 'A'; +} + +/* + * Parse MAC address in format XXXXXXXXXXXX. + */ +static int +parallelsMacAddrParse(const char *str, virMacAddrPtr addr) +{ + int i; + + if (strlen(str) != 12) + goto error; + + for (i = 0; i < 6; i++) { + if (!c_isxdigit(str[2 * i]) || !c_isxdigit(str[2 * i + 1])) + goto error; + + addr->addr[i] = (hex2int(str[2 * i]) << 4) + hex2int(str[2 * i + 1]); + } + + return 0; +error: + virReportError(VIR_ERR_INVALID_ARG, + _("Invalid MAC address format '%s'"), str); + return -1; +} + +static int +parallelsGetNetInfo(virDomainNetDefPtr net, + const char *key, + virJSONValuePtr value) +{ + const char *tmp; + + /* use device name, shown by prlctl as target device + * for identifying network adapter in virDomainDefineXML */ + if (!(net->ifname = strdup(key))) { + virReportOOMError(); + goto error; + } + + net->type = VIR_DOMAIN_NET_TYPE_NETWORK; + + if (!(tmp = virJSONValueObjectGetString(value, "mac"))) { + parallelsParseError(); + return -1; + } + + if (parallelsMacAddrParse(tmp, &net->mac) < 0) { + parallelsParseError(); + goto error; + } + + if (!(tmp = virJSONValueObjectGetString(value, "network"))) { + parallelsParseError(); + goto error; + } + + if (!(net->data.network.name = strdup(tmp))) { + virReportOOMError(); + goto error; + } + + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP; + if (virJSONValueObjectHasKey(value, "state")) { + tmp = virJSONValueObjectGetString(value, "state"); + if STREQ(tmp, "disconnected") + net->linkstate = VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN; + } + + return 0; + +error: + return -1; +} + +static int +parallelsAddNetInfo(virDomainDefPtr def, const char *key, virJSONValuePtr value) +{ + virDomainNetDefPtr net = NULL; + + if (VIR_ALLOC(net) < 0) + goto no_memory; + + if (parallelsGetNetInfo(net, key, value)) + goto error; + + if (VIR_EXPAND_N(def->nets, def->nnets, 1) < 0) + goto no_memory; + + def->nets[def->nnets - 1] = net; + + return 0; + +no_memory: + virReportOOMError(); +error: + virDomainNetDefFree(net); + return -1; +} + static int parallelsAddDomainHardware(virDomainDefPtr def, virJSONValuePtr jobj) { @@ -457,6 +565,9 @@ parallelsAddDomainHardware(virDomainDefPtr def, virJSONValuePtr jobj) } else if (STRPREFIX(key, "hdd")) { if (parallelsAddHddInfo(def, key, value)) goto cleanup; + } else if (STRPREFIX(key, "net")) { + if (parallelsAddNetInfo(def, key, value)) + goto cleanup; } }
Looks fine, ACK, but I would double check for existing hex parsing we already have parsing of arbitrary number in a user specified base in utils/utils.h so it is likely the parsing code could be cleaned up or even better with some of the routine from src/util/virmacaddr.h but that cleanup can be deferred, Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

Allow changing network interfaces in domain configuration. ifname is used as iterface identifier: if there is interface with some ifname in old config and there are no interfaces with such name in the new config - issue prlctl command to delete the network interface. And vice versa - if interface with some ifname exists only in new config - issue prlctl command to create it. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 169 +++++++++++++++++++++++++++++++++++++- 1 files changed, 168 insertions(+), 1 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 755816e..f29b6ca 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -1776,6 +1776,170 @@ parallelsApplyDisksParams(virConnectPtr conn, parallelsDomObjPtr pdom, return 0; } +static int parallelsApplyIfaceParams(parallelsDomObjPtr pdom, + virDomainNetDefPtr oldnet, + virDomainNetDefPtr newnet) +{ + bool create = false; + bool is_changed = false; + virCommandPtr cmd; + char strmac[VIR_MAC_STRING_BUFLEN]; + int i; + + if (!oldnet) { + create = true; + if (VIR_ALLOC(oldnet) < 0) { + virReportOOMError(); + return -1; + } + } + + if (!create && oldnet->type != newnet->type) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing network type is not supported")); + return -1; + } + + if (!STREQ_NULLABLE(oldnet->model, newnet->model)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing network device model is not supported")); + return -1; + } + + if (!STREQ_NULLABLE(oldnet->data.network.portgroup, + newnet->data.network.portgroup)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing network portgroup is not supported")); + return -1; + } + + if (!virNetDevVPortProfileEqual(oldnet->virtPortProfile, + newnet->virtPortProfile)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing virtual port profile is not supported")); + return -1; + } + + if (newnet->tune.sndbuf_specified) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Setting send buffer size is not supported")); + return -1; + } + + if (!STREQ_NULLABLE(oldnet->script, newnet->script)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Setting startup script is not supported")); + return -1; + } + + if (!STREQ_NULLABLE(oldnet->filter, newnet->filter)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing filter params is not supported")); + return -1; + } + + if (newnet->bandwidth != NULL) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Setting bandwidth params is not supported")); + return -1; + } + + for (i = 0; i < sizeof(newnet->vlan); i++) { + if (((char *)&newnet->vlan)[i] != 0) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Setting vlan params is not supported")); + return -1; + } + } + + /* Here we know, that there are no differences, that are forbidden. + * Check is something changed, if no - do nothing */ + + if (create) { + cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid, + "--device-add", "net", NULL); + } else { + cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid, + "--device-set", newnet->ifname, NULL); + } + + if (virMacAddrCmp(&oldnet->mac, &newnet->mac)) { + virMacAddrFormat(&newnet->mac, strmac); + virCommandAddArgFormat(cmd, "--mac=%s", strmac); + is_changed = true; + } + + if (!STREQ_NULLABLE(oldnet->data.network.name, newnet->data.network.name)) { + virCommandAddArgFormat(cmd, "--network=%s", newnet->data.network.name); + is_changed = true; + } + + if (oldnet->linkstate != newnet->linkstate) { + if (newnet->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP) { + virCommandAddArgFormat(cmd, "--connect"); + } else if (newnet->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) { + virCommandAddArgFormat(cmd, "--disconnect"); + } + is_changed = true; + } + + if (!create && !is_changed) { + /* nothing changed - no need to run prlctl */ + return 0; + } + + if (virCommandRun(cmd, NULL)) + return -1; + + return 0; +} + +static int +parallelsApplyIfacesParams(parallelsDomObjPtr pdom, + virDomainNetDefPtr *oldnets, int nold, + virDomainNetDefPtr *newnets, int nnew) +{ + int i, j; + + for (i = 0; i < nold; i++) { + virDomainNetDefPtr newnet = NULL; + virDomainNetDefPtr oldnet = oldnets[i]; + for (j = 0; j < nnew; j++) { + if (STREQ_NULLABLE(newnets[j]->ifname, oldnet->ifname)) { + newnet = newnets[j]; + break; + } + } + + if (!newnet) { + if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, + "--device-del", oldnet->ifname, NULL) < 0) + return -1; + + continue; + } + + if (parallelsApplyIfaceParams(pdom, oldnet, newnet) < 0) + return -1; + } + + for (i = 0; i < nnew; i++) { + virDomainNetDefPtr newnet = newnets[i]; + bool found = false; + + for (j = 0; j < nold; j++) + if (STREQ_NULLABLE(oldnets[j]->ifname, newnet->ifname)) + found = true; + if (found) + continue; + + if (parallelsApplyIfaceParams(pdom, NULL, newnet)) + return -1; + } + + return 0; +} + static int parallelsApplyChanges(virConnectPtr conn, virDomainObjPtr dom, virDomainDefPtr new) { @@ -1975,7 +2139,7 @@ parallelsApplyChanges(virConnectPtr conn, virDomainObjPtr dom, virDomainDefPtr n new->graphics, new->ngraphics) < 0) return -1; - if (new->nfss != 0 || new->nnets != 0 || + if (new->nfss != 0 || new->nsounds != 0 || new->nhostdevs != 0 || new->nredirdevs != 0 || new->nsmartcards != 0 || new->nparallels || new->nchannels != 0 || @@ -2013,6 +2177,9 @@ parallelsApplyChanges(virConnectPtr conn, virDomainObjPtr dom, virDomainDefPtr n if (parallelsApplyDisksParams(conn, pdom, old->disks, old->ndisks, new->disks, new->ndisks) < 0) return -1; + if (parallelsApplyIfacesParams(pdom, old->nets, old->nnets, + new->nets, new->nnets) < 0) + return -1; return 0; } -- 1.7.7.6

On Tue, Dec 11, 2012 at 02:59:43PM +0400, Dmitry Guryanov wrote:
Allow changing network interfaces in domain configuration.
ifname is used as iterface identifier: if there is interface with some ifname in old config and there are no interfaces with such name in the new config - issue prlctl command to delete the network interface. And vice versa - if interface with some ifname exists only in new config - issue prlctl command to create it.
Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 169 +++++++++++++++++++++++++++++++++++++- 1 files changed, 168 insertions(+), 1 deletions(-)
diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 755816e..f29b6ca 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -1776,6 +1776,170 @@ parallelsApplyDisksParams(virConnectPtr conn, parallelsDomObjPtr pdom, return 0; }
+static int parallelsApplyIfaceParams(parallelsDomObjPtr pdom, + virDomainNetDefPtr oldnet, + virDomainNetDefPtr newnet) +{ + bool create = false; + bool is_changed = false; + virCommandPtr cmd; + char strmac[VIR_MAC_STRING_BUFLEN]; + int i; + + if (!oldnet) { + create = true; + if (VIR_ALLOC(oldnet) < 0) { + virReportOOMError(); + return -1; + } + } + + if (!create && oldnet->type != newnet->type) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing network type is not supported")); + return -1; + } + + if (!STREQ_NULLABLE(oldnet->model, newnet->model)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing network device model is not supported")); + return -1; + } + + if (!STREQ_NULLABLE(oldnet->data.network.portgroup, + newnet->data.network.portgroup)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing network portgroup is not supported")); + return -1; + } + + if (!virNetDevVPortProfileEqual(oldnet->virtPortProfile, + newnet->virtPortProfile)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing virtual port profile is not supported")); + return -1; + } + + if (newnet->tune.sndbuf_specified) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Setting send buffer size is not supported")); + return -1; + } + + if (!STREQ_NULLABLE(oldnet->script, newnet->script)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Setting startup script is not supported")); + return -1; + } + + if (!STREQ_NULLABLE(oldnet->filter, newnet->filter)) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Changing filter params is not supported")); + return -1; + } + + if (newnet->bandwidth != NULL) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Setting bandwidth params is not supported")); + return -1; + } + + for (i = 0; i < sizeof(newnet->vlan); i++) { + if (((char *)&newnet->vlan)[i] != 0) { + virReportError(VIR_ERR_ARGUMENT_UNSUPPORTED, "%s", + _("Setting vlan params is not supported")); + return -1; + } + } + + /* Here we know, that there are no differences, that are forbidden. + * Check is something changed, if no - do nothing */ + + if (create) { + cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid, + "--device-add", "net", NULL); + } else { + cmd = virCommandNewArgList(PRLCTL, "set", pdom->uuid, + "--device-set", newnet->ifname, NULL); + } + + if (virMacAddrCmp(&oldnet->mac, &newnet->mac)) { + virMacAddrFormat(&newnet->mac, strmac); + virCommandAddArgFormat(cmd, "--mac=%s", strmac); + is_changed = true; + } + + if (!STREQ_NULLABLE(oldnet->data.network.name, newnet->data.network.name)) { + virCommandAddArgFormat(cmd, "--network=%s", newnet->data.network.name); + is_changed = true; + } + + if (oldnet->linkstate != newnet->linkstate) { + if (newnet->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_UP) { + virCommandAddArgFormat(cmd, "--connect"); + } else if (newnet->linkstate == VIR_DOMAIN_NET_INTERFACE_LINK_STATE_DOWN) { + virCommandAddArgFormat(cmd, "--disconnect"); + } + is_changed = true; + } + + if (!create && !is_changed) { + /* nothing changed - no need to run prlctl */ + return 0; + } + + if (virCommandRun(cmd, NULL)) + return -1; + + return 0; +} + +static int +parallelsApplyIfacesParams(parallelsDomObjPtr pdom, + virDomainNetDefPtr *oldnets, int nold, + virDomainNetDefPtr *newnets, int nnew) +{ + int i, j; + + for (i = 0; i < nold; i++) { + virDomainNetDefPtr newnet = NULL; + virDomainNetDefPtr oldnet = oldnets[i];
let's move those declarations out of the loop
+ for (j = 0; j < nnew; j++) { + if (STREQ_NULLABLE(newnets[j]->ifname, oldnet->ifname)) { + newnet = newnets[j]; + break; + } + } + + if (!newnet) { + if (parallelsCmdRun(PRLCTL, "set", pdom->uuid, + "--device-del", oldnet->ifname, NULL) < 0) + return -1; + + continue; + } + + if (parallelsApplyIfaceParams(pdom, oldnet, newnet) < 0) + return -1; + } + + for (i = 0; i < nnew; i++) { + virDomainNetDefPtr newnet = newnets[i]; + bool found = false; +
same
+ for (j = 0; j < nold; j++) + if (STREQ_NULLABLE(oldnets[j]->ifname, newnet->ifname)) + found = true; + if (found) + continue; + + if (parallelsApplyIfaceParams(pdom, NULL, newnet)) + return -1; + } + + return 0; +} + static int parallelsApplyChanges(virConnectPtr conn, virDomainObjPtr dom, virDomainDefPtr new) { @@ -1975,7 +2139,7 @@ parallelsApplyChanges(virConnectPtr conn, virDomainObjPtr dom, virDomainDefPtr n new->graphics, new->ngraphics) < 0) return -1;
- if (new->nfss != 0 || new->nnets != 0 || + if (new->nfss != 0 || new->nsounds != 0 || new->nhostdevs != 0 || new->nredirdevs != 0 || new->nsmartcards != 0 || new->nparallels || new->nchannels != 0 || @@ -2013,6 +2177,9 @@ parallelsApplyChanges(virConnectPtr conn, virDomainObjPtr dom, virDomainDefPtr n if (parallelsApplyDisksParams(conn, pdom, old->disks, old->ndisks, new->disks, new->ndisks) < 0) return -1; + if (parallelsApplyIfacesParams(pdom, old->nets, old->nnets, + new->nets, new->nnets) < 0) + return -1;
return 0; }
ACK with associated fixup: diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index f16777a..60507e7 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -1924,10 +1924,13 @@ parallelsApplyIfacesParams(parallelsDomObjPtr pdom, virDomainNetDefPtr *newnets, int nnew) { int i, j; + virDomainNetDefPtr newnet; + virDomainNetDefPtr oldnet; + bool found; for (i = 0; i < nold; i++) { - virDomainNetDefPtr newnet = NULL; - virDomainNetDefPtr oldnet = oldnets[i]; + newnet = NULL; + oldnet = oldnets[i]; for (j = 0; j < nnew; j++) { if (STREQ_NULLABLE(newnets[j]->ifname, oldnet->ifname)) { newnet = newnets[j]; @@ -1948,8 +1951,8 @@ parallelsApplyIfacesParams(parallelsDomObjPtr pdom, } for (i = 0; i < nnew; i++) { - virDomainNetDefPtr newnet = newnets[i]; - bool found = false; + newnet = newnets[i]; + found = false; for (j = 0; j < nold; j++) if (STREQ_NULLABLE(oldnets[j]->ifname, newnet->ifname)) Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

This macro will be used in another file in the next patch, so move it to common header file. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- po/POTFILES.in | 1 + src/parallels/parallels_driver.c | 4 ---- src/parallels/parallels_utils.h | 4 ++++ 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/po/POTFILES.in b/po/POTFILES.in index 586aa2b..50cdc4e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -77,6 +77,7 @@ src/openvz/openvz_driver.c src/openvz/openvz_util.c src/parallels/parallels_driver.c src/parallels/parallels_utils.c +src/parallels/parallels_utils.h src/parallels/parallels_storage.c src/phyp/phyp_driver.c src/qemu/qemu_agent.c diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index f29b6ca..5d89503 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -69,10 +69,6 @@ _("no domain with matching uuid '%s'"), uuidstr); \ } while (0) -#define parallelsParseError() \ - virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ - __FUNCTION__, __LINE__, _("Can't parse prlctl output")) - #define IS_CT(def) (STREQ_NULLABLE(def->os.type, "exe")) static int parallelsClose(virConnectPtr conn); diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index e4b3f8b..8b0bdf6 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -30,6 +30,10 @@ # include "conf/domain_event.h" # include "json.h" +# define parallelsParseError() \ + virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ + __FUNCTION__, __LINE__, _("Can't parse prlctl output")) + struct _parallelsConn { virMutex lock; virDomainObjList domains; -- 1.7.7.6

On Tue, Dec 11, 2012 at 02:59:44PM +0400, Dmitry Guryanov wrote:
This macro will be used in another file in the next patch, so move it to common header file.
Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- po/POTFILES.in | 1 + src/parallels/parallels_driver.c | 4 ---- src/parallels/parallels_utils.h | 4 ++++ 3 files changed, 5 insertions(+), 4 deletions(-)
diff --git a/po/POTFILES.in b/po/POTFILES.in index 586aa2b..50cdc4e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -77,6 +77,7 @@ src/openvz/openvz_driver.c src/openvz/openvz_util.c src/parallels/parallels_driver.c src/parallels/parallels_utils.c +src/parallels/parallels_utils.h src/parallels/parallels_storage.c src/phyp/phyp_driver.c src/qemu/qemu_agent.c diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index f29b6ca..5d89503 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -69,10 +69,6 @@ _("no domain with matching uuid '%s'"), uuidstr); \ } while (0)
-#define parallelsParseError() \ - virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ - __FUNCTION__, __LINE__, _("Can't parse prlctl output")) - #define IS_CT(def) (STREQ_NULLABLE(def->os.type, "exe"))
static int parallelsClose(virConnectPtr conn); diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index e4b3f8b..8b0bdf6 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -30,6 +30,10 @@ # include "conf/domain_event.h" # include "json.h"
+# define parallelsParseError() \ + virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ + __FUNCTION__, __LINE__, _("Can't parse prlctl output")) + struct _parallelsConn { virMutex lock; virDomainObjList domains;
ACK, Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

Parallels Cloud Server uses virtual networks model for network configuration. It uses own tools for virtual network management. So add network driver, which will be responsible for listing virtual networks and performing different operations on them (in consequent patched). This patch only allows listing virtual network names, without any parameters like DHCP server settings. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/parallels/parallels_driver.c | 2 + src/parallels/parallels_network.c | 424 +++++++++++++++++++++++++++++++++++++ src/parallels/parallels_utils.h | 3 + 5 files changed, 432 insertions(+), 1 deletions(-) create mode 100644 src/parallels/parallels_network.c diff --git a/po/POTFILES.in b/po/POTFILES.in index 50cdc4e..4789a97 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -76,6 +76,7 @@ src/openvz/openvz_conf.c src/openvz/openvz_driver.c src/openvz/openvz_util.c src/parallels/parallels_driver.c +src/parallels/parallels_network.c src/parallels/parallels_utils.c src/parallels/parallels_utils.h src/parallels/parallels_storage.c diff --git a/src/Makefile.am b/src/Makefile.am index 1a2f94f..6d2816d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -557,7 +557,8 @@ PARALLELS_DRIVER_SOURCES = \ parallels/parallels_driver.c \ parallels/parallels_utils.c \ parallels/parallels_utils.h \ - parallels/parallels_storage.c + parallels/parallels_storage.c \ + parallels/parallels_network.c NETWORK_DRIVER_SOURCES = \ network/bridge_driver.h network/bridge_driver.c diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 5d89503..21279c0 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -2410,6 +2410,8 @@ parallelsRegister(void) return -1; if (parallelsStorageRegister()) return -1; + if (parallelsNetworkRegister()) + return -1; return 0; } diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c new file mode 100644 index 0000000..d30c94d --- /dev/null +++ b/src/parallels/parallels_network.c @@ -0,0 +1,424 @@ +/* + * parallels_storage.c: core privconn functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2012 Parallels, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include "datatypes.h" +#include "memory.h" +#include "virterror_internal.h" +#include "md5.h" + +#include "parallels_utils.h" + +#define VIR_FROM_THIS VIR_FROM_PARALLELS + +#define parallelsParseError() \ + virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ + __FUNCTION__, __LINE__, _("Can't parse prlctl output")) + +static virNetworkObjPtr +parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) +{ + virNetworkObjPtr net; + virNetworkDefPtr def; + const char *tmp; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + + if (VIR_ALLOC(def) < 0) + goto no_memory; + + if (!(tmp = virJSONValueObjectGetString(jobj, "Network ID"))) { + parallelsParseError(); + goto cleanup; + } + + if (!(def->name = strdup(tmp))) + goto no_memory; + + /* Network names are unique in Parallels Cloud Server, so we can make + * an UUID from it */ + md5_buffer(tmp, strlen(tmp), md5); + memcpy(def->uuid, md5, VIR_UUID_BUFLEN); + def->uuid_specified = 1; + + if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) { + virNetworkDefFree(def); + goto cleanup; + } + net->active = 1; + net->persistent = 1; + net->autostart = 1; + virNetworkObjUnlock(net); + return net; + +no_memory: + virReportOOMError(); +cleanup: + virNetworkDefFree(def); + return NULL; +} + +static int parallelsLoadNetworks(parallelsConnPtr privconn) +{ + virJSONValuePtr jobj, jobj2; + virNetworkObjPtr net; + int ret = -1; + int count, i; + + jobj = parallelsParseOutput("prlsrvctl", "net", "list", "-j", NULL); + + if (!jobj) { + parallelsParseError(); + goto cleanup; + } + + count = virJSONValueArraySize(jobj); + if (count < 0) { + parallelsParseError(); + goto cleanup; + } + + for (i = 0; i < count; i++) { + jobj2 = virJSONValueArrayGet(jobj, i); + if (!jobj2) { + parallelsParseError(); + goto cleanup; + } + + net = parallelsLoadNetwork(privconn, jobj2); + if (!net) + goto cleanup; + + } + + ret = 0; + +cleanup: + virJSONValueFree(jobj); + return ret; +} + +static virDrvOpenStatus +parallelsOpenNetwork(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); + + if (STRNEQ(conn->driver->name, "Parallels")) + return VIR_DRV_OPEN_DECLINED; + + conn->networkPrivateData = conn->privateData; + + if (parallelsLoadNetworks(conn->privateData) < 0) + return VIR_DRV_OPEN_DECLINED; + + return VIR_DRV_OPEN_SUCCESS; +} + +static int parallelsCloseNetwork(virConnectPtr conn) +{ + parallelsConnPtr privconn = conn->privateData; + parallelsDriverLock(privconn); + virNetworkObjListFree(&privconn->networks); + parallelsDriverUnlock(privconn); + return 0; +} + +static int parallelsNumNetworks(virConnectPtr conn) +{ + int nactive = 0, i; + parallelsConnPtr privconn = conn->privateData; + + parallelsDriverLock(privconn); + for (i = 0 ; i < privconn->networks.count ; i++) { + virNetworkObjLock(privconn->networks.objs[i]); + if (virNetworkObjIsActive(privconn->networks.objs[i])) + nactive++; + virNetworkObjUnlock(privconn->networks.objs[i]); + } + parallelsDriverUnlock(privconn); + + return nactive; +} + +static int parallelsListNetworks(virConnectPtr conn, + char **const names, + int nnames) +{ + parallelsConnPtr privconn = conn->privateData; + int got = 0, i; + + parallelsDriverLock(privconn); + for (i = 0 ; i < privconn->networks.count && got < nnames ; i++) { + virNetworkObjLock(privconn->networks.objs[i]); + if (virNetworkObjIsActive(privconn->networks.objs[i])) { + if (!(names[got] = strdup(privconn->networks.objs[i]->def->name))) { + virNetworkObjUnlock(privconn->networks.objs[i]); + virReportOOMError(); + goto cleanup; + } + got++; + } + virNetworkObjUnlock(privconn->networks.objs[i]); + } + parallelsDriverUnlock(privconn); + + return got; + + cleanup: + parallelsDriverUnlock(privconn); + for (i = 0 ; i < got ; i++) + VIR_FREE(names[i]); + return -1; +} + +static int parallelsNumDefinedNetworks(virConnectPtr conn) +{ + int ninactive = 0, i; + parallelsConnPtr privconn = conn->privateData; + + parallelsDriverLock(privconn); + for (i = 0 ; i < privconn->networks.count ; i++) { + virNetworkObjLock(privconn->networks.objs[i]); + if (!virNetworkObjIsActive(privconn->networks.objs[i])) + ninactive++; + virNetworkObjUnlock(privconn->networks.objs[i]); + } + parallelsDriverUnlock(privconn); + + return ninactive; +} + +static int parallelsListDefinedNetworks(virConnectPtr conn, + char **const names, + int nnames) +{ + parallelsConnPtr privconn = conn->privateData; + int got = 0, i; + + parallelsDriverLock(privconn); + for (i = 0 ; i < privconn->networks.count && got < nnames ; i++) { + virNetworkObjLock(privconn->networks.objs[i]); + if (!virNetworkObjIsActive(privconn->networks.objs[i])) { + if (!(names[got] = strdup(privconn->networks.objs[i]->def->name))) { + virNetworkObjUnlock(privconn->networks.objs[i]); + virReportOOMError(); + goto cleanup; + } + got++; + } + virNetworkObjUnlock(privconn->networks.objs[i]); + } + parallelsDriverUnlock(privconn); + return got; + + cleanup: + parallelsDriverUnlock(privconn); + for (i = 0 ; i < got ; i++) + VIR_FREE(names[i]); + return -1; +} + +static int parallelsListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + parallelsConnPtr privconn = conn->privateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); + + parallelsDriverLock(privconn); + ret = virNetworkList(conn, privconn->networks, nets, flags); + parallelsDriverUnlock(privconn); + + return ret; +} + +static virNetworkPtr parallelsNetworkLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + parallelsConnPtr privconn = conn->privateData; + virNetworkObjPtr network; + virNetworkPtr ret = NULL; + + parallelsDriverLock(privconn); + network = virNetworkFindByUUID(&privconn->networks, uuid); + parallelsDriverUnlock(privconn); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + ret = virGetNetwork(conn, network->def->name, network->def->uuid); + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} + +static virNetworkPtr parallelsNetworkLookupByName(virConnectPtr conn, + const char *name) +{ + parallelsConnPtr privconn = conn->privateData; + virNetworkObjPtr network; + virNetworkPtr ret = NULL; + + parallelsDriverLock(privconn); + network = virNetworkFindByName(&privconn->networks, name); + parallelsDriverUnlock(privconn); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + _("no network with matching name '%s'"), name); + goto cleanup; + } + + ret = virGetNetwork(conn, network->def->name, network->def->uuid); + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} + +static char *parallelsNetworkGetXMLDesc(virNetworkPtr net, + unsigned int flags) +{ + parallelsConnPtr privconn = net->conn->privateData; + virNetworkObjPtr network; + char *ret = NULL; + + virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL); + + parallelsDriverLock(privconn); + network = virNetworkFindByUUID(&privconn->networks, net->uuid); + parallelsDriverUnlock(privconn); + + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + ret = virNetworkDefFormat(network->def, flags); + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} + +static int parallelsNetworkIsActive(virNetworkPtr net) +{ + parallelsConnPtr privconn = net->conn->privateData; + virNetworkObjPtr obj; + int ret = -1; + + parallelsDriverLock(privconn); + obj = virNetworkFindByUUID(&privconn->networks, net->uuid); + parallelsDriverUnlock(privconn); + if (!obj) { + virReportError(VIR_ERR_NO_NETWORK, NULL); + goto cleanup; + } + ret = virNetworkObjIsActive(obj); + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return ret; +} + +static int parallelsNetworkIsPersistent(virNetworkPtr net) +{ + parallelsConnPtr privconn = net->conn->privateData; + virNetworkObjPtr obj; + int ret = -1; + + parallelsDriverLock(privconn); + obj = virNetworkFindByUUID(&privconn->networks, net->uuid); + parallelsDriverUnlock(privconn); + if (!obj) { + virReportError(VIR_ERR_NO_NETWORK, NULL); + goto cleanup; + } + ret = obj->persistent; + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return ret; +} + +static int parallelsNetworkGetAutostart(virNetworkPtr net, + int *autostart) +{ + parallelsConnPtr privconn = net->conn->privateData; + virNetworkObjPtr network; + int ret = -1; + + parallelsDriverLock(privconn); + network = virNetworkFindByUUID(&privconn->networks, net->uuid); + parallelsDriverUnlock(privconn); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + *autostart = network->autostart; + ret = 0; + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} +static virNetworkDriver parallelsNetworkDriver = { + "Parallels", + .open = parallelsOpenNetwork, /* 1.0.1 */ + .close = parallelsCloseNetwork, /* 1.0.1 */ + .numOfNetworks = parallelsNumNetworks, /* 1.0.1 */ + .listNetworks = parallelsListNetworks, /* 1.0.1 */ + .numOfDefinedNetworks = parallelsNumDefinedNetworks, /* 1.0.1 */ + .listDefinedNetworks = parallelsListDefinedNetworks, /* 1.0.1 */ + .listAllNetworks = parallelsListAllNetworks, /* 1.0.1 */ + .networkLookupByUUID = parallelsNetworkLookupByUUID, /* 1.0.1 */ + .networkLookupByName = parallelsNetworkLookupByName, /* 1.0.1 */ + .networkGetXMLDesc = parallelsNetworkGetXMLDesc, /* 1.0.1 */ + .networkGetAutostart = parallelsNetworkGetAutostart, /* 1.0.1 */ + .networkIsActive = parallelsNetworkIsActive, /* 1.0.1 */ + .networkIsPersistent = parallelsNetworkIsPersistent, /* 1.0.1 */ +}; + +int +parallelsNetworkRegister(void) +{ + if (virRegisterNetworkDriver(¶llelsNetworkDriver) < 0) + return -1; + + return 0; +} diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index 8b0bdf6..aca3ee2 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -28,6 +28,7 @@ # include "conf/domain_conf.h" # include "conf/storage_conf.h" # include "conf/domain_event.h" +# include "conf/network_conf.h" # include "json.h" # define parallelsParseError() \ @@ -38,6 +39,7 @@ struct _parallelsConn { virMutex lock; virDomainObjList domains; virStoragePoolObjList pools; + virNetworkObjList networks; virCapsPtr caps; virDomainEventStatePtr domainEventState; }; @@ -54,6 +56,7 @@ struct parallelsDomObj { typedef struct parallelsDomObj *parallelsDomObjPtr; int parallelsStorageRegister(void); +int parallelsNetworkRegister(void); virJSONValuePtr parallelsParseOutput(const char *binary, ...) ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL; -- 1.7.7.6

On Tue, Dec 11, 2012 at 02:59:45PM +0400, Dmitry Guryanov wrote:
Parallels Cloud Server uses virtual networks model for network configuration. It uses own tools for virtual network management. So add network driver, which will be responsible for listing virtual networks and performing different operations on them (in consequent patched).
This patch only allows listing virtual network names, without any parameters like DHCP server settings.
Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- po/POTFILES.in | 1 + src/Makefile.am | 3 +- src/parallels/parallels_driver.c | 2 + src/parallels/parallels_network.c | 424 +++++++++++++++++++++++++++++++++++++ src/parallels/parallels_utils.h | 3 + 5 files changed, 432 insertions(+), 1 deletions(-) create mode 100644 src/parallels/parallels_network.c
diff --git a/po/POTFILES.in b/po/POTFILES.in index 50cdc4e..4789a97 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -76,6 +76,7 @@ src/openvz/openvz_conf.c src/openvz/openvz_driver.c src/openvz/openvz_util.c src/parallels/parallels_driver.c +src/parallels/parallels_network.c src/parallels/parallels_utils.c src/parallels/parallels_utils.h src/parallels/parallels_storage.c diff --git a/src/Makefile.am b/src/Makefile.am index 1a2f94f..6d2816d 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -557,7 +557,8 @@ PARALLELS_DRIVER_SOURCES = \ parallels/parallels_driver.c \ parallels/parallels_utils.c \ parallels/parallels_utils.h \ - parallels/parallels_storage.c + parallels/parallels_storage.c \ + parallels/parallels_network.c
NETWORK_DRIVER_SOURCES = \ network/bridge_driver.h network/bridge_driver.c diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 5d89503..21279c0 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -2410,6 +2410,8 @@ parallelsRegister(void) return -1; if (parallelsStorageRegister()) return -1; + if (parallelsNetworkRegister()) + return -1;
return 0; } diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c new file mode 100644 index 0000000..d30c94d --- /dev/null +++ b/src/parallels/parallels_network.c @@ -0,0 +1,424 @@ +/* + * parallels_storage.c: core privconn functions for managing + * Parallels Cloud Server hosts + * + * Copyright (C) 2012 Parallels, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library. If not, see + * <http://www.gnu.org/licenses/>. + * + */ + +#include <config.h> + +#include "datatypes.h" +#include "memory.h" +#include "virterror_internal.h" +#include "md5.h" + +#include "parallels_utils.h" + +#define VIR_FROM_THIS VIR_FROM_PARALLELS + +#define parallelsParseError() \ + virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ + __FUNCTION__, __LINE__, _("Can't parse prlctl output")) + +static virNetworkObjPtr +parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) +{ + virNetworkObjPtr net; + virNetworkDefPtr def; + const char *tmp; + /* MD5_DIGEST_SIZE = VIR_UUID_BUFLEN = 16 */ + unsigned char md5[MD5_DIGEST_SIZE]; + + if (VIR_ALLOC(def) < 0) + goto no_memory; + + if (!(tmp = virJSONValueObjectGetString(jobj, "Network ID"))) { + parallelsParseError(); + goto cleanup; + } + + if (!(def->name = strdup(tmp))) + goto no_memory; + + /* Network names are unique in Parallels Cloud Server, so we can make + * an UUID from it */ + md5_buffer(tmp, strlen(tmp), md5); + memcpy(def->uuid, md5, VIR_UUID_BUFLEN); + def->uuid_specified = 1; + + if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) { + virNetworkDefFree(def); + goto cleanup; + } + net->active = 1; + net->persistent = 1; + net->autostart = 1; + virNetworkObjUnlock(net); + return net; + +no_memory: + virReportOOMError(); +cleanup: + virNetworkDefFree(def); + return NULL; +} + +static int parallelsLoadNetworks(parallelsConnPtr privconn) +{ + virJSONValuePtr jobj, jobj2; + virNetworkObjPtr net; + int ret = -1; + int count, i; + + jobj = parallelsParseOutput("prlsrvctl", "net", "list", "-j", NULL); + + if (!jobj) { + parallelsParseError(); + goto cleanup; + } + + count = virJSONValueArraySize(jobj); + if (count < 0) { + parallelsParseError(); + goto cleanup; + } + + for (i = 0; i < count; i++) { + jobj2 = virJSONValueArrayGet(jobj, i); + if (!jobj2) { + parallelsParseError(); + goto cleanup; + } + + net = parallelsLoadNetwork(privconn, jobj2); + if (!net) + goto cleanup; + + } + + ret = 0; + +cleanup: + virJSONValueFree(jobj); + return ret; +} + +static virDrvOpenStatus +parallelsOpenNetwork(virConnectPtr conn, + virConnectAuthPtr auth ATTRIBUTE_UNUSED, + unsigned int flags) +{ + virCheckFlags(VIR_CONNECT_RO, VIR_DRV_OPEN_ERROR); + + if (STRNEQ(conn->driver->name, "Parallels")) + return VIR_DRV_OPEN_DECLINED; + + conn->networkPrivateData = conn->privateData; + + if (parallelsLoadNetworks(conn->privateData) < 0) + return VIR_DRV_OPEN_DECLINED; + + return VIR_DRV_OPEN_SUCCESS; +} + +static int parallelsCloseNetwork(virConnectPtr conn) +{ + parallelsConnPtr privconn = conn->privateData; + parallelsDriverLock(privconn); + virNetworkObjListFree(&privconn->networks); + parallelsDriverUnlock(privconn); + return 0; +} + +static int parallelsNumNetworks(virConnectPtr conn) +{ + int nactive = 0, i; + parallelsConnPtr privconn = conn->privateData; + + parallelsDriverLock(privconn); + for (i = 0 ; i < privconn->networks.count ; i++) { + virNetworkObjLock(privconn->networks.objs[i]); + if (virNetworkObjIsActive(privconn->networks.objs[i])) + nactive++; + virNetworkObjUnlock(privconn->networks.objs[i]); + } + parallelsDriverUnlock(privconn); + + return nactive; +} + +static int parallelsListNetworks(virConnectPtr conn, + char **const names, + int nnames) +{ + parallelsConnPtr privconn = conn->privateData; + int got = 0, i; + + parallelsDriverLock(privconn); + for (i = 0 ; i < privconn->networks.count && got < nnames ; i++) { + virNetworkObjLock(privconn->networks.objs[i]); + if (virNetworkObjIsActive(privconn->networks.objs[i])) { + if (!(names[got] = strdup(privconn->networks.objs[i]->def->name))) { + virNetworkObjUnlock(privconn->networks.objs[i]); + virReportOOMError(); + goto cleanup; + } + got++; + } + virNetworkObjUnlock(privconn->networks.objs[i]); + } + parallelsDriverUnlock(privconn); + + return got; + + cleanup: + parallelsDriverUnlock(privconn); + for (i = 0 ; i < got ; i++) + VIR_FREE(names[i]); + return -1; +} + +static int parallelsNumDefinedNetworks(virConnectPtr conn) +{ + int ninactive = 0, i; + parallelsConnPtr privconn = conn->privateData; + + parallelsDriverLock(privconn); + for (i = 0 ; i < privconn->networks.count ; i++) { + virNetworkObjLock(privconn->networks.objs[i]); + if (!virNetworkObjIsActive(privconn->networks.objs[i])) + ninactive++; + virNetworkObjUnlock(privconn->networks.objs[i]); + } + parallelsDriverUnlock(privconn); + + return ninactive; +} + +static int parallelsListDefinedNetworks(virConnectPtr conn, + char **const names, + int nnames) +{ + parallelsConnPtr privconn = conn->privateData; + int got = 0, i; + + parallelsDriverLock(privconn); + for (i = 0 ; i < privconn->networks.count && got < nnames ; i++) { + virNetworkObjLock(privconn->networks.objs[i]); + if (!virNetworkObjIsActive(privconn->networks.objs[i])) { + if (!(names[got] = strdup(privconn->networks.objs[i]->def->name))) { + virNetworkObjUnlock(privconn->networks.objs[i]); + virReportOOMError(); + goto cleanup; + } + got++; + } + virNetworkObjUnlock(privconn->networks.objs[i]); + } + parallelsDriverUnlock(privconn); + return got; + + cleanup: + parallelsDriverUnlock(privconn); + for (i = 0 ; i < got ; i++) + VIR_FREE(names[i]); + return -1; +} + +static int parallelsListAllNetworks(virConnectPtr conn, + virNetworkPtr **nets, + unsigned int flags) +{ + parallelsConnPtr privconn = conn->privateData; + int ret = -1; + + virCheckFlags(VIR_CONNECT_LIST_NETWORKS_FILTERS_ALL, -1); + + parallelsDriverLock(privconn); + ret = virNetworkList(conn, privconn->networks, nets, flags); + parallelsDriverUnlock(privconn); + + return ret; +} + +static virNetworkPtr parallelsNetworkLookupByUUID(virConnectPtr conn, + const unsigned char *uuid) +{ + parallelsConnPtr privconn = conn->privateData; + virNetworkObjPtr network; + virNetworkPtr ret = NULL; + + parallelsDriverLock(privconn); + network = virNetworkFindByUUID(&privconn->networks, uuid); + parallelsDriverUnlock(privconn); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + ret = virGetNetwork(conn, network->def->name, network->def->uuid); + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} + +static virNetworkPtr parallelsNetworkLookupByName(virConnectPtr conn, + const char *name) +{ + parallelsConnPtr privconn = conn->privateData; + virNetworkObjPtr network; + virNetworkPtr ret = NULL; + + parallelsDriverLock(privconn); + network = virNetworkFindByName(&privconn->networks, name); + parallelsDriverUnlock(privconn); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + _("no network with matching name '%s'"), name); + goto cleanup; + } + + ret = virGetNetwork(conn, network->def->name, network->def->uuid); + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} + +static char *parallelsNetworkGetXMLDesc(virNetworkPtr net, + unsigned int flags) +{ + parallelsConnPtr privconn = net->conn->privateData; + virNetworkObjPtr network; + char *ret = NULL; + + virCheckFlags(VIR_NETWORK_XML_INACTIVE, NULL); + + parallelsDriverLock(privconn); + network = virNetworkFindByUUID(&privconn->networks, net->uuid); + parallelsDriverUnlock(privconn); + + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + ret = virNetworkDefFormat(network->def, flags); + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} + +static int parallelsNetworkIsActive(virNetworkPtr net) +{ + parallelsConnPtr privconn = net->conn->privateData; + virNetworkObjPtr obj; + int ret = -1; + + parallelsDriverLock(privconn); + obj = virNetworkFindByUUID(&privconn->networks, net->uuid); + parallelsDriverUnlock(privconn); + if (!obj) { + virReportError(VIR_ERR_NO_NETWORK, NULL); + goto cleanup; + } + ret = virNetworkObjIsActive(obj); + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return ret; +} + +static int parallelsNetworkIsPersistent(virNetworkPtr net) +{ + parallelsConnPtr privconn = net->conn->privateData; + virNetworkObjPtr obj; + int ret = -1; + + parallelsDriverLock(privconn); + obj = virNetworkFindByUUID(&privconn->networks, net->uuid); + parallelsDriverUnlock(privconn); + if (!obj) { + virReportError(VIR_ERR_NO_NETWORK, NULL); + goto cleanup; + } + ret = obj->persistent; + +cleanup: + if (obj) + virNetworkObjUnlock(obj); + return ret; +} + +static int parallelsNetworkGetAutostart(virNetworkPtr net, + int *autostart) +{ + parallelsConnPtr privconn = net->conn->privateData; + virNetworkObjPtr network; + int ret = -1; + + parallelsDriverLock(privconn); + network = virNetworkFindByUUID(&privconn->networks, net->uuid); + parallelsDriverUnlock(privconn); + if (!network) { + virReportError(VIR_ERR_NO_NETWORK, + "%s", _("no network with matching uuid")); + goto cleanup; + } + + *autostart = network->autostart; + ret = 0; + +cleanup: + if (network) + virNetworkObjUnlock(network); + return ret; +} +static virNetworkDriver parallelsNetworkDriver = { + "Parallels", + .open = parallelsOpenNetwork, /* 1.0.1 */ + .close = parallelsCloseNetwork, /* 1.0.1 */ + .numOfNetworks = parallelsNumNetworks, /* 1.0.1 */ + .listNetworks = parallelsListNetworks, /* 1.0.1 */ + .numOfDefinedNetworks = parallelsNumDefinedNetworks, /* 1.0.1 */ + .listDefinedNetworks = parallelsListDefinedNetworks, /* 1.0.1 */ + .listAllNetworks = parallelsListAllNetworks, /* 1.0.1 */ + .networkLookupByUUID = parallelsNetworkLookupByUUID, /* 1.0.1 */ + .networkLookupByName = parallelsNetworkLookupByName, /* 1.0.1 */ + .networkGetXMLDesc = parallelsNetworkGetXMLDesc, /* 1.0.1 */ + .networkGetAutostart = parallelsNetworkGetAutostart, /* 1.0.1 */ + .networkIsActive = parallelsNetworkIsActive, /* 1.0.1 */ + .networkIsPersistent = parallelsNetworkIsPersistent, /* 1.0.1 */ +}; + +int +parallelsNetworkRegister(void) +{ + if (virRegisterNetworkDriver(¶llelsNetworkDriver) < 0) + return -1; + + return 0; +} diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index 8b0bdf6..aca3ee2 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -28,6 +28,7 @@ # include "conf/domain_conf.h" # include "conf/storage_conf.h" # include "conf/domain_event.h" +# include "conf/network_conf.h" # include "json.h"
# define parallelsParseError() \ @@ -38,6 +39,7 @@ struct _parallelsConn { virMutex lock; virDomainObjList domains; virStoragePoolObjList pools; + virNetworkObjList networks; virCapsPtr caps; virDomainEventStatePtr domainEventState; }; @@ -54,6 +56,7 @@ struct parallelsDomObj { typedef struct parallelsDomObj *parallelsDomObjPtr;
int parallelsStorageRegister(void); +int parallelsNetworkRegister(void);
virJSONValuePtr parallelsParseOutput(const char *binary, ...) ATTRIBUTE_NONNULL(1) ATTRIBUTE_SENTINEL;
ACK, big chunk, but looks fine to me, Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

Use size_t as array length, so that VIR_EXPAND_N can be used for expanding arrays. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/conf/network_conf.h | 4 ++-- 1 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/conf/network_conf.h b/src/conf/network_conf.h index 949b3d2..87d7746 100644 --- a/src/conf/network_conf.h +++ b/src/conf/network_conf.h @@ -129,10 +129,10 @@ struct _virNetworkIpDef { unsigned int prefix; /* ipv6 - only prefix allowed */ virSocketAddr netmask; /* ipv4 - either netmask or prefix specified */ - unsigned int nranges; /* Zero or more dhcp ranges */ + size_t nranges; /* Zero or more dhcp ranges */ virNetworkDHCPRangeDefPtr ranges; - unsigned int nhosts; /* Zero or more dhcp hosts */ + size_t nhosts; /* Zero or more dhcp hosts */ virNetworkDHCPHostDefPtr hosts; char *tftproot; -- 1.7.7.6

On Tue, Dec 11, 2012 at 02:59:46PM +0400, Dmitry Guryanov wrote:
Use size_t as array length, so that VIR_EXPAND_N can be used for expanding arrays.
That one is already applied upstream as part of commit 2dc5839a16b28c80d8d848f5d6f3711393cbb5eb Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

Fill bridge name and mac for bridged network and DHCP server parameter for host-only network. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_network.c | 172 +++++++++++++++++++++++++++++++++++++ 1 files changed, 172 insertions(+), 0 deletions(-) diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index d30c94d..64e5351 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -35,6 +35,158 @@ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ __FUNCTION__, __LINE__, _("Can't parse prlctl output")) +#define SYSFS_NET_DIR "/sys/class/net" + +static int parallelsGetBridgedNetInfo(virNetworkDefPtr def, virJSONValuePtr jobj) +{ + const char *ifname; + char *bridgeLink = NULL; + char *bridgePath = NULL; + char *bridgeAddressPath = NULL; + char *bridgeAddress = NULL; + int len = 0; + int ret = -1; + + if (!(ifname = virJSONValueObjectGetString(jobj, "Bound To"))) { + parallelsParseError(); + goto cleanup; + } + + if (virAsprintf(&bridgeLink, "%s/%s/brport/bridge", + SYSFS_NET_DIR, ifname) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileResolveLink(bridgeLink, &bridgePath) < 0) { + virReportSystemError(errno, _("cannot read link '%s'"), bridgeLink); + goto cleanup; + } + + if (!(def->bridge = strdup(basename(bridgePath)))) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&bridgeAddressPath, "%s/%s/brport/bridge/address", + SYSFS_NET_DIR, ifname) < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((len = virFileReadAll(bridgeAddressPath, 18, &bridgeAddress)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading file '%s'"), bridgeAddressPath); + + goto cleanup; + } + + if (len < VIR_MAC_STRING_BUFLEN) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading MAC from '%s'"), bridgeAddressPath); + } + + bridgeAddress[VIR_MAC_STRING_BUFLEN - 1] = '\0'; + if (virMacAddrParse(bridgeAddress, &def->mac) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Can't parse MAC '%s'"), bridgeAddress); + goto cleanup; + } + def->mac_specified = 1; + + ret = 0; + +cleanup: + VIR_FREE(bridgeLink); + VIR_FREE(bridgePath); + VIR_FREE(bridgeAddress); + VIR_FREE(bridgeAddressPath); + return ret; +} + +static int parallelsGetHostOnlyNetInfo(virNetworkDefPtr def, const char *name) +{ + const char *tmp; + virJSONValuePtr jobj, jobj2; + int ret = -1; + + if (VIR_EXPAND_N(def->ips, def->nips, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + jobj = parallelsParseOutput("prlsrvctl", "net", "info", "-j", name, NULL); + + if (!jobj) { + parallelsParseError(); + goto cleanup; + } + + if (!(jobj2 = virJSONValueObjectGet(jobj, "Parallels adapter"))) { + parallelsParseError(); + goto cleanup; + } + + if (!(def->ips[0].family = strdup("ipv4"))) { + virReportOOMError(); + goto cleanup; + }; + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].address, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "Subnet mask"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].netmask, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(jobj2 = virJSONValueObjectGet(jobj, "DHCPv4 server"))) { + parallelsParseError(); + goto cleanup; + } + + if (VIR_EXPAND_N(def->ips[0].ranges, def->ips[0].nranges, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope start address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].start, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope end address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].end, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + ret = 0; +cleanup: + virJSONValueFree(jobj); + return ret; +} + static virNetworkObjPtr parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) { @@ -61,6 +213,26 @@ parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) memcpy(def->uuid, md5, VIR_UUID_BUFLEN); def->uuid_specified = 1; + if (!(tmp = virJSONValueObjectGetString(jobj, "Type"))) { + parallelsParseError(); + goto cleanup; + } + + if (STREQ(tmp, "bridged")) { + def->forwardType = VIR_NETWORK_FORWARD_BRIDGE; + + if (parallelsGetBridgedNetInfo(def, jobj) < 0) + goto cleanup; + } else if (STREQ(tmp, "host-only")) { + def->forwardType = VIR_NETWORK_FORWARD_NONE; + + if (parallelsGetHostOnlyNetInfo(def, def->name) < 0) + goto cleanup; + } else { + parallelsParseError(); + goto cleanup; + } + if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) { virNetworkDefFree(def); goto cleanup; -- 1.7.7.6

On Tue, Dec 11, 2012 at 02:59:47PM +0400, Dmitry Guryanov wrote:
Fill bridge name and mac for bridged network and DHCP server parameter for host-only network.
Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_network.c | 172 +++++++++++++++++++++++++++++++++++++ 1 files changed, 172 insertions(+), 0 deletions(-)
diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index d30c94d..64e5351 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -35,6 +35,158 @@ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ __FUNCTION__, __LINE__, _("Can't parse prlctl output"))
+#define SYSFS_NET_DIR "/sys/class/net" + +static int parallelsGetBridgedNetInfo(virNetworkDefPtr def, virJSONValuePtr jobj) +{ + const char *ifname; + char *bridgeLink = NULL; + char *bridgePath = NULL; + char *bridgeAddressPath = NULL; + char *bridgeAddress = NULL; + int len = 0; + int ret = -1; + + if (!(ifname = virJSONValueObjectGetString(jobj, "Bound To"))) { + parallelsParseError(); + goto cleanup; + } + + if (virAsprintf(&bridgeLink, "%s/%s/brport/bridge", + SYSFS_NET_DIR, ifname) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileResolveLink(bridgeLink, &bridgePath) < 0) { + virReportSystemError(errno, _("cannot read link '%s'"), bridgeLink); + goto cleanup; + } + + if (!(def->bridge = strdup(basename(bridgePath)))) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&bridgeAddressPath, "%s/%s/brport/bridge/address", + SYSFS_NET_DIR, ifname) < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((len = virFileReadAll(bridgeAddressPath, 18, &bridgeAddress)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading file '%s'"), bridgeAddressPath); + + goto cleanup; + } + + if (len < VIR_MAC_STRING_BUFLEN) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading MAC from '%s'"), bridgeAddressPath); + } + + bridgeAddress[VIR_MAC_STRING_BUFLEN - 1] = '\0'; + if (virMacAddrParse(bridgeAddress, &def->mac) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Can't parse MAC '%s'"), bridgeAddress); + goto cleanup; + } + def->mac_specified = 1; + + ret = 0; + +cleanup: + VIR_FREE(bridgeLink); + VIR_FREE(bridgePath); + VIR_FREE(bridgeAddress); + VIR_FREE(bridgeAddressPath); + return ret; +} + +static int parallelsGetHostOnlyNetInfo(virNetworkDefPtr def, const char *name) +{ + const char *tmp; + virJSONValuePtr jobj, jobj2; + int ret = -1; + + if (VIR_EXPAND_N(def->ips, def->nips, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + jobj = parallelsParseOutput("prlsrvctl", "net", "info", "-j", name, NULL); + + if (!jobj) { + parallelsParseError(); + goto cleanup; + } + + if (!(jobj2 = virJSONValueObjectGet(jobj, "Parallels adapter"))) { + parallelsParseError(); + goto cleanup; + } + + if (!(def->ips[0].family = strdup("ipv4"))) { + virReportOOMError(); + goto cleanup; + }; + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].address, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "Subnet mask"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].netmask, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(jobj2 = virJSONValueObjectGet(jobj, "DHCPv4 server"))) { + parallelsParseError(); + goto cleanup; + } + + if (VIR_EXPAND_N(def->ips[0].ranges, def->ips[0].nranges, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope start address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].start, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope end address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].end, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + ret = 0; +cleanup: + virJSONValueFree(jobj); + return ret; +} + static virNetworkObjPtr parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) { @@ -61,6 +213,26 @@ parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) memcpy(def->uuid, md5, VIR_UUID_BUFLEN); def->uuid_specified = 1;
+ if (!(tmp = virJSONValueObjectGetString(jobj, "Type"))) { + parallelsParseError(); + goto cleanup; + } + + if (STREQ(tmp, "bridged")) { + def->forwardType = VIR_NETWORK_FORWARD_BRIDGE; + + if (parallelsGetBridgedNetInfo(def, jobj) < 0) + goto cleanup; + } else if (STREQ(tmp, "host-only")) { + def->forwardType = VIR_NETWORK_FORWARD_NONE;
that needed fixing since in the meantime forward got it own dedicated structure
+ if (parallelsGetHostOnlyNetInfo(def, def->name) < 0) + goto cleanup; + } else { + parallelsParseError(); + goto cleanup; + } + if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) { virNetworkDefFree(def); goto cleanup;
So I squashed in the following: diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index d6452bf..19af19a 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -220,12 +220,12 @@ parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) } if (STREQ(tmp, "bridged")) { - def->forwardType = VIR_NETWORK_FORWARD_BRIDGE; + def->forward.type = VIR_NETWORK_FORWARD_BRIDGE; if (parallelsGetBridgedNetInfo(def, jobj) < 0) goto cleanup; } else if (STREQ(tmp, "host-only")) { - def->forwardType = VIR_NETWORK_FORWARD_NONE; + def->forward.type = VIR_NETWORK_FORWARD_NONE; if (parallelsGetHostOnlyNetInfo(def, def->name) < 0) goto cleanup; Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Dec 11, 2012 at 10:43:55PM +0800, Daniel Veillard wrote:
On Tue, Dec 11, 2012 at 02:59:47PM +0400, Dmitry Guryanov wrote:
Fill bridge name and mac for bridged network and DHCP server parameter for host-only network.
Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_network.c | 172 +++++++++++++++++++++++++++++++++++++ 1 files changed, 172 insertions(+), 0 deletions(-)
diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index d30c94d..64e5351 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -35,6 +35,158 @@ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ __FUNCTION__, __LINE__, _("Can't parse prlctl output"))
+#define SYSFS_NET_DIR "/sys/class/net" + +static int parallelsGetBridgedNetInfo(virNetworkDefPtr def, virJSONValuePtr jobj) +{ + const char *ifname; + char *bridgeLink = NULL; + char *bridgePath = NULL; + char *bridgeAddressPath = NULL; + char *bridgeAddress = NULL; + int len = 0; + int ret = -1; + + if (!(ifname = virJSONValueObjectGetString(jobj, "Bound To"))) { + parallelsParseError(); + goto cleanup; + } + + if (virAsprintf(&bridgeLink, "%s/%s/brport/bridge", + SYSFS_NET_DIR, ifname) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (virFileResolveLink(bridgeLink, &bridgePath) < 0) { + virReportSystemError(errno, _("cannot read link '%s'"), bridgeLink); + goto cleanup; + } + + if (!(def->bridge = strdup(basename(bridgePath)))) { + virReportOOMError(); + goto cleanup; + } + + if (virAsprintf(&bridgeAddressPath, "%s/%s/brport/bridge/address", + SYSFS_NET_DIR, ifname) < 0) { + virReportOOMError(); + goto cleanup; + } + + if ((len = virFileReadAll(bridgeAddressPath, 18, &bridgeAddress)) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading file '%s'"), bridgeAddressPath); + + goto cleanup; + } + + if (len < VIR_MAC_STRING_BUFLEN) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Error reading MAC from '%s'"), bridgeAddressPath); + } + + bridgeAddress[VIR_MAC_STRING_BUFLEN - 1] = '\0'; + if (virMacAddrParse(bridgeAddress, &def->mac) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, + _("Can't parse MAC '%s'"), bridgeAddress); + goto cleanup; + } + def->mac_specified = 1; + + ret = 0; + +cleanup: + VIR_FREE(bridgeLink); + VIR_FREE(bridgePath); + VIR_FREE(bridgeAddress); + VIR_FREE(bridgeAddressPath); + return ret; +} + +static int parallelsGetHostOnlyNetInfo(virNetworkDefPtr def, const char *name) +{ + const char *tmp; + virJSONValuePtr jobj, jobj2; + int ret = -1; + + if (VIR_EXPAND_N(def->ips, def->nips, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + jobj = parallelsParseOutput("prlsrvctl", "net", "info", "-j", name, NULL); + + if (!jobj) { + parallelsParseError(); + goto cleanup; + } + + if (!(jobj2 = virJSONValueObjectGet(jobj, "Parallels adapter"))) { + parallelsParseError(); + goto cleanup; + } + + if (!(def->ips[0].family = strdup("ipv4"))) { + virReportOOMError(); + goto cleanup; + }; + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].address, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "Subnet mask"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].netmask, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(jobj2 = virJSONValueObjectGet(jobj, "DHCPv4 server"))) { + parallelsParseError(); + goto cleanup; + } + + if (VIR_EXPAND_N(def->ips[0].ranges, def->ips[0].nranges, 1) < 0) { + virReportOOMError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope start address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].start, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + if (!(tmp = virJSONValueObjectGetString(jobj2, "IP scope end address"))) { + parallelsParseError(); + goto cleanup; + } + + if (virSocketAddrParseIPv4(&def->ips[0].ranges[0].end, tmp) < 0) { + parallelsParseError(); + goto cleanup; + } + + ret = 0; +cleanup: + virJSONValueFree(jobj); + return ret; +} + static virNetworkObjPtr parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) { @@ -61,6 +213,26 @@ parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) memcpy(def->uuid, md5, VIR_UUID_BUFLEN); def->uuid_specified = 1;
+ if (!(tmp = virJSONValueObjectGetString(jobj, "Type"))) { + parallelsParseError(); + goto cleanup; + } + + if (STREQ(tmp, "bridged")) { + def->forwardType = VIR_NETWORK_FORWARD_BRIDGE; + + if (parallelsGetBridgedNetInfo(def, jobj) < 0) + goto cleanup; + } else if (STREQ(tmp, "host-only")) { + def->forwardType = VIR_NETWORK_FORWARD_NONE;
that needed fixing since in the meantime forward got it own dedicated structure
+ if (parallelsGetHostOnlyNetInfo(def, def->name) < 0) + goto cleanup; + } else { + parallelsParseError(); + goto cleanup; + } + if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) { virNetworkDefFree(def); goto cleanup;
So I squashed in the following:
diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index d6452bf..19af19a 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -220,12 +220,12 @@ parallelsLoadNetwork(parallelsConnPtr privconn, virJSONValuePtr jobj) }
if (STREQ(tmp, "bridged")) { - def->forwardType = VIR_NETWORK_FORWARD_BRIDGE; + def->forward.type = VIR_NETWORK_FORWARD_BRIDGE;
if (parallelsGetBridgedNetInfo(def, jobj) < 0) goto cleanup; } else if (STREQ(tmp, "host-only")) { - def->forwardType = VIR_NETWORK_FORWARD_NONE; + def->forward.type = VIR_NETWORK_FORWARD_NONE;
if (parallelsGetHostOnlyNetInfo(def, def->name) < 0) goto cleanup;
this also required the following to avoid uninitialized data access warning: diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index aacceca..40706aa 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -108,7 +108,7 @@ cleanup: static int parallelsGetHostOnlyNetInfo(virNetworkDefPtr def, const char *name) { const char *tmp; - virJSONValuePtr jobj, jobj2; + virJSONValuePtr jobj = NULL, jobj2; int ret = -1; if (VIR_EXPAND_N(def->ips, def->nips, 1) < 0) { Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

Historically if traffic from the adapter is routed to LAN without NAT, it isn't connected to any virtual networks, but has a 'type' instead. Sinse libvirt has special virtual network type for such case, let's add pseudo network 'routed' to fit libvirt's API well. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_network.c | 43 +++++++++++++++++++++++++++++++++++++ src/parallels/parallels_utils.h | 2 + 2 files changed, 45 insertions(+), 0 deletions(-) diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index 64e5351..d6452bf 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -30,6 +30,7 @@ #include "parallels_utils.h" #define VIR_FROM_THIS VIR_FROM_PARALLELS +#define PARALLELS_ROUTED_NETWORK_UUID "eb593dd1-6846-45b0-84a0-de0729286982" #define parallelsParseError() \ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ @@ -250,6 +251,45 @@ cleanup: return NULL; } +static virNetworkObjPtr +parallelsAddRoutedNetwork(parallelsConnPtr privconn) +{ + virNetworkObjPtr net; + virNetworkDefPtr def; + + if (VIR_ALLOC(def) < 0) + goto no_memory; + + def->forwardType = VIR_NETWORK_FORWARD_ROUTE; + + if (!(def->name = strdup(PARALLELS_ROUTED_NETWORK_NAME))) + goto no_memory; + + if (virUUIDParse(PARALLELS_ROUTED_NETWORK_UUID, def->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Can't parse UUID")); + goto cleanup; + } + def->uuid_specified = 1; + + if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) { + virNetworkDefFree(def); + goto cleanup; + } + net->active = 1; + net->persistent = 1; + net->autostart = 1; + virNetworkObjUnlock(net); + + return net; + +no_memory: + virReportOOMError(); +cleanup: + virNetworkDefFree(def); + return NULL; +} + static int parallelsLoadNetworks(parallelsConnPtr privconn) { virJSONValuePtr jobj, jobj2; @@ -283,6 +323,9 @@ static int parallelsLoadNetworks(parallelsConnPtr privconn) } + if (!parallelsAddRoutedNetwork(privconn)) + goto cleanup; + ret = 0; cleanup: diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index aca3ee2..0010f85 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -35,6 +35,8 @@ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ __FUNCTION__, __LINE__, _("Can't parse prlctl output")) +# define PARALLELS_ROUTED_NETWORK_NAME "Routed" + struct _parallelsConn { virMutex lock; virDomainObjList domains; -- 1.7.7.6

On Tue, Dec 11, 2012 at 02:59:48PM +0400, Dmitry Guryanov wrote:
Historically if traffic from the adapter is routed to LAN without NAT, it isn't connected to any virtual networks, but has a 'type' instead. Sinse libvirt has special virtual network type for such case, let's add pseudo network 'routed' to fit libvirt's API well.
Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_network.c | 43 +++++++++++++++++++++++++++++++++++++ src/parallels/parallels_utils.h | 2 + 2 files changed, 45 insertions(+), 0 deletions(-)
diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index 64e5351..d6452bf 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -30,6 +30,7 @@ #include "parallels_utils.h"
#define VIR_FROM_THIS VIR_FROM_PARALLELS +#define PARALLELS_ROUTED_NETWORK_UUID "eb593dd1-6846-45b0-84a0-de0729286982"
#define parallelsParseError() \ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ @@ -250,6 +251,45 @@ cleanup: return NULL; }
+static virNetworkObjPtr +parallelsAddRoutedNetwork(parallelsConnPtr privconn) +{ + virNetworkObjPtr net; + virNetworkDefPtr def; + + if (VIR_ALLOC(def) < 0) + goto no_memory; + + def->forwardType = VIR_NETWORK_FORWARD_ROUTE;
similar problem as for patch 6
+ if (!(def->name = strdup(PARALLELS_ROUTED_NETWORK_NAME))) + goto no_memory; + + if (virUUIDParse(PARALLELS_ROUTED_NETWORK_UUID, def->uuid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Can't parse UUID")); + goto cleanup; + } + def->uuid_specified = 1; + + if (!(net = virNetworkAssignDef(&privconn->networks, def, false))) { + virNetworkDefFree(def); + goto cleanup; + } + net->active = 1; + net->persistent = 1; + net->autostart = 1; + virNetworkObjUnlock(net); + + return net; + +no_memory: + virReportOOMError(); +cleanup: + virNetworkDefFree(def); + return NULL; +} + static int parallelsLoadNetworks(parallelsConnPtr privconn) { virJSONValuePtr jobj, jobj2; @@ -283,6 +323,9 @@ static int parallelsLoadNetworks(parallelsConnPtr privconn)
}
+ if (!parallelsAddRoutedNetwork(privconn)) + goto cleanup; + ret = 0;
cleanup: diff --git a/src/parallels/parallels_utils.h b/src/parallels/parallels_utils.h index aca3ee2..0010f85 100644 --- a/src/parallels/parallels_utils.h +++ b/src/parallels/parallels_utils.h @@ -35,6 +35,8 @@ virReportErrorHelper(VIR_FROM_TEST, VIR_ERR_OPERATION_FAILED, __FILE__, \ __FUNCTION__, __LINE__, _("Can't parse prlctl output"))
+# define PARALLELS_ROUTED_NETWORK_NAME "Routed" + struct _parallelsConn { virMutex lock; virDomainObjList domains;
and similar fix: diff --git a/src/parallels/parallels_network.c b/src/parallels/parallels_network.c index 19af19a..aacceca 100644 --- a/src/parallels/parallels_network.c +++ b/src/parallels/parallels_network.c @@ -260,7 +260,7 @@ parallelsAddRoutedNetwork(parallelsConnPtr privconn) if (VIR_ALLOC(def) < 0) goto no_memory; - def->forwardType = VIR_NETWORK_FORWARD_ROUTE; + def->forward.type = VIR_NETWORK_FORWARD_ROUTE; if (!(def->name = strdup(PARALLELS_ROUTED_NETWORK_NAME))) goto no_memory; Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

Network adapters of type 'routed' is a special case. Other adapters have 'network' parameter in prlctl's output instead. Routed network adapters should be connected to 'routed' network from libvirt's view. Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 42 +++++++++++++++++++++++++++++++------ 1 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 21279c0..f16777a 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -482,13 +482,34 @@ parallelsGetNetInfo(virDomainNetDefPtr net, goto error; } - if (!(tmp = virJSONValueObjectGetString(value, "network"))) { - parallelsParseError(); - goto error; - } - if (!(net->data.network.name = strdup(tmp))) { - virReportOOMError(); + if (virJSONValueObjectHasKey(value, "network")) { + if (!(tmp = virJSONValueObjectGetString(value, "network"))) { + parallelsParseError(); + goto error; + } + + if (!(net->data.network.name = strdup(tmp))) { + virReportOOMError(); + goto error; + } + } else if (virJSONValueObjectHasKey(value, "type")) { + if (!(tmp = virJSONValueObjectGetString(value, "type"))) { + parallelsParseError(); + goto error; + } + + if (!STREQ(tmp, "routed")) { + parallelsParseError(); + goto error; + } + + if (!(net->data.network.name = strdup(PARALLELS_ROUTED_NETWORK_NAME))) { + virReportOOMError(); + goto error; + } + } else { + parallelsParseError(); goto error; } @@ -1866,7 +1887,14 @@ static int parallelsApplyIfaceParams(parallelsDomObjPtr pdom, } if (!STREQ_NULLABLE(oldnet->data.network.name, newnet->data.network.name)) { - virCommandAddArgFormat(cmd, "--network=%s", newnet->data.network.name); + if (STREQ_NULLABLE(newnet->data.network.name, + PARALLELS_ROUTED_NETWORK_NAME)) { + virCommandAddArgFormat(cmd, "--type=routed"); + } else { + virCommandAddArgFormat(cmd, "--network=%s", + newnet->data.network.name); + } + is_changed = true; } -- 1.7.7.6

On Tue, Dec 11, 2012 at 02:59:49PM +0400, Dmitry Guryanov wrote:
Network adapters of type 'routed' is a special case. Other adapters have 'network' parameter in prlctl's output instead.
Routed network adapters should be connected to 'routed' network from libvirt's view.
Signed-off-by: Dmitry Guryanov <dguryanov@parallels.com> --- src/parallels/parallels_driver.c | 42 +++++++++++++++++++++++++++++++------ 1 files changed, 35 insertions(+), 7 deletions(-)
diff --git a/src/parallels/parallels_driver.c b/src/parallels/parallels_driver.c index 21279c0..f16777a 100644 --- a/src/parallels/parallels_driver.c +++ b/src/parallels/parallels_driver.c @@ -482,13 +482,34 @@ parallelsGetNetInfo(virDomainNetDefPtr net, goto error; }
- if (!(tmp = virJSONValueObjectGetString(value, "network"))) { - parallelsParseError(); - goto error; - }
- if (!(net->data.network.name = strdup(tmp))) { - virReportOOMError(); + if (virJSONValueObjectHasKey(value, "network")) { + if (!(tmp = virJSONValueObjectGetString(value, "network"))) { + parallelsParseError(); + goto error; + } + + if (!(net->data.network.name = strdup(tmp))) { + virReportOOMError(); + goto error; + } + } else if (virJSONValueObjectHasKey(value, "type")) { + if (!(tmp = virJSONValueObjectGetString(value, "type"))) { + parallelsParseError(); + goto error; + } + + if (!STREQ(tmp, "routed")) { + parallelsParseError(); + goto error; + } + + if (!(net->data.network.name = strdup(PARALLELS_ROUTED_NETWORK_NAME))) { + virReportOOMError(); + goto error; + } + } else { + parallelsParseError(); goto error; }
@@ -1866,7 +1887,14 @@ static int parallelsApplyIfaceParams(parallelsDomObjPtr pdom, }
if (!STREQ_NULLABLE(oldnet->data.network.name, newnet->data.network.name)) { - virCommandAddArgFormat(cmd, "--network=%s", newnet->data.network.name); + if (STREQ_NULLABLE(newnet->data.network.name, + PARALLELS_ROUTED_NETWORK_NAME)) { + virCommandAddArgFormat(cmd, "--type=routed"); + } else { + virCommandAddArgFormat(cmd, "--network=%s", + newnet->data.network.name); + } + is_changed = true; }
ACK, Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

On Tue, Dec 11, 2012 at 02:59:41PM +0400, Dmitry Guryanov wrote:
The goal of this patch series is to add initial support of networking to Parallels Cloud Server driver.
Parallels driver will be able to show read-only list of virtual networks and manage network adapters of virtual machines (list, add, remove, change properties, switch to another virtual network).
Dmitry Guryanov (8): parallels: parse information about network interfaces parallels: add support of network interfaces to parallelsDomainDefineXML parallels: move parallelsParseError to parallels_utils.h parallels: add network driver Use size_t for virNetworkIpDef structure parallels: parse virtual network properties parallels: add routed pseudo network parallels: handle network adapters of type 'routed'
po/POTFILES.in | 2 + src/Makefile.am | 3 +- src/conf/network_conf.h | 4 +- src/parallels/parallels_driver.c | 314 ++++++++++++++++++- src/parallels/parallels_network.c | 639 +++++++++++++++++++++++++++++++++++++ src/parallels/parallels_utils.h | 9 + 6 files changed, 963 insertions(+), 8 deletions(-) create mode 100644 src/parallels/parallels_network.c
Okay, pushed, though it needed a bit of tweaking due to change in the last few hours, double check when you have time ! Daniel -- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/

On 121211 22:55:59, Daniel Veillard wrote:
On Tue, Dec 11, 2012 at 02:59:41PM +0400, Dmitry Guryanov wrote:
The goal of this patch series is to add initial support of networking to Parallels Cloud Server driver.
Parallels driver will be able to show read-only list of virtual networks and manage network adapters of virtual machines (list, add, remove, change properties, switch to another virtual network).
Dmitry Guryanov (8): parallels: parse information about network interfaces parallels: add support of network interfaces to parallelsDomainDefineXML parallels: move parallelsParseError to parallels_utils.h parallels: add network driver Use size_t for virNetworkIpDef structure parallels: parse virtual network properties parallels: add routed pseudo network parallels: handle network adapters of type 'routed'
po/POTFILES.in | 2 + src/Makefile.am | 3 +- src/conf/network_conf.h | 4 +- src/parallels/parallels_driver.c | 314 ++++++++++++++++++- src/parallels/parallels_network.c | 639 +++++++++++++++++++++++++++++++++++++ src/parallels/parallels_utils.h | 9 + 6 files changed, 963 insertions(+), 8 deletions(-) create mode 100644 src/parallels/parallels_network.c
Okay, pushed, though it needed a bit of tweaking due to change in the last few hours, double check when you have time !
Thanks !
Daniel
-- Daniel Veillard | Open Source and Standards, Red Hat veillard@redhat.com | libxml Gnome XML XSLT toolkit http://xmlsoft.org/ http://veillard.com/ | virtualization library http://libvirt.org/
participants (2)
-
Daniel Veillard
-
Dmitry Guryanov