]> xenbits.xensource.com Git - libvirt.git/commitdiff
Add bridged network to openvz driver & add some openvz docs
authorDaniel P. Berrange <berrange@redhat.com>
Wed, 12 Nov 2008 16:35:47 +0000 (16:35 +0000)
committerDaniel P. Berrange <berrange@redhat.com>
Wed, 12 Nov 2008 16:35:47 +0000 (16:35 +0000)
ChangeLog
docs/drvopenvz.html
docs/drvopenvz.html.in
src/openvz_conf.c
src/openvz_conf.h
src/openvz_driver.c

index 13e9e730944777452453117b2b128c6ea668e192..d8d95bf656cb9c22be0f2e187d5cca3f6e88b683 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed Nov 12 16:33:42 GMT 2008 Daniel P. Berrange <berrange@redhat.com>
+
+       * docs/drvopenvz.html, docs/drvopenvz.html.in: Introductory
+       docs for openvz driver
+       * src/openvz_conf.c, src/openvz_conf.h, src/openvz_driver.c:
+       Support bridged network configuration for containers
+
 Wed Nov 12 16:13:42 GMT 2008 Daniel P. Berrange <berrange@redhat.com>
 
        * src/storage_backend.c, src/storage_backend.h, src/storage_driver.c:
index 89de4327eea9932aa1d6d652afd2cab6ccb51790..58cb34796daa57497174b5797ebc74bb186a02cd 100644 (file)
       </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 &amp; 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>
+&lt;domain type='openvz' id='104'&gt;
+  &lt;name&gt;104&lt;/name&gt;
+  &lt;uuid&gt;86c12009-e591-a159-6e9f-91d18b85ef78&lt;/uuid&gt;
+  &lt;vcpu&gt;3&lt;/vcpu&gt;
+  &lt;os&gt;
+    &lt;type&gt;exe&lt;/type&gt;
+    &lt;init&gt;/sbin/init&lt;/init&gt;
+  &lt;/os&gt;
+  &lt;devices&gt;
+    &lt;filesystem type='template'&gt;
+      &lt;source name='fedora-9-i386-minimal'/&gt;
+      &lt;target dir='/'/&gt;
+    &lt;/filesystem&gt;
+    &lt;interface type='bridge'&gt;
+      &lt;mac address='00:18:51:5b:ea:bf'/&gt;
+      &lt;source bridge='br0'/&gt;
+      &lt;target dev='veth101.0'/&gt;
+    &lt;/interface&gt;
+  &lt;/devices&gt;
+&lt;/domain&gt;
+    </pre>
       </div>
     </div>
     <div id="footer">
index b002289cf99281ab69daba4978b11c8f454594ae..e92533676ed3d7f0ffe5bae8030a782913572f14 100644 (file)
@@ -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 &amp; 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>
+&lt;domain type='openvz' id='104'&gt;
+  &lt;name&gt;104&lt;/name&gt;
+  &lt;uuid&gt;86c12009-e591-a159-6e9f-91d18b85ef78&lt;/uuid&gt;
+  &lt;vcpu&gt;3&lt;/vcpu&gt;
+  &lt;os&gt;
+    &lt;type&gt;exe&lt;/type&gt;
+    &lt;init&gt;/sbin/init&lt;/init&gt;
+  &lt;/os&gt;
+  &lt;devices&gt;
+    &lt;filesystem type='template'&gt;
+      &lt;source name='fedora-9-i386-minimal'/&gt;
+      &lt;target dir='/'/&gt;
+    &lt;/filesystem&gt;
+    &lt;interface type='bridge'&gt;
+      &lt;mac address='00:18:51:5b:ea:bf'/&gt;
+      &lt;source bridge='br0'/&gt;
+      &lt;target dev='veth101.0'/&gt;
+    &lt;/interface&gt;
+  &lt;/devices&gt;
+&lt;/domain&gt;
+    </pre>
+
   </body>
 </html>
index ca423a776d83e621c293b7ad4b238cfa06e847f2..b179b11efdc2b9e8dd689abed03a01459916d537 100644 (file)
@@ -52,7 +52,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
@@ -145,6 +145,8 @@ virCapsPtr openvzCapsInit(void)
                                    0, 0)) == NULL)
         goto no_memory;
 
+    virCapabilitiesSetMacPrefix(caps, (unsigned char[]){ 0x52, 0x54, 0x00 });
+
     if ((guest = virCapabilitiesAddGuest(caps,
                                          "exe",
                                          utsname.machine,
@@ -170,54 +172,6 @@ no_memory:
 }
 
 
-/* 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,
                       virDomainDefPtr def,
@@ -288,6 +242,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,
@@ -295,14 +252,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;
@@ -313,14 +281,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));
@@ -492,6 +457,68 @@ int openvzLoadDomains(struct openvz_driver *driver) {
     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
@@ -509,7 +536,7 @@ openvzReadConfigParam(int vpsid ,const char * param, char *value, int maxlen)
     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;
@@ -549,7 +576,7 @@ openvzReadConfigParam(int vpsid ,const char * param, char *value, int maxlen)
 *         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;
@@ -558,7 +585,8 @@ openvzLocateConfFile(int vpsid, char *conffile, int maxlen)
     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);
@@ -615,7 +643,7 @@ openvzGetVPSUUID(int vpsid, char *uuidstr)
     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);
@@ -655,7 +683,7 @@ openvzSetDefinedUUID(int vpsid, unsigned char *uuid)
     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))
@@ -723,4 +751,3 @@ static int openvzAssignUUIDs(void)
     VIR_FREE(conf_dir);
     return 0;
 }
-
index d06a547741b51c21fa98fa7bc6cc79c9612c9858..f30f0879bdd60f6bfca06660a5af94f27249ffde 100644 (file)
@@ -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 openvz_readline(int fd, char *ptr, int maxlen);
 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 */
index 8e6a0343d9144ac420618dc2efa9cf513e63d27d..bbee4516011f53670b0b354c6b940510904b4a78 100644 (file)
@@ -56,6 +56,7 @@
 #include "openvz_conf.h"
 #include "nodeinfo.h"
 #include "memory.h"
+#include "bridge.h"
 
 #define OPENVZ_MAX_ARG 28
 #define CMDBUF_LEN 1488
@@ -330,13 +331,56 @@ static int openvzDomainReboot(virDomainPtr dom,
     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 {                                                                \
@@ -368,21 +412,61 @@ openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
         ADD_ARG_LIT(vpsid);
     }
 
-    if (openvzCheckEmptyMac(net->mac) > 0)
-          mac = openvzMacToString(net->mac);
+    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);
 
-    if (net->type == VIR_DOMAIN_NET_TYPE_BRIDGE &&
-           net->data.bridge.brname != NULL) {
-        char opt[1024];
         //--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") ;
@@ -403,19 +487,67 @@ openvzDomainSetNetwork(virConnectPtr conn, const char *vpsid,
 
  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)
 {
@@ -423,7 +555,6 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml)
     virDomainDefPtr vmdef = NULL;
     virDomainObjPtr vm = NULL;
     virDomainPtr dom = NULL;
-    int i;
     const char *prog[OPENVZ_MAX_ARG];
     prog[0] = NULL;
 
@@ -469,18 +600,13 @@ openvzDomainDefineXML(virConnectPtr conn, const char *xml)
         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) {
             openvzError(conn, VIR_ERR_INTERNAL_ERROR,
@@ -501,7 +627,6 @@ openvzDomainCreateXML(virConnectPtr conn, const char *xml,
     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];
@@ -547,13 +672,8 @@ openvzDomainCreateXML(virConnectPtr conn, const char *xml,
         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;