diff options
Diffstat (limited to 'libnm-core/nm-team-utils.c')
| -rw-r--r-- | libnm-core/nm-team-utils.c | 2866 |
1 files changed, 0 insertions, 2866 deletions
diff --git a/libnm-core/nm-team-utils.c b/libnm-core/nm-team-utils.c deleted file mode 100644 index b7da35aa..00000000 --- a/libnm-core/nm-team-utils.c +++ /dev/null @@ -1,2866 +0,0 @@ -/* SPDX-License-Identifier: LGPL-2.1-or-later */ -/* - * Copyright (C) 2019 Red Hat, Inc. - */ - -#define NM_VALUE_TYPE_DEFINE_FUNCTIONS - -#include "libnm-core/nm-default-libnm-core.h" - -#include "nm-team-utils.h" - -#include "nm-errors.h" -#include "nm-utils-private.h" -#include "nm-glib-aux/nm-json-aux.h" -#include "nm-core-internal.h" -#include "nm-setting-team.h" -#include "nm-setting-team-port.h" - -/*****************************************************************************/ - -typedef enum { - SET_FIELD_MODE_UNSET = 0, - SET_FIELD_MODE_SET = 1, - - /* Sets the field as set, unless the field is at the default. - * This is the case for API that is called from NMSettingTeam/NMSettingTeamPort. - * This means, using libnm API to reset the value of a NMSetting to the default, - * will mark the field as unset. - * This is different from initializing the field when parsing JSON/GVariant. In - * that case an explicitly set field (even set to the default value) will be remembered - * to be set. */ - SET_FIELD_MODE_SET_UNLESS_DEFAULT = 2, -} SetFieldModeEnum; - -typedef enum { - RESET_JSON_NO = FALSE, - RESET_JSON_YES = TRUE, -} ResetJsonEnum; - -/* we rely on "config" being the first. At various places we iterate over attribute types, - * starting after "config".*/ -G_STATIC_ASSERT(_NM_TEAM_ATTRIBUTE_0 == 0); -G_STATIC_ASSERT(NM_TEAM_ATTRIBUTE_CONFIG == 1); - -static const char *const _valid_names_runner[] = { - NM_SETTING_TEAM_RUNNER_BROADCAST, - NM_SETTING_TEAM_RUNNER_ROUNDROBIN, - NM_SETTING_TEAM_RUNNER_RANDOM, - NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP, - NM_SETTING_TEAM_RUNNER_LOADBALANCE, - NM_SETTING_TEAM_RUNNER_LACP, - NULL, -}; - -static const char *const _valid_names_runner_hwaddr_policy[] = { - NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_SAME_ALL, - NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_BY_ACTIVE, - NM_SETTING_TEAM_RUNNER_HWADDR_POLICY_ONLY_ACTIVE, - NULL, -}; - -static const char *const _valid_names_runner_tx_balancer[] = { - "basic", - NULL, -}; - -static const char *const _valid_names_runner_tx_hash[] = { - "eth", - "vlan", - "ipv4", - "ipv6", - "ip", - "l3", - "l4", - "tcp", - "udp", - "sctp", - NULL, -}; - -static const char *const _valid_names_runner_agg_select_policy[] = { - "lacp_prio", - "lacp_prio_stable", - "bandwidth", - "count", - "port_config", - NULL, -}; - -typedef struct { - NMTeamAttribute team_attr; - const char *const *valid_runners; -} RunnerCompatElem; - -static const RunnerCompatElem _runner_compat_lst[] = { - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_ACTIVEBACKUP), - }, - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_LOADBALANCE, NM_SETTING_TEAM_RUNNER_LACP), - }, - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_LOADBALANCE, NM_SETTING_TEAM_RUNNER_LACP), - }, - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_LOADBALANCE, NM_SETTING_TEAM_RUNNER_LACP), - }, - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_LACP), - }, - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_LACP), - }, - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_LACP), - }, - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_LACP), - }, - { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY, - NM_MAKE_STRV(NM_SETTING_TEAM_RUNNER_LACP), - }, -}; - -typedef struct { - const char *const *js_keys; - const char * property_name; - NMValueTypUnion default_val; - union { - struct { - gint32 min; - gint32 max; - } r_int32; - struct { - const char *const *valid_names; - } r_string; - } range; - NMTeamAttribute team_attr; - NMValueType value_type; - guint8 field_offset; - guint8 js_keys_len; - bool for_master : 1; - bool for_port : 1; - bool has_range : 1; -} TeamAttrData; - -#define TEAM_ATTR_IDX(_is_port, _team_attr) \ - (((!(_is_port) || (_team_attr) < _NM_TEAM_ATTRIBUTE_START) \ - ? (int) (_team_attr) \ - : (((int) (_NM_TEAM_ATTRIBUTE_MASTER_NUM - _NM_TEAM_ATTRIBUTE_START)) \ - + ((int) (_team_attr)))) \ - - 1) - -#define TEAM_ATTR_IDX_CONFIG (TEAM_ATTR_IDX(FALSE, NM_TEAM_ATTRIBUTE_CONFIG)) - -static const TeamAttrData team_attr_datas[] = { - -#define _JS_KEYS(...) .js_keys = NM_MAKE_STRV(__VA_ARGS__), .js_keys_len = NM_NARG(__VA_ARGS__) - -#define _VAL_BOOL(_default) .default_val.v_bool = (_default) - -#define _VAL_INT32(_default) .default_val.v_int32 = (_default) - -#define _VAL_INT32_RANGE(_default, _min, _max) \ - _VAL_INT32(_default), .has_range = TRUE, \ - .range.r_int32 = { \ - .min = _min, \ - .max = _max, \ - } - -#define _VAL_STRING() .default_val.v_string = NULL - -#define _VAL_STRING_RANGE(_valid_names) \ - _VAL_STRING(), .has_range = TRUE, \ - .range.r_string = { \ - .valid_names = (_valid_names), \ - } - -#define _VAL_UNSPEC() .default_val.v_string = (NULL) - -#define _INIT(_is_port, _team_attr, field, _value_type, _property_name, ...) \ - [TEAM_ATTR_IDX(_is_port, _team_attr)] = { \ - .for_master = (_team_attr) < _NM_TEAM_ATTRIBUTE_START || !(_is_port), \ - .for_port = (_team_attr) < _NM_TEAM_ATTRIBUTE_START || (_is_port), \ - .team_attr = (_team_attr), \ - .field_offset = G_STRUCT_OFFSET(NMTeamSetting, _data_priv.field), \ - .value_type = (_value_type), \ - .property_name = ""_property_name \ - "", \ - __VA_ARGS__} - - _INIT(0, NM_TEAM_ATTRIBUTE_CONFIG, _js_str, NM_VALUE_TYPE_UNSPEC, NM_SETTING_TEAM_CONFIG, ), - - _INIT(0, - NM_TEAM_ATTRIBUTE_LINK_WATCHERS, - link_watchers, - NM_VALUE_TYPE_UNSPEC, - NM_SETTING_TEAM_LINK_WATCHERS, - _JS_KEYS("link_watch"), - _VAL_UNSPEC(), ), - - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT, - master.notify_peers_count, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_NOTIFY_PEERS_COUNT, - _JS_KEYS("notify_peers", "count"), - _VAL_INT32_RANGE(-1, 0, G_MAXINT32), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL, - master.notify_peers_interval, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_NOTIFY_PEERS_INTERVAL, - _JS_KEYS("notify_peers", "interval"), - _VAL_INT32_RANGE(-1, 0, G_MAXINT32), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT, - master.mcast_rejoin_count, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_MCAST_REJOIN_COUNT, - _JS_KEYS("mcast_rejoin", "count"), - _VAL_INT32_RANGE(-1, 0, G_MAXINT32), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL, - master.mcast_rejoin_interval, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_MCAST_REJOIN_INTERVAL, - _JS_KEYS("mcast_rejoin", "interval"), - _VAL_INT32_RANGE(-1, 0, G_MAXINT32), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER, - master.runner, - NM_VALUE_TYPE_STRING, - NM_SETTING_TEAM_RUNNER, - _JS_KEYS("runner", "name"), - _VAL_STRING_RANGE(_valid_names_runner), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY, - master.runner_hwaddr_policy, - NM_VALUE_TYPE_STRING, - NM_SETTING_TEAM_RUNNER_HWADDR_POLICY, - _JS_KEYS("runner", "hwaddr_policy"), - _VAL_STRING_RANGE(_valid_names_runner_hwaddr_policy), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, - master.runner_tx_hash, - NM_VALUE_TYPE_UNSPEC, - NM_SETTING_TEAM_RUNNER_TX_HASH, - _JS_KEYS("runner", "tx_hash"), - _VAL_UNSPEC(), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER, - master.runner_tx_balancer, - NM_VALUE_TYPE_STRING, - NM_SETTING_TEAM_RUNNER_TX_BALANCER, - _JS_KEYS("runner", "tx_balancer", "name"), - _VAL_STRING_RANGE(_valid_names_runner_tx_balancer), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL, - master.runner_tx_balancer_interval, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_RUNNER_TX_BALANCER_INTERVAL, - _JS_KEYS("runner", "tx_balancer", "balancing_interval"), - _VAL_INT32_RANGE(-1, 0, G_MAXINT32), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE, - master.runner_active, - NM_VALUE_TYPE_BOOL, - NM_SETTING_TEAM_RUNNER_ACTIVE, - _JS_KEYS("runner", "active"), - _VAL_BOOL(TRUE), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE, - master.runner_fast_rate, - NM_VALUE_TYPE_BOOL, - NM_SETTING_TEAM_RUNNER_FAST_RATE, - _JS_KEYS("runner", "fast_rate"), - _VAL_BOOL(FALSE), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO, - master.runner_sys_prio, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_RUNNER_SYS_PRIO, - _JS_KEYS("runner", "sys_prio"), - _VAL_INT32_RANGE(-1, 0, USHRT_MAX + 1), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS, - master.runner_min_ports, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_RUNNER_MIN_PORTS, - _JS_KEYS("runner", "min_ports"), - _VAL_INT32_RANGE(-1, 1, UCHAR_MAX + 1), ), - _INIT(0, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY, - master.runner_agg_select_policy, - NM_VALUE_TYPE_STRING, - NM_SETTING_TEAM_RUNNER_AGG_SELECT_POLICY, - _JS_KEYS("runner", "agg_select_policy"), - _VAL_STRING_RANGE(_valid_names_runner_agg_select_policy), ), - - _INIT(1, - NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID, - port.queue_id, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_PORT_QUEUE_ID, - _JS_KEYS("queue_id"), - _VAL_INT32_RANGE(-1, 0, G_MAXINT32), ), - _INIT(1, - NM_TEAM_ATTRIBUTE_PORT_PRIO, - port.prio, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_PORT_PRIO, - _JS_KEYS("prio"), - _VAL_INT32(0), ), - _INIT(1, - NM_TEAM_ATTRIBUTE_PORT_STICKY, - port.sticky, - NM_VALUE_TYPE_BOOL, - NM_SETTING_TEAM_PORT_STICKY, - _JS_KEYS("sticky"), - _VAL_BOOL(FALSE), ), - _INIT(1, - NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO, - port.lacp_prio, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_PORT_LACP_PRIO, - _JS_KEYS("lacp_prio"), - _VAL_INT32_RANGE(-1, 0, USHRT_MAX + 1), ), - _INIT(1, - NM_TEAM_ATTRIBUTE_PORT_LACP_KEY, - port.lacp_key, - NM_VALUE_TYPE_INT32, - NM_SETTING_TEAM_PORT_LACP_KEY, - _JS_KEYS("lacp_key"), - _VAL_INT32_RANGE(-1, 0, USHRT_MAX + 1), ), - -#undef _INIT -}; - -/*****************************************************************************/ - -typedef enum { - LINK_WATCHER_ATTRIBUTE_NAME, - LINK_WATCHER_ATTRIBUTE_DELAY_UP, - LINK_WATCHER_ATTRIBUTE_DELAY_DOWN, - LINK_WATCHER_ATTRIBUTE_INTERVAL, - LINK_WATCHER_ATTRIBUTE_INIT_WAIT, - LINK_WATCHER_ATTRIBUTE_MISSED_MAX, - LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, - LINK_WATCHER_ATTRIBUTE_TARGET_HOST, - LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, - LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, - LINK_WATCHER_ATTRIBUTE_VLANID, - LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS, -} LinkWatcherAttribute; - -#define _EXPECTED_LINK_WATCHER_ATTRIBUTES_ETHTOOL \ - LINK_WATCHER_ATTRIBUTE_NAME, LINK_WATCHER_ATTRIBUTE_DELAY_UP, LINK_WATCHER_ATTRIBUTE_DELAY_DOWN -#define _EXPECTED_LINK_WATCHER_ATTRIBUTES_NSNA_PING \ - LINK_WATCHER_ATTRIBUTE_NAME, LINK_WATCHER_ATTRIBUTE_INTERVAL, \ - LINK_WATCHER_ATTRIBUTE_INIT_WAIT, LINK_WATCHER_ATTRIBUTE_MISSED_MAX, \ - LINK_WATCHER_ATTRIBUTE_TARGET_HOST -#define _EXPECTED_LINK_WATCHER_ATTRIBUTES_ARP_PING \ - LINK_WATCHER_ATTRIBUTE_NAME, LINK_WATCHER_ATTRIBUTE_INTERVAL, \ - LINK_WATCHER_ATTRIBUTE_INIT_WAIT, LINK_WATCHER_ATTRIBUTE_MISSED_MAX, \ - LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, LINK_WATCHER_ATTRIBUTE_TARGET_HOST, \ - LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, \ - LINK_WATCHER_ATTRIBUTE_VLANID, LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS - -typedef struct { - const char * js_key; - const char * dbus_name; - NMValueTypUnion default_val; - LinkWatcherAttribute link_watcher_attr; - NMValueType value_type; -} LinkWatcherAttrData; - -static const LinkWatcherAttrData link_watcher_attr_datas[] = { -#define _INIT(_link_watcher_attr, _js_key, _dbus_name, _value_type, ...) \ - [_link_watcher_attr] = {.link_watcher_attr = (_link_watcher_attr), \ - .value_type = (_value_type), \ - .js_key = (""_js_key \ - ""), \ - .dbus_name = (""_dbus_name \ - ""), \ - __VA_ARGS__} - _INIT(LINK_WATCHER_ATTRIBUTE_NAME, "name", "name", NM_VALUE_TYPE_STRING, ), - _INIT(LINK_WATCHER_ATTRIBUTE_DELAY_UP, "delay_up", "delay-up", NM_VALUE_TYPE_INT, ), - _INIT(LINK_WATCHER_ATTRIBUTE_DELAY_DOWN, "delay_down", "delay-down", NM_VALUE_TYPE_INT, ), - _INIT(LINK_WATCHER_ATTRIBUTE_INTERVAL, "interval", "interval", NM_VALUE_TYPE_INT, ), - _INIT(LINK_WATCHER_ATTRIBUTE_INIT_WAIT, "init_wait", "init-wait", NM_VALUE_TYPE_INT, ), - _INIT(LINK_WATCHER_ATTRIBUTE_MISSED_MAX, - "missed_max", - "missed-max", - NM_VALUE_TYPE_INT, - .default_val.v_int = 3, ), - _INIT(LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, "source_host", "source-host", NM_VALUE_TYPE_STRING, ), - _INIT(LINK_WATCHER_ATTRIBUTE_TARGET_HOST, "target_host", "target-host", NM_VALUE_TYPE_STRING, ), - _INIT(LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, - "validate_active", - "validate-active", - NM_VALUE_TYPE_BOOL, ), - _INIT(LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, - "validate_inactive", - "validate-inactive", - NM_VALUE_TYPE_BOOL, ), - _INIT(LINK_WATCHER_ATTRIBUTE_VLANID, - "vlanid", - "vlanid", - NM_VALUE_TYPE_INT, - .default_val.v_int = -1, ), - _INIT(LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS, "send_always", "send-always", NM_VALUE_TYPE_BOOL, ), -#undef _INIT -}; - -/*****************************************************************************/ - -static const TeamAttrData *_team_attr_data_get(gboolean is_port, NMTeamAttribute team_attr); -static gpointer _team_setting_get_field(const NMTeamSetting *self, const TeamAttrData *attr_data); -static void _link_watcher_to_json(const NMTeamLinkWatcher *link_watcher, GString *gstr); - -/*****************************************************************************/ - -static void -_team_attr_data_ASSERT(const TeamAttrData *attr_data) -{ -#if NM_MORE_ASSERTS > 5 - nm_assert(attr_data); - if (attr_data->for_port) - nm_assert(attr_data == _team_attr_data_get(TRUE, attr_data->team_attr)); - if (attr_data->for_master) - nm_assert(attr_data == _team_attr_data_get(FALSE, attr_data->team_attr)); - nm_assert((attr_data - team_attr_datas) - == TEAM_ATTR_IDX(attr_data->for_port, attr_data->team_attr)); - nm_assert(attr_data->value_type > 0); - nm_assert(attr_data->field_offset < sizeof(NMTeamSetting)); - nm_assert(attr_data->js_keys_len == NM_PTRARRAY_LEN(attr_data->js_keys)); - nm_assert(attr_data->property_name); - { - static int checked = 0; - - if (checked == 0) { - checked = 1; - - for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; - attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) - _team_attr_data_ASSERT(attr_data); - } - } -#endif -} - -static gboolean -_team_attr_data_is_relevant(const TeamAttrData *attr_data, gboolean is_port) -{ - return is_port ? attr_data->for_port : attr_data->for_master; -} - -static const TeamAttrData * -_team_attr_data_get(gboolean is_port, NMTeamAttribute team_attr) -{ - const int idx = TEAM_ATTR_IDX(is_port, team_attr); - - nm_assert(idx >= 0 && idx < G_N_ELEMENTS(team_attr_datas)); - nm_assert(team_attr_datas[idx].team_attr == team_attr); - nm_assert(_team_attr_data_is_relevant(&team_attr_datas[idx], is_port)); - - return &team_attr_datas[idx]; -} - -static const TeamAttrData * -_team_attr_data_find_for_property_name(gboolean is_port, const char *property_name) -{ - const TeamAttrData *attr_data; - - for (attr_data = team_attr_datas; attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) { - if (_team_attr_data_is_relevant(attr_data, is_port) - && nm_streq(property_name, attr_data->property_name)) - return attr_data; - } - return NULL; -} - -static int -_team_attr_data_cmp(const TeamAttrData *attr_data, - gboolean is_port, - gconstpointer val_a, - gconstpointer val_b) -{ - const GPtrArray *v_ptrarray_a; - const GPtrArray *v_ptrarray_b; - guint len; - - _team_attr_data_ASSERT(attr_data); - nm_assert(val_a); - nm_assert(val_b); - - if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) - NM_CMP_RETURN(nm_value_type_cmp(attr_data->value_type, val_a, val_b)); - else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) { - v_ptrarray_a = *((const GPtrArray *const *) val_a); - v_ptrarray_b = *((const GPtrArray *const *) val_b); - len = v_ptrarray_a ? v_ptrarray_a->len : 0u; - NM_CMP_DIRECT(len, (v_ptrarray_b ? v_ptrarray_b->len : 0u)); - if (len > 0) { - NM_CMP_RETURN( - nm_team_link_watchers_cmp((const NMTeamLinkWatcher *const *) v_ptrarray_a->pdata, - (const NMTeamLinkWatcher *const *) v_ptrarray_b->pdata, - len, - FALSE)); - } - } else if (!is_port && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { - v_ptrarray_a = *((const GPtrArray *const *) val_a); - v_ptrarray_b = *((const GPtrArray *const *) val_b); - NM_CMP_RETURN( - nm_utils_strv_cmp_n(v_ptrarray_a ? (const char *const *) v_ptrarray_a->pdata : NULL, - v_ptrarray_a ? v_ptrarray_a->len : 0u, - v_ptrarray_b ? (const char *const *) v_ptrarray_b->pdata : NULL, - v_ptrarray_b ? v_ptrarray_b->len : 0u)); - } else - nm_assert_not_reached(); - return 0; -} - -static gboolean -_team_attr_data_equal(const TeamAttrData *attr_data, - gboolean is_port, - gconstpointer val_a, - gconstpointer val_b) -{ - return _team_attr_data_cmp(attr_data, is_port, val_a, val_b) == 0; -} - -static void -_team_attr_data_copy(const TeamAttrData *attr_data, - gboolean is_port, - gpointer dst, - gconstpointer src) -{ - GPtrArray * v_ptrarray_dst; - const GPtrArray *v_ptrarray_src; - GPtrArray * dst_array; - guint i, len; - - if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) - nm_value_type_copy(attr_data->value_type, dst, src); - else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) { - v_ptrarray_src = *((const GPtrArray *const *) src); - v_ptrarray_dst = *((GPtrArray **) dst); - len = (v_ptrarray_src ? v_ptrarray_src->len : 0u); - - if (len == 0) { - if (v_ptrarray_dst) - g_ptr_array_set_size(v_ptrarray_dst, 0); - } else { - dst_array = g_ptr_array_new_full(len, (GDestroyNotify) nm_team_link_watcher_unref); - for (i = 0; i < len; i++) { - if (v_ptrarray_src->pdata[i]) { - nm_team_link_watcher_ref(v_ptrarray_src->pdata[i]); - g_ptr_array_add(dst_array, v_ptrarray_src->pdata[i]); - } - } - if (v_ptrarray_dst) - g_ptr_array_unref(v_ptrarray_dst); - *((GPtrArray **) dst) = dst_array; - } - } else if (!is_port && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { - v_ptrarray_src = *((const GPtrArray *const *) src); - v_ptrarray_dst = *((GPtrArray **) dst); - len = (v_ptrarray_src ? v_ptrarray_src->len : 0u); - - if (v_ptrarray_src && v_ptrarray_src->len > 0) { - dst_array = g_ptr_array_new_full(v_ptrarray_src->len, g_free); - for (i = 0; i < v_ptrarray_src->len; i++) - g_ptr_array_add(dst_array, g_strdup(v_ptrarray_src->pdata[i])); - } else - dst_array = NULL; - if (v_ptrarray_dst) - g_ptr_array_unref(v_ptrarray_dst); - *((GPtrArray **) dst) = dst_array; - } else - nm_assert_not_reached(); -} - -static void -_team_attr_data_to_json(const TeamAttrData *attr_data, - gboolean is_port, - GString * gstr, - gconstpointer p_field) -{ - guint i; - - _team_attr_data_ASSERT(attr_data); - nm_assert(p_field); - - nm_json_gstr_append_obj_name(gstr, attr_data->js_keys[attr_data->js_keys_len - 1], '\0'); - - if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) { - nm_value_type_to_json(attr_data->value_type, gstr, p_field); - return; - } - - if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) { - const GPtrArray *v_ptrarray = *((const GPtrArray *const *) p_field); - - if (!v_ptrarray) - g_string_append(gstr, "null"); - else if (v_ptrarray->len == 0) - g_string_append(gstr, "[ ]"); - else if (v_ptrarray->len == 1) - _link_watcher_to_json(v_ptrarray->pdata[0], gstr); - else { - g_string_append(gstr, "[ "); - for (i = 0; i < v_ptrarray->len; i++) { - if (i > 0) - nm_json_gstr_append_delimiter(gstr); - _link_watcher_to_json(v_ptrarray->pdata[i], gstr); - } - g_string_append(gstr, " ]"); - } - return; - } - - if (!is_port && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { - const GPtrArray *v_ptrarray = *((const GPtrArray *const *) p_field); - - if (!v_ptrarray) - g_string_append(gstr, "null"); - else { - g_string_append(gstr, "[ "); - for (i = 0; i < v_ptrarray->len; i++) { - if (i > 0) - nm_json_gstr_append_delimiter(gstr); - nm_json_gstr_append_string(gstr, v_ptrarray->pdata[i]); - } - g_string_append(gstr, i > 0 ? " ]" : "]"); - } - return; - } - - nm_assert_not_reached(); -} - -/*****************************************************************************/ - -static void -_team_setting_ASSERT(const NMTeamSetting *self) -{ - nm_assert(self); - nm_assert(!self->d._js_str_need_synthetize || !self->d._js_str); -#if NM_MORE_ASSERTS > 2 - if (!self->d.strict_validated) { - nm_assert(!self->d._js_str_need_synthetize); - nm_assert(self->d._js_str); - } - nm_assert(self->d.link_watchers); - nm_assert(self->d.is_port || !self->d.master.runner_tx_hash - || self->d.master.runner_tx_hash->len > 0); -#endif -} - -static gboolean -_team_setting_has_field(const NMTeamSetting *self, const TeamAttrData *attr_data) -{ - _team_setting_ASSERT(self); - return NM_FLAGS_ALL(self->d.has_fields_mask, nm_team_attribute_to_flags(attr_data->team_attr)); -} - -static gboolean -_team_setting_has_fields_any_v(const NMTeamSetting * self, - const NMTeamAttribute *team_attrs, - gsize n_team_attrs) -{ - gsize i; - - for (i = 0; i < n_team_attrs; i++) { - const TeamAttrData *attr_data = _team_attr_data_get(self->d.is_port, team_attrs[i]); - - if (_team_setting_has_field(self, attr_data)) - return TRUE; - } - return FALSE; -} - -#define _team_setting_has_fields_any(self, ...) \ - _team_setting_has_fields_any_v((self), \ - ((const NMTeamAttribute[]){__VA_ARGS__}), \ - NM_NARG(__VA_ARGS__)) - -static void -_team_setting_has_field_set(NMTeamSetting * self, - const TeamAttrData *attr_data, - SetFieldModeEnum set_field_mode) -{ - guint32 mask = nm_team_attribute_to_flags(attr_data->team_attr); - - _team_setting_ASSERT(self); - - switch (set_field_mode) { - case SET_FIELD_MODE_UNSET: - goto do_unset; - case SET_FIELD_MODE_SET: - goto do_set; - case SET_FIELD_MODE_SET_UNLESS_DEFAULT: - if (_team_attr_data_equal(attr_data, - self->d.is_port, - _team_setting_get_field(self, attr_data), - &attr_data->default_val)) - goto do_unset; - goto do_set; - } - nm_assert_not_reached(); - -do_unset: - self->_data_priv.has_fields_mask &= ~mask; - return; -do_set: - self->_data_priv.has_fields_mask |= mask; -} - -static gpointer -_team_setting_get_field(const NMTeamSetting *self, const TeamAttrData *attr_data) -{ - _team_setting_ASSERT(self); - _team_attr_data_ASSERT(attr_data); - nm_assert(_team_attr_data_is_relevant(attr_data, self->d.is_port)); - -#if NM_MORE_ASSERTS > 5 - if (attr_data->for_master && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO) - nm_assert((gpointer)(((char *) self) + attr_data->field_offset) - == &self->d.master.runner_sys_prio); -#endif - - return (((char *) self) + attr_data->field_offset); -} - -static guint32 -_team_setting_attribute_changed(NMTeamSetting * self, - const TeamAttrData *attr_data, - gboolean changed, - SetFieldModeEnum set_field_mode, - ResetJsonEnum reset_json) -{ - guint32 changed_flags; - - _team_setting_has_field_set(self, attr_data, set_field_mode); - - if (!reset_json) { - return changed ? nm_team_attribute_to_flags(attr_data->team_attr) : 0u; - } - - if (!changed) { - /* a regular attribute was set, but the value did not change. - * - * If we previously were in non-strict mode, then - * - * - switch to strict-mode. Clearly the user set a regular attribute - * and hence now we want to validate the setting. - * - * - clear the JSON string. We need to regenerate it. - */ - if (self->_data_priv.strict_validated) - return 0; - changed_flags = nm_team_attribute_to_flags(NM_TEAM_ATTRIBUTE_CONFIG); - } else { - changed_flags = nm_team_attribute_to_flags(attr_data->team_attr) - | nm_team_attribute_to_flags(NM_TEAM_ATTRIBUTE_CONFIG); - } - - nm_clear_g_free((char **) &self->_data_priv._js_str); - self->_data_priv.strict_validated = TRUE; - self->_data_priv._js_str_need_synthetize = TRUE; - - return changed_flags; -} - -static guint32 -_team_setting_attribute_changed_attr(NMTeamSetting * self, - NMTeamAttribute team_attr, - gboolean changed, - SetFieldModeEnum set_field_mode, - ResetJsonEnum reset_json) -{ - return _team_setting_attribute_changed(self, - _team_attr_data_get(self->d.is_port, team_attr), - changed, - set_field_mode, - reset_json); -} - -static gboolean -_team_setting_field_to_json(const NMTeamSetting *self, - GString * gstr, - gboolean prepend_delimiter, - const TeamAttrData * attr_data) -{ - if (!_team_setting_has_field(self, attr_data)) - return FALSE; - - if (prepend_delimiter) - nm_json_gstr_append_delimiter(gstr); - _team_attr_data_to_json(attr_data, - self->d.is_port, - gstr, - _team_setting_get_field(self, attr_data)); - return TRUE; -} - -static gboolean -_team_setting_fields_to_json_maybe(const NMTeamSetting * self, - GString * gstr, - gboolean prepend_delimiter, - const NMTeamAttribute *team_attrs_lst, - gsize team_attrs_lst_len) -{ - gsize i; - gboolean any_added = FALSE; - - for (i = 0; i < team_attrs_lst_len; i++) { - if (_team_setting_field_to_json(self, - gstr, - prepend_delimiter, - _team_attr_data_get(self->d.is_port, team_attrs_lst[i]))) { - any_added = TRUE; - prepend_delimiter = TRUE; - } - } - return any_added; -} - -static guint32 -_team_setting_set(NMTeamSetting * self, - gboolean modify, - const bool * has_lst, - const NMValueTypUnion *val_lst) -{ - guint32 changed_flags = 0; - const TeamAttrData *attr_data; - - nm_assert((!has_lst) == (!val_lst)); - - for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; - attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) { - const NMValueTypUnion *p_val; - gconstpointer p_field; - gboolean has_field; - - if (!_team_attr_data_is_relevant(attr_data, self->d.is_port)) - continue; - - has_field = (has_lst && has_lst[attr_data->team_attr]); - - p_val = has_field ? &val_lst[attr_data->team_attr] : &attr_data->default_val; - - p_field = _team_setting_get_field(self, attr_data); - - if (!_team_attr_data_equal(attr_data, self->d.is_port, p_val, p_field)) { - if (modify) { - _team_attr_data_copy(attr_data, self->d.is_port, (gpointer) p_field, p_val); - } - changed_flags |= nm_team_attribute_to_flags(attr_data->team_attr); - } - - if (modify) { - _team_setting_has_field_set(self, - attr_data, - has_field ? SET_FIELD_MODE_SET : SET_FIELD_MODE_UNSET); - } - } - - return changed_flags; -} - -static guint32 -_team_setting_check_default(const NMTeamSetting *self) -{ - return _team_setting_set((NMTeamSetting *) self, FALSE, NULL, NULL); -} - -static guint32 -_team_setting_set_default(NMTeamSetting *self) -{ - return _team_setting_set(self, TRUE, NULL, NULL); -} - -/*****************************************************************************/ - -gconstpointer -_nm_team_setting_value_get(const NMTeamSetting *self, - NMTeamAttribute team_attr, - NMValueType value_type) -{ - const TeamAttrData *attr_data = _team_attr_data_get(self->d.is_port, team_attr); - - nm_assert(value_type == attr_data->value_type); - - nm_assert(_team_setting_has_field(self, attr_data) - || _team_attr_data_equal(attr_data, - self->d.is_port, - _team_setting_get_field(self, attr_data), - &attr_data->default_val)); - return _team_setting_get_field(self, attr_data); -} - -static guint32 -_team_setting_value_set(NMTeamSetting * self, - const TeamAttrData *attr_data, - gconstpointer val, - SetFieldModeEnum set_field_mode, - ResetJsonEnum reset_json) -{ - gpointer p_field; - gboolean changed; - - nm_assert(self); - _team_attr_data_ASSERT(attr_data); - nm_assert(val); - - p_field = _team_setting_get_field(self, attr_data); - - changed = !_team_attr_data_equal(attr_data, self->d.is_port, p_field, val); - if (changed) - nm_value_type_copy(attr_data->value_type, p_field, val); - return _team_setting_attribute_changed(self, attr_data, changed, set_field_mode, reset_json); -} - -guint32 -nm_team_setting_value_reset(NMTeamSetting * self, - NMTeamAttribute team_attr, - gboolean to_default /* or else unset */) -{ - const TeamAttrData *attr_data; - - nm_assert(self); - - attr_data = _team_attr_data_get(self->d.is_port, team_attr); - - return _team_setting_value_set(self, - attr_data, - &attr_data->default_val, - to_default ? SET_FIELD_MODE_SET : SET_FIELD_MODE_UNSET, - RESET_JSON_YES); -} - -guint32 -_nm_team_setting_value_set(NMTeamSetting * self, - NMTeamAttribute team_attr, - NMValueType value_type, - gconstpointer val) -{ - const TeamAttrData *attr_data; - - nm_assert(self); - - attr_data = _team_attr_data_get(self->d.is_port, team_attr); - - nm_assert(value_type == attr_data->value_type); - - return _team_setting_value_set(self, - attr_data, - val, - SET_FIELD_MODE_SET_UNLESS_DEFAULT, - RESET_JSON_YES); -} - -guint32 -nm_team_setting_value_link_watchers_add(NMTeamSetting *self, const NMTeamLinkWatcher *link_watcher) -{ - guint i; - gboolean changed; - - for (i = 0; i < self->d.link_watchers->len; i++) { - if (nm_team_link_watcher_equal(self->d.link_watchers->pdata[i], link_watcher)) { - changed = FALSE; - goto out; - } - } - changed = TRUE; - g_ptr_array_add((GPtrArray *) self->d.link_watchers, - _nm_team_link_watcher_ref((NMTeamLinkWatcher *) link_watcher)); -out: - return _team_setting_attribute_changed_attr(self, - NM_TEAM_ATTRIBUTE_LINK_WATCHERS, - changed, - SET_FIELD_MODE_SET_UNLESS_DEFAULT, - RESET_JSON_YES); -} - -guint32 -nm_team_setting_value_link_watchers_remove_by_value(NMTeamSetting * self, - const NMTeamLinkWatcher *link_watcher) -{ - guint i; - - for (i = 0; i < self->d.link_watchers->len; i++) { - if (nm_team_link_watcher_equal(self->d.link_watchers->pdata[i], link_watcher)) - return nm_team_setting_value_link_watchers_remove(self, i); - } - return _team_setting_attribute_changed_attr(self, - NM_TEAM_ATTRIBUTE_LINK_WATCHERS, - FALSE, - SET_FIELD_MODE_SET_UNLESS_DEFAULT, - RESET_JSON_YES); -} - -guint32 -nm_team_setting_value_link_watchers_remove(NMTeamSetting *self, guint idx) -{ - g_ptr_array_remove_index((GPtrArray *) self->d.link_watchers, idx); - return _team_setting_attribute_changed_attr(self, - NM_TEAM_ATTRIBUTE_LINK_WATCHERS, - TRUE, - SET_FIELD_MODE_SET_UNLESS_DEFAULT, - RESET_JSON_YES); -} - -static guint32 -_team_setting_value_link_watchers_set_list(NMTeamSetting * self, - const NMTeamLinkWatcher *const *arr, - guint len, - SetFieldModeEnum set_field_mode, - ResetJsonEnum reset_json) -{ - gboolean changed; - - if (self->d.link_watchers->len == len - && nm_team_link_watchers_cmp( - (const NMTeamLinkWatcher *const *) self->d.link_watchers->pdata, - arr, - len, - FALSE) - == 0) { - changed = FALSE; - goto out; - } - - changed = TRUE; - if (len == 0) - g_ptr_array_set_size((GPtrArray *) self->d.link_watchers, 0); - else { - _nm_unused gs_unref_ptrarray GPtrArray *old_val_destroy = NULL; - guint i; - - old_val_destroy = (GPtrArray *) g_steal_pointer(&self->_data_priv.link_watchers); - - self->_data_priv.link_watchers = - g_ptr_array_new_with_free_func((GDestroyNotify) nm_team_link_watcher_unref); - - for (i = 0; i < len; i++) { - if (arr[i]) { - g_ptr_array_add((GPtrArray *) self->d.link_watchers, - _nm_team_link_watcher_ref((NMTeamLinkWatcher *) arr[i])); - } - } - } - -out: - return _team_setting_attribute_changed_attr(self, - NM_TEAM_ATTRIBUTE_LINK_WATCHERS, - changed, - set_field_mode, - reset_json); -} - -guint32 -nm_team_setting_value_link_watchers_set_list(NMTeamSetting * self, - const NMTeamLinkWatcher *const *arr, - guint len) -{ - return _team_setting_value_link_watchers_set_list(self, - arr, - len, - SET_FIELD_MODE_SET_UNLESS_DEFAULT, - RESET_JSON_YES); -} - -/*****************************************************************************/ - -guint32 -nm_team_setting_value_master_runner_tx_hash_add(NMTeamSetting *self, const char *txhash) -{ - gboolean changed; - guint i; - - if (!self->d.master.runner_tx_hash) - self->_data_priv.master.runner_tx_hash = g_ptr_array_new_with_free_func(g_free); - else { - for (i = 0; i < self->d.master.runner_tx_hash->len; i++) { - if (nm_streq(txhash, self->d.master.runner_tx_hash->pdata[i])) { - changed = FALSE; - goto out; - } - } - } - changed = TRUE; - g_ptr_array_add((GPtrArray *) self->d.master.runner_tx_hash, g_strdup(txhash)); -out: - return _team_setting_attribute_changed_attr(self, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, - changed, - SET_FIELD_MODE_SET_UNLESS_DEFAULT, - RESET_JSON_YES); -} - -guint32 -nm_team_setting_value_master_runner_tx_hash_remove(NMTeamSetting *self, guint idx) -{ - g_ptr_array_remove_index((GPtrArray *) self->d.master.runner_tx_hash, idx); - return _team_setting_attribute_changed_attr(self, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, - TRUE, - SET_FIELD_MODE_SET_UNLESS_DEFAULT, - RESET_JSON_YES); -} - -static guint32 -_team_setting_value_master_runner_tx_hash_set_list(NMTeamSetting * self, - const char *const *arr, - guint len, - SetFieldModeEnum set_field_mode, - ResetJsonEnum reset_json) -{ - _nm_unused gs_unref_ptrarray GPtrArray *old_val_destroy = NULL; - gboolean changed; - guint i; - - if (nm_utils_strv_cmp_n(self->d.master.runner_tx_hash - ? (const char *const *) self->d.master.runner_tx_hash->pdata - : NULL, - self->d.master.runner_tx_hash ? self->d.master.runner_tx_hash->len : 0u, - arr, - len) - == 0) { - changed = FALSE; - goto out; - } - - changed = TRUE; - - old_val_destroy = (GPtrArray *) g_steal_pointer(&self->_data_priv.master.runner_tx_hash); - - for (i = 0; i < len; i++) { - if (!arr[i]) - continue; - if (!self->d.master.runner_tx_hash) - self->_data_priv.master.runner_tx_hash = g_ptr_array_new_with_free_func(g_free); - g_ptr_array_add((GPtrArray *) self->d.master.runner_tx_hash, g_strdup(arr[i])); - } - -out: - return _team_setting_attribute_changed_attr(self, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, - changed, - set_field_mode, - reset_json); -} - -guint32 -nm_team_setting_value_master_runner_tx_hash_set_list(NMTeamSetting * self, - const char *const *arr, - guint len) -{ - return _team_setting_value_master_runner_tx_hash_set_list(self, - arr, - len, - SET_FIELD_MODE_SET_UNLESS_DEFAULT, - RESET_JSON_YES); -} - -/*****************************************************************************/ - -#define _LINK_WATCHER_ATTR_GET(args, link_watcher_attribute, _value_type) \ - ({ \ - const NMValueTypUnioMaybe *const _args = (args); \ - \ - nm_assert(link_watcher_attr_datas[(link_watcher_attribute)].value_type == (_value_type)); \ - \ - _args[(link_watcher_attribute)].has \ - ? &_args[(link_watcher_attribute)].val \ - : &link_watcher_attr_datas[(link_watcher_attribute)].default_val; \ - }) -#define _LINK_WATCHER_ATTR_GET_BOOL(args, link_watcher_attribute) \ - (_LINK_WATCHER_ATTR_GET(args, link_watcher_attribute, NM_VALUE_TYPE_BOOL)->v_bool) -#define _LINK_WATCHER_ATTR_GET_INT(args, link_watcher_attribute) \ - (_LINK_WATCHER_ATTR_GET(args, link_watcher_attribute, NM_VALUE_TYPE_INT)->v_int) -#define _LINK_WATCHER_ATTR_GET_STRING(args, link_watcher_attribute) \ - (_LINK_WATCHER_ATTR_GET(args, link_watcher_attribute, NM_VALUE_TYPE_STRING)->v_string) - -#define _LINK_WATCHER_ATTR_SET(args, link_watcher_attribute, _value_type, c_type, val) \ - ({ \ - nm_assert(link_watcher_attr_datas[(link_watcher_attribute)].value_type == (_value_type)); \ - \ - NM_VALUE_TYP_UNIO_MAYBE_SET(&(args)[(link_watcher_attribute)], c_type, (val)); \ - }) -#define _LINK_WATCHER_ATTR_SET_BOOL(args, link_watcher_attribute, val) \ - _LINK_WATCHER_ATTR_SET((args), (link_watcher_attribute), NM_VALUE_TYPE_BOOL, v_bool, (val)) -#define _LINK_WATCHER_ATTR_SET_INT(args, link_watcher_attribute, val) \ - _LINK_WATCHER_ATTR_SET((args), (link_watcher_attribute), NM_VALUE_TYPE_INT, v_int, (val)) -#define _LINK_WATCHER_ATTR_SET_STRING(args, link_watcher_attribute, val) \ - _LINK_WATCHER_ATTR_SET((args), (link_watcher_attribute), NM_VALUE_TYPE_STRING, v_string, (val)) - -static void -_link_watcher_unpack(const NMTeamLinkWatcher *link_watcher, - NMValueTypUnioMaybe args[static G_N_ELEMENTS(link_watcher_attr_datas)]) -{ - const char * v_name = nm_team_link_watcher_get_name(link_watcher); - NMTeamLinkWatcherArpPingFlags v_arp_ping_flags; - - memset(args, 0, sizeof(args[0]) * G_N_ELEMENTS(link_watcher_attr_datas)); - - _LINK_WATCHER_ATTR_SET_STRING(args, LINK_WATCHER_ATTRIBUTE_NAME, v_name); - - if (nm_streq(v_name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { - _LINK_WATCHER_ATTR_SET_INT(args, - LINK_WATCHER_ATTRIBUTE_DELAY_UP, - nm_team_link_watcher_get_delay_up(link_watcher)); - _LINK_WATCHER_ATTR_SET_INT(args, - LINK_WATCHER_ATTRIBUTE_DELAY_DOWN, - nm_team_link_watcher_get_delay_down(link_watcher)); - } else if (NM_IN_STRSET(v_name, - NM_TEAM_LINK_WATCHER_NSNA_PING, - NM_TEAM_LINK_WATCHER_ARP_PING)) { - _LINK_WATCHER_ATTR_SET_INT(args, - LINK_WATCHER_ATTRIBUTE_INIT_WAIT, - nm_team_link_watcher_get_init_wait(link_watcher)); - _LINK_WATCHER_ATTR_SET_INT(args, - LINK_WATCHER_ATTRIBUTE_INTERVAL, - nm_team_link_watcher_get_interval(link_watcher)); - _LINK_WATCHER_ATTR_SET_INT(args, - LINK_WATCHER_ATTRIBUTE_MISSED_MAX, - nm_team_link_watcher_get_missed_max(link_watcher)); - _LINK_WATCHER_ATTR_SET_STRING(args, - LINK_WATCHER_ATTRIBUTE_TARGET_HOST, - nm_team_link_watcher_get_target_host(link_watcher)); - if (nm_streq(v_name, NM_TEAM_LINK_WATCHER_ARP_PING)) { - v_arp_ping_flags = nm_team_link_watcher_get_flags(link_watcher); - _LINK_WATCHER_ATTR_SET_INT(args, - LINK_WATCHER_ATTRIBUTE_VLANID, - nm_team_link_watcher_get_vlanid(link_watcher)); - _LINK_WATCHER_ATTR_SET_STRING(args, - LINK_WATCHER_ATTRIBUTE_SOURCE_HOST, - nm_team_link_watcher_get_source_host(link_watcher)); - _LINK_WATCHER_ATTR_SET_BOOL( - args, - LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE, - NM_FLAGS_HAS(v_arp_ping_flags, NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE)); - _LINK_WATCHER_ATTR_SET_BOOL( - args, - LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE, - NM_FLAGS_HAS(v_arp_ping_flags, - NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE)); - _LINK_WATCHER_ATTR_SET_BOOL( - args, - LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS, - NM_FLAGS_HAS(v_arp_ping_flags, NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS)); - } - } -} - -static void -_link_watcher_to_json(const NMTeamLinkWatcher *link_watcher, GString *gstr) -{ - NMValueTypUnioMaybe args[G_N_ELEMENTS(link_watcher_attr_datas)]; - int i; - gboolean is_first = TRUE; - - if (!link_watcher) { - g_string_append(gstr, "null"); - return; - } - - _link_watcher_unpack(link_watcher, args); - - g_string_append(gstr, "{ "); - - for (i = 0; i < (int) G_N_ELEMENTS(link_watcher_attr_datas); i++) { - const NMValueTypUnioMaybe *p_val = &args[i]; - const LinkWatcherAttrData *attr_data = &link_watcher_attr_datas[i]; - - if (!p_val->has) - continue; - if (nm_value_type_equal(attr_data->value_type, &attr_data->default_val, &p_val->val)) - continue; - - if (is_first) - is_first = FALSE; - else - nm_json_gstr_append_delimiter(gstr); - nm_json_gstr_append_obj_name(gstr, attr_data->js_key, '\0'); - nm_value_type_to_json(attr_data->value_type, gstr, &p_val->val); - } - - g_string_append(gstr, " }"); -} - -static NMTeamLinkWatcher * -_link_watcher_from_json(const NMJsonVt * vt, - const nm_json_t *root_js_obj, - gboolean * out_unrecognized_content) -{ - NMValueTypUnioMaybe args[G_N_ELEMENTS(link_watcher_attr_datas)] = {}; - const char * j_key; - nm_json_t * j_val; - const char * v_name; - NMTeamLinkWatcher * result = NULL; - - if (!nm_json_is_object(root_js_obj)) - goto fail; - - nm_json_object_foreach (vt, (nm_json_t *) root_js_obj, j_key, j_val) { - const LinkWatcherAttrData *attr_data = NULL; - NMValueTypUnioMaybe * parse_result; - - if (j_key) { - int i; - - for (i = 0; i < (int) G_N_ELEMENTS(link_watcher_attr_datas); i++) { - if (nm_streq(link_watcher_attr_datas[i].js_key, j_key)) { - attr_data = &link_watcher_attr_datas[i]; - break; - } - } - } - if (!attr_data) { - *out_unrecognized_content = TRUE; - continue; - } - - parse_result = &args[attr_data->link_watcher_attr]; - - if (parse_result->has) - *out_unrecognized_content = TRUE; - - if (!nm_value_type_from_json(vt, attr_data->value_type, j_val, &parse_result->val)) - *out_unrecognized_content = TRUE; - else - parse_result->has = TRUE; - } - -#define _PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES(_parse_results, ...) \ - ({ \ - int _i; \ - \ - for (_i = 0; _i < (int) G_N_ELEMENTS((_parse_results)); _i++) { \ - if ((_parse_results)[_i].has && !NM_IN_SET((LinkWatcherAttribute) _i, __VA_ARGS__)) \ - break; \ - } \ - \ - (_i == (int) G_N_ELEMENTS((_parse_results))); \ - }) - - v_name = _LINK_WATCHER_ATTR_GET_STRING(args, LINK_WATCHER_ATTRIBUTE_NAME); - - if (nm_streq0(v_name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { - if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES(args, - _EXPECTED_LINK_WATCHER_ATTRIBUTES_ETHTOOL)) - *out_unrecognized_content = TRUE; - result = nm_team_link_watcher_new_ethtool( - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_DELAY_UP), - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_DELAY_DOWN), - NULL); - } else if (nm_streq0(v_name, NM_TEAM_LINK_WATCHER_NSNA_PING)) { - if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES(args, - _EXPECTED_LINK_WATCHER_ATTRIBUTES_NSNA_PING)) - *out_unrecognized_content = TRUE; - result = nm_team_link_watcher_new_nsna_ping( - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_INIT_WAIT), - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_INTERVAL), - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_MISSED_MAX), - _LINK_WATCHER_ATTR_GET_STRING(args, LINK_WATCHER_ATTRIBUTE_TARGET_HOST), - NULL); - } else if (nm_streq0(v_name, NM_TEAM_LINK_WATCHER_ARP_PING)) { - NMTeamLinkWatcherArpPingFlags v_flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE; - - if (_PARSE_RESULT_HAS_UNEXPECTED_ATTRIBUTES(args, - _EXPECTED_LINK_WATCHER_ATTRIBUTES_ARP_PING)) - *out_unrecognized_content = TRUE; - - if (_LINK_WATCHER_ATTR_GET_BOOL(args, LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE)) - v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE; - if (_LINK_WATCHER_ATTR_GET_BOOL(args, LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE)) - v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE; - if (_LINK_WATCHER_ATTR_GET_BOOL(args, LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS)) - v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS; - - result = nm_team_link_watcher_new_arp_ping2( - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_INIT_WAIT), - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_INTERVAL), - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_MISSED_MAX), - _LINK_WATCHER_ATTR_GET_INT(args, LINK_WATCHER_ATTRIBUTE_VLANID), - _LINK_WATCHER_ATTR_GET_STRING(args, LINK_WATCHER_ATTRIBUTE_TARGET_HOST), - _LINK_WATCHER_ATTR_GET_STRING(args, LINK_WATCHER_ATTRIBUTE_SOURCE_HOST), - v_flags, - NULL); - } - - if (result) - return result; -fail: - *out_unrecognized_content = TRUE; - return NULL; -} - -/*****************************************************************************/ - -static GVariant * -_link_watcher_to_variant(const NMTeamLinkWatcher *link_watcher) -{ - NMValueTypUnioMaybe args[G_N_ELEMENTS(link_watcher_attr_datas)]; - GVariantBuilder builder; - int i; - - if (!link_watcher) - return NULL; - - _link_watcher_unpack(link_watcher, args); - - if (!args[LINK_WATCHER_ATTRIBUTE_NAME].has) - return NULL; - - g_variant_builder_init(&builder, G_VARIANT_TYPE("a{sv}")); - - for (i = 0; i < (int) G_N_ELEMENTS(link_watcher_attr_datas); i++) { - const NMValueTypUnioMaybe *p_val = &args[i]; - const LinkWatcherAttrData *attr_data = &link_watcher_attr_datas[i]; - GVariant * v; - - if (!p_val->has) - continue; - if (nm_value_type_equal(attr_data->value_type, &attr_data->default_val, &p_val->val)) - continue; - - if (attr_data->value_type == NM_VALUE_TYPE_INT) - v = g_variant_new_int32(p_val->val.v_int); - else { - v = nm_value_type_to_variant(attr_data->value_type, &p_val->val); - } - if (!v) - continue; - - nm_assert(g_variant_is_floating(v)); - g_variant_builder_add(&builder, "{sv}", attr_data->dbus_name, v); - } - - return g_variant_builder_end(&builder); -} - -#define _LINK_WATCHER_ATTR_VARGET(variants, link_watcher_attribute, _value_type, c_type, _cmd) \ - ({ \ - GVariant *const *_variants = (variants); \ - GVariant * _cc; \ - \ - nm_assert(link_watcher_attr_datas[(link_watcher_attribute)].value_type == (_value_type)); \ - \ - (_cc = _variants[(link_watcher_attribute)]) \ - ? (_cmd) \ - : link_watcher_attr_datas[(link_watcher_attribute)].default_val.c_type; \ - }) -#define _LINK_WATCHER_ATTR_VARGET_BOOL(variants, link_watcher_attribute) \ - (_LINK_WATCHER_ATTR_VARGET(variants, \ - link_watcher_attribute, \ - NM_VALUE_TYPE_BOOL, \ - v_bool, \ - g_variant_get_boolean(_cc))) -#define _LINK_WATCHER_ATTR_VARGET_INT(variants, link_watcher_attribute) \ - (_LINK_WATCHER_ATTR_VARGET(variants, \ - link_watcher_attribute, \ - NM_VALUE_TYPE_INT, \ - v_int, \ - g_variant_get_int32(_cc))) -#define _LINK_WATCHER_ATTR_VARGET_STRING(variants, link_watcher_attribute) \ - (_LINK_WATCHER_ATTR_VARGET(variants, \ - link_watcher_attribute, \ - NM_VALUE_TYPE_STRING, \ - v_string, \ - g_variant_get_string(_cc, NULL))) - -static void -_variants_list_link_watcher_unref_auto(GVariant *(*p_variants)[]) -{ - int i; - - for (i = 0; i < (int) G_N_ELEMENTS(link_watcher_attr_datas); i++) - nm_g_variant_unref((*p_variants)[i]); -} - -static NMTeamLinkWatcher * -_link_watcher_from_variant(GVariant *watcher_var, gboolean strict_parsing, GError **error) -{ - nm_auto(_variants_list_link_watcher_unref_auto) - GVariant *variants[G_N_ELEMENTS(link_watcher_attr_datas)] = { - NULL, - }; - const char * v_key; - GVariant * v_val; - const char * v_name; - GVariantIter iter; - - g_return_val_if_fail(g_variant_is_of_type(watcher_var, G_VARIANT_TYPE("a{sv}")), NULL); - - g_variant_iter_init(&iter, watcher_var); - while (g_variant_iter_next(&iter, "{&sv}", &v_key, &v_val)) { - _nm_unused gs_unref_variant GVariant *v_val_free = v_val; - const LinkWatcherAttrData * attr_data = NULL; - const GVariantType * variant_type; - int i; - - for (i = 0; i < (int) G_N_ELEMENTS(link_watcher_attr_datas); i++) { - if (nm_streq(link_watcher_attr_datas[i].dbus_name, v_key)) { - attr_data = &link_watcher_attr_datas[i]; - break; - } - } - if (!attr_data) { - if (strict_parsing) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("invalid D-Bus property \"%s\""), - v_key); - return NULL; - } - continue; - } - - if (attr_data->value_type == NM_VALUE_TYPE_INT) - variant_type = G_VARIANT_TYPE_INT32; - else - variant_type = nm_value_type_get_variant_type(attr_data->value_type); - - if (!g_variant_is_of_type(v_val, variant_type)) { - if (strict_parsing) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("invalid D-Bus property \"%s\""), - v_key); - return NULL; - } - continue; - } - - if (variants[attr_data->link_watcher_attr]) { - if (strict_parsing) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("duplicate D-Bus property \"%s\""), - v_key); - return NULL; - } - g_variant_unref(variants[attr_data->link_watcher_attr]); - } - variants[attr_data->link_watcher_attr] = g_steal_pointer(&v_val_free); - } - -#define _VARIANTS_HAVE_UNEXPECTED_ATTRIBUTES(_type, _variants, _error, ...) \ - ({ \ - int _i; \ - gboolean _has_error = FALSE; \ - \ - for (_i = 0; _i < (int) G_N_ELEMENTS((_variants)); _i++) { \ - if ((_variants)[_i] && !NM_IN_SET((LinkWatcherAttribute) _i, __VA_ARGS__)) { \ - _has_error = TRUE; \ - g_set_error(_error, \ - NM_CONNECTION_ERROR, \ - NM_CONNECTION_ERROR_INVALID_PROPERTY, \ - _("invalid D-Bus property \"%s\" for \"%s\""), \ - link_watcher_attr_datas[_i].dbus_name, \ - _type); \ - break; \ - } \ - } \ - \ - _has_error; \ - }) - - v_name = _LINK_WATCHER_ATTR_VARGET_STRING(variants, LINK_WATCHER_ATTRIBUTE_NAME); - - if (nm_streq0(v_name, NM_TEAM_LINK_WATCHER_ETHTOOL)) { - if (strict_parsing - && _VARIANTS_HAVE_UNEXPECTED_ATTRIBUTES(v_name, - variants, - error, - _EXPECTED_LINK_WATCHER_ATTRIBUTES_ETHTOOL)) - return NULL; - return nm_team_link_watcher_new_ethtool( - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_DELAY_UP), - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_DELAY_DOWN), - strict_parsing ? error : NULL); - } - - if (nm_streq0(v_name, NM_TEAM_LINK_WATCHER_NSNA_PING)) { - if (strict_parsing - && _VARIANTS_HAVE_UNEXPECTED_ATTRIBUTES(v_name, - variants, - error, - _EXPECTED_LINK_WATCHER_ATTRIBUTES_NSNA_PING)) - return NULL; - return nm_team_link_watcher_new_nsna_ping( - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_INIT_WAIT), - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_INTERVAL), - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_MISSED_MAX), - _LINK_WATCHER_ATTR_VARGET_STRING(variants, LINK_WATCHER_ATTRIBUTE_TARGET_HOST), - strict_parsing ? error : NULL); - } - - if (nm_streq0(v_name, NM_TEAM_LINK_WATCHER_ARP_PING)) { - NMTeamLinkWatcherArpPingFlags v_flags = NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_NONE; - - if (strict_parsing - && _VARIANTS_HAVE_UNEXPECTED_ATTRIBUTES(v_name, - variants, - error, - _EXPECTED_LINK_WATCHER_ATTRIBUTES_ARP_PING)) - return NULL; - - if (_LINK_WATCHER_ATTR_VARGET_BOOL(variants, LINK_WATCHER_ATTRIBUTE_VALIDATE_ACTIVE)) - v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_ACTIVE; - if (_LINK_WATCHER_ATTR_VARGET_BOOL(variants, LINK_WATCHER_ATTRIBUTE_VALIDATE_INACTIVE)) - v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_VALIDATE_INACTIVE; - if (_LINK_WATCHER_ATTR_VARGET_BOOL(variants, LINK_WATCHER_ATTRIBUTE_SEND_ALWAYS)) - v_flags |= NM_TEAM_LINK_WATCHER_ARP_PING_FLAG_SEND_ALWAYS; - - return nm_team_link_watcher_new_arp_ping2( - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_INIT_WAIT), - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_INTERVAL), - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_MISSED_MAX), - _LINK_WATCHER_ATTR_VARGET_INT(variants, LINK_WATCHER_ATTRIBUTE_VLANID), - _LINK_WATCHER_ATTR_VARGET_STRING(variants, LINK_WATCHER_ATTRIBUTE_TARGET_HOST), - _LINK_WATCHER_ATTR_VARGET_STRING(variants, LINK_WATCHER_ATTRIBUTE_SOURCE_HOST), - v_flags, - strict_parsing ? error : NULL); - } - - if (strict_parsing) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("unknown link-watcher name \"%s\""), - v_name); - } - return NULL; -} - -/*****************************************************************************/ - -/** - * _nm_utils_team_link_watchers_to_variant: - * @link_watchers: (element-type NMTeamLinkWatcher): array of #NMTeamLinkWatcher - * - * Utility function to convert a #GPtrArray of #NMTeamLinkWatcher objects - * representing link watcher configuration for team devices into a #GVariant - * of type 'aa{sv}' representing an array of link watchers. - * - * Returns: (transfer full): a new floating #GVariant representing link watchers. - **/ -GVariant * -_nm_utils_team_link_watchers_to_variant(const GPtrArray *link_watchers) -{ - GVariantBuilder builder; - guint i; - - g_variant_builder_init(&builder, G_VARIANT_TYPE("aa{sv}")); - if (link_watchers) { - for (i = 0; i < link_watchers->len; i++) { - g_variant_builder_add(&builder, - "@a{sv}", - _link_watcher_to_variant(link_watchers->pdata[i])); - } - } - return g_variant_builder_end(&builder); -} - -/** - * _nm_utils_team_link_watchers_from_variant: - * @value: a #GVariant of type 'aa{sv}' - * @strict_parsing: whether to parse strictly or ignore everything invalid. - * @error: error reason. - * - * Utility function to convert a #GVariant representing a list of team link - * watchers int a #GPtrArray of #NMTeamLinkWatcher objects. - * - * Returns: (transfer full) (element-type NMTeamLinkWatcher): a newly allocated - * #GPtrArray of #NMTeamLinkWatcher objects. - * - * Note that if you provide an @error, then the function can only fail (and return %NULL) - * or succeed (and not return %NULL). If you don't provide an @error, then the function - * never returns %NULL. - **/ -GPtrArray * -_nm_utils_team_link_watchers_from_variant(GVariant *value, gboolean strict_parsing, GError **error) -{ - gs_unref_ptrarray GPtrArray *link_watchers = NULL; - GVariantIter iter; - GVariant * watcher_var; - - g_return_val_if_fail(g_variant_is_of_type(value, G_VARIANT_TYPE("aa{sv}")), NULL); - - link_watchers = g_ptr_array_new_with_free_func((GDestroyNotify) nm_team_link_watcher_unref); - - g_variant_iter_init(&iter, value); - while (g_variant_iter_next(&iter, "@a{sv}", &watcher_var)) { - _nm_unused gs_unref_variant GVariant *watcher_var_free = watcher_var; - NMTeamLinkWatcher * watcher; - - watcher = _link_watcher_from_variant(watcher_var, strict_parsing, error); - if (error && *error) - return NULL; - if (watcher) - g_ptr_array_add(link_watchers, watcher); - } - - return g_steal_pointer(&link_watchers); -} - -/*****************************************************************************/ - -const char * -nm_team_setting_config_get(const NMTeamSetting *self) -{ - char *js_str; - - nm_assert(self); - - if (G_LIKELY(!self->d._js_str_need_synthetize)) - return self->d._js_str; - - nm_assert(!self->d._js_str); - nm_assert(self->d.strict_validated); - - if (_team_setting_check_default(self) == 0) { - /* the default is set. We signal this as a NULL JSON string. - * Nothing to do. */ - js_str = NULL; - } else { - gboolean list_is_empty = TRUE; - GString *gstr; - - gstr = g_string_new(NULL); - - g_string_append(gstr, "{ "); - - if (self->d.is_port) { - static const NMTeamAttribute attr_lst_port[] = { - NM_TEAM_ATTRIBUTE_PORT_QUEUE_ID, - NM_TEAM_ATTRIBUTE_PORT_PRIO, - NM_TEAM_ATTRIBUTE_PORT_STICKY, - NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO, - NM_TEAM_ATTRIBUTE_PORT_LACP_KEY, - }; - - if (_team_setting_fields_to_json_maybe(self, - gstr, - !list_is_empty, - attr_lst_port, - G_N_ELEMENTS(attr_lst_port))) - list_is_empty = FALSE; - } else { - static const NMTeamAttribute attr_lst_runner_pt1[] = { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_HWADDR_POLICY, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH, - }; - static const NMTeamAttribute attr_lst_runner_pt2[] = { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_BALANCER_INTERVAL, - }; - static const NMTeamAttribute attr_lst_runner_pt3[] = { - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_ACTIVE, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_FAST_RATE, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_SYS_PRIO, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_MIN_PORTS, - NM_TEAM_ATTRIBUTE_MASTER_RUNNER_AGG_SELECT_POLICY, - }; - static const NMTeamAttribute attr_lst_notify_peers[] = { - NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_COUNT, - NM_TEAM_ATTRIBUTE_MASTER_NOTIFY_PEERS_INTERVAL, - }; - static const NMTeamAttribute attr_lst_mcast_rejoin[] = { - NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_COUNT, - NM_TEAM_ATTRIBUTE_MASTER_MCAST_REJOIN_INTERVAL, - }; - - if (_team_setting_has_fields_any_v(self, - attr_lst_runner_pt1, - G_N_ELEMENTS(attr_lst_runner_pt1)) - || _team_setting_has_fields_any_v(self, - attr_lst_runner_pt2, - G_N_ELEMENTS(attr_lst_runner_pt2)) - || _team_setting_has_fields_any_v(self, - attr_lst_runner_pt3, - G_N_ELEMENTS(attr_lst_runner_pt3))) { - gboolean list_is_empty2 = TRUE; - - nm_assert(list_is_empty); - - nm_json_gstr_append_obj_name(gstr, "runner", '{'); - - if (_team_setting_fields_to_json_maybe(self, - gstr, - !list_is_empty2, - attr_lst_runner_pt1, - G_N_ELEMENTS(attr_lst_runner_pt1))) - list_is_empty2 = FALSE; - - if (_team_setting_has_fields_any_v(self, - attr_lst_runner_pt2, - G_N_ELEMENTS(attr_lst_runner_pt2))) { - if (!list_is_empty2) - nm_json_gstr_append_delimiter(gstr); - nm_json_gstr_append_obj_name(gstr, "tx_balancer", '{'); - if (!_team_setting_fields_to_json_maybe(self, - gstr, - FALSE, - attr_lst_runner_pt2, - G_N_ELEMENTS(attr_lst_runner_pt2))) - nm_assert_not_reached(); - g_string_append(gstr, " }"); - list_is_empty2 = FALSE; - } - - if (_team_setting_fields_to_json_maybe(self, - gstr, - !list_is_empty2, - attr_lst_runner_pt3, - G_N_ELEMENTS(attr_lst_runner_pt3))) - list_is_empty2 = FALSE; - - nm_assert(!list_is_empty2); - g_string_append(gstr, " }"); - list_is_empty = FALSE; - } - - if (_team_setting_has_fields_any_v(self, - attr_lst_notify_peers, - G_N_ELEMENTS(attr_lst_notify_peers))) { - if (!list_is_empty) - nm_json_gstr_append_delimiter(gstr); - nm_json_gstr_append_obj_name(gstr, "notify_peers", '{'); - if (!_team_setting_fields_to_json_maybe(self, - gstr, - FALSE, - attr_lst_notify_peers, - G_N_ELEMENTS(attr_lst_notify_peers))) - nm_assert_not_reached(); - g_string_append(gstr, " }"); - list_is_empty = FALSE; - } - - if (_team_setting_has_fields_any_v(self, - attr_lst_mcast_rejoin, - G_N_ELEMENTS(attr_lst_mcast_rejoin))) { - if (!list_is_empty) - nm_json_gstr_append_delimiter(gstr); - nm_json_gstr_append_obj_name(gstr, "mcast_rejoin", '{'); - if (!_team_setting_fields_to_json_maybe(self, - gstr, - FALSE, - attr_lst_mcast_rejoin, - G_N_ELEMENTS(attr_lst_mcast_rejoin))) - nm_assert_not_reached(); - g_string_append(gstr, " }"); - list_is_empty = FALSE; - } - } - - if (_team_setting_field_to_json( - self, - gstr, - !list_is_empty, - _team_attr_data_get(self->d.is_port, NM_TEAM_ATTRIBUTE_LINK_WATCHERS))) - list_is_empty = FALSE; - - if (!list_is_empty) - g_string_append(gstr, " }"); - - js_str = g_string_free(gstr, list_is_empty); - } - - /* mutate the constant object. In C++ speak, these fields are "mutable". - * That is because we construct the JSON string lazily/on-demand. */ - *((char **) &self->_data_priv._js_str) = js_str; - *((bool *) &self->_data_priv._js_str_need_synthetize) = FALSE; - - return self->d._js_str; -} - -/*****************************************************************************/ - -static gboolean -_attr_data_match_keys(const TeamAttrData *attr_data, const char *const *keys, guint8 n_keys) -{ - guint8 i; - - _team_attr_data_ASSERT(attr_data); - nm_assert(keys); - nm_assert(n_keys > 0); - nm_assert(({ - gboolean all_non_null = TRUE; - - for (i = 0; i < n_keys; i++) - all_non_null = all_non_null && keys[i] && keys[i][0] != '\0'; - all_non_null; - })); - - if (attr_data->js_keys_len < n_keys) - return FALSE; - for (i = 0; i < n_keys; i++) { - if (!nm_streq(keys[i], attr_data->js_keys[i])) - return FALSE; - } - return TRUE; -} - -static const TeamAttrData * -_attr_data_find_by_json_key(gboolean is_port, const char *const *keys, guint8 n_keys) -{ - const TeamAttrData *attr_data; - - for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; - attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) { - if (_team_attr_data_is_relevant(attr_data, is_port) - && _attr_data_match_keys(attr_data, keys, n_keys)) - return attr_data; - } - - return NULL; -} - -static void -_js_parse_locate_keys(const NMJsonVt *vt, - NMTeamSetting * self, - nm_json_t * root_js_obj, - nm_json_t * found_keys[static _NM_TEAM_ATTRIBUTE_NUM], - gboolean * out_unrecognized_content) -{ - const char *keys[3]; - const char *cur_key1; - const char *cur_key2; - const char *cur_key3; - nm_json_t * cur_val1; - nm_json_t * cur_val2; - nm_json_t * cur_val3; - - nm_assert(vt); - -#define _handle(_self, _cur_key, _cur_val, _keys, _level, _found_keys, _out_unrecognized_content) \ - ({ \ - const TeamAttrData *_attr_data; \ - gboolean _handled = FALSE; \ - \ - (_keys)[(_level) -1] = (_cur_key); \ - _attr_data = _attr_data_find_by_json_key((_self)->d.is_port, (_keys), (_level)); \ - if (_attr_data && _attr_data->js_keys_len == (_level)) { \ - if ((_found_keys)[_attr_data->team_attr]) \ - *(_out_unrecognized_content) = TRUE; \ - (_found_keys)[_attr_data->team_attr] = (_cur_val); \ - _handled = TRUE; \ - } else if (!_attr_data || !nm_json_is_object((_cur_val))) { \ - *(_out_unrecognized_content) = TRUE; \ - _handled = TRUE; \ - } \ - _handled; \ - }) - - nm_json_object_foreach (vt, root_js_obj, cur_key1, cur_val1) { - if (!_handle(self, cur_key1, cur_val1, keys, 1, found_keys, out_unrecognized_content)) { - nm_json_object_foreach (vt, cur_val1, cur_key2, cur_val2) { - if (!_handle(self, - cur_key2, - cur_val2, - keys, - 2, - found_keys, - out_unrecognized_content)) { - nm_json_object_foreach (vt, cur_val2, cur_key3, cur_val3) { - if (!_handle(self, - cur_key3, - cur_val3, - keys, - 3, - found_keys, - out_unrecognized_content)) - *out_unrecognized_content = TRUE; - } - } - } - } - } - -#undef _handle -} - -static void -_js_parse_unpack(const NMJsonVt *vt, - gboolean is_port, - nm_json_t * found_keys[static _NM_TEAM_ATTRIBUTE_NUM], - bool out_has_lst[static _NM_TEAM_ATTRIBUTE_NUM], - NMValueTypUnion out_val_lst[static _NM_TEAM_ATTRIBUTE_NUM], - gboolean * out_unrecognized_content, - GPtrArray ** out_ptr_array_link_watchers_free, - GPtrArray ** out_ptr_array_master_runner_tx_hash_free) -{ - const TeamAttrData *attr_data; - - nm_assert(vt); - - for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; - attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) { - NMValueTypUnion *p_out_val; - gboolean valid = FALSE; - nm_json_t * arg_js_obj; - - if (!_team_attr_data_is_relevant(attr_data, is_port)) - continue; - - nm_assert(!out_has_lst[attr_data->team_attr]); - - arg_js_obj = found_keys[attr_data->team_attr]; - if (!arg_js_obj) - continue; - - p_out_val = &out_val_lst[attr_data->team_attr]; - - if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) - valid = nm_value_type_from_json(vt, attr_data->value_type, arg_js_obj, p_out_val); - else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) { - GPtrArray * link_watchers = NULL; - NMTeamLinkWatcher *link_watcher; - - nm_assert(out_ptr_array_link_watchers_free && !*out_ptr_array_link_watchers_free); - if (nm_json_is_array(arg_js_obj)) { - gsize i, len; - - len = vt->nm_json_array_size(arg_js_obj); - link_watchers = - g_ptr_array_new_full(len, (GDestroyNotify) nm_team_link_watcher_unref); - for (i = 0; i < len; i++) { - link_watcher = _link_watcher_from_json(vt, - vt->nm_json_array_get(arg_js_obj, i), - out_unrecognized_content); - if (link_watcher) - g_ptr_array_add(link_watchers, link_watcher); - } - } else { - link_watcher = _link_watcher_from_json(vt, arg_js_obj, out_unrecognized_content); - if (link_watcher) { - link_watchers = - g_ptr_array_new_full(1, (GDestroyNotify) nm_team_link_watcher_unref); - g_ptr_array_add(link_watchers, link_watcher); - } - } - if (link_watchers) { - valid = TRUE; - p_out_val->v_ptrarray = link_watchers; - *out_ptr_array_link_watchers_free = link_watchers; - } - } else if (!is_port && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { - GPtrArray *strv = NULL; - - nm_assert(out_ptr_array_master_runner_tx_hash_free - && !*out_ptr_array_master_runner_tx_hash_free); - if (nm_json_is_array(arg_js_obj)) { - gsize i, len; - - len = vt->nm_json_array_size(arg_js_obj); - if (len > 0) { - strv = g_ptr_array_sized_new(len); - for (i = 0; i < len; i++) { - const char *v_string; - - if (nm_jansson_json_as_string(vt, - vt->nm_json_array_get(arg_js_obj, i), - &v_string) - <= 0 - || !v_string || v_string[0] == '\0') { - /* we remember that there was some invalid content, but parts of the - * list could still be parsed. */ - *out_unrecognized_content = TRUE; - continue; - } - g_ptr_array_add(strv, (char *) v_string); - } - } - valid = TRUE; - *out_ptr_array_master_runner_tx_hash_free = strv; - } - p_out_val->v_ptrarray = strv; - } else - nm_assert_not_reached(); - - out_has_lst[attr_data->team_attr] = valid; - if (!valid) - *out_unrecognized_content = TRUE; - } -} - -guint32 -nm_team_setting_config_set(NMTeamSetting *self, const char *js_str) -{ - const NMJsonVt *vt; - guint32 changed_flags = 0; - gboolean do_set_default = TRUE; - gboolean new_js_str_invalid = FALSE; - - _team_setting_ASSERT(self); - - if (!js_str || js_str[0] == '\0') { - changed_flags = _team_setting_set_default(self); - if (changed_flags != 0 || !nm_streq0(js_str, self->d._js_str)) - changed_flags |= nm_team_attribute_to_flags(NM_TEAM_ATTRIBUTE_CONFIG); - nm_clear_g_free((char **) &self->_data_priv._js_str); - self->_data_priv._js_str = g_strdup(js_str); - self->_data_priv._js_str_need_synthetize = FALSE; - self->_data_priv.strict_validated = TRUE; - self->_data_priv.js_str_invalid = FALSE; - return changed_flags; - } - - if (self->d._js_str && nm_streq(js_str, self->d._js_str)) { - if (!self->d.strict_validated) { - /* setting the same JSON string twice in a row has no effect. */ - return 0; - } - } else - changed_flags |= nm_team_attribute_to_flags(NM_TEAM_ATTRIBUTE_CONFIG); - - if ((vt = nm_json_vt())) { - nm_auto_decref_json nm_json_t *root_js_obj = NULL; - - root_js_obj = vt->nm_json_loads(js_str, 0, NULL); - if (!root_js_obj || !nm_json_is_object(root_js_obj)) - new_js_str_invalid = TRUE; - else { - gboolean unrecognized_content = FALSE; - bool has_lst[_NM_TEAM_ATTRIBUTE_NUM] = { - FALSE, - }; - NMValueTypUnion val_lst[_NM_TEAM_ATTRIBUTE_NUM]; - nm_json_t * found_keys[_NM_TEAM_ATTRIBUTE_NUM] = { - NULL, - }; - gs_unref_ptrarray GPtrArray *ptr_array_master_runner_tx_hash_free = NULL; - gs_unref_ptrarray GPtrArray *ptr_array_link_watchers_free = NULL; - - _js_parse_locate_keys(vt, self, root_js_obj, found_keys, &unrecognized_content); - - _js_parse_unpack(vt, - self->d.is_port, - found_keys, - has_lst, - val_lst, - &unrecognized_content, - &ptr_array_link_watchers_free, - &ptr_array_master_runner_tx_hash_free); - - do_set_default = FALSE; - - changed_flags |= _team_setting_set(self, TRUE, has_lst, val_lst); - } - } - - if (do_set_default) - changed_flags |= _team_setting_set_default(self); - - self->_data_priv.strict_validated = FALSE; - self->_data_priv._js_str_need_synthetize = FALSE; - self->_data_priv.js_str_invalid = new_js_str_invalid; - g_free((char *) self->_data_priv._js_str); - self->_data_priv._js_str = g_strdup(js_str); - - return changed_flags; -} - -/*****************************************************************************/ - -static void -_team_setting_prefix_error_plain(gboolean is_port, const char *property_name, GError **error) -{ - g_prefix_error(error, - "%s.%s: ", - is_port ? NM_SETTING_TEAM_PORT_SETTING_NAME : NM_SETTING_TEAM_SETTING_NAME, - property_name); -} - -static void -_team_setting_prefix_error(const NMTeamSetting *self, - const char * prop_name_master, - const char * prop_name_port, - GError ** error) -{ - _team_setting_ASSERT(self); - nm_assert(self->d.is_port ? (!!prop_name_port) : (!!prop_name_master)); - _team_setting_prefix_error_plain(self->d.is_port, - self->d.is_port ? prop_name_port : prop_name_master, - error); -} - -static gboolean -_team_setting_verify_properties(const NMTeamSetting *self, GError **error) -{ - const TeamAttrData *attr_data; - guint i; - - for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; - attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) { - if (!_team_attr_data_is_relevant(attr_data, self->d.is_port)) - continue; - if (!_team_setting_has_field(self, attr_data)) - continue; - - if (attr_data->has_range) { - gconstpointer p_field; - - p_field = _team_setting_get_field(self, attr_data); - if (attr_data->value_type == NM_VALUE_TYPE_INT32) { - gint32 v = *((const gint32 *) p_field); - - if (v < attr_data->range.r_int32.min || v > attr_data->range.r_int32.max) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("value out or range")); - _team_setting_prefix_error_plain(self->d.is_port, - attr_data->property_name, - error); - return FALSE; - } - } else if (attr_data->value_type == NM_VALUE_TYPE_STRING) { - const char *v = *((const char *const *) p_field); - - if (nm_utils_strv_find_first((char **) attr_data->range.r_string.valid_names, -1, v) - < 0) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("invalid value")); - _team_setting_prefix_error_plain(self->d.is_port, - attr_data->property_name, - error); - return FALSE; - } - } else - nm_assert_not_reached(); - } - - if (!self->d.is_port && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { - if (self->d.master.runner_tx_hash) { - for (i = 0; i < self->d.master.runner_tx_hash->len; i++) { - const char *val = self->d.master.runner_tx_hash->pdata[i]; - - if (!val - || (nm_utils_strv_find_first((char **) _valid_names_runner_tx_hash, -1, val) - < 0)) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("invalid runner-tx-hash")); - _team_setting_prefix_error_plain(self->d.is_port, - NM_SETTING_TEAM_RUNNER_TX_HASH, - error); - return FALSE; - } - } - } - } - } - - if (!self->d.is_port) { - for (i = 0; i < G_N_ELEMENTS(_runner_compat_lst); i++) { - const RunnerCompatElem *e = &_runner_compat_lst[i]; - - nm_assert(NM_PTRARRAY_LEN(e->valid_runners) > 0); - - attr_data = _team_attr_data_get(FALSE, e->team_attr); - - if (!_team_setting_has_field(self, attr_data)) - continue; - if (self->d.master.runner - && (nm_utils_strv_find_first((char **) e->valid_runners, -1, self->d.master.runner) - >= 0)) - continue; - if (e->valid_runners[1] == NULL) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("%s is only allowed for runner %s"), - attr_data->property_name, - e->valid_runners[0]); - } else { - gs_free char *s = NULL; - - s = g_strjoinv(",", (char **) e->valid_runners); - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("%s is only allowed for runners %s"), - attr_data->property_name, - s); - } - _team_setting_prefix_error_plain(self->d.is_port, NM_SETTING_TEAM_RUNNER, error); - return FALSE; - } - } else { - gboolean has_lacp_attrs; - gboolean has_activebackup_attrs; - - has_lacp_attrs = _team_setting_has_fields_any(self, - NM_TEAM_ATTRIBUTE_PORT_LACP_PRIO, - NM_TEAM_ATTRIBUTE_PORT_LACP_KEY); - has_activebackup_attrs = _team_setting_has_fields_any(self, - NM_TEAM_ATTRIBUTE_PORT_PRIO, - NM_TEAM_ATTRIBUTE_PORT_STICKY); - if (has_lacp_attrs && has_activebackup_attrs) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("cannot set parameters for lacp and activebackup runners together")); - _team_setting_prefix_error(self, - NM_SETTING_TEAM_LINK_WATCHERS, - NM_SETTING_TEAM_PORT_LINK_WATCHERS, - error); - return FALSE; - } - } - - for (i = 0; i < self->d.link_watchers->len; i++) { - if (!self->d.link_watchers->pdata[i]) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_SETTING, - _("missing link watcher")); - _team_setting_prefix_error(self, - NM_SETTING_TEAM_LINK_WATCHERS, - NM_SETTING_TEAM_PORT_LINK_WATCHERS, - error); - return FALSE; - } - } - - return TRUE; -} - -static gboolean -_team_setting_verify_config(const NMTeamSetting *self, GError **error) -{ - const char *js_str; - - /* we always materialize the JSON string. That is because we want to validate the - * string length of the resulting JSON. */ - js_str = nm_team_setting_config_get(self); - - if (js_str) { - if (strlen(js_str) > 1 * 1024 * 1024) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("team config exceeds size limit")); - _team_setting_prefix_error(self, - NM_SETTING_TEAM_CONFIG, - NM_SETTING_TEAM_PORT_CONFIG, - error); - return FALSE; - } - if (!g_utf8_validate(js_str, -1, NULL)) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("team config is not valid UTF-8")); - _team_setting_prefix_error(self, - NM_SETTING_TEAM_CONFIG, - NM_SETTING_TEAM_PORT_CONFIG, - error); - return FALSE; - } - if (self->d.js_str_invalid) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("invalid json")); - _team_setting_prefix_error(self, - NM_SETTING_TEAM_CONFIG, - NM_SETTING_TEAM_PORT_CONFIG, - error); - return FALSE; - } - } - - return TRUE; -} - -gboolean -nm_team_setting_verify(const NMTeamSetting *self, GError **error) -{ - if (self->d.strict_validated) { - if (!_team_setting_verify_properties(self, error)) - return FALSE; - } - return _team_setting_verify_config(self, error); -} - -/*****************************************************************************/ - -int -nm_team_setting_cmp(const NMTeamSetting *self_a, - const NMTeamSetting *self_b, - gboolean ignore_js_str) -{ - const TeamAttrData *attr_data; - - NM_CMP_SELF(self_a, self_b); - - NM_CMP_FIELD_UNSAFE(self_a, self_b, d.is_port); - - for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; - attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) { - if (!_team_attr_data_is_relevant(attr_data, self_a->d.is_port)) - continue; - - NM_CMP_RETURN(_team_attr_data_cmp(attr_data, - self_a->d.is_port, - _team_setting_get_field(self_a, attr_data), - _team_setting_get_field(self_b, attr_data))); - } - - if (!ignore_js_str) { - NM_CMP_DIRECT_STRCMP0(nm_team_setting_config_get(self_a), - nm_team_setting_config_get(self_b)); - } - - return 0; -} - -guint32 -nm_team_setting_reset(NMTeamSetting *self, const NMTeamSetting *src) -{ - const TeamAttrData *attr_data; - guint32 changed_flags; - - _team_setting_ASSERT(self); - _team_setting_ASSERT(src); - nm_assert(self->d.is_port == src->d.is_port); - - if (self == src) - return 0; - - changed_flags = 0; - - for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; - attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) { - if (!_team_attr_data_is_relevant(attr_data, self->d.is_port)) - continue; - if (_team_attr_data_equal(attr_data, - self->d.is_port, - _team_setting_get_field(self, attr_data), - _team_setting_get_field(src, attr_data))) - continue; - _team_attr_data_copy(attr_data, - self->d.is_port, - _team_setting_get_field(self, attr_data), - _team_setting_get_field(src, attr_data)); - changed_flags |= nm_team_attribute_to_flags(attr_data->team_attr); - } - - self->_data_priv.has_fields_mask = src->d.has_fields_mask; - - if (!nm_streq0(self->d._js_str, src->d._js_str)) { - g_free((char *) self->_data_priv._js_str); - self->_data_priv._js_str = g_strdup(src->d._js_str); - changed_flags |= nm_team_attribute_to_flags(NM_TEAM_ATTRIBUTE_CONFIG); - } else if (changed_flags != 0) - changed_flags |= nm_team_attribute_to_flags(NM_TEAM_ATTRIBUTE_CONFIG); - - self->_data_priv._js_str_need_synthetize = src->d._js_str_need_synthetize; - self->_data_priv.strict_validated = src->d.strict_validated; - self->_data_priv.js_str_invalid = src->d.js_str_invalid; - - return changed_flags; -} - -static void -_variants_list_team_unref_auto(GVariant *(*p_variants)[]) -{ - int i; - - for (i = 0; i < _NM_TEAM_ATTRIBUTE_NUM; i++) - nm_g_variant_unref((*p_variants)[i]); -} - -gboolean -nm_team_setting_reset_from_dbus(NMTeamSetting * self, - GVariant * setting_dict, - GHashTable * keys, - guint32 * out_changed, - guint /* NMSettingParseFlags */ parse_flags, - GError ** error) -{ - nm_auto(_variants_list_team_unref_auto) GVariant *variants[_NM_TEAM_ATTRIBUTE_NUM] = { - NULL, - }; - gs_unref_ptrarray GPtrArray *v_link_watchers = NULL; - const TeamAttrData * attr_data; - GVariantIter iter; - const char * v_key; - GVariant * v_val; - const NMJsonVt * vt; - - *out_changed = 0; - - g_variant_iter_init(&iter, setting_dict); - while (g_variant_iter_next(&iter, "{&sv}", &v_key, &v_val)) { - _nm_unused gs_unref_variant GVariant *v_val_free = v_val; - const GVariantType * variant_type = NULL; - - attr_data = _team_attr_data_find_for_property_name(self->d.is_port, v_key); - if (!attr_data) { - /* _nm_setting_new_from_dbus() already checks for unknown keys. Don't - * do that here. */ - continue; - } - - if (keys) - g_hash_table_remove(keys, v_key); - - if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) - variant_type = nm_value_type_get_variant_type(attr_data->value_type); - else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_CONFIG) - variant_type = G_VARIANT_TYPE_STRING; - else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) - variant_type = G_VARIANT_TYPE("aa{sv}"); - else if (!self->d.is_port - && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) - variant_type = G_VARIANT_TYPE_STRING_ARRAY; - else - nm_assert_not_reached(); - - if (!g_variant_is_of_type(v_val, variant_type)) { - if (NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("invalid D-Bus type \"%s\""), - g_variant_get_type_string(v_val)); - _team_setting_prefix_error_plain(self->d.is_port, attr_data->property_name, error); - return FALSE; - } - continue; - } - - /* _nm_setting_new_from_dbus() already checks for duplicate keys. Don't - * do that here. */ - nm_g_variant_unref(variants[attr_data->team_attr]); - variants[attr_data->team_attr] = g_steal_pointer(&v_val_free); - } - - vt = nm_json_vt(); - - if (variants[NM_TEAM_ATTRIBUTE_LINK_WATCHERS]) { - if (variants[NM_TEAM_ATTRIBUTE_CONFIG] && vt - && !NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) { - /* we don't require the content of the "link-watchers" and we also - * don't perform strict validation. No need to parse it. */ - } else { - gs_free_error GError *local = NULL; - - /* We might need the parsed v_link_watchers array below (because there is no JSON - * "config" present or because we don't have json support). - * - * Or we might run with NM_SETTING_PARSE_FLAGS_STRICT. In that mode, we may not necessarily - * require that the entire setting as a whole validates (if a JSON config is present and - * we are not "strict_validated") , but we require that we can at least parse the link watchers - * on their own. */ - v_link_watchers = _nm_utils_team_link_watchers_from_variant( - variants[NM_TEAM_ATTRIBUTE_LINK_WATCHERS], - NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT), - &local); - if (local && NM_FLAGS_HAS(parse_flags, NM_SETTING_PARSE_FLAGS_STRICT)) { - g_set_error(error, - NM_CONNECTION_ERROR, - NM_CONNECTION_ERROR_INVALID_PROPERTY, - _("invalid link-watchers: %s"), - local->message); - _team_setting_prefix_error(self, - NM_SETTING_TEAM_LINK_WATCHERS, - NM_SETTING_TEAM_PORT_LINK_WATCHERS, - error); - return FALSE; - } - } - } - - *out_changed |= nm_team_setting_config_set( - self, - variants[NM_TEAM_ATTRIBUTE_CONFIG] - ? g_variant_get_string(variants[NM_TEAM_ATTRIBUTE_CONFIG], NULL) - : NULL); - - if (vt && variants[NM_TEAM_ATTRIBUTE_CONFIG]) { - /* for team settings, the JSON must be able to express all possible options. That means, - * if the GVariant contains both the JSON "config" and other options, then the other options - * are silently ignored. */ - } else { - guint32 extra_changed = 0u; - - for (attr_data = &team_attr_datas[TEAM_ATTR_IDX_CONFIG + 1]; - attr_data < &team_attr_datas[G_N_ELEMENTS(team_attr_datas)]; - attr_data++) { - NMValueTypUnion val; - guint32 changed_flags = 0u; - - if (!_team_attr_data_is_relevant(attr_data, self->d.is_port)) - continue; - if (!variants[attr_data->team_attr]) - continue; - - if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) { - nm_value_type_get_from_variant(attr_data->value_type, - &val, - variants[attr_data->team_attr], - FALSE); - changed_flags = _team_setting_value_set(self, - attr_data, - &val, - SET_FIELD_MODE_SET, - RESET_JSON_NO); - } else if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) { - changed_flags = _team_setting_value_link_watchers_set_list( - self, - v_link_watchers ? (const NMTeamLinkWatcher *const *) v_link_watchers->pdata - : NULL, - v_link_watchers ? v_link_watchers->len : 0u, - SET_FIELD_MODE_SET, - RESET_JSON_NO); - } else if (!self->d.is_port - && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { - gs_free const char **strv = NULL; - gsize len; - - strv = g_variant_get_strv(variants[attr_data->team_attr], &len); - changed_flags = _team_setting_value_master_runner_tx_hash_set_list( - self, - strv, - NM_MIN(len, (gsize) G_MAXUINT), - SET_FIELD_MODE_SET, - RESET_JSON_NO); - } else - nm_assert_not_reached(); - - extra_changed |= changed_flags; - } - - if (!variants[NM_TEAM_ATTRIBUTE_CONFIG]) { - /* clear the JSON string so it can be regenerated. But only if we didn't set - * it above. */ - self->_data_priv.strict_validated = TRUE; - self->_data_priv._js_str_need_synthetize = TRUE; - } - - *out_changed |= extra_changed; - } - - return TRUE; -} - -/*****************************************************************************/ - -gboolean -nm_team_setting_maybe_changed(NMSetting * source, - const GParamSpec *const *obj_properties, - guint32 changed_flags) -{ - NMTeamAttribute team_attr; - int count_flags; - guint32 ch; - - if (changed_flags == 0u) - return FALSE; - - count_flags = 0; - for (ch = changed_flags; ch != 0u; ch >>= 1) { - if (NM_FLAGS_HAS(ch, 0x1u)) - count_flags++; - } - - if (count_flags > 1) - g_object_freeze_notify(G_OBJECT(source)); - - ch = changed_flags; - for (team_attr = 0; team_attr < _NM_TEAM_ATTRIBUTE_NUM; team_attr++) { - if (!NM_FLAGS_ANY(ch, nm_team_attribute_to_flags(team_attr))) - continue; - g_object_notify_by_pspec(G_OBJECT(source), (GParamSpec *) obj_properties[team_attr]); - ch &= ~nm_team_attribute_to_flags(team_attr); - if (ch == 0) - break; - } - - if (count_flags > 1) - g_object_thaw_notify(G_OBJECT(source)); - - return TRUE; -} - -/*****************************************************************************/ - -NMTeamSetting * -_nm_setting_get_team_setting(struct _NMSetting *setting) -{ - if (NM_IS_SETTING_TEAM(setting)) - return _nm_setting_team_get_team_setting(NM_SETTING_TEAM(setting)); - return _nm_setting_team_port_get_team_setting(NM_SETTING_TEAM_PORT(setting)); -} - -static GVariant * -_nm_team_settings_property_to_dbus(const NMSettInfoSetting * sett_info, - guint property_idx, - NMConnection * connection, - NMSetting * setting, - NMConnectionSerializationFlags flags, - const NMConnectionSerializationOptions *options) -{ - NMTeamSetting * self = _nm_setting_get_team_setting(setting); - const TeamAttrData *attr_data = - _team_attr_data_get(self->d.is_port, - sett_info->property_infos[property_idx].param_spec->param_id); - - if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_CONFIG) { - const char *config; - - if (self->d.strict_validated && !_nm_utils_is_manager_process) { - /* if we are in strict validating mode on the client side, the JSON is generated - * artificially. In this case, don't send the config via D-Bus to the server. - * - * This also will cause NetworkManager to strictly validate the settings. - * If a JSON "config" is present, strict validation won't be performed. */ - return NULL; - } - - config = nm_team_setting_config_get(self); - return config ? g_variant_new_string(config) : NULL; - } - - if (!_team_setting_has_field(self, attr_data)) - return NULL; - - if (attr_data->value_type != NM_VALUE_TYPE_UNSPEC) { - return nm_value_type_to_variant(attr_data->value_type, - _team_setting_get_field(self, attr_data)); - } - if (attr_data->team_attr == NM_TEAM_ATTRIBUTE_LINK_WATCHERS) - return _nm_utils_team_link_watchers_to_variant(self->d.link_watchers); - if (!self->d.is_port && attr_data->team_attr == NM_TEAM_ATTRIBUTE_MASTER_RUNNER_TX_HASH) { - return g_variant_new_strv(self->d.master.runner_tx_hash - ? (const char *const *) self->d.master.runner_tx_hash->pdata - : NULL, - self->d.master.runner_tx_hash ? self->d.master.runner_tx_hash->len - : 0u); - } - - nm_assert_not_reached(); - return NULL; -} - -static void -_nm_team_settings_property_from_dbus_link_watchers(GVariant *dbus_value, GValue *prop_value) -{ - g_value_take_boxed(prop_value, - _nm_utils_team_link_watchers_from_variant(dbus_value, FALSE, NULL)); -} - -const NMSettInfoPropertType nm_sett_info_propert_type_team_b = { - .dbus_type = G_VARIANT_TYPE_BOOLEAN, - .to_dbus_fcn = _nm_team_settings_property_to_dbus, -}; - -const NMSettInfoPropertType nm_sett_info_propert_type_team_i = { - .dbus_type = G_VARIANT_TYPE_INT32, - .to_dbus_fcn = _nm_team_settings_property_to_dbus, -}; - -const NMSettInfoPropertType nm_sett_info_propert_type_team_s = { - .dbus_type = G_VARIANT_TYPE_STRING, - .to_dbus_fcn = _nm_team_settings_property_to_dbus, -}; - -const NMSettInfoPropertType nm_sett_info_propert_type_team_as = { - .dbus_type = NM_G_VARIANT_TYPE("as"), - .to_dbus_fcn = _nm_team_settings_property_to_dbus, -}; - -const NMSettInfoPropertType nm_sett_info_propert_type_team_link_watchers = { - .dbus_type = NM_G_VARIANT_TYPE("aa{sv}"), - .to_dbus_fcn = _nm_team_settings_property_to_dbus, - .gprop_from_dbus_fcn = _nm_team_settings_property_from_dbus_link_watchers, -}; - -/*****************************************************************************/ - -NMTeamSetting * -nm_team_setting_new(gboolean is_port, const char *js_str) -{ - NMTeamSetting *self; - gsize l; - - G_STATIC_ASSERT_EXPR(sizeof(*self) == sizeof(self->_data_priv)); - G_STATIC_ASSERT_EXPR(sizeof(*self) - == NM_CONST_MAX(nm_offsetofend(NMTeamSetting, d.master), - nm_offsetofend(NMTeamSetting, d.port))); - - l = is_port ? nm_offsetofend(NMTeamSetting, d.port) : nm_offsetofend(NMTeamSetting, d.master); - - self = g_malloc0(l); - - self->_data_priv.is_port = is_port; - self->_data_priv.strict_validated = TRUE; - self->_data_priv._js_str_need_synthetize = FALSE; - self->_data_priv.link_watchers = - g_ptr_array_new_with_free_func((GDestroyNotify) nm_team_link_watcher_unref); - - _team_setting_ASSERT(self); - - nm_team_setting_config_set(self, js_str); - - _team_setting_ASSERT(self); - - return self; -} - -void -nm_team_setting_free(NMTeamSetting *self) -{ - if (!self) - return; - - _team_setting_ASSERT(self); - - if (!self->d.is_port) { - nm_clear_pointer(((GPtrArray **) &self->_data_priv.master.runner_tx_hash), - g_ptr_array_unref); - g_free((char *) self->_data_priv.master.runner); - g_free((char *) self->_data_priv.master.runner_hwaddr_policy); - g_free((char *) self->_data_priv.master.runner_tx_balancer); - g_free((char *) self->_data_priv.master.runner_agg_select_policy); - } - g_ptr_array_unref((GPtrArray *) self->_data_priv.link_watchers); - g_free((char *) self->_data_priv._js_str); - g_free(self); -} |