bridge: merge branch 'bg/bridge-vlan-ranges'

In some cases it is convenient to specify ranges of bridge vlans, as
already supported by iproute2 and natively by kernel.

https://bugzilla.redhat.com/show_bug.cgi?id=1652910
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/114
This commit is contained in:
Beniamino Galvani 2019-04-18 09:39:51 +02:00
commit 693252d049
19 changed files with 342 additions and 185 deletions

View file

@ -167,8 +167,8 @@ _value_str_as_index_list (const char *value, gsize *out_len)
#define MULTILIST_WITH_ESCAPE_CHARS NM_ASCII_SPACES","
#define ESCAPED_TOKENS_DELIMTER ','
#define ESCAPED_TOKENS_DELIMTERS ","
#define ESCAPED_TOKENS_DELIMITER ','
#define ESCAPED_TOKENS_DELIMITERS ","
typedef enum {
VALUE_STRSPLIT_MODE_STRIPPED,
@ -216,7 +216,7 @@ _value_strsplit (const char *value,
strv = nm_utils_strsplit_set_full (value, MULTILIST_WITH_ESCAPE_CHARS, NM_UTILS_STRSPLIT_SET_FLAGS_ALLOW_ESCAPING);
break;
case VALUE_STRSPLIT_MODE_ESCAPED_TOKENS:
strv = nm_utils_escaped_tokens_split (value, ESCAPED_TOKENS_DELIMTERS);
strv = nm_utils_escaped_tokens_split (value, ESCAPED_TOKENS_DELIMITERS);
NM_SET_OUT (out_len, NM_PTRARRAY_LEN (strv));
return g_steal_pointer (&strv);
default:
@ -3072,7 +3072,7 @@ _get_fcn_objlist (ARGS_GET_FCN)
&& property_info->property_typ_data->subtype.objlist.delimit_pretty_with_semicolon)
g_string_append (str, "; ");
else {
G_STATIC_ASSERT_EXPR (ESCAPED_TOKENS_DELIMTER == ',');
G_STATIC_ASSERT_EXPR (ESCAPED_TOKENS_DELIMITER == ',');
g_string_append (str, ", ");
}
}
@ -3400,7 +3400,7 @@ _objlist_obj_to_str_fcn_ip_config_routing_rules (NMMetaAccessorGetType get_type,
NULL,
NULL);
if (s)
nm_utils_escaped_tokens_escape_gstr (s, ESCAPED_TOKENS_DELIMTERS, str);
nm_utils_escaped_tokens_escape_gstr (s, ESCAPED_TOKENS_DELIMITERS, str);
}
static gboolean
@ -3559,7 +3559,7 @@ _objlist_obj_to_str_fcn_bridge_vlans (NMMetaAccessorGetType get_type,
s = nm_bridge_vlan_to_str (vlan, NULL);
if (s)
g_string_append (str, s);
nm_utils_escaped_tokens_escape_gstr_assert (s, ESCAPED_TOKENS_DELIMITERS, str);
}
static gboolean
@ -3618,13 +3618,14 @@ _objlist_set_fcn_bridge_vlans (NMSetting *setting,
{
nm_auto_unref_bridge_vlan NMBridgeVlan *vlan = NULL;
gs_free_error GError *local = NULL;
guint16 vid_start, vid_end;
vlan = nm_bridge_vlan_from_str (value, &local);
if (!vlan) {
nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT,
"%s. %s",
local->message,
_("The valid syntax is: '<vid> [pvid] [untagged]"));
_("The valid syntax is: '<vid>[-<vid>] [pvid] [untagged]'"));
return FALSE;
}
@ -3632,15 +3633,18 @@ _objlist_set_fcn_bridge_vlans (NMSetting *setting,
if (do_add)
nm_setting_bridge_add_vlan (NM_SETTING_BRIDGE (setting), vlan);
else {
nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
nm_setting_bridge_remove_vlan_by_vid (NM_SETTING_BRIDGE (setting),
nm_bridge_vlan_get_vid (vlan));
vid_start, vid_end);
}
} else {
if (do_add)
nm_setting_bridge_port_add_vlan (NM_SETTING_BRIDGE_PORT (setting), vlan);
else {
nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
nm_setting_bridge_port_remove_vlan_by_vid (NM_SETTING_BRIDGE_PORT (setting),
nm_bridge_vlan_get_vid (vlan));
vid_start,
vid_end);
}
}
@ -4987,6 +4991,7 @@ static const NMMetaPropertyInfo *const property_infos_BRIDGE[] = {
.clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingBridge, nm_setting_bridge_clear_vlans),
.obj_to_str_fcn = _objlist_obj_to_str_fcn_bridge_vlans,
.set_fcn = _objlist_set_fcn_bridge_vlans,
.strsplit_escaped_tokens = TRUE,
),
),
),
@ -5022,6 +5027,7 @@ static const NMMetaPropertyInfo *const property_infos_BRIDGE_PORT[] = {
.clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingBridgePort, nm_setting_bridge_port_clear_vlans),
.obj_to_str_fcn = _objlist_obj_to_str_fcn_bridge_vlans,
.set_fcn = _objlist_set_fcn_bridge_vlans,
.strsplit_escaped_tokens = TRUE,
),
),
),

