Changes:
- Throw an error after parsing if nets were specified and NETNS support
is not present
diff -r 203dce381784 -r bb48967cf19e src/lxc_conf.c
--- a/src/lxc_conf.c Mon Jun 23 11:53:42 2008 -0700
+++ b/src/lxc_conf.c Mon Jun 23 11:53:45 2008 -0700
@@ -69,6 +69,190 @@
__virRaiseError(conn, dom, NULL, VIR_FROM_LXC, code, VIR_ERR_ERROR,
codeErrorMessage, errorMessage, NULL, 0, 0,
codeErrorMessage, errorMessage);
+}
+
+/**
+ * lxcParseInterfaceXML:
+ * @conn: pointer to connection
+ * @nodePtr: pointer to xml node structure
+ * @vm: pointer to net definition structure to fill in
+ *
+ * Parses the XML for a network interface and places the configuration
+ * in the given structure.
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcParseInterfaceXML(virConnectPtr conn, xmlNodePtr nodePtr,
+ lxc_net_def_t *netDef)
+{
+ int rc = -1;
+ xmlNodePtr cur;
+ xmlChar *type = NULL;
+ xmlChar *parentIfName = NULL;
+ xmlChar *network = NULL;
+ xmlChar *bridge = NULL;
+ xmlChar *macaddr = NULL;
+
+ netDef->type = LXC_NET_NETWORK;
+
+ type = xmlGetProp(nodePtr, BAD_CAST "type");
+ if (type != NULL) {
+ if (xmlStrEqual(type, BAD_CAST "network")) {
+ netDef->type = LXC_NET_NETWORK;
+ }
+ else if (xmlStrEqual(type, BAD_CAST "bridge")) {
+ netDef->type = LXC_NET_BRIDGE;
+ }
+ else {
+ lxcError(conn, NULL, VIR_ERR_XML_ERROR,
+ _("invalid interface type: %s"), type);
+ goto error_out;
+ }
+ }
+
+ cur = nodePtr->children;
+ for (cur = nodePtr->children; cur != NULL; cur = cur->next) {
+ if (cur->type == XML_ELEMENT_NODE) {
+ DEBUG("cur->name: %s", (char*)(cur->name));
+ if ((macaddr == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "mac"))) {
+ macaddr = xmlGetProp(cur, BAD_CAST "address");
+ } else if ((network == NULL) &&
+ (netDef->type == LXC_NET_NETWORK) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ network = xmlGetProp(cur, BAD_CAST "network");
+ parentIfName = xmlGetProp(cur, BAD_CAST "dev");
+ } else if ((bridge == NULL) &&
+ (netDef->type == LXC_NET_BRIDGE) &&
+ (xmlStrEqual(cur->name, BAD_CAST "source"))) {
+ bridge = xmlGetProp(cur, BAD_CAST "bridge");
+ } else if ((parentIfName == NULL) &&
+ (xmlStrEqual(cur->name, BAD_CAST "target"))) {
+ parentIfName = xmlGetProp(cur, BAD_CAST "dev");
+ }
+ }
+ }
+
+ if (netDef->type == LXC_NET_NETWORK) {
+ if (network == NULL) {
+ lxcError(conn, NULL, VIR_ERR_XML_ERROR,
+ _("No <source> 'network' attribute specified with
<interface type='network'/>"));
+ goto error_out;
+ }
+
+ netDef->txName = strdup((char *)network);
+ if (NULL == netDef->txName) {
+ lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
+ _("No storage for network name"));
+ goto error_out;
+ }
+
+ } else if (netDef->type == LXC_NET_BRIDGE) {
+ if (bridge == NULL) {
+ lxcError(conn, NULL, VIR_ERR_XML_ERROR,
+ _("No <source> 'bridge' attribute specified with
<interface type='bridge'/>"));
+ goto error_out;
+ }
+
+ netDef->txName = strdup((char *)bridge);
+ if (NULL == netDef->txName) {
+ lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
+ _("No storage for bridge name"));
+ goto error_out;
+ }
+ }
+
+ if (parentIfName != NULL) {
+ DEBUG("set netDef->parentVeth: %s", netDef->parentVeth);
+ netDef->parentVeth = strdup((char *)parentIfName);
+ if (NULL == netDef->parentVeth) {
+ lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
+ _("No storage for parent veth device name"));
+ goto error_out;
+ }
+ } else {
+ netDef->parentVeth = NULL;
+ DEBUG0("set netDef->parentVeth: NULL");
+ }
+
+ rc = 0;
+
+error_out:
+ xmlFree(macaddr);
+ macaddr = NULL;
+ xmlFree(network);
+ network = NULL;
+ xmlFree(bridge);
+ bridge = NULL;
+ xmlFree(parentIfName);
+ parentIfName = NULL;
+
+ return rc;
+}
+
+/**
+ * lxcParseDomainInterfaces:
+ * @conn: pointer to connection
+ * @nets: on success, points to an list of net def structs
+ * @contextPtr: pointer to xml context
+ *
+ * Parses the domain network interfaces and returns the information in a list
+ *
+ * Returns 0 on success or -1 in case of error
+ */
+static int lxcParseDomainInterfaces(virConnectPtr conn,
+ lxc_net_def_t **nets,
+ xmlXPathContextPtr contextPtr)
+{
+ lxc_driver_t *driver = conn->privateData;
+ int rc = -1;
+ int i;
+ lxc_net_def_t *netDef;
+ lxc_net_def_t *prevDef = NULL;
+ int numNets = 0;
+ xmlNodePtr *list;
+ int res;
+
+ DEBUG0("parsing nets");
+
+ res = virXPathNodeSet("/domain/devices/interface", contextPtr, &list);
+ if (res > 0) {
+ for (i = 0; i < res; ++i) {
+ netDef = calloc(1, sizeof(lxc_net_def_t));
+ if (NULL == netDef) {
+ lxcError(conn, NULL, VIR_ERR_NO_MEMORY,
+ _("No storage for net def structure"));
+ goto parse_complete;
+ }
+
+ rc = lxcParseInterfaceXML(conn, list[i], netDef);
+ if (0 > rc) {
+ DEBUG("failed parsing a net: %d", rc);
+
+ free(netDef);
+ goto parse_complete;
+ }
+
+ DEBUG0("parsed a net");
+
+ /* set the linked list pointers */
+ numNets++;
+ netDef->next = NULL;
+ if (0 == i) {
+ *nets = netDef;
+ } else {
+ prevDef->next = netDef;
+ }
+ prevDef = netDef;
+ }
+ free(list);
+ }
+
+ rc = numNets;
+
+parse_complete:
+ DEBUG("parsed %d nets", rc);
+ return rc;
}
static int lxcParseMountXML(virConnectPtr conn, xmlNodePtr nodePtr,
@@ -372,6 +556,13 @@
containerDef->nmounts = lxcParseDomainMounts(conn,
&(containerDef->mounts),
contextPtr);
if (0 > containerDef->nmounts) {
+ goto error;
+ }
+
+ containerDef->numNets = lxcParseDomainInterfaces(conn,
+ &(containerDef->nets),
+ contextPtr);
+ if (0 > containerDef->numNets) {
goto error;
}
@@ -741,6 +932,7 @@
unsigned char *uuid;
char uuidstr[VIR_UUID_STRING_BUFLEN];
lxc_mount_t *mount;
+ lxc_net_def_t *net;
if (lxcIsActiveVM(vm))
virBufferVSprintf(&buf, "<domain type='%s'
id='%d'>\n",
@@ -770,6 +962,27 @@
virBufferAddLit(&buf, " </filesystem>\n");
}
+ /* loop adding nets */
+ for (net = def->nets; net; net = net->next) {
+ if (net->type == LXC_NET_NETWORK) {
+ virBufferAddLit(&buf, " <interface
type='network'>\n");
+ virBufferVSprintf(&buf, " <source
network='%s'/>\n",
+ net->txName);
+ } else {
+ virBufferAddLit(&buf, " <interface
type='bridge'>\n");
+ virBufferVSprintf(&buf, " <source
bridge='%s'/>\n",
+ net->txName);
+ }
+
+ if (NULL != net->parentVeth) {
+ virBufferVSprintf(&buf, " <target
dev='%s'/>\n",
+ net->parentVeth);
+ }
+
+ virBufferAddLit(&buf, " </interface>\n");
+
+ }
+
virBufferVSprintf(&buf, " <console tty='%s'/>\n",
def->tty);
virBufferAddLit(&buf, " </devices>\n");
virBufferAddLit(&buf, "</domain>\n");
@@ -786,6 +999,8 @@
{
lxc_mount_t *curMount;
lxc_mount_t *nextMount;
+ lxc_net_def_t *curNet;
+ lxc_net_def_t *nextNet;
if (vmdef == NULL)
return;
@@ -795,6 +1010,17 @@
nextMount = curMount->next;
VIR_FREE(curMount);
curMount = nextMount;
+ }
+
+ curNet = vmdef->nets;
+ while (curNet) {
+ nextNet = curNet->next;
+ printf("Freeing %s:%s\n", curNet->parentVeth,
curNet->containerVeth);
+ VIR_FREE(curNet->parentVeth);
+ VIR_FREE(curNet->containerVeth);
+ VIR_FREE(curNet->txName);
+ VIR_FREE(curNet);
+ curNet = nextNet;
}
VIR_FREE(vmdef->name);
diff -r 203dce381784 -r bb48967cf19e src/lxc_conf.h
--- a/src/lxc_conf.h Mon Jun 23 11:53:42 2008 -0700
+++ b/src/lxc_conf.h Mon Jun 23 11:53:45 2008 -0700
@@ -36,6 +36,22 @@
#define LXC_MAX_ERROR_LEN 1024
#define LXC_DOMAIN_TYPE "lxc"
+/* types of networks for containers */
+enum lxc_net_type {
+ LXC_NET_NETWORK,
+ LXC_NET_BRIDGE
+};
+
+typedef struct __lxc_net_def lxc_net_def_t;
+struct __lxc_net_def {
+ int type;
+ char *parentVeth; /* veth device in parent namespace */
+ char *containerVeth; /* veth device in container namespace */
+ char *txName; /* bridge or network name */
+
+ lxc_net_def_t *next;
+};
+
typedef struct __lxc_mount lxc_mount_t;
struct __lxc_mount {
char source[PATH_MAX]; /* user's directory */
@@ -61,6 +77,10 @@
/* tty device */
char *tty;
+
+ /* network devices */
+ int numNets;
+ lxc_net_def_t *nets;
};
typedef struct __lxc_vm lxc_vm_t;
diff -r 203dce381784 -r bb48967cf19e src/lxc_driver.c
--- a/src/lxc_driver.c Mon Jun 23 11:53:42 2008 -0700
+++ b/src/lxc_driver.c Mon Jun 23 11:53:45 2008 -0700
@@ -288,6 +288,13 @@
virDomainPtr dom;
if (!(def = lxcParseVMDef(conn, xml, NULL))) {
+ return NULL;
+ }
+
+ if ((def->nets != NULL) && !(driver->have_netns)) {
+ lxcError(conn, NULL, VIR_ERR_NO_SUPPORT,
+ _("System lacks NETNS support"));
+ lxcFreeVMDef(def);
return NULL;
}