Provides functions to create and delete bridging devices and
to attach/detach slaves from bridging devices.

It currently relies on the ioctl() kernel interface. The long
term goal is to use the netlink interface for this.
---
 src/nm-system.c |  247 ++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 src/nm-system.h |   13 +++
 2 files changed, 259 insertions(+), 1 deletions(-)

diff --git a/src/nm-system.c b/src/nm-system.c
index 6a35997..a0e7275 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 <[email protected]>
  * Copyright (C) January, 1998 Sergei Viznyuk <[email protected]>
@@ -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,245 @@ 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 (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);
+
+       // 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

_______________________________________________
networkmanager-list mailing list
[email protected]
https://mail.gnome.org/mailman/listinfo/networkmanager-list

Reply via email to