View file

@ -120,11 +120,11 @@
#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_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]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash.")
#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_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]]... where $vid is either a single id between 1 and 4094 or a range, represented as a couple of ids separated by a dash.")
#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

@ -1626,51 +1626,37 @@ team_config_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key
static void
bridge_vlan_parser (KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
const char *setting_name = nm_setting_get_name (setting);
gs_unref_ptrarray GPtrArray *vlans = NULL;
gs_strfreev char **keys = NULL;
gsize n_keys = 0;
int i;
gs_free char *value = NULL;
gs_free const char **strv = NULL;
const char *const *iter;
GError *local = NULL;
NMBridgeVlan *vlan;
keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
if (n_keys == 0)
value = nm_keyfile_plugin_kf_get_string (info->keyfile,
nm_setting_get_name (setting),
key,
NULL);
if (!value || !value[0])
return;
vlans = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref);
for (i = 0; i < n_keys; i++) {
NMBridgeVlan *vlan;
const char *index;
gs_free char *vlan_rest = NULL;
gs_free char *vlan_str = NULL;
gs_free_error GError *err = NULL;
if (!g_str_has_prefix (keys[i], "vlan."))
continue;
index = keys[i] + NM_STRLEN("vlan.");
if (index[0] == '\0')
continue;
if (index[0] == '0' && index[1] != '\0')
continue;
if (!NM_STRCHAR_ALL (index, ch, g_ascii_isdigit (ch)))
continue;
vlan_rest = nm_keyfile_plugin_kf_get_string (info->keyfile, setting_name, keys[i], NULL);
vlan_str = g_strdup_printf ("%s %s", index, vlan_rest);
vlan = nm_bridge_vlan_from_str (vlan_str, &err);
if (!vlan) {
handle_warn (info, keys[i], NM_KEYFILE_WARN_SEVERITY_WARN,
_("invalid bridge vlan: %s"),
err->message);
continue;
strv = nm_utils_escaped_tokens_split (value, ",");
if (strv) {
for (iter = strv; *iter; iter++) {
vlan = nm_bridge_vlan_from_str (*iter, &local);
if (!vlan) {
handle_warn (info, key, NM_KEYFILE_WARN_SEVERITY_WARN,
"invalid bridge VLAN: %s", local->message);
g_clear_error (&local);
continue;
}
g_ptr_array_add (vlans, vlan);
}
g_ptr_array_add (vlans, vlan);
}
if (vlans->len >= 1)
if (vlans->len > 0)
g_object_set (setting, key, vlans, NULL);
}
@ -2004,26 +1990,34 @@ bridge_vlan_writer (KeyfileWriterInfo *info,
const char *key,
const GValue *value)
{
gsize i;
GPtrArray *array;
nm_auto_free_gstring GString *value_str = NULL;
NMBridgeVlan *vlan;
GPtrArray *vlans;
GString *string;
guint i;
array = (GPtrArray *) g_value_get_boxed (value);
if (!array || !array->len)
vlans = (GPtrArray *) g_value_get_boxed (value);
if (!vlans || !vlans->len)
return;
for (i = 0; i < array->len; i++) {
NMBridgeVlan *vlan = array->pdata[i];
char key_name[32];
string = g_string_new ("");
for (i = 0; i < vlans->len; i++) {
gs_free char *vlan_str = NULL;
nm_sprintf_buf (key_name, "vlan.%u", nm_bridge_vlan_get_vid (vlan));
nm_gstring_prepare (&value_str);
_nm_bridge_vlan_str_append_rest (vlan, value_str, FALSE);
nm_keyfile_plugin_kf_set_string (info->keyfile,
nm_setting_get_name (setting),
key_name,
value_str->str);
vlan = vlans->pdata[i];
vlan_str = nm_bridge_vlan_to_str (vlan, NULL);
if (!vlan_str)
continue;
if (string->len > 0)
g_string_append (string, ",");
nm_utils_escaped_tokens_escape_gstr_assert (vlan_str, ",", string);
}
nm_keyfile_plugin_kf_set_string (info->keyfile,
nm_setting_get_name (setting),
"vlans",
string->str);
g_string_free (string, TRUE);
}
static void

View file

@ -235,9 +235,12 @@ nm_setting_bridge_port_remove_vlan (NMSettingBridgePort *setting, guint idx)
/**
* nm_setting_bridge_port_remove_vlan_by_vid:
* @setting: the #NMSettingBridgePort
* @vid: the vlan index of the vlan to remove
* @vid_start: the vlan start index
* @vid_end: the vlan end index
*
* Removes the vlan vith id @vid.
* 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
*
@ -245,16 +248,24 @@ nm_setting_bridge_port_remove_vlan (NMSettingBridgePort *setting, guint idx)
**/
gboolean
nm_setting_bridge_port_remove_vlan_by_vid (NMSettingBridgePort *setting,
guint16 vid)
guint16 vid_start,
guint16 vid_end)
{
NMSettingBridgePortPrivate *priv;
guint16 v_start, v_end;
NMBridgeVlan *vlan;
guint i;
if (vid_end == 0)
vid_end = vid_start;
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) {
vlan = (NMBridgeVlan *) priv->vlans->pdata[i];
nm_bridge_vlan_get_vid_range (vlan, &v_start, &v_end);
if (v_start == vid_start && v_end == vid_end) {
g_ptr_array_remove_index (priv->vlans, i);
_notify (setting, PROP_VLANS);
return TRUE;
@ -556,13 +567,16 @@ nm_setting_bridge_port_class_init (NMSettingBridgePortClass *klass)
*
* $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_PORT_VLANS
* description: List of VLANs on the bridge port
* example: BRIDGE_PORT_VLANS="1 pvid untagged,20,40 untagged"
* example: BRIDGE_PORT_VLANS="1 pvid untagged,20,300-400 untagged"
* ---end---
*/
obj_properties[PROP_VLANS] =

View file

@ -81,7 +81,9 @@ NMBridgeVlan *nm_setting_bridge_port_get_vlan (NMSettingBridgePort *setting, gui
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);
gboolean nm_setting_bridge_port_remove_vlan_by_vid (NMSettingBridgePort *setting,
guint16 vid_start,
guint16 vid_end);
NM_AVAILABLE_IN_1_18
void nm_setting_bridge_port_clear_vlans (NMSettingBridgePort *setting);

View file

@ -80,7 +80,8 @@ G_DEFINE_BOXED_TYPE (NMBridgeVlan, nm_bridge_vlan, _nm_bridge_vlan_dup, nm_bridg
struct _NMBridgeVlan {
guint refcount;
guint16 vid;
guint16 vid_start;
guint16 vid_end;
bool untagged:1;
bool pvid:1;
bool sealed:1;
@ -96,25 +97,33 @@ NM_IS_BRIDGE_VLAN (const NMBridgeVlan *self, gboolean also_sealed)
/**
* nm_bridge_vlan_new:
* @vid: the VLAN id, must be between 1 and 4094.
* @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.
* 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)
nm_bridge_vlan_new (guint16 vid_start, guint16 vid_end)
{
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);
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 = vid;
vlan->vid_start = vid_start;
vlan->vid_end = vid_end;
return vlan;
}
@ -179,7 +188,8 @@ nm_bridge_vlan_cmp (const NMBridgeVlan *a, const NMBridgeVlan *b)
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 (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);
@ -213,21 +223,29 @@ _nm_bridge_vlan_dup_and_seal (const NMBridgeVlan *vlan)
}
/**
* nm_bridge_vlan_get_vid:
* nm_bridge_vlan_get_vid_range:
* @vlan: the #NMBridgeVlan
* @vid_start: location to store the VLAN id range start.
* @vid_end: location to store the VLAN id range end
*
* Gets the VLAN id of the object.
* Gets the VLAN id range.
*
* Returns: the VLAN id
* Returns: %TRUE is the VLAN specifies a range, %FALSE if it is
* a single-id VLAN.
*
* Since: 1.18
**/
guint16
nm_bridge_vlan_get_vid (const NMBridgeVlan *vlan)
gboolean
nm_bridge_vlan_get_vid_range (const NMBridgeVlan *vlan,
guint16 *vid_start,
guint16 *vid_end)
{
g_return_val_if_fail (NM_IS_BRIDGE_VLAN (vlan, TRUE), 0);
return vlan->vid;
NM_SET_OUT (vid_start, vlan->vid_start);
NM_SET_OUT (vid_end, vlan->vid_end);
return vlan->vid_start != vlan->vid_end;
}
/**
@ -288,7 +306,9 @@ nm_bridge_vlan_set_untagged (NMBridgeVlan *vlan, gboolean value)
* @vlan: the #NMBridgeVlan
* @value: the new value
*
* Change the value of the PVID property of the VLAN.
* 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
**/
@ -296,6 +316,7 @@ 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;
}
@ -351,7 +372,7 @@ nm_bridge_vlan_new_clone (const NMBridgeVlan *vlan)
g_return_val_if_fail (NM_IS_BRIDGE_VLAN (vlan, TRUE), NULL);
copy = nm_bridge_vlan_new (vlan->vid);
copy = nm_bridge_vlan_new (vlan->vid_start, vlan->vid_end);
copy->untagged = vlan->untagged;
copy->pvid = vlan->pvid;
@ -400,9 +421,13 @@ nm_bridge_vlan_to_str (const NMBridgeVlan *vlan, GError **error)
* future if more parameters are added to the object that could
* make it invalid. */
string = g_string_sized_new (20);
string = g_string_sized_new (28);
if (vlan->vid_start == vlan->vid_end)
g_string_append_printf (string, "%u", vlan->vid_start);
else
g_string_append_printf (string, "%u-%u", vlan->vid_start, vlan->vid_end);
g_string_append_printf (string, "%u", nm_bridge_vlan_get_vid (vlan));
_nm_bridge_vlan_str_append_rest (vlan, string, TRUE);
return g_string_free (string, FALSE);
@ -425,14 +450,15 @@ nm_bridge_vlan_from_str (const char *str, GError **error)
{
NMBridgeVlan *vlan = NULL;
gs_free const char **tokens = NULL;
guint i, vid;
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_strsplit_set (str, " ");
tokens = nm_utils_escaped_tokens_split (str, NM_ASCII_SPACES);
if (!tokens || !tokens[0]) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
@ -441,23 +467,58 @@ nm_bridge_vlan_from_str (const char *str, GError **error)
return NULL;
}
vid = _nm_utils_ascii_str_to_uint64 (tokens[0],
10,
NM_BRIDGE_VLAN_VID_MIN,
NM_BRIDGE_VLAN_VID_MAX,
G_MAXUINT);
if (vid == G_MAXUINT) {
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 '%s', must be in [1,4094]", tokens[0]);
"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 (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"))
} else if (nm_streq (tokens[i], "untagged"))
untagged = TRUE;
else {
g_set_error (error,
@ -468,7 +529,7 @@ nm_bridge_vlan_from_str (const char *str, GError **error)
}
}
vlan = nm_bridge_vlan_new (vid);
vlan = nm_bridge_vlan_new (vid_start, vid_end);
nm_bridge_vlan_set_pvid (vlan, pvid);
nm_bridge_vlan_set_untagged (vlan, untagged);
@ -772,9 +833,12 @@ nm_setting_bridge_remove_vlan (NMSettingBridge *setting, guint idx)
/**
* nm_setting_bridge_remove_vlan_by_vid:
* @setting: the #NMSettingBridge
* @vid: the vlan index of the vlan to remove
* @vid_start: the vlan start index
* @vid_end: the vlan end index
*
* Removes the vlan vith id @vid.
* 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
*
@ -782,16 +846,22 @@ nm_setting_bridge_remove_vlan (NMSettingBridge *setting, guint idx)
**/
gboolean
nm_setting_bridge_remove_vlan_by_vid (NMSettingBridge *setting,
guint16 vid)
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++) {
if (nm_bridge_vlan_get_vid (priv->vlans->pdata[i]) == vid) {
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;
@ -1390,13 +1460,16 @@ nm_setting_bridge_class_init (NMSettingBridgeClass *klass)
*
* $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,40 untagged"
* example: BRIDGE_VLANS="1 pvid untagged,20,300-400 untagged"
* ---end---
*/
obj_properties[PROP_VLANS] =

View file

@ -108,14 +108,16 @@ 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);
gboolean nm_setting_bridge_remove_vlan_by_vid (NMSettingBridge *setting,
guint16 vid_start,
guint16 vid_end);
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);
NM_AVAILABLE_IN_1_18
NMBridgeVlan * nm_bridge_vlan_new (guint16 vid);
NMBridgeVlan * nm_bridge_vlan_new (guint16 vid_start, guint16 vid_end);
NM_AVAILABLE_IN_1_18
NMBridgeVlan * nm_bridge_vlan_ref (NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18
@ -133,7 +135,7 @@ 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);
gboolean nm_bridge_vlan_get_vid_range (const NMBridgeVlan *vlan, guint16 *vid_start, guint16 *vid_end);
NM_AVAILABLE_IN_1_18
gboolean nm_bridge_vlan_is_untagged (const NMBridgeVlan *vlan);
NM_AVAILABLE_IN_1_18

View file

@ -6800,10 +6800,15 @@ _nm_utils_bridge_vlans_to_dbus (NMSetting *setting, const char *property)
for (i = 0; i < vlans->len; i++) {
NMBridgeVlan *vlan = vlans->pdata[i];
GVariantBuilder vlan_builder;
guint16 vid_start, vid_end;
nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
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}", "vid-start",
g_variant_new_uint16 (vid_start));
g_variant_builder_add (&vlan_builder, "{sv}", "vid-end",
g_variant_new_uint16 (vid_end));
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",
@ -6834,19 +6839,29 @@ _nm_utils_bridge_vlans_from_dbus (NMSetting *setting,
while (g_variant_iter_next (&vlan_iter, "@a{sv}", &vlan_var)) {
_nm_unused gs_unref_variant GVariant *var_unref = vlan_var;
NMBridgeVlan *vlan;
guint16 vid;
guint16 vid_start, vid_end;
gboolean pvid = FALSE, untagged = FALSE;
if (!g_variant_lookup (vlan_var, "vid", "q", &vid))
if (!g_variant_lookup (vlan_var, "vid-start", "q", &vid_start))
continue;
if ( vid < NM_BRIDGE_VLAN_VID_MIN
|| vid > NM_BRIDGE_VLAN_VID_MAX)
if ( vid_start < NM_BRIDGE_VLAN_VID_MIN
|| vid_start > NM_BRIDGE_VLAN_VID_MAX)
continue;
if (!g_variant_lookup (vlan_var, "vid-end", "q", &vid_end))
continue;
if ( vid_end < NM_BRIDGE_VLAN_VID_MIN
|| vid_end > NM_BRIDGE_VLAN_VID_MAX)
continue;
if (vid_start > vid_end)
continue;
g_variant_lookup (vlan_var, "pvid", "b", &pvid);
if (pvid && vid_start != vid_end)
continue;
g_variant_lookup (vlan_var, "untagged", "b", &untagged);
vlan = nm_bridge_vlan_new (vid);
vlan = nm_bridge_vlan_new (vid_start, vid_end);
nm_bridge_vlan_set_untagged (vlan, untagged);
nm_bridge_vlan_set_pvid (vlan, pvid);
g_ptr_array_add (vlans, vlan);
@ -6868,24 +6883,33 @@ _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
gs_unref_hashtable GHashTable *h = NULL;
gboolean pvid_found = FALSE;
if (!vlans || !vlans->len)
if ( !vlans
|| vlans->len <= 1)
return TRUE;
if (check_normalizable) {
for (i = 1; i < vlans->len; i++) {
NMBridgeVlan *vlan_prev = vlans->pdata[i - 1];
NMBridgeVlan *vlan = vlans->pdata[i];
guint16 vid_prev_end, vid_start, vid_end;
if (nm_bridge_vlan_get_vid (vlan_prev) > nm_bridge_vlan_get_vid (vlan)) {
nm_assert (_nm_utils_bridge_vlan_verify_list (vlans, FALSE, NULL, setting, property));
nm_bridge_vlan_get_vid_range (vlans->pdata[0], NULL, &vid_prev_end);
for (i = 1; i < vlans->len; i++) {
const NMBridgeVlan *vlan = vlans->pdata[i];
nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
if (vid_prev_end > vid_start) {
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));
vid_prev_end,
vid_start);
g_prefix_error (error, "%s.%s: ", setting, property);
return FALSE;
}
vid_prev_end = vid_end;
}
return TRUE;
}
@ -6893,21 +6917,24 @@ _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
h = g_hash_table_new (nm_direct_hash, NULL);
for (i = 0; i < vlans->len; i++) {
NMBridgeVlan *vlan = vlans->pdata[i];
guint vid;
guint16 v, vid_start, vid_end;
vid = nm_bridge_vlan_get_vid (vlan);
nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
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;
for (v = vid_start; v <= vid_end; v++) {
if (!nm_g_hash_table_add (h, GUINT_TO_POINTER (v))) {
g_set_error (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
_("duplicate bridge VLAN vid %u"), v);
g_prefix_error (error, "%s.%s: ", setting, property);
return FALSE;
}
}
if (nm_bridge_vlan_is_pvid (vlan)) {
if (pvid_found) {
if ( vid_start != vid_end
|| pvid_found) {
g_set_error_literal (error,
NM_CONNECTION_ERROR,
NM_CONNECTION_ERROR_INVALID_PROPERTY,
@ -6917,8 +6944,6 @@ _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
}
pvid_found = TRUE;
}
g_hash_table_add (h, GUINT_TO_POINTER (vid));
}
return TRUE;

View file

@ -751,6 +751,7 @@ test_bridge_vlans (void)
gs_unref_object NMConnection *con = NULL;
NMSettingBridge *s_bridge;
NMBridgeVlan *vlan;
guint16 vid, vid_end;
con = nmtst_create_connection_from_keyfile (
"[connection]\n"
@ -759,26 +760,37 @@ test_bridge_vlans (void)
"interface-name=br4\n"
"\n"
"[bridge]\n"
"vlan.9=untagged\n"
"vlan.1=pvid untagged\n"
"vlans=900 , 1 pvid untagged, 100-123 untagged\n"
"",
"/test_bridge_port/vlans");
s_bridge = NM_SETTING_BRIDGE (nm_connection_get_setting (con, NM_TYPE_SETTING_BRIDGE));
g_assert (s_bridge);
g_assert_cmpuint (nm_setting_bridge_get_num_vlans (s_bridge), ==, 2);
g_assert_cmpuint (nm_setting_bridge_get_num_vlans (s_bridge), ==, 3);
vlan = nm_setting_bridge_get_vlan (s_bridge, 0);
g_assert (vlan);
g_assert_cmpuint (nm_bridge_vlan_get_vid (vlan), ==, 1);
nm_bridge_vlan_get_vid_range (vlan, &vid, &vid_end);
g_assert_cmpuint (vid, ==, 1);
g_assert_cmpuint (vid_end, ==, 1);
g_assert_cmpint (nm_bridge_vlan_is_pvid (vlan), ==, TRUE);
g_assert_cmpint (nm_bridge_vlan_is_untagged (vlan), ==, TRUE);
vlan = nm_setting_bridge_get_vlan (s_bridge, 1);
g_assert (vlan);
g_assert_cmpuint (nm_bridge_vlan_get_vid (vlan), ==, 9);
nm_bridge_vlan_get_vid_range (vlan, &vid, &vid_end);
g_assert_cmpuint (vid, ==, 100);
g_assert_cmpuint (vid_end, ==, 123);
g_assert_cmpint (nm_bridge_vlan_is_pvid (vlan), ==, FALSE);
g_assert_cmpint (nm_bridge_vlan_is_untagged (vlan), ==, TRUE);
vlan = nm_setting_bridge_get_vlan (s_bridge, 2);
g_assert (vlan);
nm_bridge_vlan_get_vid_range (vlan, &vid, &vid_end);
g_assert_cmpuint (vid, ==, 900);
g_assert_cmpuint (vid_end, ==, 900);
g_assert_cmpint (nm_bridge_vlan_is_pvid (vlan), ==, FALSE);
g_assert_cmpint (nm_bridge_vlan_is_untagged (vlan), ==, FALSE);
CLEAR (&con, &keyfile);
}
@ -789,6 +801,7 @@ test_bridge_port_vlans (void)
gs_unref_object NMConnection *con = NULL;
NMSettingBridgePort *s_port;
NMBridgeVlan *vlan;
guint16 vid_start, vid_end;
con = nmtst_create_connection_from_keyfile (
"[connection]\n"
@ -799,31 +812,27 @@ test_bridge_port_vlans (void)
"slave-type=bridge\n"
"\n"
"[bridge-port]\n"
"vlan.4000=\n"
"vlan.10=untagged\n"
"vlan.20=pvid untagged"
"vlans=4094 pvid , 10-20 untagged\n"
"",
"/test_bridge_port/vlans");
s_port = NM_SETTING_BRIDGE_PORT (nm_connection_get_setting (con, NM_TYPE_SETTING_BRIDGE_PORT));
g_assert (s_port);
g_assert_cmpuint (nm_setting_bridge_port_get_num_vlans (s_port), ==, 3);
g_assert_cmpuint (nm_setting_bridge_port_get_num_vlans (s_port), ==, 2);
vlan = nm_setting_bridge_port_get_vlan (s_port, 0);
g_assert (vlan);
g_assert_cmpuint (nm_bridge_vlan_get_vid (vlan), ==, 10);
nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
g_assert_cmpuint (vid_start, ==, 10);
g_assert_cmpuint (vid_end, ==, 20);
g_assert_cmpint (nm_bridge_vlan_is_pvid (vlan), ==, FALSE);
g_assert_cmpint (nm_bridge_vlan_is_untagged (vlan), ==, TRUE);
vlan = nm_setting_bridge_port_get_vlan (s_port, 1);
g_assert (vlan);
g_assert_cmpuint (nm_bridge_vlan_get_vid (vlan), ==, 20);
nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
g_assert_cmpuint (vid_start, ==, 4094);
g_assert_cmpuint (vid_end, ==, 4094);
g_assert_cmpint (nm_bridge_vlan_is_pvid (vlan), ==, TRUE);
g_assert_cmpint (nm_bridge_vlan_is_untagged (vlan), ==, TRUE);
vlan = nm_setting_bridge_port_get_vlan (s_port, 2);
g_assert (vlan);
g_assert_cmpuint (nm_bridge_vlan_get_vid (vlan), ==, 4000);
g_assert_cmpint (nm_bridge_vlan_is_pvid (vlan), ==, FALSE);
g_assert_cmpint (nm_bridge_vlan_is_untagged (vlan), ==, FALSE);
CLEAR (&con, &keyfile);

View file

@ -1664,6 +1664,7 @@ test_bridge_vlans (void)
{
NMBridgeVlan *v1, *v2;
GError *error = NULL;
guint16 vid_start, vid_end;
char *str;
v1 = nm_bridge_vlan_from_str ("1 foobar", &error);
@ -1674,11 +1675,23 @@ test_bridge_vlans (void)
nmtst_assert_no_success (v1, error);
g_clear_error (&error);
/* test ranges */
v1 = nm_bridge_vlan_from_str ("2-1000 untagged", &error);
nmtst_assert_success (v1, error);
g_assert_cmpint (nm_bridge_vlan_get_vid_range (v1, &vid_start, &vid_end), ==, TRUE);
g_assert_cmpuint (vid_start, ==, 2);
g_assert_cmpuint (vid_end, ==, 1000);
g_assert_cmpint (nm_bridge_vlan_is_pvid (v1), ==, FALSE);
g_assert_cmpint (nm_bridge_vlan_is_untagged (v1), ==, TRUE);
nm_bridge_vlan_unref (v1);
/* test comparison (1) */
v1 = nm_bridge_vlan_from_str ("10 untagged", &error);
nmtst_assert_success (v1, error);
g_assert_cmpuint (nm_bridge_vlan_get_vid (v1), ==, 10);
g_assert_cmpint (nm_bridge_vlan_get_vid_range (v1, &vid_start, &vid_end), ==, FALSE);
g_assert_cmpuint (vid_start, ==, 10);
g_assert_cmpuint (vid_end, ==, 10);
g_assert_cmpint (nm_bridge_vlan_is_sealed (v1), ==, FALSE);
g_assert_cmpint (nm_bridge_vlan_is_pvid (v1), ==, FALSE);
g_assert_cmpint (nm_bridge_vlan_is_untagged (v1), ==, TRUE);

View file

@ -1524,7 +1524,7 @@ global:
nm_bridge_vlan_cmp;
nm_bridge_vlan_from_str;
nm_bridge_vlan_get_type;
nm_bridge_vlan_get_vid;
nm_bridge_vlan_get_vid_range;
nm_bridge_vlan_is_pvid;
nm_bridge_vlan_is_sealed;
nm_bridge_vlan_is_untagged;

View file

@ -268,31 +268,37 @@ commit_option (NMDevice *device, NMSetting *setting, const Option *option, gbool
nm_platform_sysctl_master_set_option (nm_device_get_platform (device), ifindex, option->sysname, value);
}
static NMPlatformBridgeVlan **
static const NMPlatformBridgeVlan **
setting_vlans_to_platform (GPtrArray *array)
{
GPtrArray *plat_vlans;
NMPlatformBridgeVlan **arr;
NMPlatformBridgeVlan *p_data;
guint i;
if (!array || !array->len)
return NULL;
plat_vlans = g_ptr_array_sized_new (array->len + 1);
G_STATIC_ASSERT_EXPR (_nm_alignof (NMPlatformBridgeVlan *) >= _nm_alignof (NMPlatformBridgeVlan));
arr = g_malloc ( (sizeof (NMPlatformBridgeVlan *) * (array->len + 1))
+ (sizeof (NMPlatformBridgeVlan ) * (array->len )));
p_data = (NMPlatformBridgeVlan *) &arr[array->len + 1];
for (i = 0; i < array->len; i++) {
NMBridgeVlan *vlan = array->pdata[i];
NMPlatformBridgeVlan *plat_vlan;
guint16 vid_start, vid_end;
plat_vlan = g_new0 (NMPlatformBridgeVlan, 1);
plat_vlan->vid = nm_bridge_vlan_get_vid (vlan);
plat_vlan->pvid = nm_bridge_vlan_is_pvid (vlan);
plat_vlan->untagged = nm_bridge_vlan_is_untagged (vlan);
nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
g_ptr_array_add (plat_vlans, plat_vlan);
p_data[i] = (NMPlatformBridgeVlan) {
.vid_start = vid_start,
.vid_end = vid_end,
.pvid = nm_bridge_vlan_is_pvid (vlan),
.untagged = nm_bridge_vlan_is_untagged (vlan),
};
arr[i] = &p_data[i];
}
g_ptr_array_add (plat_vlans, NULL);
return (NMPlatformBridgeVlan **) g_ptr_array_free (plat_vlans, FALSE);
arr[i] = NULL;
return (const NMPlatformBridgeVlan **) arr;
}
static void
@ -424,7 +430,7 @@ bridge_set_vlan_options (NMDevice *device, NMSettingBridge *s_bridge)
NMPlatform *plat;
int ifindex;
gs_unref_ptrarray GPtrArray *vlans = NULL;
nm_auto_freev NMPlatformBridgeVlan **plat_vlans = NULL;
gs_free const NMPlatformBridgeVlan **plat_vlans = NULL;
if (self->vlan_configured)
return TRUE;
@ -479,8 +485,7 @@ bridge_set_vlan_options (NMDevice *device, NMSettingBridge *s_bridge)
g_object_get (s_bridge, NM_SETTING_BRIDGE_VLANS, &vlans, NULL);
plat_vlans = setting_vlans_to_platform (vlans);
if ( plat_vlans
&& !nm_platform_link_set_bridge_vlans (plat, ifindex, FALSE,
(const NMPlatformBridgeVlan *const *) plat_vlans))
&& !nm_platform_link_set_bridge_vlans (plat, ifindex, FALSE, plat_vlans))
return FALSE;
if (!nm_platform_sysctl_master_set_option (plat, ifindex, "vlan_filtering", "1"))
@ -568,8 +573,6 @@ enslave_slave (NMDevice *device,
NMConnection *master_connection;
NMSettingBridge *s_bridge;
NMSettingBridgePort *s_port;
gs_unref_ptrarray GPtrArray *vlans = NULL;
nm_auto_freev NMPlatformBridgeVlan **plat_vlans = NULL;
if (configure) {
if (!nm_platform_link_enslave (nm_device_get_platform (device), nm_device_get_ip_ifindex (device), nm_device_get_ip_ifindex (slave)))
@ -584,8 +587,12 @@ enslave_slave (NMDevice *device,
bridge_set_vlan_options (device, s_bridge);
if (nm_setting_bridge_get_vlan_filtering (s_bridge)) {
gs_free const NMPlatformBridgeVlan **plat_vlans = NULL;
gs_unref_ptrarray GPtrArray *vlans = NULL;
if (s_port)
g_object_get (s_port, NM_SETTING_BRIDGE_PORT_VLANS, &vlans, NULL);
plat_vlans = setting_vlans_to_platform (vlans);
/* Since the link was just enslaved, there are no existing VLANs
@ -595,7 +602,7 @@ enslave_slave (NMDevice *device,
&& !nm_platform_link_set_bridge_vlans (nm_device_get_platform (slave),
nm_device_get_ifindex (slave),
TRUE,
(const NMPlatformBridgeVlan *const *) plat_vlans))
plat_vlans))
return FALSE;
}

View file

@ -6838,9 +6838,10 @@ link_set_bridge_vlans (NMPlatform *platform,
/* Add VLANs */
for (i = 0; vlans[i]; i++) {
const NMPlatformBridgeVlan *vlan = vlans[i];
gboolean is_range = vlan->vid_start != vlan->vid_end;
vinfo.vid = vlan->vid;
vinfo.flags = 0;
vinfo.vid = vlan->vid_start;
vinfo.flags = is_range ? BRIDGE_VLAN_INFO_RANGE_BEGIN : 0;
if (vlan->untagged)
vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
@ -6848,6 +6849,12 @@ link_set_bridge_vlans (NMPlatform *platform,
vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo);
if (is_range) {
vinfo.vid = vlan->vid_end;
vinfo.flags = BRIDGE_VLAN_INFO_RANGE_END;
NLA_PUT (nlmsg, IFLA_BRIDGE_VLAN_INFO, sizeof (vinfo), &vinfo);
}
}
} else {
/* Flush existing VLANs */

View file

@ -6542,14 +6542,18 @@ nm_platform_vf_to_string (const NMPlatformVF *vf, char *buf, gsize len)
const char *
nm_platform_bridge_vlan_to_string (const NMPlatformBridgeVlan *vlan, char *buf, gsize len)
{
char str_vid_end[64];
if (!nm_utils_to_string_buffer_init_null (vlan, &buf, &len))
return buf;
g_snprintf (buf, len,
"%u"
"%s"
"%s"
"%s",
vlan->vid,
vlan->vid_start,
vlan->vid_start != vlan->vid_end ? nm_sprintf_buf (str_vid_end, "-%u", vlan->vid_end) : "",
vlan->pvid ? " PVID" : "",
vlan->untagged ? " untagged" : "");

View file

@ -671,7 +671,8 @@ typedef struct {
} NMPlatformVF;
typedef struct {
guint16 vid;
guint16 vid_start;
guint16 vid_end;
bool untagged:1;
bool pvid:1;
} NMPlatformBridgeVlan;

View file

@ -5114,7 +5114,7 @@ read_bridge_vlans (shvarFile *ifcfg,
array = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref);
strv = nm_utils_strsplit_set (value, ",");
strv = nm_utils_escaped_tokens_split (value, ",");
if (strv) {
for (iter = strv; *iter; iter++) {
vlan = nm_bridge_vlan_from_str (*iter, &local);

View file

@ -1491,8 +1491,8 @@ write_bridge_vlans (NMSetting *setting,
if (!vlan_str)
return FALSE;
if (string->len > 0)
g_string_append (string, ", ");
g_string_append (string, vlan_str);
g_string_append (string, ",");
nm_utils_escaped_tokens_escape_gstr_assert (vlan_str, ",", string);
}
svSetValueStr (ifcfg, key, string->str);

View file

@ -2,7 +2,7 @@ HWADDR=31:33:33:37:BE:CD
MTU=1492
TYPE=Ethernet
BRIDGING_OPTS="priority=50 path_cost=33"
BRIDGE_PORT_VLANS="1 untagged, 2 pvid untagged, 4"
BRIDGE_PORT_VLANS="1 untagged,2 pvid,4-4094 untagged"
NAME="Test Write Bridge Component"
UUID=${UUID}
ONBOOT=yes

View file

@ -7651,14 +7651,14 @@ test_write_bridge_main (void)
nm_connection_add_setting (connection, NM_SETTING (s_bridge));
vlans = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref);
vlan = nm_bridge_vlan_new (11);
vlan = nm_bridge_vlan_new (10, 16);
nm_bridge_vlan_set_untagged (vlan, TRUE);
g_ptr_array_add (vlans, vlan);
vlan = nm_bridge_vlan_new (22);
vlan = nm_bridge_vlan_new (22, 22);
nm_bridge_vlan_set_pvid (vlan, TRUE);
nm_bridge_vlan_set_untagged (vlan, TRUE);
g_ptr_array_add (vlans, vlan);
vlan = nm_bridge_vlan_new (44);
vlan = nm_bridge_vlan_new (44, 0);
g_ptr_array_add (vlans, vlan);
g_object_set (s_bridge,
@ -7774,14 +7774,14 @@ test_write_bridge_component (void)
/* Bridge port */
vlans = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_bridge_vlan_unref);
vlan = nm_bridge_vlan_new (1);
vlan = nm_bridge_vlan_new (1, 0);
nm_bridge_vlan_set_untagged (vlan, TRUE);
g_ptr_array_add (vlans, vlan);
vlan = nm_bridge_vlan_new (2);
vlan = nm_bridge_vlan_new (4, 4094);
nm_bridge_vlan_set_untagged (vlan, TRUE);
g_ptr_array_add (vlans, vlan);
vlan = nm_bridge_vlan_new (2, 2);
nm_bridge_vlan_set_pvid (vlan, TRUE);
nm_bridge_vlan_set_untagged (vlan, TRUE);
g_ptr_array_add (vlans, vlan);
vlan = nm_bridge_vlan_new (4);
g_ptr_array_add (vlans, vlan);
s_port = nm_setting_bridge_port_new ();