[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]

[libvirt] [PATCH] network: bridge: Don't start network if it collides with host routing



Fedora bug https://bugzilla.redhat.com/show_bug.cgi?id=235961

If using the default virtual network, an easy way to lose guest network
connectivity is to install libvirt inside the VM. The autostarted
default network inside the guest collides with host virtual network
routing. This is a long standing issue that has caused users quite a
bit of pain and confusion.

On network startup, parse /proc/net/route and compare the requested
IP+netmask against host routing destinations: if any matches are found,
refuse to start the network.

Caveat: I'm not very networking savvy

Signed-off-by: Cole Robinson <crobinso redhat com>
---
 src/network/bridge_driver.c |   92 +++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 92 insertions(+), 0 deletions(-)

diff --git a/src/network/bridge_driver.c b/src/network/bridge_driver.c
index 5d7ef19..79da757 100644
--- a/src/network/bridge_driver.c
+++ b/src/network/bridge_driver.c
@@ -42,6 +42,8 @@
 #include <stdio.h>
 #include <sys/wait.h>
 #include <sys/ioctl.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include "virterror_internal.h"
 #include "datatypes.h"
@@ -908,6 +910,92 @@ cleanup:
     return ret;
 }
 
+#define PROC_NET_ROUTE "/proc/net/route"
+
+static int networkCheckRouteCollision(virNetworkObjPtr network)
+{
+    int ret = -1, len;
+    char *cur, *buf = NULL;
+    enum {MAX_ROUTE_SIZE = 1024*64};
+    struct in_addr inaddress, innetmask;
+    char *netaddr = NULL;
+
+    if (!network->def->ipAddress || !network->def->netmask)
+        return 0;
+
+    if (inet_pton(AF_INET, network->def->ipAddress, &inaddress) <= 0) {
+        networkReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("cannot parse IP address '%s'"),
+                           network->def->ipAddress);
+        goto error;
+    }
+    if (inet_pton(AF_INET, network->def->netmask, &innetmask) <= 0) {
+        networkReportError(VIR_ERR_INTERNAL_ERROR,
+                           _("cannot parse netmask '%s'"),
+                           network->def->netmask);
+        goto error;
+    }
+
+    inaddress.s_addr &= innetmask.s_addr;
+    netaddr = strdup(inet_ntoa(inaddress));
+    if (!netaddr) {
+        virReportOOMError();
+        goto error;
+    }
+
+    /* Read whole routing table into memory */
+    if ((len = virFileReadAll(PROC_NET_ROUTE, MAX_ROUTE_SIZE, &buf)) < 0)
+        goto error;
+
+    /* Dropping the last character shouldn't hurt */
+    buf[len-1] = '\0';
+
+    /* First line is just headings, skip it */
+    cur = strchr(buf, '\n');
+
+    while (cur) {
+        char iface[17];
+        char dest_buf[128];
+        char *dest_ip;
+        struct in_addr in;
+        int num;
+        unsigned int addr_val;
+
+        cur++;
+        num = sscanf(cur, "%16s %127s", iface, dest_buf);
+        if (num != 2) {
+            networkReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Failed to parse %s"), PROC_NET_ROUTE);
+            goto error;
+        }
+
+        if (virStrToLong_ui(dest_buf, NULL, 16, &addr_val) < 0) {
+            networkReportError(VIR_ERR_INTERNAL_ERROR,
+                               _("Failed not convert network address %s"),
+                               dest_buf);
+            goto error;
+        }
+
+        in.s_addr = addr_val;
+        dest_ip = inet_ntoa(in);
+
+        if (STREQ(netaddr, dest_ip)) {
+            networkReportError(VIR_ERR_INTERNAL_ERROR,
+                              _("Network destination %s is already in use "
+                                "by interface %s"), netaddr, iface);
+            goto error;
+        }
+
+        cur = strchr(cur, '\n');
+    }
+
+    ret = 0;
+error:
+    VIR_FREE(buf);
+    VIR_FREE(netaddr);
+    return ret;
+}
+
 static int networkStartNetworkDaemon(struct network_driver *driver,
                                      virNetworkObjPtr network)
 {
@@ -919,6 +1007,10 @@ static int networkStartNetworkDaemon(struct network_driver *driver,
         return -1;
     }
 
+    /* Check to see if network collides with an existing route */
+    if (networkCheckRouteCollision(network) < 0)
+        return -1;
+
     if ((err = brAddBridge(driver->brctl, network->def->bridge))) {
         virReportSystemError(err,
                              _("cannot create bridge '%s'"),
-- 
1.6.6.1


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]