l3cfg: merge branch 'th/l3cfg-8'

https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/623
This commit is contained in:
Thomas Haller 2020-09-11 16:21:57 +02:00
commit ebd07a809c
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
21 changed files with 1916 additions and 1300 deletions

View file

@ -3294,33 +3294,253 @@ nm_utils_hash_values_to_array (GHashTable *hash,
return arr;
}
gboolean
nm_utils_hashtable_same_keys (const GHashTable *a,
const GHashTable *b)
static gboolean
_utils_hashtable_equal (GHashTable *hash_a,
GHashTable *hash_b,
GCompareDataFunc cmp_values,
gpointer user_data)
{
GHashTableIter h;
const char *k;
gpointer a_key;
gpointer a_val;
gpointer b_val;
if (a == b)
return TRUE;
if (!a || !b)
return FALSE;
if (g_hash_table_size ((GHashTable *) a) != g_hash_table_size ((GHashTable *) b))
return FALSE;
nm_assert (hash_a);
nm_assert (hash_b);
nm_assert (hash_a != hash_b);
nm_assert (g_hash_table_size (hash_a) == g_hash_table_size (hash_b));
g_hash_table_iter_init (&h, (GHashTable *) a);
while (g_hash_table_iter_next (&h, (gpointer) &k, NULL)) {
if (!g_hash_table_contains ((GHashTable *) b, k))
/* We rely on both hashes to have the same hash/equal function. Otherwise, we would have to iterate
* both hashes and check whether all keys/values are present in the respective other hash (which
* 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 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
g_hash_table_iter_init (&h, (GHashTable *) b);
while (g_hash_table_iter_next (&h, (gpointer) &k, NULL))
nm_assert (g_hash_table_contains ((GHashTable *) a, k));
nm_assert (same == _utils_hashtable_equal (hash_b, hash_a, cmp_values, user_data));
#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 **

View file

@ -1521,8 +1521,24 @@ nm_utils_strdict_get_keys (const GHashTable *hash,
out_length);
}
gboolean nm_utils_hashtable_same_keys (const GHashTable *a,
const GHashTable *b);
gboolean nm_utils_hashtable_equal (const GHashTable *a,
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);
@ -1564,14 +1580,14 @@ nm_g_array_len (const GArray *arr)
#define nm_g_array_append_new(arr, type) \
({ \
GArray *_arr = (arr); \
gsize _l; \
GArray *const _arr = (arr); \
guint _len; \
\
nm_assert (_arr); \
_l = ((gsize) _arr->len) + 1u; \
nm_assert (_l > _arr->len); \
g_array_set_size (_arr, _l); \
&g_array_index (arr, type, _l); \
_len = _arr->len; \
nm_assert (_len < G_MAXUINT); \
g_array_set_size (_arr, _len + 1u); \
&g_array_index (arr, type, _len); \
})
/*****************************************************************************/

View file

@ -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 ();
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_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_utils_hashtable_cmp", test_utils_hashtable_cmp);
return g_test_run ();
}

View file

@ -159,4 +159,65 @@ void nm_utils_ip_routes_to_dbus (int addr_family,
GVariant **out_route_data,
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__ */

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@
#include "nm-rfkill-manager.h"
#include "NetworkManagerUtils.h"
typedef enum {
typedef enum _nm_packed {
NM_DEVICE_SYS_IFACE_STATE_EXTERNAL,
NM_DEVICE_SYS_IFACE_STATE_ASSUME,
NM_DEVICE_SYS_IFACE_STATE_MANAGED,

View file

@ -480,15 +480,8 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
}
}
if ( priv->addr_family == AF_INET6
&& NM_IN_SET (new_state, NM_DHCP_STATE_BOUND, NM_DHCP_STATE_EXTENDED)) {
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);
}
if (priv->addr_family == AF_INET6)
event_id = nm_dhcp_utils_get_dhcp6_event_id (options);
_LOGI ("state changed %s -> %s%s%s%s",
state_to_string (priv->state),
@ -500,8 +493,7 @@ nm_dhcp_client_set_state (NMDhcpClient *self,
signals[SIGNAL_STATE_CHANGED], 0,
new_state,
ip_config,
options,
event_id);
options);
}
static gboolean
@ -1319,7 +1311,11 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
G_SIGNAL_RUN_FIRST,
0,
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] =
g_signal_new (NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED,

View file

@ -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 */
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;
}
static void client_state_changed (NMDhcpClient *client,
NMDhcpState state,
GObject *ip_config,
GVariant *options,
const char *event_id,
NMDhcpManager *self);
static void
remove_client (NMDhcpManager *self, NMDhcpClient *client)
{
@ -192,7 +193,6 @@ client_state_changed (NMDhcpClient *client,
NMDhcpState state,
GObject *ip_config,
GVariant *options,
const char *event_id,
NMDhcpManager *self)
{
if (state >= NM_DHCP_STATE_TIMEOUT)

View file

@ -219,9 +219,9 @@ nm_dhcp_option_request_string (const NMDhcpOption *requests, guint option)
void
nm_dhcp_option_take_option (GHashTable *options,
const NMDhcpOption *requests,
guint option,
char *value)
const NMDhcpOption *requests,
guint option,
char *value)
{
nm_assert (options);
nm_assert (requests);

View file

@ -786,3 +786,23 @@ nm_dhcp_utils_get_leasefile_path (int addr_family,
*out_leasefile_path = g_steal_pointer (&statedir_path);
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);
}

View file

@ -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_utils_get_dhcp6_event_id (GHashTable *lease);
#endif /* __NETWORKMANAGER_DHCP_UTILS_H__ */

View file

@ -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:
* @unused: unused

View file

@ -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_setpgid (gpointer unused);

View file

@ -95,7 +95,6 @@ dhcp4_state_changed (NMDhcpClient *client,
NMDhcpState state,
NMIP4Config *ip4_config,
GHashTable *options,
const char *event_id,
gpointer user_data)
{
static NMIP4Config *last_config = NULL;

View file

@ -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_ip_config_iter_ip6_address_for_each (&iter, self, &addr) {
if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) {
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;
if (nm_platform_ip6_address_match (addr, match_flag))
return addr;
}
return NULL;
}

View file

@ -52,6 +52,14 @@ struct _NML3ConfigData {
char *nis_domain;
union {
struct {
NMDhcpLease *dhcp_lease_6;
NMDhcpLease *dhcp_lease_4;
};
NMDhcpLease *dhcp_lease_x[2];
};
union {
struct {
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->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_6, g_array_unref);
@ -572,6 +583,8 @@ nm_l3_config_data_lookup_index (const NML3ConfigData *self, NMPObjectType obj_ty
const NMDedupMultiHeadEntry *
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,
nm_l3_config_data_lookup_index (self, obj_type),
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
_dedup_multi_index_cmp (const NML3ConfigData *a,
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 (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->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]));
@ -2177,6 +2254,7 @@ nm_l3_config_data_merge (NML3ConfigData *self,
self->mtu = src->mtu;
/* self->source does not get merged. */
/* self->dhcp_lease_x does not get merged. */
}
NML3ConfigData *

View file

@ -486,6 +486,17 @@ gboolean nm_l3_config_data_set_dns_priority (NML3ConfigData *self,
int addr_family,
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 *
nmtst_l3_config_data_get_best_gateway (const NML3ConfigData *self,
int addr_family)

View file

@ -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
set_property (GObject *object,
guint prop_id,

View file

@ -87,6 +87,28 @@ nm_l3cfg_get_ifname (const NML3Cfg *self)
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 *
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__ */

View file

@ -3400,6 +3400,38 @@ nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr)
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
nm_platform_ip4_address_add (NMPlatform *self,
int ifindex,

View file

@ -1668,6 +1668,11 @@ struct _NMPLookup;
const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *self,
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,
gpointer user_data);
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);
/*****************************************************************************/
gboolean nm_platform_ip6_address_match (const NMPlatformIP6Address *addr,
NMPlatformMatchFlags match_flag);
#endif /* __NETWORKMANAGER_PLATFORM_H__ */