[PATCH 2/5] bridge: Functions to create, delete, attach, and detach bridges



Adds a system API to create and delete bridging devices and to
attach/detach slaves from bridges.

It currently relies on ioctl(). Long term, it should be using
netlink via libnl.
---
 src/nm-system.c |  256 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/nm-system.h |   13 +++
 2 files changed, 268 insertions(+), 1 deletions(-)

diff --git a/src/nm-system.c b/src/nm-system.c
index 5156eee..8d49b98 100644
--- a/src/nm-system.c
+++ b/src/nm-system.c
@@ -15,7 +15,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  *
- * Copyright (C) 2004 - 2010 Red Hat, Inc.
+ * Copyright (C) 2004 - 2012 Red Hat, Inc.
  * Copyright (C) 2005 - 2008 Novell, Inc.
  * Copyright (C) 1996 - 1997 Yoichi Hariguchi <yoichi fore com>
  * Copyright (C) January, 1998 Sergei Viznyuk <sv phystech com>
@@ -44,6 +44,7 @@
 #include <linux/if.h>
 #include <linux/sockios.h>
 #include <linux/if_bonding.h>
+#include <linux/if_bridge.h>
 
 #include "nm-system.h"
 #include "nm-device.h"
@@ -1614,6 +1615,8 @@ nm_system_get_iface_type (int ifindex, const char *name)
 		res = NM_IFACE_TYPE_BOND;
 	else if (!g_strcmp0 (type, "vlan"))
 		res = NM_IFACE_TYPE_VLAN;
+	else if (!g_strcmp0 (type, "bridge"))
+		res = NM_IFACE_TYPE_BRIDGE;
 	else if (!g_strcmp0 (type, "dummy"))
 		res = NM_IFACE_TYPE_DUMMY;
 
@@ -2021,3 +2024,254 @@ nm_system_del_vlan_iface (const char *iface)
 	nl_cache_free (cache);
 	return (ret == 0) ? TRUE : FALSE;
 }
