diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2019-03-21 16:49:55 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2019-03-26 17:18:29 +0100 |
commit | a680bedf94b98a454e9d4ae085d72edee69dade7 (patch) | |
tree | 99f0da00525581d3ef5eaecc00750517e08cb126 | |
parent | 1e5b0788bcc91e7998dfffda3a116735f90ed239 (diff) |
libnm-core: add vlans property to bridge setting
-rw-r--r-- | clients/common/settings-docs.h.in | 1 | ||||
-rw-r--r-- | libnm-core/nm-connection.c | 13 | ||||
-rw-r--r-- | libnm-core/nm-core-internal.h | 1 | ||||
-rw-r--r-- | libnm-core/nm-setting-bridge.c | 286 | ||||
-rw-r--r-- | libnm-core/nm-setting-bridge.h | 18 | ||||
-rw-r--r-- | libnm/libnm.ver | 6 |
6 files changed, 321 insertions, 4 deletions
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in index 3a66ae73ad..59ca4cc8a6 100644 --- a/clients/common/settings-docs.h.in +++ b/clients/common/settings-docs.h.in @@ -120,6 +120,7 @@ #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_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]]...") #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.") #define DESCRIBE_DOC_NM_SETTING_BRIDGE_PORT_PRIORITY N_("The Spanning Tree Protocol (STP) priority of this bridge port.") diff --git a/libnm-core/nm-connection.c b/libnm-core/nm-connection.c index 312898368e..e91052a35b 100644 --- a/libnm-core/nm-connection.c +++ b/libnm-core/nm-connection.c @@ -1298,6 +1298,18 @@ _normalize_sriov_vf_order (NMConnection *self, GHashTable *parameters) } static gboolean +_normalize_bridge_vlan_order (NMConnection *self, GHashTable *parameters) +{ + NMSettingBridge *s_bridge; + + s_bridge = nm_connection_get_setting_bridge (self); + if (!s_bridge) + return FALSE; + + return _nm_setting_bridge_sort_vlans (s_bridge); +} + +static gboolean _normalize_bridge_port_vlan_order (NMConnection *self, GHashTable *parameters) { NMSettingBridgePort *s_port; @@ -1657,6 +1669,7 @@ nm_connection_normalize (NMConnection *connection, was_modified |= _normalize_ovs_interface_type (connection, parameters); was_modified |= _normalize_ip_tunnel_wired_setting (connection, parameters); was_modified |= _normalize_sriov_vf_order (connection, parameters); + was_modified |= _normalize_bridge_vlan_order (connection, parameters); was_modified |= _normalize_bridge_port_vlan_order (connection, parameters); /* Verify anew. */ diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 3859c2bb40..8510699da4 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -579,6 +579,7 @@ gboolean _nm_utils_dhcp_duid_valid (const char *duid, GBytes **out_duid_bin); gboolean _nm_setting_sriov_sort_vfs (NMSettingSriov *setting); gboolean _nm_setting_bridge_port_sort_vlans (NMSettingBridgePort *setting); +gboolean _nm_setting_bridge_sort_vlans (NMSettingBridge *setting); /*****************************************************************************/ diff --git a/libnm-core/nm-setting-bridge.c b/libnm-core/nm-setting-bridge.c index 26f2fe305d..04a4f8c2ff 100644 --- a/libnm-core/nm-setting-bridge.c +++ b/libnm-core/nm-setting-bridge.c @@ -40,7 +40,7 @@ /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE_BASE ( +NM_GOBJECT_PROPERTIES_DEFINE (NMSettingBridge, PROP_MAC_ADDRESS, PROP_STP, PROP_PRIORITY, @@ -52,6 +52,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE ( PROP_MULTICAST_SNOOPING, PROP_VLAN_FILTERING, PROP_VLAN_DEFAULT_PVID, + PROP_VLANS, ); typedef struct { @@ -66,6 +67,7 @@ typedef struct { gboolean multicast_snooping; gboolean vlan_filtering; guint16 vlan_default_pvid; + GPtrArray *vlans; } NMSettingBridgePrivate; G_DEFINE_TYPE (NMSettingBridge, nm_setting_bridge, NM_TYPE_SETTING) @@ -358,6 +360,43 @@ nm_bridge_vlan_new_clone (const NMBridgeVlan *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: @@ -521,6 +560,153 @@ nm_setting_bridge_get_vlan_default_pvid (NMSettingBridge *setting) 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: the vlan index of the vlan to remove + * + * Removes the vlan vith id @vid. + * + * 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) +{ + NMSettingBridgePrivate *priv; + guint i; + + g_return_val_if_fail (NM_IS_SETTING_BRIDGE (setting), FALSE); + priv = NM_SETTING_BRIDGE_GET_PRIVATE (setting); + + for (i = 0; i < priv->vlans->len; i++) { + if (nm_bridge_vlan_get_vid (priv->vlans->pdata[i]) == vid) { + 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); + } +} + +/*****************************************************************************/ + static gboolean check_range (guint32 val, guint32 min, @@ -599,7 +785,59 @@ verify (NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } - return _nm_connection_verify_required_interface_name (connection, error); + 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; + + /* 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, + NMSetting *setting, + NMSetting *other, + 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 (other) { + priv_a = NM_SETTING_BRIDGE_GET_PRIVATE (setting); + priv_b = NM_SETTING_BRIDGE_GET_PRIVATE (other); + + 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, + setting, + other, + flags); } /*****************************************************************************/ @@ -645,6 +883,11 @@ get_property (GObject *object, guint prop_id, case PROP_VLAN_DEFAULT_PVID: g_value_set_uint (value, priv->vlan_default_pvid); 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; @@ -693,6 +936,12 @@ set_property (GObject *object, guint prop_id, case PROP_VLAN_DEFAULT_PVID: priv->vlan_default_pvid = g_value_get_uint (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; @@ -704,6 +953,9 @@ set_property (GObject *object, guint prop_id, 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); } /** @@ -725,6 +977,7 @@ finalize (GObject *object) NMSettingBridgePrivate *priv = NM_SETTING_BRIDGE_GET_PRIVATE (object); g_free (priv->mac_address); + g_ptr_array_unref (priv->vlans); G_OBJECT_CLASS (nm_setting_bridge_parent_class)->finalize (object); } @@ -742,6 +995,7 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass) object_class->set_property = set_property; object_class->finalize = finalize; + setting_class->compare_property = compare_property; setting_class->verify = verify; /** @@ -1007,6 +1261,34 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass) 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]]... + * + * Since: 1.18 + **/ + 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); + + _properties_override_add_override (properties_override, + obj_properties[PROP_VLANS], + G_VARIANT_TYPE ("aa{sv}"), + _nm_utils_bridge_vlans_to_dbus, + _nm_utils_bridge_vlans_from_dbus, + NULL); + /* ---dbus--- * property: interface-name * format: string diff --git a/libnm-core/nm-setting-bridge.h b/libnm-core/nm-setting-bridge.h index d277675f1a..2afd1bff61 100644 --- a/libnm-core/nm-setting-bridge.h +++ b/libnm-core/nm-setting-bridge.h @@ -50,6 +50,7 @@ G_BEGIN_DECLS #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_BRIDGE_VLAN_VID_MIN 1 #define NM_BRIDGE_VLAN_VID_MAX 4094 @@ -70,6 +71,8 @@ typedef struct { gpointer padding[4]; } NMSettingBridgeClass; +typedef struct _NMBridgeVlan NMBridgeVlan; + GType nm_setting_bridge_get_type (void); NMSetting * nm_setting_bridge_new (void); @@ -95,8 +98,19 @@ NM_AVAILABLE_IN_1_18 gboolean nm_setting_bridge_get_vlan_filtering (NMSettingBridge *setting); NM_AVAILABLE_IN_1_18 guint16 nm_setting_bridge_get_vlan_default_pvid (NMSettingBridge *setting); - -typedef struct _NMBridgeVlan NMBridgeVlan; +NM_AVAILABLE_IN_1_18 +void nm_setting_bridge_add_vlan (NMSettingBridge *setting, + NMBridgeVlan *vlan); +NM_AVAILABLE_IN_1_18 +guint nm_setting_bridge_get_num_vlans (NMSettingBridge *setting); +NM_AVAILABLE_IN_1_18 +NMBridgeVlan *nm_setting_bridge_get_vlan (NMSettingBridge *setting, guint idx); +NM_AVAILABLE_IN_1_18 +void nm_setting_bridge_remove_vlan (NMSettingBridge *setting, guint idx); +NM_AVAILABLE_IN_1_18 +gboolean nm_setting_bridge_remove_vlan_by_vid (NMSettingBridge *setting, guint16 vid); +NM_AVAILABLE_IN_1_18 +void nm_setting_bridge_clear_vlans (NMSettingBridge *setting); NM_AVAILABLE_IN_1_18 GType nm_bridge_vlan_get_type (void); diff --git a/libnm/libnm.ver b/libnm/libnm.ver index 444b10459b..dcf43921dc 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1534,6 +1534,10 @@ global: nm_bridge_vlan_set_pvid; nm_bridge_vlan_set_untagged; nm_bridge_vlan_unref; + nm_setting_bridge_add_vlan; + nm_setting_bridge_clear_vlans; + nm_setting_bridge_get_num_vlans; + nm_setting_bridge_get_vlan; nm_setting_bridge_get_vlan_filtering; nm_setting_bridge_get_vlan_default_pvid; nm_setting_bridge_port_add_vlan; @@ -1542,4 +1546,6 @@ global: nm_setting_bridge_port_get_vlan; nm_setting_bridge_port_remove_vlan; nm_setting_bridge_port_remove_vlan_by_vid; + nm_setting_bridge_remove_vlan; + nm_setting_bridge_remove_vlan_by_vid; } libnm_1_16_0; |