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
