libnm-core: add vlans property to bridge setting

This commit is contained in:
Beniamino Galvani 2019-03-21 16:49:55 +01:00
parent 1e5b0788bc
commit a680bedf94
6 changed files with 321 additions and 4 deletions

View file

@ -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.")

View file

@ -1297,6 +1297,18 @@ _normalize_sriov_vf_order (NMConnection *self, GHashTable *parameters)
return _nm_setting_sriov_sort_vfs (s_sriov);
}
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)
{
@ -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. */

View file

@ -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);
/*****************************************************************************/

View file

@ -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

View file

@ -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);

View file

@ -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;