|
|
43fe83 |
From d6ded4029afabd123c5578a33c4c7f9a6468044b Mon Sep 17 00:00:00 2001
|
|
|
43fe83 |
Message-Id: <d6ded4029afabd123c5578a33c4c7f9a6468044b.1381871411.git.jdenemar@redhat.com>
|
|
|
43fe83 |
From: "Daniel P. Berrange" <berrange@redhat.com>
|
|
|
43fe83 |
Date: Mon, 7 Oct 2013 17:17:30 +0100
|
|
|
43fe83 |
Subject: [PATCH] Retry veth device creation on failure
|
|
|
43fe83 |
|
|
|
43fe83 |
For
|
|
|
43fe83 |
|
|
|
43fe83 |
https://bugzilla.redhat.com/show_bug.cgi?id=1014604
|
|
|
43fe83 |
|
|
|
43fe83 |
The veth device creation code run in two steps, first it looks
|
|
|
43fe83 |
for two free veth device names, then it runs ip link to create
|
|
|
43fe83 |
the veth pair. There is an obvious race between finding free
|
|
|
43fe83 |
names and creating them, when guests are started in parallel.
|
|
|
43fe83 |
|
|
|
43fe83 |
Rewrite the code to loop and re-try creation if it fails, to
|
|
|
43fe83 |
deal with the race condition.
|
|
|
43fe83 |
|
|
|
43fe83 |
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
|
|
|
43fe83 |
(cherry picked from commit f2e53555eb6971635e526e93f9de07a76daf61cb)
|
|
|
43fe83 |
Signed-off-by: Jiri Denemark <jdenemar@redhat.com>
|
|
|
43fe83 |
---
|
|
|
43fe83 |
src/util/virnetdevveth.c | 151 +++++++++++++++++++++++++++++------------------
|
|
|
43fe83 |
1 file changed, 92 insertions(+), 59 deletions(-)
|
|
|
43fe83 |
|
|
|
43fe83 |
diff --git a/src/util/virnetdevveth.c b/src/util/virnetdevveth.c
|
|
|
43fe83 |
index c0d32c4..1ccfc54 100644
|
|
|
43fe83 |
--- a/src/util/virnetdevveth.c
|
|
|
43fe83 |
+++ b/src/util/virnetdevveth.c
|
|
|
43fe83 |
@@ -33,13 +33,26 @@
|
|
|
43fe83 |
#include "virfile.h"
|
|
|
43fe83 |
#include "virstring.h"
|
|
|
43fe83 |
#include "virutil.h"
|
|
|
43fe83 |
+#include "virnetdev.h"
|
|
|
43fe83 |
|
|
|
43fe83 |
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
43fe83 |
|
|
|
43fe83 |
/* Functions */
|
|
|
43fe83 |
+
|
|
|
43fe83 |
+static int virNetDevVethExists(int devNum)
|
|
|
43fe83 |
+{
|
|
|
43fe83 |
+ int ret;
|
|
|
43fe83 |
+ char *path = NULL;
|
|
|
43fe83 |
+ if (virAsprintf(&path, "/sys/class/net/veth%d/", devNum) < 0)
|
|
|
43fe83 |
+ return -1;
|
|
|
43fe83 |
+ ret = virFileExists(path) ? 1 : 0;
|
|
|
43fe83 |
+ VIR_DEBUG("Checked dev veth%d usage: %d", devNum, ret);
|
|
|
43fe83 |
+ VIR_FREE(path);
|
|
|
43fe83 |
+ return ret;
|
|
|
43fe83 |
+}
|
|
|
43fe83 |
+
|
|
|
43fe83 |
/**
|
|
|
43fe83 |
- * virNetDevVethGetFreeName:
|
|
|
43fe83 |
- * @veth: pointer to store returned name for veth device
|
|
|
43fe83 |
+ * virNetDevVethGetFreeNum:
|
|
|
43fe83 |
* @startDev: device number to start at (x in vethx)
|
|
|
43fe83 |
*
|
|
|
43fe83 |
* Looks in /sys/class/net/ to find the first available veth device
|
|
|
43fe83 |
@@ -47,25 +60,23 @@
|
|
|
43fe83 |
*
|
|
|
43fe83 |
* Returns non-negative device number on success or -1 in case of error
|
|
|
43fe83 |
*/
|
|
|
43fe83 |
-static int virNetDevVethGetFreeName(char **veth, int startDev)
|
|
|
43fe83 |
+static int virNetDevVethGetFreeNum(int startDev)
|
|
|
43fe83 |
{
|
|
|
43fe83 |
- int devNum = startDev-1;
|
|
|
43fe83 |
- char *path = NULL;
|
|
|
43fe83 |
+ int devNum;
|
|
|
43fe83 |
|
|
|
43fe83 |
- VIR_DEBUG("Find free from veth%d", startDev);
|
|
|
43fe83 |
- do {
|
|
|
43fe83 |
- VIR_FREE(path);
|
|
|
43fe83 |
- ++devNum;
|
|
|
43fe83 |
- if (virAsprintf(&path, "/sys/class/net/veth%d/", devNum) < 0)
|
|
|
43fe83 |
- return -1;
|
|
|
43fe83 |
- VIR_DEBUG("Probe %s", path);
|
|
|
43fe83 |
- } while (virFileExists(path));
|
|
|
43fe83 |
- VIR_FREE(path);
|
|
|
43fe83 |
+#define MAX_DEV_NUM 65536
|
|
|
43fe83 |
|
|
|
43fe83 |
- if (virAsprintf(veth, "veth%d", devNum) < 0)
|
|
|
43fe83 |
- return -1;
|
|
|
43fe83 |
+ for (devNum = startDev; devNum < MAX_DEV_NUM; devNum++) {
|
|
|
43fe83 |
+ int ret = virNetDevVethExists(devNum);
|
|
|
43fe83 |
+ if (ret < 0)
|
|
|
43fe83 |
+ return -1;
|
|
|
43fe83 |
+ if (ret == 0)
|
|
|
43fe83 |
+ return devNum;
|
|
|
43fe83 |
+ }
|
|
|
43fe83 |
|
|
|
43fe83 |
- return devNum;
|
|
|
43fe83 |
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
43fe83 |
+ _("No free veth devices available"));
|
|
|
43fe83 |
+ return -1;
|
|
|
43fe83 |
}
|
|
|
43fe83 |
|
|
|
43fe83 |
/**
|
|
|
43fe83 |
@@ -95,57 +106,79 @@ static int virNetDevVethGetFreeName(char **veth, int startDev)
|
|
|
43fe83 |
*/
|
|
|
43fe83 |
int virNetDevVethCreate(char** veth1, char** veth2)
|
|
|
43fe83 |
{
|
|
|
43fe83 |
- int rc = -1;
|
|
|
43fe83 |
- const char *argv[] = {
|
|
|
43fe83 |
- "ip", "link", "add", NULL, "type", "veth", "peer", "name", NULL, NULL
|
|
|
43fe83 |
- };
|
|
|
43fe83 |
- int vethDev = 0;
|
|
|
43fe83 |
- bool veth1_alloc = false;
|
|
|
43fe83 |
- bool veth2_alloc = false;
|
|
|
43fe83 |
-
|
|
|
43fe83 |
- VIR_DEBUG("Host: %s guest: %s", NULLSTR(*veth1), NULLSTR(*veth2));
|
|
|
43fe83 |
-
|
|
|
43fe83 |
- if (*veth1 == NULL) {
|
|
|
43fe83 |
- if ((vethDev = virNetDevVethGetFreeName(veth1, vethDev)) < 0)
|
|
|
43fe83 |
- goto cleanup;
|
|
|
43fe83 |
- VIR_DEBUG("Assigned host: %s", *veth1);
|
|
|
43fe83 |
- veth1_alloc = true;
|
|
|
43fe83 |
- vethDev++;
|
|
|
43fe83 |
- }
|
|
|
43fe83 |
- argv[3] = *veth1;
|
|
|
43fe83 |
+ int ret = -1;
|
|
|
43fe83 |
+ char *veth1auto = NULL;
|
|
|
43fe83 |
+ char *veth2auto = NULL;
|
|
|
43fe83 |
+ int vethNum = 0;
|
|
|
43fe83 |
+ size_t i;
|
|
|
43fe83 |
+
|
|
|
43fe83 |
+ /*
|
|
|
43fe83 |
+ * We might race with other containers, but this is reasonably
|
|
|
43fe83 |
+ * unlikely, so don't do too many retries for device creation
|
|
|
43fe83 |
+ */
|
|
|
43fe83 |
+#define MAX_VETH_RETRIES 10
|
|
|
43fe83 |
+
|
|
|
43fe83 |
+ for (i = 0; i < MAX_VETH_RETRIES; i++) {
|
|
|
43fe83 |
+ int status;
|
|
|
43fe83 |
+ if (!*veth1) {
|
|
|
43fe83 |
+ int veth1num;
|
|
|
43fe83 |
+ if ((veth1num = virNetDevVethGetFreeNum(vethNum)) < 0)
|
|
|
43fe83 |
+ goto cleanup;
|
|
|
43fe83 |
+
|
|
|
43fe83 |
+ if (virAsprintf(&veth1auto, "veth%d", veth1num) < 0)
|
|
|
43fe83 |
+ goto cleanup;
|
|
|
43fe83 |
+ vethNum = veth1num + 1;
|
|
|
43fe83 |
+ }
|
|
|
43fe83 |
+ if (!*veth2) {
|
|
|
43fe83 |
+ int veth2num;
|
|
|
43fe83 |
+ if ((veth2num = virNetDevVethGetFreeNum(vethNum)) < 0)
|
|
|
43fe83 |
+ goto cleanup;
|
|
|
43fe83 |
+
|
|
|
43fe83 |
+ if (virAsprintf(&veth2auto, "veth%d", veth2num) < 0)
|
|
|
43fe83 |
+ goto cleanup;
|
|
|
43fe83 |
+ vethNum = veth2num + 1;
|
|
|
43fe83 |
+ }
|
|
|
43fe83 |
+
|
|
|
43fe83 |
+ virCommandPtr cmd = virCommandNew("ip");
|
|
|
43fe83 |
+ virCommandAddArgList(cmd, "link", "add",
|
|
|
43fe83 |
+ *veth1 ? *veth1 : veth1auto,
|
|
|
43fe83 |
+ "type", "veth", "peer", "name",
|
|
|
43fe83 |
+ *veth2 ? *veth2 : veth2auto,
|
|
|
43fe83 |
+ NULL);
|
|
|
43fe83 |
|
|
|
43fe83 |
- while (*veth2 == NULL) {
|
|
|
43fe83 |
- if ((vethDev = virNetDevVethGetFreeName(veth2, vethDev)) < 0) {
|
|
|
43fe83 |
- if (veth1_alloc)
|
|
|
43fe83 |
- VIR_FREE(*veth1);
|
|
|
43fe83 |
+ if (virCommandRun(cmd, &status) < 0)
|
|
|
43fe83 |
goto cleanup;
|
|
|
43fe83 |
- }
|
|
|
43fe83 |
|
|
|
43fe83 |
- /* Just make sure they didn't accidentally get same name */
|
|
|
43fe83 |
- if (STREQ(*veth1, *veth2)) {
|
|
|
43fe83 |
- vethDev++;
|
|
|
43fe83 |
- VIR_FREE(*veth2);
|
|
|
43fe83 |
- continue;
|
|
|
43fe83 |
+ if (status == 0) {
|
|
|
43fe83 |
+ if (veth1auto) {
|
|
|
43fe83 |
+ *veth1 = veth1auto;
|
|
|
43fe83 |
+ veth1auto = NULL;
|
|
|
43fe83 |
+ }
|
|
|
43fe83 |
+ if (veth2auto) {
|
|
|
43fe83 |
+ *veth2 = veth2auto;
|
|
|
43fe83 |
+ veth2auto = NULL;
|
|
|
43fe83 |
+ }
|
|
|
43fe83 |
+ VIR_DEBUG("Create Host: %s guest: %s", *veth1, *veth2);
|
|
|
43fe83 |
+ ret = 0;
|
|
|
43fe83 |
+ goto cleanup;
|
|
|
43fe83 |
}
|
|
|
43fe83 |
|
|
|
43fe83 |
- VIR_DEBUG("Assigned guest: %s", *veth2);
|
|
|
43fe83 |
- veth2_alloc = true;
|
|
|
43fe83 |
- }
|
|
|
43fe83 |
- argv[8] = *veth2;
|
|
|
43fe83 |
-
|
|
|
43fe83 |
- VIR_DEBUG("Create Host: %s guest: %s", *veth1, *veth2);
|
|
|
43fe83 |
- if (virRun(argv, NULL) < 0) {
|
|
|
43fe83 |
- if (veth1_alloc)
|
|
|
43fe83 |
- VIR_FREE(*veth1);
|
|
|
43fe83 |
- if (veth2_alloc)
|
|
|
43fe83 |
- VIR_FREE(*veth2);
|
|
|
43fe83 |
- goto cleanup;
|
|
|
43fe83 |
+ VIR_DEBUG("Failed to create veth host: %s guest: %s: %d",
|
|
|
43fe83 |
+ *veth1 ? *veth1 : veth1auto,
|
|
|
43fe83 |
+ *veth1 ? *veth1 : veth1auto,
|
|
|
43fe83 |
+ status);
|
|
|
43fe83 |
+ VIR_FREE(veth1auto);
|
|
|
43fe83 |
+ VIR_FREE(veth2auto);
|
|
|
43fe83 |
}
|
|
|
43fe83 |
|
|
|
43fe83 |
- rc = 0;
|
|
|
43fe83 |
+ virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
43fe83 |
+ _("Failed to allocate free veth pair after %d attempts"),
|
|
|
43fe83 |
+ MAX_VETH_RETRIES);
|
|
|
43fe83 |
|
|
|
43fe83 |
cleanup:
|
|
|
43fe83 |
- return rc;
|
|
|
43fe83 |
+ VIR_FREE(veth1auto);
|
|
|
43fe83 |
+ VIR_FREE(veth2auto);
|
|
|
43fe83 |
+ return ret;
|
|
|
43fe83 |
}
|
|
|
43fe83 |
|
|
|
43fe83 |
/**
|
|
|
43fe83 |
--
|
|
|
43fe83 |
1.8.3.2
|
|
|
43fe83 |
|