mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-08 06:38:11 +02:00
l3cfg: merge branch 'th/l3cfg-8'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/623
This commit is contained in:
commit
ebd07a809c
21 changed files with 1916 additions and 1300 deletions
|
|
@ -3294,33 +3294,253 @@ nm_utils_hash_values_to_array (GHashTable *hash,
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean
|
static gboolean
|
||||||
nm_utils_hashtable_same_keys (const GHashTable *a,
|
_utils_hashtable_equal (GHashTable *hash_a,
|
||||||
const GHashTable *b)
|
GHashTable *hash_b,
|
||||||
|
GCompareDataFunc cmp_values,
|
||||||
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
GHashTableIter h;
|
GHashTableIter h;
|
||||||
const char *k;
|
gpointer a_key;
|
||||||
|
gpointer a_val;
|
||||||
|
gpointer b_val;
|
||||||
|
|
||||||
if (a == b)
|
nm_assert (hash_a);
|
||||||
return TRUE;
|
nm_assert (hash_b);
|
||||||
if (!a || !b)
|
nm_assert (hash_a != hash_b);
|
||||||
return FALSE;
|
nm_assert (g_hash_table_size (hash_a) == g_hash_table_size (hash_b));
|
||||||
if (g_hash_table_size ((GHashTable *) a) != g_hash_table_size ((GHashTable *) b))
|
|
||||||
return FALSE;
|
|
||||||
|
|
||||||
g_hash_table_iter_init (&h, (GHashTable *) a);
|
/* We rely on both hashes to have the same hash/equal function. Otherwise, we would have to iterate
|
||||||
while (g_hash_table_iter_next (&h, (gpointer) &k, NULL)) {
|
* both hashes and check whether all keys/values are present in the respective other hash (which
|
||||||
if (!g_hash_table_contains ((GHashTable *) b, k))
|
* would be O(n^2), since we couldn't use the plain lookup function. That is not a useful thing
|
||||||
|
* for this function. */
|
||||||
|
|
||||||
|
g_hash_table_iter_init (&h, hash_a);
|
||||||
|
while (g_hash_table_iter_next (&h, &a_key, &a_val)) {
|
||||||
|
|
||||||
|
if (!g_hash_table_lookup_extended (hash_b, a_key, NULL, &b_val))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (!cmp_values) {
|
||||||
|
/* we accept %NULL compare function to indicate that we don't care about the key. */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmp_values (a_val, b_val, user_data) != 0)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nm_utils_hashtable_equal:
|
||||||
|
* @a: (allow-none): the hash table or %NULL
|
||||||
|
* @b: (allow-none): the other hash table or %NULL
|
||||||
|
* @cmp_values: (allow-none): if %NULL, only the keys
|
||||||
|
* will be compared. Otherwise, this function is used to
|
||||||
|
* check whether all keys are equal.
|
||||||
|
* @user_data: the argument for @cmp_values.
|
||||||
|
*
|
||||||
|
* It is required that both @a and @b have the same hash and equals
|
||||||
|
* function.
|
||||||
|
*
|
||||||
|
* Returns: %TRUE, if both keys have the same keys and (if
|
||||||
|
* @cmp_values is given) all values are the same.
|
||||||
|
*/
|
||||||
|
gboolean
|
||||||
|
nm_utils_hashtable_equal (const GHashTable *a,
|
||||||
|
const GHashTable *b,
|
||||||
|
GCompareDataFunc cmp_values,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GHashTable *hash_a = (GHashTable *) a;
|
||||||
|
GHashTable *hash_b = (GHashTable *) b;
|
||||||
|
gboolean same;
|
||||||
|
guint size;
|
||||||
|
|
||||||
|
if (hash_a == hash_b)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
if (!hash_a || !hash_b)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
size = g_hash_table_size (hash_a);
|
||||||
|
if (size != g_hash_table_size (hash_b))
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
same = _utils_hashtable_equal (hash_a, hash_b, cmp_values, user_data);
|
||||||
|
|
||||||
#if NM_MORE_ASSERTS > 5
|
#if NM_MORE_ASSERTS > 5
|
||||||
g_hash_table_iter_init (&h, (GHashTable *) b);
|
nm_assert (same == _utils_hashtable_equal (hash_b, hash_a, cmp_values, user_data));
|
||||||
while (g_hash_table_iter_next (&h, (gpointer) &k, NULL))
|
|
||||||
nm_assert (g_hash_table_contains ((GHashTable *) a, k));
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return TRUE;
|
return same;
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
gpointer key;
|
||||||
|
gpointer val;
|
||||||
|
} HashTableCmpData;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
GCompareDataFunc cmp_keys;
|
||||||
|
gpointer user_data;
|
||||||
|
} HashTableUserData;
|
||||||
|
|
||||||
|
static int
|
||||||
|
_hashtable_cmp_func (gconstpointer a,
|
||||||
|
gconstpointer b,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
const HashTableUserData *d = user_data;
|
||||||
|
const HashTableCmpData *d_a = *((const HashTableCmpData *const*) a);
|
||||||
|
const HashTableCmpData *d_b = *((const HashTableCmpData *const*) b);
|
||||||
|
|
||||||
|
NM_CMP_RETURN (d->cmp_keys (d_a, d_b, d->user_data));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* nm_utils_hashtable_cmp:
|
||||||
|
* @a: (allow-none): the hash to compare. May be %NULL.
|
||||||
|
* @b: (allow-none): the other hash to compare. May be %NULL.
|
||||||
|
* @do_fast_precheck: if %TRUE, assume that the hashes are equal
|
||||||
|
* and that it is worth calling nm_utils_hashtable_equal() first.
|
||||||
|
* That requires, that both hashes have the same equals function
|
||||||
|
* which is compatible with the @cmp_keys function.
|
||||||
|
* @cmp_keys: the compare function for keys. Usually, the hash/equal function
|
||||||
|
* of both hashes corresponds to this function. If you set @do_fast_precheck
|
||||||
|
* to false, then this is not a requirement.
|
||||||
|
* @cmp_values: (allow-none): if %NULL, only the keys are compared.
|
||||||
|
* Otherwise, the values must are also compared with this function.
|
||||||
|
*
|
||||||
|
* Both hashes must have keys/values of the same domain, so that
|
||||||
|
* they can be effectively compared with @cmp_keys and @cmp_values.
|
||||||
|
*
|
||||||
|
* %NULL hashes compare equal to %NULL, but not to empty hashes.
|
||||||
|
*
|
||||||
|
* Returns: 0 if both hashes are equal, or -1 or 1 if one of the hashes
|
||||||
|
* sorts before/after.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
nm_utils_hashtable_cmp (const GHashTable *a,
|
||||||
|
const GHashTable *b,
|
||||||
|
gboolean do_fast_precheck,
|
||||||
|
GCompareDataFunc cmp_keys,
|
||||||
|
GCompareDataFunc cmp_values,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
GHashTable *hash_a = (GHashTable *) a;
|
||||||
|
GHashTable *hash_b = (GHashTable *) b;
|
||||||
|
gs_free HashTableCmpData *cmp_array_free = NULL;
|
||||||
|
HashTableCmpData *cmp_array_a;
|
||||||
|
HashTableCmpData *cmp_array_b;
|
||||||
|
GHashTableIter h;
|
||||||
|
gpointer i_key;
|
||||||
|
gpointer i_val;
|
||||||
|
gsize size2;
|
||||||
|
guint size;
|
||||||
|
guint i;
|
||||||
|
|
||||||
|
nm_assert (cmp_keys);
|
||||||
|
|
||||||
|
NM_CMP_SELF (hash_a, hash_b);
|
||||||
|
|
||||||
|
size = g_hash_table_size (hash_a);
|
||||||
|
|
||||||
|
NM_CMP_DIRECT (size, g_hash_table_size (hash_b));
|
||||||
|
|
||||||
|
if (size == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (do_fast_precheck) {
|
||||||
|
gboolean same;
|
||||||
|
|
||||||
|
/* we expect that the hashes are equal and the caller ensures us that they
|
||||||
|
* use the same hash/equal functions. Do a fast path check first...
|
||||||
|
*
|
||||||
|
* It's unclear whether this is worth it. The full comparison is O(n*ln(n)),
|
||||||
|
* while the fast check (using the hash lookup) is O(n). But then, the pre-check
|
||||||
|
* makes additional requirements on the hash's hash/equal functions -- the
|
||||||
|
* full comparison does not make such requirements. */
|
||||||
|
same = _utils_hashtable_equal (hash_a, hash_b, cmp_values, user_data);
|
||||||
|
#if NM_MORE_ASSERTS > 5
|
||||||
|
nm_assert (same == _utils_hashtable_equal (hash_b, hash_a, cmp_values, user_data));
|
||||||
|
#endif
|
||||||
|
if (same)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
size2 = ((gsize) size) * 2u;
|
||||||
|
if (size2 > 600u / sizeof (HashTableCmpData)) {
|
||||||
|
cmp_array_free = g_new (HashTableCmpData, size2);
|
||||||
|
cmp_array_a = cmp_array_free;
|
||||||
|
} else
|
||||||
|
cmp_array_a = g_newa (HashTableCmpData, size2);
|
||||||
|
cmp_array_b = &cmp_array_a[size];
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
g_hash_table_iter_init (&h, hash_a);
|
||||||
|
while (g_hash_table_iter_next (&h, &i_key, &i_val)) {
|
||||||
|
nm_assert (i < size);
|
||||||
|
cmp_array_a[i++] = (HashTableCmpData) {
|
||||||
|
.key = i_key,
|
||||||
|
.val = i_val,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
nm_assert (i == size);
|
||||||
|
|
||||||
|
i = 0;
|
||||||
|
g_hash_table_iter_init (&h, hash_b);
|
||||||
|
while (g_hash_table_iter_next (&h, &i_key, &i_val)) {
|
||||||
|
nm_assert (i < size);
|
||||||
|
cmp_array_b[i++] = (HashTableCmpData) {
|
||||||
|
.key = i_key,
|
||||||
|
.val = i_val,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
nm_assert (i == size);
|
||||||
|
|
||||||
|
g_qsort_with_data (cmp_array_a,
|
||||||
|
size,
|
||||||
|
sizeof (HashTableCmpData),
|
||||||
|
_hashtable_cmp_func,
|
||||||
|
&((HashTableUserData) {
|
||||||
|
.cmp_keys = cmp_keys,
|
||||||
|
.user_data = user_data,
|
||||||
|
}));
|
||||||
|
|
||||||
|
g_qsort_with_data (cmp_array_b,
|
||||||
|
size,
|
||||||
|
sizeof (HashTableCmpData),
|
||||||
|
_hashtable_cmp_func,
|
||||||
|
&((HashTableUserData) {
|
||||||
|
.cmp_keys = cmp_keys,
|
||||||
|
.user_data = user_data,
|
||||||
|
}));
|
||||||
|
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
NM_CMP_RETURN (cmp_keys (cmp_array_a[i].key,
|
||||||
|
cmp_array_b[i].key,
|
||||||
|
user_data));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cmp_values) {
|
||||||
|
for (i = 0; i < size; i++) {
|
||||||
|
NM_CMP_RETURN (cmp_values (cmp_array_a[i].val,
|
||||||
|
cmp_array_b[i].val,
|
||||||
|
user_data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* the fast-precheck should have already told that the arrays are equal. */
|
||||||
|
nm_assert (!do_fast_precheck);
|
||||||
|
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
char **
|
char **
|
||||||
|
|
|
||||||
|
|
@ -1521,8 +1521,24 @@ nm_utils_strdict_get_keys (const GHashTable *hash,
|
||||||
out_length);
|
out_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
gboolean nm_utils_hashtable_same_keys (const GHashTable *a,
|
gboolean nm_utils_hashtable_equal (const GHashTable *a,
|
||||||
const GHashTable *b);
|
const GHashTable *b,
|
||||||
|
GCompareDataFunc cmp_values,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
|
static inline gboolean
|
||||||
|
nm_utils_hashtable_same_keys (const GHashTable *a,
|
||||||
|
const GHashTable *b)
|
||||||
|
{
|
||||||
|
return nm_utils_hashtable_equal (a, b, NULL, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int nm_utils_hashtable_cmp (const GHashTable *a,
|
||||||
|
const GHashTable *b,
|
||||||
|
gboolean do_fast_precheck,
|
||||||
|
GCompareDataFunc cmp_keys,
|
||||||
|
GCompareDataFunc cmp_values,
|
||||||
|
gpointer user_data);
|
||||||
|
|
||||||
char **nm_utils_strv_make_deep_copied (const char **strv);
|
char **nm_utils_strv_make_deep_copied (const char **strv);
|
||||||
|
|
||||||
|
|
@ -1564,14 +1580,14 @@ nm_g_array_len (const GArray *arr)
|
||||||
|
|
||||||
#define nm_g_array_append_new(arr, type) \
|
#define nm_g_array_append_new(arr, type) \
|
||||||
({ \
|
({ \
|
||||||
GArray *_arr = (arr); \
|
GArray *const _arr = (arr); \
|
||||||
gsize _l; \
|
guint _len; \
|
||||||
\
|
\
|
||||||
nm_assert (_arr); \
|
nm_assert (_arr); \
|
||||||
_l = ((gsize) _arr->len) + 1u; \
|
_len = _arr->len; \
|
||||||
nm_assert (_l > _arr->len); \
|
nm_assert (_len < G_MAXUINT); \
|
||||||
g_array_set_size (_arr, _l); \
|
g_array_set_size (_arr, _len + 1u); \
|
||||||
&g_array_index (arr, type, _l); \
|
&g_array_index (arr, type, _len); \
|
||||||
})
|
})
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
|
||||||
|
|
@ -986,6 +986,122 @@ test_strv_dup_packed (void)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static int
|
||||||
|
_hash_func_cmp_direct (gconstpointer a,
|
||||||
|
gconstpointer b,
|
||||||
|
gpointer user_data)
|
||||||
|
{
|
||||||
|
NM_CMP_DIRECT (GPOINTER_TO_INT (a), GPOINTER_TO_INT (b));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
test_utils_hashtable_cmp (void)
|
||||||
|
{
|
||||||
|
static struct {
|
||||||
|
int val_i;
|
||||||
|
const char *val_s;
|
||||||
|
} vals[] = {
|
||||||
|
{ 0, "0", },
|
||||||
|
{ 1, "1", },
|
||||||
|
{ 2, "2", },
|
||||||
|
{ 3, "3", },
|
||||||
|
{ 4, "4", },
|
||||||
|
{ 5, "5", },
|
||||||
|
{ 6, "6", },
|
||||||
|
{ 7, "7", },
|
||||||
|
{ 8, "8", },
|
||||||
|
{ 9, "9", },
|
||||||
|
{ 0, "a", },
|
||||||
|
{ 1, "a", },
|
||||||
|
{ 2, "a", },
|
||||||
|
{ 3, "a", },
|
||||||
|
{ 4, "a", },
|
||||||
|
{ 5, "a", },
|
||||||
|
{ 0, "0", },
|
||||||
|
{ 0, "1", },
|
||||||
|
{ 0, "2", },
|
||||||
|
{ 0, "3", },
|
||||||
|
{ 0, "4", },
|
||||||
|
{ 0, "5", },
|
||||||
|
};
|
||||||
|
guint test_run;
|
||||||
|
int is_num_key;
|
||||||
|
|
||||||
|
for (test_run = 0; test_run < 30; test_run++) {
|
||||||
|
for (is_num_key = 0; is_num_key < 2; is_num_key++) {
|
||||||
|
GHashFunc func_key_hash = is_num_key ? nm_direct_hash : nm_str_hash;
|
||||||
|
GEqualFunc func_key_equal = is_num_key ? g_direct_equal : g_str_equal;
|
||||||
|
GCompareDataFunc func_key_cmp = is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data;
|
||||||
|
GCompareDataFunc func_val_cmp = !is_num_key ? _hash_func_cmp_direct : (GCompareDataFunc) nm_strcmp_with_data;
|
||||||
|
gs_unref_hashtable GHashTable *h1 = NULL;
|
||||||
|
gs_unref_hashtable GHashTable *h2 = NULL;
|
||||||
|
gboolean has_same_keys;
|
||||||
|
guint i, n;
|
||||||
|
|
||||||
|
h1 = g_hash_table_new (func_key_hash, func_key_equal);
|
||||||
|
h2 = g_hash_table_new (func_key_hash, func_key_equal);
|
||||||
|
|
||||||
|
n = nmtst_get_rand_word_length (NULL);
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
typeof (vals[0]) *v = &vals[nmtst_get_rand_uint32 () % G_N_ELEMENTS (vals)];
|
||||||
|
gconstpointer v_key = is_num_key ? GINT_TO_POINTER (v->val_i) : v->val_s;
|
||||||
|
gconstpointer v_val = !is_num_key ? GINT_TO_POINTER (v->val_i) : v->val_s;
|
||||||
|
|
||||||
|
g_hash_table_insert (h1, (gpointer) v_key, (gpointer) v_val);
|
||||||
|
g_hash_table_insert (h2, (gpointer) v_key, (gpointer) v_val);
|
||||||
|
}
|
||||||
|
|
||||||
|
g_assert (nm_utils_hashtable_same_keys (h1, h2));
|
||||||
|
g_assert (nm_utils_hashtable_equal (h1, h2, NULL, NULL));
|
||||||
|
g_assert (nm_utils_hashtable_equal (h1, h2, func_val_cmp, NULL));
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0);
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0);
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) == 0);
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) == 0);
|
||||||
|
|
||||||
|
n = nmtst_get_rand_word_length (NULL) + 1;
|
||||||
|
has_same_keys = TRUE;
|
||||||
|
for (i = 0; i < n; i++) {
|
||||||
|
again:
|
||||||
|
{
|
||||||
|
typeof (vals[0]) *v = &vals[nmtst_get_rand_uint32 () % G_N_ELEMENTS (vals)];
|
||||||
|
gconstpointer v_key = is_num_key ? GINT_TO_POINTER (v->val_i) : v->val_s;
|
||||||
|
gconstpointer v_val = !is_num_key ? GINT_TO_POINTER (v->val_i) : v->val_s;
|
||||||
|
gpointer v_key2;
|
||||||
|
gpointer v_val2;
|
||||||
|
|
||||||
|
if (g_hash_table_lookup_extended (h1, v_key, &v_key2, &v_val2)) {
|
||||||
|
g_assert (func_key_cmp (v_key, v_key2, NULL) == 0);
|
||||||
|
if (func_val_cmp (v_val, v_val2, NULL) == 0)
|
||||||
|
goto again;
|
||||||
|
} else
|
||||||
|
has_same_keys = FALSE;
|
||||||
|
|
||||||
|
g_hash_table_insert (h2, (gpointer) v_key, (gpointer) v_val);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (has_same_keys) {
|
||||||
|
g_assert (nm_utils_hashtable_same_keys (h1, h2));
|
||||||
|
g_assert (nm_utils_hashtable_equal (h1, h2, NULL, NULL));
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, NULL, NULL) == 0);
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, NULL, NULL) == 0);
|
||||||
|
} else {
|
||||||
|
g_assert (!nm_utils_hashtable_same_keys (h1, h2));
|
||||||
|
g_assert (!nm_utils_hashtable_equal (h1, h2, NULL, NULL));
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, NULL, NULL) != 0);
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, NULL, NULL) != 0);
|
||||||
|
}
|
||||||
|
g_assert (!nm_utils_hashtable_equal (h1, h2, func_val_cmp, NULL));
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, FALSE, func_key_cmp, func_val_cmp, NULL) != 0);
|
||||||
|
g_assert (nm_utils_hashtable_cmp (h1, h2, TRUE, func_key_cmp, func_val_cmp, NULL) != 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
NMTST_DEFINE ();
|
NMTST_DEFINE ();
|
||||||
|
|
||||||
int main (int argc, char **argv)
|
int main (int argc, char **argv)
|
||||||
|
|
@ -1011,6 +1127,7 @@ int main (int argc, char **argv)
|
||||||
g_test_add_func ("/general/test_in_strset_ascii_case", test_in_strset_ascii_case);
|
g_test_add_func ("/general/test_in_strset_ascii_case", test_in_strset_ascii_case);
|
||||||
g_test_add_func ("/general/test_is_specific_hostname", test_is_specific_hostname);
|
g_test_add_func ("/general/test_is_specific_hostname", test_is_specific_hostname);
|
||||||
g_test_add_func ("/general/test_strv_dup_packed", test_strv_dup_packed);
|
g_test_add_func ("/general/test_strv_dup_packed", test_strv_dup_packed);
|
||||||
|
g_test_add_func ("/general/test_utils_hashtable_cmp", test_utils_hashtable_cmp);
|
||||||
|
|
||||||
return g_test_run ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -159,4 +159,65 @@ void nm_utils_ip_routes_to_dbus (int addr_family,
|
||||||
GVariant **out_route_data,
|
GVariant **out_route_data,
|
||||||
GVariant **out_routes);
|
GVariant **out_routes);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/* For now, all we track about a DHCP lease is the GHashTable with
|
||||||
|
* the options.
|
||||||
|
*
|
||||||
|
* We don't add a separate type for that, but we also don't want to use
|
||||||
|
* GHashTable directly (because most importantly leases should be immutable
|
||||||
|
* and passing a GHashTable pointer around neither makes it clear that
|
||||||
|
* this is a lease nor that it's immutable.
|
||||||
|
*
|
||||||
|
* Instead, add a simple opaque pointer and accessors that cast to a GHashTable.
|
||||||
|
*
|
||||||
|
* It has no overhead at run time, but gives some rudimentary type safety. */
|
||||||
|
|
||||||
|
typedef struct _NMDhcpLease NMDhcpLease;
|
||||||
|
|
||||||
|
static inline NMDhcpLease *
|
||||||
|
nm_dhcp_lease_new_from_options (GHashTable *options_take)
|
||||||
|
{
|
||||||
|
/* a NMDhcpLease is really just a GHashTable. But it's also supposed to be *immutable*.
|
||||||
|
*
|
||||||
|
* Hence, the API here takes over ownership of the reference to @options_take, that
|
||||||
|
* is to emphasize that we acquire ownership of the hash, and it should not be modified
|
||||||
|
* anymore. */
|
||||||
|
return (NMDhcpLease *) options_take;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline GHashTable *
|
||||||
|
nm_dhcp_lease_get_options (NMDhcpLease *lease)
|
||||||
|
{
|
||||||
|
return (GHashTable *) lease;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nm_dhcp_lease_ref (NMDhcpLease *lease)
|
||||||
|
{
|
||||||
|
if (lease)
|
||||||
|
g_hash_table_ref ((GHashTable *) lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
nm_dhcp_lease_unref (NMDhcpLease *lease)
|
||||||
|
{
|
||||||
|
if (lease)
|
||||||
|
g_hash_table_unref ((GHashTable *) lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *
|
||||||
|
nm_dhcp_lease_lookup_option (NMDhcpLease *lease,
|
||||||
|
const char *option)
|
||||||
|
{
|
||||||
|
nm_assert (option);
|
||||||
|
|
||||||
|
return nm_g_hash_table_lookup ((GHashTable *) lease, option);
|
||||||
|
}
|
||||||
|
|
||||||
|
NM_AUTO_DEFINE_FCN (NMDhcpLease *, _nm_auto_unref_dhcplease, nm_dhcp_lease_unref);
|
||||||
|
#define nm_auto_unref_dhcplease nm_auto (_nm_auto_unref_dhcplease)
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
#endif /* __NETWORKMANAGER_UTILS_H__ */
|
#endif /* __NETWORKMANAGER_UTILS_H__ */
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -16,7 +16,7 @@
|
||||||
#include "nm-rfkill-manager.h"
|
#include "nm-rfkill-manager.h"
|
||||||
#include "NetworkManagerUtils.h"
|
#include "NetworkManagerUtils.h"
|
||||||
|
|
||||||
typedef enum {
|
typedef enum _nm_packed {
|
||||||
NM_DEVICE_SYS_IFACE_STATE_EXTERNAL,
|
NM_DEVICE_SYS_IFACE_STATE_EXTERNAL,
|
||||||
NM_DEVICE_SYS_IFACE_STATE_ASSUME,
|
NM_DEVICE_SYS_IFACE_STATE_ASSUME,
|
||||||
NM_DEVICE_SYS_IFACE_STATE_MANAGED,
|
NM_DEVICE_SYS_IFACE_STATE_MANAGED,
|
||||||
|
|
|
||||||
|
|
@ -480,15 +480,8 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( priv->addr_family == AF_INET6
|
if (priv->addr_family == AF_INET6)
|
||||||
&& NM_IN_SET (new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) {
|
event_id = nm_dhcp_utils_get_dhcp6_event_id (options);
|
||||||
char *start, *iaid;
|
|
||||||
|
|
||||||
iaid = g_hash_table_lookup (options, "iaid");
|
|
||||||
start = g_hash_table_lookup (options, "life_starts");
|
|
||||||
if (iaid && start)
|
|
||||||
event_id = g_strdup_printf ("%s|%s", iaid, start);
|
|
||||||
}
|
|
||||||
|
|
||||||
_LOGI ("state changed %s -> %s%s%s%s",
|
_LOGI ("state changed %s -> %s%s%s%s",
|
||||||
state_to_string (priv->state),
|
state_to_string (priv->state),
|
||||||
|
|
@ -500,8 +493,7 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
|
||||||
signals[SIGNAL_STATE_CHANGED], 0,
|
signals[SIGNAL_STATE_CHANGED], 0,
|
||||||
new_state,
|
new_state,
|
||||||
ip_config,
|
ip_config,
|
||||||
options,
|
options);
|
||||||
event_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
|
|
@ -1319,7 +1311,11 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
|
||||||
G_SIGNAL_RUN_FIRST,
|
G_SIGNAL_RUN_FIRST,
|
||||||
0,
|
0,
|
||||||
NULL, NULL, NULL,
|
NULL, NULL, NULL,
|
||||||
G_TYPE_NONE, 4, G_TYPE_UINT, G_TYPE_OBJECT, G_TYPE_HASH_TABLE, G_TYPE_STRING);
|
G_TYPE_NONE,
|
||||||
|
3,
|
||||||
|
G_TYPE_UINT,
|
||||||
|
G_TYPE_OBJECT,
|
||||||
|
G_TYPE_HASH_TABLE);
|
||||||
|
|
||||||
signals[SIGNAL_PREFIX_DELEGATED] =
|
signals[SIGNAL_PREFIX_DELEGATED] =
|
||||||
g_signal_new (NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED,
|
g_signal_new (NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED,
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,14 @@ G_DEFINE_TYPE (NMDhcpManager, nm_dhcp_manager, G_TYPE_OBJECT)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static void client_state_changed (NMDhcpClient *client,
|
||||||
|
NMDhcpState state,
|
||||||
|
GObject *ip_config,
|
||||||
|
GVariant *options,
|
||||||
|
NMDhcpManager *self);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
/* default to installed helper, but can be modified for testing */
|
/* default to installed helper, but can be modified for testing */
|
||||||
const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper";
|
const char *nm_dhcp_helper_path = LIBEXECDIR "/nm-dhcp-helper";
|
||||||
|
|
||||||
|
|
@ -161,13 +169,6 @@ get_client_for_ifindex (NMDhcpManager *manager, int addr_family, int ifindex)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void client_state_changed (NMDhcpClient *client,
|
|
||||||
NMDhcpState state,
|
|
||||||
GObject *ip_config,
|
|
||||||
GVariant *options,
|
|
||||||
const char *event_id,
|
|
||||||
NMDhcpManager *self);
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
remove_client (NMDhcpManager *self, NMDhcpClient *client)
|
remove_client (NMDhcpManager *self, NMDhcpClient *client)
|
||||||
{
|
{
|
||||||
|
|
@ -192,7 +193,6 @@ client_state_changed (NMDhcpClient *client,
|
||||||
NMDhcpState state,
|
NMDhcpState state,
|
||||||
GObject *ip_config,
|
GObject *ip_config,
|
||||||
GVariant *options,
|
GVariant *options,
|
||||||
const char *event_id,
|
|
||||||
NMDhcpManager *self)
|
NMDhcpManager *self)
|
||||||
{
|
{
|
||||||
if (state >= NM_DHCP_STATE_TIMEOUT)
|
if (state >= NM_DHCP_STATE_TIMEOUT)
|
||||||
|
|
|
||||||
|
|
@ -219,9 +219,9 @@ nm_dhcp_option_request_string (const NMDhcpOption *requests, guint option)
|
||||||
|
|
||||||
void
|
void
|
||||||
nm_dhcp_option_take_option (GHashTable *options,
|
nm_dhcp_option_take_option (GHashTable *options,
|
||||||
const NMDhcpOption *requests,
|
const NMDhcpOption *requests,
|
||||||
guint option,
|
guint option,
|
||||||
char *value)
|
char *value)
|
||||||
{
|
{
|
||||||
nm_assert (options);
|
nm_assert (options);
|
||||||
nm_assert (requests);
|
nm_assert (requests);
|
||||||
|
|
|
||||||
|
|
@ -786,3 +786,23 @@ nm_dhcp_utils_get_leasefile_path (int addr_family,
|
||||||
*out_leasefile_path = g_steal_pointer (&statedir_path);
|
*out_leasefile_path = g_steal_pointer (&statedir_path);
|
||||||
return FALSE;
|
return FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
nm_dhcp_utils_get_dhcp6_event_id (GHashTable *lease)
|
||||||
|
{
|
||||||
|
const char *start;
|
||||||
|
const char *iaid;
|
||||||
|
|
||||||
|
if (!lease)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
iaid = g_hash_table_lookup (lease, "iaid");
|
||||||
|
if (!iaid)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
start = g_hash_table_lookup (lease, "life_starts");
|
||||||
|
if (!start)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return g_strdup_printf ("%s|%s", iaid, start);
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -38,5 +38,7 @@ gboolean nm_dhcp_utils_get_leasefile_path (int addr_family,
|
||||||
|
|
||||||
char **nm_dhcp_parse_search_list (guint8 *data, size_t n_data);
|
char **nm_dhcp_parse_search_list (guint8 *data, size_t n_data);
|
||||||
|
|
||||||
|
char *nm_dhcp_utils_get_dhcp6_event_id (GHashTable *lease);
|
||||||
|
|
||||||
#endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */
|
#endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3757,6 +3757,113 @@ nm_utils_dhcp_client_id_systemd_node_specific (guint32 iaid)
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
nm_utils_generate_duid_llt (int arp_type,
|
||||||
|
const guint8 *hwaddr,
|
||||||
|
gsize hwaddr_len,
|
||||||
|
gint64 time)
|
||||||
|
{
|
||||||
|
guint8 *arr;
|
||||||
|
const guint16 duid_type = htons (1);
|
||||||
|
const guint16 hw_type = htons (arp_type);
|
||||||
|
const guint32 duid_time = htonl (NM_MAX (0, time - NM_UTILS_EPOCH_DATETIME_200001010000));
|
||||||
|
|
||||||
|
if (!nm_utils_arp_type_get_hwaddr_relevant_part (arp_type, &hwaddr, &hwaddr_len))
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
|
||||||
|
arr = g_new (guint8, (2u + 2u + 4u) + hwaddr_len);
|
||||||
|
|
||||||
|
memcpy (&arr[0], &duid_type, 2);
|
||||||
|
memcpy (&arr[2], &hw_type, 2);
|
||||||
|
memcpy (&arr[4], &duid_time, 4);
|
||||||
|
memcpy (&arr[8], hwaddr, hwaddr_len);
|
||||||
|
|
||||||
|
return g_bytes_new_take (arr, (2u + 2u + 4u) + hwaddr_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
nm_utils_generate_duid_ll (int arp_type,
|
||||||
|
const guint8 *hwaddr,
|
||||||
|
gsize hwaddr_len)
|
||||||
|
{
|
||||||
|
guint8 *arr;
|
||||||
|
const guint16 duid_type = htons (3);
|
||||||
|
const guint16 hw_type = htons (arp_type);
|
||||||
|
|
||||||
|
if (!nm_utils_arp_type_get_hwaddr_relevant_part (arp_type, &hwaddr, &hwaddr_len))
|
||||||
|
nm_assert_not_reached ();
|
||||||
|
|
||||||
|
arr = g_new (guint8, (2u + 2u) + hwaddr_len);
|
||||||
|
|
||||||
|
memcpy (&arr[0], &duid_type, 2);
|
||||||
|
memcpy (&arr[2], &hw_type, 2);
|
||||||
|
memcpy (&arr[4], hwaddr, hwaddr_len);
|
||||||
|
|
||||||
|
return g_bytes_new_take (arr, (2u + 2u) + hwaddr_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
nm_utils_generate_duid_uuid (const NMUuid *uuid)
|
||||||
|
{
|
||||||
|
const guint16 duid_type = htons (4);
|
||||||
|
guint8 *duid_buffer;
|
||||||
|
|
||||||
|
nm_assert (uuid);
|
||||||
|
|
||||||
|
/* Generate a DHCP Unique Identifier for DHCPv6 using the
|
||||||
|
* DUID-UUID method (see RFC 6355 section 4). Format is:
|
||||||
|
*
|
||||||
|
* u16: type (DUID-UUID = 4)
|
||||||
|
* u8[16]: UUID bytes
|
||||||
|
*/
|
||||||
|
G_STATIC_ASSERT_EXPR (sizeof (duid_type) == 2);
|
||||||
|
G_STATIC_ASSERT_EXPR (sizeof (*uuid) == 16);
|
||||||
|
duid_buffer = g_malloc (18);
|
||||||
|
memcpy (&duid_buffer[0], &duid_type, 2);
|
||||||
|
memcpy (&duid_buffer[2], uuid, 16);
|
||||||
|
return g_bytes_new_take (duid_buffer, 18);
|
||||||
|
}
|
||||||
|
|
||||||
|
GBytes *
|
||||||
|
nm_utils_generate_duid_from_machine_id (void)
|
||||||
|
{
|
||||||
|
static GBytes *volatile global_duid = NULL;
|
||||||
|
GBytes *p;
|
||||||
|
|
||||||
|
again:
|
||||||
|
p = g_atomic_pointer_get (&global_duid);
|
||||||
|
if (G_UNLIKELY (!p)) {
|
||||||
|
nm_auto_free_checksum GChecksum *sum = NULL;
|
||||||
|
const NMUuid *machine_id;
|
||||||
|
union {
|
||||||
|
guint8 sha256[NM_UTILS_CHECKSUM_LENGTH_SHA256];
|
||||||
|
NMUuid uuid;
|
||||||
|
} digest;
|
||||||
|
|
||||||
|
machine_id = nm_utils_machine_id_bin ();
|
||||||
|
|
||||||
|
/* Hash the machine ID so it's not leaked to the network.
|
||||||
|
*
|
||||||
|
* Optimally, we would choose an use case specific seed, but for historic
|
||||||
|
* reasons we didn't. */
|
||||||
|
sum = g_checksum_new (G_CHECKSUM_SHA256);
|
||||||
|
g_checksum_update (sum, (const guchar *) machine_id, sizeof (*machine_id));
|
||||||
|
nm_utils_checksum_get_digest (sum, digest.sha256);
|
||||||
|
|
||||||
|
G_STATIC_ASSERT_EXPR (sizeof (digest.sha256) > sizeof (digest.uuid));
|
||||||
|
p = nm_utils_generate_duid_uuid (&digest.uuid);
|
||||||
|
|
||||||
|
if (!g_atomic_pointer_compare_and_exchange (&global_duid, NULL, p)) {
|
||||||
|
g_bytes_unref (p);
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return g_bytes_ref (p);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* nm_utils_setpgid:
|
* nm_utils_setpgid:
|
||||||
* @unused: unused
|
* @unused: unused
|
||||||
|
|
|
||||||
|
|
@ -430,6 +430,26 @@ GBytes *nm_utils_dhcp_client_id_systemd_node_specific (guint32 iaid);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
/* RFC 3315 defines the epoch for the DUID-LLT time field on Jan 1st 2000. */
|
||||||
|
#define NM_UTILS_EPOCH_DATETIME_200001010000 946684800
|
||||||
|
|
||||||
|
struct _NMUuid;
|
||||||
|
|
||||||
|
GBytes *nm_utils_generate_duid_llt (int arp_type,
|
||||||
|
const guint8 *hwaddr,
|
||||||
|
gsize hwaddr_len,
|
||||||
|
gint64 time);
|
||||||
|
|
||||||
|
GBytes *nm_utils_generate_duid_ll (int arp_type,
|
||||||
|
const guint8 *hwaddr,
|
||||||
|
gsize hwaddr_len);
|
||||||
|
|
||||||
|
GBytes *nm_utils_generate_duid_uuid (const struct _NMUuid *uuid);
|
||||||
|
|
||||||
|
GBytes *nm_utils_generate_duid_from_machine_id (void);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len);
|
void nm_utils_array_remove_at_indexes (GArray *array, const guint *indexes_to_delete, gsize len);
|
||||||
|
|
||||||
void nm_utils_setpgid (gpointer unused);
|
void nm_utils_setpgid (gpointer unused);
|
||||||
|
|
|
||||||
|
|
@ -95,7 +95,6 @@ dhcp4_state_changed (NMDhcpClient *client,
|
||||||
NMDhcpState state,
|
NMDhcpState state,
|
||||||
NMIP4Config *ip4_config,
|
NMIP4Config *ip4_config,
|
||||||
GHashTable *options,
|
GHashTable *options,
|
||||||
const char *event_id,
|
|
||||||
gpointer user_data)
|
gpointer user_data)
|
||||||
{
|
{
|
||||||
static NMIP4Config *last_config = NULL;
|
static NMIP4Config *last_config = NULL;
|
||||||
|
|
|
||||||
|
|
@ -1656,30 +1656,9 @@ nm_ip6_config_find_first_address (const NMIP6Config *self,
|
||||||
nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY));
|
nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY));
|
||||||
|
|
||||||
nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) {
|
nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) {
|
||||||
|
if (nm_platform_ip6_address_match (addr, match_flag))
|
||||||
if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) {
|
return addr;
|
||||||
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL))
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED)) {
|
|
||||||
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED))
|
|
||||||
continue;
|
|
||||||
} else if ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TENTATIVE)
|
|
||||||
&& !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_OPTIMISTIC)) {
|
|
||||||
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE))
|
|
||||||
continue;
|
|
||||||
} else {
|
|
||||||
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL))
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -52,6 +52,14 @@ struct _NML3ConfigData {
|
||||||
|
|
||||||
char *nis_domain;
|
char *nis_domain;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
NMDhcpLease *dhcp_lease_6;
|
||||||
|
NMDhcpLease *dhcp_lease_4;
|
||||||
|
};
|
||||||
|
NMDhcpLease *dhcp_lease_x[2];
|
||||||
|
};
|
||||||
|
|
||||||
union {
|
union {
|
||||||
struct {
|
struct {
|
||||||
GArray *nameservers_6;
|
GArray *nameservers_6;
|
||||||
|
|
@ -472,6 +480,9 @@ nm_l3_config_data_unref (const NML3ConfigData *self)
|
||||||
nm_clear_pointer (&mutable->wins, g_array_unref);
|
nm_clear_pointer (&mutable->wins, g_array_unref);
|
||||||
nm_clear_pointer (&mutable->nis_servers, g_array_unref);
|
nm_clear_pointer (&mutable->nis_servers, g_array_unref);
|
||||||
|
|
||||||
|
nm_clear_pointer (&mutable->dhcp_lease_4, nm_dhcp_lease_unref);
|
||||||
|
nm_clear_pointer (&mutable->dhcp_lease_6, nm_dhcp_lease_unref);
|
||||||
|
|
||||||
nm_clear_pointer (&mutable->nameservers_4, g_array_unref);
|
nm_clear_pointer (&mutable->nameservers_4, g_array_unref);
|
||||||
nm_clear_pointer (&mutable->nameservers_6, g_array_unref);
|
nm_clear_pointer (&mutable->nameservers_6, g_array_unref);
|
||||||
|
|
||||||
|
|
@ -572,6 +583,8 @@ nm_l3_config_data_lookup_index (const NML3ConfigData *self, NMPObjectType obj_ty
|
||||||
const NMDedupMultiHeadEntry *
|
const NMDedupMultiHeadEntry *
|
||||||
nm_l3_config_data_lookup_objs (const NML3ConfigData *self, NMPObjectType obj_type)
|
nm_l3_config_data_lookup_objs (const NML3ConfigData *self, NMPObjectType obj_type)
|
||||||
{
|
{
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
return nm_dedup_multi_index_lookup_head (self->multi_idx,
|
return nm_dedup_multi_index_lookup_head (self->multi_idx,
|
||||||
nm_l3_config_data_lookup_index (self, obj_type),
|
nm_l3_config_data_lookup_index (self, obj_type),
|
||||||
NULL);
|
NULL);
|
||||||
|
|
@ -1324,6 +1337,63 @@ nm_l3_config_data_set_source (NML3ConfigData *self,
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
NMDhcpLease *
|
||||||
|
nm_l3_config_data_get_dhcp_lease (const NML3ConfigData *self,
|
||||||
|
int addr_family)
|
||||||
|
{
|
||||||
|
nm_assert (_NM_IS_L3_CONFIG_DATA (self, TRUE));
|
||||||
|
|
||||||
|
return self->dhcp_lease_x[NM_IS_IPv4 (addr_family)];
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
nm_l3_config_data_set_dhcp_lease (NML3ConfigData *self,
|
||||||
|
int addr_family,
|
||||||
|
NMDhcpLease *lease)
|
||||||
|
{
|
||||||
|
nm_auto_unref_dhcplease NMDhcpLease *lease_old = NULL;
|
||||||
|
NMDhcpLease **p_lease;
|
||||||
|
|
||||||
|
nm_assert (_NM_IS_L3_CONFIG_DATA (self, FALSE));
|
||||||
|
|
||||||
|
p_lease = &self->dhcp_lease_x[NM_IS_IPv4 (addr_family)];
|
||||||
|
|
||||||
|
if (*p_lease == lease)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
if (lease)
|
||||||
|
nm_dhcp_lease_ref (lease);
|
||||||
|
lease_old = *p_lease;
|
||||||
|
*p_lease = lease;
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
nm_l3_config_data_set_dhcp_lease_from_options (NML3ConfigData *self,
|
||||||
|
int addr_family,
|
||||||
|
GHashTable *options_take)
|
||||||
|
{
|
||||||
|
nm_auto_unref_dhcplease NMDhcpLease *lease = NULL;
|
||||||
|
nm_auto_unref_dhcplease NMDhcpLease *lease_old = NULL;
|
||||||
|
NMDhcpLease **p_lease;
|
||||||
|
|
||||||
|
nm_assert (_NM_IS_L3_CONFIG_DATA (self, FALSE));
|
||||||
|
|
||||||
|
if (options_take)
|
||||||
|
lease = nm_dhcp_lease_new_from_options (g_steal_pointer (&options_take));
|
||||||
|
|
||||||
|
p_lease = &self->dhcp_lease_x[NM_IS_IPv4 (addr_family)];
|
||||||
|
|
||||||
|
if (*p_lease == lease)
|
||||||
|
return FALSE;
|
||||||
|
|
||||||
|
lease_old = *p_lease;
|
||||||
|
*p_lease = g_steal_pointer (&lease);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static int
|
static int
|
||||||
_dedup_multi_index_cmp (const NML3ConfigData *a,
|
_dedup_multi_index_cmp (const NML3ConfigData *a,
|
||||||
const NML3ConfigData *b,
|
const NML3ConfigData *b,
|
||||||
|
|
@ -1386,6 +1456,13 @@ nm_l3_config_data_cmp (const NML3ConfigData *a, const NML3ConfigData *b)
|
||||||
|
|
||||||
NM_CMP_RETURN (_garray_inaddr_cmp (a->nameservers_x[IS_IPv4], b->nameservers_x[IS_IPv4], addr_family));
|
NM_CMP_RETURN (_garray_inaddr_cmp (a->nameservers_x[IS_IPv4], b->nameservers_x[IS_IPv4], addr_family));
|
||||||
|
|
||||||
|
NM_CMP_RETURN (nm_utils_hashtable_cmp (nm_dhcp_lease_get_options (a->dhcp_lease_x[IS_IPv4]),
|
||||||
|
nm_dhcp_lease_get_options (b->dhcp_lease_x[IS_IPv4]),
|
||||||
|
TRUE,
|
||||||
|
nm_strcmp_with_data,
|
||||||
|
nm_strcmp_with_data,
|
||||||
|
NULL));
|
||||||
|
|
||||||
NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->domains_x[IS_IPv4], b->domains_x[IS_IPv4]));
|
NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->domains_x[IS_IPv4], b->domains_x[IS_IPv4]));
|
||||||
NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->searches_x[IS_IPv4], b->searches_x[IS_IPv4]));
|
NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->searches_x[IS_IPv4], b->searches_x[IS_IPv4]));
|
||||||
NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->dns_options_x[IS_IPv4], b->dns_options_x[IS_IPv4]));
|
NM_CMP_RETURN (nm_strv_ptrarray_cmp (a->dns_options_x[IS_IPv4], b->dns_options_x[IS_IPv4]));
|
||||||
|
|
@ -2177,6 +2254,7 @@ nm_l3_config_data_merge (NML3ConfigData *self,
|
||||||
self->mtu = src->mtu;
|
self->mtu = src->mtu;
|
||||||
|
|
||||||
/* self->source does not get merged. */
|
/* self->source does not get merged. */
|
||||||
|
/* self->dhcp_lease_x does not get merged. */
|
||||||
}
|
}
|
||||||
|
|
||||||
NML3ConfigData *
|
NML3ConfigData *
|
||||||
|
|
|
||||||
|
|
@ -486,6 +486,17 @@ gboolean nm_l3_config_data_set_dns_priority (NML3ConfigData *self,
|
||||||
int addr_family,
|
int addr_family,
|
||||||
int dns_priority);
|
int dns_priority);
|
||||||
|
|
||||||
|
struct _NMDhcpLease *nm_l3_config_data_get_dhcp_lease (const NML3ConfigData *self,
|
||||||
|
int addr_family);
|
||||||
|
|
||||||
|
gboolean nm_l3_config_data_set_dhcp_lease (NML3ConfigData *self,
|
||||||
|
int addr_family,
|
||||||
|
struct _NMDhcpLease *lease);
|
||||||
|
|
||||||
|
gboolean nm_l3_config_data_set_dhcp_lease_from_options (NML3ConfigData *self,
|
||||||
|
int addr_family,
|
||||||
|
GHashTable *options_take);
|
||||||
|
|
||||||
static inline const NMIPAddr *
|
static inline const NMIPAddr *
|
||||||
nmtst_l3_config_data_get_best_gateway (const NML3ConfigData *self,
|
nmtst_l3_config_data_get_best_gateway (const NML3ConfigData *self,
|
||||||
int addr_family)
|
int addr_family)
|
||||||
|
|
|
||||||
|
|
@ -3018,6 +3018,34 @@ nm_l3cfg_commit_type_unregister (NML3Cfg *self,
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
const NML3ConfigData *
|
||||||
|
nm_l3cfg_get_combined_l3cd (NML3Cfg *self)
|
||||||
|
{
|
||||||
|
nm_assert (NM_IS_L3CFG (self));
|
||||||
|
|
||||||
|
return self->priv.p->combined_l3cd;
|
||||||
|
}
|
||||||
|
|
||||||
|
const NMPObject *
|
||||||
|
nm_l3cfg_get_best_default_route (NML3Cfg *self,
|
||||||
|
int addr_family)
|
||||||
|
{
|
||||||
|
nm_assert (NM_IS_L3CFG (self));
|
||||||
|
|
||||||
|
/* we only consider the combined_l3cd. This is a merge of all the l3cd, and the one
|
||||||
|
* with which we called nm_l3cfg_platform_commit() the last time.
|
||||||
|
*
|
||||||
|
* In the meantime, we might have changed the tracked l3_config_datas, but we didn't
|
||||||
|
* nm_l3cfg_platform_commit() yet. These changes are ignored for this purpose, until
|
||||||
|
* the user call nm_l3cfg_platform_commit() to re-commit the changes. */
|
||||||
|
if (!self->priv.p->combined_l3cd)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return nm_l3_config_data_get_best_default_route (self->priv.p->combined_l3cd, addr_family);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
static void
|
static void
|
||||||
set_property (GObject *object,
|
set_property (GObject *object,
|
||||||
guint prop_id,
|
guint prop_id,
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,28 @@ nm_l3cfg_get_ifname (const NML3Cfg *self)
|
||||||
return nmp_object_link_get_ifname (self->priv.pllink);
|
return nmp_object_link_get_ifname (self->priv.pllink);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline const NMPObject *
|
||||||
|
nm_l3cfg_get_plobj (const NML3Cfg *self)
|
||||||
|
{
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nm_assert (NM_IS_L3CFG (self));
|
||||||
|
|
||||||
|
return self->priv.pllink;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const NMPlatformLink *
|
||||||
|
nm_l3cfg_get_pllink (const NML3Cfg *self)
|
||||||
|
{
|
||||||
|
if (!self)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
nm_assert (NM_IS_L3CFG (self));
|
||||||
|
|
||||||
|
return NMP_OBJECT_CAST_LINK (self->priv.pllink);
|
||||||
|
}
|
||||||
|
|
||||||
static inline NMNetns *
|
static inline NMNetns *
|
||||||
nm_l3cfg_get_netns (const NML3Cfg *self)
|
nm_l3cfg_get_netns (const NML3Cfg *self)
|
||||||
{
|
{
|
||||||
|
|
@ -198,4 +220,11 @@ void nm_l3cfg_commit_type_unregister (NML3Cfg *self,
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
const NML3ConfigData *nm_l3cfg_get_combined_l3cd (NML3Cfg *self);
|
||||||
|
|
||||||
|
const NMPObject *nm_l3cfg_get_best_default_route (NML3Cfg *self,
|
||||||
|
int addr_family);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
#endif /* __NM_L3CFG_H__ */
|
#endif /* __NM_L3CFG_H__ */
|
||||||
|
|
|
||||||
|
|
@ -3400,6 +3400,38 @@ nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr)
|
||||||
return &addr->peer_address;
|
return &addr->peer_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gboolean
|
||||||
|
nm_platform_ip6_address_match (const NMPlatformIP6Address *addr,
|
||||||
|
NMPlatformMatchFlags match_flag)
|
||||||
|
{
|
||||||
|
nm_assert (!NM_FLAGS_ANY (match_flag, ~( NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY
|
||||||
|
| NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY)));
|
||||||
|
nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE__ANY));
|
||||||
|
nm_assert (NM_FLAGS_ANY (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE__ANY));
|
||||||
|
|
||||||
|
if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) {
|
||||||
|
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_LINKLOCAL))
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRTYPE_NORMAL))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED)) {
|
||||||
|
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_DADFAILED))
|
||||||
|
return FALSE;
|
||||||
|
} else if ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TENTATIVE)
|
||||||
|
&& !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_OPTIMISTIC)) {
|
||||||
|
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_TENTATIVE))
|
||||||
|
return FALSE;
|
||||||
|
} else {
|
||||||
|
if (!NM_FLAGS_HAS (match_flag, NM_PLATFORM_MATCH_WITH_ADDRSTATE_NORMAL))
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
gboolean
|
gboolean
|
||||||
nm_platform_ip4_address_add (NMPlatform *self,
|
nm_platform_ip4_address_add (NMPlatform *self,
|
||||||
int ifindex,
|
int ifindex,
|
||||||
|
|
|
||||||
|
|
@ -1668,6 +1668,11 @@ struct _NMPLookup;
|
||||||
const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *self,
|
const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *self,
|
||||||
const struct _NMPLookup *lookup);
|
const struct _NMPLookup *lookup);
|
||||||
|
|
||||||
|
#define nm_platform_iter_obj_for_each(iter, self, lookup, obj) \
|
||||||
|
for (nm_dedup_multi_iter_init ((iter), nm_platform_lookup ((self), (lookup))); \
|
||||||
|
nm_platform_dedup_multi_iter_next_obj ((iter), (obj), NMP_OBJECT_TYPE_UNKNOWN); \
|
||||||
|
)
|
||||||
|
|
||||||
gboolean nm_platform_lookup_predicate_routes_main (const NMPObject *obj,
|
gboolean nm_platform_lookup_predicate_routes_main (const NMPObject *obj,
|
||||||
gpointer user_data);
|
gpointer user_data);
|
||||||
gboolean nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel (const NMPObject *obj,
|
gboolean nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel (const NMPObject *obj,
|
||||||
|
|
@ -2158,4 +2163,9 @@ void nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self,
|
||||||
|
|
||||||
struct _NMDedupMultiIndex *nm_platform_get_multi_idx (NMPlatform *self);
|
struct _NMDedupMultiIndex *nm_platform_get_multi_idx (NMPlatform *self);
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
gboolean nm_platform_ip6_address_match (const NMPlatformIP6Address *addr,
|
||||||
|
NMPlatformMatchFlags match_flag);
|
||||||
|
|
||||||
#endif /* __NETWORKMANAGER_PLATFORM_H__ */
|
#endif /* __NETWORKMANAGER_PLATFORM_H__ */
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue