[libvirt] [PATCH 3 of 4] [LXC] Add XML parsing of container network interfaces

Dan Smith danms at us.ibm.com
Tue Jun 24 15:51:35 UTC 2008


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;
     }
 




More information about the libvir-list mailing list