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-devi...
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 :|