summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2019-04-15 15:14:33 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2019-04-18 09:39:28 +0200
commit70935157771b1de39f27d20e50112efcc50d1f5c (patch)
treed6fe33af73f65210dcd0477cb56ac132a35ad295
parentea16cf59f6972ed9444c6f42166794d7f7c15a54 (diff)
all: support bridge vlan ranges
In some cases it is convenient to specify ranges of bridge vlans, as already supported by iproute2 and natively by kernel. With this commit it becomes possible to add a range in this way: nmcli connection modify eth0-slave +bridge-port.vlans "100-200 untagged" vlan ranges can't be PVIDs because only one PVID vlan can exist. https://bugzilla.redhat.com/show_bug.cgi?id=1652910
-rw-r--r--clients/common/nm-meta-setting-desc.c10
-rw-r--r--clients/common/settings-docs.h.in4
-rw-r--r--libnm-core/nm-keyfile.c98
-rw-r--r--libnm-core/nm-setting-bridge-port.c24
-rw-r--r--libnm-core/nm-setting-bridge-port.h4
-rw-r--r--libnm-core/nm-setting-bridge.c141
-rw-r--r--libnm-core/nm-setting-bridge.h8
-rw-r--r--libnm-core/nm-utils.c81
-rw-r--r--libnm-core/tests/test-keyfile.c43
-rw-r--r--libnm-core/tests/test-setting.c15
-rw-r--r--libnm/libnm.ver2
-rw-r--r--src/devices/nm-device-bridge.c6
-rw-r--r--src/platform/nm-linux-platform.c11
-rw-r--r--src/platform/nm-platform.c6
-rw-r--r--src/platform/nm-platform.h3
-rw-r--r--src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected2
-rw-r--r--src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c14
18 files changed, 310 insertions, 164 deletions
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c
index d1c82255a7..7c1b56a90f 100644
--- a/clients/common/nm-meta-setting-desc.c
+++ b/clients/common/nm-meta-setting-desc.c
@@ -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);
}
}
diff --git a/clients/common/settings-docs.h.in b/clients/common/settings-docs.h.in
index 59ca4cc8a6..811f2f16d6 100644
--- a/clients/common/settings-docs.h.in
+++ b/clients/common/settings-docs.h.in
@@ -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.")
diff --git a/libnm-core/nm-keyfile.c b/libnm-core/nm-keyfile.c
index 773b4ba860..e14887ca52 100644
--- a/libnm-core/nm-keyfile.c
+++ b/libnm-core/nm-keyfile.c
@@ -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;
-
- keys = nm_keyfile_plugin_kf_get_keys (info->keyfile, setting_name, &n_keys, NULL);
- if (n_keys == 0)
+ gs_free char *value = NULL;
+ gs_free const char **strv = NULL;
+ const char *const *iter;
+ GError *local = NULL;
+ NMBridgeVlan *vlan;
+
+ 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_strsplit_set (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, ",");
+ g_string_append (string, vlan_str);
}
+
+ nm_keyfile_plugin_kf_set_string (info->keyfile,
+ nm_setting_get_name (setting),
+ "vlans",
+ string->str);
+
+ g_string_free (string, TRUE);
}
static void
diff --git a/libnm-core/nm-setting-bridge-port.c b/libnm-core/nm-setting-bridge-port.c
index ebac2fc2c3..7a8b345f01 100644
--- a/libnm-core/nm-setting-bridge-port.c
+++ b/libnm-core/nm-setting-bridge-port.c
@@ -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] =
diff --git a/libnm-core/nm-setting-bridge-port.h b/libnm-core/nm-setting-bridge-port.h
index b1b1c8f40c..5b75c1ecde 100644
--- a/libnm-core/nm-setting-bridge-port.h
+++ b/libnm-core/nm-setting-bridge-port.h
@@ -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);
diff --git a/libnm-core/nm-setting-bridge.c b/libnm-core/nm-setting-bridge.c
index 590f6ea2bd..3e29f86dbe 100644
--- a/libnm-core/nm-setting-bridge.c
+++ b/libnm-core/nm-setting-bridge.c
@@ -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,9 +450,10 @@ 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);
@@ -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] =
diff --git a/libnm-core/nm-setting-bridge.h b/libnm-core/nm-setting-bridge.h
index 0ec0b2a8e3..c01ab35c74 100644
--- a/libnm-core/nm-setting-bridge.h
+++ b/libnm-core/nm-setting-bridge.h
@@ -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
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index af05cdfb6e..ea333dc61c 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -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_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 < NM_BRIDGE_VLAN_VID_MIN
- || vid > NM_BRIDGE_VLAN_VID_MAX)
+ 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);
@@ -6875,14 +6890,18 @@ _nm_utils_bridge_vlan_verify_list (GPtrArray *vlans,
for (i = 1; i < vlans->len; i++) {
NMBridgeVlan *vlan_prev = vlans->pdata[i - 1];
NMBridgeVlan *vlan = vlans->pdata[i];
+ guint16 vid_prev, vid;
- if (nm_bridge_vlan_get_vid (vlan_prev) > nm_bridge_vlan_get_vid (vlan)) {
+ nm_bridge_vlan_get_vid_range (vlan_prev, &vid_prev, NULL);
+ nm_bridge_vlan_get_vid_range (vlan, &vid, NULL);
+
+ if (vid_prev > vid) {
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,
+ vid);
g_prefix_error (error, "%s.%s: ", setting, property);
return FALSE;
}
@@ -6893,32 +6912,32 @@ _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;
-
- vid = nm_bridge_vlan_get_vid (vlan);
+ guint16 v, 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;
- }
-
- 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"));
+ nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
+ for (v = vid_start; v <= vid_end; v++) {
+ if (g_hash_table_contains (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;
}
- pvid_found = TRUE;
- }
- g_hash_table_add (h, GUINT_TO_POINTER (vid));
+ 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 (v));
+ }
}
return TRUE;
diff --git a/libnm-core/tests/test-keyfile.c b/libnm-core/tests/test-keyfile.c
index fbdd7ab27b..157e8f1868 100644
--- a/libnm-core/tests/test-keyfile.c
+++ b/libnm-core/tests/test-keyfile.c
@@ -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);
diff --git a/libnm-core/tests/test-setting.c b/libnm-core/tests/test-setting.c
index 57af014021..03100a039b 100644
--- a/libnm-core/tests/test-setting.c
+++ b/libnm-core/tests/test-setting.c
@@ -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);
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index 8763e11a6c..8100f3b631 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -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;
diff --git a/src/devices/nm-device-bridge.c b/src/devices/nm-device-bridge.c
index 1d2f61e6c2..179d157907 100644
--- a/src/devices/nm-device-bridge.c
+++ b/src/devices/nm-device-bridge.c
@@ -282,9 +282,13 @@ setting_vlans_to_platform (GPtrArray *array)
for (i = 0; i < array->len; i++) {
NMBridgeVlan *vlan = array->pdata[i];
NMPlatformBridgeVlan *plat_vlan;
+ guint16 vid_start, vid_end;
+
+ nm_bridge_vlan_get_vid_range (vlan, &vid_start, &vid_end);
plat_vlan = g_new0 (NMPlatformBridgeVlan, 1);
- plat_vlan->vid = nm_bridge_vlan_get_vid (vlan);
+ plat_vlan->vid_start = vid_start;
+ plat_vlan->vid_end = vid_end;
plat_vlan->pvid = nm_bridge_vlan_is_pvid (vlan);
plat_vlan->untagged = nm_bridge_vlan_is_untagged (vlan);
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 4abb45960f..460b321bf6 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -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 */
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 4e6bf95882..53ad78caf0 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -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" : "");
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 42f6c96136..fa8200e68b 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -671,7 +671,8 @@ typedef struct {
} NMPlatformVF;
typedef struct {
- guint16 vid;
+ guint16 vid_start;
+ guint16 vid_end;
bool untagged:1;
bool pvid:1;
} NMPlatformBridgeVlan;
diff --git a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
index a57e6c3a60..7bf8c01745 100644
--- a/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
+++ b/src/settings/plugins/ifcfg-rh/nms-ifcfg-rh-writer.c
@@ -1491,7 +1491,7 @@ write_bridge_vlans (NMSetting *setting,
if (!vlan_str)
return FALSE;
if (string->len > 0)
- g_string_append (string, ", ");
+ g_string_append (string, ",");
g_string_append (string, vlan_str);
}
diff --git a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected
index 0b4db7c1ed..a8ff8df3e9 100644
--- a/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected
+++ b/src/settings/plugins/ifcfg-rh/tests/network-scripts/ifcfg-Test_Write_Bridge_Component.cexpected
@@ -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
diff --git a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
index 09e2c0e4b5..ca280fbfec 100644
--- a/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
+++ b/src/settings/plugins/ifcfg-rh/tests/test-ifcfg-rh.c
@@ -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);
- nm_bridge_vlan_set_pvid (vlan, TRUE);
+ 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 (4);
+ vlan = nm_bridge_vlan_new (2, 2);
+ nm_bridge_vlan_set_pvid (vlan, TRUE);
g_ptr_array_add (vlans, vlan);
s_port = nm_setting_bridge_port_new ();