#include "bridge.h"
#include "logging.h"
#include "dnsmasq.h"
+#include "util/network.h"
#define NETWORK_PID_DIR LOCAL_STATE_DIR "/run/libvirt/network"
#define NETWORK_STATE_DIR LOCAL_STATE_DIR "/lib/libvirt/network"
return ret;
}
+#define PROC_NET_ROUTE "/proc/net/route"
+
+/* XXX: This function can be a lot more exhaustive, there are certainly
+ * other scenarios where we can ruin host network connectivity.
+ * XXX: Using a proper library is preferred over parsing /proc
+ */
+static int networkCheckRouteCollision(virNetworkObjPtr network)
+{
+ int ret = -1, len;
+ unsigned int net_dest;
+ char *cur, *buf = NULL;
+ enum {MAX_ROUTE_SIZE = 1024*64};
+ virSocketAddr inaddress, innetmask;
+
+ if (!network->def->ipAddress || !network->def->netmask)
+ return 0;
+
+ if (virSocketParseAddr(network->def->ipAddress, &inaddress, 0) < 0) {
+ networkReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse IP address '%s'"),
+ network->def->ipAddress);
+ goto error;
+ }
+
+ if (virSocketParseAddr(network->def->netmask, &innetmask, 0) < 0) {
+ networkReportError(VIR_ERR_INTERNAL_ERROR,
+ _("cannot parse netmask '%s'"),
+ network->def->netmask);
+ goto error;
+ }
+
+ if (inaddress.stor.ss_family != AF_INET ||
+ innetmask.stor.ss_family != AF_INET) {
+ /* Only support collision check for IPv4 */
+ goto out;
+ }
+
+ net_dest = (inaddress.inet4.sin_addr.s_addr &
+ innetmask.inet4.sin_addr.s_addr);
+
+ /* 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 */
+ if (len > 0)
+ buf[len-1] = '\0';
+
+ VIR_DEBUG("%s output:\n%s", PROC_NET_ROUTE, buf);
+
+ if (!STRPREFIX (buf, "Iface"))
+ goto out;
+
+ /* First line is just headings, skip it */
+ cur = strchr(buf, '\n');
+ if (cur)
+ cur++;
+
+ while (cur) {
+ char iface[17], dest[128], mask[128];
+ unsigned int addr_val, mask_val;
+ int num;
+
+ /* NUL-terminate the line, so sscanf doesn't go beyond a newline. */
+ char *nl = strchr(cur, '\n');
+ if (nl) {
+ *nl++ = '\0';
+ }
+
+ num = sscanf(cur, "%16s %127s %*s %*s %*s %*s %*s %127s",
+ iface, dest, mask);
+ cur = nl;
+
+ if (num != 3) {
+ VIR_DEBUG("Failed to parse %s", PROC_NET_ROUTE);
+ continue;
+ }
+
+ if (virStrToLong_ui(dest, NULL, 16, &addr_val) < 0) {
+ VIR_DEBUG("Failed to convert network address %s to uint", dest);
+ continue;
+ }
+
+ if (virStrToLong_ui(mask, NULL, 16, &mask_val) < 0) {
+ VIR_DEBUG("Failed to convert network mask %s to uint", mask);
+ continue;
+ }
+
+ addr_val &= mask_val;
+
+ if ((net_dest == addr_val) &&
+ (innetmask.inet4.sin_addr.s_addr == mask_val)) {
+ networkReportError(VIR_ERR_INTERNAL_ERROR,
+ _("Network %s/%s is already in use by "
+ "interface %s"),
+ network->def->ipAddress,
+ network->def->netmask, iface);
+ goto error;
+ }
+ }
+
+out:
+ ret = 0;
+error:
+ VIR_FREE(buf);
+ return ret;
+}
+
static int networkStartNetworkDaemon(struct network_driver *driver,
virNetworkObjPtr network)
{
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'"),