diff options
author | Francesco Giudici <fgiudici@redhat.com> | 2017-10-26 11:39:58 +0200 |
---|---|---|
committer | Francesco Giudici <fgiudici@redhat.com> | 2017-11-09 17:56:15 +0100 |
commit | dadf710ee370b928a1e3e4cd0c515eecc7bea108 (patch) | |
tree | 44f4e72e58b76ab7a3451519fccaff7cc88323b2 /libnm-core | |
parent | b6c0498b04356b7ecb8129054fe0094ae2b1b15f (diff) | |
download | NetworkManager-dadf710ee370b928a1e3e4cd0c515eecc7bea108.tar.gz |
libnm-core: add functions to align team json config to exposed properties
Diffstat (limited to 'libnm-core')
-rw-r--r-- | libnm-core/nm-core-internal.h | 13 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 292 |
2 files changed, 304 insertions, 1 deletions
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h index 60963c9cd9..5144a05077 100644 --- a/libnm-core/nm-core-internal.h +++ b/libnm-core/nm-core-internal.h @@ -435,7 +435,18 @@ gboolean _nm_utils_inet6_is_token (const struct in6_addr *in6addr); /*****************************************************************************/ -gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, gboolean port); +gboolean _nm_utils_team_config_equal (const char *conf1, const char *conf2, gboolean port); +GValue *_nm_utils_team_config_get (const char *conf, + const char *key, + const char *key2, + const char *key3, + gboolean port_config); + +gboolean _nm_utils_team_config_set (char **conf, + const char *key, + const char *key2, + const char *key3, + const GValue *value); /*****************************************************************************/ diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index f2fa73248d..ec7a80f958 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -4441,6 +4441,278 @@ out: return ret; } + + +static void +_json_add_object (json_t *json, + const char *key1, + const char *key2, + const char *key3, + json_t *value) +{ + json_t *json_element, *json_link; + + json_element = json_object_get (json, key1); + if (!json_element) { + json_element = value; + if (key2) { + if (key3) { + json_element = json_object (); + json_object_set_new (json_element, key3, value); + } + json_link = json_object (); + json_object_set_new (json_link, key2, json_element); + json_element = json_link; + } + json_object_set_new (json, key1, json_element); + return; + } + + if (!key2) + goto key_already_there; + + json_link = json_element; + json_element = json_object_get (json_element, key2); + if (!json_element) { + json_element = value; + if (key3) { + json_element = json_object (); + json_object_set_new (json_element, key3, value); + } + json_object_set_new (json_link, key2, json_element); + return; + } + + if (!key3) + goto key_already_there; + + json_link = json_element; + json_element = json_object_get (json_element, key3); + if (!json_element) { + json_object_set_new (json_link, key3, value); + return; + } + +key_already_there: + json_decref (value); +} + +GValue * +_nm_utils_team_config_get (const char *conf, + const char *key, + const char *key2, + const char *key3, + gboolean port_config) +{ + json_t *json; + json_t *json_element; + GValue *value = NULL; + json_error_t jerror; + const char *runner = NULL; + + if (!key) + return NULL; + + json = json_loads (conf ?: "{}", JSON_REJECT_DUPLICATES, &jerror); + + /* Invalid json in conf */ + if (!json) + return NULL; + + /* Some properties are added by teamd when missing from the initial + * configuration. Add them with the default value if necessary, depending + * on the configuration type. + */ + if (port_config) { + _json_add_object (json, "link_watch", "name", NULL, json_string ("ethtool")); + } else { + /* Retrieve runner or add default one */ + json_element = json_object_get (json, "runner"); + if (json_element) { + runner = json_string_value (json_object_get (json_element, "name")); + } else { + json_element = json_object (); + json_object_set_new (json, "runner", json_element); + } + if (!runner) { + runner = "roundrobin"; + json_object_set_new (json_element, "name", json_string (runner)); + } + + + if (nm_streq (runner, "activebackup")) { + _json_add_object (json, "notify_peers", "count", NULL, json_integer (1)); + _json_add_object (json, "mcast_rejoin", "count", NULL, json_integer (1)); + _json_add_object (json, "runner", "hwaddr_policy", NULL, json_string ("same_all")); + } else if (nm_streq (runner, "loadbalance") || nm_streq (runner, "lacp")) { + json_element = json_array (); + json_array_append_new (json_element, json_string ("eth")); + json_array_append_new (json_element, json_string ("ipv4")); + json_array_append_new (json_element, json_string ("ipv6")); + _json_add_object (json, "runner", "tx_hash", NULL, json_element); + } + } + json_element = json_object_get (json, key); + if (json_element && key2) + json_element = json_object_get (json_element, key2); + if (json_element && key3) + json_element = json_object_get (json_element, key3); + + if (json_element) { + value = g_new0 (GValue, 1); + if (json_is_string (json_element)) { + g_value_init (value, G_TYPE_STRING); + g_value_set_string (value, json_string_value (json_element)); + } else if (json_is_integer (json_element)) { + g_value_init (value, G_TYPE_INT); + g_value_set_int (value, json_integer_value (json_element)); + } else if (json_is_boolean (json_element)) { + g_value_init (value, G_TYPE_BOOLEAN); + g_value_set_boolean (value, json_boolean_value (json_element)); + } else if (json_is_array (json_element)) { + GPtrArray *data = g_ptr_array_new_with_free_func ((GDestroyNotify) g_free); + json_t *str_element; + int index; + + json_array_foreach (json_element, index, str_element) { + if (json_is_string (str_element)) + g_ptr_array_add (data, g_strdup (json_string_value (str_element))); + } + if (data->len) { + g_value_init (value, G_TYPE_STRV); + g_value_take_boxed (value, _nm_utils_ptrarray_to_strv (data)); + } + g_ptr_array_free (data, TRUE); + } else { + g_assert_not_reached (); + g_free (value); + value = NULL; + } + } + + if (json) + json_decref (json); + + return value; +} + +/* if conf is updated in place returns TRUE */ +gboolean +_nm_utils_team_config_set (char **conf, + const char *key, + const char *key2, + const char *key3, + const GValue *value) +{ + json_t *json, *json_element, *json_link, *json_value = NULL; + json_error_t jerror; + gboolean updated = FALSE; + char **strv; + const char *iter_key = key; + int i; + + json = json_loads (*conf?: "{}", JSON_REJECT_DUPLICATES, &jerror); + if (!json) + return FALSE; + + /* no new value? delete element */ + if (!value) { + json_element = json; + json_link = NULL; + + if (key2) { + json_link = json; + json_element = json_object_get (json, key); + if (!json_element) + goto done; + iter_key = key2; + } + if (key3) { + json_link = json_element; + json_element = json_object_get (json_element, key2); + if (!json_element) + goto done; + iter_key = key3; + } + if (json_object_del (json_element, iter_key) != 0) + goto done; + + updated = TRUE; + + /* 1st level key only */ + if (!json_link) + goto done; + + if (json_object_size (json_element) == 0) + json_object_del (json_link, (key3 ? key2 : key)); + + if (key3 && json_object_size (json_link) == 0) + json_object_del (json, key); + + goto done; + } + + /* insert new value */ + updated = TRUE; + if (G_VALUE_HOLDS_STRING (value)) + json_value = json_string (g_value_get_string (value)); + else if (G_VALUE_HOLDS_INT (value)) + json_value = json_integer (g_value_get_int (value)); + else if (G_VALUE_HOLDS_BOOLEAN (value)) + json_value = json_boolean (g_value_get_boolean (value)); + else if (G_VALUE_HOLDS_BOXED (value)) { + strv = g_value_get_boxed (value); + if (strv) { + json_value = json_array (); + for (i = 0; strv[i]; i++) + json_array_append_new (json_value, json_string (strv[i])); + } else + return FALSE; + } else { + g_assert_not_reached (); + updated = FALSE; + goto done; + } + + /* Simplest case: first level key only */ + json_element = json; + json_link = NULL; + + if (key2) { + json_link = json; + json_element = json_object_get (json, iter_key); + if (!json_element) { + json_element = json_object (); + json_object_set_new (json_link, iter_key, json_element); + } + iter_key = key2; + } + if (key3) { + json_link = json_element; + json_element = json_object_get (json_link, iter_key); + if (!json_element) { + json_element = json_object (); + json_object_set_new (json_link, iter_key, json_element); + } + iter_key = key3; + } + + json_object_set_new (json_element, iter_key, json_value); + +done: + if (updated) { + g_free (*conf); + *conf = json_dumps (json, 0); + /* Don't save an empty config */ + if (nm_streq0 (*conf, "{}")) { + g_free (*conf); + *conf = NULL; + } + } + json_decref (json); + return updated; +} + #else /* WITH_JANSSON */ gboolean @@ -4495,6 +4767,26 @@ _nm_utils_team_config_equal (const char *conf1, { return nm_streq0 (conf1, conf2); } + +GValue * +_nm_utils_team_config_get (const char *conf, + const char *key, + const char *key2, + const char *key3, + gboolean port_config) +{ + return NULL; +} + +gboolean +_nm_utils_team_config_set (char **conf, + const char *key, + const char *key2, + const char *key3, + const GValue *value) +{ + return FALSE; +} #endif static char * |