#ifndef __VSC_MGMT__BACKEND__DATA_H__
#define __VSC_MGMT__BACKEND__DATA_H__
+#include <libxml/tree.h>
+
#include <libvscmisc/error.h>
#include "../../include/libvscmgmt/types.h"
_vsc_mgmt_data_backup (struct VscError *error, FILE *fp);
void
-_vsc_mgmt_data_recover (struct VscError *error, const char* filename);
+_vsc_mgmt_data_recover_start (struct VscError *error, const xmlNode *node);
+
+void
+_vsc_mgmt_data_recover_commit (void);
+
+void
+_vsc_mgmt_data_recover_rollback (void);
/* Host focussed functions */
CFLAGS += $(shell pkg-config --cflags glib-2.0)
LDFLAGS += $(shell pkg-config --libs glib-2.0)
+# libxml
+CFLAGS += $(shell pkg-config libxml-2.0 --cflags)
+LDFLAGS += $(shell pkg-config libxml-2.0 --libs)
+
#
# Rules
#
* @file
*/
-#include <glib-2.0/glib.h>
#include <stdlib.h>
#include <uuid/uuid.h>
+#include <glib-2.0/glib.h>
+
+#include <libxml/parser.h>
+#include <libxml/tree.h>
#include <libvscmisc/assert.h>
#include <libvscmisc/error.h>
#include <libvscmisc/memory.h>
+#include <libvscmisc/string.h>
#include "../../../include/libvscmgmt/ipv4.h"
#include "../../../include/libvscmgmt/uuid.h"
#include "../../../lib/ipv4.h"
#include "../../../lib/mac.h"
#include "../../../lib/uuid.h"
+#include "../../../lib/xml.h"
struct HostTreeElem {
struct VscMgmtUuid vm_uuid;
};
+static struct _backup {
+ GTree *_host_by_ip_tree;
+ GTree *_vm_by_uuid_tree;
+ GTree *_vm_by_ip_lookup_tree;
+} _backup;
+
static int _data_initialized = 0;
}
+
/*
* Traversal functions for the VM trees.
*/
+/*
+ * XML restore related function
+ */
+static inline xmlChar *
+_get_content (const xmlNode *node)
+{
+ VSC__ASSERT (node != NULL);
+
+ if (node && node->children) {
+ return node->children->content;
+ } else {
+ return NULL;
+ }
+}
+
+
+static void
+_read_resource_config (struct VscError *error, const xmlNode *xml_res_conf,
+ struct VscMgmtVmResourceConfig *res_conf)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (xml_res_conf != NULL);
+ VSC__ASSERT (res_conf != NULL);
+
+ xmlNode *xml_child = NULL;
+ int temp;
+
+ VSC__ASSERT (xmlStrEqual (xml_res_conf->name, BAD_CAST "resource_config"));
+
+ for (xml_child = xml_res_conf->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrEqual (xml_child->name, BAD_CAST "num_cores")) {
+ _vsc_mgmt_xml_parse_int (error, xml_child, &res_conf->num_cores, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return;
+ }
+ }
+
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "core_clock")) {
+ _vsc_mgmt_xml_parse_int (error, xml_child, &res_conf->core_clock, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return;
+ }
+ }
+
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "memory_size")) {
+ _vsc_mgmt_xml_parse_int (error, xml_child, &temp, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return;
+ }
+
+ res_conf->memory_size = temp;
+ }
+ }
+
+}
+
+static void
+_read_vm (struct VscError *error, const xmlNode *xml_vm, const struct VscMgmtHost *host)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (xml_vm != NULL);
+ VSC__ASSERT (host != NULL);
+
+ struct VscMgmtVm *vm = NULL;
+
+ xmlNode *xml_child = NULL;
+ xmlChar *content = NULL;
+
+ VSC__ASSERT (xmlStrEqual (xml_vm->name, BAD_CAST "vm"));
+
+ vm = vsc_alloc (error, sizeof (struct VscMgmtVm));
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return;
+ }
+
+ for (xml_child = xml_vm->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ /*
+ * Forget about any previos content string and try to prefetch
+ * the new one
+ */
+ content = NULL;
+ content = _get_content (xml_child);
+
+ /*
+ * VmInfo values
+ */
+
+ /* UUID */
+ if (xmlStrEqual (xml_child->name, BAD_CAST "uuid_string")) {
+ _vsc_mgmt_xml_parse_uuid (error, xml_child,
+ &vm->info.uuid,
+ &vm->info.uuid_string);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Image filename */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "image_filename")) {
+ if (! content && host->info.type != VSC_MGMT__HOST_TYPE__VIRTUAL) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No value for 'image_filename' given at line %i",
+ xml_child->line);
+ goto failure;
+ }
+
+ vm->info.image_filename = vsc_strdup (error, (const char *) content);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Network UUID */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "network_uuid")) {
+ _vsc_mgmt_xml_parse_uuid (error, xml_child,
+ &vm->info.network_uuid,
+ NULL);
+ if (error->occured) {
+ goto failure;
+ }
+ }
+
+ /* IP address */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "ipv4")) {
+ _vsc_mgmt_xml_parse_ipv4 (error, xml_child, &vm->info.ipv4, NULL);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Mac address */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "mac")) {
+ _vsc_mgmt_xml_parse_mac (error, xml_child, &vm->info.mac);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+
+ /* Resource config */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "resource_config")) {
+ _read_resource_config (error, xml_child, &vm->info.resource_config);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* FIXME:
+ - state
+ - suspension_uuid
+ - checkpoint_uuid_list
+ - timevals
+ */
+
+
+ /*
+ * Vm values
+ */
+
+ /* Host IP */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "host_ip")) {
+ _vsc_mgmt_xml_parse_ipv4 (error, xml_child, &vm->host_ip, NULL);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+ if (_vsc_mgmt_ipv4_compare (&host->info.ipv4, &vm->host_ip) != 0) {
+ VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Host IP of VM does not fit IP of corresponding host");
+ goto failure;
+ }
+ }
+ } /* for each value */
+
+ _vsc_mgmt_data_vm_add (error, vm);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+
+ return;
+
+failure:
+ vsc_free (&vm->info.uuid_string);
+ vsc_free (&vm->info.image_filename);
+ vsc_free (&vm);
+}
+
+static void
+_read_host (struct VscError *error, const xmlNode *xml_host)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (xml_host != NULL);
+
+ struct VscMgmtHost *host = NULL;
+
+ xmlNode *xml_child = NULL;
+ xmlNode *vms = NULL;
+ xmlChar *content = NULL;
+
+ int int_temp;
+
+ VSC__ASSERT (xmlStrEqual (xml_host->name, BAD_CAST "host"));
+
+ host = vsc_alloc (error, sizeof (struct VscMgmtHost));
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return;
+ }
+
+ for (xml_child = xml_host->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ /*
+ * Forget about any previos content string and try to prefetch
+ * the new one
+ */
+ content = NULL;
+ content = _get_content (xml_child);
+
+ /* VMs (delay parsing) */
+ if (xmlStrEqual (xml_child->name, BAD_CAST "vms")) {
+ vms = xml_child;
+ }
+
+ /*
+ * HostInfo values
+ */
+
+ /* Host IP */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "ipv4")) {
+ _vsc_mgmt_xml_parse_ipv4 (error, xml_child, &host->info.ipv4, NULL);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Type */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "type")) {
+ if (! content) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No value for 'type' given at line %i",
+ xml_child->line);
+ goto failure;
+ }
+
+ host->info.type = _vsc_mgmt_host_type_parse (error,
+ (const char *) content);
+ if (error->occured) {
+ VSC__APPEND_ERROR2 (error, VSC__ERROR_CODE__TRACE,
+ "Invalid host type at line %i",
+ xml_child->line);
+ goto failure;
+ }
+ }
+
+ /* Num cores */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "num_cores")) {
+ _vsc_mgmt_xml_parse_int (error, xml_child, &host->info.num_cores, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return;
+ }
+ }
+
+ /* Core clock */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "core_clock")) {
+ _vsc_mgmt_xml_parse_int (error, xml_child, &host->info.core_clock, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return;
+ }
+ }
+
+ /* Memory size */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "memory_size")) {
+ _vsc_mgmt_xml_parse_int (error, xml_child, &int_temp, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return;
+ }
+
+ host->info.memory_size = int_temp;
+ }
+
+
+ /*
+ * VscMgmtHost values
+ */
+
+ /* Transport type (maybe optional) */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "transport_type") && content) {
+ host->transport_type = vsc_strdup (error, (const char *) content);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Username */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "username") && content) {
+ host->username = vsc_strdup (error, (const char *) content);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Password */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "password") && content) {
+ host->password = vsc_strdup (error, (const char *) content);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+
+ /* Virtual hardware filename */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "virtual_hardware_filename") &&
+ content) {
+ host->virtual_hardware_filename = vsc_strdup (error, (const char *) content);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+
+ /* ESX vCenter IP */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "vcenter_ip") && content) {
+ vsc_mgmt_ipv4_parse (error, (const char *) content, &host->vcenter_ip);
+ if (error->occured) {
+ VSC__APPEND_ERROR2 (error, VSC__ERROR_CODE__TRACE,
+ "Invalid IP for host at line %i",
+ xml_child->line);
+ goto failure;
+ }
+ }
+
+ } /* for each attribute */
+
+ /*
+ * Validate host and add if to the storage (if valid)
+ */
+ if (! _vsc_mgmt_host_is_valid (host)) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Invalid host entry at line %i",
+ xml_child->line);
+ goto failure;
+ }
+
+ /* It's suspicous if there is no <vms> entry */
+ if (! vms) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Host found at line %i does not have a <vms> entry.",
+ xml_child->line);
+ goto failure;
+ }
+
+ _vsc_mgmt_data_host_add (error, host);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+
+ /*
+ * Parse VMs (if any)
+ */
+ for (xml_child = vms->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type == XML_ELEMENT_NODE &&
+ xmlStrEqual (xml_child->name, BAD_CAST "vm")) {
+ _read_vm (error, xml_child, host);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ /*
+ * Don't free the host here, as it will be freed
+ * on the succeding call to recover_rollback.
+ */
+ return;
+ }
+ }
+ }
+
+ return;
+
+
+failure:
+ vsc_free (&host->transport_type);
+ vsc_free (&host->username);
+ vsc_free (&host->password);
+ vsc_free (&host->virtual_hardware_filename);
+ vsc_free (&host);
+}
/******************************************************************************
* private API functions *
+
void
-_vsc_mgmt_data_recover (struct VscError *error, const char* filename)
+_vsc_mgmt_data_recover_start (struct VscError *error, const xmlNode *node)
{
VSC__ASSERT (error != NULL);
VSC__ASSERT (! error->occured);
- VSC__ASSERT (filename != NULL);
+ VSC__ASSERT (node != NULL);
+
+ VSC__ASSERT (xmlStrEqual (node->name, BAD_CAST "data"));
+
+ xmlNode *child = NULL;
+ xmlNode *hosts = NULL;
+
+ /* Save pointers to the current trees */
+ _backup._host_by_ip_tree = _host_by_ip_tree;
+ _backup._vm_by_uuid_tree = _vm_by_uuid_tree;
+ _backup._vm_by_ip_lookup_tree = _vm_by_ip_lookup_tree;
+
+ /*
+ * Clear the current pointers so it's save to use the cleanup()
+ * function if anything fails
+ */
+ _host_by_ip_tree = NULL;
+ _vm_by_uuid_tree = NULL;
+ _vm_by_ip_lookup_tree = NULL;
+
+ /* Setup new trees to be filled from the backup */
+ _host_by_ip_tree = g_tree_new (_ip_compare);
+ if (! _host_by_ip_tree) {
+ VSC__ERROR1 (error, VSC__ERROR_CODE__OUT_OF_MEMORY,
+ "Failed to setup host tree");
+ goto restore;
+ }
+
+ _vm_by_uuid_tree = g_tree_new (_uuid_compare);
+ if (! _vm_by_uuid_tree) {
+ VSC__ERROR1 (error, VSC__ERROR_CODE__OUT_OF_MEMORY,
+ "Failed to setup vm uuid tree");
+ goto restore;
+ }
+
+ _vm_by_ip_lookup_tree = g_tree_new (_ip_compare);
+ if (! _vm_by_ip_lookup_tree) {
+ VSC__ERROR1 (error, VSC__ERROR_CODE__OUT_OF_MEMORY,
+ "Failed to setup vm ipv4 tree");
+ goto restore;
+ }
+
+ /* Search for the 'hosts' entry */
+ for (child = node->children; child; child = child->next) {
+ if (child->type == XML_ELEMENT_NODE &&
+ xmlStrEqual (child->name, BAD_CAST "hosts")) {
+ hosts = child;
+ break;
+ }
+ }
+
+ if (! hosts) {
+ VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No <hosts> entry found.");
+ goto restore;
+ }
+
+ for (child = hosts->children; child; child = child->next) {
+ if (child->type == XML_ELEMENT_NODE &&
+ xmlStrEqual (child->name, BAD_CAST "host")) {
+ _read_host (error, child);
+ if (error->occured) {
+ goto restore;
+ }
+ }
+ }
+
+ return;
+
+restore:
+ _vsc_mgmt_data_recover_rollback ();
+}
+
+
+void
+_vsc_mgmt_data_recover_commit (void)
+{
+ if (_backup._vm_by_uuid_tree) {
+ g_tree_destroy (_backup._vm_by_uuid_tree);
+ }
+
+ if (_backup._vm_by_ip_lookup_tree) {
+ g_tree_foreach (_backup._vm_by_ip_lookup_tree, _vm_ip_lookup_tree_traverse_free, NULL);
+ g_tree_destroy (_backup._vm_by_ip_lookup_tree);
+ }
+
+ if (_backup._host_by_ip_tree) {
+ g_tree_foreach (_backup._host_by_ip_tree, _host_tree_traverse_free, NULL);
+ g_tree_destroy (_backup._host_by_ip_tree);
+ }
+
+ _backup._host_by_ip_tree = NULL;
+ _backup._vm_by_uuid_tree = NULL;
+ _backup._vm_by_ip_lookup_tree = NULL;
+}
+
+void
+_vsc_mgmt_data_recover_rollback (void)
+{
+ /* Cleanup the current trees (if any) but preserve the initialized flag */
+ _vsc_mgmt_data_cleanup ();
+ _data_initialized = 1;
+
+ _host_by_ip_tree = _backup._host_by_ip_tree;
+ _vm_by_uuid_tree = _backup._vm_by_uuid_tree;
+ _vm_by_ip_lookup_tree = _backup._vm_by_ip_lookup_tree;
- VSC__ERROR0 (error, VSC__ERROR_CODE__NOT_IMPLEMENTED_YET);
+ _backup._host_by_ip_tree = NULL;
+ _backup._vm_by_uuid_tree = NULL;
+ _backup._vm_by_ip_lookup_tree = NULL;
}
host_tree_elem = g_tree_lookup (_host_by_ip_tree, &vm->host_ip);
if (! host_tree_elem) {
VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
- "VM should belong to an unknown host.");
+ "VM cannot belong to an unknown host.");
return;
}
CFLAGS += $(shell pkg-config --cflags glib-2.0)
LDFLAGS += $(shell pkg-config --libs glib-2.0)
+# libxml
+CFLAGS += $(shell pkg-config libxml-2.0 --cflags)
+LDFLAGS += $(shell pkg-config libxml-2.0 --libs)
+
+
#
# Rules
#
*/
#include <errno.h>
-#include <inttypes.h>
#include <glib-2.0/glib.h>
#include <uuid/uuid.h>
#include <libvscmisc/assert.h>
#include <libvscmisc/error.h>
#include <libvscmisc/memory.h>
+#include <libvscmisc/string.h>
#include "../../../include/libvscmgmt/network.h"
+#include "../../../include/libvscmgmt/ipv4.h"
#include "../../../lib/core.h"
#include "../../../lib/ipv4.h"
+#include "../../../lib/mac.h"
#include "../../../lib/network.h"
#include "../../../lib/uuid.h"
#include "../../../lib/parser.h"
+#include "../../../lib/xml.h"
#include "../network.h"
#include "common.h"
+
+static struct _backup {
+ struct VscMgmtNetwork *_network_list_available;
+ struct VscMgmtNetwork *_network_list_used;
+
+ uint64_t _mac_base;
+ uint64_t _mac_last;
+
+ GTree *_mac_tree_available;
+ GTree *_mac_tree_used;
+} _backup;
+
+
static int _network_initialized = FALSE;
static struct VscMgmtNetwork *_network_list_available = NULL;
static struct VscMgmtNetwork *_network_list_used = NULL;
goto unlock;
}
- mac_tmp->bytes[0] = (mac_tmp_uint & 0xFF0000000000) >> 40;
- mac_tmp->bytes[1] = (mac_tmp_uint & 0x00FF00000000) >> 32;
- mac_tmp->bytes[2] = (mac_tmp_uint & 0x0000FF000000) >> 24;
- mac_tmp->bytes[3] = (mac_tmp_uint & 0x000000FF0000) >> 16;
- mac_tmp->bytes[4] = (mac_tmp_uint & 0x00000000FF00) >> 8;
- mac_tmp->bytes[5] = (mac_tmp_uint & 0x0000000000FF);
+ _vsc_mgmt_mac_from_uint (mac_tmp, mac_tmp_uint);
g_tree_insert (_mac_tree_available, (gpointer) mac_tmp,
(gpointer) mac_tmp);
}
+/*
+ * XML restore related functions
+ */
+static inline char *
+_get_content (const xmlNode *node)
+{
+ VSC__ASSERT (node != NULL);
+
+ if (node && node->children) {
+ return (char *) node->children->content;
+ } else {
+ return NULL;
+ }
+}
+
+
+static void
+_read_network (struct VscError *error, const xmlNode *xml_network,
+ int used)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (xml_network != NULL);
+
+ struct VscMgmtNetwork *network = NULL;
+
+ xmlNode *xml_child = NULL;
+ char *content;
+
+ /* Network information */
+ struct VscMgmtUuid uuid;
+ unsigned int i;
+ struct VscMgmtIpv4 ip_network;
+ int netmask = 0;
+ struct VscMgmtIpv4 gateway;
+
+ /* Network entries */
+ int id_read;
+ uint32_t entry_id;
+ enum VscMgmtIpStatus entry_status;
+ struct VscMgmtMac mac_tmp;
+
+ xmlNode *entries = NULL;
+ xmlNode *entry = NULL;
+
+ VSC__ASSERT (xmlStrEqual (xml_network->name, BAD_CAST "network"));
+
+ uuid_clear (uuid.value);
+
+ for (xml_child = xml_network->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ /*
+ * Forget about any previos content string and try to prefetch
+ * the new one
+ */
+ content = NULL;
+ content = _get_content (xml_child);
+
+ /* UUID */
+ if (xmlStrEqual (xml_child->name, BAD_CAST "uuid")) {
+ /* An unused network may not have an UUID */
+ if (! content && used == 0)
+ continue;
+
+ _vsc_mgmt_xml_parse_uuid (error, xml_child, &uuid, NULL);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* CIDR */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "cidr")) {
+ _vsc_mgmt_xml_parse_ipv4 (error, xml_child, &ip_network, &netmask);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Gateway */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "gateway")) {
+ _vsc_mgmt_xml_parse_ipv4 (error, xml_child, &gateway, NULL);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Entries */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "entries")) {
+ entries = xml_child;
+ }
+ }
+
+ /* If this network is a used one and there has to be an UUID in the backup */
+ if (used && uuid_is_null (uuid.value)) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No UUID 'used' network starting at line %i",
+ xml_network->line);
+ goto failure;
+ }
+
+
+ /* _vsc_mgmt_network_new() will validate the parameters */
+ network = _vsc_mgmt_network_new (error, &ip_network, netmask, &gateway);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+ memcpy (&network->uuid.value, uuid.value, sizeof (uuid_t));
+
+
+ /* Read the network entries and store them directly */
+ for (entry = entries->children; entry; entry = entry->next) {
+ if (entry->type != XML_ELEMENT_NODE)
+ continue;
+
+ /* Reset temp vars */
+ id_read = 0;
+ entry_status = VSC_MGMT__IP_STATUS__UNDEFINED;
+ _vsc_mgmt_mac_clear (&mac_tmp);
+
+ for (xml_child = entry->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ /*
+ * Forget about any previos content string and try to prefetch
+ * the new one
+ */
+ content = NULL;
+ content = _get_content (xml_child);
+
+
+ if (xmlStrEqual (xml_child->name, BAD_CAST "id")) {
+ _vsc_mgmt_xml_parse_uint (error, xml_child, &entry_id, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+ id_read = 1;
+ }
+
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "status")) {
+ if (! content) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No value for 'status' at line %i",
+ xml_child->line);
+ goto failure;
+ }
+
+ entry_status = vsc_strtoi (error, content, NULL, 10);
+ if (error->occured || entry_status < 1 || entry_status > 4) {
+ VSC__APPEND_ERROR2 (error, VSC__ERROR_CODE__TRACE,
+ "Invalid value for 'status' at line %i: %s",
+ xml_child->line, content);
+ goto failure;
+ }
+ }
+
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "mac")) {
+ if (! content) {
+ /* Maybe we read the MAC before the status
+ * so it's not possible to decide wether
+ * a MAC is neccessary here.
+ */
+ continue;
+ }
+
+ _vsc_mgmt_mac_parse (error, content, &mac_tmp);
+ if (error->occured || ! _vsc_mgmt_mac_is_valid (&mac_tmp)) {
+ VSC__APPEND_ERROR2 (error, VSC__ERROR_CODE__TRACE,
+ "Invalid value for 'status' at line %i: %s",
+ xml_child->line, content);
+ goto failure;
+ }
+
+ }
+ } /* for each entry element */
+
+
+ if (! id_read || entry_status == VSC_MGMT__IP_STATUS__UNDEFINED) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Invalid entry starting at line %i",
+ entry->line);
+ goto failure;
+ }
+
+ network->ip_status[entry_id] = entry_status;
+
+ if (entry_status > 1) {
+ network->num_ips_free--;
+ }
+
+ if (entry_status == VSC_MGMT__IP_STATUS__IN_USE) {
+ if (_vsc_mgmt_mac_is_valid (&mac_tmp)) {
+ memcpy (&network->macs[entry_id], &mac_tmp, sizeof (struct VscMgmtMac));
+ } else {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No or invalid MAC in entry starting at line %i",
+ entry->line);
+ goto failure;
+ }
+ }
+ } /* for each entry */
+
+
+ /* Check if any entry was missing */
+ for (entry_id = 0; entry_id < network->size; entry_id++) {
+ if (network->ip_status[i] == VSC_MGMT__IP_STATUS__UNDEFINED) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Missing entry information for entry #%i",
+ entry_id);
+ goto failure;
+ }
+ }
+
+ /* Append this network to the correct list */
+ if (used) {
+ _vsc_mgmt_network_list_append (&_network_list_used, network);
+ } else {
+ _vsc_mgmt_network_list_append (&_network_list_available, network);
+ }
+
+ return;
+
+failure:
+ _vsc_mgmt_network_free (&network);
+}
+
+
+static void
+_read_networks (struct VscError *error, const xmlNode *xml_networks)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (xml_networks != NULL);
+
+ xmlNode *child = NULL;
+ xmlNode *network = NULL;
+
+ VSC__ASSERT (xmlStrEqual (xml_networks->name, BAD_CAST "networks"));
+
+ for (child = xml_networks->children; child; child = child->next) {
+ if (child->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrEqual (child->name, BAD_CAST "available")) {
+ for (network = child->children; network; network = network->next) {
+ if (network->type != XML_ELEMENT_NODE)
+ continue;
+
+ /* Maybe this should be handled as error */
+ if (! xmlStrEqual (network->name, BAD_CAST "network"))
+ continue;
+
+ /* Read an available (un-used) network */
+ _read_network (error, network, 0);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+ }
+
+ else if (xmlStrEqual (child->name, BAD_CAST "used")) {
+ for (network = child->children; network; network = network->next) {
+ if (network->type != XML_ELEMENT_NODE)
+ continue;
+
+ /* Maybe this should be handled as error */
+ if (! xmlStrEqual (network->name, BAD_CAST "network"))
+ continue;
+
+ /* Read an used network */
+ _read_network (error, network, 1);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+ }
+ }
+
+ return;
+
+failure:
+ return;
+}
+
+
+static void
+_read_macs (struct VscError *error, const xmlNode *xml_macs)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (xml_macs != NULL);
+
+ xmlNode *child = NULL;
+ xmlNode *available_macs = NULL;
+ char *content;
+ struct VscMgmtMac mac_tmp;
+ struct VscMgmtMac *mac;
+
+ VSC__ASSERT (xmlStrEqual (xml_macs->name, BAD_CAST "macs"));
+
+ /* Get available macs tag */
+ for (child = xml_macs->children; child; child = child->next) {
+ if (child->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrEqual (child->name, BAD_CAST "available")) {
+ available_macs = child;
+ }
+ }
+
+ if (! available_macs) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Available macs missing in macs entry at line %i",
+ xml_macs->line);
+ goto failure;
+ }
+
+ for (child = available_macs->children; child; child = child->next) {
+ if (child->type != XML_ELEMENT_NODE)
+ continue;
+
+ content = NULL;
+ content = _get_content (child);
+
+ if (xmlStrEqual (child->name, BAD_CAST "mac")) {
+ _vsc_mgmt_xml_parse_mac (error, child, &mac_tmp);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+ /* Ok, seems to ba valid, store it */
+ mac = NULL;
+ mac = vsc_alloc (error, sizeof (struct VscMgmtMac));
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+ /* Copy Mac address */
+ memcpy (mac, &mac_tmp, sizeof (struct VscMgmtMac));
+
+ g_tree_insert (_mac_tree_available, (gpointer) mac,
+ (gpointer) mac);
+ }
+ }
+
+ return;
+
+failure:
+ return;
+}
+
+
+
/*******************************************************************************
* private API functions *
******************************************************************************/
{
struct VscMgmtNetwork *net = NULL;
char network_uuid[VSC_MGMT__UUID__STRING_SIZE];
+ struct VscMgmtMac mac_tmp;
unsigned int netmask;
uint32_t i;
/* <network> */
fprintf (fp, " <common>\n");
- fprintf (fp, " <mac_base>%"PRIu64"</mac_base>\n", _mac_base);
- fprintf (fp, " <mac_last>%"PRIu64"</mac_last>\n", _mac_last);
+
+ _vsc_mgmt_mac_from_uint (&mac_tmp, _mac_base);
+ fprintf (fp, " <mac_base>%02x:%02x:%02x:%02x:%02x:%02x</mac_base>\n",
+ mac_tmp.bytes[0], mac_tmp.bytes[1],mac_tmp.bytes[2],
+ mac_tmp.bytes[3], mac_tmp.bytes[4],mac_tmp.bytes[5]);
+
+ _vsc_mgmt_mac_from_uint (&mac_tmp, _mac_last);
+ fprintf (fp, " <mac_last>%02x:%02x:%02x:%02x:%02x:%02x</mac_last>\n",
+ mac_tmp.bytes[0], mac_tmp.bytes[1],mac_tmp.bytes[2],
+ mac_tmp.bytes[3], mac_tmp.bytes[4],mac_tmp.bytes[5]);
/*
* Backup networks
uuid_unparse (net->uuid.value, network_uuid);
fprintf (fp, " <network>\n");
+ fprintf (fp, " <uuid>%s</uuid>\n", network_uuid);
+
netmask = _vsc_mgmt_network_mask_from_bits (net->cidr_mask);
fprintf (fp, " <cidr>%u.%u.%u.%u/%u</cidr>\n",
(net->cidr_network & 0xFF000000) >> 24,
uuid_unparse (net->uuid.value, network_uuid);
fprintf (fp, " <network>\n");
- fprintf (fp, " <cidr>%"PRIu32"/%"PRIu32"</cidr>\n",
- net->cidr_network, net->cidr_mask);
+ netmask = _vsc_mgmt_network_mask_from_bits (net->cidr_mask);
+ fprintf (fp, " <cidr>%u.%u.%u.%u/%u</cidr>\n",
+ (net->cidr_network & 0xFF000000) >> 24,
+ (net->cidr_network & 0x00FF0000) >> 16,
+ (net->cidr_network & 0x0000FF00) >> 8,
+ (net->cidr_network & 0x000000FF),
+ netmask);
fprintf (fp, " <gateway>%u.%u.%u.%u</gateway>\n",
net->gateway_ip.bytes[0], net->gateway_ip.bytes[1],
void
+_vsc_mgmt_network_common_recover_start (struct VscError *error,
+ const xmlNode *node)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (_network_initialized);
+ VSC__ASSERT (node != NULL);
+
+ VSC__ASSERT (xmlStrEqual (node->name, BAD_CAST "common"));
+
+ xmlNode *child = NULL;
+ char *content = NULL;
+
+ struct VscMgmtMac mac_tmp;
+
+ /* Save pointers to the current trees and lists */
+ _backup._network_list_available = _network_list_available;
+ _backup._network_list_used = _network_list_used;
+ _backup._mac_base = _mac_base;
+ _backup._mac_last = _mac_last;
+ _backup._mac_tree_available = _mac_tree_available;
+ _backup._mac_tree_used = _mac_tree_used;
+
+ /*
+ * Clear the current pointers so it's save to use the cleanup()
+ * function if anything fails
+ */
+ _network_list_available = NULL;
+ _network_list_used = NULL;
+ _mac_base = 0;
+ _mac_last = 0;
+ _mac_tree_available = NULL;
+ _mac_tree_used = NULL;
+
+ /* Set up new trees */
+ _mac_tree_available = g_tree_new (_mac_compare);
+ if (! _mac_tree_available) {
+ VSC__ERROR1 (error, VSC__ERROR_CODE__OUT_OF_MEMORY,
+ "Failed to setup mac tree");
+ goto restore;
+ }
+
+ _mac_tree_used = g_tree_new (_mac_compare);
+ if (! _mac_tree_used) {
+ VSC__ERROR1 (error, VSC__ERROR_CODE__OUT_OF_MEMORY,
+ "Failed to setup mac tree");
+ goto restore;
+ }
+
+
+
+ /* Read data from XML backup file */
+ for (child = node->children; child; child = child->next) {
+ if (child->type != XML_ELEMENT_NODE)
+ continue;
+
+ content = NULL;
+
+ if (xmlStrEqual (child->name, BAD_CAST "mac_base")) {
+ content = _get_content (child);
+ _vsc_mgmt_mac_parse (error, content, &mac_tmp);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto restore;
+ }
+
+ _mac_base = _vsc_mgmt_mac_to_uint (&mac_tmp);
+ }
+
+ else if (xmlStrEqual (child->name, BAD_CAST "mac_last")) {
+ content = _get_content (child);
+ _vsc_mgmt_mac_parse (error, content, &mac_tmp);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto restore;
+ }
+
+ _mac_last = _vsc_mgmt_mac_to_uint (&mac_tmp);
+ }
+
+ else if (xmlStrEqual (child->name, BAD_CAST "networks")) {
+ _read_networks (error, child);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto restore;
+ }
+ }
+
+ else if (xmlStrEqual (child->name, BAD_CAST "macs")) {
+ _read_macs (error, child);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto restore;
+ }
+ }
+ }
+
+ return;
+
+restore:
+ _vsc_mgmt_network_common_recover_rollback ();
+}
+
+
+
+void
+_vsc_mgmt_network_common_recover_rollback (void)
+{
+ /* Cleanup the current trees/lists (if any) but preserve the initialized flag */
+ _vsc_mgmt_network_common_cleanup ();
+ _network_initialized = TRUE;
+
+ _network_list_available = _backup._network_list_available;
+ _network_list_used = _backup._network_list_used;
+
+ _mac_base = _backup._mac_base;
+ _mac_last = _backup._mac_last;
+
+ _mac_tree_available = _backup._mac_tree_available;
+ _mac_tree_used = _backup._mac_tree_used;
+
+
+ /* Clear all the backup pointers */
+ _backup._network_list_available = NULL;
+ _backup._network_list_used = NULL;
+
+ _backup._mac_base = 0;
+ _backup._mac_last = 0;
+
+ _backup._mac_tree_available = NULL;
+ _backup._mac_tree_used = NULL;
+
+}
+
+
+
+void
+_vsc_mgmt_network_common_recover_commit (void)
+{
+ /* Forget about all backups */
+ _vsc_mgmt_network_list_free (&_backup._network_list_available);
+ _vsc_mgmt_network_list_free (&_backup._network_list_used);
+
+ if (_backup._mac_tree_available) {
+ g_tree_foreach (_backup._mac_tree_available, _mac_tree_traverse_free, NULL);
+ g_tree_destroy (_backup._mac_tree_available);
+ }
+
+ if (_backup._mac_tree_used) {
+ g_tree_foreach (_backup._mac_tree_used, _mac_tree_traverse_free, NULL);
+ g_tree_destroy (_backup._mac_tree_used);
+ }
+
+ /* Clear all the backup pointers */
+ _backup._network_list_available = NULL;
+ _backup._network_list_used = NULL;
+
+ _backup._mac_base = 0;
+ _backup._mac_last = 0;
+
+ _backup._mac_tree_available = NULL;
+ _backup._mac_tree_used = NULL;
+}
+
+
+
+void
_vsc_mgmt_network_common_synchronize (struct VscError *error)
{
VSC__ASSERT (error != NULL);
}
+enum VscMgmtIpStatus *
+_vsc_mgmt_network_common_get_ip_status (struct VscError *error,
+ const struct VscMgmtUuid *network_uuid)
+{
+ struct VscMgmtNetwork *network_temp;
+
+ enum VscMgmtIpStatus *ip_status = NULL;
+
+ VSC__ASSERT (error);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (_network_initialized);
+ VSC__ASSERT (network_uuid);
+
+ network_temp = _vsc_mgmt_network_list_lookup (_network_list_used, network_uuid);
+ if (! network_temp) {
+ VSC__ERROR1 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Invalid network uuid.");
+ return NULL;
+ }
+
+ ip_status = vsc_alloc (error, network_temp->size * sizeof (enum VscMgmtIpStatus));
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ return NULL;
+ }
+
+ memcpy (ip_status, network_temp->ip_status,
+ network_temp->size * sizeof (*network_temp->ip_status));
+
+ return ip_status;
+}
+
/*!
#ifndef __VSC_MGMT__BACKEND__COMMON_H__
#define __VSC_MGMT__BACKEND__COMMON_H__
+#include <libxml/tree.h>
+
#include "../../../lib/network.h"
void
_vsc_mgmt_network_common_backup (struct VscError *error, FILE *fp);
void
+_vsc_mgmt_network_common_recover_start (struct VscError *error,
+ const xmlNode *node);
+
+void
+_vsc_mgmt_network_common_recover_rollback (void);
+
+void
+_vsc_mgmt_network_common_recover_commit (void);
+
+void
_vsc_mgmt_network_common_synchronize (struct VscError *error);
void
struct VscMgmtNetwork *network,
const struct VscMgmtUuid *network_uuid);
+enum VscMgmtIpStatus *
+_vsc_mgmt_network_common_get_ip_status (struct VscError *error,
+ const struct VscMgmtUuid *network_uuid);
+
void
_vsc_mgmt_network_common_teardown (struct VscError *error,
const struct VscMgmtUuid *network_uuid);
# network backend common library
LDFLAGS += -L ../common -lvscmgmt-network-common
+# libxml
+CFLAGS += $(shell pkg-config libxml-2.0 --cflags)
+LDFLAGS += $(shell pkg-config libxml-2.0 --libs)
+
#
# Rules
#
#include <time.h>
#include <unistd.h>
+#include <uuid/uuid.h>
+
#include <libvscmisc/assert.h>
#include <libvscmisc/error.h>
#include <libvscmisc/memory.h>
+#include <libvscmisc/string.h>
#include "../../../lib/core.h" /* locking */
-#include "../../../lib/uuid.h"
#include "../../../lib/ipv4.h"
+#include "../../../lib/mac.h"
+#include "../../../lib/uuid.h"
+#include "../../../lib/xml.h"
#include "../../../include/libvscmgmt/uuid.h"
#include "../common/common.h"
enum DhcpIpStatus {
- _DHCP_IP_STATUS__FREE = 0,
+ _DHCP_IP_STATUS__UNDEFINED = 0,
+ _DHCP_IP_STATUS__RESERVED,
+ _DHCP_IP_STATUS__FREE,
_DHCP_IP_STATUS__IN_USE,
};
struct VscMgmtUuid *uuids;
};
+static struct _backup {
+ struct DhcpNetwork *_active_network_list;
+} _backup;
+
static int _network_initialized = FALSE;
}
+static void
+_dhcp_network_free (struct DhcpNetwork **network)
+{
+ if (network == NULL || *network == NULL) {
+ return;
+ }
+
+ vsc_free (&(*network)->macs);
+ vsc_free (&(*network)->ip_status);
+ vsc_free (&(*network)->uuid);
+ vsc_free (network);
+}
+
+
static struct DhcpNetwork *
_dhcp_network_new (struct VscError *error,
const struct VscMgmtNetwork *vsc_network)
{
- struct DhcpNetwork *dhcp_network;
+ struct DhcpNetwork *dhcp_network = NULL;
+ uint32_t i;
+ enum VscMgmtIpStatus *ip_status = NULL;
VSC__ASSERT (error != NULL);
VSC__ASSERT (! error->occured);
dhcp_network = vsc_alloc (error, sizeof (struct DhcpNetwork));
if (error->occured) {
VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
- return NULL;
+ goto out_free;
+ }
+
+ /* Query the IP status informaton of the network */
+ ip_status = _vsc_mgmt_network_common_get_ip_status (error, &vsc_network->uuid);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto out_free;
}
/* To be safe in 'out_free' case */
dhcp_network->next = NULL;
dhcp_network->uuid = NULL;
+ dhcp_network->ip_status = NULL;
dhcp_network->macs = NULL;
dhcp_network->uuid = _vsc_mgmt_uuid_clone (error, &vsc_network->uuid);
dhcp_network->num_ips_active = 0;
+ for (i = 0; i < vsc_network->size; i++) {
+ if (ip_status[i] == VSC_MGMT__IP_STATUS__RESERVED) {
+ dhcp_network->ip_status[i] = _DHCP_IP_STATUS__RESERVED;
+ } else {
+ dhcp_network->ip_status[i] = _DHCP_IP_STATUS__FREE;
+ }
+
+ /*
+ * Ignore all other values here as they are not relevant when setting
+ * a new network and should be set correctly in recover case and can
+ * be easily validated then.
+ */
+ }
+
return dhcp_network;
out_free:
- vsc_free (&dhcp_network->macs);
- vsc_free (&dhcp_network->ip_status);
- vsc_free (&dhcp_network->uuid);
- vsc_free (&dhcp_network);
+ vsc_free (&ip_status);
+
+ _dhcp_network_free (&dhcp_network);
return NULL;
}
-
static inline struct DhcpNetwork *
_dhcp_network_lookup (const struct VscMgmtUuid *uuid)
{
+/*
+ * XML related stuff
+ */
+
+static char *
+_get_content (const xmlNode *node)
+{
+ VSC__ASSERT (node != NULL);
+
+ if (node->children && node->children->content)
+ return (char *) node->children->content;
+ else
+ return NULL;
+}
+
+
+
+static void
+_read_network (struct VscError *error, const xmlNode *xml_network)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (xml_network != NULL);
+
+ struct VscMgmtNetwork mgmt_network;
+ struct DhcpNetwork *dhcp_network = NULL;
+ struct DhcpNetwork *dhcp_network_loop = NULL;
+
+ xmlNode *xml_child = NULL;
+ char *content;
+
+ /* Network information */
+ struct VscMgmtUuid network_uuid;
+
+ /* Network entries */
+ int id_read;
+ uint32_t entry_id;
+ int entry_status_temp;
+ enum DhcpIpStatus entry_status;
+ struct VscMgmtMac mac_tmp;
+ struct VscMgmtUuid vm_uuid;
+
+ xmlNode *entries = NULL;
+ xmlNode *entry = NULL;
+
+ VSC__ASSERT (xmlStrEqual (xml_network->name, BAD_CAST "network"));
+
+ uuid_clear (network_uuid.value);
+
+ for (xml_child = xml_network->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ /* UUID */
+ if (xmlStrEqual (xml_child->name, BAD_CAST "uuid")) {
+ _vsc_mgmt_xml_parse_uuid (error, xml_child, &network_uuid, NULL);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* Entries */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "entries")) {
+ entries = xml_child;
+ }
+ }
+
+ /* Check is there is a UUID */
+ if (uuid_is_null (network_uuid.value)) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No UUID for network starting at line %i",
+ xml_network->line);
+ goto failure;
+ }
+
+ /* Query the network information from the common backend */
+ _vsc_mgmt_network_common_getinfo (error, &mgmt_network, &network_uuid);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+ /* Set up a DHCP network */
+ dhcp_network = _dhcp_network_new (error, &mgmt_network);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+
+ /* Read the network entries and store them directly */
+ for (entry = entries->children; entry; entry = entry->next) {
+ if (entry->type != XML_ELEMENT_NODE)
+ continue;
+
+ /* Reset temp vars */
+ id_read = 0;
+ entry_status = _DHCP_IP_STATUS__UNDEFINED;
+ uuid_clear (vm_uuid.value);
+ _vsc_mgmt_mac_clear (&mac_tmp);
+
+ for (xml_child = entry->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ /*
+ * Forget about any previos content string and try to prefetch
+ * the new one
+ */
+ content = NULL;
+ content = _get_content (xml_child);
+
+
+ /* ID */
+ if (xmlStrEqual (xml_child->name, BAD_CAST "id")) {
+ _vsc_mgmt_xml_parse_uint (error, xml_child, &entry_id, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+
+ id_read = 1;
+ }
+
+ /* Status */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "status")) {
+ _vsc_mgmt_xml_parse_int (error, xml_child, &entry_status_temp, 10);
+ if (error->occured) {
+ VSC__APPEND_ERROR2 (error, VSC__ERROR_CODE__TRACE,
+ "Invalid value for 'status' at line %i: %s",
+ xml_child->line, content);
+ goto failure;
+ }
+ if (entry_status_temp < 0 || entry_status_temp > 3) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__TRACE,
+ "Invalid value for 'status' at line %i: %s",
+ xml_child->line, content);
+ goto failure;
+ }
+
+ entry_status = entry_status_temp;
+ }
+
+ /* MAC */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "mac")) {
+ if (! content) {
+ /* Maybe we read the MAC before the status
+ * so it's not possible to decide wether
+ * a MAC is neccessary here.
+ */
+ continue;
+ }
+
+ _vsc_mgmt_xml_parse_mac (error, xml_child, &mac_tmp);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+
+ /* VM UUID */
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "vm_uuid")) {
+ _vsc_mgmt_xml_parse_uuid (error, xml_child, &vm_uuid, NULL);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto failure;
+ }
+ }
+ } /* for each entry element */
+
+
+ if (! id_read || entry_status == _DHCP_IP_STATUS__UNDEFINED) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Invalid entry starting at line %i",
+ entry->line);
+ goto failure;
+ }
+
+ dhcp_network->ip_status[entry_id] = entry_status;
+
+ if (entry_status == _DHCP_IP_STATUS__IN_USE) {
+ dhcp_network->num_ips_active++;
+
+ if (_vsc_mgmt_mac_is_valid (&mac_tmp)) {
+ memcpy (&dhcp_network->macs[entry_id], &mac_tmp, sizeof (struct VscMgmtMac));
+ } else {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No or invalid MAC in entry starting at line %i",
+ entry->line);
+ goto failure;
+ }
+
+ if (! uuid_is_null (vm_uuid.value)) {
+ memcpy (&dhcp_network->uuids[entry_id], &vm_uuid, sizeof (struct VscMgmtUuid));
+ } else {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "No or invalid VM UUID in entry starting at line %i",
+ entry->line);
+ goto failure;
+ }
+ }
+ } /* for each entry */
+
+
+ /* Check if any entry was missing */
+ for (entry_id = 0; entry_id < dhcp_network->size; entry_id++) {
+ if (dhcp_network->ip_status[entry_id] == _DHCP_IP_STATUS__UNDEFINED) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Missing entry information for entry #%i",
+ entry_id);
+ goto failure;
+ }
+ }
+
+ /* Append this network to our list */
+ if (_active_network_list) {
+ dhcp_network_loop = _active_network_list;
+
+ while (dhcp_network_loop->next) {
+ dhcp_network_loop = dhcp_network_loop->next;
+ }
+
+ dhcp_network_loop->next = dhcp_network;
+ } else {
+ _active_network_list = dhcp_network;
+ }
+
+
+ return;
+
+failure:
+ _dhcp_network_free (&dhcp_network);
+}
+
+
/*******************************************************************************
* Public API functions *
******************************************************************************/
{
struct DhcpNetwork *network = NULL;
char uuid_string[VSC_MGMT__UUID__STRING_SIZE];
- unsigned int netmask = 0;
uint32_t i;
VSC__ASSERT (error != NULL);
fprintf (fp, " <network>\n");
vsc_mgmt_uuid_format (network->uuid, uuid_string);
- netmask = _vsc_mgmt_network_mask_from_bits (network->cidr_mask);
-
fprintf (fp, " <uuid>%s</uuid>\n", uuid_string);
- fprintf (fp, " <cidr>%u.%u.%u.%u/%u</cidr>\n",
- (network->cidr_network & 0xFF000000) >> 24,
- (network->cidr_network & 0x00FF0000) >> 16,
- (network->cidr_network & 0x0000FF00) >> 8,
- (network->cidr_network & 0x000000FF),
- netmask);
+ /* The UUID is enough to identify this network in the common backend */
fprintf (fp, " <entries>\n");
for (i = 0; i < network->size; i++) {
}
+void
+_vsc_mgmt_network_recover_start (struct VscError *error, const xmlNode *node)
+{
+ VSC__ASSERT (error != NULL);
+ VSC__ASSERT (! error->occured);
+ VSC__ASSERT (node != NULL);
+
+ xmlNode *xml_child = NULL;
+ xmlNode *dhcp_only = NULL;
+
+ VSC__ASSERT (xmlStrEqual (node->name, BAD_CAST "network"));
+
+ /* Save pointer to the network list and clear current one */
+ _backup._active_network_list = _active_network_list;
+ _active_network_list = NULL;
+
+ /* Search for network subnodes and parse them */
+ for (xml_child = node->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrEqual (xml_child->name, BAD_CAST "common")) {
+ _vsc_mgmt_network_common_recover_start (error, xml_child);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto restore;
+ }
+ }
+
+ else if (xmlStrEqual (xml_child->name, BAD_CAST "dhcponly")) {
+ dhcp_only = xml_child;
+ }
+ }
+
+ /* Parse all our networks */
+ for (xml_child = dhcp_only->children; xml_child; xml_child = xml_child->next) {
+ if (xml_child->type != XML_ELEMENT_NODE)
+ continue;
+
+ if (xmlStrEqual (xml_child->name, BAD_CAST "network")) {
+ _read_network (error, xml_child);
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto restore;
+ }
+ }
+ }
+
+ return;
+
+restore:
+ _vsc_mgmt_network_recover_rollback ();
+ return;
+}
+
+
+
+void
+_vsc_mgmt_network_recover_commit (void)
+{
+}
+
+
+
+void
+_vsc_mgmt_network_recover_rollback (void)
+{
+}
+
void
_vsc_mgmt_network_synchronize (struct VscError *error)
#ifndef __VSC_MGMT__BACKEND__NETWORK_H__
#define __VSC_MGMT__BACKEND__NETWORK_H__
+#include <libxml/tree.h>
+
#include "../../lib/network.h"
#include "../../include/libvscmgmt/network.h"
_vsc_mgmt_network_backup (struct VscError *error, FILE *fp);
void
+_vsc_mgmt_network_recover_start (struct VscError *error, const xmlNode *node);
+
+void
+_vsc_mgmt_network_recover_commit (void);
+
+void
+_vsc_mgmt_network_recover_rollback (void);
+
+void
_vsc_mgmt_network_synchronize (struct VscError *error);
}
void
-vsc_mgmt_recover (struct VscError *error, const char *filename VSC__ATTR__UNUSED)
+vsc_mgmt_recover (struct VscError *error, const char *filename)
{
VSC__ASSERT (error != NULL);
VSC__ASSERT (! error->occured);
+ VSC__ASSERT (filename != NULL);
+
+ xmlDoc *doc = NULL;
+ xmlNode *root = NULL;
+ xmlNode *child = NULL;
_IF_NOT_INITIALIZED (return);
_vsc_mgmt_lock();
- /* FIXME: Implement recover */
+ /* Parse the backup file and get the DOM */
+ doc = xmlReadFile (filename, NULL, 0);
+ if (! doc) {
+ VSC__ERROR2 (error, VSC__ERROR_CODE__INVALID_ARGUMENT,
+ "Failed to parse backup file \"%s\"", filename);
+ return;
+ }
- if (error->occured) {
- VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
- goto unlock;
+ root = xmlDocGetRootElement (doc);
+
+ for (child = root->children; child; child = child->next) {
+ if (child->type == XML_ELEMENT_NODE) {
+ if (xmlStrEqual (child->name, BAD_CAST "data")) {
+ _vsc_mgmt_data_recover_start (error, child);
+ }
+
+ else if (xmlStrEqual (child->name, BAD_CAST "network")) {
+ _vsc_mgmt_network_recover_start (error, child);
+ }
+
+ if (error->occured) {
+ VSC__APPEND_ERROR0 (error, VSC__ERROR_CODE__TRACE);
+ goto unlock;
+ }
+ }
}
+ /*
+ * Validate our new world view
+ */
+
+ _vsc_mgmt_data_recover_commit ();
+
+ _vsc_mgmt_network_recover_commit ();
+
unlock:
_vsc_mgmt_unlock();
}
ip_index = gateway_uint - network_uint;
network->ip_status[ip_index] = VSC_MGMT__IP_STATUS__RESERVED;
+ /* Free IPs = All IPs - (network_address + broadcast_address + gateway) */
+ network->num_ips_free = network->size - 3;
return network;
out_free:
- vsc_free (&network->ips);
- vsc_free (&network->ip_status);
- vsc_free (&network);
+ _vsc_mgmt_network_free (&network);
return NULL;
}
enum VscMgmtIpStatus {
VSC_MGMT__IP_STATUS__UNDEFINED = 0,
- VSC_MGMT__IP_STATUS__FREE,
- VSC_MGMT__IP_STATUS__ACQUIRED,
- VSC_MGMT__IP_STATUS__IN_USE,
- VSC_MGMT__IP_STATUS__RESERVED,
+ VSC_MGMT__IP_STATUS__FREE = 1,
+ VSC_MGMT__IP_STATUS__ACQUIRED = 2,
+ VSC_MGMT__IP_STATUS__IN_USE = 3,
+ VSC_MGMT__IP_STATUS__RESERVED = 4,
};
# libvscmgmt
LDFLAGS += $(LIBVSCMGMT_LDFLAGS_L2)
+# libxml
+CFLAGS += $(shell pkg-config libxml-2.0 --cflags)
+LDFLAGS += $(shell pkg-config libxml-2.0 --libs)
+
+
#
# Rules
#