summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2019-03-21 16:49:55 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2019-03-26 17:18:29 +0100
commita680bedf94b98a454e9d4ae085d72edee69dade7 (patch)
tree99f0da00525581d3ef5eaecc00750517e08cb126
parent1e5b0788bcc91e7998dfffda3a116735f90ed239 (diff)
libnm-core: add vlans property to bridge setting
-rw-r--r--clients/common/settings-docs.h.in1
-rw-r--r--libnm-core/nm-connection.c13
-rw-r--r--libnm-core/nm-core-internal.h1
-rw-r--r--libnm-core/nm-setting-bridge.c286
-rw-r--r--libnm-core/nm-setting-bridge.h18
-rw-r--r--libnm/libnm.ver6
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;