libnm-core: add vlans property to bridge-port setting

This commit is contained in:
Beniamino Galvani
2019-03-16 17:21:35 +01:00
parent 96fab7b462
commit 1e5b0788bc
12 changed files with 825 additions and 3 deletions

View File

@@ -123,6 +123,7 @@
#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.")
#define DESCRIBE_DOC_NM_SETTING_BRIDGE_PORT_VLANS N_("Array of bridge VLAN objects. In addition to the VLANs specified here, the port will also have the default-pvid VLAN configured on the bridge 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_CDMA_MTU N_("If non-zero, only transmit packets of the specified size or smaller, breaking larger packets up into multiple frames.")
#define DESCRIBE_DOC_NM_SETTING_CDMA_NUMBER N_("The number to dial to establish the connection to the CDMA-based mobile broadband network, if any. If not specified, the default number (#777) is used when required.")
#define DESCRIBE_DOC_NM_SETTING_CDMA_PASSWORD N_("The password used to authenticate with the network, if required. Many providers do not require a password, or accept any password. But if a password is required, it is specified here.")

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_port_vlan_order (NMConnection *self, GHashTable *parameters)
{
NMSettingBridgePort *s_port;
s_port = nm_connection_get_setting_bridge_port (self);
if (!s_port)
return FALSE;
return _nm_setting_bridge_port_sort_vlans (s_port);
}
static gboolean
_normalize_required_settings (NMConnection *self, GHashTable *parameters)
{
@@ -1645,6 +1657,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_port_vlan_order (connection, parameters);
/* Verify anew. */
success = _nm_connection_verify (connection, error);

View File

@@ -578,6 +578,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);
/*****************************************************************************/

View File

