diff --git a/src/libnm-client-impl/libnm.ver b/src/libnm-client-impl/libnm.ver index 9a6c74be56..66538c5e29 100644 --- a/src/libnm-client-impl/libnm.ver +++ b/src/libnm-client-impl/libnm.ver @@ -1898,5 +1898,11 @@ global: nm_setting_loopback_get_type; nm_setting_loopback_new; nm_setting_ovs_interface_get_ofport_request; + nm_setting_ovs_port_add_trunk; + nm_setting_ovs_port_clear_trunks; + nm_setting_ovs_port_get_num_trunks; + nm_setting_ovs_port_get_trunk; + nm_setting_ovs_port_remove_trunk; + nm_setting_ovs_port_remove_trunk_by_value; nm_utils_ensure_gtypes; } libnm_1_40_0; diff --git a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in index 42fd7c4773..781f7610ec 100644 --- a/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in +++ b/src/libnm-core-impl/gen-metadata-nm-settings-libnm-core.xml.in @@ -1898,6 +1898,10 @@ dbus-type="u" gprop-type="guint" /> + keyfile, nm_setting_get_name(setting), key, NULL); + if (!value || !value[0]) + return; + + ranges = g_ptr_array_new_with_free_func((GDestroyNotify) nm_range_unref); + + strv = nm_utils_escaped_tokens_split(value, ","); + if (strv) { + for (iter = strv; *iter; iter++) { + range = nm_range_from_str(*iter, &local); + if (!range) { + read_handle_warn(info, + key, + key, + NM_KEYFILE_WARN_SEVERITY_WARN, + "invalid range: %s", + local->message); + g_clear_error(&local); + continue; + } + g_ptr_array_add(ranges, range); + } + } + + if (ranges->len > 0) + g_object_set(setting, key, ranges, NULL); +} + static void qdisc_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key) { @@ -2344,6 +2382,33 @@ bridge_vlan_writer(KeyfileWriterInfo *info, } } +static void +range_list_writer(KeyfileWriterInfo *info, NMSetting *setting, const char *key, const GValue *value) +{ + GPtrArray *ranges; + + ranges = g_value_get_boxed(value); + if (ranges && ranges->len > 0) { + const guint string_initial_size = ranges->len * 10u; + nm_auto_str_buf NMStrBuf string = NM_STR_BUF_INIT(string_initial_size, FALSE); + guint i; + + for (i = 0; i < ranges->len; i++) { + gs_free char *range_str = NULL; + + range_str = nm_range_to_str(ranges->pdata[i]); + if (i > 0) + nm_str_buf_append_c(&string, ','); + nm_utils_escaped_tokens_escape_strbuf_assert(range_str, ",", &string); + } + + nm_keyfile_plugin_kf_set_string(info->keyfile, + nm_setting_get_name(setting), + key, + nm_str_buf_get_str(&string)); + } +} + static void wired_s390_options_parser_full(KeyfileReaderInfo *info, const NMMetaSettingInfo *setting_info, @@ -2933,6 +2998,12 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = { .parser_no_check_key = TRUE, .parser = bridge_vlan_parser, .writer = bridge_vlan_writer, ), ), ), + PARSE_INFO_SETTING( + NM_META_SETTING_TYPE_OVS_PORT, + PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_OVS_PORT_TRUNKS, + .parser_no_check_key = TRUE, + .parser = range_list_parser, + .writer = range_list_writer, ), ), ), PARSE_INFO_SETTING( NM_META_SETTING_TYPE_BRIDGE_PORT, PARSE_INFO_PROPERTIES(PARSE_INFO_PROPERTY(NM_SETTING_BRIDGE_PORT_VLANS, diff --git a/src/libnm-core-impl/nm-setting-ovs-port.c b/src/libnm-core-impl/nm-setting-ovs-port.c index ab9c0a1141..840221edbc 100644 --- a/src/libnm-core-impl/nm-setting-ovs-port.c +++ b/src/libnm-core-impl/nm-setting-ovs-port.c @@ -21,12 +21,14 @@ /*****************************************************************************/ -NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_VLAN_MODE, - PROP_TAG, - PROP_LACP, - PROP_BOND_MODE, - PROP_BOND_UPDELAY, - PROP_BOND_DOWNDELAY, ); +NM_GOBJECT_PROPERTIES_DEFINE(NMSettingOvsPort, + PROP_VLAN_MODE, + PROP_TAG, + PROP_TRUNKS, + PROP_LACP, + PROP_BOND_MODE, + PROP_BOND_UPDELAY, + PROP_BOND_DOWNDELAY, ); /** * NMSettingOvsPort: @@ -36,12 +38,13 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE(PROP_VLAN_MODE, struct _NMSettingOvsPort { NMSetting parent; - char *vlan_mode; - char *lacp; - char *bond_mode; - guint32 tag; - guint32 bond_updelay; - guint32 bond_downdelay; + GPtrArray *trunks; + char *vlan_mode; + char *lacp; + char *bond_mode; + guint32 tag; + guint32 bond_updelay; + guint32 bond_downdelay; }; struct _NMSettingOvsPortClass { @@ -84,6 +87,143 @@ nm_setting_ovs_port_get_tag(NMSettingOvsPort *self) return self->tag; } +/*****************************************************************************/ + +/** + * nm_setting_ovs_port_add_trunk: + * @setting: the #NMSettingOvsPort + * @trunk: the trunk to add + * + * Appends a new trunk range to the setting. + * This takes a reference to @trunk. + * + * Since: 1.42 + **/ +void +nm_setting_ovs_port_add_trunk(NMSettingOvsPort *self, NMRange *trunk) +{ + g_return_if_fail(NM_IS_SETTING_OVS_PORT(self)); + g_return_if_fail(trunk); + + g_ptr_array_add(self->trunks, nm_range_ref(trunk)); + _notify(self, PROP_TRUNKS); +} + +/** + * nm_setting_ovs_port_get_num_trunks: + * @setting: the #NMSettingOvsPort + * + * Returns: the number of trunk ranges + * + * Since: 1.42 + **/ +guint +nm_setting_ovs_port_get_num_trunks(NMSettingOvsPort *self) +{ + g_return_val_if_fail(NM_IS_SETTING_OVS_PORT(self), 0); + + return self->trunks->len; +} + +/** + * nm_setting_ovs_port_get_trunk: + * @setting: the #NMSettingOvsPort + * @idx: index number of the trunk range to return + * + * Returns: (transfer none): the trunk range at index @idx + * + * Since: 1.42 + **/ +NMRange * +nm_setting_ovs_port_get_trunk(NMSettingOvsPort *self, guint idx) +{ + g_return_val_if_fail(NM_IS_SETTING_OVS_PORT(self), NULL); + + g_return_val_if_fail(idx < self->trunks->len, NULL); + + return self->trunks->pdata[idx]; +} + +/** + * nm_setting_ovs_port_remove_trunk: + * @setting: the #NMSettingOvsPort + * @idx: index number of the trunk range. + * + * Removes the trunk range at index @idx. + * + * Since: 1.42 + **/ +void +nm_setting_ovs_port_remove_trunk(NMSettingOvsPort *self, guint idx) +{ + g_return_if_fail(NM_IS_SETTING_OVS_PORT(self)); + + g_return_if_fail(idx < self->trunks->len); + + g_ptr_array_remove_index(self->trunks, idx); + _notify(self, PROP_TRUNKS); +} + +/** + * nm_setting_ovs_port_remove_trunk_by_value: + * @setting: the #NMSettingOvsPort + * @start: the trunk range start index + * @end: the trunk range end index + * + * Remove the trunk range with range @start to @end. + * + * Returns: %TRUE if the trunk range was found and removed; %FALSE otherwise + * + * Since: 1.42 + **/ +gboolean +nm_setting_ovs_port_remove_trunk_by_value(NMSettingOvsPort *self, guint start, guint end) +{ + NMRange *trunk; + guint i; + + g_return_val_if_fail(NM_IS_SETTING_OVS_PORT(self), FALSE); + + for (i = 0; i < self->trunks->len; i++) { + trunk = (NMRange *) self->trunks->pdata[i]; + if (trunk->start == start && trunk->end == end) { + g_ptr_array_remove_index(self->trunks, i); + _notify(self, PROP_TRUNKS); + return TRUE; + } + } + return FALSE; +} + +/** + * nm_setting_ovs_port_clear_trunks: + * @setting: the #NMSettingOvsPort + * + * Removes all configured trunk ranges. + * + * Since: 1.42 + **/ +void +nm_setting_ovs_port_clear_trunks(NMSettingOvsPort *self) +{ + g_return_if_fail(NM_IS_SETTING_OVS_PORT(self)); + + if (self->trunks->len != 0) { + g_ptr_array_set_size(self->trunks, 0); + _notify(self, PROP_TRUNKS); + } +} + +const GPtrArray * +_nm_setting_ovs_port_get_trunks_arr(NMSettingOvsPort *self) +{ + g_return_val_if_fail(NM_IS_SETTING_OVS_PORT(self), NULL); + + return self->trunks; +} + +/*****************************************************************************/ + /** * nm_setting_ovs_port_get_lacp: * @self: the #NMSettingOvsPort @@ -150,6 +290,107 @@ nm_setting_ovs_port_get_bond_downdelay(NMSettingOvsPort *self) /*****************************************************************************/ +static int +range_cmp(gconstpointer a, gconstpointer b) +{ + const NMRange *range_a = *(const NMRange **) a; + const NMRange *range_b = *(const NMRange **) b; + + return nm_range_cmp(range_a, range_b); +} + +gboolean +_nm_setting_ovs_port_sort_trunks(NMSettingOvsPort *self) +{ + gboolean need_sort = FALSE; + guint i; + + for (i = 1; i < self->trunks->len; i++) { + NMRange *range_prev = self->trunks->pdata[i - 1]; + NMRange *range = self->trunks->pdata[i]; + + if (nm_range_cmp(range_prev, range) > 0) { + need_sort = TRUE; + break; + } + } + + if (need_sort) { + g_ptr_array_sort(self->trunks, range_cmp); + _notify(self, PROP_TRUNKS); + } + + return need_sort; +} + +static gboolean +verify_trunks(GPtrArray *ranges, GError **error) +{ + gs_unref_hashtable GHashTable *h = NULL; + NMRange *range; + guint i; + guint vlan; + + if (!ranges) + return TRUE; + + h = g_hash_table_new(nm_direct_hash, NULL); + + for (i = 0; i < ranges->len; i++) { + range = ranges->pdata[i]; + nm_assert(range->start <= range->end); + + if (range->start > 4095 || range->end > 4095) { + g_set_error_literal(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("VLANs must be between 0 and 4095")); + return FALSE; + } + + for (vlan = range->start; vlan <= range->end; vlan++) { + if (!nm_g_hash_table_add(h, GUINT_TO_POINTER(vlan))) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("duplicate VLAN %u"), + vlan); + return FALSE; + } + } + } + + return TRUE; +} + +static gboolean +verify_trunks_normalizable(GPtrArray *ranges, GError **error) +{ + guint i; + + nm_assert(verify_trunks(ranges, NULL)); + + if (!ranges || ranges->len <= 1) + return TRUE; + + for (i = 1; i < ranges->len; i++) { + NMRange *range_prev = ranges->pdata[i - 1]; + NMRange *range = ranges->pdata[i]; + + if (nm_range_cmp(range_prev, range) > 0) { + g_set_error(error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("VLANs %u and %u are not sorted in ascending order"), + (guint) range_prev->start, + (guint) range->start); + return FALSE; + } + } + + return TRUE; +} + static int verify(NMSetting *setting, NMConnection *connection, GError **error) { @@ -257,14 +498,68 @@ verify(NMSetting *setting, NMConnection *connection, GError **error) return FALSE; } + if (!verify_trunks(self->trunks, error)) { + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_OVS_PORT_TRUNKS); + return FALSE; + } + + if (!verify_trunks_normalizable(self->trunks, error)) { + g_prefix_error(error, + "%s.%s: ", + NM_SETTING_OVS_PORT_SETTING_NAME, + NM_SETTING_OVS_PORT_TRUNKS); + return NM_SETTING_VERIFY_NORMALIZABLE; + } + return TRUE; } /*****************************************************************************/ +static void +get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) +{ + NMSettingOvsPort *self = NM_SETTING_OVS_PORT(object); + + switch (prop_id) { + case PROP_TRUNKS: + g_value_take_boxed(value, + _nm_utils_copy_array(self->trunks, + (NMUtilsCopyFunc) nm_range_ref, + (GDestroyNotify) nm_range_unref)); + break; + default: + _nm_setting_property_get_property_direct(object, prop_id, value, pspec); + break; + } +} + +static void +set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) +{ + NMSettingOvsPort *self = NM_SETTING_OVS_PORT(object); + + switch (prop_id) { + case PROP_TRUNKS: + g_ptr_array_unref(self->trunks); + self->trunks = _nm_utils_copy_array(g_value_get_boxed(value), + (NMUtilsCopyFunc) nm_range_ref, + (GDestroyNotify) nm_range_unref); + break; + default: + _nm_setting_property_set_property_direct(object, prop_id, value, pspec); + break; + } +} + static void nm_setting_ovs_port_init(NMSettingOvsPort *self) -{} +{ + self->trunks = g_ptr_array_new_with_free_func((GDestroyNotify) nm_range_unref); +} /** * nm_setting_ovs_port_new: @@ -281,6 +576,16 @@ nm_setting_ovs_port_new(void) return g_object_new(NM_TYPE_SETTING_OVS_PORT, NULL); } +static void +finalize(GObject *object) +{ + NMSettingOvsPort *self = NM_SETTING_OVS_PORT(object); + + g_ptr_array_unref(self->trunks); + + G_OBJECT_CLASS(nm_setting_ovs_port_parent_class)->finalize(object); +} + static void nm_setting_ovs_port_class_init(NMSettingOvsPortClass *klass) { @@ -288,8 +593,9 @@ nm_setting_ovs_port_class_init(NMSettingOvsPortClass *klass) NMSettingClass *setting_class = NM_SETTING_CLASS(klass); GArray *properties_override = _nm_sett_info_property_override_create_array(); - object_class->get_property = _nm_setting_property_get_property_direct; - object_class->set_property = _nm_setting_property_set_property_direct; + object_class->get_property = get_property; + object_class->set_property = set_property; + object_class->finalize = finalize; setting_class->verify = verify; @@ -327,6 +633,31 @@ nm_setting_ovs_port_class_init(NMSettingOvsPortClass *klass) NMSettingOvsPort, tag); + /** + * NMSettingOvsPort:trunks: (type GPtrArray(NMRange)) + * + * A list of VLAN ranges that this port trunks. + * + * The property is valid only for ports with mode "trunk", + * "native-tagged", or "native-untagged port". + * If it is empty, the port trunks all VLANs. + * + * Since: 1.42 + **/ + obj_properties[PROP_TRUNKS] = g_param_spec_boxed(NM_SETTING_OVS_PORT_TRUNKS, + "", + "", + G_TYPE_PTR_ARRAY, + G_PARAM_READWRITE | NM_SETTING_PARAM_INFERRABLE + | G_PARAM_STATIC_STRINGS); + _nm_properties_override_gobj( + properties_override, + obj_properties[PROP_TRUNKS], + NM_SETT_INFO_PROPERT_TYPE_DBUS(NM_G_VARIANT_TYPE("aa{sv}"), + .to_dbus_fcn = _nm_utils_ranges_to_dbus, + .compare_fcn = _nm_utils_ranges_cmp, + .from_dbus_fcn = _nm_utils_ranges_from_dbus)); + /** * NMSettingOvsPort:lacp: * diff --git a/src/libnm-core-impl/nm-setting-private.h b/src/libnm-core-impl/nm-setting-private.h index 6791d199e6..e7a26c5d3b 100644 --- a/src/libnm-core-impl/nm-setting-private.h +++ b/src/libnm-core-impl/nm-setting-private.h @@ -1073,6 +1073,12 @@ gboolean _nm_utils_bridge_vlans_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS GVariant *_nm_utils_bridge_vlans_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil); +gboolean _nm_utils_ranges_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil); + +NMTernary _nm_utils_ranges_cmp(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil); + +GVariant *_nm_utils_ranges_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil); + NMTernary _nm_setting_ip_config_compare_fcn_addresses(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil); NMTernary _nm_setting_ip_config_compare_fcn_routes(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil); diff --git a/src/libnm-core-impl/nm-utils.c b/src/libnm-core-impl/nm-utils.c index b27d839ffe..daac3f73c4 100644 --- a/src/libnm-core-impl/nm-utils.c +++ b/src/libnm-core-impl/nm-utils.c @@ -5572,6 +5572,97 @@ _nm_utils_bridge_vlan_verify_list(GPtrArray *vlans, return TRUE; } +GVariant * +_nm_utils_ranges_to_dbus(_NM_SETT_INFO_PROP_TO_DBUS_FCN_ARGS _nm_nil) +{ + gs_unref_ptrarray GPtrArray *ranges = NULL; + GVariantBuilder builder; + const char *property_name = property_info->name; + guint i; + + nm_assert(property_name); + + g_object_get(setting, property_name, &ranges, NULL); + g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); + + if (ranges) { + for (i = 0; i < ranges->len; i++) { + NMRange *range = ranges->pdata[i]; + GVariantBuilder range_builder; + + g_variant_builder_init(&range_builder, G_VARIANT_TYPE_VARDICT); + g_variant_builder_add(&range_builder, + "{sv}", + "start", + g_variant_new_uint64(range->start)); + g_variant_builder_add(&range_builder, "{sv}", "end", g_variant_new_uint64(range->end)); + + g_variant_builder_add(&builder, "a{sv}", &range_builder); + } + } + + return g_variant_builder_end(&builder); +} + +gboolean +_nm_utils_ranges_from_dbus(_NM_SETT_INFO_PROP_FROM_DBUS_FCN_ARGS _nm_nil) +{ + gs_unref_ptrarray GPtrArray *ranges = NULL; + GVariantIter iter; + GVariant *range_var; + + g_return_val_if_fail(g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}")), FALSE); + + ranges = g_ptr_array_new_with_free_func((GDestroyNotify) nm_range_unref); + g_variant_iter_init(&iter, value); + while (g_variant_iter_next(&iter, "@a{sv}", &range_var)) { + _nm_unused gs_unref_variant GVariant *var_unref = range_var; + gint64 start; + gint64 end; + + if (!g_variant_lookup(range_var, "start", "t", &start)) + continue; + if (!g_variant_lookup(range_var, "end", "t", &end)) + continue; + if (start > end) + continue; + + g_ptr_array_add(ranges, nm_range_new(start, end)); + } + + g_object_set(setting, property_info->name, ranges, NULL); + + return TRUE; +} + +NMTernary +_nm_utils_ranges_cmp(_NM_SETT_INFO_PROP_COMPARE_FCN_ARGS _nm_nil) +{ + const GPtrArray *ranges_a = NULL; + const GPtrArray *ranges_b = NULL; + guint len; + guint i; + + if (nm_streq0(nm_setting_get_name(set_a), NM_SETTING_OVS_PORT_SETTING_NAME) + && nm_streq0(property_info->name, NM_SETTING_OVS_PORT_TRUNKS)) { + ranges_a = _nm_setting_ovs_port_get_trunks_arr(NM_SETTING_OVS_PORT(set_a)); + if (set_b) + ranges_b = _nm_setting_ovs_port_get_trunks_arr(NM_SETTING_OVS_PORT(set_b)); + } else { + nm_assert_not_reached(); + } + + len = nm_g_ptr_array_len(ranges_a); + if (len != nm_g_ptr_array_len(ranges_b)) + return FALSE; + for (i = 0; i < len; i++) { + if (nm_range_cmp(ranges_a->pdata[i], ranges_b->pdata[i])) + return FALSE; + } + + return TRUE; +} + gboolean _nm_utils_iaid_verify(const char *str, gint64 *out_value) { diff --git a/src/libnm-core-intern/nm-core-internal.h b/src/libnm-core-intern/nm-core-internal.h index ba28bc75f1..5d07f2c2c8 100644 --- a/src/libnm-core-intern/nm-core-internal.h +++ b/src/libnm-core-intern/nm-core-internal.h @@ -566,6 +566,7 @@ gboolean _nm_utils_dhcp_duid_valid(const char *duid, GBytes **out_duid_bin); gboolean _nm_setting_sriov_sort_vfs(NMSettingSriov *setting); gboolean _nm_setting_bridge_port_sort_vlans(NMSettingBridgePort *setting); gboolean _nm_setting_bridge_sort_vlans(NMSettingBridge *setting); +gboolean _nm_setting_ovs_port_sort_trunks(NMSettingOvsPort *self); /*****************************************************************************/ @@ -1067,4 +1068,6 @@ GPtrArray *_nm_setting_ip_config_get_dns_array(NMSettingIPConfig *setting); gboolean nm_connection_need_secrets_for_rerequest(NMConnection *connection); +const GPtrArray *_nm_setting_ovs_port_get_trunks_arr(NMSettingOvsPort *self); + #endif diff --git a/src/libnm-core-public/nm-setting-ovs-port.h b/src/libnm-core-public/nm-setting-ovs-port.h index eda23d3e7b..4a452c0c56 100644 --- a/src/libnm-core-public/nm-setting-ovs-port.h +++ b/src/libnm-core-public/nm-setting-ovs-port.h @@ -29,6 +29,7 @@ G_BEGIN_DECLS #define NM_SETTING_OVS_PORT_VLAN_MODE "vlan-mode" #define NM_SETTING_OVS_PORT_TAG "tag" +#define NM_SETTING_OVS_PORT_TRUNKS "trunks" #define NM_SETTING_OVS_PORT_LACP "lacp" #define NM_SETTING_OVS_PORT_BOND_MODE "bond-mode" #define NM_SETTING_OVS_PORT_BOND_UPDELAY "bond-updelay" @@ -54,6 +55,20 @@ guint nm_setting_ovs_port_get_bond_updelay(NMSettingOvsPort *self); NM_AVAILABLE_IN_1_10 guint nm_setting_ovs_port_get_bond_downdelay(NMSettingOvsPort *self); +NM_AVAILABLE_IN_1_42 +void nm_setting_ovs_port_add_trunk(NMSettingOvsPort *setting, NMRange *trunk); +NM_AVAILABLE_IN_1_42 +guint nm_setting_ovs_port_get_num_trunks(NMSettingOvsPort *setting); +NM_AVAILABLE_IN_1_42 +NMRange *nm_setting_ovs_port_get_trunk(NMSettingOvsPort *setting, guint idx); +NM_AVAILABLE_IN_1_42 +void nm_setting_ovs_port_remove_trunk(NMSettingOvsPort *setting, guint idx); +NM_AVAILABLE_IN_1_42 +gboolean +nm_setting_ovs_port_remove_trunk_by_value(NMSettingOvsPort *setting, guint start, guint end); +NM_AVAILABLE_IN_1_42 +void nm_setting_ovs_port_clear_trunks(NMSettingOvsPort *setting); + G_END_DECLS #endif /* __NM_SETTING_OVS_PORT_H__ */ diff --git a/src/libnmc-setting/nm-meta-setting-desc.c b/src/libnmc-setting/nm-meta-setting-desc.c index 40dd28f31b..e1f1bf3a04 100644 --- a/src/libnmc-setting/nm-meta-setting-desc.c +++ b/src/libnmc-setting/nm-meta-setting-desc.c @@ -3767,6 +3767,20 @@ _objlist_obj_to_str_fcn_tc_config_qdiscs(NMMetaAccessorGetType get_type, g_string_append(str, s); } +static void +_objlist_obj_to_str_fcn_ovs_port_trunks(NMMetaAccessorGetType get_type, + NMSetting *setting, + guint idx, + GString *str) +{ + gs_free char *s = NULL; + NMRange *trunk; + + trunk = nm_setting_ovs_port_get_trunk(NM_SETTING_OVS_PORT(setting), idx); + s = nm_range_to_str(trunk); + nm_utils_escaped_tokens_escape_gstr_assert(s, ESCAPED_TOKENS_DELIMITERS, str); +} + static void _objlist_obj_to_str_fcn_bridge_vlans(NMMetaAccessorGetType get_type, NMSetting *setting, @@ -3835,6 +3849,37 @@ _objlist_set_fcn_tc_config_qdiscs(NMSetting *setting, return TRUE; } +static gboolean +_objlist_set_fcn_ovs_port_trunks(NMSetting *setting, + gboolean do_add, + const char *value, + GError **error) +{ + NMRange *range; + gs_free_error GError *local = NULL; + guint64 start; + guint64 end; + + range = nm_range_from_str(value, &local); + if (!range) { + nm_utils_error_set(error, + NM_UTILS_ERROR_INVALID_ARGUMENT, + "%s. %s", + local->message, + _("The valid syntax is: '' or '-")); + return FALSE; + } + + if (do_add) + nm_setting_ovs_port_add_trunk(NM_SETTING_OVS_PORT(setting), range); + else { + nm_range_get_range(range, &start, &end); + nm_setting_ovs_port_remove_trunk_by_value(NM_SETTING_OVS_PORT(setting), start, end); + } + + return TRUE; +} + static gboolean _objlist_set_fcn_bridge_vlans(NMSetting *setting, gboolean do_add, @@ -6836,6 +6881,17 @@ static const NMMetaPropertyInfo *const property_infos_OVS_PORT[] = { .values_static = NM_MAKE_STRV ("access", "native-tagged", "native-untagged", "trunk"), ), ), + PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PORT_TRUNKS, + .property_type = &_pt_objlist, + .property_typ_data = DEFINE_PROPERTY_TYP_DATA ( + PROPERTY_TYP_DATA_SUBTYPE (objlist, + .get_num_fcn = OBJLIST_GET_NUM_FCN (NMSettingOvsPort, nm_setting_ovs_port_get_num_trunks), + .clear_all_fcn = OBJLIST_CLEAR_ALL_FCN (NMSettingOvsPort, nm_setting_ovs_port_clear_trunks), + .obj_to_str_fcn = _objlist_obj_to_str_fcn_ovs_port_trunks, + .set_fcn = _objlist_set_fcn_ovs_port_trunks, + ), + ), + ), PROPERTY_INFO_WITH_DESC (NM_SETTING_OVS_PORT_TAG, .property_type = &_pt_gobject_int, ), diff --git a/src/libnmc-setting/settings-docs.h.in b/src/libnmc-setting/settings-docs.h.in index 2f2d561297..11806bf3ca 100644 --- a/src/libnmc-setting/settings-docs.h.in +++ b/src/libnmc-setting/settings-docs.h.in @@ -260,6 +260,7 @@ #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_BOND_UPDELAY N_("The time port must be active before it starts forwarding traffic.") #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_LACP N_("LACP mode. One of \"active\", \"off\", or \"passive\".") #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_TAG N_("The VLAN tag in the range 0-4095.") +#define DESCRIBE_DOC_NM_SETTING_OVS_PORT_TRUNKS N_("A list of VLAN ranges that this port trunks. The property is valid only for ports with mode \"trunk\", \"native-tagged\", or \"native-untagged port\". If it is empty, the port trunks all VLANs.") #define DESCRIBE_DOC_NM_SETTING_OVS_PORT_VLAN_MODE N_("The VLAN mode. One of \"access\", \"native-tagged\", \"native-untagged\", \"trunk\" or unset.") #define DESCRIBE_DOC_NM_SETTING_PPP_BAUD N_("If non-zero, instruct pppd to set the serial port to the specified baudrate. This value should normally be left as 0 to automatically choose the speed.") #define DESCRIBE_DOC_NM_SETTING_PPP_CRTSCTS N_("If TRUE, specify that pppd should set the serial port to use hardware flow control with RTS and CTS signals. This value should normally be set to FALSE.") diff --git a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in index 41be4a8e8c..c85ef11947 100644 --- a/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in +++ b/src/nmcli/gen-metadata-nm-settings-nmcli.xml.in @@ -849,6 +849,8 @@ +