mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-06 12:50:33 +01:00
bridge: API to to create, delete, attach, and detach bridges
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.
This commit is contained in:
parent
3e3cffd0bd
commit
679212c03d
2 changed files with 257 additions and 1 deletions
243
src/nm-system.c
243
src/nm-system.c
|
|
@ -44,6 +44,7 @@
|
|||
#include <linux/sockios.h>
|
||||
#include <linux/if_bonding.h>
|
||||
#include <linux/if_vlan.h>
|
||||
#include <linux/if_bridge.h>
|
||||
|
||||
#include "nm-system.h"
|
||||
#include "nm-device.h"
|
||||
|
|
@ -1877,6 +1878,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;
|
||||
|
||||
|
|
@ -2313,3 +2316,243 @@ nm_system_del_vlan_iface (const char *iface)
|
|||
nl_cache_free (cache);
|
||||
return (ret == 0) ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
static int
|
||||
_bridge_create_compat (const char *iface)
|
||||
{
|
||||
int ret = 0, fd;
|
||||
|
||||
if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
|
||||
nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if (ioctl (fd, SIOCBRADDBR, iface) < 0)
|
||||
ret = -errno;
|
||||
|
||||
close (fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: use netlink */
|
||||
err = _bridge_create_compat (iface);
|
||||
if (err < 0 && err != -EEXIST) {
|
||||
nm_log_err (LOGD_DEVICE, "(%s): error while adding bridge: %s",
|
||||
iface, strerror (-err));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
_bridge_del_compat (const char *iface)
|
||||
{
|
||||
int ret = 0, fd;
|
||||
|
||||
if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
|
||||
nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
if (ioctl (fd, SIOCBRDELBR, iface) < 0)
|
||||
ret = -errno;
|
||||
|
||||
close (fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: use netlink */
|
||||
err = _bridge_del_compat (iface);
|
||||
if (err < 0 && err != -ENXIO) {
|
||||
nm_log_err (LOGD_DEVICE, "(%s): error while deleting bridge: %s ",
|
||||
iface, strerror (-err));
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static int
|
||||
_bridge_attach_compat (int master_ifindex,
|
||||
const char *master_iface,
|
||||
int slave_ifindex,
|
||||
const char *slave_iface)
|
||||
{
|
||||
int ret = 0, fd;
|
||||
struct ifreq ifr;
|
||||
|
||||
if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
|
||||
nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
memset (&ifr, 0, sizeof (ifr));
|
||||
strncpy (ifr.ifr_name, master_iface, IFNAMSIZ);
|
||||
ifr.ifr_ifindex = slave_ifindex;
|
||||
if (ioctl (fd, SIOCBRADDIF, &ifr) < 0)
|
||||
ret = -errno;
|
||||
|
||||
close (fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int
|
||||
_bridge_detach_compat (int master_ifindex,
|
||||
const char *master_iface,
|
||||
int slave_ifindex,
|
||||
const char *slave_iface)
|
||||
{
|
||||
int ret = 0, fd;
|
||||
struct ifreq ifr;
|
||||
|
||||
if ((fd = socket (AF_LOCAL, SOCK_STREAM, 0)) < 0) {
|
||||
nm_log_err (LOGD_DEVICE, "couldn't open control socket.");
|
||||
return -EBADF;
|
||||
}
|
||||
|
||||
memset (&ifr, 0, sizeof(ifr));
|
||||
strncpy (ifr.ifr_name, master_iface, IFNAMSIZ);
|
||||
ifr.ifr_ifindex = slave_ifindex;
|
||||
if (ioctl (fd, SIOCBRDELIF, &ifr) < 0)
|
||||
ret = -errno;
|
||||
|
||||
close (fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (int master_ifindex,
|
||||
const char *master_iface,
|
||||
int slave_ifindex,
|
||||
const char *slave_iface)
|
||||
{
|
||||
char *mif = NULL, *sif = NULL;
|
||||
int err = -1;
|
||||
|
||||
g_return_val_if_fail (master_ifindex >= 0, FALSE);
|
||||
g_return_val_if_fail (slave_ifindex >= 0, FALSE);
|
||||
|
||||
if (!master_iface) {
|
||||
mif = nm_netlink_index_to_iface (master_ifindex);
|
||||
if (mif == NULL) {
|
||||
nm_log_err (LOGD_DEVICE, "interface name lookup failed for index %d", master_ifindex);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!slave_ifindex) {
|
||||
sif = nm_netlink_index_to_iface (slave_ifindex);
|
||||
if (sif == NULL) {
|
||||
nm_log_err (LOGD_DEVICE, "interface name lookup failed for index %d", slave_ifindex);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: long term plan is to use netlink for this */
|
||||
err = _bridge_attach_compat (master_ifindex,
|
||||
mif ? mif : master_iface,
|
||||
slave_ifindex,
|
||||
sif ? sif : slave_iface);
|
||||
if (err < 0 && err != -EBUSY) {
|
||||
nm_log_err (LOGD_DEVICE, "(%s): failed to attach slave %s: %s",
|
||||
master_iface, slave_iface, strerror (-err));
|
||||
}
|
||||
|
||||
out:
|
||||
g_free (sif);
|
||||
g_free (mif);
|
||||
return err == 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 (int master_ifindex,
|
||||
const char *master_iface,
|
||||
int slave_ifindex,
|
||||
const char *slave_iface)
|
||||
{
|
||||
char *mif = NULL, *sif = NULL;
|
||||
int err = -1;
|
||||
|
||||
g_return_val_if_fail (master_ifindex >= 0, FALSE);
|
||||
g_return_val_if_fail (slave_ifindex >= 0, FALSE);
|
||||
|
||||
if (!master_iface) {
|
||||
mif = nm_netlink_index_to_iface (master_ifindex);
|
||||
if (mif == NULL) {
|
||||
nm_log_err (LOGD_DEVICE, "interface name lookup failed for index %d", master_ifindex);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
if (!slave_ifindex) {
|
||||
sif = nm_netlink_index_to_iface (slave_ifindex);
|
||||
if (sif == NULL) {
|
||||
nm_log_err (LOGD_DEVICE, "interface name lookup failed for index %d", slave_ifindex);
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
|
||||
/* FIXME: long term plan is to use netlink for this */
|
||||
err = _bridge_detach_compat (master_ifindex,
|
||||
mif ? mif : master_iface,
|
||||
slave_ifindex,
|
||||
sif ? sif : slave_iface);
|
||||
/* Kernel doesn't return an error detaching an already-detached interface */
|
||||
if (err < 0) {
|
||||
nm_log_err (LOGD_DEVICE, "(%s): failed to detach slave %s: %s",
|
||||
master_iface, slave_iface, strerror (-err));
|
||||
}
|
||||
|
||||
out:
|
||||
g_free (mif);
|
||||
g_free (sif);
|
||||
return err == 0 ? TRUE : FALSE;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -113,7 +113,8 @@ enum {
|
|||
NM_IFACE_TYPE_UNSPEC = 0,
|
||||
NM_IFACE_TYPE_BOND,
|
||||
NM_IFACE_TYPE_VLAN,
|
||||
NM_IFACE_TYPE_DUMMY,
|
||||
NM_IFACE_TYPE_BRIDGE,
|
||||
NM_IFACE_TYPE_DUMMY
|
||||
};
|
||||
|
||||
int nm_system_get_iface_type (int ifindex, const char *name);
|
||||
|
|
@ -127,4 +128,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 (int master_ifindex,
|
||||
const char *master_iface,
|
||||
int slave_ifindex,
|
||||
const char *slave_iface);
|
||||
gboolean nm_system_bridge_detach (int master_ifindex,
|
||||
const char *master_iface,
|
||||
int slave_ifindex,
|
||||
const char *slave_iface);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue