diff options
| author | Michael Biebl <biebl@debian.org> | 2021-02-11 18:11:46 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2021-02-11 18:11:46 +0100 |
| commit | 80ec1decc49c72efec2a8b87c06245c92c0ab807 (patch) | |
| tree | e3b229aa94e8dcf0590f2317664176e7b8f7607b /src/devices/nm-device-bridge.c | |
| parent | 65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (diff) | |
New upstream version 1.29.90 upstream/1.29.90
Diffstat (limited to 'src/devices/nm-device-bridge.c')
| -rw-r--r-- | src/devices/nm-device-bridge.c | 1245 |
1 files changed, 0 insertions, 1245 deletions
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c deleted file mode 100644 index 48dcec1b..00000000 --- a/src/devices/nm-device-bridge.c +++ /dev/null @@ -1,1245 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2011 - 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-device-bridge.h" - -#include <stdlib.h> - -#include "NetworkManagerUtils.h" -#include "nm-device-private.h" -#include "platform/nm-platform.h" -#include "nm-device-factory.h" -#include "nm-core-internal.h" - -#include "nm-device-logging.h" -_LOG_DECLARE_SELF(NMDeviceBridge); - -/*****************************************************************************/ - -struct _NMDeviceBridge { - NMDevice parent; - GCancellable *bt_cancellable; - bool vlan_configured : 1; - bool bt_registered : 1; -}; - -struct _NMDeviceBridgeClass { - NMDeviceClass parent; -}; - -G_DEFINE_TYPE(NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE) - -/*****************************************************************************/ - -const NMBtVTableNetworkServer *nm_bt_vtable_network_server = NULL; - -/*****************************************************************************/ - -static NMDeviceCapabilities -get_generic_capabilities(NMDevice *dev) -{ - return NM_DEVICE_CAP_CARRIER_DETECT | NM_DEVICE_CAP_IS_SOFTWARE; -} - -static gboolean -check_connection_available(NMDevice * device, - NMConnection * connection, - NMDeviceCheckConAvailableFlags flags, - const char * specific_object, - GError ** error) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMSettingBluetooth *s_bt; - - if (!NM_DEVICE_CLASS(nm_device_bridge_parent_class) - ->check_connection_available(device, connection, flags, specific_object, error)) - return FALSE; - - s_bt = _nm_connection_get_setting_bluetooth_for_nap(connection); - if (s_bt) { - const char *bdaddr; - - if (!nm_bt_vtable_network_server) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "bluetooth plugin not available to activate NAP profile"); - return FALSE; - } - - bdaddr = nm_setting_bluetooth_get_bdaddr(s_bt); - if (!nm_bt_vtable_network_server->is_available( - nm_bt_vtable_network_server, - bdaddr, - (self->bt_cancellable || self->bt_registered) ? device : NULL)) { - if (bdaddr) - nm_utils_error_set(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "no suitable NAP device \"%s\" available", - bdaddr); - else - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "no suitable NAP device available"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -check_connection_compatible(NMDevice *device, NMConnection *connection, GError **error) -{ - NMSettingBridge *s_bridge; - const char * mac_address; - - if (!NM_DEVICE_CLASS(nm_device_bridge_parent_class) - ->check_connection_compatible(device, connection, error)) - return FALSE; - - if (nm_connection_is_type(connection, NM_SETTING_BLUETOOTH_SETTING_NAME) - && _nm_connection_get_setting_bluetooth_for_nap(connection)) { - s_bridge = nm_connection_get_setting_bridge(connection); - if (!s_bridge) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "missing bridge setting for bluetooth NAP profile"); - return FALSE; - } - - /* a bluetooth NAP connection is handled by the bridge. - * - * Proceed... */ - } else { - s_bridge = - _nm_connection_check_main_setting(connection, NM_SETTING_BRIDGE_SETTING_NAME, error); - if (!s_bridge) - return FALSE; - } - - mac_address = nm_setting_bridge_get_mac_address(s_bridge); - if (mac_address && nm_device_is_real(device)) { - const char *hw_addr; - - hw_addr = nm_device_get_hw_address(device); - if (!hw_addr || !nm_utils_hwaddr_matches(hw_addr, -1, mac_address, -1)) { - nm_utils_error_set_literal(error, - NM_UTILS_ERROR_CONNECTION_AVAILABLE_TEMPORARY, - "mac address mismatches"); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -complete_connection(NMDevice * device, - NMConnection * connection, - const char * specific_object, - NMConnection *const *existing_connections, - GError ** error) -{ - NMSettingBridge *s_bridge; - - nm_utils_complete_generic(nm_device_get_platform(device), - connection, - NM_SETTING_BRIDGE_SETTING_NAME, - existing_connections, - NULL, - _("Bridge connection"), - "bridge", - NULL, - 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; -} - -static void -to_sysfs_group_address_sys(const char *group_address, NMEtherAddr *out_addr) -{ - if (group_address == NULL) { - *out_addr = (NMEtherAddr) NM_ETHER_ADDR_INIT(NM_BRIDGE_GROUP_ADDRESS_DEF_BIN); - return; - } - if (!nm_utils_hwaddr_aton(group_address, out_addr, ETH_ALEN)) - nm_assert_not_reached(); -} - -static void -from_sysfs_group_address(const char *value, GValue *out) -{ - if (!nm_utils_hwaddr_matches(value, -1, NM_BRIDGE_GROUP_ADDRESS_DEF_STR, -1)) - g_value_set_string(out, value); -} - -static const char * -to_sysfs_group_address(GValue *value) -{ - return g_value_get_string(value) ?: NM_BRIDGE_GROUP_ADDRESS_DEF_STR; -} - -static int -to_sysfs_vlan_protocol_sys(const char *value) -{ - if (nm_streq0(value, "802.1ad")) - return ETH_P_8021AD; - - return ETH_P_8021Q; -} - -static void -from_sysfs_vlan_protocol(const char *value, GValue *out) -{ - switch (_nm_utils_ascii_str_to_uint64(value, 16, 0, G_MAXUINT, -1)) { - case ETH_P_8021Q: - /* default value */ - break; - case ETH_P_8021AD: - g_value_set_string(out, "802.1ad"); - break; - } -} - -static const char * -to_sysfs_vlan_protocol(GValue *value) -{ - const char *str = g_value_get_string(value); - - if (nm_streq0(str, "802.1ad")) { - G_STATIC_ASSERT_EXPR(ETH_P_8021AD == 0x88A8); - return "0x88A8"; - } - - G_STATIC_ASSERT_EXPR(ETH_P_8021Q == 0x8100); - return "0x8100"; -} - -static int -to_sysfs_multicast_router_sys(const char *value) -{ - if (nm_streq0(value, "disabled")) - return 0; - if (nm_streq0(value, "auto")) - return 1; - if (nm_streq0(value, "enabled")) - return 2; - - return 1; -} - -static const char * -to_sysfs_multicast_router(GValue *value) -{ - const char *str = g_value_get_string(value); - - if (nm_streq0(str, "disabled")) - return "0"; - if (nm_streq0(str, "auto")) - return "1"; - if (nm_streq0(str, "enabled")) - return "2"; - - return "1"; -} - -static void -from_sysfs_multicast_router(const char *value, GValue *out) -{ - switch (_nm_utils_ascii_str_to_uint64(value, 10, 0, G_MAXUINT, -1)) { - case 0: - g_value_set_string(out, "disabled"); - break; - case 2: - g_value_set_string(out, "enabled"); - break; - case 1: - default: - /* default value */ - break; - } -} - -/*****************************************************************************/ -#define _DEFAULT_IF_ZERO(val, def_val) \ - ({ \ - typeof(val) _val = (val); \ - typeof(val) _def_val = (def_val); \ - \ - (_val == 0) ? _def_val : _val; \ - }) - -typedef struct { - const char *name; - const char *sysname; - const char *(*to_sysfs)(GValue *value); - void (*from_sysfs)(const char *value, GValue *out); - guint64 nm_min; - guint64 nm_max; - guint64 nm_default; - bool default_if_zero; - bool user_hz_compensate; - bool only_with_stp; -} Option; - -#define OPTION(_name, _sysname, ...) \ - { \ - .name = ""_name \ - "", \ - .sysname = ""_sysname \ - "", \ - __VA_ARGS__ \ - } - -#define OPTION_TYPE_INT(min, max, def) .nm_min = (min), .nm_max = (max), .nm_default = (def) - -#define OPTION_TYPE_BOOL(def) OPTION_TYPE_INT(FALSE, TRUE, def) - -#define OPTION_TYPE_TOFROM(to, fro) .to_sysfs = (to), .from_sysfs = (fro) - -static const Option master_options[] = { - OPTION(NM_SETTING_BRIDGE_STP, /* this must stay as the first item */ - "stp_state", - OPTION_TYPE_BOOL(NM_BRIDGE_STP_DEF), ), - OPTION(NM_SETTING_BRIDGE_PRIORITY, - "priority", - OPTION_TYPE_INT(NM_BRIDGE_PRIORITY_MIN, NM_BRIDGE_PRIORITY_MAX, NM_BRIDGE_PRIORITY_DEF), - .default_if_zero = TRUE, - .only_with_stp = TRUE, ), - OPTION(NM_SETTING_BRIDGE_FORWARD_DELAY, - "forward_delay", - OPTION_TYPE_INT(NM_BRIDGE_FORWARD_DELAY_MIN, - NM_BRIDGE_FORWARD_DELAY_MAX, - NM_BRIDGE_FORWARD_DELAY_DEF), - .default_if_zero = TRUE, - .user_hz_compensate = TRUE, - .only_with_stp = TRUE, ), - OPTION(NM_SETTING_BRIDGE_HELLO_TIME, - "hello_time", - OPTION_TYPE_INT(NM_BRIDGE_HELLO_TIME_MIN, - NM_BRIDGE_HELLO_TIME_MAX, - NM_BRIDGE_HELLO_TIME_DEF), - .default_if_zero = TRUE, - .user_hz_compensate = TRUE, - .only_with_stp = TRUE, ), - OPTION(NM_SETTING_BRIDGE_MAX_AGE, - "max_age", - OPTION_TYPE_INT(NM_BRIDGE_MAX_AGE_MIN, NM_BRIDGE_MAX_AGE_MAX, NM_BRIDGE_MAX_AGE_DEF), - .default_if_zero = TRUE, - .user_hz_compensate = TRUE, - .only_with_stp = TRUE, ), - OPTION(NM_SETTING_BRIDGE_AGEING_TIME, - "ageing_time", - OPTION_TYPE_INT(NM_BRIDGE_AGEING_TIME_MIN, - NM_BRIDGE_AGEING_TIME_MAX, - NM_BRIDGE_AGEING_TIME_DEF), - .default_if_zero = TRUE, - .user_hz_compensate = TRUE, ), - OPTION(NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, "group_fwd_mask", OPTION_TYPE_INT(0, 0xFFFF, 0), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_HASH_MAX, - "hash_max", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_HASH_MAX_MIN, - NM_BRIDGE_MULTICAST_HASH_MAX_MAX, - NM_BRIDGE_MULTICAST_HASH_MAX_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_COUNT, - "multicast_last_member_count", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_MIN, - NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_MAX, - NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL, - "multicast_last_member_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL, - "multicast_membership_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERIER, - "multicast_querier", - OPTION_TYPE_BOOL(NM_BRIDGE_MULTICAST_QUERIER_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERIER_INTERVAL, - "multicast_querier_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERY_INTERVAL, - "multicast_query_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_QUERY_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_QUERY_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_QUERY_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL, - "multicast_query_response_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, - "multicast_query_use_ifaddr", - OPTION_TYPE_BOOL(NM_BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_SNOOPING, - "multicast_snooping", - OPTION_TYPE_BOOL(NM_BRIDGE_MULTICAST_SNOOPING_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_ROUTER, - "multicast_router", - OPTION_TYPE_TOFROM(to_sysfs_multicast_router, from_sysfs_multicast_router), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT, - "multicast_startup_query_count", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_MIN, - NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_MAX, - NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_DEF), ), - OPTION(NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL, - "multicast_startup_query_interval", - OPTION_TYPE_INT(NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_MIN, - NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_MAX, - NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_DEF), ), - OPTION(NM_SETTING_BRIDGE_GROUP_ADDRESS, - "group_addr", - OPTION_TYPE_TOFROM(to_sysfs_group_address, from_sysfs_group_address), ), - OPTION(NM_SETTING_BRIDGE_VLAN_PROTOCOL, - "vlan_protocol", - OPTION_TYPE_TOFROM(to_sysfs_vlan_protocol, from_sysfs_vlan_protocol), ), - OPTION(NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, - "vlan_stats_enabled", - OPTION_TYPE_BOOL(NM_BRIDGE_VLAN_STATS_ENABLED_DEF)), - { - 0, - }}; - -static const Option slave_options[] = { - OPTION(NM_SETTING_BRIDGE_PORT_PRIORITY, - "priority", - OPTION_TYPE_INT(NM_BRIDGE_PORT_PRIORITY_MIN, - NM_BRIDGE_PORT_PRIORITY_MAX, - NM_BRIDGE_PORT_PRIORITY_DEF), - .default_if_zero = TRUE, ), - OPTION(NM_SETTING_BRIDGE_PORT_PATH_COST, - "path_cost", - OPTION_TYPE_INT(NM_BRIDGE_PORT_PATH_COST_MIN, - NM_BRIDGE_PORT_PATH_COST_MAX, - NM_BRIDGE_PORT_PATH_COST_DEF), - .default_if_zero = TRUE, ), - OPTION(NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", OPTION_TYPE_BOOL(FALSE), ), - {0}}; - -static void -commit_option(NMDevice *device, NMSetting *setting, const Option *option, gboolean slave) -{ - int ifindex = nm_device_get_ifindex(device); - nm_auto_unset_gvalue GValue val = G_VALUE_INIT; - GParamSpec * pspec; - const char * value; - char value_buf[100]; - - if (slave) - nm_assert(NM_IS_SETTING_BRIDGE_PORT(setting)); - else - nm_assert(NM_IS_SETTING_BRIDGE(setting)); - - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(setting), option->name); - nm_assert(pspec); - - g_value_init(&val, G_PARAM_SPEC_VALUE_TYPE(pspec)); - g_object_get_property((GObject *) setting, option->name, &val); - - if (option->to_sysfs) { - value = option->to_sysfs(&val); - goto out; - } - - switch (pspec->value_type) { - case G_TYPE_BOOLEAN: - value = g_value_get_boolean(&val) ? "1" : "0"; - break; - case G_TYPE_UINT64: - case G_TYPE_UINT: - { - guint64 uval; - - if (pspec->value_type == G_TYPE_UINT64) - uval = g_value_get_uint64(&val); - else - uval = (guint) 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. - */ - if (option->default_if_zero && uval == 0) { - if (pspec->value_type == G_TYPE_UINT64) - uval = NM_G_PARAM_SPEC_GET_DEFAULT_UINT64(pspec); - else - uval = NM_G_PARAM_SPEC_GET_DEFAULT_UINT(pspec); - } - - /* 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; - - if (pspec->value_type == G_TYPE_UINT64) - nm_sprintf_buf(value_buf, "%" G_GUINT64_FORMAT, uval); - else - nm_sprintf_buf(value_buf, "%u", (guint) uval); - - value = value_buf; - } break; - case G_TYPE_STRING: - value = g_value_get_string(&val); - break; - default: - nm_assert_not_reached(); - value = NULL; - break; - } - -out: - if (!value) - return; - - if (slave) { - nm_platform_sysctl_slave_set_option(nm_device_get_platform(device), - ifindex, - option->sysname, - value); - } else { - nm_platform_sysctl_master_set_option(nm_device_get_platform(device), - ifindex, - option->sysname, - value); - } -} - -static const NMPlatformBridgeVlan ** -setting_vlans_to_platform(GPtrArray *array) -{ - NMPlatformBridgeVlan **arr; - NMPlatformBridgeVlan * p_data; - guint i; - - if (!array || !array->len) - return NULL; - - G_STATIC_ASSERT_EXPR(_nm_alignof(NMPlatformBridgeVlan *) >= _nm_alignof(NMPlatformBridgeVlan)); - arr = g_malloc((sizeof(NMPlatformBridgeVlan *) * (array->len + 1)) - + (sizeof(NMPlatformBridgeVlan) * (array->len))); - p_data = (NMPlatformBridgeVlan *) &arr[array->len + 1]; - - for (i = 0; i < array->len; i++) { - NMBridgeVlan *vlan = array->pdata[i]; - guint16 vid_start, vid_end; - - nm_bridge_vlan_get_vid_range(vlan, &vid_start, &vid_end); - - p_data[i] = (NMPlatformBridgeVlan){ - .vid_start = vid_start, - .vid_end = vid_end, - .pvid = nm_bridge_vlan_is_pvid(vlan), - .untagged = nm_bridge_vlan_is_untagged(vlan), - }; - arr[i] = &p_data[i]; - } - arr[i] = NULL; - return (const NMPlatformBridgeVlan **) arr; -} - -static void -commit_slave_options(NMDevice *device, NMSettingBridgePort *setting) -{ - const Option * option; - NMSetting * s; - gs_unref_object NMSetting *s_clear = NULL; - - if (setting) - s = NM_SETTING(setting); - else - s = s_clear = nm_setting_bridge_port_new(); - - for (option = slave_options; option->name; option++) - commit_option(device, s, option, TRUE); -} - -static void -update_connection(NMDevice *device, NMConnection *connection) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMSettingBridge *s_bridge = nm_connection_get_setting_bridge(connection); - int ifindex = nm_device_get_ifindex(device); - const Option * option; - gs_free char * stp = NULL; - int stp_value; - - if (!s_bridge) { - s_bridge = (NMSettingBridge *) nm_setting_bridge_new(); - nm_connection_add_setting(connection, (NMSetting *) s_bridge); - } - - option = master_options; - nm_assert(nm_streq(option->sysname, "stp_state")); - - stp = nm_platform_sysctl_master_get_option(nm_device_get_platform(device), - ifindex, - option->sysname); - stp_value = - _nm_utils_ascii_str_to_int64(stp, 10, option->nm_min, option->nm_max, option->nm_default); - g_object_set(s_bridge, option->name, stp_value, NULL); - option++; - - for (; option->name; option++) { - nm_auto_unset_gvalue GValue value = G_VALUE_INIT; - gs_free char * str = NULL; - GParamSpec * pspec; - - str = nm_platform_sysctl_master_get_option(nm_device_get_platform(device), - ifindex, - option->sysname); - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(s_bridge), option->name); - - if (!stp_value && option->only_with_stp) - continue; - - if (!str) { - _LOGW(LOGD_BRIDGE, "failed to read bridge setting '%s'", option->sysname); - continue; - } - - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - - if (option->from_sysfs) { - option->from_sysfs(str, &value); - goto out; - } - - switch (pspec->value_type) { - case G_TYPE_UINT64: - case G_TYPE_UINT: - { - guint64 uvalue; - - /* See comments in set_sysfs_uint() about centiseconds. */ - if (option->user_hz_compensate) { - uvalue = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min * 100, - option->nm_max * 100, - option->nm_default * 100); - uvalue /= 100; - } else { - uvalue = _nm_utils_ascii_str_to_uint64(str, - 10, - option->nm_min, - option->nm_max, - option->nm_default); - } - - if (pspec->value_type == G_TYPE_UINT64) - g_value_set_uint64(&value, uvalue); - else - g_value_set_uint(&value, (guint) uvalue); - } break; - case G_TYPE_BOOLEAN: - { - gboolean bvalue; - - bvalue = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min, - option->nm_max, - option->nm_default); - g_value_set_boolean(&value, bvalue); - } break; - case G_TYPE_STRING: - g_value_set_string(&value, str); - break; - default: - nm_assert_not_reached(); - break; - } - -out: - g_object_set_property(G_OBJECT(s_bridge), option->name, &value); - } -} - -static gboolean -master_update_slave_connection(NMDevice * device, - NMDevice * slave, - NMConnection *connection, - GError ** error) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMSettingConnection *s_con; - NMSettingBridgePort *s_port; - int ifindex_slave = nm_device_get_ifindex(slave); - const char * iface = nm_device_get_iface(device); - const Option * option; - - g_return_val_if_fail(ifindex_slave > 0, FALSE); - - s_con = nm_connection_get_setting_connection(connection); - 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++) { - gs_free char *str = nm_platform_sysctl_slave_get_option(nm_device_get_platform(device), - ifindex_slave, - option->sysname); - uint value; - - if (str) { - /* See comments in set_sysfs_uint() about centiseconds. */ - if (option->user_hz_compensate) { - value = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min * 100, - option->nm_max * 100, - option->nm_default * 100); - value /= 100; - } else { - value = _nm_utils_ascii_str_to_int64(str, - 10, - option->nm_min, - option->nm_max, - option->nm_default); - } - g_object_set(s_port, option->name, value, NULL); - } else - _LOGW(LOGD_BRIDGE, "failed to read bridge port setting '%s'", option->sysname); - } - - g_object_set(s_con, - NM_SETTING_CONNECTION_MASTER, - iface, - NM_SETTING_CONNECTION_SLAVE_TYPE, - NM_SETTING_BRIDGE_SETTING_NAME, - NULL); - return TRUE; -} - -static gboolean -bridge_set_vlan_options(NMDevice *device, NMSettingBridge *s_bridge) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - gconstpointer hwaddr; - size_t length; - gboolean enabled; - guint16 pvid; - NMPlatform * plat; - int ifindex; - gs_unref_ptrarray GPtrArray *vlans = NULL; - gs_free const NMPlatformBridgeVlan **plat_vlans = NULL; - - if (self->vlan_configured) - return TRUE; - - plat = nm_device_get_platform(device); - ifindex = nm_device_get_ifindex(device); - enabled = nm_setting_bridge_get_vlan_filtering(s_bridge); - - if (!enabled) { - nm_platform_sysctl_master_set_option(plat, ifindex, "vlan_filtering", "0"); - nm_platform_sysctl_master_set_option(plat, ifindex, "default_pvid", "1"); - nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL); - return TRUE; - } - - hwaddr = nm_platform_link_get_address(plat, ifindex, &length); - g_return_val_if_fail(length == ETH_ALEN, FALSE); - if (nm_utils_hwaddr_matches(hwaddr, length, &nm_ether_addr_zero, ETH_ALEN)) { - /* We need a non-zero MAC address to set the default pvid. - * Retry later. */ - return TRUE; - } - - self->vlan_configured = TRUE; - - /* Filtering must be disabled to change the default PVID */ - if (!nm_platform_sysctl_master_set_option(plat, ifindex, "vlan_filtering", "0")) - return FALSE; - - /* Clear the default PVID so that we later can force the re-creation of - * default PVID VLANs by writing the option again. */ - if (!nm_platform_sysctl_master_set_option(plat, ifindex, "default_pvid", "0")) - return FALSE; - - /* Clear all existing VLANs */ - if (!nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, NULL)) - return FALSE; - - /* Now set the default PVID. After this point the kernel creates - * a PVID VLAN on each port, including the bridge itself. */ - pvid = nm_setting_bridge_get_vlan_default_pvid(s_bridge); - if (pvid) { - char value[32]; - - nm_sprintf_buf(value, "%u", pvid); - if (!nm_platform_sysctl_master_set_option(plat, ifindex, "default_pvid", value)) - return FALSE; - } - - /* Create VLANs only after setting the default PVID, so that - * any PVID VLAN overrides the bridge's default PVID. */ - g_object_get(s_bridge, NM_SETTING_BRIDGE_VLANS, &vlans, NULL); - plat_vlans = setting_vlans_to_platform(vlans); - if (plat_vlans && !nm_platform_link_set_bridge_vlans(plat, ifindex, FALSE, plat_vlans)) - return FALSE; - - if (!nm_platform_sysctl_master_set_option(plat, ifindex, "vlan_filtering", "1")) - return FALSE; - - return TRUE; -} - -static NMActStageReturn -act_stage1_prepare(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMConnection *connection; - NMSetting * s_bridge; - const Option *option; - - connection = nm_device_get_applied_connection(device); - g_return_val_if_fail(connection, NM_ACT_STAGE_RETURN_FAILURE); - - s_bridge = (NMSetting *) nm_connection_get_setting_bridge(connection); - g_return_val_if_fail(s_bridge, NM_ACT_STAGE_RETURN_FAILURE); - - for (option = master_options; option->name; option++) - commit_option(device, s_bridge, option, FALSE); - - if (!bridge_set_vlan_options(device, (NMSettingBridge *) s_bridge)) { - NM_SET_OUT(out_failure_reason, NM_DEVICE_STATE_REASON_CONFIG_FAILED); - return NM_ACT_STAGE_RETURN_FAILURE; - } - - return NM_ACT_STAGE_RETURN_SUCCESS; -} - -static void -_bt_register_bridge_cb(GError *error, gpointer user_data) -{ - NMDeviceBridge *self; - - if (nm_utils_error_is_cancelled(error)) - return; - - self = user_data; - - g_clear_object(&self->bt_cancellable); - - if (error) { - _LOGD(LOGD_DEVICE, "bluetooth NAP server failed to register bridge: %s", error->message); - nm_device_state_changed(NM_DEVICE(self), - NM_DEVICE_STATE_FAILED, - NM_DEVICE_STATE_REASON_BT_FAILED); - return; - } - - nm_device_activate_schedule_stage2_device_config(NM_DEVICE(self), FALSE); -} - -void -_nm_device_bridge_notify_unregister_bt_nap(NMDevice *device, const char *reason) -{ - NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); - - _LOGD(LOGD_DEVICE, - "bluetooth NAP server unregistered from bridge: %s%s", - reason, - self->bt_registered ? "" : " (was no longer registered)"); - - nm_clear_g_cancellable(&self->bt_cancellable); - - if (self->bt_registered) { - self->bt_registered = FALSE; - nm_device_state_changed(device, NM_DEVICE_STATE_FAILED, NM_DEVICE_STATE_REASON_BT_FAILED); - } -} - -static NMActStageReturn -act_stage2_config(NMDevice *device, NMDeviceStateReason *out_failure_reason) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMConnection * connection; - NMSettingBluetooth *s_bt; - gs_free_error GError *error = NULL; - - connection = nm_device_get_applied_connection(device); - - s_bt = _nm_connection_get_setting_bluetooth_for_nap(connection); - if (!s_bt) - return NM_ACT_STAGE_RETURN_SUCCESS; - - if (!nm_bt_vtable_network_server) { - _LOGD(LOGD_DEVICE, "bluetooth NAP server failed because bluetooth plugin not available"); - *out_failure_reason = NM_DEVICE_STATE_REASON_BT_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - if (self->bt_cancellable) - return NM_ACT_STAGE_RETURN_POSTPONE; - - if (self->bt_registered) - return NM_ACT_STAGE_RETURN_POSTPONE; - - self->bt_cancellable = g_cancellable_new(); - if (!nm_bt_vtable_network_server->register_bridge(nm_bt_vtable_network_server, - nm_setting_bluetooth_get_bdaddr(s_bt), - device, - self->bt_cancellable, - _bt_register_bridge_cb, - device, - &error)) { - _LOGD(LOGD_DEVICE, "bluetooth NAP server failed to register bridge: %s", error->message); - *out_failure_reason = NM_DEVICE_STATE_REASON_BT_FAILED; - return NM_ACT_STAGE_RETURN_FAILURE; - } - - self->bt_registered = TRUE; - return NM_ACT_STAGE_RETURN_POSTPONE; -} - -static void -deactivate(NMDevice *device) -{ - NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); - - _LOGD(LOGD_DEVICE, - "deactivate bridge%s", - self->bt_registered ? " (registered as NAP bluetooth device)" : ""); - - self->vlan_configured = FALSE; - - nm_clear_g_cancellable(&self->bt_cancellable); - - if (self->bt_registered) { - self->bt_registered = FALSE; - nm_bt_vtable_network_server->unregister_bridge(nm_bt_vtable_network_server, device); - } -} - -static gboolean -enslave_slave(NMDevice *device, NMDevice *slave, NMConnection *connection, gboolean configure) -{ - NMDeviceBridge * self = NM_DEVICE_BRIDGE(device); - NMConnection * master_connection; - NMSettingBridge * s_bridge; - NMSettingBridgePort *s_port; - - if (configure) { - if (!nm_platform_link_enslave(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - nm_device_get_ip_ifindex(slave))) - return FALSE; - - master_connection = nm_device_get_applied_connection(device); - nm_assert(master_connection); - s_bridge = nm_connection_get_setting_bridge(master_connection); - nm_assert(s_bridge); - s_port = nm_connection_get_setting_bridge_port(connection); - - bridge_set_vlan_options(device, s_bridge); - - if (nm_setting_bridge_get_vlan_filtering(s_bridge)) { - gs_free const NMPlatformBridgeVlan **plat_vlans = NULL; - gs_unref_ptrarray GPtrArray *vlans = NULL; - - if (s_port) - g_object_get(s_port, NM_SETTING_BRIDGE_PORT_VLANS, &vlans, NULL); - - plat_vlans = setting_vlans_to_platform(vlans); - - /* Since the link was just enslaved, there are no existing VLANs - * (except for the default one) and so there's no need to flush. */ - - if (plat_vlans - && !nm_platform_link_set_bridge_vlans(nm_device_get_platform(slave), - nm_device_get_ifindex(slave), - TRUE, - plat_vlans)) - return FALSE; - } - - commit_slave_options(slave, s_port); - - _LOGI(LOGD_BRIDGE, "attached bridge port %s", nm_device_get_ip_iface(slave)); - } else { - _LOGI(LOGD_BRIDGE, "bridge port %s was attached", nm_device_get_ip_iface(slave)); - } - - return TRUE; -} - -static void -release_slave(NMDevice *device, NMDevice *slave, gboolean configure) -{ - NMDeviceBridge *self = NM_DEVICE_BRIDGE(device); - gboolean success; - int ifindex_slave; - int ifindex; - - if (configure) { - ifindex = nm_device_get_ifindex(device); - if (ifindex <= 0 || !nm_platform_link_get(nm_device_get_platform(device), ifindex)) - configure = FALSE; - } - - ifindex_slave = nm_device_get_ip_ifindex(slave); - - if (ifindex_slave <= 0) { - _LOGD(LOGD_TEAM, "bond slave %s is already released", nm_device_get_ip_iface(slave)); - return; - } - - if (configure) { - success = nm_platform_link_release(nm_device_get_platform(device), - nm_device_get_ip_ifindex(device), - ifindex_slave); - - if (success) { - _LOGI(LOGD_BRIDGE, "detached bridge port %s", nm_device_get_ip_iface(slave)); - } else { - _LOGW(LOGD_BRIDGE, "failed to detach bridge port %s", nm_device_get_ip_iface(slave)); - } - } else { - _LOGI(LOGD_BRIDGE, "bridge port %s was detached", nm_device_get_ip_iface(slave)); - } -} - -static gboolean -create_and_realize(NMDevice * device, - NMConnection * connection, - NMDevice * parent, - const NMPlatformLink **out_plink, - GError ** error) -{ - NMSettingWired * s_wired; - NMSettingBridge * s_bridge; - const char * iface = nm_device_get_iface(device); - const char * hwaddr; - gs_free char * hwaddr_cloned = NULL; - guint8 mac_address[NM_UTILS_HWADDR_LEN_MAX]; - NMPlatformLnkBridge props; - int r; - guint32 mtu = 0; - - nm_assert(iface); - - s_bridge = nm_connection_get_setting_bridge(connection); - nm_assert(s_bridge); - - s_wired = nm_connection_get_setting_wired(connection); - if (s_wired) - mtu = nm_setting_wired_get_mtu(s_wired); - - hwaddr = nm_setting_bridge_get_mac_address(s_bridge); - if (!hwaddr - && nm_device_hw_addr_get_cloned(device, connection, FALSE, &hwaddr_cloned, NULL, NULL)) { - /* FIXME: we set the MAC address when creating the interface, while the - * NMDevice is still unrealized. As we afterwards realize the device, it - * forgets the parameters for the cloned MAC address, and in stage 1 - * it might create a different MAC address. That should be fixed by - * better handling device realization. */ - hwaddr = hwaddr_cloned; - } - - 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); - g_return_val_if_reached(FALSE); - } - } - - props = (NMPlatformLnkBridge){ - .forward_delay = _DEFAULT_IF_ZERO(nm_setting_bridge_get_forward_delay(s_bridge) * 100u, - NM_BRIDGE_FORWARD_DELAY_DEF_SYS), - .hello_time = _DEFAULT_IF_ZERO(nm_setting_bridge_get_hello_time(s_bridge) * 100u, - NM_BRIDGE_HELLO_TIME_DEF_SYS), - .max_age = _DEFAULT_IF_ZERO(nm_setting_bridge_get_max_age(s_bridge) * 100u, - NM_BRIDGE_MAX_AGE_DEF_SYS), - .ageing_time = _DEFAULT_IF_ZERO(nm_setting_bridge_get_ageing_time(s_bridge) * 100u, - NM_BRIDGE_AGEING_TIME_DEF_SYS), - .stp_state = nm_setting_bridge_get_stp(s_bridge), - .priority = nm_setting_bridge_get_priority(s_bridge), - .vlan_protocol = to_sysfs_vlan_protocol_sys(nm_setting_bridge_get_vlan_protocol(s_bridge)), - .vlan_stats_enabled = nm_setting_bridge_get_vlan_stats_enabled(s_bridge), - .group_fwd_mask = nm_setting_bridge_get_group_forward_mask(s_bridge), - .mcast_snooping = nm_setting_bridge_get_multicast_snooping(s_bridge), - .mcast_router = - to_sysfs_multicast_router_sys(nm_setting_bridge_get_multicast_router(s_bridge)), - .mcast_query_use_ifaddr = nm_setting_bridge_get_multicast_query_use_ifaddr(s_bridge), - .mcast_querier = nm_setting_bridge_get_multicast_querier(s_bridge), - .mcast_hash_max = nm_setting_bridge_get_multicast_hash_max(s_bridge), - .mcast_last_member_count = nm_setting_bridge_get_multicast_last_member_count(s_bridge), - .mcast_startup_query_count = nm_setting_bridge_get_multicast_startup_query_count(s_bridge), - .mcast_last_member_interval = - nm_setting_bridge_get_multicast_last_member_interval(s_bridge), - .mcast_membership_interval = nm_setting_bridge_get_multicast_membership_interval(s_bridge), - .mcast_querier_interval = nm_setting_bridge_get_multicast_querier_interval(s_bridge), - .mcast_query_interval = nm_setting_bridge_get_multicast_query_interval(s_bridge), - .mcast_query_response_interval = - nm_setting_bridge_get_multicast_query_response_interval(s_bridge), - .mcast_startup_query_interval = - nm_setting_bridge_get_multicast_startup_query_interval(s_bridge), - }; - - to_sysfs_group_address_sys(nm_setting_bridge_get_group_address(s_bridge), &props.group_addr); - - /* If mtu != 0, we set the MTU of the new bridge at creation time. However, kernel will still - * automatically adjust the MTU of the bridge based on the minimum of the slave's MTU. - * We don't want this automatism as the user asked for a fixed MTU. - * - * To workaround this behavior of kernel, we will later toggle the MTU twice. See - * NMDeviceClass.mtu_force_set. */ - r = nm_platform_link_bridge_add(nm_device_get_platform(device), - iface, - hwaddr ? mac_address : NULL, - hwaddr ? ETH_ALEN : 0, - mtu, - &props, - out_plink); - if (r < 0) { - 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_strerror(r)); - return FALSE; - } - - return TRUE; -} - -/*****************************************************************************/ - -static void -nm_device_bridge_init(NMDeviceBridge *self) -{ - nm_assert(nm_device_is_master(NM_DEVICE(self))); -} - -static const NMDBusInterfaceInfoExtended interface_info_device_bridge = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_DEVICE_BRIDGE, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("HwAddress", - "s", - NM_DEVICE_HW_ADDRESS), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Carrier", "b", NM_DEVICE_CARRIER), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Slaves", - "ao", - NM_DEVICE_SLAVES), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_device_bridge_class_init(NMDeviceBridgeClass *klass) -{ - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(klass); - NMDeviceClass * device_class = NM_DEVICE_CLASS(klass); - - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_device_bridge); - - device_class->connection_type_supported = NM_SETTING_BRIDGE_SETTING_NAME; - device_class->link_types = NM_DEVICE_DEFINE_LINK_TYPES(NM_LINK_TYPE_BRIDGE); - - device_class->is_master = TRUE; - device_class->mtu_force_set = TRUE; - device_class->get_generic_capabilities = get_generic_capabilities; - device_class->check_connection_compatible = check_connection_compatible; - device_class->check_connection_available = check_connection_available; - device_class->complete_connection = complete_connection; - - device_class->update_connection = update_connection; - device_class->master_update_slave_connection = master_update_slave_connection; - - device_class->create_and_realize = create_and_realize; - device_class->act_stage1_prepare_set_hwaddr_ethernet = TRUE; - device_class->act_stage1_prepare = act_stage1_prepare; - device_class->act_stage2_config = act_stage2_config; - device_class->deactivate = deactivate; - device_class->enslave_slave = enslave_slave; - device_class->release_slave = release_slave; - device_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired; -} - -/*****************************************************************************/ - -#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)) - -static NMDevice * -create_device(NMDeviceFactory * factory, - const char * iface, - const NMPlatformLink *plink, - NMConnection * connection, - gboolean * out_ignore) -{ - 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, - NM_DEVICE_LINK_TYPE, - NM_LINK_TYPE_BRIDGE, - NULL); -} - -static gboolean -match_connection(NMDeviceFactory *factory, NMConnection *connection) -{ - const char *type = nm_connection_get_connection_type(connection); - - if (nm_streq(type, NM_SETTING_BRIDGE_SETTING_NAME)) - return TRUE; - - nm_assert(nm_streq(type, NM_SETTING_BLUETOOTH_SETTING_NAME)); - - if (!_nm_connection_get_setting_bluetooth_for_nap(connection)) - return FALSE; - - if (!g_type_from_name("NMBluezManager")) { - /* bluetooth NAP connections are handled by bridge factory. However, - * it needs help from the bluetooth plugin, so if the plugin is not loaded, - * we claim not to support it. */ - return FALSE; - } - - return TRUE; -} - -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, - NM_SETTING_BLUETOOTH_SETTING_NAME), - factory_class->create_device = create_device; - factory_class->match_connection = match_connection;); |