[libvirt] PATCH 3/4: SUpport bridge config for openvz

Daniel P. Berrange berrange at redhat.com
Tue Oct 14 15:21:24 UTC 2008


This implements support for bridge configs in openvz following the rules
set out in

http://wiki.openvz.org/Virtual_Ethernet_device#Making_a_bridged_veth-device_persistent

This simply requires that the admin has created /etc/vz/vznetctl.conf
containing

  #!/bin/bash
  EXTERNAL_SCRIPT="/usr/sbin/vznetaddbr"


For openvz <= 3.0.22, we have to manually re-write the NETIF line to
add the bridge config parameter. For newer openvz we can simply pass
the bridge name on the commnand line to --netif_add.

Older openvz also requires that the admin install /usr/sbin/vznetaddbr
since it is not available out of the box

Daniel

diff -r 2e218ae09a5d src/openvz_conf.c
--- a/src/openvz_conf.c	Tue Oct 14 15:14:35 2008 +0100
+++ b/src/openvz_conf.c	Tue Oct 14 15:42:02 2008 +0100
@@ -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
@@ -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,
@@ -169,54 +171,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,
@@ -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));
@@ -450,6 +415,71 @@ 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)) {
+            if (safewrite(temp_fd, line, strlen(line)) !=
+                strlen(line))
+                goto error;
+        }
+    }
+
+    if (safewrite(temp_fd, param, strlen(param)) !=
+        strlen(param))
+        goto error;
+    if (safewrite(temp_fd, "=\"", 2) != 2)
+        goto error;
+    if (safewrite(temp_fd, value, strlen(value)) !=
+        strlen(value))
+        goto error;
+    if (safewrite(temp_fd, "\"\n", 2) != 2)
+        goto error;
+
+    close(fd);
+    close(temp_fd);
+    fd = temp_fd = -1;
+
+    if (rename(temp_file, conf_file) < 0)
+        goto error;
+
+    return 0;
+
+error:
+        fprintf(stderr, "damn %s\n", strerror(errno));
+
+    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
@@ -467,7 +497,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;
@@ -507,7 +537,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;
@@ -516,7 +546,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);
@@ -573,7 +604,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);
@@ -613,7 +644,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))
@@ -681,4 +712,3 @@ static int openvzAssignUUIDs(void)
     VIR_FREE(conf_dir);
     return 0;
 }
-
diff -r 2e218ae09a5d src/openvz_conf.h
--- a/src/openvz_conf.h	Tue Oct 14 15:14:35 2008 +0100
+++ b/src/openvz_conf.h	Tue Oct 14 15:17:02 2008 +0100
@@ -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 2e218ae09a5d src/openvz_driver.c
--- a/src/openvz_driver.c	Tue Oct 14 15:14:35 2008 +0100
+++ b/src/openvz_driver.c	Tue Oct 14 15:43:36 2008 +0100
@@ -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,55 @@ 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;
 
 #define ADD_ARG_LIT(thisarg)                                            \
     do {                                                                \
@@ -367,21 +410,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 *opt;
+        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 &&
+    } else if (net->type == VIR_DOMAIN_NET_TYPE_ETHERNET &&
               net->data.ethernet.ipaddr != NULL) {
         //--ipadd ip
         ADD_ARG_LIT("--ipadd") ;
@@ -402,18 +485,57 @@ openvzDomainSetNetwork(virConnectPtr con
 
  exit:
     cmdExecFree(prog);
-    VIR_FREE(mac);
     return rc;
 
  no_memory:
     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;
+    struct openvz_driver *driver = (struct openvz_driver *) conn->privateData;
+
+    for (i = 0 ; i < def->nnets ; i++) {
+        if (driver->version < VZCTL_BRIDGE_MIN_VERSION && i > 0)
+            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;
+        }
+    }
+
+    param = virBufferContentAndReset(&buf);
+    if (driver->version < VZCTL_BRIDGE_MIN_VERSION && def->nnets) {
+        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 +544,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 +589,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 +616,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 +661,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