core: use nm_platform_*_*_option() for bridges
And refactor to prepare for update_connection() implementation. Acked-by: Dan Winship <danw@gnome.org>
This commit is contained in:
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include <netinet/ether.h>
|
#include <netinet/ether.h>
|
||||||
|
|
||||||
|
#include "gsystem-local-alloc.h"
|
||||||
#include "nm-device-bridge.h"
|
#include "nm-device-bridge.h"
|
||||||
#include "nm-logging.h"
|
#include "nm-logging.h"
|
||||||
#include "nm-utils.h"
|
#include "nm-utils.h"
|
||||||
@@ -177,26 +178,45 @@ match_l2_config (NMDevice *self, NMConnection *connection)
|
|||||||
|
|
||||||
/******************************************************************/
|
/******************************************************************/
|
||||||
|
|
||||||
|
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 },
|
||||||
|
{ 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 },
|
||||||
|
{ NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "harpin_mode", FALSE, FALSE },
|
||||||
|
{ NULL, NULL }
|
||||||
|
};
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_sysfs_uint (const char *iface,
|
commit_option (NMDevice *device, GObject *setting, const Option *option, gboolean slave)
|
||||||
GObject *obj,
|
|
||||||
const char *obj_prop,
|
|
||||||
const char *dir,
|
|
||||||
const char *sysfs_prop,
|
|
||||||
gboolean default_if_zero,
|
|
||||||
gboolean user_hz_compensate)
|
|
||||||
{
|
{
|
||||||
char *path, *s;
|
int ifindex = nm_device_get_ifindex (device);
|
||||||
GParamSpec *pspec;
|
GParamSpec *pspec;
|
||||||
GValue val = G_VALUE_INIT;
|
GValue val = G_VALUE_INIT;
|
||||||
guint32 uval = 0;
|
guint32 uval = 0;
|
||||||
|
gs_free char *value = NULL;
|
||||||
|
|
||||||
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), obj_prop);
|
pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (setting), option->name);
|
||||||
g_return_if_fail (pspec != NULL);
|
g_assert (pspec);
|
||||||
|
|
||||||
/* Get the property's value */
|
/* Get the property's value */
|
||||||
g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
||||||
g_object_get_property (obj, obj_prop, &val);
|
g_object_get_property (setting, option->name, &val);
|
||||||
if (G_VALUE_HOLDS_BOOLEAN (&val))
|
if (G_VALUE_HOLDS_BOOLEAN (&val))
|
||||||
uval = g_value_get_boolean (&val) ? 1 : 0;
|
uval = g_value_get_boolean (&val) ? 1 : 0;
|
||||||
else if (G_VALUE_HOLDS_UINT (&val)) {
|
else if (G_VALUE_HOLDS_UINT (&val)) {
|
||||||
@@ -205,88 +225,81 @@ set_sysfs_uint (const char *iface,
|
|||||||
/* zero means "unspecified" for some NM properties but isn't in the
|
/* zero means "unspecified" for some NM properties but isn't in the
|
||||||
* allowed kernel range, so reset the property to the default value.
|
* allowed kernel range, so reset the property to the default value.
|
||||||
*/
|
*/
|
||||||
if (default_if_zero && uval == 0) {
|
if (option->default_if_zero && uval == 0) {
|
||||||
g_value_unset (&val);
|
g_value_unset (&val);
|
||||||
g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec));
|
||||||
g_param_value_set_default (pspec, &val);
|
g_param_value_set_default (pspec, &val);
|
||||||
uval = g_value_get_uint (&val);
|
uval = g_value_get_uint (&val);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* 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;
|
||||||
} else
|
} else
|
||||||
g_assert_not_reached ();
|
g_assert_not_reached ();
|
||||||
|
|
||||||
g_value_unset (&val);
|
g_value_unset (&val);
|
||||||
|
|
||||||
/* Linux kernel bridge interfaces use 'centiseconds' for time-based values.
|
value = g_strdup_printf ("%u", uval);
|
||||||
* In reality it's not centiseconds, but depends on HZ and USER_HZ, which
|
if (slave)
|
||||||
* is almost always works out to be a multiplier of 100, so we can assume
|
nm_platform_slave_set_option (ifindex, option->sysname, value);
|
||||||
* centiseconds. See clock_t_to_jiffies().
|
else
|
||||||
*/
|
nm_platform_master_set_option (ifindex, option->sysname, value);
|
||||||
if (user_hz_compensate)
|
}
|
||||||
uval *= 100;
|
|
||||||
|
|
||||||
path = g_strdup_printf ("/sys/class/net/%s/%s/%s", iface, dir, sysfs_prop);
|
static void
|
||||||
s = g_strdup_printf ("%u", uval);
|
commit_master_options (NMDevice *device, GObject *setting)
|
||||||
/* FIXME: how should failure be handled? */
|
{
|
||||||
nm_utils_do_sysctl (path, s);
|
const Option *option;
|
||||||
g_free (path);
|
|
||||||
g_free (s);
|
g_assert (setting);
|
||||||
|
|
||||||
|
for (option = master_options; option->name; option++)
|
||||||
|
commit_option (device, setting, option, FALSE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
commit_slave_options (NMDevice *device, GObject *setting)
|
||||||
|
{
|
||||||
|
const Option *option;
|
||||||
|
|
||||||
|
g_assert (setting);
|
||||||
|
|
||||||
|
for (option = slave_options; option->name; option++)
|
||||||
|
commit_option (device, setting, option, TRUE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static NMActStageReturn
|
static NMActStageReturn
|
||||||
act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
|
act_stage1_prepare (NMDevice *device, NMDeviceStateReason *reason)
|
||||||
{
|
{
|
||||||
NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
|
NMActStageReturn ret;
|
||||||
NMConnection *connection;
|
NMConnection *connection = nm_device_get_connection (device);
|
||||||
NMSettingBridge *s_bridge;
|
|
||||||
const char *iface;
|
|
||||||
|
|
||||||
g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
|
g_assert (connection);
|
||||||
|
|
||||||
ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage1_prepare (dev, reason);
|
ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage1_prepare (device, reason);
|
||||||
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
|
if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
|
||||||
connection = nm_device_get_connection (dev);
|
return ret;
|
||||||
g_assert (connection);
|
|
||||||
|
|
||||||
s_bridge = nm_connection_get_setting_bridge (connection);
|
commit_master_options (device, (GObject *) nm_connection_get_setting_bridge (connection));
|
||||||
g_assert (s_bridge);
|
|
||||||
|
|
||||||
iface = nm_device_get_ip_iface (dev);
|
return NM_ACT_STAGE_RETURN_SUCCESS;
|
||||||
g_assert (iface);
|
|
||||||
|
|
||||||
set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_STP, "bridge", "stp_state", FALSE, FALSE);
|
|
||||||
set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_PRIORITY, "bridge", "priority", TRUE, FALSE);
|
|
||||||
set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY, "bridge", "forward_delay", TRUE, TRUE);
|
|
||||||
set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME, "bridge", "hello_time", TRUE, TRUE);
|
|
||||||
set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_MAX_AGE, "bridge", "max_age", TRUE, TRUE);
|
|
||||||
set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME, "bridge", "ageing_time", TRUE, TRUE);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
|
enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
|
||||||
{
|
{
|
||||||
gboolean success;
|
if (!nm_platform_link_enslave (nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)))
|
||||||
NMSettingBridgePort *s_port;
|
|
||||||
const char *iface = nm_device_get_ip_iface (device);
|
|
||||||
const char *slave_iface = nm_device_get_ip_iface (slave);
|
|
||||||
|
|
||||||
success = nm_platform_link_enslave (nm_device_get_ip_ifindex (device),
|
|
||||||
nm_device_get_ip_ifindex (slave));
|
|
||||||
|
|
||||||
if (!success)
|
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
/* Set port properties */
|
commit_slave_options (slave, (GObject *) nm_connection_get_setting_bridge_port (connection));
|
||||||
s_port = nm_connection_get_setting_bridge_port (connection);
|
|
||||||
if (s_port) {
|
|
||||||
set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY, "brport", "priority", TRUE, FALSE);
|
|
||||||
set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST, "brport", "path_cost", TRUE, FALSE);
|
|
||||||
set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "brport", "hairpin_mode", FALSE, FALSE);
|
|
||||||
}
|
|
||||||
|
|
||||||
nm_log_info (LOGD_BRIDGE, "(%s): attached bridge port %s", iface, slave_iface);
|
|
||||||
|
|
||||||
|
nm_log_info (LOGD_BRIDGE, "(%s): attached bridge port %s",
|
||||||
|
nm_device_get_ip_iface (device),
|
||||||
|
nm_device_get_ip_iface (slave));
|
||||||
g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES);
|
g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
Reference in New Issue
Block a user