[PATCH 2/5] bridge: Functions to create, delete, attach, and detach bridges
- From: Thomas Graf <tgraf redhat com>
- To: networkmanager-list gnome org
- Cc: Thomas Graf <tgraf redhat com>
- Subject: [PATCH 2/5] bridge: Functions to create, delete, attach, and detach bridges
- Date: Fri, 11 May 2012 16:01:34 +0200
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]