diff options
author | Antonio Cardace <acardace@redhat.com> | 2020-04-06 09:58:47 +0200 |
---|---|---|
committer | Antonio Cardace <acardace@redhat.com> | 2020-04-06 09:58:47 +0200 |
commit | 1cf366c3189e097bb85f0abdd20de4c4a4ca8947 (patch) | |
tree | 51e70eafdbbfcc2719667b16cef07f78552cf8dd | |
parent | 3670aa9bcd182505be1b88c055661ff06e4338e4 (diff) | |
parent | ad052c3d672f9658c1d4cb47d58ec574a79ac716 (diff) | |
download | NetworkManager-1cf366c3189e097bb85f0abdd20de4c4a4ca8947.tar.gz |
bridge: merge branch 'ac/bridge_options'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/449
-rw-r--r-- | clients/common/nm-meta-setting-desc.c | 27 | ||||
-rw-r--r-- | clients/common/settings-docs.h.in | 6 | ||||
-rw-r--r-- | libnm-core/nm-setting-bridge.c | 390 | ||||
-rw-r--r-- | libnm-core/nm-setting-bridge.h | 64 | ||||
-rw-r--r-- | libnm-core/nm-utils-private.h | 2 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 35 | ||||
-rw-r--r-- | libnm-core/tests/test-setting.c | 149 | ||||
-rw-r--r-- | libnm/libnm.ver | 6 | ||||
-rw-r--r-- | shared/nm-utils/nm-test-utils.h | 4 | ||||
-rw-r--r-- | src/devices/nm-device-bridge.c | 327 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c | 33 | ||||
-rw-r--r-- | src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c | 48 |
12 files changed, 944 insertions, 147 deletions
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 27f1d2882b..03f9b313ce 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -4890,24 +4890,51 @@ static const NMMetaPropertyInfo *const property_infos_BRIDGE[] = { .prompt = N_("MAC address ageing time [300]"), .property_type = &_pt_gobject_int, ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_GROUP_ADDRESS, + .property_type = &_pt_gobject_mac, + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, .is_cli_option = TRUE, .property_alias = "group-forward-mask", .prompt = N_("Group forward mask [0]"), .property_type = &_pt_gobject_int, ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_QUERIER, + .property_type = &_pt_gobject_bool, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, + .property_type = &_pt_gobject_bool, + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_SNOOPING, .is_cli_option = TRUE, .property_alias = "multicast-snooping", .prompt = N_("Enable IGMP snooping [no]"), .property_type = &_pt_gobject_bool, ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_MULTICAST_ROUTER, + .property_type = &_pt_gobject_string, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + .values_static = NM_MAKE_STRV ("auto", + "disabled", + "enabled"), + ), + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLAN_FILTERING, .property_type = &_pt_gobject_bool, ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID, .property_type = &_pt_gobject_int, ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, + .property_type = &_pt_gobject_bool, + ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLAN_PROTOCOL, + .property_type = &_pt_gobject_string, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + .values_static = NM_MAKE_STRV ("802.1Q", + "802.1ad"), + ), + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_BRIDGE_VLANS, .property_type = &_pt_objlist, .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index cc6bcdbbda..5cbef4285f 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -114,15 +114,21 @@ #define DESCRIBE_DOC_NM_SETTING_BOND_OPTIONS N_("Dictionary of key/value pairs of bonding options. Both keys and values must be strings. Option names must contain only alphanumeric characters (ie, [a-zA-Z0-9]).") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_AGEING_TIME N_("The Ethernet MAC address aging time, in seconds.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_FORWARD_DELAY N_("The Spanning Tree Protocol (STP) forwarding delay, in seconds.") +#define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_ADDRESS N_("If specified, The MAC address of the multicast group this bridge uses for STP. The address must be a link-local address in standard Ethernet MAC address format, ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. If not specified the default value is 01:80:C2:00:00:00.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_GROUP_FORWARD_MASK N_("A mask of group addresses to forward. Usually, group addresses in the range from 01:80:C2:00:00:00 to 01:80:C2:00:00:0F are not forwarded according to standards. This property is a mask of 16 bits, each corresponding to a group address in that range that must be forwarded. The mask can't have bits 0, 1 or 2 set because they are used for STP, MAC pause frames and LACP.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_HELLO_TIME N_("The Spanning Tree Protocol (STP) hello time, in seconds.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAC_ADDRESS N_("If specified, the MAC address of bridge. When creating a new bridge, this MAC address will be set. If this field is left unspecified, the \"ethernet.cloned-mac-address\" is referred instead to generate the initial MAC address. Note that setting \"ethernet.cloned-mac-address\" anyway overwrites the MAC address of the bridge later while activating the bridge. Hence, this property is deprecated. Deprecated: 1") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MAX_AGE N_("The Spanning Tree Protocol (STP) maximum message age, in seconds.") +#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERIER N_("Enable or disable sending of multicast queries by the bridge. If not specified the option is disabled.") +#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR N_("If enabled the bridge's own IP address is used as the source address for IGMP queries otherwise the default of 0.0.0.0 is used.") +#define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_ROUTER N_("Sets bridge's multicast router. multicast-snooping must be enabled for this option to work. Supported values are: 'auto', 'disabled', 'enabled'. If not specified the default value is 'auto'.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_MULTICAST_SNOOPING N_("Controls whether IGMP snooping is enabled for this bridge. Note that if snooping was automatically disabled due to hash collisions, the system may refuse to enable the feature until the collisions are resolved.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PRIORITY N_("Sets the Spanning Tree Protocol (STP) priority for this bridge. Lower values are \"better\"; the lowest priority bridge will be elected the root bridge.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_STP N_("Controls whether Spanning Tree Protocol (STP) is enabled for this bridge.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID N_("The default PVID for the ports of the bridge, that is the VLAN id assigned to incoming untagged frames.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_FILTERING N_("Control whether VLAN filtering is enabled on the bridge.") +#define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_PROTOCOL N_("If specified, the protocol used for VLAN filtering. Supported values are: '802.1Q', '802.1ad'. If not specified the default value is '802.1Q'.") +#define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLAN_STATS_ENABLED N_("Controls whether per-VLAN stats accounting is enabled.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_VLANS N_("Array of bridge VLAN objects. In addition to the VLANs specified here, the bridge will also have the default-pvid VLAN configured by the bridge.vlan-default-pvid property. In nmcli the VLAN list can be specified with the following syntax: $vid [pvid] [untagged] [, $vid [pvid] [untagged]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE N_("Enables or disables \"hairpin mode\" for the port, which allows frames to be sent back out through the port the frame was received on.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PORT_PATH_COST N_("The Spanning Tree Protocol (STP) port cost for destinations via this port.") diff --git a/libnm-core/nm-setting-bridge.c b/libnm-core/nm-setting-bridge.c index 9c22ac0f7e..d800022168 100644 --- a/libnm-core/nm-setting-bridge.c +++ b/libnm-core/nm-setting-bridge.c @@ -22,14 +22,17 @@ * necessary for bridging connections. **/ -#define BRIDGE_AGEING_TIME_DEFAULT 300 -#define BRIDGE_FORWARD_DELAY_DEFAULT 15 -#define BRIDGE_HELLO_TIME_DEFAULT 2 -#define BRIDGE_MAX_AGE_DEFAULT 20 -#define BRIDGE_MULTICAST_SNOOPING_DEFAULT TRUE -#define BRIDGE_PRIORITY_DEFAULT 0x8000 -#define BRIDGE_STP_DEFAULT TRUE -#define BRIDGE_VLAN_DEFAULT_PVID_DEFAULT 1 +#define BRIDGE_AGEING_TIME_DEFAULT 300 +#define BRIDGE_FORWARD_DELAY_DEFAULT 15 +#define BRIDGE_HELLO_TIME_DEFAULT 2 +#define BRIDGE_MAX_AGE_DEFAULT 20 +#define BRIDGE_MULTICAST_QUERIER_DEFAULT FALSE +#define BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEFAULT FALSE +#define BRIDGE_MULTICAST_SNOOPING_DEFAULT TRUE +#define BRIDGE_PRIORITY_DEFAULT 0x8000 +#define BRIDGE_STP_DEFAULT TRUE +#define BRIDGE_VLAN_DEFAULT_PVID_DEFAULT 1 +#define BRIDGE_VLAN_STATS_ENABLED_DEFAULT FALSE /*****************************************************************************/ @@ -41,16 +44,25 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMSettingBridge, PROP_HELLO_TIME, PROP_MAX_AGE, PROP_AGEING_TIME, + PROP_GROUP_ADDRESS, PROP_GROUP_FORWARD_MASK, + PROP_MULTICAST_ROUTER, + PROP_MULTICAST_QUERIER, + PROP_MULTICAST_QUERY_USE_IFADDR, PROP_MULTICAST_SNOOPING, PROP_VLAN_FILTERING, PROP_VLAN_DEFAULT_PVID, + PROP_VLAN_PROTOCOL, + PROP_VLAN_STATS_ENABLED, PROP_VLANS, ); typedef struct { GPtrArray *vlans; char * mac_address; + char * multicast_router; + char * group_address; + char * vlan_protocol; guint32 ageing_time; guint16 priority; guint16 forward_delay; @@ -61,11 +73,28 @@ typedef struct { bool multicast_snooping:1; bool vlan_filtering:1; bool stp:1; + bool vlan_stats_enabled:1; + bool multicast_query_use_ifaddr:1; + bool multicast_querier:1; } NMSettingBridgePrivate; +/** + * NMSettingBridge: + * + * Bridging Settings + */ +struct _NMSettingBridge { + NMSetting parent; + NMSettingBridgePrivate _priv; +}; + +struct _NMSettingBridgeClass { + NMSettingClass parent; +}; + G_DEFINE_TYPE (NMSettingBridge, nm_setting_bridge, NM_TYPE_SETTING) -#define NM_SETTING_BRIDGE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BRIDGE, NMSettingBridgePrivate)) +#define NM_SETTING_BRIDGE_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMSettingBridge, NM_IS_SETTING_BRIDGE, NMSetting) /*****************************************************************************/ @@ -885,6 +914,102 @@ nm_setting_bridge_clear_vlans (NMSettingBridge *setting) } } +/** + * nm_setting_bridge_get_group_address: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:group-address property of the setting + * + * Since 1.24 + **/ +const char * +nm_setting_bridge_get_group_address (const NMSettingBridge *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BRIDGE (setting), NULL); + + return NM_SETTING_BRIDGE_GET_PRIVATE (setting)->group_address; +} + +/** + * nm_setting_bridge_get_vlan_protocol: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:vlan-protocol property of the setting + * + * Since 1.24 + **/ +const char * +nm_setting_bridge_get_vlan_protocol (const NMSettingBridge *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BRIDGE (setting), NULL); + + return NM_SETTING_BRIDGE_GET_PRIVATE (setting)->vlan_protocol; +} + +/** + * nm_setting_bridge_get_vlan_stats_enabled: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:vlan-stats-enabled property of the setting + * + * Since 1.24 + **/ +gboolean +nm_setting_bridge_get_vlan_stats_enabled (const NMSettingBridge *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BRIDGE (setting), FALSE); + + return NM_SETTING_BRIDGE_GET_PRIVATE (setting)->vlan_stats_enabled; +} + +/** + * nm_setting_bridge_get_multicast_router: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-router property of the setting + * + * Since 1.24 + **/ +const char * +nm_setting_bridge_get_multicast_router (const NMSettingBridge *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BRIDGE (setting), NULL); + + return NM_SETTING_BRIDGE_GET_PRIVATE (setting)->multicast_router; +} + +/** + * nm_setting_bridge_get_multicast_query_use_ifaddr: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-query-use-ifaddr property of the setting + * + * Since 1.24 + **/ +gboolean +nm_setting_bridge_get_multicast_query_use_ifaddr (const NMSettingBridge *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BRIDGE (setting), FALSE); + + return NM_SETTING_BRIDGE_GET_PRIVATE (setting)->multicast_query_use_ifaddr; +} + +/** + * nm_setting_bridge_get_multicast_querier: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-querier property of the setting + * + * Since 1.24 + **/ +gboolean +nm_setting_bridge_get_multicast_querier (const NMSettingBridge *setting) +{ + g_return_val_if_fail (NM_IS_SETTING_BRIDGE (setting), FALSE); + + return NM_SETTING_BRIDGE_GET_PRIVATE (setting)->multicast_querier; +} + /*****************************************************************************/ static gboolean @@ -975,6 +1100,55 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) NM_SETTING_BRIDGE_VLANS)) return FALSE; + if ( priv->group_address + && !_nm_utils_hwaddr_link_local_valid (priv->group_address)) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("is not a valid link local MAC address")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_GROUP_ADDRESS); + return FALSE; + } + + if ( priv->vlan_protocol + && !NM_IN_STRSET (priv->vlan_protocol, + "802.1Q", + "802.1ad")) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("is not a valid VLAN filtering protocol")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_VLAN_PROTOCOL); + return FALSE; + } + + if (priv->multicast_router) { + if (!NM_IN_STRSET (priv->multicast_router, + "auto", + "enabled", + "disabled")) { + g_set_error_literal (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("is not a valid option")); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_MULTICAST_ROUTER); + return FALSE; + } + + if ( NM_IN_STRSET (priv->multicast_router, + "auto", + "enabled") + && !priv->multicast_snooping) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' option requires '%s' option to be enabled"), + NM_SETTING_BRIDGE_MULTICAST_ROUTER, NM_SETTING_BRIDGE_MULTICAST_SNOOPING); + g_prefix_error (error, "%s.%s: ", NM_SETTING_BRIDGE_SETTING_NAME, NM_SETTING_BRIDGE_MULTICAST_ROUTER); + return FALSE; + } + } + /* Failures from here on are NORMALIZABLE... */ if (!_nm_utils_bridge_vlan_verify_list (priv->vlans, @@ -1055,18 +1229,36 @@ get_property (GObject *object, guint prop_id, case PROP_AGEING_TIME: g_value_set_uint (value, priv->ageing_time); break; + case PROP_GROUP_ADDRESS: + g_value_set_string (value, priv->group_address); + break; case PROP_GROUP_FORWARD_MASK: g_value_set_uint (value, priv->group_forward_mask); break; case PROP_MULTICAST_SNOOPING: g_value_set_boolean (value, priv->multicast_snooping); break; + case PROP_MULTICAST_ROUTER: + g_value_set_string (value, priv->multicast_router); + break; + case PROP_MULTICAST_QUERIER: + g_value_set_boolean (value, priv->multicast_querier); + break; + case PROP_MULTICAST_QUERY_USE_IFADDR: + g_value_set_boolean (value, priv->multicast_query_use_ifaddr); + break; case PROP_VLAN_FILTERING: g_value_set_boolean (value, priv->vlan_filtering); break; case PROP_VLAN_DEFAULT_PVID: g_value_set_uint (value, priv->vlan_default_pvid); break; + case PROP_VLAN_PROTOCOL: + g_value_set_string (value, priv->vlan_protocol); + break; + case PROP_VLAN_STATS_ENABLED: + g_value_set_boolean (value, priv->vlan_stats_enabled); + break; case PROP_VLANS: g_value_take_boxed (value, _nm_utils_copy_array (priv->vlans, (NMUtilsCopyFunc) nm_bridge_vlan_ref, @@ -1108,18 +1300,40 @@ set_property (GObject *object, guint prop_id, case PROP_AGEING_TIME: priv->ageing_time = g_value_get_uint (value); break; + case PROP_GROUP_ADDRESS: + g_free (priv->group_address); + priv->group_address = _nm_utils_hwaddr_canonical_or_invalid (g_value_get_string (value), + ETH_ALEN); + break; case PROP_GROUP_FORWARD_MASK: priv->group_forward_mask = (guint16) g_value_get_uint (value); break; case PROP_MULTICAST_SNOOPING: priv->multicast_snooping = g_value_get_boolean (value); break; + case PROP_MULTICAST_ROUTER: + g_free (priv->multicast_router); + priv->multicast_router = g_value_dup_string (value); + break; + case PROP_MULTICAST_QUERIER: + priv->multicast_querier = g_value_get_boolean (value); + break; + case PROP_MULTICAST_QUERY_USE_IFADDR: + priv->multicast_query_use_ifaddr = g_value_get_boolean (value); + break; case PROP_VLAN_FILTERING: priv->vlan_filtering = g_value_get_boolean (value); break; case PROP_VLAN_DEFAULT_PVID: priv->vlan_default_pvid = g_value_get_uint (value); break; + case PROP_VLAN_PROTOCOL: + g_free (priv->vlan_protocol); + priv->vlan_protocol = g_value_dup_string (value); + break; + case PROP_VLAN_STATS_ENABLED: + priv->vlan_stats_enabled = g_value_get_boolean (value); + break; case PROP_VLANS: g_ptr_array_unref (priv->vlans); priv->vlans = _nm_utils_copy_array (g_value_get_boxed (value), @@ -1141,14 +1355,17 @@ nm_setting_bridge_init (NMSettingBridge *setting) priv->vlans = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref); - priv->ageing_time = BRIDGE_AGEING_TIME_DEFAULT; - priv->forward_delay = BRIDGE_FORWARD_DELAY_DEFAULT; - priv->hello_time = BRIDGE_HELLO_TIME_DEFAULT; - priv->max_age = BRIDGE_MAX_AGE_DEFAULT; - priv->multicast_snooping = BRIDGE_MULTICAST_SNOOPING_DEFAULT; - priv->priority = BRIDGE_PRIORITY_DEFAULT; - priv->stp = BRIDGE_STP_DEFAULT; - priv->vlan_default_pvid = BRIDGE_VLAN_DEFAULT_PVID_DEFAULT; + priv->ageing_time = BRIDGE_AGEING_TIME_DEFAULT; + priv->forward_delay = BRIDGE_FORWARD_DELAY_DEFAULT; + priv->hello_time = BRIDGE_HELLO_TIME_DEFAULT; + priv->max_age = BRIDGE_MAX_AGE_DEFAULT; + priv->multicast_snooping = BRIDGE_MULTICAST_SNOOPING_DEFAULT; + priv->priority = BRIDGE_PRIORITY_DEFAULT; + priv->stp = BRIDGE_STP_DEFAULT; + priv->vlan_default_pvid = BRIDGE_VLAN_DEFAULT_PVID_DEFAULT; + priv->vlan_stats_enabled = BRIDGE_VLAN_STATS_ENABLED_DEFAULT; + priv->multicast_query_use_ifaddr = BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEFAULT; + priv->multicast_querier = BRIDGE_MULTICAST_QUERIER_DEFAULT; } /** @@ -1170,6 +1387,9 @@ finalize (GObject *object) NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE (object); g_free (priv->mac_address); + g_free (priv->multicast_router); + g_free (priv->group_address); + g_free (priv->vlan_protocol); g_ptr_array_unref (priv->vlans); G_OBJECT_CLASS (nm_setting_bridge_parent_class)->finalize (object); @@ -1182,8 +1402,6 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass) NMSettingClass *setting_class = NM_SETTING_CLASS (klass); GArray *properties_override = _nm_sett_info_property_override_create_array (); - g_type_class_add_private (klass, sizeof (NMSettingBridgePrivate)); - object_class->get_property = get_property; object_class->set_property = set_property; object_class->finalize = finalize; @@ -1481,6 +1699,140 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass) */ _nm_properties_override_dbus (properties_override, "interface-name", &nm_sett_info_propert_type_deprecated_interface_name); + /** + * NMSettingBridge:group-address: + * + * If specified, The MAC address of the multicast group this bridge uses for STP. + * + * The address must be a link-local address in standard Ethernet MAC address format, + * ie an address of the form 01:80:C2:00:00:0X, with X in [0, 4..F]. + * If not specified the default value is 01:80:C2:00:00:00. + * + * Since: 1.24 + **/ + /* ---ifcfg-rh--- + * property: group-address + * variable: BRIDGING_OPTS: group_address= + * description: STP group address. + * example: BRIDGING_OPTS="group_address=01:80:C2:00:00:0A" + * ---end--- + */ + obj_properties[PROP_GROUP_ADDRESS] = + g_param_spec_string (NM_SETTING_BRIDGE_GROUP_ADDRESS, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS); + _nm_properties_override_gobj (properties_override, obj_properties[PROP_GROUP_ADDRESS], &nm_sett_info_propert_type_mac_address); + + /** + * NMSettingBridge:vlan-protocol: + * + * If specified, the protocol used for VLAN filtering. + * + * Supported values are: '802.1Q', '802.1ad'. + * If not specified the default value is '802.1Q'. + * + * Since: 1.24 + **/ + /* ---ifcfg-rh--- + * property: vlan-protocol + * variable: BRIDGING_OPTS: vlan_protocol= + * description: VLAN filtering protocol. + * example: BRIDGING_OPTS="vlan_protocol=802.1Q" + * ---end--- + */ + obj_properties[PROP_VLAN_PROTOCOL] = + g_param_spec_string (NM_SETTING_BRIDGE_VLAN_PROTOCOL, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:vlan-stats-enabled: + * + * Controls whether per-VLAN stats accounting is enabled. + **/ + /* ---ifcfg-rh--- + * property: vlan-stats-enabled + * variable: BRIDGING_OPTS: vlan_stats_enabled= + * default: 0 + * example: BRIDGING_OPTS="vlan_stats_enabled=1" + * ---end--- + */ + obj_properties[PROP_VLAN_STATS_ENABLED] = + g_param_spec_boolean (NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, "", "", + BRIDGE_VLAN_STATS_ENABLED_DEFAULT, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-router: + * + * Sets bridge's multicast router. + * multicast-snooping must be enabled for this option to work. + * + * Supported values are: 'auto', 'disabled', 'enabled'. + * If not specified the default value is 'auto'. + **/ + /* ---ifcfg-rh--- + * property: multicast-router + * variable: BRIDGING_OPTS: multicast_router= + * values: auto, enabled, disabled + * default: auto + * example: BRIDGING_OPTS="multicast_router=enabled" + * ---end--- + */ + obj_properties[PROP_MULTICAST_ROUTER] = + g_param_spec_string (NM_SETTING_BRIDGE_MULTICAST_ROUTER, "", "", + NULL, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-query-use-ifaddr: + * + * If enabled the bridge's own IP address is used as + * the source address for IGMP queries otherwise + * the default of 0.0.0.0 is used. + **/ + /* ---ifcfg-rh--- + * property: multicast-query-use-ifaddr + * variable: BRIDGING_OPTS: multicast_query_use_ifaddr= + * default: 0 + * example: BRIDGING_OPTS="multicast_query-use_ifaddr=1" + * ---end--- + */ + obj_properties[PROP_MULTICAST_QUERY_USE_IFADDR] = + g_param_spec_boolean (NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, "", "", + BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEFAULT, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-querier: + * + * Enable or disable sending of multicast queries by the bridge. + * If not specified the option is disabled. + **/ + /* ---ifcfg-rh--- + * property: multicast-querier + * variable: BRIDGING_OPTS: multicast_querier= + * default: 0 + * example: BRIDGING_OPTS="multicast_querier=1" + * ---end--- + */ + obj_properties[PROP_MULTICAST_QUERIER] = + g_param_spec_boolean (NM_SETTING_BRIDGE_MULTICAST_QUERIER, "", "", + BRIDGE_MULTICAST_QUERIER_DEFAULT, + G_PARAM_READWRITE | + NM_SETTING_PARAM_INFERRABLE | + G_PARAM_STATIC_STRINGS); + g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); _nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_BRIDGE, diff --git a/libnm-core/nm-setting-bridge.h b/libnm-core/nm-setting-bridge.h index ee8b45f617..6bd5100f26 100644 --- a/libnm-core/nm-setting-bridge.h +++ b/libnm-core/nm-setting-bridge.h @@ -23,37 +23,29 @@ G_BEGIN_DECLS #define NM_SETTING_BRIDGE_SETTING_NAME "bridge" -#define NM_SETTING_BRIDGE_MAC_ADDRESS "mac-address" -#define NM_SETTING_BRIDGE_STP "stp" -#define NM_SETTING_BRIDGE_PRIORITY "priority" -#define NM_SETTING_BRIDGE_FORWARD_DELAY "forward-delay" -#define NM_SETTING_BRIDGE_HELLO_TIME "hello-time" -#define NM_SETTING_BRIDGE_MAX_AGE "max-age" -#define NM_SETTING_BRIDGE_AGEING_TIME "ageing-time" -#define NM_SETTING_BRIDGE_GROUP_FORWARD_MASK "group-forward-mask" -#define NM_SETTING_BRIDGE_MULTICAST_SNOOPING "multicast-snooping" -#define NM_SETTING_BRIDGE_VLAN_FILTERING "vlan-filtering" -#define NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID "vlan-default-pvid" -#define NM_SETTING_BRIDGE_VLANS "vlans" +#define NM_SETTING_BRIDGE_MAC_ADDRESS "mac-address" +#define NM_SETTING_BRIDGE_STP "stp" +#define NM_SETTING_BRIDGE_PRIORITY "priority" +#define NM_SETTING_BRIDGE_FORWARD_DELAY "forward-delay" +#define NM_SETTING_BRIDGE_HELLO_TIME "hello-time" +#define NM_SETTING_BRIDGE_MAX_AGE "max-age" +#define NM_SETTING_BRIDGE_AGEING_TIME "ageing-time" +#define NM_SETTING_BRIDGE_GROUP_FORWARD_MASK "group-forward-mask" +#define NM_SETTING_BRIDGE_MULTICAST_SNOOPING "multicast-snooping" +#define NM_SETTING_BRIDGE_MULTICAST_ROUTER "multicast-router" +#define NM_SETTING_BRIDGE_MULTICAST_QUERIER "multicast-querier" +#define NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR "multicast-query-use-ifaddr" +#define NM_SETTING_BRIDGE_VLAN_FILTERING "vlan-filtering" +#define NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID "vlan-default-pvid" +#define NM_SETTING_BRIDGE_VLANS "vlans" +#define NM_SETTING_BRIDGE_GROUP_ADDRESS "group-address" +#define NM_SETTING_BRIDGE_VLAN_PROTOCOL "vlan-protocol" +#define NM_SETTING_BRIDGE_VLAN_STATS_ENABLED "vlan-stats-enabled" #define NM_BRIDGE_VLAN_VID_MIN 1 #define NM_BRIDGE_VLAN_VID_MAX 4094 -/** - * NMSettingBridge: - * - * Bridging Settings - */ -struct _NMSettingBridge { - NMSetting parent; -}; - -typedef struct { - NMSettingClass parent; - - /*< private >*/ - gpointer padding[4]; -} NMSettingBridgeClass; +typedef struct _NMSettingBridgeClass NMSettingBridgeClass; typedef struct _NMBridgeVlan NMBridgeVlan; @@ -130,6 +122,24 @@ char * nm_bridge_vlan_to_str (const NMBridgeVlan *vlan, GError **error); NM_AVAILABLE_IN_1_18 NMBridgeVlan * nm_bridge_vlan_from_str (const char *str, GError **error); +NM_AVAILABLE_IN_1_24 +const char * nm_setting_bridge_get_group_address (const NMSettingBridge *setting); + +NM_AVAILABLE_IN_1_24 +const char * nm_setting_bridge_get_vlan_protocol (const NMSettingBridge *setting); + +NM_AVAILABLE_IN_1_24 +gboolean nm_setting_bridge_get_vlan_stats_enabled (const NMSettingBridge *setting); + +NM_AVAILABLE_IN_1_24 +const char * nm_setting_bridge_get_multicast_router (const NMSettingBridge *setting); + +NM_AVAILABLE_IN_1_24 +gboolean nm_setting_bridge_get_multicast_query_use_ifaddr (const NMSettingBridge *setting); + +NM_AVAILABLE_IN_1_24 +gboolean nm_setting_bridge_get_multicast_querier (const NMSettingBridge *setting); + G_END_DECLS #endif /* __NM_SETTING_BRIDGE_H__ */ diff --git a/libnm-core/nm-utils-private.h b/libnm-core/nm-utils-private.h index 67074840ff..f3e9d3f1cb 100644 --- a/libnm-core/nm-utils-private.h +++ b/libnm-core/nm-utils-private.h @@ -65,6 +65,8 @@ void _nm_utils_bytes_from_dbus (GVariant *dbus_value, char * _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize length); +gboolean _nm_utils_hwaddr_link_local_valid (const char *mac); + void _nm_utils_format_variant_attributes_full (GString *str, const NMUtilsNamedValue *values, guint num_values, diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 2cfaea6dd4..062ff39337 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4186,6 +4186,41 @@ _nm_utils_hwaddr_canonical_or_invalid (const char *mac, gssize length) return g_strdup (mac); } +/* + * Determine if given Ethernet address is link-local + * + * Return value: %TRUE if @mac is link local + * reserved addr (01:80:c2:00:00:0X) per IEEE 802.1Q 8.6.3 Frame filtering, %FALSE if not. + */ +gboolean +_nm_utils_hwaddr_link_local_valid (const char *mac) +{ + guint8 mac_net[ETH_ALEN]; + static const guint8 eth_reserved_addr_base[] = { + 0x01, 0x80, + 0xc2, 0x00, + 0x00 + }; + + if (!mac) + return FALSE; + + if (!nm_utils_hwaddr_aton (mac, mac_net, ETH_ALEN)) + return FALSE; + + if ( memcmp (mac_net, + eth_reserved_addr_base, ETH_ALEN - 1) + || (mac_net[5] & 0xF0)) + return FALSE; + + if ( mac_net[5] == 1 /* 802.3x Pause address */ + || mac_net[5] == 2 /* 802.3ad Slow protocols */ + || mac_net[5] == 3) /* 802.1X PAE address */ + return FALSE; + + return TRUE; +} + /** * nm_utils_hwaddr_matches: * @hwaddr1: (nullable): pointer to a binary or ASCII hardware address, or %NULL diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c index 382c52a944..cb8f41fb03 100644 --- a/libnm-core/tests/test-setting.c +++ b/libnm-core/tests/test-setting.c @@ -500,8 +500,6 @@ create_bond_connection (NMConnection **con, NMSettingBond **s_bond) NULL, NM_SETTING_BOND_SETTING_NAME, &s_con); - g_assert (*con); - g_assert (s_con); g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "bond0", NULL); @@ -512,28 +510,25 @@ create_bond_connection (NMConnection **con, NMSettingBond **s_bond) } #define test_verify_options(exp, ...) \ - _test_verify_options (NM_MAKE_STRV (__VA_ARGS__), exp) + _test_verify_options (exp, NM_MAKE_STRV (__VA_ARGS__)) static void -_test_verify_options (const char *const *options, - gboolean expected_result) +_test_verify_options (gboolean expected_result, + const char *const *options) { gs_unref_object NMConnection *con = NULL; NMSettingBond *s_bond; - GError *error = NULL; - gboolean success; const char *const *option; + g_assert (NM_PTRARRAY_LEN (options) % 2 == 0); + create_bond_connection (&con, &s_bond); - for (option = options; option[0] && option[1]; option += 2) + for (option = options; option[0]; option += 2) g_assert (nm_setting_bond_add_option (s_bond, option[0], option[1])); if (expected_result) { nmtst_assert_connection_verifies_and_normalizable (con); - nmtst_connection_normalize (con); - success = nm_setting_verify ((NMSetting *) s_bond, con, &error); - nmtst_assert_success (success, error); } else { nmtst_assert_connection_unnormalizable (con, NM_CONNECTION_ERROR, @@ -1874,6 +1869,137 @@ test_bridge_vlans (void) nm_bridge_vlan_unref (v2); } +static void +create_bridge_connection (NMConnection **con, NMSettingBridge **s_bridge) +{ + NMSettingConnection *s_con; + + g_assert (con); + g_assert (s_bridge); + + *con = nmtst_create_minimal_connection ("bridge", + NULL, + NM_SETTING_BOND_SETTING_NAME, + &s_con); + + g_object_set (s_con, NM_SETTING_CONNECTION_INTERFACE_NAME, "bridge0", NULL); + + *s_bridge = (NMSettingBridge *) nm_setting_bridge_new (); + g_assert (*s_bridge); + + nm_connection_add_setting (*con, NM_SETTING (*s_bridge)); +} + +#define test_verify_options_bridge(exp, ...) \ + _test_verify_options_bridge (exp, NM_MAKE_STRV (__VA_ARGS__)) + +static void +_test_verify_options_bridge (gboolean expected_result, + const char *const *options) +{ + gs_unref_object NMConnection *con = NULL; + NMSettingBridge *s_bridge; + const char *const *option; + + g_assert (NM_PTRARRAY_LEN (options) % 2 == 0); + + create_bridge_connection (&con, &s_bridge); + + for (option = options; option[0]; option += 2) { + const char *option_key = option[0]; + const char *option_val = option[1]; + GParamSpec *pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (s_bridge), option_key); + + g_assert (pspec); + g_assert (option_val); + + switch (G_PARAM_SPEC_VALUE_TYPE (pspec)) { + case G_TYPE_UINT: { + guint uvalue; + + uvalue = _nm_utils_ascii_str_to_uint64 (option_val, 10, 0, G_MAXUINT, 0); + g_object_set (s_bridge, option_key, uvalue, NULL); + } + break; + case G_TYPE_BOOLEAN: { + gboolean bvalue; + + bvalue = _nm_utils_ascii_str_to_bool (option_val, FALSE); + g_object_set (s_bridge, option_key, bvalue, NULL); + } + break; + case G_TYPE_STRING: + g_object_set (s_bridge, option_key, option_val, NULL); + break; + default: + g_assert_not_reached(); + break; + } + } + + if (expected_result) + nmtst_assert_connection_verifies_and_normalizable (con); + else { + nmtst_assert_connection_unnormalizable (con, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY); + } +} + +static void +test_bridge_verify (void) +{ + /* group-address */ + test_verify_options_bridge (FALSE, + "group-address", "nonsense"); + test_verify_options_bridge (FALSE, + "group-address", "FF:FF:FF:FF:FF:FF"); + test_verify_options_bridge (FALSE, + "group-address", "01:02:03:04:05:06"); + test_verify_options_bridge (TRUE, + "group-address", "01:80:C2:00:00:00"); + test_verify_options_bridge (FALSE, + "group-address", "01:80:C2:00:00:02"); + test_verify_options_bridge (FALSE, + "group-address", "01:80:C2:00:00:03"); + test_verify_options_bridge (TRUE, + "group-address", "01:80:C2:00:00:00"); + test_verify_options_bridge (TRUE, + "group-address", "01:80:C2:00:00:0A"); + /* vlan-protocol */ + test_verify_options_bridge (FALSE, + "vlan-protocol", "nonsense124"); + test_verify_options_bridge (FALSE, + "vlan-protocol", "802.11"); + test_verify_options_bridge (FALSE, + "vlan-protocol", "802.1Q1"); + test_verify_options_bridge (TRUE, + "vlan-protocol", "802.1Q"); + test_verify_options_bridge (TRUE, + "vlan-protocol", "802.1ad"); + /* multicast-router */ + test_verify_options_bridge (FALSE, + "multicast-router", "nonsense"); + test_verify_options_bridge (FALSE, + "multicast-snooping", "no", + "multicast-router", "auto"); + test_verify_options_bridge (FALSE, + "multicast-snooping", "no", + "multicast-router", "enabled"); + test_verify_options_bridge (TRUE, + "multicast-snooping", "no", + "multicast-router", "disabled"); + test_verify_options_bridge (TRUE, + "multicast-snooping", "yes", + "multicast-router", "enabled"); + test_verify_options_bridge (TRUE, + "multicast-snooping", "yes", + "multicast-router", "auto"); + test_verify_options_bridge (TRUE, + "multicast-snooping", "yes", + "multicast-router", "disabled"); +} + /*****************************************************************************/ static void @@ -3653,6 +3779,7 @@ main (int argc, char **argv) g_test_add_func ("/libnm/settings/tc_config/dbus", test_tc_config_dbus); g_test_add_func ("/libnm/settings/bridge/vlans", test_bridge_vlans); + g_test_add_func ("/libnm/settings/bridge/verify", test_bridge_verify); g_test_add_func ("/libnm/settings/team/sync_runner_from_config_roundrobin", test_runner_roundrobin_sync_from_config); diff --git a/libnm/libnm.ver b/libnm/libnm.ver index b83aa33821..b5ce8c34a3 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1685,6 +1685,12 @@ global: nm_setting_802_1x_get_domain_match; nm_setting_802_1x_get_phase2_domain_match; nm_setting_bond_get_option_normalized; + nm_setting_bridge_get_group_address; + nm_setting_bridge_get_multicast_querier; + nm_setting_bridge_get_multicast_query_use_ifaddr; + nm_setting_bridge_get_multicast_router; + nm_setting_bridge_get_vlan_protocol; + nm_setting_bridge_get_vlan_stats_enabled; nm_setting_vrf_get_table; nm_setting_vrf_get_type; nm_setting_vrf_new; diff --git a/shared/nm-utils/nm-test-utils.h b/shared/nm-utils/nm-test-utils.h index 0d03456319..96e361358f 100644 --- a/shared/nm-utils/nm-test-utils.h +++ b/shared/nm-utils/nm-test-utils.h @@ -1803,8 +1803,12 @@ nmtst_create_minimal_connection (const char *id, const char *uuid, const char *t con = nm_connection_new (); #endif + g_assert (con); + s_con = NM_SETTING_CONNECTION (nm_setting_connection_new ()); + g_assert (s_con); + g_object_set (s_con, NM_SETTING_CONNECTION_ID, id, NM_SETTING_CONNECTION_UUID, uuid, diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c index 874d4966e3..6eb9850e45 100644 --- a/src/devices/nm-device-bridge.c +++ b/src/devices/nm-device-bridge.c @@ -158,11 +158,85 @@ complete_connection (NMDevice *device, return TRUE; } +static void +from_sysfs_group_address (const char *value, GValue *out) +{ + if (!nm_utils_hwaddr_matches (value, -1, "01:80:C2:00:00:00", -1)) + g_value_set_string (out, value); +} + +static const char * +to_sysfs_group_address (GValue *value) +{ + return g_value_get_string (value) ?: "01:80:C2:00:00:00"; +} + +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 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; + } +} + /*****************************************************************************/ typedef struct { const char *name; const char *sysname; + const char *(*to_sysfs) (GValue *value); + void (*from_sysfs) (const char *value, GValue *out); uint nm_min; uint nm_max; uint nm_default; @@ -172,41 +246,76 @@ typedef struct { } Option; static const Option master_options[] = { - { NM_SETTING_BRIDGE_STP, "stp_state", /* this must stay as the first item */ - 0, 1, 1, - FALSE, FALSE, FALSE }, - { NM_SETTING_BRIDGE_PRIORITY, "priority", - 0, G_MAXUINT16, 0x8000, - TRUE, FALSE, TRUE }, - { NM_SETTING_BRIDGE_FORWARD_DELAY, "forward_delay", - 0, NM_BR_MAX_FORWARD_DELAY, 15, - TRUE, TRUE, TRUE}, - { NM_SETTING_BRIDGE_HELLO_TIME, "hello_time", - 0, NM_BR_MAX_HELLO_TIME, 2, - TRUE, TRUE, TRUE }, - { NM_SETTING_BRIDGE_MAX_AGE, "max_age", - 0, NM_BR_MAX_MAX_AGE, 20, - TRUE, TRUE, TRUE }, - { NM_SETTING_BRIDGE_AGEING_TIME, "ageing_time", - NM_BR_MIN_AGEING_TIME, NM_BR_MAX_AGEING_TIME, 300, - TRUE, TRUE, FALSE }, - { NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, "group_fwd_mask", - 0, 0xFFFF, 0, - TRUE, FALSE, FALSE }, - { NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "multicast_snooping", - 0, 1, 1, - FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_STP, "stp_state", /* this must stay as the first item */ + NULL, NULL, + 0, 1, 1, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_PRIORITY, "priority", + NULL, NULL, + 0, G_MAXUINT16, 0x8000, + TRUE, FALSE, TRUE }, + { NM_SETTING_BRIDGE_FORWARD_DELAY, "forward_delay", + NULL, NULL, + 0, NM_BR_MAX_FORWARD_DELAY, 15, + TRUE, TRUE, TRUE}, + { NM_SETTING_BRIDGE_HELLO_TIME, "hello_time", + NULL, NULL, + 0, NM_BR_MAX_HELLO_TIME, 2, + TRUE, TRUE, TRUE }, + { NM_SETTING_BRIDGE_MAX_AGE, "max_age", + NULL, NULL, + 0, NM_BR_MAX_MAX_AGE, 20, + TRUE, TRUE, TRUE }, + { NM_SETTING_BRIDGE_AGEING_TIME, "ageing_time", + NULL, NULL, + NM_BR_MIN_AGEING_TIME, NM_BR_MAX_AGEING_TIME, 300, + TRUE, TRUE, FALSE }, + { NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, "group_fwd_mask", + NULL, NULL, + 0, 0xFFFF, 0, + TRUE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_MULTICAST_QUERIER, "multicast_querier", + NULL, NULL, + 0, 1, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, "multicast_query_use_ifaddr", + NULL, NULL, + 0, 1, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_MULTICAST_SNOOPING, "multicast_snooping", + NULL, NULL, + 0, 1, 1, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_MULTICAST_ROUTER, "multicast_router", + to_sysfs_multicast_router, from_sysfs_multicast_router, + 0, 0, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_GROUP_ADDRESS, "group_addr", + to_sysfs_group_address, from_sysfs_group_address, + 0, 0, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_VLAN_PROTOCOL, "vlan_protocol", + to_sysfs_vlan_protocol, from_sysfs_vlan_protocol, + 0, 0, 0, + FALSE, FALSE, FALSE }, + { NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, "vlan_stats_enabled", + NULL, NULL, + 0, 1, 0, + FALSE, FALSE, FALSE }, { NULL, NULL } }; static const Option slave_options[] = { { NM_SETTING_BRIDGE_PORT_PRIORITY, "priority", + NULL, NULL, 0, NM_BR_PORT_MAX_PRIORITY, NM_BR_PORT_DEF_PRIORITY, TRUE, FALSE }, { NM_SETTING_BRIDGE_PORT_PATH_COST, "path_cost", + NULL, NULL, 0, NM_BR_PORT_MAX_PATH_COST, 100, TRUE, FALSE }, { NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", + NULL, NULL, 0, 1, 0, FALSE, FALSE }, { NULL, NULL } @@ -216,10 +325,9 @@ 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; - GValue val = G_VALUE_INIT; - guint32 uval = 0; - char value[100]; + const char *value; g_assert (setting); @@ -229,37 +337,67 @@ commit_option (NMDevice *device, NMSetting *setting, const Option *option, gbool /* Get the property's value */ g_value_init (&val, G_PARAM_SPEC_VALUE_TYPE (pspec)); g_object_get_property ((GObject *) setting, option->name, &val); - 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. - */ - if (option->default_if_zero && uval == 0) { - 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); - } - /* 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 - nm_assert_not_reached (); - g_value_unset (&val); - - nm_sprintf_buf (value, "%u", uval); - 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); + 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_UINT: { + char value_buf[100]; + guint uval; + + 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. + */ + if (option->default_if_zero && uval == 0) { + 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); + } + + /* 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; + + nm_sprintf_buf (value_buf, "%u", uval); + value = value_buf; + } + break; + case G_TYPE_STRING: + value = g_value_get_string (&val); + break; + default: + nm_assert_not_reached (); + 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 ** @@ -335,29 +473,68 @@ update_connection (NMDevice *device, NMConnection *connection) option++; for (; option->name; option++) { - gs_free char *str = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, option->sysname); - uint value; + 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) { - /* 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_bridge, option->name, value, NULL); - } else + 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_UINT: { + guint 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_int64 (str, 10, + option->nm_min, + option->nm_max, + option->nm_default); + } + g_value_set_uint (&value, 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); } } diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c index 60bc504717..8e15341238 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-reader.c @@ -5152,18 +5152,24 @@ handle_bridge_option (NMSetting *setting, gboolean only_with_stp; gboolean extended_bool; } m/*etadata*/[] = { - { "DELAY", NM_SETTING_BRIDGE_FORWARD_DELAY, BRIDGE_OPT_TYPE_MAIN, .only_with_stp = TRUE }, - { "priority", NM_SETTING_BRIDGE_PRIORITY, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, - { "hello_time", NM_SETTING_BRIDGE_HELLO_TIME, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, - { "max_age", NM_SETTING_BRIDGE_MAX_AGE, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, - { "ageing_time", NM_SETTING_BRIDGE_AGEING_TIME, BRIDGE_OPT_TYPE_OPTION }, - { "multicast_snooping", NM_SETTING_BRIDGE_MULTICAST_SNOOPING, BRIDGE_OPT_TYPE_OPTION }, - { "vlan_filtering", NM_SETTING_BRIDGE_VLAN_FILTERING, BRIDGE_OPT_TYPE_OPTION }, - { "default_pvid", NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID, BRIDGE_OPT_TYPE_OPTION }, - { "group_fwd_mask", NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, BRIDGE_OPT_TYPE_OPTION }, - { "priority", NM_SETTING_BRIDGE_PORT_PRIORITY, BRIDGE_OPT_TYPE_PORT_OPTION }, - { "path_cost", NM_SETTING_BRIDGE_PORT_PATH_COST, BRIDGE_OPT_TYPE_PORT_OPTION }, - { "hairpin_mode", NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, BRIDGE_OPT_TYPE_PORT_OPTION, .extended_bool = TRUE, }, + { "DELAY", NM_SETTING_BRIDGE_FORWARD_DELAY, BRIDGE_OPT_TYPE_MAIN, .only_with_stp = TRUE }, + { "priority", NM_SETTING_BRIDGE_PRIORITY, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "hello_time", NM_SETTING_BRIDGE_HELLO_TIME, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "max_age", NM_SETTING_BRIDGE_MAX_AGE, BRIDGE_OPT_TYPE_OPTION, .only_with_stp = TRUE }, + { "ageing_time", NM_SETTING_BRIDGE_AGEING_TIME, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_querier", NM_SETTING_BRIDGE_MULTICAST_QUERIER, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_query_use_ifaddr", NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_snooping", NM_SETTING_BRIDGE_MULTICAST_SNOOPING, BRIDGE_OPT_TYPE_OPTION }, + { "multicast_router", NM_SETTING_BRIDGE_MULTICAST_ROUTER, BRIDGE_OPT_TYPE_OPTION }, + { "vlan_filtering", NM_SETTING_BRIDGE_VLAN_FILTERING, BRIDGE_OPT_TYPE_OPTION }, + { "default_pvid", NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID, BRIDGE_OPT_TYPE_OPTION }, + { "group_address", NM_SETTING_BRIDGE_GROUP_ADDRESS, BRIDGE_OPT_TYPE_OPTION }, + { "group_fwd_mask", NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, BRIDGE_OPT_TYPE_OPTION }, + { "vlan_protocol", NM_SETTING_BRIDGE_VLAN_PROTOCOL, BRIDGE_OPT_TYPE_OPTION }, + { "vlan_stats_enabled", NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, BRIDGE_OPT_TYPE_OPTION }, + { "priority", NM_SETTING_BRIDGE_PORT_PRIORITY, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "path_cost", NM_SETTING_BRIDGE_PORT_PATH_COST, BRIDGE_OPT_TYPE_PORT_OPTION }, + { "hairpin_mode", NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, BRIDGE_OPT_TYPE_PORT_OPTION, .extended_bool = TRUE, }, }; const char *error_message = NULL; int i; @@ -5216,6 +5222,9 @@ handle_bridge_option (NMSetting *setting, goto warn; } return; + case G_TYPE_STRING: + nm_g_object_set_property_string (G_OBJECT (setting), m[i].property_name, value, NULL); + return; default: nm_assert_not_reached (); continue; diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c index 1876aa31ed..a0797fdc79 100644 --- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c +++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c @@ -1438,8 +1438,8 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire NMSettingBridge *s_bridge; guint32 i; gboolean b; + const char *s; GString *opts; - const char *mac; s_bridge = nm_connection_get_setting_bridge (connection); if (!s_bridge) { @@ -1450,8 +1450,8 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire svSetValueBoolean (ifcfg, "STP", FALSE); - mac = nm_setting_bridge_get_mac_address (s_bridge); - svSetValueStr (ifcfg, "BRIDGE_MACADDR", mac); + s = nm_setting_bridge_get_mac_address (s_bridge); + svSetValueStr (ifcfg, "BRIDGE_MACADDR", s); /* Bridge options */ opts = g_string_sized_new (32); @@ -1487,6 +1487,13 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire g_string_append_printf (opts, "ageing_time=%u", i); } + s = nm_setting_bridge_get_group_address (s_bridge); + if (s) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "group_address=%s", s); + } + i = nm_setting_bridge_get_group_forward_mask (s_bridge); if (i != get_setting_default_uint (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_GROUP_FORWARD_MASK)) { if (opts->len) @@ -1494,6 +1501,20 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire g_string_append_printf (opts, "group_fwd_mask=%u", i); } + b = nm_setting_bridge_get_multicast_querier (s_bridge); + if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MULTICAST_QUERIER)) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "multicast_querier=%u", (guint) b); + } + + b = nm_setting_bridge_get_multicast_query_use_ifaddr (s_bridge); + if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR)) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "multicast_query_use_ifaddr=%u", (guint) b); + } + b = nm_setting_bridge_get_multicast_snooping (s_bridge); if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_MULTICAST_SNOOPING)) { if (opts->len) @@ -1501,6 +1522,13 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire g_string_append_printf (opts, "multicast_snooping=%u", (guint32) b); } + s = nm_setting_bridge_get_multicast_router (s_bridge); + if (s) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "multicast_router=%s", s); + } + b = nm_setting_bridge_get_vlan_filtering (s_bridge); if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_VLAN_FILTERING)) { if (opts->len) @@ -1515,6 +1543,20 @@ write_bridge_setting (NMConnection *connection, shvarFile *ifcfg, gboolean *wire g_string_append_printf (opts, "default_pvid=%u", i); } + s = nm_setting_bridge_get_vlan_protocol (s_bridge); + if (s) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "vlan_protocol=%s", s); + } + + b = nm_setting_bridge_get_vlan_stats_enabled (s_bridge); + if (b != get_setting_default_boolean (NM_SETTING (s_bridge), NM_SETTING_BRIDGE_VLAN_STATS_ENABLED)) { + if (opts->len) + g_string_append_c (opts, ' '); + g_string_append_printf (opts, "vlan_stats_enabled=%u", (guint) b); + } + if (opts->len) svSetValueStr (ifcfg, "BRIDGING_OPTS", opts->str); g_string_free (opts, TRUE); |