Adding networkCreateXML, networkDestroy, networkIsActive and networkLookupByName.
In the function phypCreateNetwork I just use the def->domain information to create
the new network interface because of the behaviour of the HMC and the hypervisor:
* HMC can't simply create a network interface without assigning it to a specific
LPAR.
* I also can't assign an IP addr or any other information from the HMC or VIOS
side, but I can control in which vlan or vswitch it will be attached - but
thought just in the simplest case scenarion now, I'll make some improvements
in the future.
That's why I used a very simple XML for testing:
<network>
<uuid>3e3fce45-4f53-4fa7-bb32-11f34168b82b</uuid>
<domain name="LPAR01" />
<name>whatever</name>
<bridge name="whatever" />
</network>
The only information I really need is the domain name which I'll assign the created
network interface. Name, MAC Addr MUST be created automatically by the hypervisor,
they're all unique. I had to put those two other tags "name" and
"bridge" so the
function virNetworkDefParseString can return successfully, otherwise it would say
that the XML is malformed.
---
src/phyp/phyp_driver.c | 400 +++++++++++++++++++++++++++++++++++++++++++++++-
src/phyp/phyp_driver.h | 2 +-
2 files changed, 396 insertions(+), 6 deletions(-)
diff --git a/src/phyp/phyp_driver.c b/src/phyp/phyp_driver.c
index c44fc69..244561e 100644
--- a/src/phyp/phyp_driver.c
+++ b/src/phyp/phyp_driver.c
@@ -1,7 +1,7 @@
/*
* Copyright (C) 2010 Red Hat, Inc.
- * Copyright IBM Corp. 2009
+ * Copyright IBM Corp. 2010
*
* phyp_driver.c: ssh layer to access Power Hypervisors
*
@@ -2829,6 +2829,396 @@ phypGetStoragePoolXMLDesc(virStoragePoolPtr pool, unsigned int
flags)
return NULL;
}
+static int
+networkDestroy(virNetworkPtr net)
+{
+ ConnectionData *connection_data = net->conn->networkPrivateData;
+ phyp_driverPtr phyp_driver = net->conn->privateData;
+ LIBSSH2_SESSION *session = connection_data->session;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ uuid_nettablePtr uuid_nettable = phyp_driver->uuid_nettable;
+ char *managed_system = phyp_driver->managed_system;
+ int system_type = phyp_driver->system_type;
+ int exit_status = 0;
+ int slot_num = 0;
+ char *char_ptr;
+ char *cmd = NULL;
+ char *ret = NULL;
+ unsigned int i = 0;
+ int lpar_id = 0;
+ long long mac = 0;
+
+ for (i = 0; i < uuid_nettable->nnets; i++) {
+ if (STREQ(uuid_nettable->nets[i]->name, net->name)) {
+ mac = uuid_nettable->nets[i]->mac;
+ break;
+ }
+ }
+
+ /* Getting the LPAR ID */
+
+ virBufferAddLit(&buf, "lshwres ");
+ if (system_type == HMC)
+ virBufferVSprintf(&buf, "-m %s ", managed_system);
+
+ virBufferVSprintf(&buf,
+ " -r virtualio --rsubtype slot --level slot "
+ " -F drc_name,lpar_id|grep %s|"
+ " sed -e 's/^.*,//g'", net->name);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return -1;
+ }
+ cmd = virBufferContentAndReset(&buf);
+
+ ret = phypExec(session, cmd, &exit_status, net->conn);
+
+ if (exit_status < 0 || ret == NULL)
+ goto err;
+
+ if (virStrToLong_i(ret, &char_ptr, 10, &lpar_id) == -1)
+ goto err;
+
+ /* Getting the remote slot number */
+
+ virBufferAddLit(&buf, "lshwres ");
+ if (system_type == HMC)
+ virBufferVSprintf(&buf, "-m %s ", managed_system);
+
+ virBufferVSprintf(&buf,
+ " -r virtualio --rsubtype eth --level lpar "
+ " -F mac_addr,slot_num|grep %lld|"
+ " sed -e 's/^.*,//g'", mac);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return -1;
+ }
+ cmd = virBufferContentAndReset(&buf);
+
+ ret = phypExec(session, cmd, &exit_status, net->conn);
+
+ if (exit_status < 0 || ret == NULL)
+ goto err;
+
+ if (virStrToLong_i(ret, &char_ptr, 10, &slot_num) == -1)
+ goto err;
+
+ /* excluding interface */
+
+ virBufferAddLit(&buf, "chhwres ");
+ if (system_type == HMC)
+ virBufferVSprintf(&buf, "-m %s ", managed_system);
+
+ virBufferVSprintf(&buf,
+ " -r virtualio --rsubtype eth"
+ " --id %d -o r -s %d", lpar_id, slot_num);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return -1;
+ }
+ cmd = virBufferContentAndReset(&buf);
+
+ ret = phypExec(session, cmd, &exit_status, net->conn);
+
+ if (exit_status < 0 || ret != NULL)
+ goto err;
+
+ if (phypUUIDTable_RemNetwork(net->conn, mac) < 0)
+ goto err;
+
+ VIR_FREE(cmd);
+ VIR_FREE(ret);
+ return 0;
+
+ err:
+ VIR_FREE(cmd);
+ VIR_FREE(ret);
+ return -1;
+}
+
+static virNetworkPtr
+phypCreateNetwork(virConnectPtr conn, const char *xml)
+{
+ ConnectionData *connection_data = conn->networkPrivateData;
+ phyp_driverPtr phyp_driver = conn->privateData;
+ LIBSSH2_SESSION *session = connection_data->session;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ uuid_nettablePtr uuid_nettable = phyp_driver->uuid_nettable;
+ char *managed_system = phyp_driver->managed_system;
+ int system_type = phyp_driver->system_type;
+ int exit_status = 0;
+ char *char_ptr;
+ char *cmd = NULL;
+ int lpar_id = 0;
+ int slot = 0;
+ char *ret = NULL;
+ unsigned int i = 0;
+ long long mac = 0;
+ unsigned char *uuid = NULL;
+ char *name = NULL;
+ virNetworkDefPtr def;
+
+ if (VIR_ALLOC_N(name, NETNAME_SIZE) < 0) {
+ virReportOOMError();
+ goto err;
+ }
+
+ if (VIR_ALLOC_N(uuid, VIR_UUID_BUFLEN) < 0) {
+ virReportOOMError();
+ goto err;
+ }
+
+ if (!(def = virNetworkDefParseString(xml)))
+ goto err;
+
+ /* Checking for duplicate uuid */
+ if (def->uuid && virUUIDIsValid(def->uuid)) {
+ for (i = 0; i < uuid_nettable->nnets; i++) {
+ if (uuid_nettable->nets[i]->uuid == def->uuid) {
+ VIR_ERROR(_("UUID %s already exists"), name);
+ goto duplicate_uuid;
+ }
+ }
+ if (!memcpy(uuid, def->uuid, VIR_UUID_BUFLEN))
+ goto err;
+
+ goto good_uuid;
+ }
+
+ duplicate_uuid:
+
+ /*generate a new uuid */
+ if (virUUIDGenerate(uuid) < 0)
+ goto err;
+
+ good_uuid:
+
+ if (def->name)
+ VIR_WARN0
+ ("Name will be ignored, hypervisor must create one
automatically.");
+
+ if (!def->domain) {
+ VIR_ERROR0(_("Domain can't be NULL, you must especify in which"
+ "domain you want to add the new network interface."));
+ goto err;
+ }
+
+ if ((lpar_id =
+ phypGetLparID(session, managed_system, def->domain, conn)) < 0)
+ goto err;
+
+ /* Now need to get the next free slot number */
+ virBufferAddLit(&buf, "lshwres ");
+ if (system_type == HMC)
+ virBufferVSprintf(&buf, "-m %s ", managed_system);
+
+ virBufferVSprintf(&buf,
+ " -r virtualio --rsubtype slot --level slot"
+ " -Fslot_num --filter lpar_ids=%d"
+ " |sort|tail -n 1", lpar_id);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ goto err;
+ }
+ cmd = virBufferContentAndReset(&buf);
+
+ ret = phypExec(session, cmd, &exit_status, conn);
+
+ if (exit_status < 0 || ret == NULL)
+ goto err;
+
+ if (virStrToLong_i(ret, &char_ptr, 10, &slot) == -1)
+ goto err;
+
+ /* The next free slot itself: */
+ slot++;
+
+ /* Now addig the new network interface */
+ virBufferAddLit(&buf, "chhwres ");
+ if (system_type == HMC)
+ virBufferVSprintf(&buf, "-m %s ", managed_system);
+
+ virBufferVSprintf(&buf,
+ " -r virtualio --rsubtype eth"
+ " --id %d -o a -s %d -a port_vlan_id=1,"
+ "ieee_virtual_eth=0", lpar_id, slot);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ goto err;
+ }
+ cmd = virBufferContentAndReset(&buf);
+
+ ret = phypExec(session, cmd, &exit_status, conn);
+
+ if (exit_status < 0 || ret != NULL)
+ goto err;
+
+ /* Need to sleep a little while to wait for the HMC to
+ * complete the execution of the command.
+ * */
+ sleep(1);
+
+ /* Getting the new interface name */
+ virBufferAddLit(&buf, "lshwres ");
+ if (system_type == HMC)
+ virBufferVSprintf(&buf, "-m %s ", managed_system);
+
+ virBufferVSprintf(&buf,
+ " -r virtualio --rsubtype slot --level slot"
+ " |grep lpar_id=%d|grep slot_num=%d|"
+ " sed -e 's/^.*drc_name=//g'", lpar_id, slot);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ goto err;
+ }
+ cmd = virBufferContentAndReset(&buf);
+
+ ret = phypExec(session, cmd, &exit_status, conn);
+
+ if (exit_status < 0 || ret == NULL)
+ goto err;
+
+ char_ptr = NULL;
+ char_ptr = strchr(ret, '\n');
+
+ if (char_ptr)
+ *char_ptr = '\0';
+
+ if (memcpy(name, ret, NETNAME_SIZE) == NULL)
+ goto err;
+
+ /* Getting the new interface mac addr */
+ virBufferAddLit(&buf, "lshwres ");
+ if (system_type == HMC)
+ virBufferVSprintf(&buf, "-m %s ", managed_system);
+
+ virBufferVSprintf(&buf,
+ "-r virtualio --rsubtype eth --level lpar "
+ "|grep lpar_id=%d|grep slot_num=%d|"
+ " sed -e 's/^.*mac_addr=//g'", lpar_id, slot);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ goto err;
+ }
+ cmd = virBufferContentAndReset(&buf);
+
+ ret = phypExec(session, cmd, &exit_status, conn);
+
+ if (exit_status < 0 || ret == NULL)
+ goto err;
+
+ if (virStrToLong_ll(ret, &char_ptr, 10, &mac) == -1)
+ goto err;
+
+ /* Adding the new interface to the uuid database: */
+ if (phypUUIDTable_AddNetwork(conn, uuid, mac, name) < 0)
+ goto err;
+
+ VIR_FREE(cmd);
+ VIR_FREE(ret);
+ return virGetNetwork(conn, name, uuid);
+
+ err:
+ VIR_FREE(name);
+ VIR_FREE(cmd);
+ VIR_FREE(ret);
+ VIR_FREE(uuid);
+ return NULL;
+}
+
+static int
+networkIsActive(virNetworkPtr net)
+{
+ ConnectionData *connection_data = net->conn->networkPrivateData;
+ phyp_driverPtr phyp_driver = net->conn->privateData;
+ LIBSSH2_SESSION *session = connection_data->session;
+ virBuffer buf = VIR_BUFFER_INITIALIZER;
+ uuid_nettablePtr uuid_nettable = phyp_driver->uuid_nettable;
+ char *managed_system = phyp_driver->managed_system;
+ int system_type = phyp_driver->system_type;
+ int exit_status = 0;
+ int state = 0;
+ char *char_ptr;
+ char *cmd = NULL;
+ char *ret = NULL;
+ unsigned int i = 0;
+ long long mac = 0;
+
+ for (i = 0; i < uuid_nettable->nnets; i++) {
+ if (uuid_nettable->nets[i]->uuid == net->uuid) {
+ mac = uuid_nettable->nets[i]->mac;
+ break;
+ }
+ }
+
+ virBufferAddLit(&buf, "lshwres ");
+ if (system_type == HMC)
+ virBufferVSprintf(&buf, "-m %s ", managed_system);
+
+ virBufferVSprintf(&buf,
+ "-r virtualio --rsubtype eth --level lpar "
+ "-F mac_addr,state |grep %lld|"
+ "sed -e 's/^.*,//g'", mac);
+
+ if (virBufferError(&buf)) {
+ virBufferFreeAndReset(&buf);
+ virReportOOMError();
+ return -1;
+ }
+ cmd = virBufferContentAndReset(&buf);
+
+ ret = phypExec(session, cmd, &exit_status, net->conn);
+
+ if (exit_status < 0 || ret == NULL)
+ goto err;
+
+ if (virStrToLong_i(ret, &char_ptr, 10, &state) == -1)
+ goto err;
+
+ if (char_ptr)
+ *char_ptr = '\0';
+
+ VIR_FREE(cmd);
+ return state;
+
+ err:
+ VIR_FREE(cmd);
+ VIR_FREE(ret);
+ return -1;
+
+}
+
+static virNetworkPtr
+phypNetworkLookupByName(virConnectPtr conn, const char *name)
+{
+
+ phyp_driverPtr phyp_driver = conn->privateData;
+ uuid_nettablePtr uuid_nettable = phyp_driver->uuid_nettable;
+ unsigned int i = 0;
+
+ for (i = 0; i < uuid_nettable->nnets; i++) {
+ if (STREQ(uuid_nettable->nets[i]->name, name))
+ return virGetNetwork(conn, name, uuid_nettable->nets[i]->uuid);
+ }
+
+ VIR_ERROR(_("No network found matching %s "), name);
+ return NULL;
+}
+
int
phypListNetworkMAC(virConnectPtr conn, long long *macs, int nnets)
{
@@ -3834,17 +4224,17 @@ static virNetworkDriver phypNetworkDriver = {
.numOfDefinedNetworks = NULL,
.listDefinedNetworks = NULL,
.networkLookupByUUID = NULL,
- .networkLookupByName = NULL,
- .networkCreateXML = NULL,
+ .networkLookupByName = phypNetworkLookupByName,
+ .networkCreateXML = phypCreateNetwork,
.networkDefineXML = NULL,
.networkUndefine = NULL,
.networkCreate = NULL,
- .networkDestroy = NULL,
+ .networkDestroy = networkDestroy,
.networkDumpXML = NULL,
.networkGetBridgeName = NULL,
.networkGetAutostart = NULL,
.networkSetAutostart = NULL,
- .networkIsActive = NULL,
+ .networkIsActive = networkIsActive,
.networkIsPersistent = NULL
};
diff --git a/src/phyp/phyp_driver.h b/src/phyp/phyp_driver.h
index 603d048..34ad84b 100644
--- a/src/phyp/phyp_driver.h
+++ b/src/phyp/phyp_driver.h
@@ -1,6 +1,6 @@
/*
* Copyright (C) 2010 Red Hat, Inc.
- * Copyright IBM Corp. 2009
+ * Copyright IBM Corp. 2010
*
* phyp_driver.c: ssh layer to access Power Hypervisors
*
--
1.7.1