mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2025-12-25 13:00:16 +01:00
libnm: merge branch 'lr/tc-attrs-part1'
https://github.com/NetworkManager/NetworkManager/pull/343
This commit is contained in:
commit
6fe1a38de0
5 changed files with 251 additions and 20 deletions
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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[] = {
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue