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(a)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