@@ -42,22 +42,60 @@
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
NM_GOBJECT_PROPERTIES_DEFINE (NMSettingBridgePort,
PROP_PRIORITY,
PROP_PATH_COST,
PROP_HAIRPIN_MODE,
PROP_VLANS,
);
typedef struct {
guint16 priority;
guint16 path_cost;
gboolean hairpin_mode;
GPtrArray *vlans;
} NMSettingBridgePortPrivate;
G_DEFINE_TYPE (NMSettingBridgePort, nm_setting_bridge_port, NM_TYPE_SETTING)
#define NM_SETTING_BRIDGE_PORT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_SETTING_BRIDGE_PORT, NMSettingBridgePortPrivate))
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_port_sort_vlans (NMSettingBridgePort *setting)
{
NMSettingBridgePortPrivate *priv;
gboolean need_sort = FALSE;
guint i;
priv = NM_SETTING_BRIDGE_PORT_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;
}
/*****************************************************************************/
/**
@@ -102,11 +140,160 @@ nm_setting_bridge_port_get_hairpin_mode (NMSettingBridgePort *setting)
return NM_SETTING_BRIDGE_PORT_GET_PRIVATE (setting)->hairpin_mode;
}
/**
* nm_setting_bridge_port_add_vlan:
* @setting: the #NMSettingBridgePort
* @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_port_add_vlan (NMSettingBridgePort *setting,
NMBridgeVlan *vlan)
{
NMSettingBridgePortPrivate *priv;
g_return_if_fail (NM_IS_SETTING_BRIDGE_PORT (setting));
g_return_if_fail (vlan);
priv = NM_SETTING_BRIDGE_PORT_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_port_get_num_vlans:
* @setting: the #NMSettingBridgePort
*
* Returns: the number of VLANs
*
* Since: 1.18
**/
guint
nm_setting_bridge_port_get_num_vlans (NMSettingBridgePort *setting)
{
NMSettingBridgePortPrivate *priv;
g_return_val_if_fail (NM_IS_SETTING_BRIDGE_PORT (setting), 0);
priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (setting);
return priv->vlans->len;
}
/**
* nm_setting_bridge_port_get_vlan:
* @setting: the #NMSettingBridgePort
* @idx: index number of the VLAN to return
*
* Returns: (transfer none): the VLAN at index @idx
*
* Since: 1.18
**/
NMBridgeVlan *
nm_setting_bridge_port_get_vlan (NMSettingBridgePort *setting, guint idx)
{
NMSettingBridgePortPrivate *priv;
g_return_val_if_fail (NM_IS_SETTING_BRIDGE_PORT (setting), NULL);
priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (setting);
g_return_val_if_fail (idx < priv->vlans->len, NULL);
return priv->vlans->pdata[idx];
}
/**
* nm_setting_bridge_port_remove_vlan:
* @setting: the #NMSettingBridgePort
* @idx: index number of the VLAN.
*
* Removes the vlan at index @idx.
*
* Since: 1.18
**/
void
nm_setting_bridge_port_remove_vlan (NMSettingBridgePort *setting, guint idx)
{
NMSettingBridgePortPrivate *priv;
g_return_if_fail (NM_IS_SETTING_BRIDGE_PORT (setting));
priv = NM_SETTING_BRIDGE_PORT_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_port_remove_vlan_by_vid:
* @setting: the #NMSettingBridgePort
* @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_port_remove_vlan_by_vid (NMSettingBridgePort *setting,
guint16 vid)
{
NMSettingBridgePortPrivate *priv;
guint i;
g_return_val_if_fail (NM_IS_SETTING_BRIDGE_PORT (setting), FALSE);
priv = NM_SETTING_BRIDGE_PORT_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_port_clear_vlans:
* @setting: the #NMSettingBridgePort
*
* Removes all configured VLANs.
*
* Since: 1.18
**/
void
nm_setting_bridge_port_clear_vlans (NMSettingBridgePort *setting)
{
NMSettingBridgePortPrivate *priv;
g_return_if_fail (NM_IS_SETTING_BRIDGE_PORT (setting));
priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (setting);
if (priv->vlans->len != 0) {
g_ptr_array_set_size (priv->vlans, 0);
_notify (setting, PROP_VLANS);
}
}
/*****************************************************************************/
static gboolean
verify (NMSetting *setting, NMConnection *connection, GError **error)
{
NMSettingBridgePortPrivate *priv;
priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (setting);
if (connection) {
NMSettingConnection *s_con;
const char *slave_type;
@@ -136,9 +323,58 @@ verify (NMSetting *setting, NMConnection *connection, GError **error)
}
}
if (!_nm_utils_bridge_vlan_verify_list (priv->vlans,
FALSE,
error,
NM_SETTING_BRIDGE_PORT_SETTING_NAME,
NM_SETTING_BRIDGE_PORT_VLANS))
return FALSE;
/* Failures from here on are NORMALIZABLE... */
if (!_nm_utils_bridge_vlan_verify_list (priv->vlans,
TRUE,
error,
NM_SETTING_BRIDGE_PORT_SETTING_NAME,
NM_SETTING_BRIDGE_PORT_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)
{
NMSettingBridgePortPrivate *priv_a;
NMSettingBridgePortPrivate *priv_b;
guint i;
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_BRIDGE_PORT_VLANS)) {
if (other) {
priv_a = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (setting);
priv_b = NM_SETTING_BRIDGE_PORT_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_port_parent_class)->compare_property (sett_info,
property_idx,
setting,
other,
flags);
}
/*****************************************************************************/
static void
@@ -157,6 +393,11 @@ get_property (GObject *object, guint prop_id,
case PROP_HAIRPIN_MODE:
g_value_set_boolean (value, priv->hairpin_mode);
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;
@@ -179,6 +420,12 @@ set_property (GObject *object, guint prop_id,
case PROP_HAIRPIN_MODE:
priv->hairpin_mode = 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;
@@ -190,6 +437,9 @@ set_property (GObject *object, guint prop_id,
static void
nm_setting_bridge_port_init (NMSettingBridgePort *setting)
{
NMSettingBridgePortPrivate *priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (setting);
priv->vlans = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref);
}
/**
@@ -205,17 +455,30 @@ nm_setting_bridge_port_new (void)
return (NMSetting *) g_object_new (NM_TYPE_SETTING_BRIDGE_PORT, NULL);
}
static void
finalize (GObject *object)
{
NMSettingBridgePortPrivate *priv = NM_SETTING_BRIDGE_PORT_GET_PRIVATE (object);
g_ptr_array_unref (priv->vlans);
G_OBJECT_CLASS (nm_setting_bridge_port_parent_class)->finalize (object);
}
static void
nm_setting_bridge_port_class_init (NMSettingBridgePortClass *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 ();
g_type_class_add_private (klass, sizeof (NMSettingBridgePortPrivate));
object_class->finalize = finalize;
object_class->get_property = get_property;
object_class->set_property = set_property;
setting_class->compare_property = compare_property;
setting_class->verify = verify;
/**
@@ -280,7 +543,38 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
NM_SETTING_PARAM_INFERRABLE |
G_PARAM_STATIC_STRINGS);
/**
* NMSettingBridgePort:vlans: (type GPtrArray(NMBridgeVlan))
*
* Array of bridge VLAN objects. In addition to the VLANs
* specified here, the port will also have the default-pvid
* VLAN configured on the bridge 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_PORT_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);
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
_nm_setting_class_commit (setting_class, NM_META_SETTING_TYPE_BRIDGE_PORT);
_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_BRIDGE_PORT,
NULL, properties_override);
}

View File

@@ -27,6 +27,7 @@
#endif
#include "nm-setting.h"
#include "nm-setting-bridge.h"
G_BEGIN_DECLS
@@ -42,6 +43,7 @@ G_BEGIN_DECLS
#define NM_SETTING_BRIDGE_PORT_PRIORITY "priority"
#define NM_SETTING_BRIDGE_PORT_PATH_COST "path-cost"
#define NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE "hairpin-mode"
#define NM_SETTING_BRIDGE_PORT_VLANS "vlans"
/**
* NMSettingBridgePort:
@@ -69,6 +71,20 @@ guint16 nm_setting_bridge_port_get_path_cost (NMSettingBridgePort *settin
gboolean nm_setting_bridge_port_get_hairpin_mode (NMSettingBridgePort *setting);
NM_AVAILABLE_IN_1_18
void nm_setting_bridge_port_add_vlan (NMSettingBridgePort *setting,
NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
guint nm_setting_bridge_port_get_num_vlans (NMSettingBridgePort *setting);
NM_AVAILABLE_IN_1_18
NMBridgeVlan *nm_setting_bridge_port_get_vlan (NMSettingBridgePort *setting, guint idx);
NM_AVAILABLE_IN_1_18
void nm_setting_bridge_port_remove_vlan (NMSettingBridgePort *setting, guint idx);
NM_AVAILABLE_IN_1_18
gboolean nm_setting_bridge_port_remove_vlan_by_vid (NMSettingBridgePort *setting, guint16 vid);
NM_AVAILABLE_IN_1_18
void nm_setting_bridge_port_clear_vlans (NMSettingBridgePort *setting);
G_END_DECLS
#endif /* __NM_SETTING_BRIDGE_PORT_H__ */

View File

@@ -74,6 +74,291 @@ G_DEFINE_TYPE (NMSettingBridge, nm_setting_bridge, NM_TYPE_SETTING)
/*****************************************************************************/
G_DEFINE_BOXED_TYPE (NMBridgeVlan, nm_bridge_vlan, _nm_bridge_vlan_dup, nm_bridge_vlan_unref)
struct _NMBridgeVlan {
guint refcount;
guint16 vid;
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: the VLAN id, must be between 1 and 4094.
*
* Creates a new #NMBridgeVlan object.
*
* Returns: (transfer full): the new #NMBridgeVlan object.
*
* Since: 1.18
**/
NMBridgeVlan *
nm_bridge_vlan_new (guint16 vid)
{
NMBridgeVlan *vlan;
g_return_val_if_fail (vid >= NM_BRIDGE_VLAN_VID_MIN, NULL);
g_return_val_if_fail (vid <= NM_BRIDGE_VLAN_VID_MAX, NULL);
vlan = g_slice_new0 (NMBridgeVlan);
vlan->refcount = 1;
vlan->vid = vid;
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);
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:
* @vlan: the #NMBridgeVlan
*
* Gets the VLAN id of the object.
*
* Returns: the VLAN id
*
* Since: 1.18
**/
guint16
nm_bridge_vlan_get_vid (const NMBridgeVlan *vlan)
{
g_return_val_if_fail (NM_IS_BRIDGE_VLAN (vlan, TRUE), 0);
return vlan->vid;
}
/**
* 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.
*
* Since: 1.18
**/
void
nm_bridge_vlan_set_pvid (NMBridgeVlan *vlan, gboolean value)
{
g_return_if_fail (NM_IS_BRIDGE_VLAN (vlan, FALSE));
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);
copy->untagged = vlan->untagged;
copy->pvid = vlan->pvid;
return copy;
}
/*****************************************************************************/
/**
* nm_setting_bridge_get_mac_address:
* @setting: the #NMSettingBridge
@@ -716,7 +1001,7 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
*/
obj_properties[PROP_VLAN_DEFAULT_PVID] =
g_param_spec_uint (NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID, "", "",
0, 4094, 1,
0, NM_BRIDGE_VLAN_VID_MAX, 1,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT |
NM_SETTING_PARAM_INFERRABLE |

View File

@@ -51,6 +51,9 @@ G_BEGIN_DECLS
#define NM_SETTING_BRIDGE_VLAN_FILTERING "vlan-filtering"
#define NM_SETTING_BRIDGE_VLAN_DEFAULT_PVID "vlan-default-pvid"
#define NM_BRIDGE_VLAN_VID_MIN 1
#define NM_BRIDGE_VLAN_VID_MAX 4094
/**
* NMSettingBridge:
*
@@ -93,6 +96,35 @@ 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
GType nm_bridge_vlan_get_type (void);
NM_AVAILABLE_IN_1_18
NMBridgeVlan * nm_bridge_vlan_new (guint16 vid);
NM_AVAILABLE_IN_1_18
NMBridgeVlan * nm_bridge_vlan_ref (NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
void nm_bridge_vlan_unref (NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
NMBridgeVlan * nm_bridge_vlan_new_clone (const NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
int nm_bridge_vlan_cmp (const NMBridgeVlan *a, const NMBridgeVlan *b);
NM_AVAILABLE_IN_1_18
void nm_bridge_vlan_seal (NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
gboolean nm_bridge_vlan_is_sealed (const NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
void nm_bridge_vlan_set_untagged (NMBridgeVlan *vlan, gboolean value);
NM_AVAILABLE_IN_1_18
void nm_bridge_vlan_set_pvid (NMBridgeVlan *vlan, gboolean value);
NM_AVAILABLE_IN_1_18
guint16 nm_bridge_vlan_get_vid (const NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
gboolean nm_bridge_vlan_is_untagged (const NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
gboolean nm_bridge_vlan_is_pvid (const NMBridgeVlan *vlan);
G_END_DECLS
#endif /* __NM_SETTING_BRIDGE_H__ */

View File

@@ -26,6 +26,7 @@
#endif
#include "nm-setting.h"
#include "nm-setting-bridge.h"
#include "nm-connection.h"
#include "nm-core-enum-types.h"
@@ -204,6 +205,9 @@ gboolean _nm_setting_should_compare_secret_property (NMSetting *setting,
const char *secret_name,
NMSettingCompareFlags flags);
NMBridgeVlan *_nm_bridge_vlan_dup (const NMBridgeVlan *vlan);
NMBridgeVlan *_nm_bridge_vlan_dup_and_seal (const NMBridgeVlan *vlan);
/*****************************************************************************/
#endif /* NM_SETTING_PRIVATE_H */

View File

@@ -103,6 +103,19 @@ void _nm_utils_format_variant_attributes_full (GString *str,
char key_value_separator);
gboolean _nm_sriov_vf_parse_vlans (NMSriovVF *vf, const char *str, GError **error);
GVariant * _nm_utils_bridge_vlans_to_dbus (NMSetting *setting, const char *property);
gboolean _nm_utils_bridge_vlans_from_dbus (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error);
gboolean _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
gboolean check_normalizable,
GError **error,
const char *setting,
const char *property);
/* JSON to GValue conversion macros */
static inline void

View File

@@ -46,6 +46,7 @@
#include "nm-crypto.h"
#include "nm-setting-bond.h"
#include "nm-setting-bridge.h"
#include "nm-setting-bridge-port.h"
#include "nm-setting-infiniband.h"
#include "nm-setting-ip6-config.h"
#include "nm-setting-team.h"
@@ -6710,3 +6711,142 @@ nm_utils_base64secret_normalize (const char *base64_key,
nm_explicit_bzero (buf, required_key_len);
return TRUE;
}
GVariant *
_nm_utils_bridge_vlans_to_dbus (NMSetting *setting, const char *property)
{
gs_unref_ptrarray GPtrArray *vlans = NULL;
GVariantBuilder builder;
guint i;
g_object_get (setting, property, &vlans, NULL);
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
if (vlans) {
for (i = 0; i < vlans->len; i++) {
NMBridgeVlan *vlan = vlans->pdata[i];
GVariantBuilder vlan_builder;
g_variant_builder_init (&vlan_builder, G_VARIANT_TYPE_VARDICT);
g_variant_builder_add (&vlan_builder, "{sv}", "vid",
g_variant_new_uint16 (nm_bridge_vlan_get_vid (vlan)));
g_variant_builder_add (&vlan_builder, "{sv}", "pvid",
g_variant_new_boolean (nm_bridge_vlan_is_pvid (vlan)));
g_variant_builder_add (&vlan_builder, "{sv}", "untagged",
g_variant_new_boolean (nm_bridge_vlan_is_untagged (vlan)));
g_variant_builder_add (&builder, "a{sv}", &vlan_builder);
}
}
return g_variant_builder_end (&builder);
}
gboolean
_nm_utils_bridge_vlans_from_dbus (NMSetting *setting,
GVariant *connection_dict,
const char *property,
GVariant *value,
NMSettingParseFlags parse_flags,
GError **error)
{
gs_unref_ptrarray GPtrArray *vlans = NULL;
GVariantIter vlan_iter;
GVariant *vlan_var;
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), FALSE);
vlans = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref);
g_variant_iter_init (&vlan_iter, value);
while (g_variant_iter_next (&vlan_iter, "@a{sv}", &vlan_var)) {
gs_unref_variant GVariant *var_unref = vlan_var;
NMBridgeVlan *vlan;
guint16 vid;
gboolean pvid = FALSE, untagged = FALSE;
if (!g_variant_lookup (vlan_var, "vid", "q", &vid))
continue;
if ( vid < NM_BRIDGE_VLAN_VID_MIN
|| vid > NM_BRIDGE_VLAN_VID_MAX)
continue;
g_variant_lookup (vlan_var, "pvid", "b", &pvid);
g_variant_lookup (vlan_var, "untagged", "b", &untagged);
vlan = nm_bridge_vlan_new (vid);
nm_bridge_vlan_set_untagged (vlan, untagged);
nm_bridge_vlan_set_pvid (vlan, pvid);
g_ptr_array_add (vlans, vlan);
}
g_object_set (setting, property, vlans, NULL);
return TRUE;
}
gboolean
_nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
gboolean check_normalizable,
GError **error,
const char *setting,
const char *property)
{
guint i;
gs_unref_hashtable GHashTable *h = NULL;
gboolean pvid_found = FALSE;
if (!vlans || !vlans->len)
return TRUE;
if (check_normalizable) {
for (i = 1; i < vlans->len; i++) {
NMBridgeVlan *vlan_prev = vlans->pdata[i - 1];
NMBridgeVlan *vlan = vlans->pdata[i];
if (nm_bridge_vlan_get_vid (vlan_prev) > nm_bridge_vlan_get_vid (vlan)) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("Bridge VLANs %d and %d are not sorted by ascending vid"),
nm_bridge_vlan_get_vid (vlan_prev),
nm_bridge_vlan_get_vid (vlan));
g_prefix_error (error, "%s.%s: ", setting, property);
return FALSE;
}
}
return TRUE;
}
h = g_hash_table_new (nm_direct_hash, NULL);
for (i = 0; i < vlans->len; i++) {
NMBridgeVlan *vlan = vlans->pdata[i];
guint vid;
vid = nm_bridge_vlan_get_vid (vlan);
if (g_hash_table_contains (h, GUINT_TO_POINTER (vid))) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("duplicate bridge VLAN vid %u"), vid);
g_prefix_error (error, "%s.%s: ", setting, property);
return FALSE;
}
if (nm_bridge_vlan_is_pvid (vlan)) {
if (pvid_found) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("only one VLAN can be the PVID"));
g_prefix_error (error, "%s.%s: ", setting, property);
return FALSE;
}
pvid_found = TRUE;
}
g_hash_table_add (h, GUINT_TO_POINTER (vid));
}
return TRUE;
}

