2012-10-29 19:02:45 -05:00
|
|
|
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
|
|
|
|
|
/* NetworkManager -- Network link manager
|
|
|
|
|
*
|
|
|
|
|
* This program is free software; you can redistribute it and/or modify
|
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
|
|
|
* (at your option) any later version.
|
|
|
|
|
*
|
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
|
*
|
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
|
* with this program; if not, write to the Free Software Foundation, Inc.,
|
|
|
|
|
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
|
*
|
2015-02-20 12:51:44 +01:00
|
|
|
* Copyright 2011 - 2015 Red Hat, Inc.
|
2012-10-29 19:02:45 -05:00
|
|
|
*/
|
|
|
|
|
|
2016-02-19 14:57:48 +01:00
|
|
|
#include "nm-default.h"
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
#include "nm-device-bridge.h"
|
|
|
|
|
|
2013-08-23 23:02:54 +02:00
|
|
|
#include <stdlib.h>
|
2012-10-29 19:02:45 -05:00
|
|
|
|
|
|
|
|
#include "NetworkManagerUtils.h"
|
|
|
|
|
#include "nm-device-private.h"
|
2016-11-21 00:43:52 +01:00
|
|
|
#include "platform/nm-platform.h"
|
2014-09-08 10:12:28 -05:00
|
|
|
#include "nm-device-factory.h"
|
2014-10-21 22:09:52 -04:00
|
|
|
#include "nm-core-internal.h"
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2016-11-23 13:14:08 +01:00
|
|
|
#include "introspection/org.freedesktop.NetworkManager.Device.Bridge.h"
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2014-08-02 15:14:26 +02:00
|
|
|
#include "nm-device-logging.h"
|
|
|
|
|
_LOG_DECLARE_SELF(NMDeviceBridge);
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
struct _NMDeviceBridge {
|
|
|
|
|
NMDevice parent;
|
|
|
|
|
};
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
struct _NMDeviceBridgeClass {
|
|
|
|
|
NMDeviceClass parent;
|
|
|
|
|
};
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2016-09-29 13:49:01 +02:00
|
|
|
G_DEFINE_TYPE (NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE)
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2015-04-17 15:15:38 +02:00
|
|
|
static NMDeviceCapabilities
|
2012-10-29 19:02:45 -05:00
|
|
|
get_generic_capabilities (NMDevice *dev)
|
|
|
|
|
{
|
2014-09-24 17:46:15 -05:00
|
|
|
return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE;
|
2012-10-29 19:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2015-01-20 20:25:25 +01:00
|
|
|
is_available (NMDevice *dev, NMDeviceCheckDevAvailableFlags flags)
|
2012-10-29 19:02:45 -05:00
|
|
|
{
|
2015-03-27 17:39:20 -05:00
|
|
|
return TRUE;
|
2012-10-29 19:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
2013-11-06 17:44:18 -06:00
|
|
|
static gboolean
|
|
|
|
|
check_connection_available (NMDevice *device,
|
|
|
|
|
NMConnection *connection,
|
2015-01-16 14:54:11 +01:00
|
|
|
NMDeviceCheckConAvailableFlags flags,
|
2013-11-06 17:44:18 -06:00
|
|
|
const char *specific_object)
|
|
|
|
|
{
|
|
|
|
|
/* Connections are always available because the carrier state is determined
|
|
|
|
|
* by the bridge port carrier states, not the bridge's state.
|
|
|
|
|
*/
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-29 19:02:45 -05:00
|
|
|
static gboolean
|
2014-05-30 13:44:53 -05:00
|
|
|
check_connection_compatible (NMDevice *device, NMConnection *connection)
|
2012-10-29 19:02:45 -05:00
|
|
|
{
|
|
|
|
|
NMSettingBridge *s_bridge;
|
2014-07-30 10:57:45 -04:00
|
|
|
const char *mac_address;
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2014-05-30 13:44:53 -05:00
|
|
|
if (!NM_DEVICE_CLASS (nm_device_bridge_parent_class)->check_connection_compatible (device, connection))
|
2013-03-07 07:44:36 -05:00
|
|
|
return FALSE;
|
|
|
|
|
|
2012-10-29 19:02:45 -05:00
|
|
|
s_bridge = nm_connection_get_setting_bridge (connection);
|
2014-05-30 13:44:53 -05:00
|
|
|
if (!s_bridge || !nm_connection_is_type (connection, NM_SETTING_BRIDGE_SETTING_NAME))
|
2012-10-29 19:02:45 -05:00
|
|
|
return FALSE;
|
|
|
|
|
|
2014-05-16 17:51:27 +02:00
|
|
|
mac_address = nm_setting_bridge_get_mac_address (s_bridge);
|
2014-09-24 16:58:07 -05:00
|
|
|
if (mac_address && nm_device_is_real (device)) {
|
2014-06-21 12:44:56 -04:00
|
|
|
const char *hw_addr;
|
2014-05-16 17:51:27 +02:00
|
|
|
|
2014-06-21 12:44:56 -04:00
|
|
|
hw_addr = nm_device_get_hw_address (device);
|
2014-07-30 10:57:45 -04:00
|
|
|
if (!hw_addr || !nm_utils_hwaddr_matches (hw_addr, -1, mac_address, -1))
|
2014-05-16 17:51:27 +02:00
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-29 19:02:45 -05:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
complete_connection (NMDevice *device,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
const char *specific_object,
|
|
|
|
|
const GSList *existing_connections,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
2014-08-05 14:13:42 -04:00
|
|
|
NMSettingBridge *s_bridge;
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2016-03-08 13:57:20 +01:00
|
|
|
nm_utils_complete_generic (NM_PLATFORM_GET,
|
|
|
|
|
connection,
|
2012-10-29 19:02:45 -05:00
|
|
|
NM_SETTING_BRIDGE_SETTING_NAME,
|
|
|
|
|
existing_connections,
|
|
|
|
|
NULL,
|
2014-08-25 16:21:59 +02:00
|
|
|
_("Bridge connection"),
|
2014-08-05 17:11:57 -04:00
|
|
|
"bridge",
|
2012-10-29 19:02:45 -05:00
|
|
|
TRUE);
|
|
|
|
|
|
|
|
|
|
s_bridge = nm_connection_get_setting_bridge (connection);
|
|
|
|
|
if (!s_bridge) {
|
|
|
|
|
s_bridge = (NMSettingBridge *) nm_setting_bridge_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_bridge));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2013-08-23 23:02:31 +02:00
|
|
|
typedef struct {
|
|
|
|
|
const char *name;
|
|
|
|
|
const char *sysname;
|
|
|
|
|
gboolean default_if_zero;
|
|
|
|
|
gboolean user_hz_compensate;
|
|
|
|
|
} Option;
|
|
|
|
|
|
|
|
|
|
static const Option master_options[] = {
|
|
|
|
|
{ NM_SETTING_BRIDGE_STP, "stp_state", FALSE, FALSE },
|
|
|
|
|
{ NM_SETTING_BRIDGE_PRIORITY, "priority", TRUE, FALSE },
|
|
|
|
|
{ NM_SETTING_BRIDGE_FORWARD_DELAY, "forward_delay", TRUE, TRUE },
|
|
|
|
|
{ NM_SETTING_BRIDGE_HELLO_TIME, "hello_time", TRUE, TRUE },
|
|
|
|
|
{ NM_SETTING_BRIDGE_MAX_AGE, "max_age", TRUE, TRUE },
|
|
|
|
|
{ NM_SETTING_BRIDGE_AGEING_TIME, "ageing_time", TRUE, TRUE },
|
2015-02-20 12:51:44 +01:00
|
|
|
{ NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "multicast_snooping", FALSE, FALSE },
|
2013-08-23 23:02:31 +02:00
|
|
|
{ NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
static const Option slave_options[] = {
|
|
|
|
|
{ NM_SETTING_BRIDGE_PORT_PRIORITY, "priority", TRUE, FALSE },
|
|
|
|
|
{ NM_SETTING_BRIDGE_PORT_PATH_COST, "path_cost", TRUE, FALSE },
|
2013-11-06 20:50:18 -06:00
|
|
|
{ NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", FALSE, FALSE },
|
2013-08-23 23:02:31 +02:00
|
|
|
{ NULL, NULL }
|
|
|
|
|
};
|
|
|
|
|
|
2012-10-29 19:02:45 -05:00
|
|
|
static void
|
2013-10-11 18:25:20 +02:00
|
|
|
commit_option (NMDevice *device, NMSetting *setting, const Option *option, gboolean slave)
|
2012-10-29 19:02:45 -05:00
|
|
|
{
|
2013-08-23 23:02:31 +02:00
|
|
|
int ifindex = nm_device_get_ifindex (device);
|
2012-10-29 19:02:45 -05:00
|
|
|
GParamSpec *pspec;
|
2013-03-22 10:49:19 +01:00
|
|
|
GValue val = G_VALUE_INIT;
|
2012-10-29 19:02:45 -05:00
|
|
|
guint32 uval = 0;
|
2013-08-23 23:02:31 +02:00
|
|
|
gs_free char *value = NULL;
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2013-10-11 18:25:20 +02:00
|
|
|
g_assert (setting);
|
|
|
|
|
|
2013-08-23 23:02:31 +02:00
|
|
|
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), option->name);
|
|
|
|
|
g_assert (pspec);
|
2012-10-29 19:02:45 -05:00
|
|
|
|
|
|
|
|
/* Get the property's value */
|
|
|
|
|
g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
2013-10-11 18:25:20 +02:00
|
|
|
g_object_get_property ((GObject *) setting, option->name, &val);
|
2012-10-29 19:02:45 -05:00
|
|
|
if (G_VALUE_HOLDS_BOOLEAN (&val))
|
|
|
|
|
uval = g_value_get_boolean (&val) ? 1 : 0;
|
|
|
|
|
else if (G_VALUE_HOLDS_UINT (&val)) {
|
|
|
|
|
uval = g_value_get_uint (&val);
|
|
|
|
|
|
|
|
|
|
/* zero means "unspecified" for some NM properties but isn't in the
|
|
|
|
|
* allowed kernel range, so reset the property to the default value.
|
|
|
|
|
*/
|
2013-08-23 23:02:31 +02:00
|
|
|
if (option->default_if_zero && uval == 0) {
|
2012-10-29 19:02:45 -05:00
|
|
|
g_value_unset (&val);
|
|
|
|
|
g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
|
|
|
|
g_param_value_set_default (pspec, &val);
|
|
|
|
|
uval = g_value_get_uint (&val);
|
|
|
|
|
}
|
2013-08-23 23:02:31 +02:00
|
|
|
|
|
|
|
|
/* Linux kernel bridge interfaces use 'centiseconds' for time-based values.
|
|
|
|
|
* In reality it's not centiseconds, but depends on HZ and USER_HZ, which
|
|
|
|
|
* is almost always works out to be a multiplier of 100, so we can assume
|
|
|
|
|
* centiseconds. See clock_t_to_jiffies().
|
|
|
|
|
*/
|
|
|
|
|
if (option->user_hz_compensate)
|
|
|
|
|
uval *= 100;
|
2012-10-29 19:02:45 -05:00
|
|
|
} else
|
|
|
|
|
g_assert_not_reached ();
|
|
|
|
|
g_value_unset (&val);
|
|
|
|
|
|
2013-08-23 23:02:31 +02:00
|
|
|
value = g_strdup_printf ("%u", uval);
|
|
|
|
|
if (slave)
|
2015-12-09 17:33:30 +01:00
|
|
|
nm_platform_sysctl_slave_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value);
|
2013-08-23 23:02:31 +02:00
|
|
|
else
|
2015-12-09 17:33:30 +01:00
|
|
|
nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, option->sysname, value);
|
2012-10-29 19:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
2013-08-23 23:02:31 +02:00
|
|
|
static void
|
2013-10-11 18:25:20 +02:00
|
|
|
commit_master_options (NMDevice *device, NMSettingBridge *setting)
|
2012-10-29 19:02:45 -05:00
|
|
|
{
|
2013-08-23 23:02:31 +02:00
|
|
|
const Option *option;
|
2013-10-11 18:25:20 +02:00
|
|
|
NMSetting *s = NM_SETTING (setting);
|
2013-08-23 23:02:31 +02:00
|
|
|
|
|
|
|
|
for (option = master_options; option->name; option++)
|
2013-10-11 18:25:20 +02:00
|
|
|
commit_option (device, s, option, FALSE);
|
2013-08-23 23:02:31 +02:00
|
|
|
}
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2013-08-23 23:02:31 +02:00
|
|
|
static void
|
2013-10-11 18:25:20 +02:00
|
|
|
commit_slave_options (NMDevice *device, NMSettingBridgePort *setting)
|
2013-08-23 23:02:31 +02:00
|
|
|
{
|
|
|
|
|
const Option *option;
|
2013-10-11 18:25:20 +02:00
|
|
|
NMSetting *s, *s_clear = NULL;
|
2013-08-23 23:02:31 +02:00
|
|
|
|
2013-10-11 18:25:20 +02:00
|
|
|
if (setting)
|
|
|
|
|
s = NM_SETTING (setting);
|
|
|
|
|
else
|
|
|
|
|
s = s_clear = nm_setting_bridge_port_new ();
|
2013-08-23 23:02:31 +02:00
|
|
|
|
|
|
|
|
for (option = slave_options; option->name; option++)
|
2013-10-11 18:25:20 +02:00
|
|
|
commit_option (device, s, option, TRUE);
|
|
|
|
|
|
|
|
|
|
g_clear_object (&s_clear);
|
2013-08-23 23:02:31 +02:00
|
|
|
}
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2013-08-23 23:02:54 +02:00
|
|
|
static void
|
|
|
|
|
update_connection (NMDevice *device, NMConnection *connection)
|
|
|
|
|
{
|
2014-08-02 15:14:26 +02:00
|
|
|
NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
|
2013-08-23 23:02:54 +02:00
|
|
|
NMSettingBridge *s_bridge = nm_connection_get_setting_bridge (connection);
|
|
|
|
|
int ifindex = nm_device_get_ifindex (device);
|
|
|
|
|
const Option *option;
|
|
|
|
|
|
|
|
|
|
if (!s_bridge) {
|
|
|
|
|
s_bridge = (NMSettingBridge *) nm_setting_bridge_new ();
|
|
|
|
|
nm_connection_add_setting (connection, (NMSetting *) s_bridge);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (option = master_options; option->name; option++) {
|
2015-12-09 17:33:30 +01:00
|
|
|
gs_free char *str = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, option->sysname);
|
device: don't call strtol() for NULL strings
#1 0x0000003c47239ea2 in __GI_strtol (nptr=nptr@entry=0x0, endptr=endptr@entry=0x0, base=base@entry=10) at ../stdlib/strtol.c:110
#2 0x000000000043b896 in update_connection (device=<optimized out>, connection=<optimized out>) at devices/nm-device-bridge.c:308
#3 0x000000000042ed2f in nm_device_generate_connection (device=device@entry=0xfbb260 [NMDeviceBridge]) at devices/nm-device.c:1644
#4 0x0000000000481613 in get_existing_connection (device=0xfbb260 [NMDeviceBridge], manager=0xfb2000 [NMManager]) at nm-manager.c:1549
#5 add_device (self=self@entry=0xfb2000 [NMManager], device=device@entry=0xfbb260 [NMDeviceBridge], generate_con=<optimized out>)
at nm-manager.c:1688
#6 0x0000000000481f50 in platform_link_added (plink=0x7fffffffdd50, ifindex=695, self=0xfb2000 [NMManager], reason=<optimized out>)
at nm-manager.c:2023
#7 platform_link_cb (platform=<optimized out>, ifindex=695, plink=0x7fffffffdd50, change_type=<optimized out>, reason=<optimized out>,
user_data=<optimized out>) at nm-manager.c:2038
2014-06-06 18:22:06 +02:00
|
|
|
int value;
|
2013-08-23 23:02:54 +02:00
|
|
|
|
device: don't call strtol() for NULL strings
#1 0x0000003c47239ea2 in __GI_strtol (nptr=nptr@entry=0x0, endptr=endptr@entry=0x0, base=base@entry=10) at ../stdlib/strtol.c:110
#2 0x000000000043b896 in update_connection (device=<optimized out>, connection=<optimized out>) at devices/nm-device-bridge.c:308
#3 0x000000000042ed2f in nm_device_generate_connection (device=device@entry=0xfbb260 [NMDeviceBridge]) at devices/nm-device.c:1644
#4 0x0000000000481613 in get_existing_connection (device=0xfbb260 [NMDeviceBridge], manager=0xfb2000 [NMManager]) at nm-manager.c:1549
#5 add_device (self=self@entry=0xfb2000 [NMManager], device=device@entry=0xfbb260 [NMDeviceBridge], generate_con=<optimized out>)
at nm-manager.c:1688
#6 0x0000000000481f50 in platform_link_added (plink=0x7fffffffdd50, ifindex=695, self=0xfb2000 [NMManager], reason=<optimized out>)
at nm-manager.c:2023
#7 platform_link_cb (platform=<optimized out>, ifindex=695, plink=0x7fffffffdd50, change_type=<optimized out>, reason=<optimized out>,
user_data=<optimized out>) at nm-manager.c:2038
2014-06-06 18:22:06 +02:00
|
|
|
if (str) {
|
|
|
|
|
value = strtol (str, NULL, 10);
|
|
|
|
|
|
|
|
|
|
/* See comments in set_sysfs_uint() about centiseconds. */
|
|
|
|
|
if (option->user_hz_compensate)
|
|
|
|
|
value /= 100;
|
2013-08-23 23:02:54 +02:00
|
|
|
|
device: don't call strtol() for NULL strings
#1 0x0000003c47239ea2 in __GI_strtol (nptr=nptr@entry=0x0, endptr=endptr@entry=0x0, base=base@entry=10) at ../stdlib/strtol.c:110
#2 0x000000000043b896 in update_connection (device=<optimized out>, connection=<optimized out>) at devices/nm-device-bridge.c:308
#3 0x000000000042ed2f in nm_device_generate_connection (device=device@entry=0xfbb260 [NMDeviceBridge]) at devices/nm-device.c:1644
#4 0x0000000000481613 in get_existing_connection (device=0xfbb260 [NMDeviceBridge], manager=0xfb2000 [NMManager]) at nm-manager.c:1549
#5 add_device (self=self@entry=0xfb2000 [NMManager], device=device@entry=0xfbb260 [NMDeviceBridge], generate_con=<optimized out>)
at nm-manager.c:1688
#6 0x0000000000481f50 in platform_link_added (plink=0x7fffffffdd50, ifindex=695, self=0xfb2000 [NMManager], reason=<optimized out>)
at nm-manager.c:2023
#7 platform_link_cb (platform=<optimized out>, ifindex=695, plink=0x7fffffffdd50, change_type=<optimized out>, reason=<optimized out>,
user_data=<optimized out>) at nm-manager.c:2038
2014-06-06 18:22:06 +02:00
|
|
|
g_object_set (s_bridge, option->name, value, NULL);
|
2014-08-02 15:14:26 +02:00
|
|
|
} else
|
|
|
|
|
_LOGW (LOGD_BRIDGE, "failed to read bridge setting '%s'", option->sysname);
|
2013-08-23 23:02:54 +02:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2014-06-18 20:17:57 +02:00
|
|
|
static gboolean
|
2014-08-02 15:14:26 +02:00
|
|
|
master_update_slave_connection (NMDevice *device,
|
2014-06-18 20:17:57 +02:00
|
|
|
NMDevice *slave,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
GError **error)
|
2013-08-22 20:41:01 +02:00
|
|
|
{
|
2014-08-02 15:14:26 +02:00
|
|
|
NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
|
2014-06-18 20:17:57 +02:00
|
|
|
NMSettingConnection *s_con;
|
2013-08-22 20:41:01 +02:00
|
|
|
NMSettingBridgePort *s_port;
|
2014-06-18 20:17:57 +02:00
|
|
|
int ifindex_slave = nm_device_get_ifindex (slave);
|
2014-08-02 15:14:26 +02:00
|
|
|
const char *iface = nm_device_get_iface (device);
|
2013-08-22 20:41:01 +02:00
|
|
|
const Option *option;
|
|
|
|
|
|
2014-06-18 20:17:57 +02:00
|
|
|
g_return_val_if_fail (ifindex_slave > 0, FALSE);
|
2013-08-22 20:41:01 +02:00
|
|
|
|
2014-06-18 20:17:57 +02:00
|
|
|
s_con = nm_connection_get_setting_connection (connection);
|
2013-08-22 20:41:01 +02:00
|
|
|
s_port = nm_connection_get_setting_bridge_port (connection);
|
|
|
|
|
if (!s_port) {
|
|
|
|
|
s_port = (NMSettingBridgePort *) nm_setting_bridge_port_new ();
|
|
|
|
|
nm_connection_add_setting (connection, NM_SETTING (s_port));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (option = slave_options; option->name; option++) {
|
2015-12-09 17:33:30 +01:00
|
|
|
gs_free char *str = nm_platform_sysctl_slave_get_option (NM_PLATFORM_GET, ifindex_slave, option->sysname);
|
2013-08-22 20:41:01 +02:00
|
|
|
int value;
|
|
|
|
|
|
|
|
|
|
if (str) {
|
|
|
|
|
value = strtol (str, NULL, 10);
|
|
|
|
|
|
|
|
|
|
/* See comments in set_sysfs_uint() about centiseconds. */
|
|
|
|
|
if (option->user_hz_compensate)
|
|
|
|
|
value /= 100;
|
|
|
|
|
|
|
|
|
|
g_object_set (s_port, option->name, value, NULL);
|
2014-08-02 15:14:26 +02:00
|
|
|
} else
|
|
|
|
|
_LOGW (LOGD_BRIDGE, "failed to read bridge port setting '%s'", option->sysname);
|
2013-08-22 20:41:01 +02:00
|
|
|
}
|
|
|
|
|
|
2014-06-18 20:17:57 +02:00
|
|
|
g_object_set (s_con,
|
|
|
|
|
NM_SETTING_CONNECTION_MASTER, iface,
|
|
|
|
|
NM_SETTING_CONNECTION_SLAVE_TYPE, NM_SETTING_BRIDGE_SETTING_NAME,
|
|
|
|
|
NULL);
|
2013-08-22 20:41:01 +02:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2013-08-23 23:02:31 +02:00
|
|
|
static NMActStageReturn
|
|
|
|
|
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
|
|
|
|
|
{
|
|
|
|
|
NMActStageReturn ret;
|
2015-07-14 16:53:24 +02:00
|
|
|
NMConnection *connection = nm_device_get_applied_connection (device);
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2013-08-23 23:02:31 +02:00
|
|
|
g_assert (connection);
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2013-08-23 23:02:31 +02:00
|
|
|
ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage1_prepare (device, reason);
|
|
|
|
|
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
|
|
|
|
|
return ret;
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2016-10-21 14:40:37 +02:00
|
|
|
if (!nm_device_hw_addr_set_cloned (device, nm_device_get_applied_connection (device), FALSE))
|
|
|
|
|
return NM_ACT_STAGE_RETURN_FAILURE;
|
|
|
|
|
|
2013-10-11 18:25:20 +02:00
|
|
|
commit_master_options (device, nm_connection_get_setting_bridge (connection));
|
2013-08-23 23:02:31 +02:00
|
|
|
|
|
|
|
|
return NM_ACT_STAGE_RETURN_SUCCESS;
|
2012-10-29 19:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
2013-11-07 01:08:02 -06:00
|
|
|
enslave_slave (NMDevice *device,
|
|
|
|
|
NMDevice *slave,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
gboolean configure)
|
2012-10-29 19:02:45 -05:00
|
|
|
{
|
2014-08-02 15:14:26 +02:00
|
|
|
NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
|
|
|
|
|
|
2013-11-07 01:08:02 -06:00
|
|
|
if (configure) {
|
platform: add self argument to platform functions
Most nm_platform_*() functions operate on the platform
singleton nm_platform_get(). That made sense because the
NMPlatform instance was mainly to hook fake platform for
testing.
While the implicit argument saved some typing, I think explicit is
better. Especially, because NMPlatform could become a more usable
object then just a hook for testing.
With this change, NMPlatform instances can be used individually, not
only as a singleton instance.
Before this change, the constructor of NMLinuxPlatform could not
call any nm_platform_*() functions because the singleton was not
yet initialized. We could only instantiate an incomplete instance,
register it via nm_platform_setup(), and then complete initialization
via singleton->setup().
With this change, we can create and fully initialize NMPlatform instances
before/without setting them up them as singleton.
Also, currently there is no clear distinction between functions
that operate on the NMPlatform instance, and functions that can
be used stand-alone (e.g. nm_platform_ip4_address_to_string()).
The latter can not be mocked for testing. With this change, the
distinction becomes obvious. That is also useful because it becomes
clearer which functions make use of the platform cache and which not.
Inside nm-linux-platform.c, continue the pattern that the
self instance is named @platform. That makes sense because
its type is NMPlatform, and not NMLinuxPlatform what we
would expect from a paramter named @self.
This is a major diff that causes some pain when rebasing. Try
to rebase to the parent commit of this commit as a first step.
Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
|
|
|
if (!nm_platform_link_enslave (NM_PLATFORM_GET, nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)))
|
2013-11-07 01:08:02 -06:00
|
|
|
return FALSE;
|
2012-11-14 14:05:30 -06:00
|
|
|
|
2013-11-07 01:08:02 -06:00
|
|
|
commit_slave_options (slave, nm_connection_get_setting_bridge_port (connection));
|
2014-02-25 16:44:01 -05:00
|
|
|
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGI (LOGD_BRIDGE, "attached bridge port %s",
|
|
|
|
|
nm_device_get_ip_iface (slave));
|
2014-02-25 16:44:01 -05:00
|
|
|
} else {
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGI (LOGD_BRIDGE, "bridge port %s was attached",
|
|
|
|
|
nm_device_get_ip_iface (slave));
|
2013-11-07 01:08:02 -06:00
|
|
|
}
|
2012-11-14 14:05:30 -06:00
|
|
|
|
|
|
|
|
return TRUE;
|
2012-10-29 19:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
2015-12-02 09:56:17 +01:00
|
|
|
static void
|
2014-02-25 16:44:01 -05:00
|
|
|
release_slave (NMDevice *device,
|
|
|
|
|
NMDevice *slave,
|
|
|
|
|
gboolean configure)
|
2012-10-29 19:02:45 -05:00
|
|
|
{
|
2014-08-02 15:14:26 +02:00
|
|
|
NMDeviceBridge *self = NM_DEVICE_BRIDGE (device);
|
2015-12-02 09:56:17 +01:00
|
|
|
gboolean success;
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2014-02-25 16:44:01 -05:00
|
|
|
if (configure) {
|
platform: add self argument to platform functions
Most nm_platform_*() functions operate on the platform
singleton nm_platform_get(). That made sense because the
NMPlatform instance was mainly to hook fake platform for
testing.
While the implicit argument saved some typing, I think explicit is
better. Especially, because NMPlatform could become a more usable
object then just a hook for testing.
With this change, NMPlatform instances can be used individually, not
only as a singleton instance.
Before this change, the constructor of NMLinuxPlatform could not
call any nm_platform_*() functions because the singleton was not
yet initialized. We could only instantiate an incomplete instance,
register it via nm_platform_setup(), and then complete initialization
via singleton->setup().
With this change, we can create and fully initialize NMPlatform instances
before/without setting them up them as singleton.
Also, currently there is no clear distinction between functions
that operate on the NMPlatform instance, and functions that can
be used stand-alone (e.g. nm_platform_ip4_address_to_string()).
The latter can not be mocked for testing. With this change, the
distinction becomes obvious. That is also useful because it becomes
clearer which functions make use of the platform cache and which not.
Inside nm-linux-platform.c, continue the pattern that the
self instance is named @platform. That makes sense because
its type is NMPlatform, and not NMLinuxPlatform what we
would expect from a paramter named @self.
This is a major diff that causes some pain when rebasing. Try
to rebase to the parent commit of this commit as a first step.
Then rebase on top of this commit using merge-strategy "ours".
2015-04-18 12:36:09 +02:00
|
|
|
success = nm_platform_link_release (NM_PLATFORM_GET,
|
|
|
|
|
nm_device_get_ip_ifindex (device),
|
2014-02-25 16:44:01 -05:00
|
|
|
nm_device_get_ip_ifindex (slave));
|
2013-01-21 15:12:24 +01:00
|
|
|
|
2014-02-25 16:44:01 -05:00
|
|
|
if (success) {
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGI (LOGD_BRIDGE, "detached bridge port %s",
|
|
|
|
|
nm_device_get_ip_iface (slave));
|
2014-02-25 16:44:01 -05:00
|
|
|
} else {
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGW (LOGD_BRIDGE, "failed to detach bridge port %s",
|
|
|
|
|
nm_device_get_ip_iface (slave));
|
2014-02-25 16:44:01 -05:00
|
|
|
}
|
2014-02-25 16:41:33 -05:00
|
|
|
} else {
|
2014-08-02 15:14:26 +02:00
|
|
|
_LOGI (LOGD_BRIDGE, "bridge port %s was detached",
|
|
|
|
|
nm_device_get_ip_iface (slave));
|
2014-02-25 16:41:33 -05:00
|
|
|
}
|
2012-10-29 19:02:45 -05:00
|
|
|
}
|
|
|
|
|
|
2014-09-05 08:50:02 -05:00
|
|
|
static gboolean
|
|
|
|
|
create_and_realize (NMDevice *device,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
NMDevice *parent,
|
2015-12-09 15:13:57 +01:00
|
|
|
const NMPlatformLink **out_plink,
|
2014-09-05 08:50:02 -05:00
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
NMSettingBridge *s_bridge;
|
|
|
|
|
const char *iface = nm_device_get_iface (device);
|
|
|
|
|
const char *hwaddr;
|
|
|
|
|
guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX];
|
|
|
|
|
NMPlatformError plerr;
|
|
|
|
|
|
|
|
|
|
g_assert (iface);
|
|
|
|
|
|
|
|
|
|
s_bridge = nm_connection_get_setting_bridge (connection);
|
|
|
|
|
g_assert (s_bridge);
|
|
|
|
|
hwaddr = nm_setting_bridge_get_mac_address (s_bridge);
|
|
|
|
|
if (hwaddr) {
|
|
|
|
|
if (!nm_utils_hwaddr_aton (hwaddr, mac_address, ETH_ALEN)) {
|
|
|
|
|
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
|
|
|
|
|
"Invalid hardware address '%s'",
|
|
|
|
|
hwaddr);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2015-12-09 16:14:49 +01:00
|
|
|
plerr = nm_platform_link_bridge_add (NM_PLATFORM_GET,
|
|
|
|
|
iface,
|
|
|
|
|
hwaddr ? mac_address : NULL,
|
|
|
|
|
hwaddr ? ETH_ALEN : 0,
|
|
|
|
|
out_plink);
|
2016-01-25 13:03:51 +01:00
|
|
|
if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
|
2014-09-05 08:50:02 -05:00
|
|
|
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
|
|
|
|
|
"Failed to create bridge interface '%s' for '%s': %s",
|
|
|
|
|
iface,
|
|
|
|
|
nm_connection_get_id (connection),
|
|
|
|
|
nm_platform_error_to_string (plerr));
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2012-10-29 19:02:45 -05:00
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_device_bridge_init (NMDeviceBridge * self)
|
|
|
|
|
{
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
|
|
|
|
|
{
|
|
|
|
|
NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass);
|
|
|
|
|
|
2014-10-09 12:42:29 -05:00
|
|
|
NM_DEVICE_CLASS_DECLARE_TYPES (klass, NM_SETTING_BRIDGE_SETTING_NAME, NM_LINK_TYPE_BRIDGE)
|
2013-08-23 23:02:54 +02:00
|
|
|
|
2012-10-29 19:02:45 -05:00
|
|
|
parent_class->get_generic_capabilities = get_generic_capabilities;
|
|
|
|
|
parent_class->is_available = is_available;
|
|
|
|
|
parent_class->check_connection_compatible = check_connection_compatible;
|
2013-11-06 17:44:18 -06:00
|
|
|
parent_class->check_connection_available = check_connection_available;
|
2012-10-29 19:02:45 -05:00
|
|
|
parent_class->complete_connection = complete_connection;
|
|
|
|
|
|
2013-08-23 23:02:54 +02:00
|
|
|
parent_class->update_connection = update_connection;
|
2014-06-18 20:17:57 +02:00
|
|
|
parent_class->master_update_slave_connection = master_update_slave_connection;
|
2012-10-29 19:02:45 -05:00
|
|
|
|
2014-09-05 08:50:02 -05:00
|
|
|
parent_class->create_and_realize = create_and_realize;
|
2012-10-29 19:02:45 -05:00
|
|
|
parent_class->act_stage1_prepare = act_stage1_prepare;
|
|
|
|
|
parent_class->enslave_slave = enslave_slave;
|
|
|
|
|
parent_class->release_slave = release_slave;
|
|
|
|
|
|
2015-04-13 13:31:42 -04:00
|
|
|
nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
|
2015-04-15 14:53:30 -04:00
|
|
|
NMDBUS_TYPE_DEVICE_BRIDGE_SKELETON,
|
|
|
|
|
NULL);
|
2012-10-29 19:02:45 -05:00
|
|
|
}
|
2014-09-08 10:12:28 -05:00
|
|
|
|
2016-10-02 18:22:50 +02:00
|
|
|
/*****************************************************************************/
|
2014-09-08 10:12:28 -05:00
|
|
|
|
2016-10-07 17:00:59 +02:00
|
|
|
#define NM_TYPE_BRIDGE_DEVICE_FACTORY (nm_bridge_device_factory_get_type ())
|
|
|
|
|
#define NM_BRIDGE_DEVICE_FACTORY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_BRIDGE_DEVICE_FACTORY, NMBridgeDeviceFactory))
|
2014-09-08 10:12:28 -05:00
|
|
|
|
|
|
|
|
static NMDevice *
|
2014-09-05 08:50:02 -05:00
|
|
|
create_device (NMDeviceFactory *factory,
|
|
|
|
|
const char *iface,
|
2016-01-10 15:13:20 +01:00
|
|
|
const NMPlatformLink *plink,
|
2014-09-05 08:50:02 -05:00
|
|
|
NMConnection *connection,
|
|
|
|
|
gboolean *out_ignore)
|
2014-09-08 10:12:28 -05:00
|
|
|
{
|
|
|
|
|
return (NMDevice *) g_object_new (NM_TYPE_DEVICE_BRIDGE,
|
|
|
|
|
NM_DEVICE_IFACE, iface,
|
|
|
|
|
NM_DEVICE_DRIVER, "bridge",
|
|
|
|
|
NM_DEVICE_TYPE_DESC, "Bridge",
|
|
|
|
|
NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE,
|
2015-12-08 14:51:12 +01:00
|
|
|
NM_DEVICE_LINK_TYPE, NM_LINK_TYPE_BRIDGE,
|
2014-09-08 10:12:28 -05:00
|
|
|
NM_DEVICE_IS_MASTER, TRUE,
|
|
|
|
|
NULL);
|
|
|
|
|
}
|
|
|
|
|
|
2014-09-17 14:17:30 -05:00
|
|
|
NM_DEVICE_FACTORY_DEFINE_INTERNAL (BRIDGE, Bridge, bridge,
|
|
|
|
|
NM_DEVICE_FACTORY_DECLARE_LINK_TYPES (NM_LINK_TYPE_BRIDGE)
|
|
|
|
|
NM_DEVICE_FACTORY_DECLARE_SETTING_TYPES (NM_SETTING_BRIDGE_SETTING_NAME),
|
2016-10-07 16:05:43 +02:00
|
|
|
factory_class->create_device = create_device;
|
2016-09-29 13:49:01 +02:00
|
|
|
);
|