[libvirt] PATCH: OpenVZ bridge support

Daniel P. Berrange berrange at redhat.com
Mon Nov 10 12:11:15 UTC 2008


This is an update of the patch 

http://www.redhat.com/archives/libvir-list/2008-October/msg00326.html

To enable bridge support in the OpenVZ driver. As well as the fixes
suggested last time, it includes an initial bit of HTML doc for the
openvz driver, covering example XML, and the bridge configuration
requirements

Daniel

diff -r 34eb1c9bdd7c docs/drvopenvz.html
--- a/docs/drvopenvz.html	Mon Nov 10 11:02:51 2008 +0000
+++ b/docs/drvopenvz.html	Mon Nov 10 12:08:30 2008 +0000
@@ -122,6 +122,93 @@
       </div>
       <div id="content">
         <h1>OpenVZ container driver</h1>
+        <p>
+    The OpenVZ driver for libvirt allows use and management of container
+    based virtualization on a Linux host OS. Prior to using the OpenVZ
+    driver, the OpenVZ enabled kernel must be installed & booted, and the
+    OpenVZ userspace tools installed. The libvirt driver has been tested
+    with OpenVZ 3.0.22, but other 3.0.x versions should also work without
+    undue trouble.
+    </p>
+        <h2>Connections to OpenVZ driver</h2>
+        <p>
+    The libvirt OpenVZ driver is a single-instance privileged driver,
+    with a driver name of 'openvz'. Some example conection URIs for
+    the libvirt driver are:
+    </p>
+        <pre>
+    openvz:///system                     (local access)
+    openvz://example.com/system          (remote access, TLS/x509)
+    openvz+tcp://example.com/system      (remote access, SASl/Kerberos)
+    openvz+ssh://root@example.com/system (remote access, SSH tunnelled)
+    </pre>
+        <h2>Notes on bridged networking</h2>
+        <p>
+    Bridged networking enables a guest domain (ie container) to have its
+    network interface connected directly to the host's physical LAN. Before
+    this can be used there are a couple of configuration pre-requisites for
+    the host OS.
+    </p>
+        <h3>Host network devices</h3>
+        <p>
+    One or more of the physical devices must be attached to a bridge. The
+    process for this varies according to the operating system in use, so
+    for up to date notes consult the <a href="http://wiki.libvirt.org">Wiki</a>
+    or your operating system's networking documentation. The basic idea is
+    that the host OS should end up with a bridge device "br0" containing a
+    physical device "eth0", or a bonding device "bond0".
+    </p>
+        <h3>OpenVZ tools configuration</h3>
+        <p>
+    OpenVZ releases later than 3.0.23 ship with a standard network device
+    setup script that is able to setup bridging, named
+    <code>/usr/sbin/vznetaddbr</code>. For releases prior to 3.0.23, this
+    script must be created manually by the host OS adminstrator. The
+    simplest way is to just download the latest version of this script
+    from a newer OpenVZ release, or upstream source repository. Then
+    a generic configuration file <code>/etc/vz/vznetctl.conf</code>
+    must be created containing
+    </p>
+        <pre>
+#!/bin/bash
+EXTERNAL_SCRIPT="/usr/sbin/vznetaddbr"
+    </pre>
+        <p>
+    The host OS is now ready to allow bridging of guest containers, which
+    will work whether the container is started with libvirt, or OpenVZ
+    tools.
+    </p>
+        <h2>Example guest domain XML configuration</h2>
+        <p>
+    The current libvirt OpenVZ driver has a restriction that the
+    domain names must match the OpenVZ container VEID, which by
+    convention start at 100, and are incremented from there. The
+    choice of OS template to use inside the container is determined
+    by the <code>filesystem</code> tag, and the template source name
+    matches the templates known to OpenVZ tools.
+    </p>
+        <pre>
+<domain type='openvz' id='104'>
+  <name>104</name>
+  <uuid>86c12009-e591-a159-6e9f-91d18b85ef78</uuid>
+  <vcpu>3</vcpu>
+  <os>
+    <type>exe</type>
+    <init>/sbin/init</init>
+  </os>
+  <devices>
+    <filesystem type='template'>
+      <source name='fedora-9-i386-minimal'/>
+      <target dir='/'/>
+    </filesystem>
+    <interface type='bridge'>
+      <mac address='00:18:51:5b:ea:bf'/>
+      <source bridge='br0'/>
+      <target dev='veth101.0'/>
+    </interface>
+  </devices>
+</domain>
+    </pre>
       </div>
     </div>
     <div id="footer">
diff -r 34eb1c9bdd7c docs/drvopenvz.html.in
--- a/docs/drvopenvz.html.in	Mon Nov 10 11:02:51 2008 +0000
+++ b/docs/drvopenvz.html.in	Mon Nov 10 12:08:30 2008 +0000
@@ -1,5 +1,109 @@
-<html>
+<html> <!-- -*- html -*- -->
   <body>
     <h1>OpenVZ container driver</h1>
+
+    <p>
+    The OpenVZ driver for libvirt allows use and management of container
+    based virtualization on a Linux host OS. Prior to using the OpenVZ
+    driver, the OpenVZ enabled kernel must be installed & booted, and the
+    OpenVZ userspace tools installed. The libvirt driver has been tested
+    with OpenVZ 3.0.22, but other 3.0.x versions should also work without
+    undue trouble.
+    </p>
+
+    <h2>Connections to OpenVZ driver</h2>
+
+    <p>
+    The libvirt OpenVZ driver is a single-instance privileged driver,
+    with a driver name of 'openvz'. Some example conection URIs for
+    the libvirt driver are:
+    </p>
+
+    <pre>
+    openvz:///system                     (local access)
+    openvz://example.com/system          (remote access, TLS/x509)
+    openvz+tcp://example.com/system      (remote access, SASl/Kerberos)
+    openvz+ssh://root@example.com/system (remote access, SSH tunnelled)
+    </pre>
+
+    <h2>Notes on bridged networking</h2>
+
+    <p>
+    Bridged networking enables a guest domain (ie container) to have its
+    network interface connected directly to the host's physical LAN. Before
+    this can be used there are a couple of configuration pre-requisites for
+    the host OS.
+    </p>
+
+    <h3>Host network devices</h3>
+
+    <p>
+    One or more of the physical devices must be attached to a bridge. The
+    process for this varies according to the operating system in use, so
+    for up to date notes consult the <a href="http://wiki.libvirt.org">Wiki</a>
+    or your operating system's networking documentation. The basic idea is
+    that the host OS should end up with a bridge device "br0" containing a
+    physical device "eth0", or a bonding device "bond0".
+    </p>
+
+    <h3>OpenVZ tools configuration</h3>
+
+    <p>
+    OpenVZ releases later than 3.0.23 ship with a standard network device
+    setup script that is able to setup bridging, named
+    <code>/usr/sbin/vznetaddbr</code>. For releases prior to 3.0.23, this
+    script must be created manually by the host OS adminstrator. The
+    simplest way is to just download the latest version of this script
+    from a newer OpenVZ release, or upstream source repository. Then
+    a generic configuration file <code>/etc/vz/vznetctl.conf</code>
+    must be created containing
+    </p>
+
+    <pre>
+#!/bin/bash
+EXTERNAL_SCRIPT="/usr/sbin/vznetaddbr"
+    </pre>
+
+    <p>
+    The host OS is now ready to allow bridging of guest containers, which
+    will work whether the container is started with libvirt, or OpenVZ
+    tools.
+    </p>
+
+
+    <h2>Example guest domain XML configuration</h2>
+
+    <p>
+    The current libvirt OpenVZ driver has a restriction that the
+    domain names must match the OpenVZ container VEID, which by
+    convention start at 100, and are incremented from there. The
+    choice of OS template to use inside the container is determined
+    by the <code>filesystem</code> tag, and the template source name
+    matches the templates known to OpenVZ tools.
+    </p>
+
+    <pre>
+<domain type='openvz' id='104'>
+  <name>104</name>
+  <uuid>86c12009-e591-a159-6e9f-91d18b85ef78</uuid>
+  <vcpu>3</vcpu>
+  <os>
+    <type>exe</type>
+    <init>/sbin/init</init>
+  </os>
+  <devices>
+    <filesystem type='template'>
+      <source name='fedora-9-i386-minimal'/>
+      <target dir='/'/>
+    </filesystem>
+    <interface type='bridge'>
+      <mac address='00:18:51:5b:ea:bf'/>
+      <source bridge='br0'/>
+      <target dev='veth101.0'/>
+    </interface>
+  </devices>
+</domain>
+    </pre>
+
   </body>
 </html>