+
+static int
+nm_system_create_bridge_compat (const char *iface)
+{
+	int ret, fd;
+
+	if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return FALSE;
+	}
+
+#ifdef SIOCBRADDBR
+	ret = ioctl(fd, SIOCBRADDBR, iface);
+	if (ret < 0 && errno != -EEXIST)
+#endif
+	{
+		char _br[IFNAMSIZ];
+		unsigned long arg[3] = { BRCTL_ADD_BRIDGE, (unsigned long) _br };
+
+		strncpy(_br, iface, IFNAMSIZ);
+		ret = ioctl(fd, SIOCSIFBR, arg);
+	}
+
+	close (fd);
+
+	return ret < 0 ? errno : 0;
+}
+
+/**
+ * nm_system_create_bridge:
+ * @iface: Name bridging device to create
+ *
+ * Creates a new bridging device in the kernel. If a bridging device with
+ * the specified name already exists, it is being reused.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+nm_system_create_bridge (const char *iface)
+{
+	int err;
+
+	// FIXME: long term plan is to use netlink for this
+
+	err = nm_system_create_bridge_compat (iface);
+	if (err == -EEXIST) {
+		/* Reuse existing bridging devices */
+		return TRUE;
+	}
+
+	if (err < 0) {
+		nm_log_err (LOGD_DEVICE, "(%s): error while adding bridge: %s ",
+		            iface, strerror(err));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int
+nm_system_del_bridge_compat (const char *iface)
+{
+	int ret, fd;
+
+	if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return FALSE;
+	}
+
+#ifdef SIOCBRDELBR
+	ret = ioctl(fd, SIOCBRDELBR, iface);
+	if (ret < 0)
+#endif
+	{
+		char _br[IFNAMSIZ];
+		unsigned long arg[3]
+			= { BRCTL_DEL_BRIDGE, (unsigned long) _br };
+
+		strncpy(_br, iface, IFNAMSIZ);
+		ret = ioctl(fd, SIOCSIFBR, arg);
+	}
+
+	close (fd);
+
+	return ret < 0 ? errno : 0;
+}
+
+/**
+ * nm_system_del_bridge:
+ * @iface: Name of bridging device to delete
+ *
+ * Deletes the specified bridging device in the kernel.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ */
+gboolean
+nm_system_del_bridge (const char *iface)
+{
+	int err;
+
+	// FIXME: long term plan is to use netlink for this
+
+	err = nm_system_del_bridge_compat (iface);
+	if (err < 0) {
+		nm_log_err (LOGD_DEVICE, "(%s): error while deleting bridge: %s ",
+		            iface, strerror(err));
+		return FALSE;
+	}
+
+	return TRUE;
+}
+
+static int
+nm_system_bridge_attach_compat (gint master_ifindex,
+                                const char *master_iface,
+                                gint slave_ifindex,
+                                const char *slave_iface)
+{
+	int ret, fd;
+	struct ifreq ifr;
+
+	memset (&ifr, 0, sizeof(ifr));
+
+	if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return FALSE;
+	}
+
+	strncpy(ifr.ifr_name, master_iface, IFNAMSIZ);
+
+#ifdef SIOCBRADDIF
+	ifr.ifr_ifindex = slave_ifindex;
+	ret = ioctl(fd, SIOCBRADDIF, &ifr);
+	if (ret < 0)
+#endif
+	{
+		unsigned long args[4] = { BRCTL_ADD_IF, slave_ifindex, 0, 0 };
+
+		ifr.ifr_data = (char *) args;
+		ret = ioctl(fd, SIOCDEVPRIVATE, &ifr);
+	}
+
+	close (fd);
+
+	return ret < 0 ? errno : 0;
+}
+
+static int
+nm_system_bridge_detach_compat (gint master_ifindex,
+                                const char *master_iface,
+                                gint slave_ifindex,
+                                const char *slave_iface)
+{
+	int ret, fd;
+	struct ifreq ifr;
+
+	if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
+		nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
+		return FALSE;
+	}
+
+	memset (&ifr, 0, sizeof(ifr));
+	strncpy(ifr.ifr_name, master_iface, IFNAMSIZ);
+
+#ifdef SIOCBRDELIF
+	ifr.ifr_ifindex = slave_ifindex;
+	ret = ioctl(fd, SIOCBRDELIF, &ifr);
+	if (ret < 0)
+#endif
+	{
+		unsigned long args[4] = { BRCTL_DEL_IF, slave_ifindex, 0, 0 };
+
+		ifr.ifr_data = (char *) args;
+		ret = ioctl(fd, SIOCDEVPRIVATE, &ifr);
+	}
+
+	close (fd);
+
+	return ret < 0 ? errno : 0;
+}
+
+/**
+ * nm_system_bridge_attach:
+ * @master_ifindex: master device interface index
+ * @master_iface: master device interface name
+ * @slave_ifindex: slave device interface index
+ * @slave_iface: slave device interface name
+ *
+ * Attaches interface 'slave' to bridge 'master'
+ *
+ * Returns: %TRUE on success, or %FALSE
+ */
+gboolean
+nm_system_bridge_attach (gint master_ifindex,
+                         const char *master_iface,
+                         gint slave_ifindex,
+                         const char *slave_iface)
+{
+	g_return_val_if_fail (master_ifindex >= 0, FALSE);
+	g_return_val_if_fail (master_iface != NULL, FALSE);
+	g_return_val_if_fail (slave_ifindex >= 0, FALSE);
+	g_return_val_if_fail (slave_iface != NULL, FALSE);
+
+	if (!(nm_system_iface_get_flags (master_ifindex) & IFF_MASTER)) {
+		nm_log_err (LOGD_DEVICE, "(%s): interface is not a master", master_iface);
+		return FALSE;
+	}
+
+	if (nm_system_iface_get_flags (slave_ifindex) & IFF_SLAVE) {
+		nm_log_err (LOGD_DEVICE, "(%s): %s is already a slave",
+		            master_iface, slave_iface);
+		return FALSE;
+	}
+
+	// FIXME: long term plan is to use netlink for this
+
+	return !!nm_system_bridge_attach_compat (master_ifindex, master_iface,
+	                                         slave_ifindex, slave_iface);
+}
+
+/**
+ * nm_system_bridge_detach:
+ * @master_ifindex: master device interface index
+ * @master_iface: master device interface name
+ * @slave_ifindex: slave device interface index
+ * @slave_iface: slave device interface name
+ *
+ * Detaches the interface 'slave' from the bridge 'master'.
+ *
+ * Returns: %TRUE on success, or %FALSE
+ */
+gboolean
+nm_system_bridge_detach (gint master_ifindex,
+                         const char *master_iface,
+                         gint slave_ifindex,
+                         const char *slave_iface)
+{
+	g_return_val_if_fail (master_ifindex >= 0, FALSE);
+	g_return_val_if_fail (master_iface != NULL, FALSE);
+	g_return_val_if_fail (slave_ifindex >= 0, FALSE);
+	g_return_val_if_fail (slave_iface != NULL, FALSE);
+
+	/* Only release if this is actually a slave */
+	if (!(nm_system_iface_get_flags (slave_ifindex) & IFF_SLAVE))
+		return TRUE;
+
+	// FIXME: long term plan is to use netlink for this
+
+	return !!nm_system_bridge_detach_compat (master_ifindex, master_iface,
+	                                         slave_ifindex, slave_iface);
+}
diff --git a/src/nm-system.h b/src/nm-system.h
index 84ae6c2..859265b 100644
--- a/src/nm-system.h
+++ b/src/nm-system.h
@@ -107,6 +107,7 @@ enum {
 		NM_IFACE_TYPE_BOND,
 		NM_IFACE_TYPE_VLAN,
 		NM_IFACE_TYPE_DUMMY,
+		NM_IFACE_TYPE_BRIDGE,
 };
 
 int             nm_system_get_iface_type      (int ifindex, const char *name);
@@ -120,4 +121,16 @@ gboolean        nm_system_add_vlan_iface (NMConnection *connection,
                                           int parent_ifindex);
 gboolean        nm_system_del_vlan_iface (const char *iface);
 
+gboolean        nm_system_create_bridge (const char *iface);
+gboolean        nm_system_del_bridge (const char *iface);
+
+gboolean        nm_system_bridge_attach (gint master_ifindex,
+                                         const char *master_iface,
+                                         gint slave_ifindex,
+                                         const char *slave_iface);
+gboolean        nm_system_bridge_detach (gint master_ifindex,
+                                         const char *master_iface,
+                                         gint slave_ifindex,
+                                         const char *slave_iface);
+
 #endif
-- 
1.7.7.6



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