libnm: add ovs-port.trunks property

Add a new "ovs-port.trunks" property that indicates which VLANs are
trunked by the port.

At ovsdb level the property is just an array of integers; on the
command line, ovs-vsctl accepts ranges and expands them.

In NetworkManager the ovs-port setting stores the trunks directly as a
list of ranges.
This commit is contained in:
Beniamino Galvani 2022-11-18 17:43:57 +01:00
parent 041e38b151
commit b64e690db8
12 changed files with 614 additions and 15 deletions

View file

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

View file

@ -1898,6 +1898,10 @@
dbus-type="u"
gprop-type="guint"
/>
<property name="trunks"
dbus-type="aa{sv}"
gprop-type="GPtrArray"
/>
<property name="vlan-mode"
dbus-type="s"
gprop-type="gchararray"

View file

@ -1597,6 +1597,18 @@ _normalize_bridge_port_vlan_order(NMConnection *self)
return _nm_setting_bridge_port_sort_vlans(s_port);
}
static gboolean
_normalize_ovs_port_trunks(NMConnection *self)
{
NMSettingOvsPort *s_ovs_port;
s_ovs_port = nm_connection_get_setting_ovs_port(self);
if (!s_ovs_port)
return FALSE;
return _nm_setting_ovs_port_sort_trunks(s_ovs_port);
}
static gboolean
_normalize_gsm_auto_config(NMConnection *self)
{
@ -1989,6 +2001,7 @@ _connection_normalize(NMConnection *connection,
was_modified |= _normalize_bridge_port_vlan_order(connection);
was_modified |= _normalize_gsm_auto_config(connection);
was_modified |= _normalize_802_1x_empty_strings(connection);
was_modified |= _normalize_ovs_port_trunks(connection);
was_modified = !!was_modified;

View file

@ -2007,6 +2007,44 @@ bridge_vlan_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key)
g_object_set(setting, key, vlans, NULL);
}
static void
range_list_parser(KeyfileReaderInfo *info, NMSetting *setting, const char *key)
{
gs_unref_ptrarray GPtrArray *ranges = NULL;
gs_free char *value = NULL;
gs_free const char **strv = NULL;
const char *const *iter;
GError *local = NULL;
NMRange *range;
value = nm_keyfile_plugin_kf_get_string(info->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,

View file

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

View file

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

View file

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

View file

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

View file

@ -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__ */

View file

@ -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: '<value>' or '<start>-<end>"));
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,
),

View file

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

View file

@ -849,6 +849,8 @@
<setting name="ovs-port" >
<property name="vlan-mode"
description="The VLAN mode. One of &quot;access&quot;, &quot;native-tagged&quot;, &quot;native-untagged&quot;, &quot;trunk&quot; or unset." />
<property name="trunks"
description="A list of VLAN ranges that this port trunks. The property is valid only for ports with mode &quot;trunk&quot;, &quot;native-tagged&quot;, or &quot;native-untagged port&quot;. If it is empty, the port trunks all VLANs." />
<property name="tag"
description="The VLAN tag in the range 0-4095." />
<property name="lacp"