View File

@@ -1521,6 +1521,25 @@ global:
libnm_1_18_0 {
global:
nm_bridge_vlan_cmp;
nm_bridge_vlan_get_type;
nm_bridge_vlan_get_vid;
nm_bridge_vlan_is_pvid;
nm_bridge_vlan_is_sealed;
nm_bridge_vlan_is_untagged;
nm_bridge_vlan_new;
nm_bridge_vlan_new_clone;
nm_bridge_vlan_ref;
nm_bridge_vlan_seal;
nm_bridge_vlan_set_pvid;
nm_bridge_vlan_set_untagged;
nm_bridge_vlan_unref;
nm_setting_bridge_get_vlan_filtering;
nm_setting_bridge_get_vlan_default_pvid;
nm_setting_bridge_port_add_vlan;
nm_setting_bridge_port_clear_vlans;
nm_setting_bridge_port_get_num_vlans;
nm_setting_bridge_port_get_vlan;
nm_setting_bridge_port_remove_vlan;
nm_setting_bridge_port_remove_vlan_by_vid;
} libnm_1_16_0;

View File

@@ -20,6 +20,7 @@
/****************************************************************************/
#include "nm-setting-bridge.h"
#include "nm-setting-connection.h"
#include "nm-setting-ip-config.h"
#include "nm-setting-ip4-config.h"
@@ -46,6 +47,9 @@ NM_AUTO_DEFINE_FCN0 (NMTCQdisc *, _nm_auto_unref_tc_qdisc, nm_tc_qdisc_unref)
#define nm_auto_unref_tc_tfilter nm_auto (_nm_auto_unref_tc_tfilter)
NM_AUTO_DEFINE_FCN0 (NMTCTfilter *, _nm_auto_unref_tc_tfilter, nm_tc_tfilter_unref)
#define nm_auto_unref_bridge_vlan nm_auto (_nm_auto_unref_bridge_vlan)
NM_AUTO_DEFINE_FCN0 (NMBridgeVlan *, _nm_auto_unref_bridge_vlan, nm_bridge_vlan_unref)
#define nm_auto_unref_team_link_watcher nm_auto (_nm_auto_unref_team_link_watcher)
NM_AUTO_DEFINE_FCN0 (NMTeamLinkWatcher *, _nm_auto_unref_team_link_watcher, nm_team_link_watcher_unref)