diff options
author | Thomas Haller <thaller@redhat.com> | 2019-04-13 18:12:18 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-04-13 18:12:18 +0200 |
commit | 6fe1a38de0f437ad06a119340fc40464dff4e2c4 (patch) | |
tree | 58d282a73e48d057e3aab6de10d83b39ebbda22b | |
parent | 549112c1ba5306dff281ef0788961ac855342d02 (diff) | |
parent | 65831ee84c47cb8e3e3412b6f1adb5e7ee1e87c4 (diff) | |
download | NetworkManager-6fe1a38de0f437ad06a119340fc40464dff4e2c4.tar.gz |
libnm: merge branch 'lr/tc-attrs-part1'
https://github.com/NetworkManager/NetworkManager/pull/343
-rw-r--r-- | clients/common/nm-meta-setting-desc.c | 10 | ||||
-rw-r--r-- | libnm-core/nm-setting-tc-config.c | 183 | ||||
-rw-r--r-- | libnm-core/nm-setting-tc-config.h | 10 | ||||
-rw-r--r-- | libnm-core/nm-utils.c | 65 | ||||
-rw-r--r-- | libnm/libnm.ver | 3 |
5 files changed, 251 insertions, 20 deletions
diff --git a/clients/common/nm-meta-setting-desc.c b/clients/common/nm-meta-setting-desc.c index 2b0386265c..1de51dc191 100644 --- a/clients/common/nm-meta-setting-desc.c +++ b/clients/common/nm-meta-setting-desc.c @@ -3580,9 +3580,9 @@ _objlist_set_fcn_tc_config_qdiscs (NMSetting *setting, tc_qdisc = nm_utils_tc_qdisc_from_str (value, &local); if (!tc_qdisc) { nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, - "%s %s", + "%s. %s", local->message, - _("The valid syntax is: '[root | parent <handle>] [handle <handle>] <qdisc>'")); + _("The valid syntax is: '[root | parent <handle>] [handle <handle>] <kind>'")); return FALSE; } if (do_add) @@ -3604,7 +3604,7 @@ _objlist_set_fcn_bridge_vlans (NMSetting *setting, vlan = nm_bridge_vlan_from_str (value, &local); if (!vlan) { nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, - "%s %s", + "%s. %s", local->message, _("The valid syntax is: '<vid> [pvid] [untagged]")); return FALSE; @@ -3656,9 +3656,9 @@ _objlist_set_fcn_tc_config_tfilters (NMSetting *setting, tc_tfilter = nm_utils_tc_tfilter_from_str (value, &local); if (!tc_tfilter) { nm_utils_error_set (error, NM_UTILS_ERROR_INVALID_ARGUMENT, - "%s %s", + "%s. %s", local->message, - _("The valid syntax is: '[root | parent <handle>] [handle <handle>] <tfilter>'")); + _("The valid syntax is: '[root | parent <handle>] [handle <handle>] <kind>'")); return FALSE; } if (do_add) diff --git a/libnm-core/nm-setting-tc-config.c b/libnm-core/nm-setting-tc-config.c index 7425ae73f4..d040a2ffbc 100644 --- a/libnm-core/nm-setting-tc-config.c +++ b/libnm-core/nm-setting-tc-config.c @@ -41,6 +41,7 @@ struct NMTCQdisc { char *kind; guint32 handle; guint32 parent; + GHashTable *attributes; }; /** @@ -62,7 +63,15 @@ nm_tc_qdisc_new (const char *kind, { NMTCQdisc *qdisc; - if (!kind || !*kind || strchr (kind, ' ') || strchr (kind, '\t')) { + if (!kind || !*kind) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("kind is missing")); + return NULL; + } + + if (strchr (kind, ' ') || strchr (kind, '\t')) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -122,6 +131,8 @@ nm_tc_qdisc_unref (NMTCQdisc *qdisc) qdisc->refcount--; if (qdisc->refcount == 0) { g_free (qdisc->kind); + if (qdisc->attributes) + g_hash_table_unref (qdisc->attributes); g_slice_free (NMTCQdisc, qdisc); } } @@ -141,6 +152,11 @@ nm_tc_qdisc_unref (NMTCQdisc *qdisc) gboolean nm_tc_qdisc_equal (NMTCQdisc *qdisc, NMTCQdisc *other) { + GHashTableIter iter; + const char *key; + GVariant *value, *value2; + guint n; + g_return_val_if_fail (qdisc != NULL, FALSE); g_return_val_if_fail (qdisc->refcount > 0, FALSE); @@ -152,19 +168,53 @@ nm_tc_qdisc_equal (NMTCQdisc *qdisc, NMTCQdisc *other) || g_strcmp0 (qdisc->kind, other->kind) != 0) return FALSE; + n = qdisc->attributes ? g_hash_table_size (qdisc->attributes) : 0; + if (n != (other->attributes ? g_hash_table_size (other->attributes) : 0)) + return FALSE; + if (n) { + g_hash_table_iter_init (&iter, qdisc->attributes); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) { + value2 = g_hash_table_lookup (other->attributes, key); + if (!value2) + return FALSE; + if (!g_variant_equal (value, value2)) + return FALSE; + } + } + return TRUE; } static guint _nm_tc_qdisc_hash (NMTCQdisc *qdisc) { + gs_free const char **names = NULL; + GVariant *variant; NMHashState h; + guint length; + guint i; + + names = nm_utils_strdict_get_keys (qdisc->attributes, TRUE, &length); nm_hash_init (&h, 43869703); nm_hash_update_vals (&h, qdisc->handle, - qdisc->parent); + qdisc->parent, + length); nm_hash_update_str0 (&h, qdisc->kind); + for (i = 0; i < length; i++) { + const GVariantType *vtype; + + variant = g_hash_table_lookup (qdisc->attributes, names[i]); + + vtype = g_variant_get_type (variant); + + nm_hash_update_str (&h, names[i]); + nm_hash_update_str (&h, (const char *) vtype); + if (g_variant_type_is_basic (vtype)) + nm_hash_update_val (&h, g_variant_hash (variant)); + } + return nm_hash_complete (&h); } @@ -189,6 +239,16 @@ nm_tc_qdisc_dup (NMTCQdisc *qdisc) copy = nm_tc_qdisc_new (qdisc->kind, qdisc->parent, NULL); nm_tc_qdisc_set_handle (copy, qdisc->handle); + if (qdisc->attributes) { + GHashTableIter iter; + const char *key; + GVariant *value; + + g_hash_table_iter_init (&iter, qdisc->attributes); + while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value)) + nm_tc_qdisc_set_attribute (copy, key, value); + } + return copy; } @@ -261,6 +321,79 @@ nm_tc_qdisc_get_parent (NMTCQdisc *qdisc) return qdisc->parent; } +/** + * nm_tc_qdisc_get_attribute_names: + * @qdisc: the #NMTCQdisc + * + * Gets an array of attribute names defined on @qdisc. + * + * Returns: (transfer full): a %NULL-terminated array of attribute names, + * + * Since: 1.18 + **/ +char ** +nm_tc_qdisc_get_attribute_names (NMTCQdisc *qdisc) +{ + const char **names; + + g_return_val_if_fail (qdisc, NULL); + + names = nm_utils_strdict_get_keys (qdisc->attributes, TRUE, NULL); + return nm_utils_strv_make_deep_copied_nonnull (names); +} + +/** + * nm_tc_qdisc_get_attribute: + * @qdisc: the #NMTCQdisc + * @name: the name of an qdisc attribute + * + * Gets the value of the attribute with name @name on @qdisc + * + * Returns: (transfer none): the value of the attribute with name @name on + * @qdisc, or %NULL if @qdisc has no such attribute. + * + * Since: 1.18 + **/ +GVariant * +nm_tc_qdisc_get_attribute (NMTCQdisc *qdisc, const char *name) +{ + g_return_val_if_fail (qdisc != NULL, NULL); + g_return_val_if_fail (name != NULL && *name != '\0', NULL); + + if (qdisc->attributes) + return g_hash_table_lookup (qdisc->attributes, name); + else + return NULL; +} + +/** + * nm_tc_qdisc_set_attribute: + * @qdisc: the #NMTCQdisc + * @name: the name of an qdisc attribute + * @value: (transfer none) (allow-none): the value + * + * Sets or clears the named attribute on @qdisc to the given value. + * + * Since: 1.18 + **/ +void +nm_tc_qdisc_set_attribute (NMTCQdisc *qdisc, const char *name, GVariant *value) +{ + g_return_if_fail (qdisc != NULL); + g_return_if_fail (name != NULL && *name != '\0'); + g_return_if_fail (strcmp (name, "kind") != 0); + + if (!qdisc->attributes) { + qdisc->attributes = g_hash_table_new_full (nm_str_hash, g_str_equal, + g_free, (GDestroyNotify) g_variant_unref); + } + + if (value) + g_hash_table_insert (qdisc->attributes, g_strdup (name), g_variant_ref_sink (value)); + else + g_hash_table_remove (qdisc->attributes, name); +} + /*****************************************************************************/ G_DEFINE_BOXED_TYPE (NMTCAction, nm_tc_action, nm_tc_action_dup, nm_tc_action_unref) @@ -290,7 +423,15 @@ nm_tc_action_new (const char *kind, { NMTCAction *action; - if (!kind || !*kind || strchr (kind, ' ') || strchr (kind, '\t')) { + if (!kind || !*kind) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("kind is missing")); + return NULL; + } + + if (strchr (kind, ' ') || strchr (kind, '\t')) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -544,7 +685,15 @@ nm_tc_tfilter_new (const char *kind, { NMTCTfilter *tfilter; - if (!kind || !*kind || strchr (kind, ' ') || strchr (kind, '\t')) { + if (!kind || !*kind) { + g_set_error (error, + NM_CONNECTION_ERROR, + NM_CONNECTION_ERROR_INVALID_PROPERTY, + _("kind is missing")); + return NULL; + } + + if (strchr (kind, ' ') || strchr (kind, '\t')) { g_set_error (error, NM_CONNECTION_ERROR, NM_CONNECTION_ERROR_INVALID_PROPERTY, @@ -1222,7 +1371,10 @@ _qdiscs_to_variant (GPtrArray *qdiscs) if (qdiscs) { for (i = 0; i < qdiscs->len; i++) { NMTCQdisc *qdisc = qdiscs->pdata[i]; + guint length; + gs_free const char **attrs = nm_utils_strdict_get_keys (qdisc->attributes, TRUE, &length); GVariantBuilder qdisc_builder; + guint y; g_variant_builder_init (&qdisc_builder, G_VARIANT_TYPE_VARDICT); @@ -1235,6 +1387,11 @@ _qdiscs_to_variant (GPtrArray *qdiscs) g_variant_builder_add (&qdisc_builder, "{sv}", "parent", g_variant_new_uint32 (nm_tc_qdisc_get_parent (qdisc))); + for (y = 0; y < length; y++) { + g_variant_builder_add (&qdisc_builder, "{sv}", attrs[y], + g_hash_table_lookup (qdisc->attributes, attrs[y])); + } + g_variant_builder_add (&builder, "a{sv}", &qdisc_builder); } } @@ -1267,9 +1424,11 @@ _qdiscs_from_variant (GVariant *value) while (g_variant_iter_next (&iter, "@a{sv}", &qdisc_var)) { const char *kind; - guint32 handle; guint32 parent; NMTCQdisc *qdisc; + GVariantIter qdisc_iter; + const char *key; + GVariant *attr_value; if ( !g_variant_lookup (qdisc_var, "kind", "&s", &kind) || !g_variant_lookup (qdisc_var, "parent", "u", &parent)) { @@ -1284,8 +1443,18 @@ _qdiscs_from_variant (GVariant *value) goto next; } - if (g_variant_lookup (qdisc_var, "handle", "u", &handle)) - nm_tc_qdisc_set_handle (qdisc, handle); + g_variant_iter_init (&qdisc_iter, qdisc_var); + while (g_variant_iter_next (&qdisc_iter, "{&sv}", &key, &attr_value)) { + if ( strcmp (key, "kind") == 0 + || strcmp (key, "parent") == 0) { + /* Already processed above */ + } else if (strcmp (key, "handle") == 0) { + nm_tc_qdisc_set_handle (qdisc, g_variant_get_uint32 (attr_value)); + } else { + nm_tc_qdisc_set_attribute (qdisc, key, attr_value); + } + g_variant_unref (attr_value); + } g_ptr_array_add (qdiscs, qdisc); next: diff --git a/libnm-core/nm-setting-tc-config.h b/libnm-core/nm-setting-tc-config.h index 6296b1abba..002b3db161 100644 --- a/libnm-core/nm-setting-tc-config.h +++ b/libnm-core/nm-setting-tc-config.h @@ -59,6 +59,16 @@ void nm_tc_qdisc_set_handle (NMTCQdisc *qdisc, NM_AVAILABLE_IN_1_12 guint32 nm_tc_qdisc_get_parent (NMTCQdisc *qdisc); +NM_AVAILABLE_IN_1_18 +char**nm_tc_qdisc_get_attribute_names (NMTCQdisc *qdisc); +NM_AVAILABLE_IN_1_18 +GVariant *nm_tc_qdisc_get_attribute (NMTCQdisc *qdisc, + const char *name); +NM_AVAILABLE_IN_1_18 +void nm_tc_qdisc_set_attribute (NMTCQdisc *qdisc, + const char *name, + GVariant *value); + typedef struct NMTCAction NMTCAction; NM_AVAILABLE_IN_1_12 diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c index 68c6647784..af05cdfb6e 100644 --- a/libnm-core/nm-utils.c +++ b/libnm-core/nm-utils.c @@ -2309,6 +2309,15 @@ static const NMVariantAttributeSpec * const tc_object_attribute_spec[] = { NULL, }; +typedef struct { + const char *kind; + const NMVariantAttributeSpec * const *attrs; +} NMQdiscAttributeSpec; + +static const NMQdiscAttributeSpec *const tc_qdisc_attribute_spec[] = { + NULL, +}; + /*****************************************************************************/ /** @@ -2323,8 +2332,12 @@ static const NMVariantAttributeSpec * const tc_object_attribute_spec[] = { void _nm_utils_string_append_tc_qdisc_rest (GString *string, NMTCQdisc *qdisc) { + gs_unref_hashtable GHashTable *ht = NULL; guint32 handle = nm_tc_qdisc_get_handle (qdisc); const char *kind = nm_tc_qdisc_get_kind (qdisc); + gs_strfreev char **attr_names = NULL; + gs_free char *str = NULL; + guint i; if (handle != TC_H_UNSPEC && strcmp (kind, "ingress") != 0) { g_string_append (string, "handle "); @@ -2333,6 +2346,20 @@ _nm_utils_string_append_tc_qdisc_rest (GString *string, NMTCQdisc *qdisc) } g_string_append (string, kind); + + attr_names = nm_tc_qdisc_get_attribute_names (qdisc); + if (attr_names[0]) + ht = g_hash_table_new_full (nm_str_hash, g_str_equal, NULL, NULL); + for (i = 0; attr_names[i]; i++) { + g_hash_table_insert (ht, attr_names[i], + nm_tc_qdisc_get_attribute (qdisc, attr_names[i])); + } + + if (i) { + str = nm_utils_format_variant_attributes (ht, ' ', ' '); + g_string_append_c (string, ' '); + g_string_append (string, str); + } } /** @@ -2455,21 +2482,36 @@ nm_utils_tc_qdisc_from_str (const char *str, GError **error) gs_free char *kind = NULL; gs_free char *rest = NULL; NMTCQdisc *qdisc = NULL; - gs_unref_hashtable GHashTable *ht = NULL; + gs_unref_hashtable GHashTable *options = NULL; + GHashTableIter iter; + gpointer key, value; + guint i; nm_assert (str); nm_assert (!error || !*error); - ht = nm_utils_parse_variant_attributes (str, - ' ', ' ', FALSE, - tc_object_attribute_spec, - error); - if (!ht) - return NULL; - if (!_tc_read_common_opts (str, &handle, &parent, &kind, &rest, error)) return NULL; + for (i = 0; rest && tc_qdisc_attribute_spec[i]; i++) { + if (strcmp (tc_qdisc_attribute_spec[i]->kind, kind) == 0) { + options = nm_utils_parse_variant_attributes (rest, + ' ', ' ', FALSE, + tc_qdisc_attribute_spec[i]->attrs, + error); + if (!options) + return NULL; + break; + } + } + nm_clear_pointer (&rest, g_free); + + if (options) { + value = g_hash_table_lookup (options, ""); + if (value) + rest = g_variant_dup_string (value, NULL); + } + if (rest) { g_set_error (error, 1, 0, _("unsupported qdisc option: '%s'."), rest); return NULL; @@ -2481,8 +2523,15 @@ nm_utils_tc_qdisc_from_str (const char *str, GError **error) nm_tc_qdisc_set_handle (qdisc, handle); + if (options) { + g_hash_table_iter_init (&iter, options); + while (g_hash_table_iter_next (&iter, &key, &value)) + nm_tc_qdisc_set_attribute (qdisc, key, g_variant_ref_sink (value)); + } + return qdisc; } + /*****************************************************************************/ static const NMVariantAttributeSpec * const tc_action_simple_attribute_spec[] = { diff --git a/libnm/libnm.ver b/libnm/libnm.ver index ac8c7b97cf..8763e11a6c 100644 --- a/libnm/libnm.ver +++ b/libnm/libnm.ver @@ -1600,4 +1600,7 @@ global: nm_setting_ip_config_get_num_routing_rules; nm_setting_ip_config_get_routing_rule; nm_setting_ip_config_remove_routing_rule; + nm_tc_qdisc_get_attribute; + nm_tc_qdisc_get_attribute_names; + nm_tc_qdisc_set_attribute; } libnm_1_16_0; |