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