diff -r 34eb1c9bdd7c src/openvz_conf.c
--- a/src/openvz_conf.c	Mon Nov 10 11:02:51 2008 +0000
+++ b/src/openvz_conf.c	Mon Nov 10 12:08:30 2008 +0000
@@ -51,7 +51,7 @@
 
 static char *openvzLocateConfDir(void);
 static int openvzGetVPSUUID(int vpsid, char *uuidstr);
-static int openvzLocateConfFile(int vpsid, char *conffile, int maxlen);
+static int openvzLocateConfFile(int vpsid, char *conffile, int maxlen, const char *ext);
 static int openvzAssignUUIDs(void);
 
 int
@@ -144,6 +144,8 @@ virCapsPtr openvzCapsInit(void)
                                    0, 0)) == NULL)
         goto no_memory;
 
+    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x52, 0x54, 0x00 });
+
     if ((guest = virCapabilitiesAddGuest(caps,
                                          "exe",
                                          utsname.machine,
@@ -168,54 +170,6 @@ no_memory:
     return NULL;
 }
 
-
-/* function checks MAC address is empty
-   return 0 - empty
-          1 - not
-*/
-int openvzCheckEmptyMac(const unsigned char *mac)
-{
-    int i;
-    for (i = 0; i < VIR_MAC_BUFLEN; i++)
-        if (mac[i] != 0x00)
-            return 1;
-
-    return 0;
-}
-
-/* convert mac address to string
-   return pointer to string or NULL
-*/
-char *openvzMacToString(const unsigned char *mac)
-{
-    char str[20];
-    if (snprintf(str, 18, "%02X:%02X:%02X:%02X:%02X:%02X",
-                      mac[0], mac[1], mac[2],
-                      mac[3], mac[4], mac[5]) >= 18)
-        return NULL;
-
-    return strdup(str);
-}
-
-/*parse MAC from view: 00:18:51:8F:D9:F3
-  return -1 - error
-          0 - OK
-*/
-static int openvzParseMac(const char *macaddr, unsigned char *mac)
-{
-    int ret;
-    ret = sscanf((const char *)macaddr, "%02X:%02X:%02X:%02X:%02X:%02X",
-               (unsigned int*)&mac[0],
-               (unsigned int*)&mac[1],
-               (unsigned int*)&mac[2],
-               (unsigned int*)&mac[3],
-               (unsigned int*)&mac[4],
-               (unsigned int*)&mac[5]) ;
-    if (ret == 6)
-        return 0;
-
-    return -1;
-}
 
 static int
 openvzReadNetworkConf(virConnectPtr conn,
@@ -287,6 +241,9 @@ openvzReadNetworkConf(virConnectPtr conn
                 while (*next != '\0' && *next != ',') next++;
                 if (STRPREFIX(p, "ifname=")) {
                     p += 7;
+                    /* skip in libvirt */
+                } else if (STRPREFIX(p, "host_ifname=")) {
+                    p += 12;
                     len = next - p;
                     if (len > 16) {
                         openvzError(conn, VIR_ERR_INTERNAL_ERROR,
@@ -294,14 +251,25 @@ openvzReadNetworkConf(virConnectPtr conn
                         goto error;
                     }
 
+                    if (VIR_ALLOC_N(net->ifname, len+1) < 0)
+                        goto no_memory;
+
+                    strncpy(net->ifname, p, len);
+                    net->ifname[len] = '\0';
+                } else if (STRPREFIX(p, "bridge=")) {
+                    p += 7;
+                    len = next - p;
+                    if (len > 16) {
+                        openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+                                "%s", _("Too long bridge device name"));
+                        goto error;
+                    }
+
                     if (VIR_ALLOC_N(net->data.bridge.brname, len+1) < 0)
                         goto no_memory;
 
                     strncpy(net->data.bridge.brname, p, len);
                     net->data.bridge.brname[len] = '\0';
-                } else if (STRPREFIX(p, "host_ifname=")) {
-                    p += 12;
-                    //skip in libvirt
                 } else if (STRPREFIX(p, "mac=")) {
                     p += 4;
                     len = next - p;
@@ -312,14 +280,11 @@ openvzReadNetworkConf(virConnectPtr conn
                     }
                     strncpy(cpy_temp, p, len);
                     cpy_temp[len] = '\0';
-                    if (openvzParseMac(cpy_temp, net->mac)<0) {
+                    if (virParseMacAddr(cpy_temp, net->mac) < 0) {
                         openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                               "%s", _("Wrong MAC address"));
                         goto error;
                     }
-                } else if (STRPREFIX(p, "host_mac=")) {
-                    p += 9;
-                    //skip in libvirt
                 }
                 p = ++next;
             } while (p < token + strlen(token));
@@ -491,6 +456,68 @@ int openvzLoadDomains(struct openvz_driv
     return -1;
 }
 
+
+int
+openvzWriteConfigParam(int vpsid, const char *param, const char *value)
+{
+    char conf_file[PATH_MAX];
+    char temp_file[PATH_MAX];
+    char line[PATH_MAX] ;
+    int fd, temp_fd;
+
+    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
+        return -1;
+    if (openvzLocateConfFile(vpsid, temp_file, PATH_MAX, "tmp")<0)
+        return -1;
+
+    fd = open(conf_file, O_RDONLY);
+    if (fd == -1)
+        return -1;
+    temp_fd = open(temp_file, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+    if (temp_fd == -1) {
+        close(fd);
+        return -1;
+    }
+
+    while(1) {
+        if (openvz_readline(fd, line, sizeof(line)) <= 0)
+            break;
+
+        if (!STRPREFIX(line, param) &&
+            line[strlen(param)] == '=') {
+            if (safewrite(temp_fd, line, strlen(line)) !=
+                strlen(line))
+                goto error;
+        }
+    }
+
+    if (safewrite(temp_fd, param, strlen(param)) < 0 ||
+        safewrite(temp_fd, "=\"", 2) < 0 ||
+        safewrite(temp_fd, value, strlen(value)) < 0 ||
+        safewrite(temp_fd, "\"\n", 2) < 0)
+        goto error;
+
+    if (close(fd) < 0)
+        goto error;
+    fd = -1;
+    if (close(temp_fd) < 0)
+        goto error;
+    temp_fd = -1;
+
+    if (rename(temp_file, conf_file) < 0)
+        goto error;
+
+    return 0;
+
+error:
+    if (fd != -1)
+        close(fd);
+    if (temp_fd != -1)
+        close(temp_fd);
+    unlink(temp_file);
+    return -1;
+}
+
 /*
 * Read parameter from container config
 * sample: 133, "OSTEMPLATE", value, 1024
@@ -508,7 +535,7 @@ openvzReadConfigParam(int vpsid ,const c
     char * sf, * token;
     char *saveptr = NULL;
 
-    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX)<0)
+    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
         return -1;
 
     value[0] = 0;
@@ -548,7 +575,7 @@ openvzReadConfigParam(int vpsid ,const c
 *         0 - OK
 */
 static int
-openvzLocateConfFile(int vpsid, char *conffile, int maxlen)
+openvzLocateConfFile(int vpsid, char *conffile, int maxlen, const char *ext)
 {
     char * confdir;
     int ret = 0;
@@ -557,7 +584,8 @@ openvzLocateConfFile(int vpsid, char *co
     if (confdir == NULL)
         return -1;
 
-    if (snprintf(conffile, maxlen, "%s/%d.conf", confdir, vpsid) >= maxlen)
+    if (snprintf(conffile, maxlen, "%s/%d.%s",
+                 confdir, vpsid, ext ? ext : "conf") >= maxlen)
         ret = -1;
 
     VIR_FREE(confdir);
@@ -614,7 +642,7 @@ openvzGetVPSUUID(int vpsid, char *uuidst
     char iden[1024];
     int fd, ret;
 
-   if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX)<0)
+    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
        return -1;
 
     fd = open(conf_file, O_RDONLY);
@@ -654,7 +682,7 @@ openvzSetDefinedUUID(int vpsid, unsigned
     if (uuid == NULL)
         return -1;
 
-   if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX)<0)
+    if (openvzLocateConfFile(vpsid, conf_file, PATH_MAX, "conf")<0)
        return -1;
 
     if (openvzGetVPSUUID(vpsid, uuidstr))
@@ -722,4 +750,3 @@ static int openvzAssignUUIDs(void)
     VIR_FREE(conf_dir);
     return 0;
 }
-
diff -r 34eb1c9bdd7c src/openvz_conf.h
--- a/src/openvz_conf.h	Mon Nov 10 11:02:51 2008 +0000
+++ b/src/openvz_conf.h	Mon Nov 10 12:08:30 2008 +0000
@@ -50,6 +50,8 @@ enum { OPENVZ_WARN, OPENVZ_ERR };
 #define VZLIST  "/usr/sbin/vzlist"
 #define VZCTL   "/usr/sbin/vzctl"
 
+#define VZCTL_BRIDGE_MIN_VERSION ((3 * 1000 * 1000) + (0 * 1000) + 22 + 1)
+
 struct openvz_driver {
     virCapsPtr caps;
     virDomainObjList domains;
@@ -60,12 +62,11 @@ int openvzExtractVersion(virConnectPtr c
 int openvzExtractVersion(virConnectPtr conn,
                          struct openvz_driver *driver);
 int openvzReadConfigParam(int vpsid ,const char * param, char *value, int maxlen);
+int openvzWriteConfigParam(int vpsid, const char *param, const char *value);
 virCapsPtr openvzCapsInit(void);
 int openvzLoadDomains(struct openvz_driver *driver);
 void openvzFreeDriver(struct openvz_driver *driver);
 int strtoI(const char *str);
-int openvzCheckEmptyMac(const unsigned char *mac);
-char *openvzMacToString(const unsigned char *mac);
 int openvzSetDefinedUUID(int vpsid, unsigned char *uuid);
 
 #endif /* OPENVZ_CONF_H */
diff -r 34eb1c9bdd7c src/openvz_driver.c
--- a/src/openvz_driver.c	Mon Nov 10 11:02:51 2008 +0000
+++ b/src/openvz_driver.c	Mon Nov 10 12:08:30 2008 +0000
@@ -55,6 +55,7 @@
 #include "openvz_conf.h"
 #include "nodeinfo.h"
 #include "memory.h"
+#include "bridge.h"
 
 #define OPENVZ_MAX_ARG 28
 #define CMDBUF_LEN 1488
@@ -329,13 +330,56 @@ static int openvzDomainReboot(virDomainP
     return 0;
 }
 
+static char *
+openvzGenerateVethName(int veid, char *dev_name_ve)
+{
+    char    dev_name[32];
+    int     ifNo = 0;
+
+    if (sscanf(dev_name_ve, "%*[^0-9]%d", &ifNo) != 1)
+        return NULL;
+    if (snprintf(dev_name, sizeof(dev_name), "veth%d.%d", veid, ifNo) < 7)
+        return NULL;
+    return strdup(dev_name);
+}
+
+static char *
+openvzGenerateContainerVethName(int veid)
+{
+    int     ret;
+    char    temp[1024];
+
+    /* try to get line "^NETIF=..." from config */
+    if ( (ret = openvzReadConfigParam(veid, "NETIF", temp, sizeof(temp))) <= 0) {
+        snprintf(temp, sizeof(temp), "eth0");
+    } else {
+        char   *s;
+        int     max = 0;
+
+        /* get maximum interface number (actually, it is the last one) */
+        for (s=strtok(temp, ";"); s; s=strtok(NULL, ";")) {
+            int x;
+
+            if (sscanf(s, "ifname=eth%d", &x) != 1) return NULL;
+            if (x > max) max = x;
+        }
+
+        /* set new name */
+        snprintf(temp, sizeof(temp), "eth%d", max+1);
+    }
+    return strdup(temp);
+}
+
 static int
 openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
-                        virDomainNetDefPtr net)
+                       virDomainNetDefPtr net,
+                       virBufferPtr configBuf)
 {
     int rc = 0, narg;
     const char *prog[OPENVZ_MAX_ARG];
-    char *mac = NULL;
+    char macaddr[VIR_MAC_STRING_BUFLEN];
+    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
+    char *opt = NULL;
 
 #define ADD_ARG_LIT(thisarg)                                            \
     do {                                                                \
@@ -367,21 +411,61 @@ openvzDomainSetNetwork(virConnectPtr con
         ADD_ARG_LIT(vpsid);
     }
 
-    if (openvzCheckEmptyMac(net->mac) > 0)
-          mac = openvzMacToString(net->mac);
-
-    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
-           net->data.bridge.brname != NULL) {
-        char opt[1024];
+    virFormatMacAddr(net->mac, macaddr);
+
+    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+        virBuffer buf = VIR_BUFFER_INITIALIZER;
+        char *dev_name_ve;
+        int veid = strtoI(vpsid);
+
         //--netif_add ifname[,mac,host_ifname,host_mac]
         ADD_ARG_LIT("--netif_add") ;
-        strncpy(opt, net->data.bridge.brname, 256);
-        if (mac != NULL) {
-            strcat(opt, ",");
-            strcat(opt, mac);
-        }
+
+        /* generate interface name in ve and copy it to options */
+        dev_name_ve = openvzGenerateContainerVethName(veid);
+        if (dev_name_ve == NULL) {
+           openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+                    _("Could not generate eth name for container"));
+           rc = -1;
+           goto exit;
+        }
+
+        /* if user doesn't specified host interface name,
+         * than we need to generate it */
+        if (net->ifname == NULL) {
+            net->ifname = openvzGenerateVethName(veid, dev_name_ve);
+            if (net->ifname == NULL) {
+               openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+                        _("Could not generate veth name"));
+               rc = -1;
+               VIR_FREE(dev_name_ve);
+               goto exit;
+            }
+        }
+
+        virBufferAdd(&buf, dev_name_ve, -1); /* Guest dev */
+        virBufferVSprintf(&buf, ",%s", macaddr); /* Guest dev mac */
+        virBufferVSprintf(&buf, ",%s", net->ifname); /* Host dev */
+        virBufferVSprintf(&buf, ",%s", macaddr); /* Host dev mac */
+
+        if (driver->version >= VZCTL_BRIDGE_MIN_VERSION) {
+            virBufferVSprintf(&buf, ",%s", net->data.bridge.brname); /* Host bridge */
+        } else {
+            virBufferVSprintf(configBuf, "ifname=%s", dev_name_ve);
+            virBufferVSprintf(configBuf, ",mac=%s", macaddr); /* Guest dev mac */
+            virBufferVSprintf(configBuf, ",host_ifname=%s", net->ifname); /* Host dev */
+            virBufferVSprintf(configBuf, ",host_mac=%s", macaddr); /* Host dev mac */
+            virBufferVSprintf(configBuf, ",bridge=%s", net->data.bridge.brname); /* Host bridge */
+        }
+
+        VIR_FREE(dev_name_ve);
+
+        if (!(opt = virBufferContentAndReset(&buf)))
+            goto no_memory;
+
         ADD_ARG_LIT(opt) ;
-    }else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
+        VIR_FREE(opt);
+    } else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
               net->data.ethernet.ipaddr != NULL) {
         //--ipadd ip
         ADD_ARG_LIT("--ipadd") ;
@@ -402,18 +486,66 @@ openvzDomainSetNetwork(virConnectPtr con
 
  exit:
     cmdExecFree(prog);
-    VIR_FREE(mac);
     return rc;
 
  no_memory:
+    VIR_FREE(opt);
     openvzError(conn, VIR_ERR_INTERNAL_ERROR,
                 _("Could not put argument to %s"), VZCTL);
     cmdExecFree(prog);
-    VIR_FREE(mac);
     return -1;
 
 #undef ADD_ARG_LIT
 }
+
+
+static int
+openvzDomainSetNetworkConfig(virConnectPtr conn,
+                             virDomainDefPtr def)
+{
+    unsigned int i;
+    virBuffer buf = VIR_BUFFER_INITIALIZER;
+    char *param;
+    int first = 1;
+    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
+
+    for (i = 0 ; i < def->nnets ; i++) {
+        if (driver->version < VZCTL_BRIDGE_MIN_VERSION &&
+            def->nets[i]->type == VIR_DOMAIN_NET_TYPE_BRIDGE) {
+            if (first)
+                first = 0;
+            else
+                virBufferAddLit(&buf, ";");
+        }
+
+        if (openvzDomainSetNetwork(conn, def->name, def->nets[i], &buf) < 0) {
+            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+                        "%s", _("Could not configure network"));
+            goto exit;
+        }
+    }
+
+    if (driver->version < VZCTL_BRIDGE_MIN_VERSION && def->nnets) {
+        param = virBufferContentAndReset(&buf);
+        if (param) {
+            if (openvzWriteConfigParam(strtoI(def->name), "NETIF", param) < 0) {
+                VIR_FREE(param);
+                openvzError(conn, VIR_ERR_INTERNAL_ERROR,
+                            "%s", _("cannot replace NETIF config"));
+                return -1;
+            }
+            VIR_FREE(param);
+        }
+    }
+
+    return 0;
+
+exit:
+    param = virBufferContentAndReset(&buf);
+    VIR_FREE(param);
+    return -1;
+}
+
 
 static virDomainPtr
 openvzDomainDefineXML(virConnectPtr conn, const char *xml)
@@ -422,7 +554,6 @@ openvzDomainDefineXML(virConnectPtr conn
     virDomainDefPtr vmdef = NULL;
     virDomainObjPtr vm = NULL;
     virDomainPtr dom = NULL;
-    int i;
     const char *prog[OPENVZ_MAX_ARG];
     prog[0] = NULL;
 
@@ -468,17 +599,12 @@ openvzDomainDefineXML(virConnectPtr conn
         goto exit;
     }
 
+    if (openvzDomainSetNetworkConfig(conn, vmdef) < 0)
+        goto exit;
+
     dom = virGetDomain(conn, vm->def->name, vm->def->uuid);
     if (dom)
         dom->id = -1;
-
-    for (i = 0 ; i < vmdef->nnets ; i++) {
-        if (openvzDomainSetNetwork(conn, vmdef->name, vmdef->nets[i]) < 0) {
-            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
-                        "%s", _("Could not configure network"));
-            goto exit;
-        }
-    }
 
     if (vmdef->vcpus > 0) {
         if (openvzDomainSetVcpus(dom, vmdef->vcpus) < 0) {
@@ -500,7 +626,6 @@ openvzDomainCreateXML(virConnectPtr conn
     virDomainDefPtr vmdef = NULL;
     virDomainObjPtr vm = NULL;
     virDomainPtr dom = NULL;
-    int i;
     struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
     const char *progstart[] = {VZCTL, "--quiet", "start", NULL, NULL};
     const char *progcreate[OPENVZ_MAX_ARG];
@@ -546,13 +671,8 @@ openvzDomainCreateXML(virConnectPtr conn
         goto exit;
     }
 
-    for (i = 0 ; i < vmdef->nnets ; i++) {
-        if (openvzDomainSetNetwork(conn, vmdef->name, vmdef->nets[i]) < 0) {
-            openvzError(conn, VIR_ERR_INTERNAL_ERROR,
-                        "%s", _("Could not configure network"));
-            goto exit;
-        }
-    }
+    if (openvzDomainSetNetworkConfig(conn, vmdef) < 0)
+        goto exit;
 
     progstart[3] = vmdef->name;
 


-- 
|: Red Hat, Engineering, London   -o-   http://people.redhat.com/berrange/ :|
|: http://libvirt.org  -o-  http://virt-manager.org  -o-  http://ovirt.org :|
|: http://autobuild.org       -o-         http://search.cpan.org/~danberr/ :|
|: GnuPG: 7D3B9505  -o-  F3C9 553F A1DA 4AC2 5648 23C1 B3DF F742 7D3B 9505 :|




More information about the libvir-list mailing list