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 :| -- Libvir-list mailing list Libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list