2019-09-10 11:19:01 +02:00
|
|
|
// SPDX-License-Identifier: LGPL-2.1+
|
2017-11-16 17:35:20 +01:00
|
|
|
/*
|
2019-10-01 09:20:35 +02:00
|
|
|
* Copyright (C) 2017 Red Hat, Inc.
|
2017-11-16 17:35:20 +01:00
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "nm-default.h"
|
|
|
|
|
|
2019-01-11 08:32:54 +01:00
|
|
|
#include "nm-setting-tc-config.h"
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
#include <linux/pkt_sched.h>
|
|
|
|
|
|
|
|
|
|
#include "nm-setting-private.h"
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* SECTION:nm-setting-tc-config
|
|
|
|
|
* @short_description: Describes connection properties for the Linux Traffic Control
|
|
|
|
|
* @include: nm-setting-tc-config.h
|
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
G_DEFINE_BOXED_TYPE (NMTCQdisc, nm_tc_qdisc, nm_tc_qdisc_dup, nm_tc_qdisc_unref)
|
|
|
|
|
|
|
|
|
|
struct NMTCQdisc {
|
|
|
|
|
guint refcount;
|
|
|
|
|
|
|
|
|
|
char *kind;
|
|
|
|
|
guint32 handle;
|
|
|
|
|
guint32 parent;
|
2019-04-09 09:10:43 +02:00
|
|
|
GHashTable *attributes;
|
2017-11-16 17:35:20 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_new:
|
|
|
|
|
* @kind: name of the queueing discipline
|
|
|
|
|
* @parent: the parent queueing discipline
|
|
|
|
|
* @error: location to store error, or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Creates a new #NMTCQdisc object.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): the new #NMTCQdisc object, or %NULL on error
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCQdisc *
|
|
|
|
|
nm_tc_qdisc_new (const char *kind,
|
|
|
|
|
guint32 parent,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
NMTCQdisc *qdisc;
|
|
|
|
|
|
2019-04-09 08:14:25 +02:00
|
|
|
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')) {
|
2017-11-16 17:35:20 +01:00
|
|
|
g_set_error (error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("'%s' is not a valid kind"), kind);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
|
g_set_error_literal (error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("parent handle missing"));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qdisc = g_slice_new0 (NMTCQdisc);
|
|
|
|
|
qdisc->refcount = 1;
|
|
|
|
|
|
|
|
|
|
qdisc->kind = g_strdup (kind);
|
|
|
|
|
qdisc->parent = parent;
|
|
|
|
|
|
|
|
|
|
return qdisc;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_ref:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
*
|
|
|
|
|
* Increases the reference count of the object.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_qdisc_ref (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (qdisc != NULL);
|
|
|
|
|
g_return_if_fail (qdisc->refcount > 0);
|
|
|
|
|
|
|
|
|
|
qdisc->refcount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_unref:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
*
|
|
|
|
|
* Decreases the reference count of the object. If the reference count
|
|
|
|
|
* reaches zero, the object will be destroyed.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_qdisc_unref (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (qdisc != NULL);
|
|
|
|
|
g_return_if_fail (qdisc->refcount > 0);
|
|
|
|
|
|
|
|
|
|
qdisc->refcount--;
|
|
|
|
|
if (qdisc->refcount == 0) {
|
|
|
|
|
g_free (qdisc->kind);
|
2019-04-09 09:10:43 +02:00
|
|
|
if (qdisc->attributes)
|
|
|
|
|
g_hash_table_unref (qdisc->attributes);
|
2017-11-16 17:35:20 +01:00
|
|
|
g_slice_free (NMTCQdisc, qdisc);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_equal:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
* @other: the #NMTCQdisc to compare @qdisc to.
|
|
|
|
|
*
|
|
|
|
|
* Determines if two #NMTCQdisc objects contain the same kind, * handle
|
|
|
|
|
* and parent.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the objects contain the same values, %FALSE if they do not.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_tc_qdisc_equal (NMTCQdisc *qdisc, NMTCQdisc *other)
|
|
|
|
|
{
|
2019-04-09 09:10:43 +02:00
|
|
|
GHashTableIter iter;
|
|
|
|
|
const char *key;
|
|
|
|
|
GVariant *value, *value2;
|
|
|
|
|
guint n;
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
g_return_val_if_fail (qdisc != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (qdisc->refcount > 0, FALSE);
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (other != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (other->refcount > 0, FALSE);
|
|
|
|
|
|
|
|
|
|
if ( qdisc->handle != other->handle
|
|
|
|
|
|| qdisc->parent != other->parent
|
|
|
|
|
|| g_strcmp0 (qdisc->kind, other->kind) != 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
static guint
|
|
|
|
|
_nm_tc_qdisc_hash (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
2020-06-07 01:16:04 +02:00
|
|
|
NMUtilsNamedValue attrs_static[30];
|
|
|
|
|
gs_free NMUtilsNamedValue *attrs_free = NULL;
|
|
|
|
|
const NMUtilsNamedValue *attrs;
|
2018-06-21 15:56:29 +02:00
|
|
|
NMHashState h;
|
2019-04-09 09:10:43 +02:00
|
|
|
guint length;
|
|
|
|
|
guint i;
|
|
|
|
|
|
2020-06-07 01:16:04 +02:00
|
|
|
attrs = nm_utils_named_values_from_strdict (qdisc->attributes, &length, attrs_static, &attrs_free);
|
2018-06-21 15:56:29 +02:00
|
|
|
|
|
|
|
|
nm_hash_init (&h, 43869703);
|
|
|
|
|
nm_hash_update_vals (&h,
|
|
|
|
|
qdisc->handle,
|
2019-04-09 09:10:43 +02:00
|
|
|
qdisc->parent,
|
|
|
|
|
length);
|
2018-06-21 15:56:29 +02:00
|
|
|
nm_hash_update_str0 (&h, qdisc->kind);
|
2019-04-09 09:10:43 +02:00
|
|
|
for (i = 0; i < length; i++) {
|
2020-06-07 01:16:04 +02:00
|
|
|
const char *key = attrs[i].name;
|
|
|
|
|
GVariant *variant = attrs[i].value_ptr;
|
2019-04-09 09:10:43 +02:00
|
|
|
const GVariantType *vtype;
|
|
|
|
|
|
|
|
|
|
vtype = g_variant_get_type (variant);
|
|
|
|
|
|
2020-06-07 01:16:04 +02:00
|
|
|
nm_hash_update_str (&h, key);
|
2019-04-09 09:10:43 +02:00
|
|
|
nm_hash_update_str (&h, (const char *) vtype);
|
|
|
|
|
if (g_variant_type_is_basic (vtype))
|
|
|
|
|
nm_hash_update_val (&h, g_variant_hash (variant));
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
return nm_hash_complete (&h);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_dup:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
*
|
|
|
|
|
* Creates a copy of @qdisc
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): a copy of @qdisc
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCQdisc *
|
|
|
|
|
nm_tc_qdisc_dup (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
NMTCQdisc *copy;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (qdisc != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (qdisc->refcount > 0, NULL);
|
|
|
|
|
|
|
|
|
|
copy = nm_tc_qdisc_new (qdisc->kind, qdisc->parent, NULL);
|
|
|
|
|
nm_tc_qdisc_set_handle (copy, qdisc->handle);
|
|
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
return copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_get_kind:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
*
|
|
|
|
|
* Returns:
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
const char *
|
|
|
|
|
nm_tc_qdisc_get_kind (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (qdisc != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (qdisc->refcount > 0, NULL);
|
|
|
|
|
|
|
|
|
|
return qdisc->kind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_get_handle:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
*
|
|
|
|
|
* Returns: the queueing discipline handle
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_tc_qdisc_get_handle (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (qdisc != NULL, TC_H_UNSPEC);
|
|
|
|
|
g_return_val_if_fail (qdisc->refcount > 0, TC_H_UNSPEC);
|
|
|
|
|
|
|
|
|
|
return qdisc->handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_set_handle:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
* @handle: the queueing discipline handle
|
|
|
|
|
*
|
|
|
|
|
* Sets the queueing discipline handle.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_qdisc_set_handle (NMTCQdisc *qdisc, guint32 handle)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (qdisc != NULL);
|
|
|
|
|
g_return_if_fail (qdisc->refcount > 0);
|
|
|
|
|
|
|
|
|
|
qdisc->handle = handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_get_parent:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
*
|
|
|
|
|
* Returns: the parent class
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_tc_qdisc_get_parent (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (qdisc != NULL, TC_H_UNSPEC);
|
|
|
|
|
g_return_val_if_fail (qdisc->refcount > 0, TC_H_UNSPEC);
|
|
|
|
|
|
|
|
|
|
return qdisc->parent;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
/**
|
|
|
|
|
* nm_tc_qdisc_get_attribute_names:
|
|
|
|
|
* @qdisc: the #NMTCQdisc
|
|
|
|
|
*
|
|
|
|
|
* Gets an array of attribute names defined on @qdisc.
|
|
|
|
|
*
|
2019-04-19 11:40:56 +02:00
|
|
|
* Returns: (transfer container): a %NULL-terminated array of attribute names
|
|
|
|
|
* or %NULL if no attributes are set.
|
2019-04-09 09:10:43 +02:00
|
|
|
*
|
|
|
|
|
* Since: 1.18
|
|
|
|
|
**/
|
2019-04-19 11:40:56 +02:00
|
|
|
const char **
|
2019-04-09 09:10:43 +02:00
|
|
|
nm_tc_qdisc_get_attribute_names (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (qdisc, NULL);
|
|
|
|
|
|
2019-04-19 11:40:56 +02:00
|
|
|
return nm_utils_strdict_get_keys (qdisc->attributes, TRUE, NULL);
|
2019-04-09 09:10:43 +02:00
|
|
|
}
|
|
|
|
|
|
2019-04-19 11:51:42 +02:00
|
|
|
GHashTable *
|
|
|
|
|
_nm_tc_qdisc_get_attributes (NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
nm_assert (qdisc);
|
|
|
|
|
|
|
|
|
|
return qdisc->attributes;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
/**
|
|
|
|
|
* 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);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
/*****************************************************************************/
|
2017-11-25 22:45:32 +01:00
|
|
|
|
|
|
|
|
G_DEFINE_BOXED_TYPE (NMTCAction, nm_tc_action, nm_tc_action_dup, nm_tc_action_unref)
|
|
|
|
|
|
|
|
|
|
struct NMTCAction {
|
|
|
|
|
guint refcount;
|
|
|
|
|
|
|
|
|
|
char *kind;
|
|
|
|
|
|
|
|
|
|
GHashTable *attributes;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_action_new:
|
|
|
|
|
* @kind: name of the queueing discipline
|
|
|
|
|
* @error: location to store error, or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Creates a new #NMTCAction object.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): the new #NMTCAction object, or %NULL on error
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCAction *
|
|
|
|
|
nm_tc_action_new (const char *kind,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
NMTCAction *action;
|
|
|
|
|
|
2019-04-09 08:14:25 +02:00
|
|
|
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')) {
|
2017-11-28 09:22:49 +01:00
|
|
|
g_set_error (error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("'%s' is not a valid kind"), kind);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-25 22:45:32 +01:00
|
|
|
action = g_slice_new0 (NMTCAction);
|
|
|
|
|
action->refcount = 1;
|
|
|
|
|
|
|
|
|
|
action->kind = g_strdup (kind);
|
|
|
|
|
|
|
|
|
|
return action;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_action_ref:
|
|
|
|
|
* @action: the #NMTCAction
|
|
|
|
|
*
|
|
|
|
|
* Increases the reference count of the object.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_action_ref (NMTCAction *action)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (action != NULL);
|
|
|
|
|
g_return_if_fail (action->refcount > 0);
|
|
|
|
|
|
|
|
|
|
action->refcount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_action_unref:
|
|
|
|
|
* @action: the #NMTCAction
|
|
|
|
|
*
|
|
|
|
|
* Decreases the reference count of the object. If the reference count
|
|
|
|
|
* reaches zero, the object will be destroyed.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_action_unref (NMTCAction *action)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (action != NULL);
|
|
|
|
|
g_return_if_fail (action->refcount > 0);
|
|
|
|
|
|
|
|
|
|
action->refcount--;
|
|
|
|
|
if (action->refcount == 0) {
|
|
|
|
|
g_free (action->kind);
|
|
|
|
|
if (action->attributes)
|
|
|
|
|
g_hash_table_unref (action->attributes);
|
|
|
|
|
g_slice_free (NMTCAction, action);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_action_equal:
|
|
|
|
|
* @action: the #NMTCAction
|
|
|
|
|
* @other: the #NMTCAction to compare @action to.
|
|
|
|
|
*
|
|
|
|
|
* Determines if two #NMTCAction objects contain the same kind, family,
|
|
|
|
|
* handle, parent and info.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the objects contain the same values, %FALSE if they do not.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_tc_action_equal (NMTCAction *action, NMTCAction *other)
|
|
|
|
|
{
|
2017-12-10 12:43:34 +01:00
|
|
|
GHashTableIter iter;
|
|
|
|
|
const char *key;
|
|
|
|
|
GVariant *value, *value2;
|
|
|
|
|
guint n;
|
2017-11-25 22:45:32 +01:00
|
|
|
|
2017-12-10 12:43:34 +01:00
|
|
|
g_return_val_if_fail (!action || action->refcount > 0, FALSE);
|
|
|
|
|
g_return_val_if_fail (!other || other->refcount > 0, FALSE);
|
2017-11-25 22:45:32 +01:00
|
|
|
|
2017-12-10 12:43:34 +01:00
|
|
|
if (action == other)
|
|
|
|
|
return TRUE;
|
|
|
|
|
if (!action || !other)
|
|
|
|
|
return FALSE;
|
2017-11-25 22:45:32 +01:00
|
|
|
|
|
|
|
|
if (g_strcmp0 (action->kind, other->kind) != 0)
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
2017-12-10 12:43:34 +01:00
|
|
|
n = action->attributes ? g_hash_table_size (action->attributes) : 0;
|
|
|
|
|
if (n != (other->attributes ? g_hash_table_size (other->attributes) : 0))
|
|
|
|
|
return FALSE;
|
|
|
|
|
if (n) {
|
|
|
|
|
g_hash_table_iter_init (&iter, action->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;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-25 22:45:32 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_action_dup:
|
|
|
|
|
* @action: the #NMTCAction
|
|
|
|
|
*
|
|
|
|
|
* Creates a copy of @action
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): a copy of @action
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCAction *
|
|
|
|
|
nm_tc_action_dup (NMTCAction *action)
|
|
|
|
|
{
|
|
|
|
|
NMTCAction *copy;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (action != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (action->refcount > 0, NULL);
|
|
|
|
|
|
|
|
|
|
copy = nm_tc_action_new (action->kind, NULL);
|
|
|
|
|
|
|
|
|
|
if (action->attributes) {
|
|
|
|
|
GHashTableIter iter;
|
|
|
|
|
const char *key;
|
|
|
|
|
GVariant *value;
|
|
|
|
|
|
|
|
|
|
g_hash_table_iter_init (&iter, action->attributes);
|
|
|
|
|
while (g_hash_table_iter_next (&iter, (gpointer *) &key, (gpointer *) &value))
|
|
|
|
|
nm_tc_action_set_attribute (copy, key, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_action_get_kind:
|
|
|
|
|
* @action: the #NMTCAction
|
|
|
|
|
*
|
|
|
|
|
* Returns:
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
const char *
|
|
|
|
|
nm_tc_action_get_kind (NMTCAction *action)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (action != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (action->refcount > 0, NULL);
|
|
|
|
|
|
|
|
|
|
return action->kind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_action_get_attribute_names:
|
|
|
|
|
* @action: the #NMTCAction
|
|
|
|
|
*
|
|
|
|
|
* Gets an array of attribute names defined on @action.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): a %NULL-terminated array of attribute names,
|
2020-06-07 01:10:11 +02:00
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
2017-11-25 22:45:32 +01:00
|
|
|
**/
|
|
|
|
|
char **
|
|
|
|
|
nm_tc_action_get_attribute_names (NMTCAction *action)
|
|
|
|
|
{
|
2017-12-10 12:20:38 +01:00
|
|
|
const char **names;
|
2017-11-25 22:45:32 +01:00
|
|
|
|
2017-12-10 12:20:38 +01:00
|
|
|
g_return_val_if_fail (action, NULL);
|
2017-11-25 22:45:32 +01:00
|
|
|
|
2017-12-10 12:20:38 +01:00
|
|
|
names = nm_utils_strdict_get_keys (action->attributes, TRUE, NULL);
|
|
|
|
|
return nm_utils_strv_make_deep_copied_nonnull (names);
|
2017-11-25 22:45:32 +01:00
|
|
|
}
|
|
|
|
|
|
2019-04-19 11:51:42 +02:00
|
|
|
GHashTable *
|
|
|
|
|
_nm_tc_action_get_attributes (NMTCAction *action)
|
|
|
|
|
{
|
|
|
|
|
nm_assert (action);
|
|
|
|
|
|
|
|
|
|
return action->attributes;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-25 22:45:32 +01:00
|
|
|
/**
|
|
|
|
|
* nm_tc_action_get_attribute:
|
|
|
|
|
* @action: the #NMTCAction
|
|
|
|
|
* @name: the name of an action attribute
|
|
|
|
|
*
|
|
|
|
|
* Gets the value of the attribute with name @name on @action
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): the value of the attribute with name @name on
|
|
|
|
|
* @action, or %NULL if @action has no such attribute.
|
2020-06-07 01:10:11 +02:00
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
2017-11-25 22:45:32 +01:00
|
|
|
**/
|
|
|
|
|
GVariant *
|
|
|
|
|
nm_tc_action_get_attribute (NMTCAction *action, const char *name)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (action != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (name != NULL && *name != '\0', NULL);
|
|
|
|
|
|
|
|
|
|
if (action->attributes)
|
|
|
|
|
return g_hash_table_lookup (action->attributes, name);
|
|
|
|
|
else
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_action_set_attribute:
|
|
|
|
|
* @action: the #NMTCAction
|
|
|
|
|
* @name: the name of an action attribute
|
|
|
|
|
* @value: (transfer none) (allow-none): the value
|
|
|
|
|
*
|
|
|
|
|
* Sets or clears the named attribute on @action to the given value.
|
2020-06-07 01:10:11 +02:00
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
2017-11-25 22:45:32 +01:00
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_action_set_attribute (NMTCAction *action, const char *name, GVariant *value)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (action != NULL);
|
|
|
|
|
g_return_if_fail (name != NULL && *name != '\0');
|
|
|
|
|
g_return_if_fail (strcmp (name, "kind") != 0);
|
|
|
|
|
|
|
|
|
|
if (!action->attributes) {
|
|
|
|
|
action->attributes = g_hash_table_new_full (nm_str_hash, g_str_equal,
|
|
|
|
|
g_free, (GDestroyNotify) g_variant_unref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (value)
|
|
|
|
|
g_hash_table_insert (action->attributes, g_strdup (name), g_variant_ref_sink (value));
|
|
|
|
|
else
|
|
|
|
|
g_hash_table_remove (action->attributes, name);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
2017-11-16 17:35:20 +01:00
|
|
|
|
2017-11-27 22:16:36 +01:00
|
|
|
G_DEFINE_BOXED_TYPE (NMTCTfilter, nm_tc_tfilter, nm_tc_tfilter_dup, nm_tc_tfilter_unref)
|
|
|
|
|
|
|
|
|
|
struct NMTCTfilter {
|
|
|
|
|
guint refcount;
|
|
|
|
|
|
2017-11-28 09:26:46 +01:00
|
|
|
char *kind;
|
2017-11-27 22:16:36 +01:00
|
|
|
guint32 handle;
|
|
|
|
|
guint32 parent;
|
|
|
|
|
NMTCAction *action;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_new:
|
|
|
|
|
* @kind: name of the queueing discipline
|
|
|
|
|
* @parent: the parent queueing discipline
|
|
|
|
|
* @error: location to store error, or %NULL
|
|
|
|
|
*
|
|
|
|
|
* Creates a new #NMTCTfilter object.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): the new #NMTCTfilter object, or %NULL on error
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCTfilter *
|
|
|
|
|
nm_tc_tfilter_new (const char *kind,
|
|
|
|
|
guint32 parent,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
NMTCTfilter *tfilter;
|
|
|
|
|
|
2019-04-09 08:14:25 +02:00
|
|
|
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')) {
|
2017-11-28 09:26:46 +01:00
|
|
|
g_set_error (error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("'%s' is not a valid kind"), kind);
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!parent) {
|
|
|
|
|
g_set_error_literal (error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("parent handle missing"));
|
|
|
|
|
return NULL;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 22:16:36 +01:00
|
|
|
tfilter = g_slice_new0 (NMTCTfilter);
|
|
|
|
|
tfilter->refcount = 1;
|
|
|
|
|
|
2017-11-28 09:26:46 +01:00
|
|
|
tfilter->kind = g_strdup (kind);
|
2017-11-27 22:16:36 +01:00
|
|
|
tfilter->parent = parent;
|
|
|
|
|
|
|
|
|
|
return tfilter;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_ref:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
*
|
|
|
|
|
* Increases the reference count of the object.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_tfilter_ref (NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (tfilter != NULL);
|
|
|
|
|
g_return_if_fail (tfilter->refcount > 0);
|
|
|
|
|
|
|
|
|
|
tfilter->refcount++;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_unref:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
*
|
|
|
|
|
* Decreases the reference count of the object. If the reference count
|
|
|
|
|
* reaches zero, the object will be destroyed.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_tfilter_unref (NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (tfilter != NULL);
|
|
|
|
|
g_return_if_fail (tfilter->refcount > 0);
|
|
|
|
|
|
|
|
|
|
tfilter->refcount--;
|
|
|
|
|
if (tfilter->refcount == 0) {
|
2017-11-28 09:26:46 +01:00
|
|
|
g_free (tfilter->kind);
|
2017-11-27 22:16:36 +01:00
|
|
|
if (tfilter->action)
|
|
|
|
|
nm_tc_action_unref (tfilter->action);
|
|
|
|
|
g_slice_free (NMTCTfilter, tfilter);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_equal:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
* @other: the #NMTCTfilter to compare @tfilter to.
|
|
|
|
|
*
|
|
|
|
|
* Determines if two #NMTCTfilter objects contain the same kind, family,
|
|
|
|
|
* handle, parent and info.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the objects contain the same values, %FALSE if they do not.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_tc_tfilter_equal (NMTCTfilter *tfilter, NMTCTfilter *other)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (tfilter != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (tfilter->refcount > 0, FALSE);
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (other != NULL, FALSE);
|
|
|
|
|
g_return_val_if_fail (other->refcount > 0, FALSE);
|
|
|
|
|
|
|
|
|
|
if ( tfilter->handle != other->handle
|
|
|
|
|
|| tfilter->parent != other->parent
|
|
|
|
|
|| g_strcmp0 (tfilter->kind, other->kind) != 0
|
|
|
|
|
|| !nm_tc_action_equal (tfilter->action, other->action))
|
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
static guint
|
|
|
|
|
_nm_tc_tfilter_hash (NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
NMHashState h;
|
|
|
|
|
|
|
|
|
|
nm_hash_init (&h, 63624437);
|
|
|
|
|
nm_hash_update_vals (&h,
|
|
|
|
|
tfilter->handle,
|
|
|
|
|
tfilter->parent);
|
|
|
|
|
nm_hash_update_str0 (&h, tfilter->kind);
|
2020-06-07 01:16:04 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
if (tfilter->action) {
|
2020-06-07 01:16:04 +02:00
|
|
|
gs_free NMUtilsNamedValue *attrs_free = NULL;
|
|
|
|
|
NMUtilsNamedValue attrs_static[30];
|
|
|
|
|
const NMUtilsNamedValue *attrs;
|
|
|
|
|
guint length;
|
|
|
|
|
guint i;
|
|
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
nm_hash_update_str0 (&h, tfilter->action->kind);
|
2020-06-07 01:16:04 +02:00
|
|
|
|
|
|
|
|
attrs = nm_utils_named_values_from_strdict (tfilter->action->attributes, &length, attrs_static, &attrs_free);
|
2018-06-21 15:56:29 +02:00
|
|
|
for (i = 0; i < length; i++) {
|
2020-06-07 01:16:04 +02:00
|
|
|
GVariant *variant = attrs[i].value_ptr;
|
|
|
|
|
|
|
|
|
|
nm_hash_update_str (&h, attrs[i].name);
|
2018-06-21 15:56:29 +02:00
|
|
|
if (g_variant_type_is_basic (g_variant_get_type (variant))) {
|
2020-06-07 01:16:04 +02:00
|
|
|
guint attr_hash;
|
|
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
/* g_variant_hash() works only for basic types, thus
|
|
|
|
|
* we ignore any non-basic attribute. Actions differing
|
|
|
|
|
* only for non-basic attributes will collide. */
|
|
|
|
|
attr_hash = g_variant_hash (variant);
|
|
|
|
|
nm_hash_update_val (&h, attr_hash);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-06-07 01:16:04 +02:00
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
return nm_hash_complete (&h);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 22:16:36 +01:00
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_dup:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
*
|
|
|
|
|
* Creates a copy of @tfilter
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): a copy of @tfilter
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCTfilter *
|
|
|
|
|
nm_tc_tfilter_dup (NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
NMTCTfilter *copy;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (tfilter != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (tfilter->refcount > 0, NULL);
|
|
|
|
|
|
|
|
|
|
copy = nm_tc_tfilter_new (tfilter->kind, tfilter->parent, NULL);
|
|
|
|
|
nm_tc_tfilter_set_handle (copy, tfilter->handle);
|
|
|
|
|
nm_tc_tfilter_set_action (copy, tfilter->action);
|
|
|
|
|
|
|
|
|
|
return copy;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_get_kind:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
*
|
|
|
|
|
* Returns:
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
const char *
|
|
|
|
|
nm_tc_tfilter_get_kind (NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (tfilter != NULL, NULL);
|
|
|
|
|
g_return_val_if_fail (tfilter->refcount > 0, NULL);
|
|
|
|
|
|
|
|
|
|
return tfilter->kind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_get_handle:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
*
|
|
|
|
|
* Returns: the queueing discipline handle
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_tc_tfilter_get_handle (NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (tfilter != NULL, TC_H_UNSPEC);
|
|
|
|
|
g_return_val_if_fail (tfilter->refcount > 0, TC_H_UNSPEC);
|
|
|
|
|
|
|
|
|
|
return tfilter->handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_set_handle:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
* @handle: the queueing discipline handle
|
|
|
|
|
*
|
|
|
|
|
* Sets the queueing discipline handle.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_tfilter_set_handle (NMTCTfilter *tfilter, guint32 handle)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (tfilter != NULL);
|
|
|
|
|
g_return_if_fail (tfilter->refcount > 0);
|
|
|
|
|
|
|
|
|
|
tfilter->handle = handle;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_get_parent:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
*
|
|
|
|
|
* Returns: the parent class
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
guint32
|
|
|
|
|
nm_tc_tfilter_get_parent (NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (tfilter != NULL, TC_H_UNSPEC);
|
|
|
|
|
g_return_val_if_fail (tfilter->refcount > 0, TC_H_UNSPEC);
|
|
|
|
|
|
|
|
|
|
return tfilter->parent;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_get_action:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
*
|
|
|
|
|
* Returns: the action associated with a traffic filter.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCAction *
|
|
|
|
|
nm_tc_tfilter_get_action (NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (tfilter != NULL, TC_H_UNSPEC);
|
|
|
|
|
g_return_val_if_fail (tfilter->refcount > 0, TC_H_UNSPEC);
|
|
|
|
|
|
|
|
|
|
if (tfilter->action == NULL)
|
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
return tfilter->action;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_tc_tfilter_set_action:
|
|
|
|
|
* @tfilter: the #NMTCTfilter
|
|
|
|
|
* @action: the action object
|
|
|
|
|
*
|
|
|
|
|
* Sets the action associated with a traffic filter.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_tc_tfilter_set_action (NMTCTfilter *tfilter, NMTCAction *action)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (tfilter != NULL);
|
|
|
|
|
g_return_if_fail (tfilter->refcount > 0);
|
|
|
|
|
|
|
|
|
|
if (action)
|
|
|
|
|
nm_tc_action_ref (action);
|
|
|
|
|
if (tfilter->action)
|
|
|
|
|
nm_tc_action_unref (tfilter->action);
|
|
|
|
|
tfilter->action = action;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2019-01-11 08:28:26 +01:00
|
|
|
NM_GOBJECT_PROPERTIES_DEFINE (NMSettingTCConfig,
|
2017-11-16 17:35:20 +01:00
|
|
|
PROP_QDISCS,
|
2017-11-27 22:16:36 +01:00
|
|
|
PROP_TFILTERS,
|
2019-01-11 08:28:26 +01:00
|
|
|
);
|
2017-11-16 17:35:20 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* NMSettingTCConfig:
|
|
|
|
|
*
|
2020-03-10 11:47:46 +01:00
|
|
|
* Linux Traffic Control Settings
|
2017-11-16 17:35:20 +01:00
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
*/
|
|
|
|
|
struct _NMSettingTCConfig {
|
2018-05-16 09:41:45 +02:00
|
|
|
NMSetting parent;
|
2017-11-16 17:35:20 +01:00
|
|
|
GPtrArray *qdiscs;
|
2017-11-27 22:16:36 +01:00
|
|
|
GPtrArray *tfilters;
|
2017-11-16 17:35:20 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct _NMSettingTCConfigClass {
|
2018-05-16 09:41:45 +02:00
|
|
|
NMSettingClass parent;
|
2017-11-16 17:35:20 +01:00
|
|
|
};
|
|
|
|
|
|
libnm: use NMMetaSettingInfo for tracking setting priority
Previously, each (non abstract) NMSetting class had to register
its name and priority via _nm_register_setting().
Note, that libnm-core.la already links against "nm-meta-setting.c",
which also redundantly keeps track of the settings name and gtype
as well.
Re-use NMMetaSettingInfo also in libnm-core.la, to track this meta
data.
The goal is to get rid of private data structures that track
meta data about NMSetting classes. In this case, "registered_settings"
hash. Instead, we should have one place where all this meta data
is tracked. This was, it is also accessible as internal API,
which can be useful (for keyfile).
Note that NMSettingClass has some overlap with NMMetaSettingInfo.
One difference is, that NMMetaSettingInfo is const, while NMSettingClass
is only initialized during the class_init() method. Appart from that,
it's mostly a matter of taste, whether we attach meta data to
NMSettingClass, to NMMetaSettingInfo, or to a static-array indexed
by NMMetaSettingType.
Note, that previously, _nm_register_setting() was private API. That
means, no user could subclass a functioning NMSetting instance. The same
is still true: NMMetaSettingInfo is internal API and users cannot access
it to create their own NMSetting subclasses. But that is almost desired.
libnm is not designed, to be extensible via subclassing, nor is it
clear why that would be a useful thing to do. One day, we should remove
the NMSetting and NMSettingClass definitions from public headers. Their
only use is subclassing the types, which however does not work.
While libnm-core was linking already against nm-meta-setting.c,
nm_meta_setting_infos was unreferenced. So, this change increases
the binary size of libnm and NetworkManager (1032 bytes). Note however
that roughly the same information was previously allocated at runtime.
2018-07-27 14:08:14 +02:00
|
|
|
G_DEFINE_TYPE (NMSettingTCConfig, nm_setting_tc_config, NM_TYPE_SETTING)
|
2017-11-16 17:35:20 +01:00
|
|
|
|
2019-01-11 08:32:54 +01:00
|
|
|
/*****************************************************************************/
|
2017-11-16 17:35:20 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_get_num_qdiscs:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
*
|
|
|
|
|
* Returns: the number of configured queueing disciplines
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
guint
|
|
|
|
|
nm_setting_tc_config_get_num_qdiscs (NMSettingTCConfig *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING_TC_CONFIG (self), 0);
|
|
|
|
|
|
|
|
|
|
return self->qdiscs->len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_get_qdisc:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
* @idx: index number of the qdisc to return
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): the qdisc at index @idx
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCQdisc *
|
|
|
|
|
nm_setting_tc_config_get_qdisc (NMSettingTCConfig *self, guint idx)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING_TC_CONFIG (self), NULL);
|
|
|
|
|
g_return_val_if_fail (idx < self->qdiscs->len, NULL);
|
|
|
|
|
|
|
|
|
|
return self->qdiscs->pdata[idx];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_add_qdisc:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
* @qdisc: the qdisc to add
|
|
|
|
|
*
|
|
|
|
|
* Appends a new qdisc and associated information to the setting. The
|
|
|
|
|
* given qdisc is duplicated internally and is not changed by this function.
|
|
|
|
|
* If an identical qdisc (considering attributes as well) already exists, the
|
|
|
|
|
* qdisc is not added and the function returns %FALSE.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the qdisc was added; %FALSE if the qdisc was already known.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_tc_config_add_qdisc (NMSettingTCConfig *self,
|
|
|
|
|
NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING_TC_CONFIG (self), FALSE);
|
|
|
|
|
g_return_val_if_fail (qdisc != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < self->qdiscs->len; i++) {
|
|
|
|
|
if (nm_tc_qdisc_equal (self->qdiscs->pdata[i], qdisc))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_ptr_array_add (self->qdiscs, nm_tc_qdisc_dup (qdisc));
|
2019-01-11 08:28:26 +01:00
|
|
|
_notify (self, PROP_QDISCS);
|
2017-11-16 17:35:20 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_remove_qdisc:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
* @idx: index number of the qdisc
|
|
|
|
|
*
|
|
|
|
|
* Removes the qdisc at index @idx.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_tc_config_remove_qdisc (NMSettingTCConfig *self, guint idx)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (NM_IS_SETTING_TC_CONFIG (self));
|
|
|
|
|
|
|
|
|
|
g_return_if_fail (idx < self->qdiscs->len);
|
|
|
|
|
|
|
|
|
|
g_ptr_array_remove_index (self->qdiscs, idx);
|
2019-01-11 08:28:26 +01:00
|
|
|
_notify (self, PROP_QDISCS);
|
2017-11-16 17:35:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_remove_qdisc_by_value:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
* @qdisc: the qdisc to remove
|
|
|
|
|
*
|
|
|
|
|
* Removes the first matching qdisc that matches @qdisc.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the qdisc was found and removed; %FALSE if it was not.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_tc_config_remove_qdisc_by_value (NMSettingTCConfig *self,
|
|
|
|
|
NMTCQdisc *qdisc)
|
|
|
|
|
{
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING_TC_CONFIG (self), FALSE);
|
|
|
|
|
g_return_val_if_fail (qdisc != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < self->qdiscs->len; i++) {
|
|
|
|
|
if (nm_tc_qdisc_equal (self->qdiscs->pdata[i], qdisc)) {
|
|
|
|
|
g_ptr_array_remove_index (self->qdiscs, i);
|
2019-01-11 08:28:26 +01:00
|
|
|
_notify (self, PROP_QDISCS);
|
2017-11-16 17:35:20 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_clear_qdiscs:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
*
|
|
|
|
|
* Removes all configured queueing disciplines.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_tc_config_clear_qdiscs (NMSettingTCConfig *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (NM_IS_SETTING_TC_CONFIG (self));
|
|
|
|
|
|
2018-05-28 15:31:11 +02:00
|
|
|
if (self->qdiscs->len != 0) {
|
|
|
|
|
g_ptr_array_set_size (self->qdiscs, 0);
|
2019-01-11 08:28:26 +01:00
|
|
|
_notify (self, PROP_QDISCS);
|
2018-05-28 15:31:11 +02:00
|
|
|
}
|
2017-11-16 17:35:20 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-27 22:16:36 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_get_num_tfilters:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
*
|
|
|
|
|
* Returns: the number of configured queueing disciplines
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
guint
|
|
|
|
|
nm_setting_tc_config_get_num_tfilters (NMSettingTCConfig *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING_TC_CONFIG (self), 0);
|
|
|
|
|
|
|
|
|
|
return self->tfilters->len;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_get_tfilter:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
* @idx: index number of the tfilter to return
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): the tfilter at index @idx
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMTCTfilter *
|
|
|
|
|
nm_setting_tc_config_get_tfilter (NMSettingTCConfig *self, guint idx)
|
|
|
|
|
{
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING_TC_CONFIG (self), NULL);
|
|
|
|
|
g_return_val_if_fail (idx < self->tfilters->len, NULL);
|
|
|
|
|
|
|
|
|
|
return self->tfilters->pdata[idx];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_add_tfilter:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
* @tfilter: the tfilter to add
|
|
|
|
|
*
|
|
|
|
|
* Appends a new tfilter and associated information to the setting. The
|
|
|
|
|
* given tfilter is duplicated internally and is not changed by this function.
|
|
|
|
|
* If an identical tfilter (considering attributes as well) already exists, the
|
|
|
|
|
* tfilter is not added and the function returns %FALSE.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the tfilter was added; %FALSE if the tfilter was already known.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_tc_config_add_tfilter (NMSettingTCConfig *self,
|
|
|
|
|
NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING_TC_CONFIG (self), FALSE);
|
|
|
|
|
g_return_val_if_fail (tfilter != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < self->tfilters->len; i++) {
|
|
|
|
|
if (nm_tc_tfilter_equal (self->tfilters->pdata[i], tfilter))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_ptr_array_add (self->tfilters, nm_tc_tfilter_dup (tfilter));
|
2019-01-11 08:28:26 +01:00
|
|
|
_notify (self, PROP_TFILTERS);
|
2017-11-27 22:16:36 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_remove_tfilter:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
* @idx: index number of the tfilter
|
|
|
|
|
*
|
|
|
|
|
* Removes the tfilter at index @idx.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_tc_config_remove_tfilter (NMSettingTCConfig *self, guint idx)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (NM_IS_SETTING_TC_CONFIG (self));
|
|
|
|
|
g_return_if_fail (idx < self->tfilters->len);
|
|
|
|
|
|
|
|
|
|
g_ptr_array_remove_index (self->tfilters, idx);
|
2019-01-11 08:28:26 +01:00
|
|
|
_notify (self, PROP_TFILTERS);
|
2017-11-27 22:16:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_remove_tfilter_by_value:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
* @tfilter: the tfilter to remove
|
|
|
|
|
*
|
|
|
|
|
* Removes the first matching tfilter that matches @tfilter.
|
|
|
|
|
*
|
|
|
|
|
* Returns: %TRUE if the tfilter was found and removed; %FALSE if it was not.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
gboolean
|
|
|
|
|
nm_setting_tc_config_remove_tfilter_by_value (NMSettingTCConfig *self,
|
|
|
|
|
NMTCTfilter *tfilter)
|
|
|
|
|
{
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (NM_IS_SETTING_TC_CONFIG (self), FALSE);
|
|
|
|
|
g_return_val_if_fail (tfilter != NULL, FALSE);
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < self->tfilters->len; i++) {
|
|
|
|
|
if (nm_tc_tfilter_equal (self->tfilters->pdata[i], tfilter)) {
|
|
|
|
|
g_ptr_array_remove_index (self->tfilters, i);
|
2019-01-11 08:28:26 +01:00
|
|
|
_notify (self, PROP_TFILTERS);
|
2017-11-27 22:16:36 +01:00
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_clear_tfilters:
|
|
|
|
|
* @setting: the #NMSettingTCConfig
|
|
|
|
|
*
|
|
|
|
|
* Removes all configured queueing disciplines.
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
void
|
|
|
|
|
nm_setting_tc_config_clear_tfilters (NMSettingTCConfig *self)
|
|
|
|
|
{
|
|
|
|
|
g_return_if_fail (NM_IS_SETTING_TC_CONFIG (self));
|
|
|
|
|
|
2018-05-28 15:31:11 +02:00
|
|
|
if (self->tfilters->len != 0) {
|
|
|
|
|
g_ptr_array_set_size (self->tfilters, 0);
|
2019-01-11 08:28:26 +01:00
|
|
|
_notify (self, PROP_TFILTERS);
|
2018-05-28 15:31:11 +02:00
|
|
|
}
|
2017-11-27 22:16:36 +01:00
|
|
|
}
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
2018-06-21 15:56:29 +02:00
|
|
|
static gboolean
|
|
|
|
|
verify (NMSetting *setting, NMConnection *connection, GError **error)
|
|
|
|
|
{
|
|
|
|
|
NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (setting);
|
|
|
|
|
guint i;
|
|
|
|
|
|
|
|
|
|
if (self->qdiscs->len != 0) {
|
|
|
|
|
gs_unref_hashtable GHashTable *ht = NULL;
|
|
|
|
|
|
|
|
|
|
ht = g_hash_table_new ((GHashFunc) _nm_tc_qdisc_hash,
|
|
|
|
|
(GEqualFunc) nm_tc_qdisc_equal);
|
|
|
|
|
for (i = 0; i < self->qdiscs->len; i++) {
|
|
|
|
|
if (!g_hash_table_add (ht, self->qdiscs->pdata[i])) {
|
|
|
|
|
g_set_error_literal (error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("there are duplicate TC qdiscs"));
|
|
|
|
|
g_prefix_error (error,
|
|
|
|
|
"%s.%s: ",
|
|
|
|
|
NM_SETTING_TC_CONFIG_SETTING_NAME,
|
|
|
|
|
NM_SETTING_TC_CONFIG_QDISCS);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (self->tfilters->len != 0) {
|
|
|
|
|
gs_unref_hashtable GHashTable *ht = NULL;
|
|
|
|
|
|
|
|
|
|
ht = g_hash_table_new ((GHashFunc) _nm_tc_tfilter_hash,
|
|
|
|
|
(GEqualFunc) nm_tc_tfilter_equal);
|
|
|
|
|
for (i = 0; i < self->tfilters->len; i++) {
|
|
|
|
|
if (!g_hash_table_add (ht, self->tfilters->pdata[i])) {
|
|
|
|
|
g_set_error_literal (error,
|
|
|
|
|
NM_CONNECTION_ERROR,
|
|
|
|
|
NM_CONNECTION_ERROR_INVALID_PROPERTY,
|
|
|
|
|
_("there are duplicate TC filters"));
|
|
|
|
|
g_prefix_error (error,
|
|
|
|
|
"%s.%s: ",
|
|
|
|
|
NM_SETTING_TC_CONFIG_SETTING_NAME,
|
|
|
|
|
NM_SETTING_TC_CONFIG_TFILTERS);
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
static NMTernary
|
|
|
|
|
compare_property (const NMSettInfoSetting *sett_info,
|
|
|
|
|
guint property_idx,
|
2019-04-25 10:17:47 +02:00
|
|
|
NMConnection *con_a,
|
|
|
|
|
NMSetting *set_a,
|
|
|
|
|
NMConnection *con_b,
|
|
|
|
|
NMSetting *set_b,
|
2017-11-16 17:35:20 +01:00
|
|
|
NMSettingCompareFlags flags)
|
|
|
|
|
{
|
2019-04-25 10:17:47 +02:00
|
|
|
NMSettingTCConfig *a_tc_config = NM_SETTING_TC_CONFIG (set_a);
|
|
|
|
|
NMSettingTCConfig *b_tc_config = NM_SETTING_TC_CONFIG (set_b);
|
2017-11-16 17:35:20 +01:00
|
|
|
guint i;
|
|
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TC_CONFIG_QDISCS)) {
|
2019-04-25 10:17:47 +02:00
|
|
|
if (set_b) {
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (a_tc_config->qdiscs->len != b_tc_config->qdiscs->len)
|
2017-11-16 17:35:20 +01:00
|
|
|
return FALSE;
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
for (i = 0; i < a_tc_config->qdiscs->len; i++) {
|
|
|
|
|
if (!nm_tc_qdisc_equal (a_tc_config->qdiscs->pdata[i], b_tc_config->qdiscs->pdata[i]))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2017-11-16 17:35:20 +01:00
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (nm_streq (sett_info->property_infos[property_idx].name, NM_SETTING_TC_CONFIG_TFILTERS)) {
|
2019-04-25 10:17:47 +02:00
|
|
|
if (set_b) {
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
if (a_tc_config->tfilters->len != b_tc_config->tfilters->len)
|
2017-11-27 22:16:36 +01:00
|
|
|
return FALSE;
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
for (i = 0; i < a_tc_config->tfilters->len; i++) {
|
|
|
|
|
if (!nm_tc_tfilter_equal (a_tc_config->tfilters->pdata[i], b_tc_config->tfilters->pdata[i]))
|
|
|
|
|
return FALSE;
|
|
|
|
|
}
|
2017-11-27 22:16:36 +01:00
|
|
|
}
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
return NM_SETTING_CLASS (nm_setting_tc_config_parent_class)->compare_property (sett_info,
|
|
|
|
|
property_idx,
|
2019-04-25 10:17:47 +02:00
|
|
|
con_a,
|
|
|
|
|
set_a,
|
|
|
|
|
con_b,
|
|
|
|
|
set_b,
|
libnm: rework compare_property() implementation for NMSetting
NMSetting's compare_property() has and had two callers:
nm_setting_compare() and nm_setting_diff().
compare_property() accepts a NMSettingCompareFlags argument, but
at the same time, both callers have another complex (and
inconsistent!) set of pre-checks for shortcuting the call of
compare_property(): should_compare_prop().
Merge should_compare_prop() into compare_property(). This way,
nm_setting_compare() and nm_setting_diff() has less additional
code, and are simpler to follow. Especially nm_setting_compare()
is now trivial. And nm_setting_diff() is still complicated, but
not related to the question how the property compares or whether
it should be compared at all.
If you want to know whether it should be compared, all you need to do
now is follow NMSettingClass.compare_property().
This changes function pointer NMSettingClass.compare_property(),
which is public API. However, no user can actually use this (and shall
not!), because _nm_setting_class_commit_full() etc. is private API. A
user outside of libnm-core cannot create his/her own subclasses of
NMSetting, and never could in the past. So, this API/ABI change doesn't
matter.
2019-01-09 09:08:39 +01:00
|
|
|
flags);
|
2017-11-16 17:35:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _qdiscs_to_variant:
|
|
|
|
|
* @qdiscs: (element-type NMTCQdisc): an array of #NMTCQdisc objects
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GPtrArray of #NMTCQdisc objects representing
|
|
|
|
|
* TC qdiscs into a #GVariant of type 'aa{sv}' representing an array
|
|
|
|
|
* of NetworkManager TC qdiscs.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @qdiscs.
|
|
|
|
|
**/
|
|
|
|
|
static GVariant *
|
|
|
|
|
_qdiscs_to_variant (GPtrArray *qdiscs)
|
|
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
|
|
|
|
|
|
|
|
|
|
if (qdiscs) {
|
|
|
|
|
for (i = 0; i < qdiscs->len; i++) {
|
2020-06-07 01:16:04 +02:00
|
|
|
NMUtilsNamedValue attrs_static[30];
|
|
|
|
|
gs_free NMUtilsNamedValue *attrs_free = NULL;
|
|
|
|
|
const NMUtilsNamedValue *attrs;
|
2017-11-16 17:35:20 +01:00
|
|
|
NMTCQdisc *qdisc = qdiscs->pdata[i];
|
2019-04-09 09:10:43 +02:00
|
|
|
guint length;
|
2017-11-16 17:35:20 +01:00
|
|
|
GVariantBuilder qdisc_builder;
|
2019-04-09 09:10:43 +02:00
|
|
|
guint y;
|
2017-11-16 17:35:20 +01:00
|
|
|
|
|
|
|
|
g_variant_builder_init (&qdisc_builder, G_VARIANT_TYPE_VARDICT);
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add (&qdisc_builder, "{sv}", "kind",
|
|
|
|
|
g_variant_new_string (nm_tc_qdisc_get_kind (qdisc)));
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add (&qdisc_builder, "{sv}", "handle",
|
|
|
|
|
g_variant_new_uint32 (nm_tc_qdisc_get_handle (qdisc)));
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add (&qdisc_builder, "{sv}", "parent",
|
|
|
|
|
g_variant_new_uint32 (nm_tc_qdisc_get_parent (qdisc)));
|
|
|
|
|
|
2020-06-07 01:16:04 +02:00
|
|
|
attrs = nm_utils_named_values_from_strdict (qdisc->attributes, &length, attrs_static, &attrs_free);
|
2019-04-09 09:10:43 +02:00
|
|
|
for (y = 0; y < length; y++) {
|
2020-06-07 01:16:04 +02:00
|
|
|
g_variant_builder_add (&qdisc_builder,
|
|
|
|
|
"{sv}",
|
|
|
|
|
attrs[y].name,
|
|
|
|
|
attrs[y].value_ptr);
|
2019-04-09 09:10:43 +02:00
|
|
|
}
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
g_variant_builder_add (&builder, "a{sv}", &qdisc_builder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end (&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _qdiscs_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aa{sv}'
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant representing a list of TC qdiscs
|
|
|
|
|
* into a #GPtrArray of * #NMTCQdisc objects.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMTCQdisc): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMTCQdisc objects
|
|
|
|
|
**/
|
|
|
|
|
static GPtrArray *
|
|
|
|
|
_qdiscs_from_variant (GVariant *value)
|
|
|
|
|
{
|
|
|
|
|
GPtrArray *qdiscs;
|
|
|
|
|
GVariant *qdisc_var;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
|
|
|
|
|
|
|
|
|
|
g_variant_iter_init (&iter, value);
|
|
|
|
|
qdiscs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_qdisc_unref);
|
|
|
|
|
|
|
|
|
|
while (g_variant_iter_next (&iter, "@a{sv}", &qdisc_var)) {
|
|
|
|
|
const char *kind;
|
|
|
|
|
guint32 parent;
|
|
|
|
|
NMTCQdisc *qdisc;
|
2019-04-09 09:10:43 +02:00
|
|
|
GVariantIter qdisc_iter;
|
|
|
|
|
const char *key;
|
|
|
|
|
GVariant *attr_value;
|
2017-11-16 17:35:20 +01:00
|
|
|
|
|
|
|
|
if ( !g_variant_lookup (qdisc_var, "kind", "&s", &kind)
|
|
|
|
|
|| !g_variant_lookup (qdisc_var, "parent", "u", &parent)) {
|
2017-12-08 17:12:46 +01:00
|
|
|
//g_warning ("Ignoring invalid qdisc");
|
2017-11-16 17:35:20 +01:00
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qdisc = nm_tc_qdisc_new (kind, parent, &error);
|
|
|
|
|
if (!qdisc) {
|
2017-12-08 17:12:46 +01:00
|
|
|
//g_warning ("Ignoring invalid qdisc: %s", error->message);
|
2017-11-16 17:35:20 +01:00
|
|
|
g_clear_error (&error);
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
2019-04-09 09:10:43 +02:00
|
|
|
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);
|
|
|
|
|
}
|
2017-11-16 17:35:20 +01:00
|
|
|
|
|
|
|
|
g_ptr_array_add (qdiscs, qdisc);
|
|
|
|
|
next:
|
|
|
|
|
g_variant_unref (qdisc_var);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return qdiscs;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GVariant *
|
2019-04-24 17:41:32 +02:00
|
|
|
tc_qdiscs_get (const NMSettInfoSetting *sett_info,
|
|
|
|
|
guint property_idx,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
NMSetting *setting,
|
2019-06-27 09:07:16 +02:00
|
|
|
NMConnectionSerializationFlags flags,
|
|
|
|
|
const NMConnectionSerializationOptions *options)
|
2017-11-16 17:35:20 +01:00
|
|
|
{
|
2019-04-24 17:41:32 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *qdiscs = NULL;
|
2017-11-16 17:35:20 +01:00
|
|
|
|
|
|
|
|
g_object_get (setting, NM_SETTING_TC_CONFIG_QDISCS, &qdiscs, NULL);
|
2019-04-24 17:41:32 +02:00
|
|
|
return _qdiscs_to_variant (qdiscs);
|
2017-11-16 17:35:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
tc_qdiscs_set (NMSetting *setting,
|
|
|
|
|
GVariant *connection_dict,
|
|
|
|
|
const char *property,
|
|
|
|
|
GVariant *value,
|
|
|
|
|
NMSettingParseFlags parse_flags,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
|
|
|
|
GPtrArray *qdiscs;
|
|
|
|
|
|
|
|
|
|
qdiscs = _qdiscs_from_variant (value);
|
|
|
|
|
g_object_set (setting, NM_SETTING_TC_CONFIG_QDISCS, qdiscs, NULL);
|
|
|
|
|
g_ptr_array_unref (qdiscs);
|
|
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-27 22:16:36 +01:00
|
|
|
static GVariant *
|
|
|
|
|
_action_to_variant (NMTCAction *action)
|
|
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
|
|
|
|
gs_strfreev char **attrs = nm_tc_action_get_attribute_names (action);
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add (&builder, "{sv}", "kind",
|
|
|
|
|
g_variant_new_string (nm_tc_action_get_kind (action)));
|
|
|
|
|
|
|
|
|
|
for (i = 0; attrs[i]; i++) {
|
|
|
|
|
g_variant_builder_add (&builder, "{sv}", attrs[i],
|
2017-12-10 12:20:38 +01:00
|
|
|
nm_tc_action_get_attribute (action, attrs[i]));
|
2017-11-27 22:16:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end (&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _tfilters_to_variant:
|
|
|
|
|
* @tfilters: (element-type NMTCTfilter): an array of #NMTCTfilter objects
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GPtrArray of #NMTCTfilter objects representing
|
|
|
|
|
* TC tfilters into a #GVariant of type 'aa{sv}' representing an array
|
|
|
|
|
* of NetworkManager TC tfilters.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer none): a new floating #GVariant representing @tfilters.
|
|
|
|
|
**/
|
|
|
|
|
static GVariant *
|
|
|
|
|
_tfilters_to_variant (GPtrArray *tfilters)
|
|
|
|
|
{
|
|
|
|
|
GVariantBuilder builder;
|
|
|
|
|
int i;
|
|
|
|
|
|
|
|
|
|
g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}"));
|
|
|
|
|
|
|
|
|
|
if (tfilters) {
|
|
|
|
|
for (i = 0; i < tfilters->len; i++) {
|
|
|
|
|
NMTCTfilter *tfilter = tfilters->pdata[i];
|
|
|
|
|
NMTCAction *action = nm_tc_tfilter_get_action (tfilter);
|
|
|
|
|
GVariantBuilder tfilter_builder;
|
|
|
|
|
|
|
|
|
|
g_variant_builder_init (&tfilter_builder, G_VARIANT_TYPE ("a{sv}"));
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add (&tfilter_builder, "{sv}", "kind",
|
|
|
|
|
g_variant_new_string (nm_tc_tfilter_get_kind (tfilter)));
|
|
|
|
|
g_variant_builder_add (&tfilter_builder, "{sv}", "handle",
|
|
|
|
|
g_variant_new_uint32 (nm_tc_tfilter_get_handle (tfilter)));
|
|
|
|
|
g_variant_builder_add (&tfilter_builder, "{sv}", "parent",
|
|
|
|
|
g_variant_new_uint32 (nm_tc_tfilter_get_parent (tfilter)));
|
|
|
|
|
|
|
|
|
|
if (action) {
|
|
|
|
|
g_variant_builder_add (&tfilter_builder, "{sv}", "action",
|
|
|
|
|
_action_to_variant (action));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_variant_builder_add (&builder, "a{sv}", &tfilter_builder);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return g_variant_builder_end (&builder);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* _tfilters_from_variant:
|
|
|
|
|
* @value: a #GVariant of type 'aa{sv}'
|
|
|
|
|
*
|
|
|
|
|
* Utility function to convert a #GVariant representing a list of TC tfilters
|
|
|
|
|
* into a #GPtrArray of * #NMTCTfilter objects.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full) (element-type NMTCTfilter): a newly allocated
|
|
|
|
|
* #GPtrArray of #NMTCTfilter objects
|
|
|
|
|
**/
|
|
|
|
|
static GPtrArray *
|
|
|
|
|
_tfilters_from_variant (GVariant *value)
|
|
|
|
|
{
|
|
|
|
|
GPtrArray *tfilters;
|
|
|
|
|
GVariant *tfilter_var;
|
|
|
|
|
GVariantIter iter;
|
|
|
|
|
GError *error = NULL;
|
|
|
|
|
|
|
|
|
|
g_return_val_if_fail (g_variant_is_of_type (value, G_VARIANT_TYPE ("aa{sv}")), NULL);
|
|
|
|
|
|
|
|
|
|
g_variant_iter_init (&iter, value);
|
|
|
|
|
tfilters = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_tfilter_unref);
|
|
|
|
|
|
|
|
|
|
while (g_variant_iter_next (&iter, "@a{sv}", &tfilter_var)) {
|
|
|
|
|
NMTCTfilter *tfilter = NULL;
|
|
|
|
|
const char *kind;
|
|
|
|
|
guint32 handle;
|
|
|
|
|
guint32 parent;
|
|
|
|
|
NMTCAction *action;
|
|
|
|
|
const char *action_kind = NULL;
|
|
|
|
|
char *action_key;
|
|
|
|
|
GVariantIter action_iter;
|
|
|
|
|
GVariant *action_var = NULL;
|
|
|
|
|
GVariant *action_val;
|
|
|
|
|
|
|
|
|
|
if ( !g_variant_lookup (tfilter_var, "kind", "&s", &kind)
|
|
|
|
|
|| !g_variant_lookup (tfilter_var, "parent", "u", &parent)) {
|
2017-12-08 17:12:46 +01:00
|
|
|
//g_warning ("Ignoring invalid tfilter");
|
2017-11-27 22:16:36 +01:00
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tfilter = nm_tc_tfilter_new (kind, parent, &error);
|
|
|
|
|
if (!tfilter) {
|
2017-12-08 17:12:46 +01:00
|
|
|
//g_warning ("Ignoring invalid tfilter: %s", error->message);
|
2017-11-27 22:16:36 +01:00
|
|
|
g_clear_error (&error);
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (g_variant_lookup (tfilter_var, "handle", "u", &handle))
|
|
|
|
|
nm_tc_tfilter_set_handle (tfilter, handle);
|
|
|
|
|
|
|
|
|
|
action_var = g_variant_lookup_value (tfilter_var, "action", G_VARIANT_TYPE_VARDICT);
|
|
|
|
|
|
|
|
|
|
if (action_var) {
|
|
|
|
|
if (!g_variant_lookup (action_var, "kind", "&s", &action_kind)) {
|
2017-12-08 17:12:46 +01:00
|
|
|
//g_warning ("Ignoring tfilter with invalid action");
|
2017-11-27 22:16:36 +01:00
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
action = nm_tc_action_new (action_kind, &error);
|
|
|
|
|
if (!action) {
|
2017-12-08 17:12:46 +01:00
|
|
|
//g_warning ("Ignoring tfilter with invalid action: %s", error->message);
|
2017-11-27 22:16:36 +01:00
|
|
|
g_clear_error (&error);
|
|
|
|
|
goto next;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
g_variant_iter_init (&action_iter, action_var);
|
|
|
|
|
while (g_variant_iter_next (&action_iter, "{&sv}", &action_key, &action_val)) {
|
|
|
|
|
if (strcmp (action_key, "kind") != 0)
|
|
|
|
|
nm_tc_action_set_attribute (action, action_key, action_val);
|
|
|
|
|
g_variant_unref (action_val);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_tc_tfilter_set_action (tfilter, action);
|
|
|
|
|
nm_tc_action_unref (action);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
nm_tc_tfilter_ref (tfilter);
|
|
|
|
|
g_ptr_array_add (tfilters, tfilter);
|
|
|
|
|
next:
|
|
|
|
|
if (tfilter)
|
|
|
|
|
nm_tc_tfilter_unref (tfilter);
|
|
|
|
|
if (action_var)
|
|
|
|
|
g_variant_unref (action_var);
|
|
|
|
|
g_variant_unref (tfilter_var);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return tfilters;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static GVariant *
|
2019-04-24 17:41:32 +02:00
|
|
|
tc_tfilters_get (const NMSettInfoSetting *sett_info,
|
|
|
|
|
guint property_idx,
|
|
|
|
|
NMConnection *connection,
|
|
|
|
|
NMSetting *setting,
|
2019-06-27 09:07:16 +02:00
|
|
|
NMConnectionSerializationFlags flags,
|
|
|
|
|
const NMConnectionSerializationOptions *options)
|
2017-11-27 22:16:36 +01:00
|
|
|
{
|
2019-04-24 17:41:32 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *tfilters = NULL;
|
2017-11-27 22:16:36 +01:00
|
|
|
|
|
|
|
|
g_object_get (setting, NM_SETTING_TC_CONFIG_TFILTERS, &tfilters, NULL);
|
2019-04-24 17:41:32 +02:00
|
|
|
return _tfilters_to_variant (tfilters);
|
2017-11-27 22:16:36 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
|
tc_tfilters_set (NMSetting *setting,
|
|
|
|
|
GVariant *connection_dict,
|
|
|
|
|
const char *property,
|
|
|
|
|
GVariant *value,
|
|
|
|
|
NMSettingParseFlags parse_flags,
|
|
|
|
|
GError **error)
|
|
|
|
|
{
|
2019-04-24 17:41:32 +02:00
|
|
|
gs_unref_ptrarray GPtrArray *tfilters = NULL;
|
2017-11-27 22:16:36 +01:00
|
|
|
|
|
|
|
|
tfilters = _tfilters_from_variant (value);
|
|
|
|
|
g_object_set (setting, NM_SETTING_TC_CONFIG_TFILTERS, tfilters, NULL);
|
|
|
|
|
return TRUE;
|
|
|
|
|
}
|
|
|
|
|
|
2019-01-11 08:32:54 +01:00
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
get_property (GObject *object, guint prop_id,
|
|
|
|
|
GValue *value, GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
|
|
|
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
|
case PROP_QDISCS:
|
|
|
|
|
g_value_take_boxed (value, _nm_utils_copy_array (self->qdiscs,
|
|
|
|
|
(NMUtilsCopyFunc) nm_tc_qdisc_dup,
|
|
|
|
|
(GDestroyNotify) nm_tc_qdisc_unref));
|
|
|
|
|
break;
|
|
|
|
|
case PROP_TFILTERS:
|
|
|
|
|
g_value_take_boxed (value, _nm_utils_copy_array (self->tfilters,
|
|
|
|
|
(NMUtilsCopyFunc) nm_tc_tfilter_dup,
|
|
|
|
|
(GDestroyNotify) nm_tc_tfilter_unref));
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
set_property (GObject *object, guint prop_id,
|
|
|
|
|
const GValue *value, GParamSpec *pspec)
|
|
|
|
|
{
|
|
|
|
|
NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
|
|
|
|
|
|
|
|
|
|
switch (prop_id) {
|
|
|
|
|
case PROP_QDISCS:
|
|
|
|
|
g_ptr_array_unref (self->qdiscs);
|
|
|
|
|
self->qdiscs = _nm_utils_copy_array (g_value_get_boxed (value),
|
|
|
|
|
(NMUtilsCopyFunc) nm_tc_qdisc_dup,
|
|
|
|
|
(GDestroyNotify) nm_tc_qdisc_unref);
|
|
|
|
|
break;
|
|
|
|
|
case PROP_TFILTERS:
|
|
|
|
|
g_ptr_array_unref (self->tfilters);
|
|
|
|
|
self->tfilters = _nm_utils_copy_array (g_value_get_boxed (value),
|
|
|
|
|
(NMUtilsCopyFunc) nm_tc_tfilter_dup,
|
|
|
|
|
(GDestroyNotify) nm_tc_tfilter_unref);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*****************************************************************************/
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
nm_setting_tc_config_init (NMSettingTCConfig *self)
|
|
|
|
|
{
|
|
|
|
|
self->qdiscs = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_qdisc_unref);
|
|
|
|
|
self->tfilters = g_ptr_array_new_with_free_func ((GDestroyNotify) nm_tc_tfilter_unref);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* nm_setting_tc_config_new:
|
|
|
|
|
*
|
|
|
|
|
* Creates a new #NMSettingTCConfig object with default values.
|
|
|
|
|
*
|
|
|
|
|
* Returns: (transfer full): the new empty #NMSettingTCConfig object
|
|
|
|
|
*
|
|
|
|
|
* Since: 1.12
|
|
|
|
|
**/
|
|
|
|
|
NMSetting *
|
|
|
|
|
nm_setting_tc_config_new (void)
|
|
|
|
|
{
|
|
|
|
|
return (NMSetting *) g_object_new (NM_TYPE_SETTING_TC_CONFIG, NULL);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
|
finalize (GObject *object)
|
|
|
|
|
{
|
|
|
|
|
NMSettingTCConfig *self = NM_SETTING_TC_CONFIG (object);
|
|
|
|
|
|
|
|
|
|
g_ptr_array_unref (self->qdiscs);
|
|
|
|
|
g_ptr_array_unref (self->tfilters);
|
|
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (nm_setting_tc_config_parent_class)->finalize (object);
|
|
|
|
|
}
|
|
|
|
|
|
2017-11-16 17:35:20 +01:00
|
|
|
static void
|
libnm/trivial: cleanup variable names in settings' class-init functions
- Don't use @parent_class name. This local variable (and @object_class) is
the class instance up-cast to the pointer types of the parents. The point
here is not that it is the direct parent. The point is, that it's the
NMSettingClass type.
Also, it can only be used inconsistently, in face of NMSettingIP4Config,
who's parent type is NMSettingIPConfig. Clearly, inside
nm-setting-ip4-config.c we wouldn't want to use the "parent_class"
name. Consistently rename @parent_class to @setting_class.
- Also rename the pointer to the own class to @klass. "setting_class" is also the
wrong name for that, because the right name would be something like
"setting_6lowpan_class".
However, "klass" is preferred over the latter, because we commonly create new
GObject implementations by copying an existing one. Generic names like "klass"
and "self" inside a type implementation make that simpler.
- drop useless comments like
/* virtual functions */
/* Properties */
It's better to logically and visually structure the code, and avoid trival
remarks about that. They only end up being used inconsistently. If you
even need a stronger visual separator, then an 80 char /****/ line
should be preferred.
2018-07-28 10:43:21 +02:00
|
|
|
nm_setting_tc_config_class_init (NMSettingTCConfigClass *klass)
|
2017-11-16 17:35:20 +01:00
|
|
|
{
|
libnm/trivial: cleanup variable names in settings' class-init functions
- Don't use @parent_class name. This local variable (and @object_class) is
the class instance up-cast to the pointer types of the parents. The point
here is not that it is the direct parent. The point is, that it's the
NMSettingClass type.
Also, it can only be used inconsistently, in face of NMSettingIP4Config,
who's parent type is NMSettingIPConfig. Clearly, inside
nm-setting-ip4-config.c we wouldn't want to use the "parent_class"
name. Consistently rename @parent_class to @setting_class.
- Also rename the pointer to the own class to @klass. "setting_class" is also the
wrong name for that, because the right name would be something like
"setting_6lowpan_class".
However, "klass" is preferred over the latter, because we commonly create new
GObject implementations by copying an existing one. Generic names like "klass"
and "self" inside a type implementation make that simpler.
- drop useless comments like
/* virtual functions */
/* Properties */
It's better to logically and visually structure the code, and avoid trival
remarks about that. They only end up being used inconsistently. If you
even need a stronger visual separator, then an 80 char /****/ line
should be preferred.
2018-07-28 10:43:21 +02:00
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
|
NMSettingClass *setting_class = NM_SETTING_CLASS (klass);
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
GArray *properties_override = _nm_sett_info_property_override_create_array ();
|
2017-11-16 17:35:20 +01:00
|
|
|
|
|
|
|
|
object_class->get_property = get_property;
|
2019-01-11 08:32:54 +01:00
|
|
|
object_class->set_property = set_property;
|
2017-11-16 17:35:20 +01:00
|
|
|
object_class->finalize = finalize;
|
|
|
|
|
|
libnm/trivial: cleanup variable names in settings' class-init functions
- Don't use @parent_class name. This local variable (and @object_class) is
the class instance up-cast to the pointer types of the parents. The point
here is not that it is the direct parent. The point is, that it's the
NMSettingClass type.
Also, it can only be used inconsistently, in face of NMSettingIP4Config,
who's parent type is NMSettingIPConfig. Clearly, inside
nm-setting-ip4-config.c we wouldn't want to use the "parent_class"
name. Consistently rename @parent_class to @setting_class.
- Also rename the pointer to the own class to @klass. "setting_class" is also the
wrong name for that, because the right name would be something like
"setting_6lowpan_class".
However, "klass" is preferred over the latter, because we commonly create new
GObject implementations by copying an existing one. Generic names like "klass"
and "self" inside a type implementation make that simpler.
- drop useless comments like
/* virtual functions */
/* Properties */
It's better to logically and visually structure the code, and avoid trival
remarks about that. They only end up being used inconsistently. If you
even need a stronger visual separator, then an 80 char /****/ line
should be preferred.
2018-07-28 10:43:21 +02:00
|
|
|
setting_class->compare_property = compare_property;
|
|
|
|
|
setting_class->verify = verify;
|
2017-11-16 17:35:20 +01:00
|
|
|
|
|
|
|
|
/**
|
2018-03-24 15:18:21 +00:00
|
|
|
* NMSettingTCConfig:qdiscs: (type GPtrArray(NMTCQdisc))
|
2017-11-16 17:35:20 +01:00
|
|
|
*
|
2018-05-16 09:41:45 +02:00
|
|
|
* Array of TC queueing disciplines.
|
2017-11-16 17:35:20 +01:00
|
|
|
**/
|
2017-12-08 14:13:25 +01:00
|
|
|
/* ---ifcfg-rh---
|
|
|
|
|
* property: qdiscs
|
2018-05-28 18:13:42 +02:00
|
|
|
* variable: QDISC1(+), QDISC2(+), ...
|
2017-12-08 14:13:25 +01:00
|
|
|
* description: Queueing disciplines
|
|
|
|
|
* example: QDISC1=ingress, QDISC2="root handle 1234: fq_codel"
|
|
|
|
|
* ---end---
|
|
|
|
|
*/
|
2019-01-11 08:28:26 +01:00
|
|
|
obj_properties[PROP_QDISCS] =
|
|
|
|
|
g_param_spec_boxed (NM_SETTING_TC_CONFIG_QDISCS, "", "",
|
|
|
|
|
G_TYPE_PTR_ARRAY,
|
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
|
NM_SETTING_PARAM_INFERRABLE |
|
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
2019-09-22 15:32:04 +02:00
|
|
|
_nm_properties_override_gobj (properties_override,
|
|
|
|
|
obj_properties[PROP_QDISCS],
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE (
|
|
|
|
|
.dbus_type = NM_G_VARIANT_TYPE ("aa{sv}"),
|
|
|
|
|
.to_dbus_fcn = tc_qdiscs_get,
|
|
|
|
|
.from_dbus_fcn = tc_qdiscs_set,
|
|
|
|
|
));
|
2017-11-16 17:35:20 +01:00
|
|
|
|
2017-11-27 22:16:36 +01:00
|
|
|
/**
|
2018-03-24 15:18:21 +00:00
|
|
|
* NMSettingTCConfig:tfilters: (type GPtrArray(NMTCTfilter))
|
2017-11-27 22:16:36 +01:00
|
|
|
*
|
|
|
|
|
* Array of TC traffic filters.
|
|
|
|
|
**/
|
2017-12-08 14:13:25 +01:00
|
|
|
/* ---ifcfg-rh---
|
|
|
|
|
* property: qdiscs
|
2018-05-28 18:13:42 +02:00
|
|
|
* variable: FILTER1(+), FILTER2(+), ...
|
2017-12-08 14:13:25 +01:00
|
|
|
* description: Traffic filters
|
|
|
|
|
* example: FILTER1="parent ffff: matchall action simple sdata Input", ...
|
|
|
|
|
* ---end---
|
|
|
|
|
*/
|
2019-01-11 08:28:26 +01:00
|
|
|
obj_properties[PROP_TFILTERS] =
|
|
|
|
|
g_param_spec_boxed (NM_SETTING_TC_CONFIG_TFILTERS, "", "",
|
|
|
|
|
G_TYPE_PTR_ARRAY,
|
|
|
|
|
G_PARAM_READWRITE |
|
|
|
|
|
NM_SETTING_PARAM_INFERRABLE |
|
|
|
|
|
G_PARAM_STATIC_STRINGS);
|
2019-09-22 15:32:04 +02:00
|
|
|
_nm_properties_override_gobj (properties_override,
|
|
|
|
|
obj_properties[PROP_TFILTERS],
|
|
|
|
|
NM_SETT_INFO_PROPERT_TYPE (
|
|
|
|
|
.dbus_type = NM_G_VARIANT_TYPE ("aa{sv}"),
|
|
|
|
|
.to_dbus_fcn = tc_tfilters_get,
|
|
|
|
|
.from_dbus_fcn = tc_tfilters_set,
|
|
|
|
|
));
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
|
2019-01-11 08:28:26 +01:00
|
|
|
g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties);
|
|
|
|
|
|
libnm: rework setting metadata for property handling
NMSetting internally already tracked a list of all proper GObject properties
and D-Bus-only properties.
Rework the tracking of the list, so that:
- instead of attaching the data to the GType of the setting via
g_type_set_qdata(), it is tracked in a static array indexed by
NMMetaSettingType. This allows to find the setting-data by simple
pointer arithmetic, instead of taking a look and iterating (like
g_type_set_qdata() does).
Note, that this is still thread safe, because the static table entry is
initialized in the class-init function with _nm_setting_class_commit().
And it only accessed by following a NMSettingClass instance, thus
the class constructor already ran (maybe not for all setting classes,
but for the particular one that we look up).
I think this makes initialization of the metadata simpler to
understand.
Previously, in a first phase each class would attach the metadata
to the GType as setting_property_overrides_quark(). Then during
nm_setting_class_ensure_properties() it would merge them and
set as setting_properties_quark(). Now, during the first phase,
we only incrementally build a properties_override GArray, which
we finally hand over during nm_setting_class_commit().
- sort the property infos by name and do binary search.
Also expose this meta data types as internal API in nm-setting-private.h.
While not accessed yet, it can prove beneficial, to have direct (internal)
access to these structures.
Also, rename NMSettingProperty to NMSettInfoProperty to use a distinct
naming scheme. We already have 40+ subclasses of NMSetting that are called
NMSetting*. Likewise, NMMetaSetting* is heavily used already. So, choose a
new, distinct name.
2018-07-28 15:26:03 +02:00
|
|
|
_nm_setting_class_commit_full (setting_class, NM_META_SETTING_TYPE_TC_CONFIG,
|
|
|
|
|
NULL, properties_override);
|
2017-11-16 17:35:20 +01:00
|
|
|
}
|