diff options
Diffstat (limited to 'src/libnm-core-impl/nm-setting-bridge.c')
| -rw-r--r-- | src/libnm-core-impl/nm-setting-bridge.c | 2308 |
1 files changed, 2308 insertions, 0 deletions
diff --git a/src/libnm-core-impl/nm-setting-bridge.c b/src/libnm-core-impl/nm-setting-bridge.c new file mode 100644 index 00000000..e987310f --- /dev/null +++ b/src/libnm-core-impl/nm-setting-bridge.c @@ -0,0 +1,2308 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ +/* + * Copyright (C) 2011 - 2017 Red Hat, Inc. + */ + +#include "libnm-core-impl/nm-default-libnm-core.h" + +#include "nm-setting-bridge.h" + +#include <ctype.h> +#include <stdlib.h> +#include <linux/if_ether.h> + +#include "libnm-glib-aux/nm-str-buf.h" +#include "nm-connection-private.h" +#include "nm-utils.h" +#include "nm-utils-private.h" + +/** + * SECTION:nm-setting-bridge + * @short_description: Describes connection properties for bridges + * + * The #NMSettingBridge object is a #NMSetting subclass that describes properties + * necessary for bridging connections. + **/ + +/*****************************************************************************/ + +NM_GOBJECT_PROPERTIES_DEFINE(NMSettingBridge, + PROP_MAC_ADDRESS, + PROP_STP, + PROP_PRIORITY, + PROP_FORWARD_DELAY, + PROP_HELLO_TIME, + PROP_MAX_AGE, + PROP_AGEING_TIME, + PROP_GROUP_ADDRESS, + PROP_GROUP_FORWARD_MASK, + PROP_MULTICAST_HASH_MAX, + PROP_MULTICAST_LAST_MEMBER_COUNT, + PROP_MULTICAST_LAST_MEMBER_INTERVAL, + PROP_MULTICAST_MEMBERSHIP_INTERVAL, + PROP_MULTICAST_ROUTER, + PROP_MULTICAST_QUERIER, + PROP_MULTICAST_QUERIER_INTERVAL, + PROP_MULTICAST_QUERY_INTERVAL, + PROP_MULTICAST_QUERY_RESPONSE_INTERVAL, + PROP_MULTICAST_QUERY_USE_IFADDR, + PROP_MULTICAST_SNOOPING, + PROP_MULTICAST_STARTUP_QUERY_COUNT, + PROP_MULTICAST_STARTUP_QUERY_INTERVAL, + 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; + guint64 multicast_last_member_interval; + guint64 multicast_membership_interval; + guint64 multicast_querier_interval; + guint64 multicast_query_interval; + guint64 multicast_query_response_interval; + guint64 multicast_startup_query_interval; + guint32 ageing_time; + guint32 multicast_hash_max; + guint32 multicast_last_member_count; + guint32 multicast_startup_query_count; + guint16 priority; + guint16 forward_delay; + guint16 hello_time; + guint16 max_age; + guint16 vlan_default_pvid; + guint16 group_forward_mask; + 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(self) \ + _NM_GET_PRIVATE(self, NMSettingBridge, NM_IS_SETTING_BRIDGE, NMSetting) + +/*****************************************************************************/ + +G_DEFINE_BOXED_TYPE(NMBridgeVlan, nm_bridge_vlan, _nm_bridge_vlan_dup, nm_bridge_vlan_unref) + +struct _NMBridgeVlan { + guint refcount; + guint16 vid_start; + guint16 vid_end; + bool untagged : 1; + bool pvid : 1; + bool sealed : 1; +}; + +static gboolean +NM_IS_BRIDGE_VLAN(const NMBridgeVlan *self, gboolean also_sealed) +{ + return self && self->refcount > 0 && (also_sealed || !self->sealed); +} + +/** + * nm_bridge_vlan_new: + * @vid_start: the start VLAN id, must be between 1 and 4094. + * @vid_end: the end VLAN id, must be 0 or between @vid_start and 4094. + * + * Creates a new #NMBridgeVlan object for the given VLAN id range. + * Setting @vid_end to 0 is equivalent to setting it to @vid_start + * and creates a single-id VLAN. + * + * Returns: (transfer full): the new #NMBridgeVlan object. + * + * Since: 1.18 + **/ +NMBridgeVlan * +nm_bridge_vlan_new(guint16 vid_start, guint16 vid_end) +{ + NMBridgeVlan *vlan; + + if (vid_end == 0) + vid_end = vid_start; + + g_return_val_if_fail(vid_start >= NM_BRIDGE_VLAN_VID_MIN, NULL); + g_return_val_if_fail(vid_end <= NM_BRIDGE_VLAN_VID_MAX, NULL); + g_return_val_if_fail(vid_start <= vid_end, NULL); + + vlan = g_slice_new0(NMBridgeVlan); + vlan->refcount = 1; + vlan->vid_start = vid_start; + vlan->vid_end = vid_end; + + return vlan; +} + +/** + * nm_bridge_vlan_ref: + * @vlan: the #NMBridgeVlan + * + * Increases the reference count of the object. + * + * Returns: the input argument @vlan object. + * + * Since: 1.18 + **/ +NMBridgeVlan * +nm_bridge_vlan_ref(NMBridgeVlan *vlan) +{ + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE), NULL); + + nm_assert(vlan->refcount < G_MAXUINT); + + vlan->refcount++; + return vlan; +} + +/** + * nm_bridge_vlan_unref: + * @vlan: the #NMBridgeVlan + * + * Decreases the reference count of the object. If the reference count + * reaches zero the object will be destroyed. + * + * Since: 1.18 + **/ +void +nm_bridge_vlan_unref(NMBridgeVlan *vlan) +{ + g_return_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE)); + + if (--vlan->refcount == 0) + g_slice_free(NMBridgeVlan, vlan); +} + +/** + * nm_bridge_vlan_cmp: + * @a: a #NMBridgeVlan + * @b: another #NMBridgeVlan + * + * Compare two bridge VLAN objects. + * + * Returns: zero of the two instances are equivalent or + * a non-zero integer otherwise. This defines a total ordering + * over the VLANs. Whether a VLAN is sealed or not does not + * affect the comparison. + * + * Since: 1.18 + **/ +int +nm_bridge_vlan_cmp(const NMBridgeVlan *a, const NMBridgeVlan *b) +{ + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(a, TRUE), 0); + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(b, TRUE), 0); + + NM_CMP_SELF(a, b); + NM_CMP_FIELD(a, b, vid_start); + NM_CMP_FIELD(a, b, vid_end); + NM_CMP_FIELD_BOOL(a, b, untagged); + NM_CMP_FIELD_BOOL(a, b, pvid); + + return 0; +} + +NMBridgeVlan * +_nm_bridge_vlan_dup(const NMBridgeVlan *vlan) +{ + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE), NULL); + + if (vlan->sealed) { + nm_bridge_vlan_ref((NMBridgeVlan *) vlan); + return (NMBridgeVlan *) vlan; + } + + return nm_bridge_vlan_new_clone(vlan); +} + +NMBridgeVlan * +_nm_bridge_vlan_dup_and_seal(const NMBridgeVlan *vlan) +{ + NMBridgeVlan *new; + + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE), NULL); + + new = _nm_bridge_vlan_dup(vlan); + nm_bridge_vlan_seal(new); + + return new; +} + +/** + * nm_bridge_vlan_get_vid_range: + * @vlan: the #NMBridgeVlan + * @vid_start: (out): location to store the VLAN id range start. + * @vid_end: (out): location to store the VLAN id range end + * + * Gets the VLAN id range. + * + * Returns: %TRUE is the VLAN specifies a range, %FALSE if it is + * a single-id VLAN. + * + * Since: 1.18 + **/ +gboolean +nm_bridge_vlan_get_vid_range(const NMBridgeVlan *vlan, guint16 *vid_start, guint16 *vid_end) +{ + /* with LTO and optimization, the compiler complains that the + * output variables are not initialized. In practice, the function + * only sets the output on success. But make the compiler happy. + */ + NM_SET_OUT(vid_start, 0); + NM_SET_OUT(vid_end, 0); + + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE), 0); + + NM_SET_OUT(vid_start, vlan->vid_start); + NM_SET_OUT(vid_end, vlan->vid_end); + + return vlan->vid_start != vlan->vid_end; +} + +/** + * nm_bridge_vlan_is_untagged: + * @vlan: the #NMBridgeVlan + * + * Returns whether the VLAN is untagged. + * + * Returns: %TRUE if the VLAN is untagged, %FALSE otherwise + * + * Since: 1.18 + **/ +gboolean +nm_bridge_vlan_is_untagged(const NMBridgeVlan *vlan) +{ + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE), FALSE); + + return vlan->untagged; +} + +/** + * nm_bridge_vlan_is_pvid: + * @vlan: the #NMBridgeVlan + * + * Returns whether the VLAN is the PVID for the port. + * + * Returns: %TRUE if the VLAN is the PVID + * + * Since: 1.18 + **/ +gboolean +nm_bridge_vlan_is_pvid(const NMBridgeVlan *vlan) +{ + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE), FALSE); + + return vlan->pvid; +} + +/** + * nm_bridge_vlan_set_untagged: + * @vlan: the #NMBridgeVlan + * @value: the new value + * + * Change the value of the untagged property of the VLAN. + * + * Since: 1.18 + **/ +void +nm_bridge_vlan_set_untagged(NMBridgeVlan *vlan, gboolean value) +{ + g_return_if_fail(NM_IS_BRIDGE_VLAN(vlan, FALSE)); + + vlan->untagged = value; +} + +/** + * nm_bridge_vlan_set_pvid: + * @vlan: the #NMBridgeVlan + * @value: the new value + * + * Change the value of the PVID property of the VLAN. It + * is invalid to set the value to %TRUE for non-single-id + * VLANs. + * + * Since: 1.18 + **/ +void +nm_bridge_vlan_set_pvid(NMBridgeVlan *vlan, gboolean value) +{ + g_return_if_fail(NM_IS_BRIDGE_VLAN(vlan, FALSE)); + g_return_if_fail(!value || vlan->vid_start == vlan->vid_end); + + vlan->pvid = value; +} + +/** + * nm_bridge_vlan_is_sealed: + * @vlan: the #NMBridgeVlan instance + * + * Returns: whether @self is sealed or not. + * + * Since: 1.18 + */ +gboolean +nm_bridge_vlan_is_sealed(const NMBridgeVlan *vlan) +{ + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE), FALSE); + + return vlan->sealed; +} + +/** + * nm_bridge_vlan_seal: + * @vlan: the #NMBridgeVlan instance + * + * Seal the #NMBridgeVlan instance. Afterwards, it is a bug + * to call all functions that modify the instance (except ref/unref). + * A sealed instance cannot be unsealed again, but you can create + * an unsealed copy with nm_bridge_vlan_new_clone(). + * + * Since: 1.18 + */ +void +nm_bridge_vlan_seal(NMBridgeVlan *vlan) +{ + g_return_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE)); + + vlan->sealed = TRUE; +} + +/** + * nm_bridge_vlan_new_clone: + * @vlan: the #NMBridgeVlan instance to copy + * + * Returns: (transfer full): a clone of @vlan. This instance + * is always unsealed. + * + * Since: 1.18 + */ +NMBridgeVlan * +nm_bridge_vlan_new_clone(const NMBridgeVlan *vlan) +{ + NMBridgeVlan *copy; + + g_return_val_if_fail(NM_IS_BRIDGE_VLAN(vlan, TRUE), NULL); + + copy = nm_bridge_vlan_new(vlan->vid_start, vlan->vid_end); + copy->untagged = vlan->untagged; + copy->pvid = vlan->pvid; + + return copy; +} + +/** + * nm_bridge_vlan_to_str: + * @vlan: the %NMBridgeVlan + * @error: location of the error + * + * Convert a %NMBridgeVlan to a string. + * + * Returns: formatted string or %NULL + * + * Since: 1.18 + */ +char * +nm_bridge_vlan_to_str(const NMBridgeVlan *vlan, GError **error) +{ + NMStrBuf string; + + g_return_val_if_fail(vlan, NULL); + g_return_val_if_fail(!error || !*error, NULL); + + /* The function never fails at the moment, but it might in the + * future if more parameters are added to the object that could + * make it invalid. */ + + nm_str_buf_init(&string, NM_UTILS_GET_NEXT_REALLOC_SIZE_32, FALSE); + + if (vlan->vid_start == vlan->vid_end) + nm_str_buf_append_printf(&string, "%u", vlan->vid_start); + else + nm_str_buf_append_printf(&string, "%u-%u", vlan->vid_start, vlan->vid_end); + + if (nm_bridge_vlan_is_pvid(vlan)) + nm_str_buf_append(&string, " pvid"); + if (nm_bridge_vlan_is_untagged(vlan)) + nm_str_buf_append(&string, " untagged"); + + return nm_str_buf_finalize(&string, NULL); +} + +/** + * nm_bridge_vlan_from_str: + * @str: the string representation of a bridge VLAN + * @error: location of the error + * + * Parses the string representation of the queueing + * discipline to a %NMBridgeVlan instance. + * + * Returns: the %NMBridgeVlan or %NULL + * + * Since: 1.18 + */ +NMBridgeVlan * +nm_bridge_vlan_from_str(const char *str, GError **error) +{ + NMBridgeVlan * vlan = NULL; + gs_free const char **tokens = NULL; + guint i, vid_start, vid_end = 0; + gboolean pvid = FALSE; + gboolean untagged = FALSE; + char * c; + + g_return_val_if_fail(str, NULL); + g_return_val_if_fail(!error || !*error, NULL); + + tokens = nm_utils_escaped_tokens_split(str, NM_ASCII_SPACES); + if (!tokens || !tokens[0]) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + "missing VLAN id"); + return NULL; + } + + c = strchr(tokens[0], '-'); + if (c) + *c = '\0'; + + vid_start = _nm_utils_ascii_str_to_uint64(tokens[0], + 10, + NM_BRIDGE_VLAN_VID_MIN, + NM_BRIDGE_VLAN_VID_MAX, + G_MAXUINT); + if (vid_start == G_MAXUINT) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + "invalid VLAN id range start '%s', must be in [1,4094]", + tokens[0]); + return NULL; + } + + if (c) { + vid_end = _nm_utils_ascii_str_to_uint64(c + 1, + 10, + NM_BRIDGE_VLAN_VID_MIN, + NM_BRIDGE_VLAN_VID_MAX, + G_MAXUINT); + if (vid_end == G_MAXUINT) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + "invalid VLAN id range end '%s', must be in [1,4094]", + c + 1); + return NULL; + } + if (vid_end < vid_start) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + "invalid VLAN id range %u-%u, start VLAN id must be less than end VLAN id", + vid_start, + vid_end); + return NULL; + } + } else + vid_end = vid_start; + + for (i = 1; tokens[i]; i++) { + if (nm_streq(tokens[i], "pvid")) { + if (vid_start != vid_end) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + "a VLAN range can't be a PVID"); + return NULL; + } + pvid = TRUE; + } else if (nm_streq(tokens[i], "untagged")) + untagged = TRUE; + else { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_FAILED, + "invalid option '%s'", + tokens[i]); + return NULL; + } + } + + vlan = nm_bridge_vlan_new(vid_start, vid_end); + nm_bridge_vlan_set_pvid(vlan, pvid); + nm_bridge_vlan_set_untagged(vlan, untagged); + + return vlan; +} + +/*****************************************************************************/ + +static int +vlan_ptr_cmp(gconstpointer a, gconstpointer b) +{ + const NMBridgeVlan *vlan_a = *(const NMBridgeVlan **) a; + const NMBridgeVlan *vlan_b = *(const NMBridgeVlan **) b; + + return nm_bridge_vlan_cmp(vlan_a, vlan_b); +} + +gboolean +_nm_setting_bridge_sort_vlans(NMSettingBridge *setting) +{ + NMSettingBridgePrivate *priv; + gboolean need_sort = FALSE; + guint i; + + priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + for (i = 1; i < priv->vlans->len; i++) { + NMBridgeVlan *vlan_prev = priv->vlans->pdata[i - 1]; + NMBridgeVlan *vlan = priv->vlans->pdata[i]; + + if (nm_bridge_vlan_cmp(vlan_prev, vlan) > 0) { + need_sort = TRUE; + break; + } + } + + if (need_sort) { + g_ptr_array_sort(priv->vlans, vlan_ptr_cmp); + _notify(setting, PROP_VLANS); + } + + return need_sort; +} + +/*****************************************************************************/ + +/** + * nm_setting_bridge_get_mac_address: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:mac-address property of the setting + **/ +const char * +nm_setting_bridge_get_mac_address(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), NULL); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->mac_address; +} + +/** + * nm_setting_bridge_get_stp: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:stp property of the setting + **/ +gboolean +nm_setting_bridge_get_stp(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), FALSE); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->stp; +} + +/** + * nm_setting_bridge_get_priority: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:priority property of the setting + **/ +guint16 +nm_setting_bridge_get_priority(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->priority; +} + +/** + * nm_setting_bridge_get_forward_delay: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:forward-delay property of the setting + **/ +guint16 +nm_setting_bridge_get_forward_delay(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->forward_delay; +} + +/** + * nm_setting_bridge_get_hello_time: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:hello-time property of the setting + **/ +guint16 +nm_setting_bridge_get_hello_time(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->hello_time; +} + +/** + * nm_setting_bridge_get_max_age: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:max-age property of the setting + **/ +guint16 +nm_setting_bridge_get_max_age(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->max_age; +} + +/** + * nm_setting_bridge_get_ageing_time: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:ageing-time property of the setting + **/ +guint +nm_setting_bridge_get_ageing_time(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->ageing_time; +} + +/** + * nm_setting_bridge_get_group_forward_mask: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:group-forward-mask property of the setting + * + * Since: 1.10 + **/ +guint16 +nm_setting_bridge_get_group_forward_mask(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->group_forward_mask; +} + +/** + * nm_setting_bridge_get_multicast_snooping: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-snooping property of the setting + * + * Since: 1.2 + **/ +gboolean +nm_setting_bridge_get_multicast_snooping(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), FALSE); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_snooping; +} + +/** + * nm_setting_bridge_get_vlan_filtering: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:vlan-filtering property of the setting + * + * Since: 1.18 + **/ +gboolean +nm_setting_bridge_get_vlan_filtering(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), FALSE); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->vlan_filtering; +} + +/** + * nm_setting_bridge_get_vlan_default_pvid: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:vlan-default-pvid property of the setting + * + * Since: 1.18 + **/ +guint16 +nm_setting_bridge_get_vlan_default_pvid(NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 1); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->vlan_default_pvid; +} + +/** + * nm_setting_bridge_add_vlan: + * @setting: the #NMSettingBridge + * @vlan: the vlan to add + * + * Appends a new vlan and associated information to the setting. The + * given vlan gets sealed and a reference to it is added. + * + * Since: 1.18 + **/ +void +nm_setting_bridge_add_vlan(NMSettingBridge *setting, NMBridgeVlan *vlan) +{ + NMSettingBridgePrivate *priv; + + g_return_if_fail(NM_IS_SETTING_BRIDGE(setting)); + g_return_if_fail(vlan); + + priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + nm_bridge_vlan_seal(vlan); + nm_bridge_vlan_ref(vlan); + + g_ptr_array_add(priv->vlans, vlan); + _notify(setting, PROP_VLANS); +} + +/** + * nm_setting_bridge_get_num_vlans: + * @setting: the #NMSettingBridge + * + * Returns: the number of VLANs + * + * Since: 1.18 + **/ +guint +nm_setting_bridge_get_num_vlans(NMSettingBridge *setting) +{ + NMSettingBridgePrivate *priv; + + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + return priv->vlans->len; +} + +/** + * nm_setting_bridge_get_vlan: + * @setting: the #NMSettingBridge + * @idx: index number of the VLAN to return + * + * Returns: (transfer none): the VLAN at index @idx + * + * Since: 1.18 + **/ +NMBridgeVlan * +nm_setting_bridge_get_vlan(NMSettingBridge *setting, guint idx) +{ + NMSettingBridgePrivate *priv; + + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), NULL); + priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + g_return_val_if_fail(idx < priv->vlans->len, NULL); + + return priv->vlans->pdata[idx]; +} + +/** + * nm_setting_bridge_remove_vlan: + * @setting: the #NMSettingBridge + * @idx: index number of the VLAN. + * + * Removes the vlan at index @idx. + * + * Since: 1.18 + **/ +void +nm_setting_bridge_remove_vlan(NMSettingBridge *setting, guint idx) +{ + NMSettingBridgePrivate *priv; + + g_return_if_fail(NM_IS_SETTING_BRIDGE(setting)); + priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + g_return_if_fail(idx < priv->vlans->len); + + g_ptr_array_remove_index(priv->vlans, idx); + _notify(setting, PROP_VLANS); +} + +/** + * nm_setting_bridge_remove_vlan_by_vid: + * @setting: the #NMSettingBridge + * @vid_start: the vlan start index + * @vid_end: the vlan end index + * + * Remove the VLAN with range @vid_start to @vid_end. + * If @vid_end is zero, it is assumed to be equal to @vid_start + * and so the single-id VLAN with id @vid_start is removed. + * + * Returns: %TRUE if the vlan was found and removed; %FALSE otherwise + * + * Since: 1.18 + **/ +gboolean +nm_setting_bridge_remove_vlan_by_vid(NMSettingBridge *setting, guint16 vid_start, guint16 vid_end) +{ + NMSettingBridgePrivate *priv; + NMBridgeVlan * vlan; + guint i; + + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), FALSE); + priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + if (vid_end == 0) + vid_end = vid_start; + + for (i = 0; i < priv->vlans->len; i++) { + vlan = (NMBridgeVlan *) priv->vlans->pdata[i]; + if (vlan->vid_start == vid_start && vlan->vid_end == vid_end) { + g_ptr_array_remove_index(priv->vlans, i); + _notify(setting, PROP_VLANS); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_bridge_clear_vlans: + * @setting: the #NMSettingBridge + * + * Removes all configured VLANs. + * + * Since: 1.18 + **/ +void +nm_setting_bridge_clear_vlans(NMSettingBridge *setting) +{ + NMSettingBridgePrivate *priv; + + g_return_if_fail(NM_IS_SETTING_BRIDGE(setting)); + priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + if (priv->vlans->len != 0) { + g_ptr_array_set_size(priv->vlans, 0); + _notify(setting, PROP_VLANS); + } +} + +GPtrArray * +_nm_setting_bridge_get_vlans(NMSettingBridge *setting) +{ + nm_assert(NM_IS_SETTING_BRIDGE(setting)); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->vlans; +} + +/*****************************************************************************/ + +/** + * 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; +} + +/** + * nm_setting_bridge_get_multicast_hash_max: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-hash-max property of the setting + * + * Since 1.26 + **/ +guint32 +nm_setting_bridge_get_multicast_hash_max(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_hash_max; +} + +/** + * nm_setting_bridge_get_multicast_last_member_count: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-last-member-count property of the setting + * + * Since 1.26 + **/ +guint32 +nm_setting_bridge_get_multicast_last_member_count(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_last_member_count; +} + +/** + * nm_setting_bridge_get_multicast_last_member_interval: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-last-member-interval property of the setting + * + * Since 1.26 + **/ +guint64 +nm_setting_bridge_get_multicast_last_member_interval(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_last_member_interval; +} + +/** + * nm_setting_bridge_get_multicast_membership_interval: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-membership-interval property of the setting + * + * Since 1.26 + **/ +guint64 +nm_setting_bridge_get_multicast_membership_interval(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_membership_interval; +} + +/** + * nm_setting_bridge_get_multicast_querier_interval: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-querier-interval property of the setting + * + * Since 1.26 + **/ +guint64 +nm_setting_bridge_get_multicast_querier_interval(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_querier_interval; +} + +/** + * nm_setting_bridge_get_multicast_query_interval: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-query-interval property of the setting + * + * Since 1.26 + **/ +guint64 +nm_setting_bridge_get_multicast_query_interval(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_query_interval; +} + +/** + * nm_setting_bridge_get_multicast_query_response_interval: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-query-response-interval property of the setting + * + * Since 1.26 + **/ +guint64 +nm_setting_bridge_get_multicast_query_response_interval(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_query_response_interval; +} + +/** + * nm_setting_bridge_get_multicast_startup_query_count: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-query-response-interval property of the setting + * + * Since 1.26 + **/ +guint32 +nm_setting_bridge_get_multicast_startup_query_count(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_startup_query_count; +} + +/** + * nm_setting_bridge_get_multicast_startup_query_interval: + * @setting: the #NMSettingBridge + * + * Returns: the #NMSettingBridge:multicast-startup-query-interval property of the setting + * + * Since 1.26 + **/ +guint64 +nm_setting_bridge_get_multicast_startup_query_interval(const NMSettingBridge *setting) +{ + g_return_val_if_fail(NM_IS_SETTING_BRIDGE(setting), 0); + + return NM_SETTING_BRIDGE_GET_PRIVATE(setting)->multicast_startup_query_interval; +} + +/*****************************************************************************/ + +static gboolean +check_range(guint32 val, guint32 min, guint32 max, gboolean zero, const char *prop, GError **error) +{ + if (zero && val == 0) + return TRUE; + + if (val < min || val > max) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("value '%d' is out of range <%d-%d>"), + val, + min, + max); + g_prefix_error(error, "%s.%s: ", NM_SETTING_BRIDGE_SETTING_NAME, prop); + return FALSE; + } + return TRUE; +} + +static gboolean +verify(NMSetting *setting, NMConnection *connection, GError **error) +{ + NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + if (priv->mac_address && !nm_utils_hwaddr_valid(priv->mac_address, ETH_ALEN)) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("is not a valid MAC address")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_BRIDGE_MAC_ADDRESS); + return FALSE; + } + + if (!check_range(priv->forward_delay, + NM_BRIDGE_FORWARD_DELAY_MIN, + NM_BRIDGE_FORWARD_DELAY_MAX, + !priv->stp, + NM_SETTING_BRIDGE_FORWARD_DELAY, + error)) + return FALSE; + + if (!check_range(priv->hello_time, + NM_BRIDGE_HELLO_TIME_MIN, + NM_BRIDGE_HELLO_TIME_MAX, + !priv->stp, + NM_SETTING_BRIDGE_HELLO_TIME, + error)) + return FALSE; + + if (!check_range(priv->max_age, + NM_BRIDGE_MAX_AGE_MIN, + NM_BRIDGE_MAX_AGE_MAX, + !priv->stp, + NM_SETTING_BRIDGE_MAX_AGE, + error)) + return FALSE; + + if (!check_range(priv->ageing_time, + NM_BRIDGE_AGEING_TIME_MIN, + NM_BRIDGE_AGEING_TIME_MAX, + !priv->stp, + NM_SETTING_BRIDGE_AGEING_TIME, + error)) + return FALSE; + + if (priv->group_forward_mask & 7) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("the mask can't contain bits 0 (STP), 1 (MAC) or 2 (LACP)")); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_BRIDGE_GROUP_FORWARD_MASK); + return FALSE; + } + + if (!_nm_connection_verify_required_interface_name(connection, error)) + return FALSE; + + if (!_nm_utils_bridge_vlan_verify_list(priv->vlans, + FALSE, + error, + NM_SETTING_BRIDGE_SETTING_NAME, + 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 (!NM_IN_STRSET(priv->multicast_router, NULL, "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_utils_is_power_of_two(priv->multicast_hash_max)) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("'%s' option must be a power of 2"), + NM_SETTING_BRIDGE_MULTICAST_HASH_MAX); + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_BRIDGE_MULTICAST_HASH_MAX); + return FALSE; + } + + /* Failures from here on are NORMALIZABLE... */ + + if (!_nm_utils_bridge_vlan_verify_list(priv->vlans, + TRUE, + error, + NM_SETTING_BRIDGE_SETTING_NAME, + NM_SETTING_BRIDGE_VLANS)) + return NM_SETTING_VERIFY_NORMALIZABLE; + + return TRUE; +} + +static NMTernary +compare_property(const NMSettInfoSetting *sett_info, + guint property_idx, + NMConnection * con_a, + NMSetting * set_a, + NMConnection * con_b, + NMSetting * set_b, + NMSettingCompareFlags flags) +{ + NMSettingBridgePrivate *priv_a; + NMSettingBridgePrivate *priv_b; + guint i; + + if (nm_streq(sett_info->property_infos[property_idx].name, NM_SETTING_BRIDGE_VLANS)) { + if (set_b) { + priv_a = NM_SETTING_BRIDGE_GET_PRIVATE(set_a); + priv_b = NM_SETTING_BRIDGE_GET_PRIVATE(set_b); + + if (priv_a->vlans->len != priv_b->vlans->len) + return FALSE; + for (i = 0; i < priv_a->vlans->len; i++) { + if (nm_bridge_vlan_cmp(priv_a->vlans->pdata[i], priv_b->vlans->pdata[i])) + return FALSE; + } + } + return TRUE; + } + + return NM_SETTING_CLASS(nm_setting_bridge_parent_class) + ->compare_property(sett_info, property_idx, con_a, set_a, con_b, set_b, flags); +} + +/*****************************************************************************/ + +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE(object); + NMSettingBridge * setting = NM_SETTING_BRIDGE(object); + + switch (prop_id) { + case PROP_MAC_ADDRESS: + g_value_set_string(value, nm_setting_bridge_get_mac_address(setting)); + break; + case PROP_STP: + g_value_set_boolean(value, priv->stp); + break; + case PROP_PRIORITY: + g_value_set_uint(value, priv->priority); + break; + case PROP_FORWARD_DELAY: + g_value_set_uint(value, priv->forward_delay); + break; + case PROP_HELLO_TIME: + g_value_set_uint(value, priv->hello_time); + break; + case PROP_MAX_AGE: + g_value_set_uint(value, priv->max_age); + break; + 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_HASH_MAX: + g_value_set_uint(value, priv->multicast_hash_max); + break; + case PROP_MULTICAST_LAST_MEMBER_COUNT: + g_value_set_uint(value, priv->multicast_last_member_count); + break; + case PROP_MULTICAST_LAST_MEMBER_INTERVAL: + g_value_set_uint64(value, priv->multicast_last_member_interval); + break; + case PROP_MULTICAST_MEMBERSHIP_INTERVAL: + g_value_set_uint64(value, priv->multicast_membership_interval); + 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_QUERIER_INTERVAL: + g_value_set_uint64(value, priv->multicast_querier_interval); + break; + case PROP_MULTICAST_QUERY_INTERVAL: + g_value_set_uint64(value, priv->multicast_query_interval); + break; + case PROP_MULTICAST_QUERY_RESPONSE_INTERVAL: + g_value_set_uint64(value, priv->multicast_query_response_interval); + break; + case PROP_MULTICAST_QUERY_USE_IFADDR: + g_value_set_boolean(value, priv->multicast_query_use_ifaddr); + break; + case PROP_MULTICAST_STARTUP_QUERY_COUNT: + g_value_set_uint(value, priv->multicast_startup_query_count); + break; + case PROP_MULTICAST_STARTUP_QUERY_INTERVAL: + g_value_set_uint64(value, priv->multicast_startup_query_interval); + 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, + (GDestroyNotify) nm_bridge_vlan_unref)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +static void +set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE(object); + + switch (prop_id) { + case PROP_MAC_ADDRESS: + g_free(priv->mac_address); + priv->mac_address = + _nm_utils_hwaddr_canonical_or_invalid(g_value_get_string(value), ETH_ALEN); + break; + case PROP_STP: + priv->stp = g_value_get_boolean(value); + break; + case PROP_PRIORITY: + priv->priority = (guint16) g_value_get_uint(value); + break; + case PROP_FORWARD_DELAY: + priv->forward_delay = (guint16) g_value_get_uint(value); + break; + case PROP_HELLO_TIME: + priv->hello_time = (guint16) g_value_get_uint(value); + break; + case PROP_MAX_AGE: + priv->max_age = (guint16) g_value_get_uint(value); + break; + 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_HASH_MAX: + priv->multicast_hash_max = g_value_get_uint(value); + break; + case PROP_MULTICAST_LAST_MEMBER_COUNT: + priv->multicast_last_member_count = g_value_get_uint(value); + break; + case PROP_MULTICAST_LAST_MEMBER_INTERVAL: + priv->multicast_last_member_interval = g_value_get_uint64(value); + break; + case PROP_MULTICAST_MEMBERSHIP_INTERVAL: + priv->multicast_membership_interval = g_value_get_uint64(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_QUERIER_INTERVAL: + priv->multicast_querier_interval = g_value_get_uint64(value); + break; + case PROP_MULTICAST_QUERY_INTERVAL: + priv->multicast_query_interval = g_value_get_uint64(value); + break; + case PROP_MULTICAST_QUERY_RESPONSE_INTERVAL: + priv->multicast_query_response_interval = g_value_get_uint64(value); + break; + case PROP_MULTICAST_QUERY_USE_IFADDR: + priv->multicast_query_use_ifaddr = g_value_get_boolean(value); + break; + case PROP_MULTICAST_STARTUP_QUERY_COUNT: + priv->multicast_startup_query_count = g_value_get_uint(value); + break; + case PROP_MULTICAST_STARTUP_QUERY_INTERVAL: + priv->multicast_startup_query_interval = g_value_get_uint64(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), + (NMUtilsCopyFunc) _nm_bridge_vlan_dup_and_seal, + (GDestroyNotify) nm_bridge_vlan_unref); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); + break; + } +} + +/*****************************************************************************/ + +static void +nm_setting_bridge_init(NMSettingBridge *setting) +{ + NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE(setting); + + priv->vlans = g_ptr_array_new_with_free_func((GDestroyNotify) nm_bridge_vlan_unref); + + priv->ageing_time = NM_BRIDGE_AGEING_TIME_DEF; + priv->forward_delay = NM_BRIDGE_FORWARD_DELAY_DEF; + priv->hello_time = NM_BRIDGE_HELLO_TIME_DEF; + priv->max_age = NM_BRIDGE_MAX_AGE_DEF; + priv->multicast_last_member_count = NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_DEF; + priv->multicast_last_member_interval = NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_DEF; + priv->multicast_membership_interval = NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_DEF; + priv->multicast_hash_max = NM_BRIDGE_MULTICAST_HASH_MAX_DEF; + priv->multicast_snooping = NM_BRIDGE_MULTICAST_SNOOPING_DEF; + priv->priority = NM_BRIDGE_PRIORITY_DEF; + priv->stp = NM_BRIDGE_STP_DEF; + priv->vlan_default_pvid = NM_BRIDGE_VLAN_DEFAULT_PVID_DEF; + priv->multicast_query_interval = NM_BRIDGE_MULTICAST_QUERY_INTERVAL_DEF; + priv->multicast_query_response_interval = NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_DEF; + priv->multicast_querier_interval = NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_DEF; + priv->multicast_startup_query_count = NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_DEF; + priv->multicast_startup_query_interval = NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_DEF; + + nm_assert(priv->multicast_querier == NM_BRIDGE_MULTICAST_QUERIER_DEF); + nm_assert(priv->multicast_query_use_ifaddr == NM_BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEF); + nm_assert(priv->vlan_stats_enabled == NM_BRIDGE_VLAN_STATS_ENABLED_DEF); +} + +/** + * nm_setting_bridge_new: + * + * Creates a new #NMSettingBridge object with default values. + * + * Returns: (transfer full): the new empty #NMSettingBridge object + **/ +NMSetting * +nm_setting_bridge_new(void) +{ + return g_object_new(NM_TYPE_SETTING_BRIDGE, NULL); +} + +static void +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); +} + +static void +nm_setting_bridge_class_init(NMSettingBridgeClass *klass) +{ + GObjectClass * object_class = G_OBJECT_CLASS(klass); + NMSettingClass *setting_class = NM_SETTING_CLASS(klass); + GArray * properties_override = _nm_sett_info_property_override_create_array(); + + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->finalize = finalize; + + setting_class->compare_property = compare_property; + setting_class->verify = verify; + + /** + * NMSettingBridge:mac-address: + * + * 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.12: Use the ethernet.cloned-mac-address property instead. + **/ + /* ---keyfile--- + * property: mac-address + * format: usual hex-digits-and-colons notation + * description: MAC address in traditional hex-digits-and-colons notation, + * or semicolon separated list of 6 decimal bytes (obsolete) + * example: mac-address=00:22:68:12:79:A2 + * mac-address=0;34;104;18;121;162; + * ---end--- + * ---ifcfg-rh--- + * property: mac-address + * variable: BRIDGE_MACADDR(+) + * description: MAC address of the bridge. Note that this requires a recent + * kernel support, originally introduced in 3.15 upstream kernel) + * BRIDGE_MACADDR for bridges is an NM extension. + * ---end--- + */ + obj_properties[PROP_MAC_ADDRESS] = g_param_spec_string( + NM_SETTING_BRIDGE_MAC_ADDRESS, + "", + "", + NULL, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + _nm_properties_override_gobj(properties_override, + obj_properties[PROP_MAC_ADDRESS], + &nm_sett_info_propert_type_mac_address); + + /** + * NMSettingBridge:stp: + * + * Controls whether Spanning Tree Protocol (STP) is enabled for this bridge. + **/ + /* ---ifcfg-rh--- + * property: stp + * variable: STP + * default: no + * description: Span tree protocol participation. + * ---end--- + */ + _nm_setting_property_define_boolean(properties_override, + obj_properties, + NM_SETTING_BRIDGE_STP, + PROP_STP, + NM_BRIDGE_STP_DEF, + NM_SETTING_PARAM_INFERRABLE, + nm_setting_bridge_get_stp); + + /** + * NMSettingBridge:priority: + * + * Sets the Spanning Tree Protocol (STP) priority for this bridge. Lower + * values are "better"; the lowest priority bridge will be elected the root + * bridge. + **/ + /* ---ifcfg-rh--- + * property: priority + * variable: BRIDGING_OPTS: priority= + * values: 0 - 32768 + * default: 32768 + * description: STP priority. + * ---end--- + */ + obj_properties[PROP_PRIORITY] = + g_param_spec_uint(NM_SETTING_BRIDGE_PRIORITY, + "", + "", + NM_BRIDGE_PRIORITY_MIN, + NM_BRIDGE_PRIORITY_MAX, + NM_BRIDGE_PRIORITY_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:forward-delay: + * + * The Spanning Tree Protocol (STP) forwarding delay, in seconds. + **/ + /* ---ifcfg-rh--- + * property: forward-delay + * variable: DELAY + * values: 2 - 30 + * default: 15 + * description: STP forwarding delay. + * ---end--- + */ + obj_properties[PROP_FORWARD_DELAY] = + g_param_spec_uint(NM_SETTING_BRIDGE_FORWARD_DELAY, + "", + "", + 0, + NM_BRIDGE_FORWARD_DELAY_MAX, + NM_BRIDGE_FORWARD_DELAY_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:hello-time: + * + * The Spanning Tree Protocol (STP) hello time, in seconds. + **/ + /* ---ifcfg-rh--- + * property: hello-time + * variable: BRIDGING_OPTS: hello_time= + * values: 1 - 10 + * default: 2 + * description: STP hello time. + * ---end--- + */ + obj_properties[PROP_HELLO_TIME] = + g_param_spec_uint(NM_SETTING_BRIDGE_HELLO_TIME, + "", + "", + 0, + NM_BRIDGE_HELLO_TIME_MAX, + NM_BRIDGE_HELLO_TIME_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:max-age: + * + * The Spanning Tree Protocol (STP) maximum message age, in seconds. + **/ + /* ---ifcfg-rh--- + * property: max-age + * variable: BRIDGING_OPTS: max_age= + * values: 6 - 40 + * default: 20 + * description: STP maximum message age. + * ---end--- + */ + obj_properties[PROP_MAX_AGE] = + g_param_spec_uint(NM_SETTING_BRIDGE_MAX_AGE, + "", + "", + 0, + NM_BRIDGE_MAX_AGE_MAX, + NM_BRIDGE_MAX_AGE_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:ageing-time: + * + * The Ethernet MAC address aging time, in seconds. + **/ + /* ---ifcfg-rh--- + * property: ageing-time + * variable: BRIDGING_OPTS: ageing_time= + * values: 0 - 1000000 + * default: 300 + * description: Ethernet MAC ageing time. + * ---end--- + */ + obj_properties[PROP_AGEING_TIME] = + g_param_spec_uint(NM_SETTING_BRIDGE_AGEING_TIME, + "", + "", + NM_BRIDGE_AGEING_TIME_MIN, + NM_BRIDGE_AGEING_TIME_MAX, + NM_BRIDGE_AGEING_TIME_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:group-forward-mask: + * + * 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. + * + * Since: 1.10 + **/ + obj_properties[PROP_GROUP_FORWARD_MASK] = + g_param_spec_uint(NM_SETTING_BRIDGE_GROUP_FORWARD_MASK, + "", + "", + 0, + 0xFFFF, + 0, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-snooping: + * + * 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. + * + * Since: 1.2 + **/ + /* ---ifcfg-rh--- + * property: multicast-snooping + * variable: BRIDGING_OPTS: multicast_snooping= + * values: 0 or 1 + * default: 1 + * description: IGMP snooping support. + * ---end--- + */ + _nm_setting_property_define_boolean(properties_override, + obj_properties, + NM_SETTING_BRIDGE_MULTICAST_SNOOPING, + PROP_MULTICAST_SNOOPING, + NM_BRIDGE_MULTICAST_SNOOPING_DEF, + NM_SETTING_PARAM_INFERRABLE, + nm_setting_bridge_get_multicast_snooping); + + /** + * NMSettingBridge:vlan-filtering: + * + * Control whether VLAN filtering is enabled on the bridge. + * + * Since: 1.18 + **/ + /* ---ifcfg-rh--- + * property: vlan-filtering + * variable: BRIDGING_OPTS: vlan_filtering= + * values: 0 or 1 + * default: 0 + * description: VLAN filtering support. + * ---end--- + */ + _nm_setting_property_define_boolean(properties_override, + obj_properties, + NM_SETTING_BRIDGE_VLAN_FILTERING, + PROP_VLAN_FILTERING, + FALSE, + NM_SETTING_PARAM_INFERRABLE, + nm_setting_bridge_get_vlan_filtering); + + /** + * NMSettingBridge:vlan-default-pvid: + * + * The default PVID for the ports of the bridge, that is the VLAN id + * assigned to incoming untagged frames. + * + * Since: 1.18 + **/ + /* ---ifcfg-rh--- + * property: vlan-default-pvid + * variable: BRIDGING_OPTS: default_pvid= + * values: 0 - 4094 + * default: 1 + * description: default VLAN PVID. + * ---end--- + */ + obj_properties[PROP_VLAN_DEFAULT_PVID] = + g_param_spec_uint(NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID, + "", + "", + 0, + NM_BRIDGE_VLAN_VID_MAX, + NM_BRIDGE_VLAN_DEFAULT_PVID_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:vlans: (type GPtrArray(NMBridgeVlan)) + * + * 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. + * + * Since: 1.18 + **/ + /* ---ifcfg-rh--- + * property: vlans + * variable: BRIDGE_VLANS + * description: List of VLANs on the bridge + * example: BRIDGE_VLANS="1 pvid untagged,20,300-400 untagged" + * ---end--- + */ + obj_properties[PROP_VLANS] = g_param_spec_boxed(NM_SETTING_BRIDGE_VLANS, + "", + "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE + | G_PARAM_STATIC_STRINGS); + _nm_properties_override_gobj(properties_override, + obj_properties[PROP_VLANS], + &nm_sett_info_propert_type_bridge_vlans); + + /* ---dbus--- + * property: interface-name + * format: string + * description: Deprecated in favor of connection.interface-name, but can + * be used for backward-compatibility with older daemons, to set the + * bridge's interface name. + * ---end--- + */ + _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--- + * + * Since: 1.24 + */ + 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--- + * + * Since: 1.24 + */ + _nm_setting_property_define_boolean(properties_override, + obj_properties, + NM_SETTING_BRIDGE_VLAN_STATS_ENABLED, + PROP_VLAN_STATS_ENABLED, + NM_BRIDGE_VLAN_STATS_ENABLED_DEF, + NM_SETTING_PARAM_INFERRABLE, + nm_setting_bridge_get_vlan_stats_enabled); + + /** + * NMSettingBridge:multicast-router: + * + * Sets bridge's multicast router. Multicast-snooping must be enabled + * for this option to work. + * + * Supported values are: 'auto', 'disabled', 'enabled' to which kernel + * assigns the numbers 1, 0, and 2, respectively. + * If not specified the default value is 'auto' (1). + **/ + /* ---ifcfg-rh--- + * property: multicast-router + * variable: BRIDGING_OPTS: multicast_router= + * values: auto, enabled, disabled + * default: auto + * example: BRIDGING_OPTS="multicast_router=enabled" + * ---end--- + * + * Since: 1.24 + */ + 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--- + * + * Since: 1.24 + */ + _nm_setting_property_define_boolean(properties_override, + obj_properties, + NM_SETTING_BRIDGE_MULTICAST_QUERY_USE_IFADDR, + PROP_MULTICAST_QUERY_USE_IFADDR, + NM_BRIDGE_MULTICAST_QUERY_USE_IFADDR_DEF, + NM_SETTING_PARAM_INFERRABLE, + nm_setting_bridge_get_multicast_query_use_ifaddr); + + /** + * 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--- + * + * Since: 1.24 + */ + _nm_setting_property_define_boolean(properties_override, + obj_properties, + NM_SETTING_BRIDGE_MULTICAST_QUERIER, + PROP_MULTICAST_QUERIER, + NM_BRIDGE_MULTICAST_QUERIER_DEF, + NM_SETTING_PARAM_INFERRABLE, + nm_setting_bridge_get_multicast_querier); + + /** + * NMSettingBridge:multicast-hash-max: + * + * Set maximum size of multicast hash table (value must be a power of 2). + **/ + /* ---ifcfg-rh--- + * property: multicast-hash-max + * variable: BRIDGING_OPTS: multicast_hash_max= + * default: 4096 + * example: BRIDGING_OPTS="multicast_hash_max=8192" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_HASH_MAX] = + g_param_spec_uint(NM_SETTING_BRIDGE_MULTICAST_HASH_MAX, + "", + "", + NM_BRIDGE_MULTICAST_HASH_MAX_MIN, + NM_BRIDGE_MULTICAST_HASH_MAX_MAX, + NM_BRIDGE_MULTICAST_HASH_MAX_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-last-member-count: + * + * Set the number of queries the bridge will send before + * stopping forwarding a multicast group after a "leave" + * message has been received. + **/ + /* ---ifcfg-rh--- + * property: multicast-last-member-count + * variable: BRIDGING_OPTS: multicast_last_member_count= + * default: 2 + * example: BRIDGING_OPTS="multicast_last_member_count=4" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_LAST_MEMBER_COUNT] = + g_param_spec_uint(NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_COUNT, + "", + "", + NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_MIN, + NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_MAX, + NM_BRIDGE_MULTICAST_LAST_MEMBER_COUNT_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-last-member-interval: + * + * Set interval (in deciseconds) between queries to find remaining + * members of a group, after a "leave" message is received. + **/ + /* ---ifcfg-rh--- + * property: multicast-last-member-interval + * variable: BRIDGING_OPTS: multicast_last_member_interval= + * default: 100 + * example: BRIDGING_OPTS="multicast_last_member_interval=200" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_LAST_MEMBER_INTERVAL] = g_param_spec_uint64( + NM_SETTING_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL, + "", + "", + NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_MIN, + NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_MAX, + NM_BRIDGE_MULTICAST_LAST_MEMBER_INTERVAL_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-membership-interval: + * + * Set delay (in deciseconds) after which the bridge will + * leave a group, if no membership reports for this + * group are received. + **/ + /* ---ifcfg-rh--- + * property: multicast-membership-interval + * variable: BRIDGING_OPTS: multicast_membership_interval= + * default: 26000 + * example: BRIDGING_OPTS="multicast_membership_interval=16000" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_MEMBERSHIP_INTERVAL] = g_param_spec_uint64( + NM_SETTING_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL, + "", + "", + NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_MIN, + NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_MAX, + NM_BRIDGE_MULTICAST_MEMBERSHIP_INTERVAL_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-querier-interval: + * + * If no queries are seen after this delay (in deciseconds) has passed, + * the bridge will start to send its own queries. + **/ + /* ---ifcfg-rh--- + * property: multicast-querier-interval + * variable: BRIDGING_OPTS: multicast_querier_interval= + * default: 25500 + * example: BRIDGING_OPTS="multicast_querier_interval=20000" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_QUERIER_INTERVAL] = g_param_spec_uint64( + NM_SETTING_BRIDGE_MULTICAST_QUERIER_INTERVAL, + "", + "", + NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_MIN, + NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_MAX, + NM_BRIDGE_MULTICAST_QUERIER_INTERVAL_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-query-interval: + * + * Interval (in deciseconds) between queries sent + * by the bridge after the end of the startup phase. + **/ + /* ---ifcfg-rh--- + * property: multicast-query-interval + * variable: BRIDGING_OPTS: multicast_query_interval= + * default: 12500 + * example: BRIDGING_OPTS="multicast_query_interval=22500" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_QUERY_INTERVAL] = g_param_spec_uint64( + NM_SETTING_BRIDGE_MULTICAST_QUERY_INTERVAL, + "", + "", + NM_BRIDGE_MULTICAST_QUERY_INTERVAL_MIN, + NM_BRIDGE_MULTICAST_QUERY_INTERVAL_MAX, + NM_BRIDGE_MULTICAST_QUERY_INTERVAL_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-query-response-interval: + * + * Set the Max Response Time/Max Response Delay + * (in deciseconds) for IGMP/MLD queries sent by the bridge. + **/ + /* ---ifcfg-rh--- + * property: multicast-query-response-interval + * variable: BRIDGING_OPTS: multicast_query_response_interval= + * default: 1000 + * example: BRIDGING_OPTS="multicast_query_response_interval=2000" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_QUERY_RESPONSE_INTERVAL] = g_param_spec_uint64( + NM_SETTING_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL, + "", + "", + NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_MIN, + NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_MAX, + NM_BRIDGE_MULTICAST_QUERY_RESPONSE_INTERVAL_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-startup-query-count: + * + * Set the number of IGMP queries to send during startup phase. + **/ + /* ---ifcfg-rh--- + * property: multicast-startup-query-count + * variable: BRIDGING_OPTS: multicast_startup_query_count= + * default: 2 + * example: BRIDGING_OPTS="multicast_startup_query_count=4" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_STARTUP_QUERY_COUNT] = + g_param_spec_uint(NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT, + "", + "", + NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_MIN, + NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_MAX, + NM_BRIDGE_MULTICAST_STARTUP_QUERY_COUNT_DEF, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE | G_PARAM_STATIC_STRINGS); + + /** + * NMSettingBridge:multicast-startup-query-interval: + * + * Sets the time (in deciseconds) between queries sent out + * at startup to determine membership information. + **/ + /* ---ifcfg-rh--- + * property: multicast-startup-query-interval + * variable: BRIDGING_OPTS: multicast_startup_query_interval= + * default: 3125 + * example: BRIDGING_OPTS="multicast_startup_query_interval=4000" + * ---end--- + * + * Since: 1.26 + */ + obj_properties[PROP_MULTICAST_STARTUP_QUERY_INTERVAL] = g_param_spec_uint64( + NM_SETTING_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL, + "", + "", + NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_MIN, + NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_MAX, + NM_BRIDGE_MULTICAST_STARTUP_QUERY_INTERVAL_DEF, + 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, + NULL, + properties_override); +} |