all: merge branch 'th/dedup-multi-bgo784220'

Refactor platform cache to track objects via a doubly linked
list, with each element indexed via a hash table.

This preserves the order of the objects, which will be needed
for improving the route cache.

Also, the NMPObjects are now immuable, ref-counted and can be
shared. This will allow other parts to reuse the same objects.

NMPIP4Config and NMPIP6Config now uses the same data structure
for tracking their routes. This changes the O(n^2) runtime for
intersect, merge and subtract to O(n).

https://bugzilla.gnome.org/show_bug.cgi?id=784220
This commit is contained in:
Thomas Haller 2017-07-07 10:21:58 +02:00
commit 22cd73d3aa
67 changed files with 6718 additions and 4514 deletions

View file

@ -415,6 +415,7 @@ libnm_core_lib_h_pub_real = \
libnm_core_lib_h_pub_mkenums = \
libnm-core/nm-core-enum-types.h
libnm_core_lib_h_priv = \
shared/nm-utils/nm-dedup-multi.h \
shared/nm-utils/nm-enum-utils.h \
shared/nm-utils/nm-shared-utils.h \
shared/nm-utils/nm-udev-utils.h \
@ -429,6 +430,7 @@ libnm_core_lib_h_priv = \
libnm-core/nm-setting-private.h \
libnm-core/nm-utils-private.h
libnm_core_lib_c_real = \
shared/nm-utils/nm-dedup-multi.c \
shared/nm-utils/nm-enum-utils.c \
shared/nm-utils/nm-shared-utils.c \
shared/nm-utils/nm-udev-utils.c \
@ -1271,13 +1273,12 @@ $(src_libsystemd_nm_la_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
src_libNetworkManagerBase_la_CPPFLAGS = $(src_cppflags)
src_libNetworkManagerBase_la_SOURCES = \
\
src/nm-core-utils.c \
src/nm-core-utils.h \
src/nm-logging.c \
src/nm-logging.h \
\
src/nm-multi-index.c \
src/nm-multi-index.h \
src/NetworkManagerUtils.c \
src/NetworkManagerUtils.h \
\
@ -1289,6 +1290,7 @@ src_libNetworkManagerBase_la_SOURCES = \
src/platform/nm-platform-utils.h \
src/platform/nm-platform.c \
src/platform/nm-platform.h \
src/platform/nm-platform-private.h \
src/platform/nm-linux-platform.c \
src/platform/nm-linux-platform.h \
src/platform/wifi/wifi-utils-nl80211.c \
@ -4444,6 +4446,7 @@ EXTRA_DIST += \
shared/nm-utils/c-list.h \
shared/nm-utils/gsystem-local-alloc.h \
shared/nm-utils/nm-glib.h \
shared/nm-utils/nm-obj.h \
shared/nm-utils/nm-macros-internal.h \
shared/nm-utils/nm-shared-utils.c \
shared/nm-utils/nm-shared-utils.h \

View file

@ -129,7 +129,10 @@ typedef enum {
} G_STMT_END
struct _NmcMetaGenericInfo {
const NMMetaType *meta_type;
union {
NMObjBaseInst parent;
const NMMetaType *meta_type;
};
NmcGenericInfoType info_type;
const char *name;
const char *name_header;

View file

@ -20,6 +20,7 @@
#ifndef __NM_META_SETTING_DESC_H__
#define __NM_META_SETTING_DESC_H__
#include "nm-utils/nm-obj.h"
#include "nm-meta-setting.h"
struct _NMDevice;
@ -284,7 +285,10 @@ enum {
#define nm_meta_property_info_vpn_service_type (nm_meta_setting_infos_editor[NM_META_SETTING_TYPE_VPN].properties[_NM_META_PROPERTY_TYPE_VPN_SERVICE_TYPE])
struct _NMMetaPropertyInfo {
const NMMetaType *meta_type;
union {
NMObjBaseInst parent;
const NMMetaType *meta_type;
};
const NMMetaSettingInfoEditor *setting_info;
@ -316,7 +320,10 @@ typedef struct _NMMetaSettingValidPartItem {
} NMMetaSettingValidPartItem;
struct _NMMetaSettingInfoEditor {
const NMMetaType *meta_type;
union {
NMObjBaseInst parent;
const NMMetaType *meta_type;
};
const NMMetaSettingInfo *general;
const char *alias;
const char *pretty_name;
@ -341,6 +348,7 @@ struct _NMMetaSettingInfoEditor {
};
struct _NMMetaType {
NMObjBaseClass parent;
const char *type_name;
const char *(*get_name) (const NMMetaAbstractInfo *abstract_info,
gboolean for_header);
@ -364,7 +372,10 @@ struct _NMMetaType {
};
struct _NMMetaAbstractInfo {
const NMMetaType *meta_type;
union {
NMObjBaseInst parent;
const NMMetaType *meta_type;
};
};
extern const NMMetaType nm_meta_type_setting_info_editor;

View file

@ -4016,16 +4016,16 @@ _nm_utils_strstrdictkey_hash (gconstpointer a)
if (((int) k->type) & ~STRSTRDICTKEY_ALL_SET)
g_return_val_if_reached (0);
h = (h << 5) + h + k->type;
h = NM_HASH_COMBINE (h, k->type);
if (k->type & STRSTRDICTKEY_ALL_SET) {
p = (void *) k->data;
for (; *p != '\0'; p++)
h = (h << 5) + h + *p;
h = NM_HASH_COMBINE (h, *p);
if (k->type == STRSTRDICTKEY_ALL_SET) {
/* the key contains two strings. Continue... */
h = (h << 5) + h + '\0';
h = NM_HASH_COMBINE (h, '\0');
for (p++; *p != '\0'; p++)
h = (h << 5) + h + *p;
h = NM_HASH_COMBINE (h, *p);
}
}
}

View file

@ -60,6 +60,7 @@
#include "nm-setting-wireless-security.h"
#include "nm-simple-connection.h"
#include "nm-keyfile-internal.h"
#include "nm-utils/nm-dedup-multi.h"
#include "test-general-enums.h"
@ -75,6 +76,302 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int));
/*****************************************************************************/
typedef struct {
NMDedupMultiObj parent;
guint val;
guint other;
} DedupObj;
static const NMDedupMultiObjClass dedup_obj_class;
static DedupObj *
_dedup_obj_assert (const NMDedupMultiObj *obj)
{
DedupObj *o;
g_assert (obj);
o = (DedupObj *) obj;
g_assert (o->parent.klass == &dedup_obj_class);
g_assert (o->parent._ref_count > 0);
g_assert (o->val > 0);
return o;
}
static const NMDedupMultiObj *
_dedup_obj_clone (const NMDedupMultiObj *obj)
{
DedupObj *o, *o2;
o = _dedup_obj_assert (obj);
o2 = g_slice_new0 (DedupObj);
o2->parent.klass = &dedup_obj_class;
o2->parent._ref_count = 1;
o2->val = o->val;
o2->other = o->other;
return (NMDedupMultiObj *) o2;
}
static void
_dedup_obj_destroy (NMDedupMultiObj *obj)
{
DedupObj *o = (DedupObj *) obj;
nm_assert (o->parent._ref_count == 0);
o->parent._ref_count = 1;
o = _dedup_obj_assert (obj);
g_slice_free (DedupObj, o);
}
static guint
_dedup_obj_full_hash (const NMDedupMultiObj *obj)
{
const DedupObj *o;
o = _dedup_obj_assert (obj);
return (o->val * 33) + o->other;
}
static gboolean
_dedup_obj_full_equal (const NMDedupMultiObj *obj_a,
const NMDedupMultiObj *obj_b)
{
const DedupObj *o_a = _dedup_obj_assert (obj_a);
const DedupObj *o_b = _dedup_obj_assert (obj_b);
return o_a->val == o_b->val
&& o_a->other == o_b->other;
}
static const NMDedupMultiObjClass dedup_obj_class = {
.obj_clone = _dedup_obj_clone,
.obj_destroy = _dedup_obj_destroy,
.obj_full_equality_allows_different_class = FALSE,
.obj_full_hash = _dedup_obj_full_hash,
.obj_full_equal = _dedup_obj_full_equal,
};
#define DEDUP_OBJ_INIT(val_val, other_other) \
(&((DedupObj) { \
.parent = { \
.klass = &dedup_obj_class, \
._ref_count = NM_OBJ_REF_COUNT_STACKINIT, \
}, \
.val = (val_val), \
.other = (other_other), \
}))
typedef struct {
NMDedupMultiIdxType parent;
guint partition_size;
guint val_mod;
} DedupIdxType;
static const NMDedupMultiIdxTypeClass dedup_idx_type_class;
static const DedupIdxType *
_dedup_idx_assert (const NMDedupMultiIdxType *idx_type)
{
DedupIdxType *t;
g_assert (idx_type);
t = (DedupIdxType *) idx_type;
g_assert (t->parent.klass == &dedup_idx_type_class);
g_assert (t->partition_size > 0);
g_assert (t->val_mod > 0);
return t;
}
static guint
_dedup_idx_obj_id_hash (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj)
{
const DedupIdxType *t;
const DedupObj *o;
guint h;
t = _dedup_idx_assert (idx_type);
o = _dedup_obj_assert (obj);
h = o->val / t->partition_size;
h = (h * 33) + (o->val % t->val_mod);
return h;
}
static gboolean
_dedup_idx_obj_id_equal (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj_a,
const NMDedupMultiObj *obj_b)
{
const DedupIdxType *t;
const DedupObj *o_a;
const DedupObj *o_b;
t = _dedup_idx_assert (idx_type);
o_a = _dedup_obj_assert (obj_a);
o_b = _dedup_obj_assert (obj_b);
return (o_a->val / t->partition_size) == (o_b->val / t->partition_size)
&& (o_a->val % t->val_mod) == (o_b->val % t->val_mod);
}
static guint
_dedup_idx_obj_partition_hash (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj)
{
const DedupIdxType *t;
const DedupObj *o;
t = _dedup_idx_assert (idx_type);
o = _dedup_obj_assert (obj);
return o->val / t->partition_size;
}
static gboolean
_dedup_idx_obj_partition_equal (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj_a,
const NMDedupMultiObj *obj_b)
{
const DedupIdxType *t;
const DedupObj *o_a;
const DedupObj *o_b;
t = _dedup_idx_assert (idx_type);
o_a = _dedup_obj_assert (obj_a);
o_b = _dedup_obj_assert (obj_b);
return (o_a->val / t->partition_size) == (o_b->val / t->partition_size);
}
static const NMDedupMultiIdxTypeClass dedup_idx_type_class = {
.idx_obj_id_hash = _dedup_idx_obj_id_hash,
.idx_obj_id_equal = _dedup_idx_obj_id_equal,
.idx_obj_partition_hash = _dedup_idx_obj_partition_hash,
.idx_obj_partition_equal = _dedup_idx_obj_partition_equal,
};
static const DedupIdxType *
DEDUP_IDX_TYPE_INIT (DedupIdxType *idx_type, guint partition_size, guint val_mod)
{
nm_dedup_multi_idx_type_init ((NMDedupMultiIdxType *) idx_type, &dedup_idx_type_class);
idx_type->val_mod = val_mod;
idx_type->partition_size = partition_size;
return idx_type;
}
static gboolean
_dedup_idx_add (NMDedupMultiIndex *idx, const DedupIdxType *idx_type, const DedupObj *obj, NMDedupMultiIdxMode mode, const NMDedupMultiEntry **out_entry)
{
g_assert (idx);
_dedup_idx_assert ((NMDedupMultiIdxType *) idx_type);
if (obj)
_dedup_obj_assert ((NMDedupMultiObj *) obj);
return nm_dedup_multi_index_add (idx, (NMDedupMultiIdxType *) idx_type,
obj, mode, out_entry, NULL);
}
static void
_dedup_head_entry_assert (const NMDedupMultiHeadEntry *entry)
{
g_assert (entry);
g_assert (entry->len > 0);
g_assert (entry->len == c_list_length (&entry->lst_entries_head));
g_assert (entry->idx_type);
g_assert (entry->is_head);
}
static const DedupObj *
_dedup_entry_assert (const NMDedupMultiEntry *entry)
{
g_assert (entry);
g_assert (!c_list_is_empty (&entry->lst_entries));
g_assert (entry->head);
g_assert (!entry->is_head);
g_assert (entry->head != (gpointer) entry);
_dedup_head_entry_assert (entry->head);
return _dedup_obj_assert (entry->obj);
}
static const DedupIdxType *
_dedup_entry_get_idx_type (const NMDedupMultiEntry *entry)
{
_dedup_entry_assert (entry);
g_assert (entry->head);
g_assert (entry->head->idx_type);
return _dedup_idx_assert (entry->head->idx_type);
}
static void
_dedup_entry_assert_all (const NMDedupMultiEntry *entry, gssize expected_idx, const DedupObj *const*expected_obj)
{
gsize n, i;
CList *iter;
g_assert (entry);
_dedup_entry_assert (entry);
g_assert (expected_obj);
n = NM_PTRARRAY_LEN (expected_obj);
g_assert (n == c_list_length (&entry->lst_entries));
g_assert (expected_idx >= -1 && expected_idx < n);
g_assert (entry->head);
if (expected_idx == -1)
g_assert (entry->head == (gpointer) entry);
else
g_assert (entry->head != (gpointer) entry);
i = 0;
c_list_for_each (iter, &entry->head->lst_entries_head) {
const NMDedupMultiEntry *entry_current = c_list_entry (iter, NMDedupMultiEntry, lst_entries);
const DedupObj *obj_current;
const DedupIdxType *idx_type = _dedup_entry_get_idx_type (entry_current);
obj_current = _dedup_entry_assert (entry_current);
g_assert (obj_current);
g_assert (i < n);
if (expected_idx == i)
g_assert (entry_current == entry);
g_assert (idx_type->parent.klass->idx_obj_partition_equal (&idx_type->parent,
entry_current->obj,
c_list_entry (entry->head->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->obj));
i++;
}
}
#define _dedup_entry_assert_all(entry, expected_idx, ...) _dedup_entry_assert_all (entry, expected_idx, (const DedupObj *const[]) { __VA_ARGS__, NULL })
static void
test_dedup_multi (void)
{
NMDedupMultiIndex *idx;
DedupIdxType IDX_20_3_a_stack;
const DedupIdxType *const IDX_20_3_a = DEDUP_IDX_TYPE_INIT (&IDX_20_3_a_stack, 20, 3);
const NMDedupMultiEntry *entry1;
idx = nm_dedup_multi_index_new ();
g_assert (_dedup_idx_add (idx, IDX_20_3_a, DEDUP_OBJ_INIT (1, 1), NM_DEDUP_MULTI_IDX_MODE_APPEND, &entry1));
_dedup_entry_assert_all (entry1, 0, DEDUP_OBJ_INIT (1, 1));
g_assert (nm_dedup_multi_index_obj_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1)));
g_assert (!nm_dedup_multi_index_obj_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 2)));
g_assert (_dedup_idx_add (idx, IDX_20_3_a, DEDUP_OBJ_INIT (1, 2), NM_DEDUP_MULTI_IDX_MODE_APPEND, &entry1));
_dedup_entry_assert_all (entry1, 0, DEDUP_OBJ_INIT (1, 2));
g_assert (!nm_dedup_multi_index_obj_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1)));
g_assert (nm_dedup_multi_index_obj_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 2)));
g_assert (_dedup_idx_add (idx, IDX_20_3_a, DEDUP_OBJ_INIT (2, 2), NM_DEDUP_MULTI_IDX_MODE_APPEND, &entry1));
_dedup_entry_assert_all (entry1, 1, DEDUP_OBJ_INIT (1, 2), DEDUP_OBJ_INIT (2, 2));
nm_dedup_multi_index_unref (idx);
}
/*****************************************************************************/
static NMConnection *
_connection_new_from_dbus (GVariant *dict, GError **error)
{
@ -5782,7 +6079,7 @@ int main (int argc, char **argv)
{
nmtst_init (&argc, &argv, TRUE);
/* The tests */
g_test_add_func ("/core/general/test_dedup_multi", test_dedup_multi);
g_test_add_func ("/core/general/test_utils_str_utf8safe", test_utils_str_utf8safe);
g_test_add_func ("/core/general/test_nm_in_set", test_nm_in_set);
g_test_add_func ("/core/general/test_nm_in_strset", test_nm_in_strset);

View file

@ -74,7 +74,7 @@ static inline void c_list_init(CList *what) {
offsetof(_t, _m)) - offsetof(_t, _m)))
/**
* c_list_is_linked() - check whether a entry is linked
* c_list_is_linked() - check whether an entry is linked
* @what: entry to check, or NULL
*
* Return: True if @what is linked in a list, false if not.
@ -206,71 +206,22 @@ static inline void c_list_swap(CList *list1, CList *list2) {
* This removes all the entries from @source and splice them into @target.
* The order of the two lists is preserved and the source is appended
* to the end of target.
*
* On return, the source list will be empty.
*/
static inline void c_list_splice(CList *target, CList *source) {
if (c_list_is_empty(source))
return;
if (!c_list_is_empty(source)) {
/* attach the front of @source to the tail of @target */
source->next->prev = target->prev;
target->prev->next = source->next;
/* attach the front of @source to the tail of @target */
source->next->prev = target->prev;
target->prev->next = source->next;
/* attach the tail of @source to the front of @target */
source->prev->next = target;
target->prev = source->prev;
/* attach the tail of @source to the front of @target */
source->prev->next = target;
target->prev = source->prev;
}
/**
* c_list_loop_first() - return first list element, or head if empty
* @list: list to operate on
*
* This is an O(1) accessor to the first list element. If the list is empty,
* this returns a pointer to the list head. Hence, this never returns NULL.
*
* Return: Pointer to first list element, or pointer to head if empty.
*/
static inline CList *c_list_loop_first(CList *list) {
return list->next;
}
/**
* c_list_loop_last() - return last list element, or head if empty
* @list: list to operate on
*
* This is an O(1) accessor to the last list element. If the list is empty,
* this returns a pointer to the list head. Hence, this never returns NULL.
*
* Return: Pointer to last list element, or pointer to head if empty.
*/
static inline CList *c_list_loop_last(CList *list) {
return list->prev;
}
/**
* c_list_loop_next() - return next list element, or head if none
* @what: list entry to operate on
*
* This is an O(1) accessor to the next list element. If @what is the list tail
* this will return a pointer to the list head. Hence, this never returns NULL.
*
* Return: Pointer to next list element, or pointer to head if none.
*/
static inline CList *c_list_loop_next(CList *what) {
return what->next;
}
/**
* c_list_loop_prev() - return previous list element, or head if none
* @what: list entry to operate on
*
* This is an O(1) accessor to the previous list element. If @what is the list
* front this will return a pointer to the list head. Hence, this never returns
* NULL.
*
* Return: Pointer to previous list element, or pointer to head if none.
*/
static inline CList *c_list_loop_prev(CList *what) {
return what->prev;
/* clear source */
*source = (CList)C_LIST_INIT(*source);
}
}
/**
@ -281,10 +232,10 @@ static inline CList *c_list_loop_prev(CList *what) {
* This is a macro to use as for-loop to iterate an entire list. It is meant as
* convenience macro. Feel free to code your own loop iterator.
*/
#define c_list_for_each(_iter, _list) \
for (_iter = c_list_loop_first(_list); \
_iter != (_list); \
_iter = c_list_loop_next(_iter))
#define c_list_for_each(_iter, _list) \
for (_iter = (_list)->next; \
(_iter) != (_list); \
_iter = (_iter)->next)
/**
@ -302,10 +253,10 @@ static inline CList *c_list_loop_prev(CList *what) {
* havoc if you remove other list entries. You better not modify anything but
* the current list entry.
*/
#define c_list_for_each_safe(_iter, _safe, _list) \
for (_iter = c_list_loop_first(_list), _safe = c_list_loop_next(_iter); \
_iter != (_list); \
_iter = _safe, _safe = c_list_loop_next(_safe))
#define c_list_for_each_safe(_iter, _safe, _list) \
for (_iter = (_list)->next, _safe = (_iter)->next; \
(_iter) != (_list); \
_iter = (_safe), _safe = (_safe)->next)
/**
* c_list_for_each_entry() - loop over all list entries
@ -316,10 +267,10 @@ static inline CList *c_list_loop_prev(CList *what) {
* This combines c_list_for_each() with c_list_entry(), making it easy to
* iterate over a list of a specific type.
*/
#define c_list_for_each_entry(_iter, _list, _m) \
for (_iter = c_list_entry(c_list_loop_first(_list), __typeof__(*_iter), _m); \
&_iter->_m != (_list); \
_iter = c_list_entry(c_list_loop_next(&_iter->_m), __typeof__(*_iter), _m))
#define c_list_for_each_entry(_iter, _list, _m) \
for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m); \
&(_iter)->_m != (_list); \
_iter = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m))
/**
* c_list_for_each_entry_safe() - loop over all list entries, safe for removal
@ -331,12 +282,12 @@ static inline CList *c_list_loop_prev(CList *what) {
* This combines c_list_for_each_safe() with c_list_entry(), making it easy to
* iterate over a list of a specific type.
*/
#define c_list_for_each_entry_safe(_iter, _safe, _list, _m) \
for (_iter = c_list_entry(c_list_loop_first(_list), __typeof__(*_iter), _m), \
_safe = c_list_entry(c_list_loop_next(&_iter->_m), __typeof__(*_iter), _m);\
&_iter->_m != (_list); \
_iter = _safe, \
_safe = c_list_entry(c_list_loop_next(&_safe->_m), __typeof__(*_iter), _m))
#define c_list_for_each_entry_safe(_iter, _safe, _list, _m) \
for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m), \
_safe = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m); \
&(_iter)->_m != (_list); \
_iter = (_safe), \
_safe = c_list_entry((_safe)->_m.next, __typeof__(*_iter), _m)) \
/**
* c_list_first() - return pointer to first element, or NULL if empty
@ -391,44 +342,54 @@ static inline CList *c_list_last(CList *list) {
c_list_entry(c_list_last(_list), _t, _m)
/**
* c_list_length() - return the number of linked entries, excluding the head
* c_list_length() - return number of linked entries, excluding the head
* @list: list to operate on
*
* Returns the number of entires in the list, excluding the list head
* @list. That is, for a list that is empty according to c_list_is_empty(),
* the returned length is 0. This requires to iterate the list and has
* thus O(n) runtime.
* Returns the number of entries in the list, excluding the list head @list.
* That is, for a list that is empty according to c_list_is_empty(), the
* returned length is 0. This requires to iterate the list and has thus O(n)
* runtime.
*
* Return: the number of items in the list
* Note that this function is meant for debugging purposes only. If you need
* the list size during normal operation, you should maintain a counter
* separately.
*
* Return: Number of items in @list.
*/
static inline size_t c_list_length(const CList *list) {
CList *iter;
size_t n = 0;
static inline unsigned long c_list_length(const CList *list) {
unsigned long n = 0;
const CList *iter;
c_list_for_each(iter, list)
++n;
c_list_for_each(iter, (CList *)list)
n++;
return n;
}
/**
* c_list_contains() - whether an item is linked in a certain list
* c_list_contains() - check whether an entry is linked in a certain list
* @list: list to operate on
* @what: the list entry to find
* @what: entry to look for
*
* Searches @list whether @what is a linked entry of the list
* in O(n). For the head @list, this also returns True.
* This checks whether @what is linked into @list. This requires a linear
* search through the list, as such runs in O(n). Note that the list-head is
* considered part of the list, and hence this returns true if @what equals
* @list.
*
* Return: True if @what is in @list
* Note that this function is meant for debugging purposes, and consistency
* checks. You should always be aware whether your objects are linked in a
* specific list.
*
* Return: True if @what is in @list, false otherwise.
*/
static inline _Bool c_list_contains(const CList *list, const CList *what) {
const CList *iter = list;
const CList *iter;
do {
if (iter == what)
c_list_for_each(iter, list)
if (what == iter)
return 1;
iter = iter->next;
} while (iter != list);
return 0;
return what == list;
}
#ifdef __cplusplus

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,379 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* (C) Copyright 2017 Red Hat, Inc.
*/
#ifndef __NM_DEDUP_MULTI_H__
#define __NM_DEDUP_MULTI_H__
#include "nm-obj.h"
#include "c-list.h"
/*****************************************************************************/
typedef struct _NMDedupMultiObj NMDedupMultiObj;
typedef struct _NMDedupMultiObjClass NMDedupMultiObjClass;
typedef struct _NMDedupMultiIdxType NMDedupMultiIdxType;
typedef struct _NMDedupMultiIdxTypeClass NMDedupMultiIdxTypeClass;
typedef struct _NMDedupMultiEntry NMDedupMultiEntry;
typedef struct _NMDedupMultiHeadEntry NMDedupMultiHeadEntry;
typedef struct _NMDedupMultiIndex NMDedupMultiIndex;
typedef enum _NMDedupMultiIdxMode {
NM_DEDUP_MULTI_IDX_MODE_PREPEND,
NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
/* append new objects to the end of the list.
* If the object is already in the cache, don't move it. */
NM_DEDUP_MULTI_IDX_MODE_APPEND,
/* like NM_DEDUP_MULTI_IDX_MODE_APPEND, but if the object
* is already in teh cache, move it to the end. */
NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE,
} NMDedupMultiIdxMode;
/*****************************************************************************/
struct _NMDedupMultiObj {
union {
NMObjBaseInst parent;
const NMDedupMultiObjClass *klass;
};
NMDedupMultiIndex *_multi_idx;
guint _ref_count;
};
struct _NMDedupMultiObjClass {
NMObjBaseClass parent;
const NMDedupMultiObj *(*obj_clone) (const NMDedupMultiObj *obj);
gboolean (*obj_needs_clone) (const NMDedupMultiObj *obj);
void (*obj_destroy) (NMDedupMultiObj *obj);
gboolean obj_full_equality_allows_different_class;
/* the NMDedupMultiObj can be deduplicated. For that the obj_full_hash()
* and obj_full_equal() compare *all* fields of the object, even minor ones. */
guint (*obj_full_hash) (const NMDedupMultiObj *obj);
gboolean (*obj_full_equal) (const NMDedupMultiObj *obj_a,
const NMDedupMultiObj *obj_b);
};
/*****************************************************************************/
const NMDedupMultiObj *nm_dedup_multi_obj_ref (const NMDedupMultiObj *obj);
const NMDedupMultiObj *nm_dedup_multi_obj_unref (const NMDedupMultiObj *obj);
const NMDedupMultiObj *nm_dedup_multi_obj_clone (const NMDedupMultiObj *obj);
gboolean nm_dedup_multi_obj_needs_clone (const NMDedupMultiObj *obj);
gconstpointer nm_dedup_multi_index_obj_intern (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj);
void nm_dedup_multi_index_obj_release (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj);
/* const NMDedupMultiObj * */ gconstpointer nm_dedup_multi_index_obj_find (NMDedupMultiIndex *self,
/* const NMDedupMultiObj * */ gconstpointer obj);
/*****************************************************************************/
/* the NMDedupMultiIdxType is an access handle under which you can store and
* retrieve NMDedupMultiObj instances in NMDedupMultiIndex.
*
* The NMDedupMultiIdxTypeClass determines it's behavior, but you can have
* multiple instances (of the same class).
*
* For example, NMIP4Config can have idx-type to put there all IPv4 Routes.
* This idx-type instance is private to the NMIP4Config instance. Basically,
* the NMIP4Config instance uses the idx-type to maintain an ordered list
* of routes in NMDedupMultiIndex.
*
* However, a NMDedupMultiIdxType may also partition the set of objects
* in multiple distinct lists. NMIP4Config doesn't do that (because instead
* of creating one idx-type for IPv4 and IPv6 routes, it just cretaes
* to distinct idx-types, one for each address family.
* This partitioning is used by NMPlatform to maintain a lookup index for
* routes by ifindex. As the ifindex is dynamic, it does not create an
* idx-type instance for each ifindex. Instead, it has one idx-type for
* all routes. But whenever accessing NMDedupMultiIndex with an NMDedupMultiObj,
* the partitioning NMDedupMultiIdxType takes into accound the NMDedupMultiObj
* instance to associate it with the right list.
*
* Hence, a NMDedupMultiIdxEntry has a list of possibly multiple NMDedupMultiHeadEntry
* instances, which each is the head for a list of NMDedupMultiEntry instances.
* In the platform example, the NMDedupMultiHeadEntry parition the indexed objects
* by their ifindex. */
struct _NMDedupMultiIdxType {
union {
NMObjBaseInst parent;
const NMDedupMultiIdxTypeClass *klass;
};
CList lst_idx_head;
guint len;
};
void nm_dedup_multi_idx_type_init (NMDedupMultiIdxType *idx_type,
const NMDedupMultiIdxTypeClass *klass);
struct _NMDedupMultiIdxTypeClass {
NMObjBaseClass parent;
guint (*idx_obj_id_hash) (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj);
gboolean (*idx_obj_id_equal) (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj_a,
const NMDedupMultiObj *obj_b);
/* an NMDedupMultiIdxTypeClass which implements partitioning of the
* tracked objects, must implement the idx_obj_partition*() functions.
*
* idx_obj_partitionable() may return NULL if the object cannot be tracked.
* For example, a index for routes by ifindex, may not want to track any
* routes that don't have a valid ifindex. If the idx-type says that the
* object is not partitionable, it is never added to the NMDedupMultiIndex. */
gboolean (*idx_obj_partitionable) (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj);
guint (*idx_obj_partition_hash) (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj);
gboolean (*idx_obj_partition_equal) (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj_a,
const NMDedupMultiObj *obj_b);
};
static inline gboolean
nm_dedup_multi_idx_type_id_equal (const NMDedupMultiIdxType *idx_type,
/* const NMDedupMultiObj * */ gconstpointer obj_a,
/* const NMDedupMultiObj * */ gconstpointer obj_b)
{
nm_assert (idx_type);
return idx_type->klass->idx_obj_id_equal (idx_type,
obj_a,
obj_b);
}
static inline gboolean
nm_dedup_multi_idx_type_partition_equal (const NMDedupMultiIdxType *idx_type,
/* const NMDedupMultiObj * */ gconstpointer obj_a,
/* const NMDedupMultiObj * */ gconstpointer obj_b)
{
nm_assert (idx_type);
if (idx_type->klass->idx_obj_partition_equal) {
nm_assert (obj_a);
nm_assert (obj_b);
return idx_type->klass->idx_obj_partition_equal (idx_type,
obj_a,
obj_b);
}
return TRUE;
}
/*****************************************************************************/
struct _NMDedupMultiEntry {
/* this is the list of all entries that share the same head entry.
* All entries compare equal according to idx_obj_partition_equal(). */
CList lst_entries;
/* const NMDedupMultiObj * */ gconstpointer obj;
bool is_head;
bool dirty;
const NMDedupMultiHeadEntry *head;
};
struct _NMDedupMultiHeadEntry {
/* this is the list of all entries that share the same head entry.
* All entries compare equal according to idx_obj_partition_equal(). */
CList lst_entries_head;
const NMDedupMultiIdxType *idx_type;
bool is_head;
guint len;
CList lst_idx;
};
static inline void
nm_dedup_multi_entry_set_dirty (const NMDedupMultiEntry *entry,
gboolean dirty)
{
/* NMDedupMultiEntry is always exposed as a const object, because it is not
* supposed to be modified outside NMDedupMultiIndex API. Except the "dirty"
* flag. In C++ speak, it is a mutable field.
*
* Add this inline function, to case-away constness and set the dirty flag. */
nm_assert (entry);
((NMDedupMultiEntry *) entry)->dirty = dirty;
}
/*****************************************************************************/
NMDedupMultiIndex *nm_dedup_multi_index_new (void);
NMDedupMultiIndex *nm_dedup_multi_index_ref (NMDedupMultiIndex *self);
NMDedupMultiIndex *nm_dedup_multi_index_unref (NMDedupMultiIndex *self);
static inline void
_nm_auto_unref_dedup_multi_index (NMDedupMultiIndex **v)
{
if (*v)
nm_dedup_multi_index_unref (*v);
}
#define nm_auto_unref_dedup_multi_index nm_auto(_nm_auto_unref_dedup_multi_index)
#define NM_DEDUP_MULTI_ENTRY_MISSING ((const NMDedupMultiEntry *) GUINT_TO_POINTER (1))
#define NM_DEDUP_MULTI_HEAD_ENTRY_MISSING ((const NMDedupMultiHeadEntry *) GUINT_TO_POINTER (1))
gboolean nm_dedup_multi_index_add_full (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj,
NMDedupMultiIdxMode mode,
const NMDedupMultiEntry *entry_order,
const NMDedupMultiEntry *entry_existing,
const NMDedupMultiHeadEntry *head_existing,
const NMDedupMultiEntry **out_entry,
/* const NMDedupMultiObj ** */ gpointer out_obj_old);
gboolean nm_dedup_multi_index_add (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj,
NMDedupMultiIdxMode mode,
const NMDedupMultiEntry **out_entry,
/* const NMDedupMultiObj ** */ gpointer out_obj_old);
const NMDedupMultiEntry *nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
const NMDedupMultiHeadEntry *nm_dedup_multi_index_lookup_head (NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
guint nm_dedup_multi_index_remove_entry (NMDedupMultiIndex *self,
gconstpointer entry);
guint nm_dedup_multi_index_remove_obj (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
guint nm_dedup_multi_index_remove_head (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
guint nm_dedup_multi_index_remove_idx (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type);
void nm_dedup_multi_index_dirty_set_head (NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
void nm_dedup_multi_index_dirty_set_idx (NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type);
guint nm_dedup_multi_index_dirty_remove_idx (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,
gboolean mark_survivors_dirty);
/*****************************************************************************/
typedef struct _NMDedupMultiIter {
const NMDedupMultiHeadEntry *head;
const NMDedupMultiEntry *current;
const NMDedupMultiEntry *next;
} NMDedupMultiIter;
static inline void
nm_dedup_multi_iter_init (NMDedupMultiIter *iter, const NMDedupMultiHeadEntry *head)
{
g_return_if_fail (iter);
iter->head = head;
iter->current = NULL;
iter->next = head && !c_list_is_empty (&head->lst_entries_head)
? c_list_entry (head->lst_entries_head.next, NMDedupMultiEntry, lst_entries)
: NULL;
}
static inline gboolean
nm_dedup_multi_iter_next (NMDedupMultiIter *iter)
{
g_return_val_if_fail (iter, FALSE);
if (!iter->next)
return FALSE;
/* we always look ahead for the @next. This way, the user
* may delete the current entry (but no other entries). */
iter->current = iter->next;
if (iter->next->lst_entries.next == &iter->head->lst_entries_head)
iter->next = NULL;
else
iter->next = c_list_entry (iter->next->lst_entries.next, NMDedupMultiEntry, lst_entries);
return TRUE;
}
static inline void
nm_dedup_multi_iter_rewind (NMDedupMultiIter *iter)
{
/* rewind the iterator.
*
* In principle, you can always delete the current entry.
* However, if you delete *all* current entries, the list
* head becomes invalid too and rewinding will crash.
*
* So, either
* - don't modify the list
* - if you modify it:
* - only delete the current entry, don't delete other entries.
* - you may add more entries, however that may make iteration
* confusing.
* - you may rewind the iterator, but only if not all
* entires were deleted.
*
* Use with care. */
g_return_if_fail (iter);
nm_dedup_multi_iter_init (iter, iter->head);
}
#define nm_dedup_multi_iter_for_each(iter, head_entry) \
for (nm_dedup_multi_iter_init ((iter), (head_entry)); \
nm_dedup_multi_iter_next ((iter)); \
)
/*****************************************************************************/
typedef gboolean (*NMDedupMultiFcnSelectPredicate) (/* const NMDedupMultiObj * */ gconstpointer obj,
gpointer user_data);
GPtrArray *nm_dedup_multi_objs_to_ptr_array_head (const NMDedupMultiHeadEntry *head_entry,
NMDedupMultiFcnSelectPredicate predicate,
gpointer user_data);
/*****************************************************************************/
#endif /* __NM_DEDUP_MULTI_H__ */

View file

@ -242,6 +242,35 @@ NM_G_ERROR_MSG (GError *error)
/*****************************************************************************/
#if (defined (__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 9 ))) || (defined (__clang__))
#define _NM_CC_SUPPORT_GENERIC 1
#else
#define _NM_CC_SUPPORT_GENERIC 0
#endif
#if _NM_CC_SUPPORT_GENERIC
#define _NM_CONSTCAST(type, obj) \
(_Generic ((obj), \
void * : ((type *) (obj)), \
void *const : ((type *) (obj)), \
const void * : ((const type *) (obj)), \
const void *const: ((const type *) (obj)), \
const type * : (obj), \
const type *const: (obj), \
type * : (obj), \
type *const : (obj)))
#else
/* _NM_CONSTCAST() is there to preserve constness of a pointer.
* It uses C11's _Generic(). If that is not supported, we fall back
* to casting away constness. So, with _Generic, we get some additional
* static type checking by preserving constness, without, we cast it
* to a non-const pointer. */
#define _NM_CONSTCAST(type, obj) \
((type *) (obj))
#endif
/*****************************************************************************/
#define _NM_IN_SET_EVAL_1( op, _x, y) (_x == (y))
#define _NM_IN_SET_EVAL_2( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_1 (op, _x, __VA_ARGS__)
#define _NM_IN_SET_EVAL_3( op, _x, y, ...) (_x == (y)) op _NM_IN_SET_EVAL_2 (op, _x, __VA_ARGS__)
@ -381,6 +410,21 @@ _NM_IN_STRSET_streq (const char *x, const char *s)
/*****************************************************************************/
static inline guint
NM_HASH_COMBINE (guint h, guint val)
{
/* see g_str_hash() for reasons */
return (h << 5) + h + val;
}
static inline guint
NM_HASH_COMBINE_UINT64 (guint h, guint64 val)
{
return NM_HASH_COMBINE (h, (((guint) val) & 0xFFFFFFFFu) + ((guint) (val >> 32)));
}
/*****************************************************************************/
/* NM_CACHED_QUARK() returns the GQuark for @string, but caches
* it in a static variable to speed up future lookups.
*
@ -522,7 +566,7 @@ _notify (obj_type *obj, _PropertyEnums prop) \
/* these are implemented as a macro, because they accept self
* as both (type*) and (const type*), and return a const
* private pointer accordingly. */
#define __NM_GET_PRIVATE(self, type, is_check, result_cmd) \
#define __NM_GET_PRIVATE(self, type, is_check, addrop) \
({ \
/* preserve the const-ness of self. Unfortunately, that
* way, @self cannot be a void pointer */ \
@ -532,11 +576,11 @@ _notify (obj_type *obj, _PropertyEnums prop) \
_nm_unused const type *const _self2 = (_self); \
\
nm_assert (is_check (_self)); \
( result_cmd ); \
( addrop ( _NM_CONSTCAST (type, _self)->_priv) ); \
})
#define _NM_GET_PRIVATE(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, &_self->_priv)
#define _NM_GET_PRIVATE_PTR(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, _self->_priv)
#define _NM_GET_PRIVATE(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, &)
#define _NM_GET_PRIVATE_PTR(self, type, is_check) __NM_GET_PRIVATE(self, type, is_check, )
#define __NM_GET_PRIVATE_VOID(self, type, is_check, result_cmd) \
({ \

82
shared/nm-utils/nm-obj.h Normal file
View file

@ -0,0 +1,82 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*
* (C) Copyright 2017 Red Hat, Inc.
*/
#ifndef __NM_OBJ_H__
#define __NM_OBJ_H__
/*****************************************************************************/
#define NM_OBJ_REF_COUNT_STACKINIT (G_MAXINT)
typedef struct _NMObjBaseInst NMObjBaseInst;
typedef struct _NMObjBaseClass NMObjBaseClass;
struct _NMObjBaseInst {
/* The first field of NMObjBaseInst is compatible with GObject.
* Basically, NMObjBaseInst is an abstract base type of GTypeInstance.
*
* If you do it right, you may derive a type of NMObjBaseInst as a proper GTypeInstance.
* That involves allocating a GType for it, which can be inconvenient because
* a GType is dynamically created (and the class can no longer be immutable
* memory).
*
* Even if your implementation of NMObjBaseInst is not a full fledged GType(Instance),
* you still can use GTypeInstances in the same context as you can decide based on the
* NMObjBaseClass with what kind of object you are dealing with.
*
* Basically, the only thing NMObjBaseInst gives you is access to an
* NMObjBaseClass instance.
*/
union {
const NMObjBaseClass *klass;
GTypeInstance g_type_instance;
};
};
struct _NMObjBaseClass {
/* NMObjBaseClass is the base class of all NMObjBaseInst implementations.
* Note that it is also an abstract super class of GTypeInstance, that means
* you may implement a NMObjBaseClass as a subtype of GTypeClass.
*
* For that to work, you must properly set the GTypeClass instance (and it's
* GType).
*
* Note that to implement a NMObjBaseClass that is *not* a GTypeClass, you wouldn't
* set the GType. Hence, this field is only useful for type implementations that actually
* extend GTypeClass.
*
* In a way it is wrong that NMObjBaseClass has the GType member, because it is
* a base class of GTypeClass and doesn't necessarily use the GType. However,
* it is here so that G_TYPE_CHECK_INSTANCE_TYPE() and friends work correctly
* on any NMObjectClass. That means, while not necessary, it is convenient that
* a NMObjBaseClass has all members of GTypeClass.
* Also note that usually you have only one instance of a certain type, so this
* wastes just a few bytes for the unneeded GType.
*/
union {
GType g_type;
GTypeClass g_type_class;
};
};
/*****************************************************************************/
#endif /* __NM_OBJ_H__ */

View file

@ -35,11 +35,14 @@
#include <fcntl.h>
#include <linux/if_addr.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-common-macros.h"
#include "nm-device-private.h"
#include "NetworkManagerUtils.h"
#include "nm-manager.h"
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
#include "ndisc/nm-ndisc.h"
#include "ndisc/nm-lndp-ndisc.h"
#include "dhcp/nm-dhcp-manager.h"
@ -647,12 +650,32 @@ nm_device_get_netns (NMDevice *self)
return NM_DEVICE_GET_PRIVATE (self)->netns;
}
NMDedupMultiIndex *
nm_device_get_multi_index (NMDevice *self)
{
return nm_netns_get_multi_idx (nm_device_get_netns (self));
}
NMPlatform *
nm_device_get_platform (NMDevice *self)
{
return nm_netns_get_platform (nm_device_get_netns (self));
}
static NMIP4Config *
_ip4_config_new (NMDevice *self)
{
return nm_ip4_config_new (nm_device_get_multi_index (self),
nm_device_get_ip_ifindex (self));
}
static NMIP6Config *
_ip6_config_new (NMDevice *self)
{
return nm_ip6_config_new (nm_device_get_multi_index (self),
nm_device_get_ip_ifindex (self));
}
/*****************************************************************************/
NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_sys_iface_state_to_str, NMDeviceSysIfaceState,
@ -5058,7 +5081,7 @@ ipv4_manual_method_apply (NMDevice *self, NMIP4Config **configs, gboolean succes
NMIP4Config *empty;
if (success) {
empty = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
empty = _ip4_config_new (self);
nm_device_activate_schedule_ip4_config_result (self, empty);
g_object_unref (empty);
} else {
@ -5215,7 +5238,7 @@ ipv4ll_get_ip4_config (NMDevice *self, guint32 lla)
NMPlatformIP4Address address;
NMPlatformIP4Route route;
config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
config = _ip4_config_new (self);
g_assert (config);
memset (&address, 0, sizeof (address));
@ -5383,45 +5406,47 @@ ipv4ll_start (NMDevice *self)
static gboolean
_device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route)
{
gboolean success = FALSE;
int ifindex = nm_device_get_ip_ifindex (self);
GArray *routes;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
const NMPlatformIPRoute *route = NULL;
guint32 route_metric = G_MAXUINT32;
if (addr_family == AF_INET)
routes = nm_platform_ip4_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
else
routes = nm_platform_ip6_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
pl_head_entry = nm_platform_lookup_route_visible (nm_device_get_platform (self),
addr_family == AF_INET
? NMP_OBJECT_TYPE_IP4_ROUTE
: NMP_OBJECT_TYPE_IP6_ROUTE,
0,
TRUE);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
guint32 m;
const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj);
if (routes) {
guint route_metric = G_MAXUINT32, m;
const NMPlatformIPRoute *route = NULL, *r;
guint i;
if (r->ifindex != ifindex)
continue;
if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
/* if there are several default routes, find the one with the best metric */
for (i = 0; i < routes->len; i++) {
if (addr_family == AF_INET) {
r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, i);
m = r->metric;
} else {
r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, i);
m = nm_utils_ip6_route_metric_normalize (r->metric);
}
if (!route || m < route_metric) {
route = r;
route_metric = m;
}
}
m = r->metric;
if (addr_family != AF_INET)
m = nm_utils_ip6_route_metric_normalize (r->metric);
if (route) {
if (addr_family == AF_INET)
*((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route);
else
*((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route);
success = TRUE;
if (!route || m < route_metric) {
route = NMP_OBJECT_CAST_IP_ROUTE (plobj);
route_metric = m;
}
g_array_free (routes, TRUE);
}
return success;
if (route) {
if (addr_family == AF_INET)
*((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route);
else
*((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route);
return TRUE;
}
return FALSE;
}
/*****************************************************************************/
@ -5430,7 +5455,6 @@ static void
ensure_con_ip4_config (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ip_ifindex = nm_device_get_ip_ifindex (self);
NMConnection *connection;
if (priv->con_ip4_config)
@ -5440,7 +5464,7 @@ ensure_con_ip4_config (NMDevice *self)
if (!connection)
return;
priv->con_ip4_config = nm_ip4_config_new (ip_ifindex);
priv->con_ip4_config = _ip4_config_new (self);
nm_ip4_config_merge_setting (priv->con_ip4_config,
nm_connection_get_setting_ip4_config (connection),
nm_device_get_ip4_route_metric (self));
@ -5456,7 +5480,6 @@ static void
ensure_con_ip6_config (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ip_ifindex = nm_device_get_ip_ifindex (self);
NMConnection *connection;
if (priv->con_ip6_config)
@ -5466,7 +5489,7 @@ ensure_con_ip6_config (NMDevice *self)
if (!connection)
return;
priv->con_ip6_config = nm_ip6_config_new (ip_ifindex);
priv->con_ip6_config = _ip6_config_new (self);
nm_ip6_config_merge_setting (priv->con_ip6_config,
nm_connection_get_setting_ip6_config (connection),
nm_device_get_ip6_route_metric (self));
@ -5548,14 +5571,15 @@ ip4_config_merge_and_apply (NMDevice *self,
}
}
composite = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
composite = _ip4_config_new (self);
init_ip4_config_dns_priority (self, composite);
if (commit) {
ensure_con_ip4_config (self);
if (priv->queued_ip4_config_id) {
g_clear_object (&priv->ext_ip4_config);
priv->ext_ip4_config = nm_ip4_config_capture (nm_device_get_platform (self),
priv->ext_ip4_config = nm_ip4_config_capture (nm_device_get_multi_index (self),
nm_device_get_platform (self),
nm_device_get_ip_ifindex (self),
FALSE);
}
@ -5824,7 +5848,7 @@ dhcp4_state_changed (NMDhcpClient *client,
connection = nm_device_get_applied_connection (self);
g_assert (connection);
manual = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
manual = _ip4_config_new (self);
nm_ip4_config_merge_setting (manual,
nm_connection_get_setting_ip4_config (connection),
nm_device_get_ip4_route_metric (self));
@ -5905,6 +5929,7 @@ dhcp4_start (NMDevice *self,
/* Begin DHCP on the interface */
g_warn_if_fail (priv->dhcp4.client == NULL);
priv->dhcp4.client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
nm_netns_get_multi_idx (nm_device_get_netns (self)),
nm_device_get_ip_iface (self),
nm_device_get_ip_ifindex (self),
tmp,
@ -6012,7 +6037,7 @@ shared4_new_config (NMDevice *self, NMConnection *connection)
is_generated = TRUE;
}
config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
config = _ip4_config_new (self);
nm_ip4_config_add_address (config, &address);
if (is_generated) {
/* Remove the address lock when the object gets disposed */
@ -6173,7 +6198,7 @@ act_stage3_ip4_config_start (NMDevice *self,
} else if (strcmp (method, NM_SETTING_IP4_CONFIG_METHOD_MANUAL) == 0) {
NMIP4Config **configs, *config;
config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
config = _ip4_config_new (self);
nm_ip4_config_merge_setting (config,
nm_connection_get_setting_ip4_config (connection),
nm_device_get_ip4_route_metric (self));
@ -6273,7 +6298,7 @@ ip6_config_merge_and_apply (NMDevice *self,
}
}
composite = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
composite = _ip6_config_new (self);
nm_ip6_config_set_privacy (composite,
priv->ndisc ?
priv->ndisc_use_tempaddr :
@ -6285,7 +6310,8 @@ ip6_config_merge_and_apply (NMDevice *self,
if (priv->queued_ip6_config_id) {
g_clear_object (&priv->ext_ip6_config);
g_clear_object (&priv->ext_ip6_config_captured);
priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self),
priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self),
nm_device_get_platform (self),
nm_device_get_ip_ifindex (self),
FALSE,
NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
@ -6702,6 +6728,7 @@ dhcp6_start_with_link_ready (NMDevice *self, NMConnection *connection)
}
priv->dhcp6.client = nm_dhcp_manager_start_ip6 (nm_dhcp_manager_get (),
nm_device_get_multi_index (self),
nm_device_get_ip_iface (self),
nm_device_get_ip_ifindex (self),
tmp,
@ -6830,7 +6857,7 @@ nm_device_use_ip6_subnet (NMDevice *self, const NMPlatformIP6Address *subnet)
NMPlatformIP6Address address = *subnet;
if (!priv->ac_ip6_config)
priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
priv->ac_ip6_config = _ip6_config_new (self);
/* Assign a ::1 address in the subnet for us. */
address.address.s6_addr32[3] |= htonl (1);
@ -6860,7 +6887,7 @@ nm_device_copy_ip6_dns_config (NMDevice *self, NMDevice *from_device)
nm_ip6_config_reset_nameservers (priv->ac_ip6_config);
nm_ip6_config_reset_searches (priv->ac_ip6_config);
} else
priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
priv->ac_ip6_config = _ip6_config_new (self);
if (from_device)
from_config = nm_device_get_ip6_config (from_device);
@ -7280,7 +7307,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
g_return_if_fail (priv->act_request);
if (!priv->ac_ip6_config)
priv->ac_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
priv->ac_ip6_config = _ip6_config_new (self);
if (changed & NM_NDISC_CONFIG_GATEWAYS) {
/* Use the first gateway as ordered in neighbor discovery cache. */
@ -7802,7 +7829,8 @@ act_stage3_ip6_config_start (NMDevice *self,
*/
nm_platform_process_events (nm_device_get_platform (self));
g_clear_object (&priv->ext_ip6_config_captured);
priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self),
priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self),
nm_device_get_platform (self),
nm_device_get_ip_ifindex (self),
FALSE,
NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
@ -7876,7 +7904,7 @@ nm_device_activate_stage3_ip4_start (NMDevice *self)
ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip4_config_start (self, &ip4_config, &failure_reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
if (!ip4_config)
ip4_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
ip4_config = _ip4_config_new (self);
nm_device_activate_schedule_ip4_config_result (self, ip4_config);
g_object_unref (ip4_config);
} else if (ret == NM_ACT_STAGE_RETURN_IP_DONE) {
@ -7923,7 +7951,7 @@ nm_device_activate_stage3_ip6_start (NMDevice *self)
ret = NM_DEVICE_GET_CLASS (self)->act_stage3_ip6_config_start (self, &ip6_config, &failure_reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
if (!ip6_config)
ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
ip6_config = _ip6_config_new (self);
/* Here we get a static IPv6 config, like for Shared where it's
* autogenerated or from modems where it comes from ModemManager.
*/
@ -8510,7 +8538,7 @@ dad6_get_pending_addresses (NMDevice *self)
nm_platform_ip6_address_to_string (pl_addr, NULL, 0));
if (!dad6_config)
dad6_config = nm_ip6_config_new (ifindex);
dad6_config = _ip6_config_new (self);
nm_ip6_config_add_address (dad6_config, pl_addr);
}
@ -8925,7 +8953,7 @@ nm_device_reactivate_ip4_config (NMDevice *self,
if (priv->ip4_state != IP_NONE) {
g_clear_object (&priv->con_ip4_config);
g_clear_object (&priv->ext_ip4_config);
priv->con_ip4_config = nm_ip4_config_new (nm_device_get_ip_ifindex (self));
priv->con_ip4_config = _ip4_config_new (self);
nm_ip4_config_merge_setting (priv->con_ip4_config,
s_ip4_new,
nm_device_get_ip4_route_metric (self));
@ -8967,7 +8995,7 @@ nm_device_reactivate_ip6_config (NMDevice *self,
if (priv->ip6_state != IP_NONE) {
g_clear_object (&priv->con_ip6_config);
g_clear_object (&priv->ext_ip6_config);
priv->con_ip6_config = nm_ip6_config_new (nm_device_get_ip_ifindex (self));
priv->con_ip6_config = _ip6_config_new (self);
nm_ip6_config_merge_setting (priv->con_ip6_config,
s_ip6_new,
nm_device_get_ip6_route_metric (self));
@ -10562,6 +10590,7 @@ find_ip4_lease_config (NMDevice *self,
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
leases = nm_dhcp_manager_get_lease_ip_configs (nm_dhcp_manager_get (),
nm_device_get_multi_index (self),
ip_iface,
ip_ifindex,
nm_connection_get_uuid (connection),
@ -10680,7 +10709,8 @@ update_ip4_config (NMDevice *self, gboolean initial)
/* IPv4 */
g_clear_object (&priv->ext_ip4_config);
priv->ext_ip4_config = nm_ip4_config_capture (nm_device_get_platform (self),
priv->ext_ip4_config = nm_ip4_config_capture (nm_device_get_multi_index (self),
nm_device_get_platform (self),
ifindex,
capture_resolv_conf);
if (priv->ext_ip4_config) {
@ -10755,7 +10785,11 @@ update_ip6_config (NMDevice *self, gboolean initial)
/* IPv6 */
g_clear_object (&priv->ext_ip6_config);
g_clear_object (&priv->ext_ip6_config_captured);
priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_platform (self), ifindex, capture_resolv_conf, NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
priv->ext_ip6_config_captured = nm_ip6_config_capture (nm_device_get_multi_index (self),
nm_device_get_platform (self),
ifindex,
capture_resolv_conf,
NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
if (priv->ext_ip6_config_captured) {
priv->ext_ip6_config = nm_ip6_config_new_cloned (priv->ext_ip6_config_captured);

View file

@ -416,6 +416,7 @@ typedef void (*NMDeviceAuthRequestFunc) (NMDevice *device,
GType nm_device_get_type (void);
struct _NMDedupMultiIndex *nm_device_get_multi_index (NMDevice *self);
NMNetns *nm_device_get_netns (NMDevice *self);
NMPlatform *nm_device_get_platform (NMDevice *self);

View file

@ -274,12 +274,12 @@ static guint
lldp_neighbor_id_hash (gconstpointer ptr)
{
const LldpNeighbor *neigh = ptr;
guint hash;
guint hash = 23423423u;
hash = 23423423u + ((guint) (neigh->chassis_id ? g_str_hash (neigh->chassis_id) : 12321u));
hash = (hash * 33u) + ((guint) (neigh->port_id ? g_str_hash (neigh->port_id) : 34342343u));
hash = (hash * 33u) + ((guint) neigh->chassis_id_type);
hash = (hash * 33u) + ((guint) neigh->port_id_type);
hash = NM_HASH_COMBINE (hash, neigh->chassis_id ? g_str_hash (neigh->chassis_id) : 12321u);
hash = NM_HASH_COMBINE (hash, neigh->port_id ? g_str_hash (neigh->port_id) : 34342343u);
hash = NM_HASH_COMBINE (hash, neigh->chassis_id_type);
hash = NM_HASH_COMBINE (hash, neigh->port_id_type);
return hash;
}

View file

@ -910,7 +910,8 @@ static_stage3_ip4_done (NMModemBroadband *self)
data_port = mm_bearer_get_interface (self->_priv.bearer);
g_assert (data_port);
config = nm_ip4_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port));
config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port));
memset (&address, 0, sizeof (address));
address.address = address_network;
@ -1004,7 +1005,8 @@ stage3_ip6_done (NMModemBroadband *self)
data_port = mm_bearer_get_interface (self->_priv.bearer);
g_assert (data_port);
config = nm_ip6_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port));
config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
nm_platform_link_get_ifindex (NM_PLATFORM_GET, data_port));
address.plen = mm_bearer_ip_config_get_prefix (self->_priv.ipv6_config);
if (address.plen <= 128)

View file

@ -908,7 +908,8 @@ context_property_changed (GDBusProxy *proxy,
*
* This needs discussion with upstream.
*/
priv->ip4_config = nm_ip4_config_new (0);
priv->ip4_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
0);
/* TODO: simply if/else error logic! */

View file

@ -30,6 +30,8 @@
#include <stdlib.h>
#include <uuid/uuid.h>
#include "nm-utils/nm-dedup-multi.h"
#include "NetworkManagerUtils.h"
#include "nm-utils.h"
#include "nm-dhcp-utils.h"
@ -48,6 +50,7 @@ enum {
static guint signals[LAST_SIGNAL] = { 0 };
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
PROP_MULTI_IDX,
PROP_IFACE,
PROP_IFINDEX,
PROP_HWADDR,
@ -58,6 +61,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE (
);
typedef struct _NMDhcpClientPrivate {
NMDedupMultiIndex *multi_idx;
char * iface;
int ifindex;
GByteArray * hwaddr;
@ -91,6 +95,14 @@ nm_dhcp_client_get_pid (NMDhcpClient *self)
return NM_DHCP_CLIENT_GET_PRIVATE (self)->pid;
}
NMDedupMultiIndex *
nm_dhcp_client_get_multi_idx (NMDhcpClient *self)
{
g_return_val_if_fail (NM_IS_DHCP_CLIENT (self), NULL);
return NM_DHCP_CLIENT_GET_PRIVATE (self)->multi_idx;
}
const char *
nm_dhcp_client_get_iface (NMDhcpClient *self)
{
@ -765,13 +777,15 @@ nm_dhcp_client_handle_event (gpointer unused,
if (g_hash_table_size (str_options)) {
if (priv->ipv6) {
prefix = nm_dhcp_utils_ip6_prefix_from_options (str_options);
ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (priv->ifindex,
ip_config = (GObject *) nm_dhcp_utils_ip6_config_from_options (nm_dhcp_client_get_multi_idx (self),
priv->ifindex,
priv->iface,
str_options,
priv->priority,
priv->info_only);
} else {
ip_config = (GObject *) nm_dhcp_utils_ip4_config_from_options (priv->ifindex,
ip_config = (GObject *) nm_dhcp_utils_ip4_config_from_options (nm_dhcp_client_get_multi_idx (self),
priv->ifindex,
priv->iface,
str_options,
priv->priority);
@ -847,6 +861,13 @@ set_property (GObject *object, guint prop_id,
NMDhcpClientPrivate *priv = NM_DHCP_CLIENT_GET_PRIVATE ((NMDhcpClient *) object);
switch (prop_id) {
case PROP_MULTI_IDX:
/* construct-only */
priv->multi_idx = g_value_get_pointer (value);
if (!priv->multi_idx)
g_return_if_reached ();
nm_dedup_multi_index_ref (priv->multi_idx);
break;
case PROP_IFACE:
/* construct-only */
priv->iface = g_value_dup_string (value);
@ -924,6 +945,8 @@ dispose (GObject *object)
}
G_OBJECT_CLASS (nm_dhcp_client_parent_class)->dispose (object);
priv->multi_idx = nm_dedup_multi_index_unref (priv->multi_idx);
}
static void
@ -940,6 +963,12 @@ nm_dhcp_client_class_init (NMDhcpClientClass *client_class)
client_class->stop = stop;
client_class->get_duid = get_duid;
obj_properties[PROP_MULTI_IDX] =
g_param_spec_pointer (NM_DHCP_CLIENT_MULTI_IDX, "", "",
G_PARAM_WRITABLE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS);
obj_properties[PROP_IFACE] =
g_param_spec_string (NM_DHCP_CLIENT_INTERFACE, "", "",
NULL,

View file

@ -38,6 +38,7 @@
#define NM_DHCP_CLIENT_UUID "uuid"
#define NM_DHCP_CLIENT_PRIORITY "priority"
#define NM_DHCP_CLIENT_TIMEOUT "timeout"
#define NM_DHCP_CLIENT_MULTI_IDX "multi-idx"
#define NM_DHCP_CLIENT_SIGNAL_STATE_CHANGED "state-changed"
#define NM_DHCP_CLIENT_SIGNAL_PREFIX_DELEGATED "prefix-delegated"
@ -101,6 +102,8 @@ typedef struct {
GType nm_dhcp_client_get_type (void);
struct _NMDedupMultiIndex *nm_dhcp_client_get_multi_idx (NMDhcpClient *self);
pid_t nm_dhcp_client_get_pid (NMDhcpClient *self);
const char *nm_dhcp_client_get_iface (NMDhcpClient *self);
@ -173,7 +176,8 @@ typedef struct {
GType (*get_type)(void);
const char *name;
const char *(*get_path) (void);
GSList *(*get_lease_ip_configs) (const char *iface,
GSList *(*get_lease_ip_configs) (struct _NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const char *uuid,
gboolean ipv6,

View file

@ -25,6 +25,8 @@
#include <ctype.h>
#include <arpa/inet.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-dhcp-utils.h"
#include "nm-ip4-config.h"
#include "nm-utils.h"
@ -659,6 +661,7 @@ lease_validity_span (const char *str_expire, GDateTime *now)
/**
* nm_dhcp_dhclient_read_lease_ip_configs:
* @multi_idx: the multi index instance for the ip config object
* @iface: the interface name to match leases with
* @ifindex: interface index of @iface
* @contents: the contents of a dhclient leasefile
@ -673,7 +676,8 @@ lease_validity_span (const char *str_expire, GDateTime *now)
* #NMIP6Config objects (if @ipv6 is %TRUE) containing the lease data.
*/
GSList *
nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
nm_dhcp_dhclient_read_lease_ip_configs (NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const char *contents,
gboolean ipv6,
@ -783,7 +787,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
address.lifetime = address.preferred = expiry;
address.addr_source = NM_IP_CONFIG_SOURCE_DHCP;
ip4 = nm_ip4_config_new (ifindex);
ip4 = nm_ip4_config_new (multi_idx, ifindex);
nm_ip4_config_add_address (ip4, &address);
nm_ip4_config_set_gateway (ip4, gw);

View file

@ -42,7 +42,8 @@ gboolean nm_dhcp_dhclient_save_duid (const char *leasefile,
const char *escaped_duid,
GError **error);
GSList *nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
GSList *nm_dhcp_dhclient_read_lease_ip_configs (struct _NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const char *contents,
gboolean ipv6,

View file

@ -38,6 +38,8 @@
#include <arpa/inet.h>
#include <ctype.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-utils.h"
#include "nm-dhcp-dhclient-utils.h"
#include "nm-dhcp-manager.h"
@ -148,7 +150,8 @@ get_dhclient_leasefile (const char *iface,
}
static GSList *
nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
nm_dhcp_dhclient_get_lease_ip_configs (NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const char *uuid,
gboolean ipv6,
@ -166,7 +169,7 @@ nm_dhcp_dhclient_get_lease_ip_configs (const char *iface,
&& g_file_get_contents (leasefile, &contents, NULL, NULL)
&& contents
&& contents[0])
leases = nm_dhcp_dhclient_read_lease_ip_configs (iface, ifindex, contents, ipv6, NULL);
leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, iface, ifindex, contents, ipv6, NULL);
g_free (leasefile);
g_free (contents);

View file

@ -34,6 +34,8 @@
#include <fcntl.h>
#include <stdio.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-config.h"
#include "NetworkManagerUtils.h"
@ -152,6 +154,7 @@ client_state_changed (NMDhcpClient *client,
static NMDhcpClient *
client_start (NMDhcpManager *self,
NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const GByteArray *hwaddr,
@ -195,6 +198,7 @@ client_start (NMDhcpManager *self,
/* And make a new one */
client = g_object_new (priv->client_factory->get_type (),
NM_DHCP_CLIENT_MULTI_IDX, multi_idx,
NM_DHCP_CLIENT_INTERFACE, iface,
NM_DHCP_CLIENT_IFINDEX, ifindex,
NM_DHCP_CLIENT_HWADDR, hwaddr,
@ -222,6 +226,7 @@ client_start (NMDhcpManager *self,
/* Caller owns a reference to the NMDhcpClient on return */
NMDhcpClient *
nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const GByteArray *hwaddr,
@ -267,7 +272,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
}
}
return client_start (self, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL,
return client_start (self, multi_idx, iface, ifindex, hwaddr, uuid, priority, FALSE, NULL,
dhcp_client_id, timeout, dhcp_anycast_addr, hostname,
use_fqdn, FALSE, 0, last_ip_address, 0);
}
@ -275,6 +280,7 @@ nm_dhcp_manager_start_ip4 (NMDhcpManager *self,
/* Caller owns a reference to the NMDhcpClient on return */
NMDhcpClient *
nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const GByteArray *hwaddr,
@ -299,7 +305,7 @@ nm_dhcp_manager_start_ip6 (NMDhcpManager *self,
/* Always prefer the explicit dhcp-hostname if given */
hostname = dhcp_hostname ? dhcp_hostname : priv->default_hostname;
}
return client_start (self, iface, ifindex, hwaddr, uuid, priority, TRUE,
return client_start (self, multi_idx, iface, ifindex, hwaddr, uuid, priority, TRUE,
ll_addr, NULL, timeout, dhcp_anycast_addr, hostname, TRUE, info_only,
privacy, NULL, needed_prefixes);
}
@ -320,6 +326,7 @@ nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager, const char *hostna
GSList *
nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self,
NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const char *uuid,
@ -336,7 +343,7 @@ nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self,
priv = NM_DHCP_MANAGER_GET_PRIVATE (self);
if ( priv->client_factory
&& priv->client_factory->get_lease_ip_configs)
return priv->client_factory->get_lease_ip_configs (iface, ifindex, uuid, ipv6, default_route_metric);
return priv->client_factory->get_lease_ip_configs (multi_idx, iface, ifindex, uuid, ipv6, default_route_metric);
return NULL;
}

View file

@ -46,6 +46,7 @@ void nm_dhcp_manager_set_default_hostname (NMDhcpManager *manager,
const char *hostname);
NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager,
struct _NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const GByteArray *hwaddr,
@ -60,6 +61,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip4 (NMDhcpManager *manager,
const char *last_ip_address);
NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
struct _NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const GByteArray *hwaddr,
@ -75,6 +77,7 @@ NMDhcpClient * nm_dhcp_manager_start_ip6 (NMDhcpManager *manager,
guint needed_prefixes);
GSList * nm_dhcp_manager_get_lease_ip_configs (NMDhcpManager *self,
struct _NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const char *uuid,

View file

@ -28,6 +28,8 @@
#include <ctype.h>
#include <net/if_arp.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-utils.h"
#include "nm-dhcp-utils.h"
#include "NetworkManagerUtils.h"
@ -216,7 +218,8 @@ G_STMT_START { \
} G_STMT_END
static NMIP4Config *
lease_to_ip4_config (const char *iface,
lease_to_ip4_config (NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
sd_dhcp_lease *lease,
GHashTable *options,
@ -244,7 +247,7 @@ lease_to_ip4_config (const char *iface,
g_return_val_if_fail (lease != NULL, NULL);
ip4_config = nm_ip4_config_new (ifindex);
ip4_config = nm_ip4_config_new (multi_idx, ifindex);
/* Address */
sd_dhcp_lease_get_address (lease, &tmp_addr);
@ -433,7 +436,8 @@ get_leasefile_path (const char *iface, const char *uuid, gboolean ipv6)
}
static GSList *
nm_dhcp_systemd_get_lease_ip_configs (const char *iface,
nm_dhcp_systemd_get_lease_ip_configs (NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
const char *uuid,
gboolean ipv6,
@ -451,7 +455,7 @@ nm_dhcp_systemd_get_lease_ip_configs (const char *iface,
path = get_leasefile_path (iface, uuid, FALSE);
r = dhcp_lease_load (&lease, path);
if (r == 0 && lease) {
ip4_config = lease_to_ip4_config (iface, ifindex, lease, NULL, default_route_metric, FALSE, NULL);
ip4_config = lease_to_ip4_config (multi_idx, iface, ifindex, lease, NULL, default_route_metric, FALSE, NULL);
if (ip4_config)
leases = g_slist_append (leases, ip4_config);
sd_dhcp_lease_unref (lease);
@ -505,7 +509,8 @@ bound4_handle (NMDhcpSystemd *self)
_LOGD ("lease available");
options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
ip4_config = lease_to_ip4_config (iface,
ip4_config = lease_to_ip4_config (nm_dhcp_client_get_multi_idx (NM_DHCP_CLIENT (self)),
iface,
nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)),
lease,
options,
@ -725,7 +730,8 @@ error:
}
static NMIP6Config *
lease_to_ip6_config (const char *iface,
lease_to_ip6_config (NMDedupMultiIndex *multi_idx,
const char *iface,
int ifindex,
sd_dhcp6_lease *lease,
GHashTable *options,
@ -743,7 +749,7 @@ lease_to_ip6_config (const char *iface,
gint32 ts;
g_return_val_if_fail (lease, NULL);
ip6_config = nm_ip6_config_new (ifindex);
ip6_config = nm_ip6_config_new (multi_idx, ifindex);
ts = nm_utils_get_monotonic_timestamp_s ();
/* Addresses */
@ -830,7 +836,8 @@ bound6_handle (NMDhcpSystemd *self)
_LOGD ("lease available");
options = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_free);
ip6_config = lease_to_ip6_config (iface,
ip6_config = lease_to_ip6_config (nm_dhcp_client_get_multi_idx (NM_DHCP_CLIENT (self)),
iface,
nm_dhcp_client_get_ifindex (NM_DHCP_CLIENT (self)),
lease,
options,

View file

@ -24,6 +24,8 @@
#include <unistd.h>
#include <arpa/inet.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-dhcp-utils.h"
#include "nm-utils.h"
#include "NetworkManagerUtils.h"
@ -383,7 +385,8 @@ ip4_add_domain_search (gpointer data, gpointer user_data)
}
NMIP4Config *
nm_dhcp_utils_ip4_config_from_options (int ifindex,
nm_dhcp_utils_ip4_config_from_options (NMDedupMultiIndex *multi_idx,
int ifindex,
const char *iface,
GHashTable *options,
guint32 priority)
@ -398,7 +401,7 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
g_return_val_if_fail (options != NULL, NULL);
ip4_config = nm_ip4_config_new (ifindex);
ip4_config = nm_ip4_config_new (multi_idx, ifindex);
memset (&address, 0, sizeof (address));
address.timestamp = nm_utils_get_monotonic_timestamp_s ();
@ -616,7 +619,8 @@ nm_dhcp_utils_ip6_prefix_from_options (GHashTable *options)
}
NMIP6Config *
nm_dhcp_utils_ip6_config_from_options (int ifindex,
nm_dhcp_utils_ip6_config_from_options (NMDedupMultiIndex *multi_idx,
int ifindex,
const char *iface,
GHashTable *options,
guint32 priority,
@ -633,7 +637,7 @@ nm_dhcp_utils_ip6_config_from_options (int ifindex,
address.plen = 128;
address.timestamp = nm_utils_get_monotonic_timestamp_s ();
ip6_config = nm_ip6_config_new (ifindex);
ip6_config = nm_ip6_config_new (multi_idx, ifindex);
str = g_hash_table_lookup (options, "max_life");
if (str) {

View file

@ -24,12 +24,14 @@
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
NMIP4Config *nm_dhcp_utils_ip4_config_from_options (int ifindex,
NMIP4Config *nm_dhcp_utils_ip4_config_from_options (struct _NMDedupMultiIndex *multi_idx,
int ifindex,
const char *iface,
GHashTable *options,
guint priority);
NMIP6Config *nm_dhcp_utils_ip6_config_from_options (int ifindex,
NMIP6Config *nm_dhcp_utils_ip6_config_from_options (struct _NMDedupMultiIndex *multi_idx,
int ifindex,
const char *iface,
GHashTable *options,
guint priority,

View file

@ -24,6 +24,8 @@
#include <unistd.h>
#include <arpa/inet.h>
#include "nm-utils/nm-dedup-multi.h"
#include "NetworkManagerUtils.h"
#include "dhcp/nm-dhcp-dhclient-utils.h"
#include "dhcp/nm-dhcp-utils.h"
@ -838,6 +840,7 @@ test_interface2 (void)
static void
test_read_lease_ip4_config_basic (void)
{
nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new ();
GError *error = NULL;
char *contents = NULL;
gboolean success;
@ -854,7 +857,7 @@ test_read_lease_ip4_config_basic (void)
/* Date from before the least expiration */
now = g_date_time_new_utc (2013, 11, 1, 19, 55, 32);
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now);
leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, "wlan0", -1, contents, FALSE, now);
g_assert_cmpint (g_slist_length (leases), ==, 2);
/* IP4Config #1 */
@ -915,6 +918,7 @@ test_read_lease_ip4_config_basic (void)
static void
test_read_lease_ip4_config_expired (void)
{
nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new ();
GError *error = NULL;
char *contents = NULL;
gboolean success;
@ -928,7 +932,7 @@ test_read_lease_ip4_config_expired (void)
/* Date from *after* the lease expiration */
now = g_date_time_new_utc (2013, 12, 1, 19, 55, 32);
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now);
leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, "wlan0", -1, contents, FALSE, now);
g_assert (leases == NULL);
g_date_time_unref (now);
@ -938,6 +942,7 @@ test_read_lease_ip4_config_expired (void)
static void
test_read_lease_ip4_config_expect_failure (gconstpointer user_data)
{
nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new ();
GError *error = NULL;
char *contents = NULL;
gboolean success;
@ -950,7 +955,7 @@ test_read_lease_ip4_config_expect_failure (gconstpointer user_data)
/* Date from before the least expiration */
now = g_date_time_new_utc (2013, 11, 1, 1, 1, 1);
leases = nm_dhcp_dhclient_read_lease_ip_configs ("wlan0", -1, contents, FALSE, now);
leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, "wlan0", -1, contents, FALSE, now);
g_assert (leases == NULL);
g_date_time_unref (now);

View file

@ -23,6 +23,7 @@
#include <arpa/inet.h>
#include <string.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-utils.h"
#include "dhcp/nm-dhcp-utils.h"
@ -30,6 +31,20 @@
#include "nm-test-utils-core.h"
static NMIP4Config *
_ip4_config_from_options (int ifindex,
const char *iface,
GHashTable *options,
guint32 priority)
{
nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new ();
NMIP4Config *config;
config = nm_dhcp_utils_ip4_config_from_options (multi_idx, ifindex, iface, options, priority);
g_assert (config);
return config;
}
typedef struct {
const char *name;
const char *value;
@ -86,8 +101,7 @@ test_generic_options (void)
const char *expected_route2_gw = "10.1.1.1";
options = fill_table (generic_options, NULL);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 address */
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
@ -121,7 +135,7 @@ test_generic_options (void)
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
/* Route #1 */
route = nm_ip4_config_get_route (ip4_config, 0);
route = _nmtst_nm_ip4_config_get_route (ip4_config, 0);
g_assert (inet_pton (AF_INET, expected_route1_dest, &tmp) > 0);
g_assert (route->network == tmp);
g_assert (inet_pton (AF_INET, expected_route1_gw, &tmp) > 0);
@ -130,7 +144,7 @@ test_generic_options (void)
g_assert_cmpint (route->metric, ==, 0);
/* Route #2 */
route = nm_ip4_config_get_route (ip4_config, 1);
route = _nmtst_nm_ip4_config_get_route (ip4_config, 1);
g_assert (inet_pton (AF_INET, expected_route2_dest, &tmp) > 0);
g_assert (route->network == tmp);
g_assert (inet_pton (AF_INET, expected_route2_gw, &tmp) > 0);
@ -157,8 +171,7 @@ test_wins_options (void)
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 address */
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
@ -184,16 +197,14 @@ test_vendor_option_metered (void)
};
options = fill_table (generic_options, NULL);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_assert (nm_ip4_config_get_metered (ip4_config) == FALSE);
g_hash_table_destroy (options);
g_clear_object (&ip4_config);
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_assert (nm_ip4_config_get_metered (ip4_config) == TRUE);
g_hash_table_destroy (options);
}
@ -210,7 +221,7 @@ ip4_test_route (NMIP4Config *ip4_config,
g_assert (expected_prefix <= 32);
route = nm_ip4_config_get_route (ip4_config, route_num);
route = _nmtst_nm_ip4_config_get_route (ip4_config, route_num);
g_assert (inet_pton (AF_INET, expected_dest, &tmp) > 0);
g_assert (route->network == tmp);
g_assert (inet_pton (AF_INET, expected_gw, &tmp) > 0);
@ -246,8 +257,7 @@ test_classless_static_routes_1 (void)
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
@ -274,8 +284,7 @@ test_classless_static_routes_2 (void)
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
@ -303,8 +312,7 @@ test_fedora_dhclient_classless_static_routes (void)
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 2);
@ -335,8 +343,7 @@ test_dhclient_invalid_classless_routes_1 (void)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
"*ignoring invalid classless static routes*");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_test_assert_expected_messages ();
/* IP4 routes */
@ -366,8 +373,7 @@ test_dhcpcd_invalid_classless_routes_1 (void)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
"*ignoring invalid classless static routes*");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_test_assert_expected_messages ();
/* Test falling back to old-style static routes if the classless static
@ -399,8 +405,7 @@ test_dhclient_invalid_classless_routes_2 (void)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
"*ignoring invalid classless static routes*");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_test_assert_expected_messages ();
/* Test falling back to old-style static routes if the classless static
@ -432,8 +437,7 @@ test_dhcpcd_invalid_classless_routes_2 (void)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
"*ignoring invalid classless static routes*");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_test_assert_expected_messages ();
/* Test falling back to old-style static routes if the classless static
@ -465,8 +469,7 @@ test_dhclient_invalid_classless_routes_3 (void)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
"*ignoring invalid classless static routes*");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_test_assert_expected_messages ();
/* IP4 routes */
@ -493,8 +496,7 @@ test_dhcpcd_invalid_classless_routes_3 (void)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
"*DHCP provided invalid classless static route*");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_test_assert_expected_messages ();
/* IP4 routes */
@ -519,8 +521,7 @@ test_dhclient_gw_in_classless_routes (void)
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1);
@ -547,8 +548,7 @@ test_dhcpcd_gw_in_classless_routes (void)
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* IP4 routes */
g_assert_cmpint (nm_ip4_config_get_num_routes (ip4_config), ==, 1);
@ -575,8 +575,7 @@ test_escaped_domain_searches (void)
options = fill_table (generic_options, NULL);
options = fill_table (data, options);
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
/* domain searches */
g_assert_cmpint (nm_ip4_config_get_num_searches (ip4_config), ==, 3);
@ -602,8 +601,7 @@ test_invalid_escaped_domain_searches (void)
g_test_expect_message ("NetworkManager", G_LOG_LEVEL_MESSAGE,
"*invalid domain search*");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_test_assert_expected_messages ();
/* domain searches */
@ -623,8 +621,7 @@ test_ip4_missing_prefix (const char *ip, guint32 expected_prefix)
g_hash_table_insert (options, "ip_address", (gpointer) ip);
g_hash_table_remove (options, "subnet_mask");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
address = nm_ip4_config_get_address (ip4_config, 0);
@ -668,8 +665,7 @@ test_ip4_prefix_classless (void)
g_hash_table_insert (options, "ip_address", "172.16.54.22");
g_hash_table_insert (options, "subnet_mask", "255.255.252.0");
ip4_config = nm_dhcp_utils_ip4_config_from_options (1, "eth0", options, 0);
g_assert (ip4_config);
ip4_config = _ip4_config_from_options (1, "eth0", options, 0);
g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1);
address = nm_ip4_config_get_address (ip4_config, 0);

View file

@ -80,7 +80,9 @@ get_ip4_rdns_domains (NMIP4Config *ip4)
{
char **strv;
GPtrArray *domains = NULL;
int i;
guint i;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Route *route;
g_return_val_if_fail (ip4 != NULL, NULL);
@ -92,11 +94,8 @@ get_ip4_rdns_domains (NMIP4Config *ip4)
nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains);
}
for (i = 0; i < nm_ip4_config_get_num_routes (ip4); i++) {
const NMPlatformIP4Route *route = nm_ip4_config_get_route (ip4, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route)
nm_utils_get_reverse_dns_domains_ip4 (route->network, route->plen, domains);
}
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);
@ -112,7 +111,9 @@ get_ip6_rdns_domains (NMIP6Config *ip6)
{
char **strv;
GPtrArray *domains = NULL;
int i;
guint i;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
g_return_val_if_fail (ip6 != NULL, NULL);
@ -124,11 +125,8 @@ get_ip6_rdns_domains (NMIP6Config *ip6)
nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains);
}
for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (ip6, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route)
nm_utils_get_reverse_dns_domains_ip6 (&route->network, route->plen, domains);
}
/* Terminating NULL so we can use g_strfreev() to free it */
g_ptr_array_add (domains, NULL);

View file

@ -190,6 +190,19 @@ nm_utils_exp10 (gint16 ex)
/*****************************************************************************/
guint
nm_utils_in6_addr_hash (const struct in6_addr *addr)
{
guint hash = (guint) 0x897da53981a13ULL;
int i;
for (i = 0; i < sizeof (*addr); i++)
hash = NM_HASH_COMBINE (hash, ((const guint8 *) addr)[i]);
return hash;
}
/*****************************************************************************/
/*
* nm_ethernet_address_is_valid:
* @addr: pointer to a binary or ASCII Ethernet address

View file

@ -109,6 +109,14 @@ extern const NMIPAddr nm_ip_addr_zero;
/*****************************************************************************/
guint nm_utils_in6_addr_hash (const struct in6_addr *addr);
static inline guint
NM_HASH_COMBINE_IN6_ADDR (guint h, const struct in6_addr *addr)
{
return NM_HASH_COMBINE (h, addr ? nm_utils_in6_addr_hash (addr) : 0);
}
gboolean nm_ethernet_address_is_valid (gconstpointer addr, gssize len);
gconstpointer nm_utils_ipx_address_clear_host_address (int family, gpointer dst, gconstpointer src, guint8 plen);

View file

@ -28,6 +28,7 @@
#include "devices/nm-device.h"
#include "vpn/nm-vpn-connection.h"
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
#include "nm-manager.h"
#include "nm-ip4-config.h"
#include "nm-ip6-config.h"
@ -195,26 +196,20 @@ typedef struct {
static const VTableIP vtable_ip4, vtable_ip6;
static NMPlatformIPRoute *
_vt_route_index (const VTableIP *vtable, GArray *routes, guint index)
{
if (vtable->vt->is_ip4)
return (NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, index);
else
return (NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, index);
}
static gboolean
_vt_routes_has_entry (const VTableIP *vtable, GArray *routes, const Entry *entry)
_vt_routes_has_entry (const VTableIP *vtable, const GPtrArray *routes, const Entry *entry)
{
guint i;
NMPlatformIPXRoute route = entry->route;
if (!routes)
return FALSE;
route.rx.metric = entry->effective_metric;
if (vtable->vt->is_ip4) {
for (i = 0; i < routes->len; i++) {
NMPlatformIP4Route *r = &g_array_index (routes, NMPlatformIP4Route, i);
const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (routes->pdata[i]);
route.rx.rt_source = r->rt_source;
if (nm_platform_ip4_route_cmp (r, &route.r4) == 0)
@ -222,7 +217,7 @@ _vt_routes_has_entry (const VTableIP *vtable, GArray *routes, const Entry *entry
}
} else {
for (i = 0; i < routes->len; i++) {
NMPlatformIP6Route *r = &g_array_index (routes, NMPlatformIP6Route, i);
const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (routes->pdata[i]);
route.rx.rt_source = r->rt_source;
if (nm_platform_ip6_route_cmp (r, &route.r6) == 0)
@ -331,19 +326,27 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self,
{
NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
GPtrArray *entries = vtable->get_entries (priv);
GArray *routes;
gs_unref_ptrarray GPtrArray *routes = NULL;
guint i, j;
gboolean changed = FALSE;
/* prune all other default routes from this device. */
routes = vtable->vt->route_get_all (priv->platform, 0, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
routes = nm_platform_lookup_route_visible_clone (priv->platform,
vtable->vt->obj_type,
0,
TRUE,
nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
NULL);
if (!routes)
return FALSE;
for (i = 0; i < routes->len; i++) {
const NMPlatformIPRoute *route;
gboolean has_ifindex_synced = FALSE;
Entry *entry = NULL;
route = _vt_route_index (vtable, routes, i);
route = NMP_OBJECT_CAST_IP_ROUTE (routes->pdata[i]);
/* look at all entries and see if the route for this ifindex pair is
* a known entry. */
@ -372,7 +375,6 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self,
changed = TRUE;
}
}
g_array_free (routes, TRUE);
return changed;
}
@ -419,7 +421,7 @@ _sort_entries_cmp (gconstpointer a, gconstpointer b, gpointer user_data)
}
static GHashTable *
_get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *self, GArray *routes)
_get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *self, const GPtrArray *routes)
{
NMDefaultRouteManagerPrivate *priv = NM_DEFAULT_ROUTE_MANAGER_GET_PRIVATE (self);
GPtrArray *entries;
@ -435,24 +437,26 @@ _get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *s
result = g_hash_table_new (NULL, NULL);
for (i = 0; i < routes->len; i++) {
gboolean ifindex_has_synced_entry = FALSE;
const NMPlatformIPRoute *route;
if (routes) {
for (i = 0; i < routes->len; i++) {
gboolean ifindex_has_synced_entry = FALSE;
const NMPlatformIPRoute *route;
route = _vt_route_index (vtable, routes, i);
route = NMP_OBJECT_CAST_IP_ROUTE (routes->pdata[i]);
for (j = 0; j < entries->len; j++) {
Entry *e = g_ptr_array_index (entries, j);
for (j = 0; j < entries->len; j++) {
Entry *e = g_ptr_array_index (entries, j);
if ( e->synced
&& e->route.rx.ifindex == route->ifindex) {
ifindex_has_synced_entry = TRUE;
break;
if ( e->synced
&& e->route.rx.ifindex == route->ifindex) {
ifindex_has_synced_entry = TRUE;
break;
}
}
}
if (!ifindex_has_synced_entry)
g_hash_table_add (result, GUINT_TO_POINTER (vtable->vt->metric_normalize (route->metric)));
if (!ifindex_has_synced_entry)
g_hash_table_add (result, GUINT_TO_POINTER (vtable->vt->metric_normalize (route->metric)));
}
}
/* also add all non-synced metrics from our entries list. We might have there some metrics that
@ -493,7 +497,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
GPtrArray *entries;
GArray *changed_metrics = g_array_new (FALSE, FALSE, sizeof (guint32));
GHashTable *assumed_metrics;
GArray *routes;
gs_unref_ptrarray GPtrArray *routes = NULL;
gboolean changed = FALSE;
int ifindex_to_flush = 0;
@ -511,7 +515,12 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
entries = vtable->get_entries (priv);
routes = vtable->vt->route_get_all (priv->platform, 0, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
routes = nm_platform_lookup_route_visible_clone (priv->platform,
vtable->vt->obj_type,
0,
TRUE,
nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
NULL);
assumed_metrics = _get_assumed_interface_metrics (vtable, self, routes);
@ -560,13 +569,15 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
* If there are any, we have to pick another effective_metric. */
/* However, if there is a matching route (ifindex+metric) for our current entry, we are done. */
for (j = 0; j < routes->len; j++) {
const NMPlatformIPRoute *r = _vt_route_index (vtable, routes, i);
if (routes) {
for (j = 0; j < routes->len; j++) {
const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (routes->pdata[i]);
if ( r->metric == expected_metric
&& r->ifindex == entry->route.rx.ifindex) {
has_metric_for_ifindex = TRUE;
break;
if ( r->metric == expected_metric
&& r->ifindex == entry->route.rx.ifindex) {
has_metric_for_ifindex = TRUE;
break;
}
}
}
if (has_metric_for_ifindex)
@ -611,8 +622,6 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
last_metric = expected_metric;
}
g_array_free (routes, TRUE);
g_array_sort_with_data (changed_metrics, nm_cmp_uint32_p_with_data, NULL);
last_metric = -1;
for (j = 0; j < changed_metrics->len; j++) {

View file

@ -113,6 +113,7 @@ static void
dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder)
{
GVariantBuilder int_builder;
NMDedupMultiIter ipconf_iter;
guint n, i;
const NMPlatformIP4Address *addr;
const NMPlatformIP4Route *route;
@ -163,9 +164,7 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder)
/* Static routes */
g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau"));
n = nm_ip4_config_get_num_routes (ip4);
for (i = 0; i < n; i++) {
route = nm_ip4_config_get_route (ip4, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) {
array[0] = route->network;
array[1] = route->plen;
array[2] = route->gateway;
@ -183,6 +182,7 @@ static void
dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder)
{
GVariantBuilder int_builder;
NMDedupMultiIter ipconf_iter;
guint n, i;
const NMPlatformIP6Address *addr;
const struct in6_addr *gw_bytes;
@ -231,9 +231,7 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder)
/* Static routes */
g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuayu)"));
n = nm_ip6_config_get_num_routes (ip6);
for (i = 0; i < n; i++) {
route = nm_ip6_config_get_route (ip6, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) {
ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE,
&route->network,
sizeof (struct in6_addr), 1);

View file

@ -122,7 +122,8 @@ dhcp4_state_changed (NMDhcpClient *client,
switch (state) {
case NM_DHCP_STATE_BOUND:
g_assert (ip4_config);
existing = nm_ip4_config_capture (NM_PLATFORM_GET, gl.ifindex, FALSE);
existing = nm_ip4_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex, FALSE);
if (last_config)
nm_ip4_config_subtract (existing, last_config);
@ -132,7 +133,8 @@ dhcp4_state_changed (NMDhcpClient *client,
if (last_config)
g_object_unref (last_config);
last_config = nm_ip4_config_new (nm_dhcp_client_get_ifindex (client));
last_config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
nm_dhcp_client_get_ifindex (client));
nm_ip4_config_replace (last_config, ip4_config, NULL);
break;
case NM_DHCP_STATE_TIMEOUT:
@ -177,11 +179,14 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
ifa_flags |= IFA_F_MANAGETEMPADDR;
}
existing = nm_ip6_config_capture (NM_PLATFORM_GET, gl.ifindex, FALSE, global_opt.tempaddr);
existing = nm_ip6_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex, FALSE, global_opt.tempaddr);
if (ndisc_config)
nm_ip6_config_subtract (existing, ndisc_config);
else
ndisc_config = nm_ip6_config_new (gl.ifindex);
else {
ndisc_config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
gl.ifindex);
}
if (changed & NM_NDISC_CONFIG_GATEWAYS) {
/* Use the first gateway as ordered in neighbor discovery cache. */
@ -469,6 +474,7 @@ main (int argc, char *argv[])
nm_platform_sysctl_set (NM_PLATFORM_GET, NMP_SYSCTL_PATHID_ABSOLUTE (nm_utils_ip4_property_path (global_opt.ifname, "promote_secondaries")), "1");
dhcp4_client = nm_dhcp_manager_start_ip4 (nm_dhcp_manager_get (),
nm_platform_get_multi_idx (NM_PLATFORM_GET),
global_opt.ifname,
gl.ifindex,
hwaddr,

View file

@ -26,7 +26,10 @@
#include <string.h>
#include <arpa/inet.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-utils.h"
#include "platform/nmp-object.h"
#include "platform/nm-platform.h"
#include "platform/nm-platform-utils.h"
#include "NetworkManagerUtils.h"
@ -43,7 +46,91 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF);
/*****************************************************************************/
gboolean
nm_ip_config_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a,
const NMPlatformIP4Route *r_b)
{
return r_a->network == r_b->network
&& r_a->plen == r_b->plen;
}
gboolean
nm_ip_config_obj_id_equal_ip6_route (const NMPlatformIP6Route *r_a,
const NMPlatformIP6Route *r_b)
{
return r_a->plen == r_b->plen
&& IN6_ARE_ADDR_EQUAL (&r_a->network, &r_b->network);
}
static guint
_idx_obj_id_hash (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj)
{
const NMPObject *o = (NMPObject *) obj;
guint h;
switch (NMP_OBJECT_GET_TYPE (o)) {
case NMP_OBJECT_TYPE_IP4_ADDRESS:
case NMP_OBJECT_TYPE_IP6_ADDRESS:
g_return_val_if_reached (0);
case NMP_OBJECT_TYPE_IP4_ROUTE:
h = 40303327;
h = NM_HASH_COMBINE (h, o->ip4_route.network);
h = NM_HASH_COMBINE (h, o->ip_route.plen);
break;
case NMP_OBJECT_TYPE_IP6_ROUTE:
h = 577629323;
h = NM_HASH_COMBINE_IN6_ADDR (h, &o->ip6_route.network);
h = NM_HASH_COMBINE (h, o->ip_route.plen);
break;
default:
g_return_val_if_reached (0);
};
return h;
}
static gboolean
_idx_obj_id_equal (const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj_a,
const NMDedupMultiObj *obj_b)
{
const NMPObject *o_a = (NMPObject *) obj_a;
const NMPObject *o_b = (NMPObject *) obj_b;
nm_assert (NMP_OBJECT_GET_TYPE (o_a) == NMP_OBJECT_GET_TYPE (o_b));
switch (NMP_OBJECT_GET_TYPE (o_a)) {
case NMP_OBJECT_TYPE_IP4_ADDRESS:
case NMP_OBJECT_TYPE_IP6_ADDRESS:
g_return_val_if_reached (FALSE);
case NMP_OBJECT_TYPE_IP4_ROUTE:
return nm_ip_config_obj_id_equal_ip4_route (&o_a->ip4_route, &o_b->ip4_route);
case NMP_OBJECT_TYPE_IP6_ROUTE:
return nm_ip_config_obj_id_equal_ip6_route (&o_a->ip6_route, &o_b->ip6_route);
default:
g_return_val_if_reached (FALSE);
};
}
static const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class = {
.idx_obj_id_hash = _idx_obj_id_hash,
.idx_obj_id_equal = _idx_obj_id_equal,
};
void
nm_ip_config_dedup_multi_idx_type_init (NMIPConfigDedupMultiIdxType *idx_type,
NMPObjectType obj_type)
{
nm_dedup_multi_idx_type_init ((NMDedupMultiIdxType *) idx_type,
&_dedup_multi_idx_type_class);
idx_type->obj_type = obj_type;
}
/*****************************************************************************/
NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config,
PROP_MULTI_IDX,
PROP_IFINDEX,
PROP_ADDRESS_DATA,
PROP_ADDRESSES,
@ -70,7 +157,6 @@ typedef struct {
gint dns_priority;
gint64 route_metric;
GArray *addresses;
GArray *routes;
GArray *nameservers;
GPtrArray *domains;
GPtrArray *searches;
@ -80,6 +166,8 @@ typedef struct {
GArray *wins;
GVariant *address_data_variant;
GVariant *addresses_variant;
NMDedupMultiIndex *multi_idx;
NMDedupMultiIdxType idx_ip4_routes;
} NMIP4ConfigPrivate;
struct _NMIP4Config {
@ -97,12 +185,22 @@ G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_EXPORTED_OBJECT)
/*****************************************************************************/
static void _add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Route *new);
/*****************************************************************************/
int
nm_ip4_config_get_ifindex (const NMIP4Config *config)
{
return NM_IP4_CONFIG_GET_PRIVATE (config)->ifindex;
}
NMDedupMultiIndex *
nm_ip4_config_get_multi_idx (const NMIP4Config *config)
{
return NM_IP4_CONFIG_GET_PRIVATE (config)->multi_idx;
}
/*****************************************************************************/
static gboolean
@ -114,6 +212,49 @@ _ipv4_is_zeronet (in_addr_t network)
/*****************************************************************************/
static const NMDedupMultiHeadEntry *
_idx_ip4_routes (const NMIP4Config *self)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
return nm_dedup_multi_index_lookup_head (priv->multi_idx,
&priv->idx_ip4_routes,
NULL);
}
static const NMPlatformIP4Route *
_entry_iter_get_ip4_route (const CList *iter)
{
const NMDedupMultiEntry *e = c_list_entry (iter, NMDedupMultiEntry, lst_entries);
const NMPObject *o = e->obj;
nm_assert (o);
nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_TYPE_IP4_ROUTE);
return &o->ip4_route;
}
void
nm_ip4_config_iter_ip4_route_init (NMDedupMultiIter *ipconf_iter, const NMIP4Config *self)
{
g_return_if_fail (NM_IS_IP4_CONFIG (self));
nm_dedup_multi_iter_init (ipconf_iter, _idx_ip4_routes (self));
}
gboolean
nm_ip4_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP4Route **out_route)
{
gboolean has_next;
has_next = nm_dedup_multi_iter_next (ipconf_iter);
if (has_next) {
nm_assert (NMP_OBJECT_GET_TYPE (ipconf_iter->current->obj) == NMP_OBJECT_TYPE_IP4_ROUTE);
NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->obj)->ip4_route));
}
return has_next;
}
/*****************************************************************************/
/**
* nm_ip4_config_capture_resolv_conf():
* @nameservers: array of guint32
@ -186,13 +327,6 @@ addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Addre
&& ((a->peer_address ^ b->peer_address) & nm_utils_ip4_prefix_to_netmask (a->plen)) == 0;
}
static gboolean
routes_are_duplicate (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_gateway_and_metric)
{
return a->network == b->network && a->plen == b->plen &&
(!consider_gateway_and_metric || (a->gateway == b->gateway && a->metric == b->metric));
}
/*****************************************************************************/
static gint
@ -259,67 +393,76 @@ sort_captured_addresses (gconstpointer a, gconstpointer b)
}
NMIP4Config *
nm_ip4_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf)
nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf)
{
NMIP4Config *config;
NMIP4ConfigPrivate *priv;
guint i;
guint32 lowest_metric = G_MAXUINT32;
guint32 lowest_metric;
guint32 old_gateway = 0;
gboolean old_has_gateway = FALSE;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
/* Slaves have no IP configuration */
if (nm_platform_link_get_master (platform, ifindex) > 0)
return NULL;
config = nm_ip4_config_new (ifindex);
config = nm_ip4_config_new (multi_idx, ifindex);
priv = NM_IP4_CONFIG_GET_PRIVATE (config);
g_array_unref (priv->addresses);
g_array_unref (priv->routes);
priv->addresses = nm_platform_ip4_address_get_all (platform, ifindex);
g_array_sort (priv->addresses, sort_captured_addresses);
priv->routes = nm_platform_ip4_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
pl_head_entry = nm_platform_lookup_route_visible (platform,
NMP_OBJECT_TYPE_IP4_ROUTE,
ifindex,
FALSE);
/* Extract gateway from default route */
old_gateway = priv->gateway;
old_has_gateway = priv->has_gateway;
for (i = 0; i < priv->routes->len; ) {
const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
lowest_metric = G_MAXUINT32;
priv->has_gateway = FALSE;
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj);
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)
&& route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) {
if (route->metric < lowest_metric) {
priv->gateway = route->gateway;
lowest_metric = route->metric;
}
priv->has_gateway = TRUE;
/* Remove the default route from the list */
g_array_remove_index_fast (priv->routes, i);
continue;
}
i++;
}
/* we detect the route metric based on the default route. All non-default
* routes have their route metrics explicitly set. */
priv->route_metric = priv->has_gateway ? (gint64) lowest_metric : (gint64) -1;
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
if (priv->has_gateway) {
for (i = 0; i < priv->routes->len; i++) {
const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i);
nm_dedup_multi_iter_rewind (&iter);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj);
if ( (route->plen == 32)
&& (route->network == priv->gateway)
&& (route->gateway == 0)) {
g_array_remove_index (priv->routes, i);
i--;
}
if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
if ( priv->has_gateway
&& route->plen == 32
&& route->network == priv->gateway
&& route->gateway == 0) {
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
continue;
}
_add_route (config, plobj, NULL);
}
/* If the interface has the default route, and has IPv4 addresses, capture
@ -357,11 +500,15 @@ nm_ip4_config_commit (const NMIP4Config *config, NMPlatform *platform, NMRouteMa
/* Routes */
{
const NMDedupMultiHeadEntry *head_entry;
guint i;
guint count = nm_ip4_config_get_num_routes (config);
GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), count);
gboolean success;
gs_unref_array GArray *routes = NULL;
gs_unref_array GArray *device_route_purge_list = NULL;
const CList *iter;
head_entry = _idx_ip4_routes (config);
routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), head_entry ? head_entry->len : 0);
if ( default_route_metric >= 0
&& added_addresses) {
@ -404,20 +551,15 @@ nm_ip4_config_commit (const NMIP4Config *config, NMPlatform *platform, NMRouteMa
}
}
for (i = 0; i < count; i++) {
const NMPlatformIP4Route *route;
route = nm_ip4_config_get_route (config, i);
/* duplicates in @routes are no problem as route-manager handles them
* gracefully (by ignoring them). */
g_array_append_vals (routes, route, 1);
if (head_entry) {
c_list_for_each (iter, &head_entry->lst_entries_head)
g_array_append_vals (routes, _entry_iter_get_ip4_route (iter), 1);
}
nm_route_manager_ip4_route_register_device_route_purge_list (route_manager, device_route_purge_list);
success = nm_route_manager_ip4_route_sync (route_manager, ifindex, routes, default_route_metric < 0, routes_full_sync);
g_array_unref (routes);
if (!success)
if (!nm_route_manager_ip4_route_sync (route_manager, ifindex, routes,
default_route_metric < 0, routes_full_sync))
return FALSE;
}
@ -537,7 +679,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
merge_route_attributes (s_route, &route);
nm_ip4_config_add_route (config, &route);
_add_route (config, NULL, &route);
}
/* DNS */
@ -573,10 +715,12 @@ nm_ip4_config_create_setting (const NMIP4Config *config)
{
NMSettingIPConfig *s_ip4;
guint32 gateway;
guint naddresses, nroutes, nnameservers, nsearches, noptions;
guint naddresses, nnameservers, nsearches, noptions;
const char *method = NULL;
int i;
gint64 route_metric;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Route *route;
s_ip4 = NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new ());
@ -589,7 +733,6 @@ nm_ip4_config_create_setting (const NMIP4Config *config)
gateway = nm_ip4_config_get_gateway (config);
naddresses = nm_ip4_config_get_num_addresses (config);
nroutes = nm_ip4_config_get_num_routes (config);
nnameservers = nm_ip4_config_get_num_nameservers (config);
nsearches = nm_ip4_config_get_num_searches (config);
noptions = nm_ip4_config_get_num_dns_options (config);
@ -636,8 +779,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config)
NULL);
/* Routes */
for (i = 0; i < nroutes; i++) {
const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, config, &route) {
NMIPRoute *s_route;
/* Ignore default route. */
@ -690,6 +832,7 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl
NMIP4ConfigPrivate *dst_priv;
const NMIP4ConfigPrivate *src_priv;
guint32 i;
NMDedupMultiIter ipconf_iter;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
@ -715,8 +858,10 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl
/* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
for (i = 0; i < nm_ip4_config_get_num_routes (src); i++)
nm_ip4_config_add_route (dst, nm_ip4_config_get_route (src, i));
const NMPlatformIP4Route *route;
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, src, &route)
_add_route (dst, NMP_OBJECT_UP_CAST (route), NULL);
}
if (dst_priv->route_metric == -1)
@ -811,22 +956,6 @@ _nameservers_get_index (const NMIP4Config *self, guint32 ns)
return -1;
}
static int
_routes_get_index (const NMIP4Config *self, const NMPlatformIP4Route *route)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
guint i;
for (i = 0; i < priv->routes->len; i++) {
const NMPlatformIP4Route *r = &g_array_index (priv->routes, NMPlatformIP4Route, i);
if ( route->network == r->network
&& route->plen == r->plen)
return (int) i;
}
return -1;
}
static int
_domains_get_index (const NMIP4Config *self, const char *domain)
{
@ -914,12 +1043,17 @@ _wins_get_index (const NMIP4Config *self, guint32 wins_server)
void
nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
{
guint32 i;
NMIP4ConfigPrivate *priv_dst;
guint i;
gint idx;
const NMPlatformIP4Route *r;
NMDedupMultiIter ipconf_iter;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
priv_dst = NM_IP4_CONFIG_GET_PRIVATE (dst);
g_object_freeze_notify (G_OBJECT (dst));
/* addresses */
@ -947,10 +1081,10 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
/* ignore route_metric */
/* routes */
for (i = 0; i < nm_ip4_config_get_num_routes (src); i++) {
idx = _routes_get_index (dst, nm_ip4_config_get_route (src, i));
if (idx >= 0)
nm_ip4_config_del_route (dst, idx);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) {
nm_dedup_multi_index_remove_obj (priv_dst->multi_idx,
&priv_dst->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r));
}
/* domains */
@ -1010,14 +1144,21 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
void
nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
{
guint32 i;
NMIP4ConfigPrivate *priv_dst;
const NMIP4ConfigPrivate *priv_src;
guint i;
gint idx;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Route *r;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
g_return_if_fail (src);
g_return_if_fail (dst);
g_object_freeze_notify (G_OBJECT (dst));
priv_dst = NM_IP4_CONFIG_GET_PRIVATE (dst);
priv_src = NM_IP4_CONFIG_GET_PRIVATE (src);
/* addresses */
for (i = 0; i < nm_ip4_config_get_num_addresses (dst); ) {
idx = _addresses_get_index (src, nm_ip4_config_get_address (dst, i));
@ -1038,12 +1179,15 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src)
}
/* routes */
for (i = 0; i < nm_ip4_config_get_num_routes (dst); ) {
idx = _routes_get_index (src, nm_ip4_config_get_route (dst, i));
if (idx < 0)
nm_ip4_config_del_route (dst, i);
else
i++;
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) {
if (nm_dedup_multi_index_lookup_obj (priv_src->multi_idx,
&priv_src->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r)))
continue;
if (nm_dedup_multi_index_remove_entry (priv_dst->multi_idx,
ipconf_iter.current) != 1)
nm_assert_not_reached ();
}
/* ignore domains */
@ -1081,7 +1225,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
NMIP4ConfigPrivate *dst_priv;
const NMIP4ConfigPrivate *src_priv;
const NMPlatformIP4Address *dst_addr, *src_addr;
const NMPlatformIP4Route *dst_route, *src_route;
NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst;
g_return_val_if_fail (src != NULL, FALSE);
g_return_val_if_fail (dst != NULL, FALSE);
@ -1148,26 +1292,45 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
}
/* routes */
num = nm_ip4_config_get_num_routes (src);
are_equal = num == nm_ip4_config_get_num_routes (dst);
if (are_equal) {
for (i = 0; i < num; i++ ) {
if (nm_platform_ip4_route_cmp (src_route = nm_ip4_config_get_route (src, i),
dst_route = nm_ip4_config_get_route (dst, i))) {
are_equal = FALSE;
if (!routes_are_duplicate (src_route, dst_route, TRUE)) {
has_relevant_changes = TRUE;
break;
}
nm_ip4_config_iter_ip4_route_init (&ipconf_iter_src, src);
nm_ip4_config_iter_ip4_route_init (&ipconf_iter_dst, dst);
are_equal = TRUE;
while (TRUE) {
gboolean has;
const NMPlatformIP4Route *r_src, *r_dst;
has = nm_ip4_config_iter_ip4_route_next (&ipconf_iter_src, &r_src);
if (has != nm_ip4_config_iter_ip4_route_next (&ipconf_iter_dst, &r_dst)) {
are_equal = FALSE;
has_relevant_changes = TRUE;
break;
}
if (!has)
break;
if (nm_platform_ip4_route_cmp (r_src, r_dst) != 0) {
are_equal = FALSE;
if (!nm_ip_config_obj_id_equal_ip4_route (r_src, r_dst)) {
has_relevant_changes = TRUE;
break;
}
}
} else
has_relevant_changes = TRUE;
}
if (!are_equal) {
nm_ip4_config_reset_routes (dst);
for (i = 0; i < num; i++)
nm_ip4_config_add_route (dst, nm_ip4_config_get_route (src, i));
const NMPlatformIP4Route *r_src;
has_minor_changes = TRUE;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes);
nm_dedup_multi_iter_rewind (&ipconf_iter_src);
while (nm_ip4_config_iter_ip4_route_next (&ipconf_iter_src, &r_src)) {
nm_dedup_multi_index_add (dst_priv->multi_idx,
&dst_priv->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r_src),
NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE,
NULL,
NULL);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, FALSE);
}
/* nameservers */
@ -1329,8 +1492,11 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
void
nm_ip4_config_dump (const NMIP4Config *config, const char *detail)
{
guint32 i, tmp;
guint32 tmp;
guint i;
const char *str;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Route *route;
g_message ("--------- NMIP4Config %p (%s)", config, detail);
@ -1360,8 +1526,8 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail)
}
/* routes */
for (i = 0; i < nm_ip4_config_get_num_routes (config); i++)
g_message (" rt: %s", nm_platform_ip4_route_to_string (nm_ip4_config_get_route (config, i), NULL, 0));
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, config, &route)
g_message (" rt: %s", nm_platform_ip4_route_to_string (route, NULL, 0));
/* domains */
for (i = 0; i < nm_ip4_config_get_num_domains (config); i++)
@ -1611,13 +1777,84 @@ nm_ip4_config_reset_routes (NMIP4Config *config)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
if (priv->routes->len != 0) {
g_array_set_size (priv->routes, 0);
if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
&priv->idx_ip4_routes) > 0) {
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
}
}
static void
_add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Route *new)
{
NMIP4ConfigPrivate *priv;
NMPObject o_new_storage;
nm_auto_nmpobj const NMPObject *obj_old = NULL;
nm_assert (NM_IS_IP4_CONFIG (config));
priv = NM_IP4_CONFIG_GET_PRIVATE (config);
nm_assert (priv->ifindex > 0);
/* we go through extra lengths to accept a full o_new object. That one,
* can be reused by increasing the ref-count. */
if (!o_new) {
nm_assert (new);
nm_assert (new->plen > 0 && new->plen <= 32);
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP4_ROUTE,
(const NMPlatformObject *) new);
o_new_storage.ip4_route.ifindex = priv->ifindex;
o_new = &o_new_storage;
} else {
nm_assert (!new);
nm_assert (NMP_OBJECT_GET_TYPE (o_new) == NMP_OBJECT_TYPE_IP4_ROUTE);
nm_assert (o_new->ip4_route.plen > 0 && o_new->ip4_route.plen <= 32);
if (o_new->ip4_route.ifindex != priv->ifindex) {
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP4_ROUTE, &o_new->object);
o_new_storage.ip4_route.ifindex = priv->ifindex;
o_new = &o_new_storage;
}
}
if (!nm_dedup_multi_index_add (priv->multi_idx,
&priv->idx_ip4_routes,
o_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
NULL,
&obj_old))
return;
if (obj_old) {
NMIPConfigSource old_source;
old_source = obj_old->ip_route.rt_source;
/* we want to keep the maximum rt_source. But since we expect
* that usually we already add the maxiumum right away, we first try to
* add the new route (replacing the old one). Only if we later
* find out that rt_source is now lower, we fix it.
*/
if (o_new->ip_route.rt_source < old_source) {
if (o_new != &o_new_storage) {
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP4_ROUTE,
&o_new->object);
o_new = &o_new_storage;
}
o_new_storage.ip_route.rt_source = old_source;
if (!nm_dedup_multi_index_add (priv->multi_idx,
&priv->idx_ip4_routes,
o_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
NULL,
NULL))
nm_assert_not_reached ();
}
}
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
}
/**
* nm_ip4_config_add_route:
* @config: the #NMIP4Config
@ -1631,76 +1868,70 @@ nm_ip4_config_reset_routes (NMIP4Config *config)
void
nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
NMIPConfigSource old_source;
int i;
g_return_if_fail (new != NULL);
g_return_if_fail (config);
g_return_if_fail (new);
g_return_if_fail (new->plen > 0 && new->plen <= 32);
g_return_if_fail (priv->ifindex > 0);
g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (config)->ifindex > 0);
for (i = 0; i < priv->routes->len; i++ ) {
NMPlatformIP4Route *item = &g_array_index (priv->routes, NMPlatformIP4Route, i);
if (routes_are_duplicate (item, new, FALSE)) {
if (nm_platform_ip4_route_cmp (item, new) == 0)
return;
old_source = item->rt_source;
memcpy (item, new, sizeof (*item));
/* Restore highest priority source */
item->rt_source = MAX (old_source, new->rt_source);
item->ifindex = priv->ifindex;
goto NOTIFY;
}
}
g_array_append_val (priv->routes, *new);
g_array_index (priv->routes, NMPlatformIP4Route, priv->routes->len - 1).ifindex = priv->ifindex;
NOTIFY:
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
_add_route (config, NULL, new);
}
void
nm_ip4_config_del_route (NMIP4Config *config, guint i)
_nmtst_nm_ip4_config_del_route (NMIP4Config *self, guint i)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
const NMPlatformIP4Route *r;
g_return_if_fail (i < priv->routes->len);
r = _nmtst_nm_ip4_config_get_route (self, i);
g_return_if_fail (r);
g_array_remove_index (priv->routes, i);
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
&priv->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r)) != 1)
g_return_if_reached ();
_notify (self, PROP_ROUTE_DATA);
_notify (self, PROP_ROUTES);
}
guint
nm_ip4_config_get_num_routes (const NMIP4Config *config)
nm_ip4_config_get_num_routes (const NMIP4Config *self)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
const NMDedupMultiHeadEntry *head_entry;
return priv->routes->len;
head_entry = _idx_ip4_routes (self);
nm_assert ((head_entry ? head_entry->len : 0) == c_list_length (&head_entry->lst_entries_head));
return head_entry ? head_entry->len : 0;
}
const NMPlatformIP4Route *
nm_ip4_config_get_route (const NMIP4Config *config, guint i)
_nmtst_nm_ip4_config_get_route (const NMIP4Config *self, guint i)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
const NMDedupMultiHeadEntry *head_entry;
CList *iter;
guint j;
return &g_array_index (priv->routes, NMPlatformIP4Route, i);
head_entry = _idx_ip4_routes (self);
if (head_entry) {
j = 0;
c_list_for_each (iter, &head_entry->lst_entries_head) {
if (i == j)
return _entry_iter_get_ip4_route (iter);
j++;
}
}
g_return_val_if_reached (NULL);
}
const NMPlatformIP4Route *
nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host)
nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, guint32 host)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
guint i;
NMPlatformIP4Route *best_route = NULL;
const NMPlatformIP4Route *best_route = NULL;
const NMPlatformIP4Route *item;
NMDedupMultiIter ipconf_iter;
g_return_val_if_fail (host, NULL);
for (i = 0; i < priv->routes->len; i++) {
NMPlatformIP4Route *item = &g_array_index (priv->routes, NMPlatformIP4Route, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, self, &item) {
if (item->gateway != 0)
continue;
@ -1715,7 +1946,6 @@ nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host
best_route = item;
}
return best_route;
}
@ -2183,6 +2413,8 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only
{
guint i;
const char *s;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Route *route;
g_return_if_fail (config);
g_return_if_fail (sum);
@ -2198,9 +2430,8 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only
hash_u32 (sum, address->peer_address & nm_utils_ip4_prefix_to_netmask (address->plen));
}
for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) {
const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, config, &route) {
hash_u32 (sum, route->network);
hash_u32 (sum, route->plen);
hash_u32 (sum, route->gateway);
@ -2285,6 +2516,9 @@ get_property (GObject *object, guint prop_id,
{
NMIP4Config *config = NM_IP4_CONFIG (object);
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Route *route;
GVariantBuilder array_builder, addr_builder, route_builder;
switch (prop_id) {
case PROP_IFINDEX:
@ -2293,7 +2527,6 @@ get_property (GObject *object, guint prop_id,
case PROP_ADDRESS_DATA:
case PROP_ADDRESSES:
{
GVariantBuilder array_builder, addr_builder;
gs_unref_array GArray *new = NULL;
guint naddr, i;
@ -2360,14 +2593,8 @@ return_cached:
break;
case PROP_ROUTE_DATA:
{
GVariantBuilder array_builder, route_builder;
guint nroutes = nm_ip4_config_get_num_routes (config);
guint i;
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}"));
for (i = 0; i < nroutes; i++) {
const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, config, &route) {
g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&route_builder, "{sv}",
"dest",
@ -2392,13 +2619,8 @@ return_cached:
break;
case PROP_ROUTES:
{
GVariantBuilder array_builder;
guint nroutes = nm_ip4_config_get_num_routes (config);
guint i;
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau"));
for (i = 0; i < nroutes; i++) {
const NMPlatformIP4Route *route = nm_ip4_config_get_route (config, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, config, &route) {
guint32 dbus_route[4];
/* legacy versions of nm_ip4_route_set_prefix() in libnm-util assert that the
@ -2467,6 +2689,13 @@ set_property (GObject *object,
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
switch (prop_id) {
case PROP_MULTI_IDX:
/* construct-only */
priv->multi_idx = g_value_get_pointer (value);
if (!priv->multi_idx)
g_return_if_reached ();
nm_dedup_multi_index_ref (priv->multi_idx);
break;
case PROP_IFINDEX:
/* construct-only */
priv->ifindex = g_value_get_int (value);
@ -2484,8 +2713,10 @@ nm_ip4_config_init (NMIP4Config *config)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
nm_ip_config_dedup_multi_idx_type_init ((NMIPConfigDedupMultiIdxType *) &priv->idx_ip4_routes,
NMP_OBJECT_TYPE_IP4_ROUTE);
priv->addresses = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Address));
priv->routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
priv->nameservers = g_array_new (FALSE, FALSE, sizeof (guint32));
priv->domains = g_ptr_array_new_with_free_func (g_free);
priv->searches = g_ptr_array_new_with_free_func (g_free);
@ -2496,10 +2727,11 @@ nm_ip4_config_init (NMIP4Config *config)
}
NMIP4Config *
nm_ip4_config_new (int ifindex)
nm_ip4_config_new (NMDedupMultiIndex *multi_idx, int ifindex)
{
g_return_val_if_fail (ifindex >= -1, NULL);
return (NMIP4Config *) g_object_new (NM_TYPE_IP4_CONFIG,
NM_IP4_CONFIG_MULTI_IDX, multi_idx,
NM_IP4_CONFIG_IFINDEX, ifindex,
NULL);
}
@ -2510,10 +2742,11 @@ finalize (GObject *object)
NMIP4Config *self = NM_IP4_CONFIG (object);
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip4_routes);
nm_clear_g_variant (&priv->address_data_variant);
nm_clear_g_variant (&priv->addresses_variant);
g_array_unref (priv->addresses);
g_array_unref (priv->routes);
g_array_unref (priv->nameservers);
g_ptr_array_unref (priv->domains);
g_ptr_array_unref (priv->searches);
@ -2523,6 +2756,8 @@ finalize (GObject *object)
g_array_unref (priv->wins);
G_OBJECT_CLASS (nm_ip4_config_parent_class)->finalize (object);
nm_dedup_multi_index_unref (priv->multi_idx);
}
static void
@ -2537,6 +2772,11 @@ nm_ip4_config_class_init (NMIP4ConfigClass *config_class)
object_class->set_property = set_property;
object_class->finalize = finalize;
obj_properties[PROP_MULTI_IDX] =
g_param_spec_pointer (NM_IP4_CONFIG_MULTI_IDX, "", "",
G_PARAM_WRITABLE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS);
obj_properties[PROP_IFINDEX] =
g_param_spec_int (NM_IP4_CONFIG_IFINDEX, "", "",
-1, G_MAXINT, -1,

View file

@ -24,6 +24,32 @@
#include "nm-exported-object.h"
#include "nm-setting-ip4-config.h"
#include "nm-utils/nm-dedup-multi.h"
/*****************************************************************************/
typedef struct {
NMDedupMultiIdxType parent;
NMPObjectType obj_type;
} NMIPConfigDedupMultiIdxType;
void nm_ip_config_dedup_multi_idx_type_init (NMIPConfigDedupMultiIdxType *idx_type, NMPObjectType obj_type);
void nm_ip4_config_iter_ip4_route_init (NMDedupMultiIter *iter, const NMIP4Config *self);
gboolean nm_ip4_config_iter_ip4_route_next (NMDedupMultiIter *iter, const NMPlatformIP4Route **out_route);
#define nm_ip4_config_iter_ip4_route_for_each(iter, self, route) \
for (nm_ip4_config_iter_ip4_route_init ((iter), (self)); \
nm_ip4_config_iter_ip4_route_next ((iter), (route)); \
)
gboolean nm_ip_config_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a,
const NMPlatformIP4Route *r_b);
gboolean nm_ip_config_obj_id_equal_ip6_route (const NMPlatformIP6Route *r_a,
const NMPlatformIP6Route *r_b);
/*****************************************************************************/
#define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type ())
#define NM_IP4_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IP4_CONFIG, NMIP4Config))
#define NM_IP4_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IP4_CONFIG, NMIP4ConfigClass))
@ -34,6 +60,7 @@
typedef struct _NMIP4ConfigClass NMIP4ConfigClass;
/* internal */
#define NM_IP4_CONFIG_MULTI_IDX "multi-idx"
#define NM_IP4_CONFIG_IFINDEX "ifindex"
/* public*/
@ -54,12 +81,14 @@ typedef struct _NMIP4ConfigClass NMIP4ConfigClass;
GType nm_ip4_config_get_type (void);
NMIP4Config * nm_ip4_config_new (int ifindex);
NMIP4Config * nm_ip4_config_new (NMDedupMultiIndex *multi_idx,
int ifindex);
int nm_ip4_config_get_ifindex (const NMIP4Config *config);
NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self);
NMIP4Config *nm_ip4_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf);
NMIP4Config *nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf);
gboolean nm_ip4_config_commit (const NMIP4Config *config, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric);
void nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip4_config_create_setting (const NMIP4Config *config);
@ -90,9 +119,9 @@ gboolean nm_ip4_config_address_exists (const NMIP4Config *config, const NMPlatfo
void nm_ip4_config_reset_routes (NMIP4Config *config);
void nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *route);
void nm_ip4_config_del_route (NMIP4Config *config, guint i);
void _nmtst_nm_ip4_config_del_route (NMIP4Config *config, guint i);
guint nm_ip4_config_get_num_routes (const NMIP4Config *config);
const NMPlatformIP4Route *nm_ip4_config_get_route (const NMIP4Config *config, guint i);
const NMPlatformIP4Route *_nmtst_nm_ip4_config_get_route (const NMIP4Config *config, guint i);
const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host);

View file

@ -26,12 +26,16 @@
#include <string.h>
#include <arpa/inet.h>
#include "nm-utils/nm-dedup-multi.h"
#include "nm-utils.h"
#include "platform/nmp-object.h"
#include "platform/nm-platform.h"
#include "platform/nm-platform-utils.h"
#include "nm-route-manager.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
#include "nm-ip4-config.h"
#include "introspection/org.freedesktop.NetworkManager.IP6Config.h"
@ -46,13 +50,14 @@ typedef struct {
gint64 route_metric;
struct in6_addr gateway;
GArray *addresses;
GArray *routes;
GArray *nameservers;
GPtrArray *domains;
GPtrArray *searches;
GPtrArray *dns_options;
GVariant *address_data_variant;
GVariant *addresses_variant;
NMDedupMultiIndex *multi_idx;
NMDedupMultiIdxType idx_ip6_routes;
} NMIP6ConfigPrivate;
struct _NMIP6Config {
@ -69,6 +74,7 @@ G_DEFINE_TYPE (NMIP6Config, nm_ip6_config, NM_TYPE_EXPORTED_OBJECT)
#define NM_IP6_CONFIG_GET_PRIVATE(self) _NM_GET_PRIVATE(self, NMIP6Config, NM_IS_IP6_CONFIG)
NM_GOBJECT_PROPERTIES_DEFINE (NMIP6Config,
PROP_MULTI_IDX,
PROP_IFINDEX,
PROP_ADDRESS_DATA,
PROP_ADDRESSES,
@ -84,12 +90,22 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP6Config,
/*****************************************************************************/
static void _add_route (NMIP6Config *config, const NMPObject *o_new, const NMPlatformIP6Route *new);
/*****************************************************************************/
int
nm_ip6_config_get_ifindex (const NMIP6Config *config)
{
return NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex;
}
NMDedupMultiIndex *
nm_ip6_config_get_multi_idx (const NMIP6Config *config)
{
return NM_IP6_CONFIG_GET_PRIVATE (config)->multi_idx;
}
void
nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privacy)
{
@ -100,6 +116,49 @@ nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privac
/*****************************************************************************/
static const NMDedupMultiHeadEntry *
_idx_ip6_routes (const NMIP6Config *self)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
return nm_dedup_multi_index_lookup_head (priv->multi_idx,
&priv->idx_ip6_routes,
NULL);
}
static const NMPlatformIP6Route *
_entry_iter_get_ip6_route (const CList *iter)
{
const NMDedupMultiEntry *e = c_list_entry (iter, NMDedupMultiEntry, lst_entries);
const NMPObject *o = e->obj;
nm_assert (o);
nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_TYPE_IP6_ROUTE);
return &o->ip6_route;
}
void
nm_ip6_config_iter_ip6_route_init (NMDedupMultiIter *ipconf_iter, const NMIP6Config *self)
{
g_return_if_fail (NM_IS_IP6_CONFIG (self));
nm_dedup_multi_iter_init (ipconf_iter, _idx_ip6_routes (self));
}
gboolean
nm_ip6_config_iter_ip6_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Route **out_route)
{
gboolean has_next;
has_next = nm_dedup_multi_iter_next (ipconf_iter);
if (has_next) {
nm_assert (NMP_OBJECT_GET_TYPE (ipconf_iter->current->obj) == NMP_OBJECT_TYPE_IP6_ROUTE);
NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->obj)->ip6_route));
}
return has_next;
}
/*****************************************************************************/
static void
notify_addresses (NMIP6Config *self)
{
@ -183,15 +242,6 @@ addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Addre
return IN6_ARE_ADDR_EQUAL (&a->address, &b->address);
}
static gboolean
routes_are_duplicate (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_gateway_and_metric)
{
return IN6_ARE_ADDR_EQUAL (&a->network, &b->network) && a->plen == b->plen &&
( !consider_gateway_and_metric
|| ( IN6_ARE_ADDR_EQUAL (&a->gateway, &b->gateway)
&& nm_utils_ip6_route_metric_normalize (a->metric) == nm_utils_ip6_route_metric_normalize (b->metric)));
}
static gint
_addresses_sort_cmp_get_prio (const struct in6_addr *addr)
{
@ -301,65 +351,75 @@ nm_ip6_config_addresses_sort (NMIP6Config *self)
}
NMIP6Config *
nm_ip6_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary)
nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary)
{
NMIP6Config *config;
NMIP6ConfigPrivate *priv;
guint i;
guint32 lowest_metric = G_MAXUINT32;
struct in6_addr old_gateway = IN6ADDR_ANY_INIT;
gboolean has_gateway = FALSE;
gboolean has_gateway;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
gboolean notify_nameservers = FALSE;
/* Slaves have no IP configuration */
if (nm_platform_link_get_master (platform, ifindex) > 0)
return NULL;
config = nm_ip6_config_new (ifindex);
config = nm_ip6_config_new (multi_idx, ifindex);
priv = NM_IP6_CONFIG_GET_PRIVATE (config);
g_array_unref (priv->addresses);
g_array_unref (priv->routes);
priv->addresses = nm_platform_ip6_address_get_all (platform, ifindex);
priv->routes = nm_platform_ip6_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
pl_head_entry = nm_platform_lookup_route_visible (platform,
NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex,
FALSE);
/* Extract gateway from default route */
old_gateway = priv->gateway;
for (i = 0; i < priv->routes->len; ) {
const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
lowest_metric = G_MAXUINT32;
has_gateway = FALSE;
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj);
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)
&& route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) {
if (route->metric < lowest_metric) {
priv->gateway = route->gateway;
lowest_metric = route->metric;
}
has_gateway = TRUE;
/* Remove the default route from the list */
g_array_remove_index_fast (priv->routes, i);
continue;
}
i++;
}
/* we detect the route metric based on the default route. All non-default
* routes have their route metrics explicitly set. */
priv->route_metric = has_gateway ? (gint64) lowest_metric : (gint64) -1;
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
if (has_gateway) {
for (i = 0; i < priv->routes->len; i++) {
const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i);
nm_dedup_multi_iter_rewind (&iter);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj);
if ( route->plen == 128
&& IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway)
&& IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) {
g_array_remove_index (priv->routes, i);
i--;
}
if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
if ( has_gateway
&& route->plen == 128
&& IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway)
&& IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) {
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
continue;
}
_add_route (config, plobj, NULL);
}
/* If the interface has the default route, and has IPv6 addresses, capture
@ -393,7 +453,6 @@ nm_ip6_config_commit (const NMIP6Config *config,
gboolean routes_full_sync)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
gboolean success;
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (config != NULL, FALSE);
@ -403,21 +462,24 @@ nm_ip6_config_commit (const NMIP6Config *config,
/* Routes */
{
guint i;
guint count = nm_ip6_config_get_num_routes (config);
GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), count);
const NMPlatformIP6Route *route;
const NMDedupMultiHeadEntry *head_entry;
gs_unref_array GArray *routes = NULL;
const CList *iter;
for (i = 0; i < count; i++) {
route = nm_ip6_config_get_route (config, i);
g_array_append_vals (routes, route, 1);
head_entry = _idx_ip6_routes (config);
routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), head_entry ? head_entry->len : 0);
if (head_entry) {
c_list_for_each (iter, &head_entry->lst_entries_head)
g_array_append_vals (routes, _entry_iter_get_ip6_route (iter), 1);
}
success = nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync);
g_array_unref (routes);
if (!nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync))
return FALSE;
}
return success;
return TRUE;
}
static void
@ -548,7 +610,7 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
merge_route_attributes (s_route, &route);
nm_ip6_config_add_route (config, &route);
_add_route (config, NULL, &route);
}
/* DNS */
@ -584,10 +646,12 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
{
NMSettingIPConfig *s_ip6;
const struct in6_addr *gateway;
guint naddresses, nroutes, nnameservers, nsearches, noptions;
guint naddresses, nnameservers, nsearches, noptions;
const char *method = NULL;
int i;
gint64 route_metric;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
s_ip6 = NM_SETTING_IP_CONFIG (nm_setting_ip6_config_new ());
@ -600,7 +664,6 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
gateway = nm_ip6_config_get_gateway (config);
naddresses = nm_ip6_config_get_num_addresses (config);
nroutes = nm_ip6_config_get_num_routes (config);
nnameservers = nm_ip6_config_get_num_nameservers (config);
nsearches = nm_ip6_config_get_num_searches (config);
noptions = nm_ip6_config_get_num_dns_options (config);
@ -651,8 +714,7 @@ nm_ip6_config_create_setting (const NMIP6Config *config)
NULL);
/* Routes */
for (i = 0; i < nroutes; i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) {
NMIPRoute *s_route;
/* Ignore link-local route. */
@ -708,6 +770,7 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
NMIP6ConfigPrivate *dst_priv;
const NMIP6ConfigPrivate *src_priv;
guint32 i;
NMDedupMultiIter ipconf_iter;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
@ -733,8 +796,10 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl
/* routes */
if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) {
for (i = 0; i < nm_ip6_config_get_num_routes (src); i++)
nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i));
const NMPlatformIP6Route *route;
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, src, &route)
_add_route (dst, NMP_OBJECT_UP_CAST (route), NULL);
}
if (dst_priv->route_metric == -1)
@ -823,21 +888,6 @@ _nameservers_get_index (const NMIP6Config *self, const struct in6_addr *ns)
return -1;
}
static int
_routes_get_index (const NMIP6Config *self, const NMPlatformIP6Route *route)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
guint i;
for (i = 0; i < priv->routes->len; i++) {
const NMPlatformIP6Route *r = &g_array_index (priv->routes, NMPlatformIP6Route, i);
if (routes_are_duplicate (route, r, FALSE))
return (int) i;
}
return -1;
}
static int
_domains_get_index (const NMIP6Config *self, const char *domain)
{
@ -895,13 +945,18 @@ _dns_options_get_index (const NMIP6Config *self, const char *option)
void
nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
{
NMIP6ConfigPrivate *priv_dst;
guint i;
gint idx;
const NMPlatformIP6Route *r;
NMDedupMultiIter ipconf_iter;
const struct in6_addr *dst_tmp, *src_tmp;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
priv_dst = NM_IP6_CONFIG_GET_PRIVATE (dst);
g_object_freeze_notify (G_OBJECT (dst));
/* addresses */
@ -930,10 +985,10 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
/* ignore route_metric */
/* routes */
for (i = 0; i < nm_ip6_config_get_num_routes (src); i++) {
idx = _routes_get_index (dst, nm_ip6_config_get_route (src, i));
if (idx >= 0)
nm_ip6_config_del_route (dst, idx);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) {
nm_dedup_multi_index_remove_obj (priv_dst->multi_idx,
&priv_dst->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r));
}
/* domains */
@ -970,12 +1025,19 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
void
nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
{
NMIP6ConfigPrivate *priv_dst;
const NMIP6ConfigPrivate *priv_src;
guint i;
gint idx;
const struct in6_addr *dst_tmp, *src_tmp;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *r;
g_return_if_fail (src != NULL);
g_return_if_fail (dst != NULL);
g_return_if_fail (src);
g_return_if_fail (dst);
priv_dst = NM_IP6_CONFIG_GET_PRIVATE (dst);
priv_src = NM_IP6_CONFIG_GET_PRIVATE (src);
g_object_freeze_notify (G_OBJECT (dst));
@ -1002,12 +1064,15 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src)
}
/* routes */
for (i = 0; i < nm_ip6_config_get_num_routes (dst); ) {
idx = _routes_get_index (src, nm_ip6_config_get_route (dst, i));
if (idx < 0)
nm_ip6_config_del_route (dst, i);
else
i++;
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) {
if (nm_dedup_multi_index_lookup_obj (priv_src->multi_idx,
&priv_src->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r)))
continue;
if (nm_dedup_multi_index_remove_entry (priv_dst->multi_idx,
ipconf_iter.current) != 1)
nm_assert_not_reached ();
}
/* ignore domains */
@ -1042,7 +1107,7 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
NMIP6ConfigPrivate *dst_priv;
const NMIP6ConfigPrivate *src_priv;
const NMPlatformIP6Address *dst_addr, *src_addr;
const NMPlatformIP6Route *dst_route, *src_route;
NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst;
g_return_val_if_fail (NM_IS_IP6_CONFIG (src), FALSE);
g_return_val_if_fail (NM_IS_IP6_CONFIG (dst), FALSE);
@ -1107,26 +1172,45 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
}
/* routes */
num = nm_ip6_config_get_num_routes (src);
are_equal = num == nm_ip6_config_get_num_routes (dst);
if (are_equal) {
for (i = 0; i < num; i++ ) {
if (nm_platform_ip6_route_cmp (src_route = nm_ip6_config_get_route (src, i),
dst_route = nm_ip6_config_get_route (dst, i))) {
are_equal = FALSE;
if (!routes_are_duplicate (src_route, dst_route, TRUE)) {
has_relevant_changes = TRUE;
break;
}
nm_ip6_config_iter_ip6_route_init (&ipconf_iter_src, src);
nm_ip6_config_iter_ip6_route_init (&ipconf_iter_dst, dst);
are_equal = TRUE;
while (TRUE) {
gboolean has;
const NMPlatformIP6Route *r_src, *r_dst;
has = nm_ip6_config_iter_ip6_route_next (&ipconf_iter_src, &r_src);
if (has != nm_ip6_config_iter_ip6_route_next (&ipconf_iter_dst, &r_dst)) {
are_equal = FALSE;
has_relevant_changes = TRUE;
break;
}
if (!has)
break;
if (nm_platform_ip6_route_cmp (r_src, r_dst) != 0) {
are_equal = FALSE;
if (!nm_ip_config_obj_id_equal_ip6_route (r_src, r_dst)) {
has_relevant_changes = TRUE;
break;
}
}
} else
has_relevant_changes = TRUE;
}
if (!are_equal) {
nm_ip6_config_reset_routes (dst);
for (i = 0; i < num; i++)
nm_ip6_config_add_route (dst, nm_ip6_config_get_route (src, i));
const NMPlatformIP6Route *r_src;
has_minor_changes = TRUE;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes);
nm_dedup_multi_iter_rewind (&ipconf_iter_src);
while (nm_ip6_config_iter_ip6_route_next (&ipconf_iter_src, &r_src)) {
nm_dedup_multi_index_add (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r_src),
NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE,
NULL,
NULL);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE);
}
/* nameservers */
@ -1242,6 +1326,8 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail)
const struct in6_addr *tmp;
guint32 i;
const char *str;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
g_return_if_fail (config != NULL);
@ -1267,8 +1353,8 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail)
}
/* routes */
for (i = 0; i < nm_ip6_config_get_num_routes (config); i++)
g_message (" rt: %s", nm_platform_ip6_route_to_string (nm_ip6_config_get_route (config, i), NULL, 0));
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route)
g_message (" rt: %s", nm_platform_ip6_route_to_string (route, NULL, 0));
/* domains */
for (i = 0; i < nm_ip6_config_get_num_domains (config); i++)
@ -1514,13 +1600,84 @@ nm_ip6_config_reset_routes (NMIP6Config *config)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
if (priv->routes->len != 0) {
g_array_set_size (priv->routes, 0);
if (nm_dedup_multi_index_remove_idx (priv->multi_idx,
&priv->idx_ip6_routes) > 0) {
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
}
}
static void
_add_route (NMIP6Config *config, const NMPObject *o_new, const NMPlatformIP6Route *new)
{
NMIP6ConfigPrivate *priv;
NMPObject o_new_storage;
nm_auto_nmpobj const NMPObject *obj_old = NULL;
nm_assert (NM_IS_IP6_CONFIG (config));
priv = NM_IP6_CONFIG_GET_PRIVATE (config);
nm_assert (priv->ifindex > 0);
/* we go through extra lengths to accept a full o_new object. That one,
* can be reused by increasing the ref-count. */
if (!o_new) {
nm_assert (new);
nm_assert (new->plen > 0 && new->plen <= 128);
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE,
(const NMPlatformObject *) new);
o_new_storage.ip6_route.ifindex = priv->ifindex;
o_new = &o_new_storage;
} else {
nm_assert (!new);
nm_assert (NMP_OBJECT_GET_TYPE (o_new) == NMP_OBJECT_TYPE_IP6_ROUTE);
nm_assert (o_new->ip6_route.plen > 0 && o_new->ip6_route.plen <= 128);
if (o_new->ip6_route.ifindex != priv->ifindex) {
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE, &o_new->object);
o_new_storage.ip6_route.ifindex = priv->ifindex;
o_new = &o_new_storage;
}
}
if (!nm_dedup_multi_index_add (priv->multi_idx,
&priv->idx_ip6_routes,
o_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
NULL,
&obj_old))
return;
if (obj_old) {
NMIPConfigSource old_source;
old_source = obj_old->ip_route.rt_source;
/* we want to keep the maximum rt_source. But since we expect
* that usually we already add the maxiumum right away, we first try to
* add the new route (replacing the old one). Only if we later
* find out that rt_source is now lower, we fix it.
*/
if (o_new->ip_route.rt_source < old_source) {
if (o_new != &o_new_storage) {
nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP6_ROUTE,
&o_new->object);
o_new = &o_new_storage;
}
o_new_storage.ip_route.rt_source = old_source;
if (!nm_dedup_multi_index_add (priv->multi_idx,
&priv->idx_ip6_routes,
o_new,
NM_DEDUP_MULTI_IDX_MODE_APPEND,
NULL,
NULL))
nm_assert_not_reached ();
}
}
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
}
/**
* nm_ip6_config_add_route:
* @config: the #NMIP6Config
@ -1534,76 +1691,70 @@ nm_ip6_config_reset_routes (NMIP6Config *config)
void
nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
NMIPConfigSource old_source;
int i;
g_return_if_fail (new != NULL);
g_return_if_fail (config);
g_return_if_fail (new);
g_return_if_fail (new->plen > 0 && new->plen <= 128);
g_return_if_fail (priv->ifindex > 0);
g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex > 0);
for (i = 0; i < priv->routes->len; i++ ) {
NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i);
if (routes_are_duplicate (item, new, FALSE)) {
if (nm_platform_ip6_route_cmp (item, new) == 0)
return;
old_source = item->rt_source;
*item = *new;
/* Restore highest priority source */
item->rt_source = MAX (old_source, new->rt_source);
item->ifindex = priv->ifindex;
goto NOTIFY;
}
}
g_array_append_val (priv->routes, *new);
g_array_index (priv->routes, NMPlatformIP6Route, priv->routes->len - 1).ifindex = priv->ifindex;
NOTIFY:
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
_add_route (config, NULL, new);
}
void
nm_ip6_config_del_route (NMIP6Config *config, guint i)
_nmtst_ip6_config_del_route (NMIP6Config *self, guint i)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
const NMPlatformIP6Route *r;
g_return_if_fail (i < priv->routes->len);
r = _nmtst_ip6_config_get_route (self, i);
g_return_if_fail (r);
g_array_remove_index (priv->routes, i);
_notify (config, PROP_ROUTE_DATA);
_notify (config, PROP_ROUTES);
if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
&priv->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r)) != 1)
g_return_if_reached ();
_notify (self, PROP_ROUTE_DATA);
_notify (self, PROP_ROUTES);
}
guint
nm_ip6_config_get_num_routes (const NMIP6Config *config)
nm_ip6_config_get_num_routes (const NMIP6Config *self)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
const NMDedupMultiHeadEntry *head_entry;
return priv->routes->len;
head_entry = _idx_ip6_routes (self);
nm_assert ((head_entry ? head_entry->len : 0) == c_list_length (&head_entry->lst_entries_head));
return head_entry ? head_entry->len : 0;
}
const NMPlatformIP6Route *
nm_ip6_config_get_route (const NMIP6Config *config, guint i)
_nmtst_ip6_config_get_route (const NMIP6Config *self, guint i)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
const NMDedupMultiHeadEntry *head_entry;
CList *iter;
guint j;
return &g_array_index (priv->routes, NMPlatformIP6Route, i);
head_entry = _idx_ip6_routes (self);
if (head_entry) {
j = 0;
c_list_for_each (iter, &head_entry->lst_entries_head) {
if (i == j)
return _entry_iter_get_ip6_route (iter);
j++;
}
}
g_return_val_if_reached (NULL);
}
const NMPlatformIP6Route *
nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host)
nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct in6_addr *host)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
guint i;
NMPlatformIP6Route *best_route = NULL;
const NMPlatformIP6Route *best_route = NULL;
const NMPlatformIP6Route *item;
NMDedupMultiIter ipconf_iter;
g_return_val_if_fail (host && !IN6_IS_ADDR_UNSPECIFIED (host), NULL);
for (i = 0; i < priv->routes->len; i++) {
NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, self, &item) {
if (!IN6_IS_ADDR_UNSPECIFIED (&item->gateway))
continue;
@ -1619,7 +1770,6 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct
best_route = item;
}
return best_route;
}
@ -1953,6 +2103,8 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only
{
guint32 i;
const char *s;
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
g_return_if_fail (config);
g_return_if_fail (sum);
@ -1967,9 +2119,7 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only
hash_u32 (sum, address->plen);
}
for (i = 0; i < nm_ip6_config_get_num_routes (config); i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) {
hash_in6addr (sum, &route->network);
hash_u32 (sum, route->plen);
hash_in6addr (sum, &route->gateway);
@ -2064,6 +2214,9 @@ get_property (GObject *object, guint prop_id,
{
NMIP6Config *config = NM_IP6_CONFIG (object);
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
GVariantBuilder array_builder, addr_builder, route_builder;
switch (prop_id) {
case PROP_IFINDEX:
@ -2072,7 +2225,6 @@ get_property (GObject *object, guint prop_id,
case PROP_ADDRESS_DATA:
case PROP_ADDRESSES:
{
GVariantBuilder array_builder, addr_builder;
gs_unref_array GArray *new = NULL;
const struct in6_addr *gateway;
guint naddr, i;
@ -2134,14 +2286,8 @@ return_cached:
break;
case PROP_ROUTE_DATA:
{
GVariantBuilder array_builder, route_builder;
guint nroutes = nm_ip6_config_get_num_routes (config);
int i;
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}"));
for (i = 0; i < nroutes; i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) {
g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}"));
g_variant_builder_add (&route_builder, "{sv}",
"dest",
@ -2167,14 +2313,8 @@ return_cached:
break;
case PROP_ROUTES:
{
GVariantBuilder array_builder;
int nroutes = nm_ip6_config_get_num_routes (config);
int i;
g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuayu)"));
for (i = 0; i < nroutes; i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) {
/* legacy versions of nm_ip6_route_set_prefix() in libnm-util assert that the
* plen is positive. Skip the default routes not to break older clients. */
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
@ -2229,6 +2369,13 @@ set_property (GObject *object,
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
switch (prop_id) {
case PROP_MULTI_IDX:
/* construct-only */
priv->multi_idx = g_value_get_pointer (value);
if (!priv->multi_idx)
g_return_if_reached ();
nm_dedup_multi_index_ref (priv->multi_idx);
break;
case PROP_IFINDEX:
/* construct-only */
priv->ifindex = g_value_get_int (value);
@ -2246,8 +2393,10 @@ nm_ip6_config_init (NMIP6Config *config)
{
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
nm_ip_config_dedup_multi_idx_type_init ((NMIPConfigDedupMultiIdxType *) &priv->idx_ip6_routes,
NMP_OBJECT_TYPE_IP6_ROUTE);
priv->addresses = g_array_new (FALSE, TRUE, sizeof (NMPlatformIP6Address));
priv->routes = g_array_new (FALSE, TRUE, sizeof (NMPlatformIP6Route));
priv->nameservers = g_array_new (FALSE, TRUE, sizeof (struct in6_addr));
priv->domains = g_ptr_array_new_with_free_func (g_free);
priv->searches = g_ptr_array_new_with_free_func (g_free);
@ -2256,10 +2405,11 @@ nm_ip6_config_init (NMIP6Config *config)
}
NMIP6Config *
nm_ip6_config_new (int ifindex)
nm_ip6_config_new (NMDedupMultiIndex *multi_idx, int ifindex)
{
g_return_val_if_fail (ifindex >= -1, NULL);
return (NMIP6Config *) g_object_new (NM_TYPE_IP6_CONFIG,
NM_IP6_CONFIG_MULTI_IDX, multi_idx,
NM_IP6_CONFIG_IFINDEX, ifindex,
NULL);
}
@ -2271,7 +2421,8 @@ nm_ip6_config_new_cloned (const NMIP6Config *src)
g_return_val_if_fail (NM_IS_IP6_CONFIG (src), NULL);
new = nm_ip6_config_new (nm_ip6_config_get_ifindex (src));
new = nm_ip6_config_new (nm_ip6_config_get_multi_idx (src),
nm_ip6_config_get_ifindex (src));
nm_ip6_config_replace (new, src, NULL);
return new;
}
@ -2282,8 +2433,9 @@ finalize (GObject *object)
NMIP6Config *self = NM_IP6_CONFIG (object);
NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_routes);
g_array_unref (priv->addresses);
g_array_unref (priv->routes);
g_array_unref (priv->nameservers);
g_ptr_array_unref (priv->domains);
g_ptr_array_unref (priv->searches);
@ -2292,6 +2444,8 @@ finalize (GObject *object)
nm_clear_g_variant (&priv->addresses_variant);
G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object);
nm_dedup_multi_index_unref (priv->multi_idx);
}
static void
@ -2306,6 +2460,11 @@ nm_ip6_config_class_init (NMIP6ConfigClass *config_class)
object_class->set_property = set_property;
object_class->finalize = finalize;
obj_properties[PROP_MULTI_IDX] =
g_param_spec_pointer (NM_IP6_CONFIG_MULTI_IDX, "", "",
G_PARAM_WRITABLE
| G_PARAM_CONSTRUCT_ONLY
| G_PARAM_STATIC_STRINGS);
obj_properties[PROP_IFINDEX] =
g_param_spec_int (NM_IP6_CONFIG_IFINDEX, "", "",
-1, G_MAXINT, -1,

View file

@ -26,6 +26,20 @@
#include "nm-exported-object.h"
#include "nm-setting-ip6-config.h"
#include "nm-utils/nm-dedup-multi.h"
/*****************************************************************************/
void nm_ip6_config_iter_ip6_route_init (NMDedupMultiIter *iter, const NMIP6Config *self);
gboolean nm_ip6_config_iter_ip6_route_next (NMDedupMultiIter *iter, const NMPlatformIP6Route **out_route);
#define nm_ip6_config_iter_ip6_route_for_each(iter, self, route) \
for (nm_ip6_config_iter_ip6_route_init ((iter), (self)); \
nm_ip6_config_iter_ip6_route_next ((iter), (route)); \
)
/*****************************************************************************/
#define NM_TYPE_IP6_CONFIG (nm_ip6_config_get_type ())
#define NM_IP6_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_IP6_CONFIG, NMIP6Config))
#define NM_IP6_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_IP6_CONFIG, NMIP6ConfigClass))
@ -36,6 +50,7 @@
typedef struct _NMIP6ConfigClass NMIP6ConfigClass;
/* internal */
#define NM_IP6_CONFIG_MULTI_IDX "multi-idx"
#define NM_IP6_CONFIG_IFINDEX "ifindex"
/* public */
@ -55,13 +70,15 @@ typedef struct _NMIP6ConfigClass NMIP6ConfigClass;
GType nm_ip6_config_get_type (void);
NMIP6Config * nm_ip6_config_new (int ifindex);
NMIP6Config * nm_ip6_config_new (struct _NMDedupMultiIndex *multi_idx, int ifindex);
NMIP6Config * nm_ip6_config_new_cloned (const NMIP6Config *src);
int nm_ip6_config_get_ifindex (const NMIP6Config *config);
struct _NMDedupMultiIndex *nm_ip6_config_get_multi_idx (const NMIP6Config *self);
NMIP6Config *nm_ip6_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex,
gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
gboolean nm_ip6_config_commit (const NMIP6Config *config,
NMPlatform *platform,
NMRouteManager *route_manager,
@ -98,9 +115,9 @@ gboolean nm_ip6_config_has_any_dad_pending (const NMIP6Config *self,
void nm_ip6_config_reset_routes (NMIP6Config *config);
void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *route);
void nm_ip6_config_del_route (NMIP6Config *config, guint i);
void _nmtst_ip6_config_del_route (NMIP6Config *config, guint i);
guint nm_ip6_config_get_num_routes (const NMIP6Config *config);
const NMPlatformIP6Route *nm_ip6_config_get_route (const NMIP6Config *config, guint i);
const NMPlatformIP6Route *_nmtst_ip6_config_get_route (const NMIP6Config *config, guint i);
const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host);
const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host (const NMIP6Config *config, const struct in6_addr *host);

View file

@ -35,6 +35,7 @@
#include "devices/nm-device.h"
#include "devices/nm-device-generic.h"
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
#include "nm-hostname-manager.h"
#include "nm-rfkill-manager.h"
#include "dhcp/nm-dhcp-manager.h"
@ -2478,8 +2479,7 @@ platform_link_cb (NMPlatform *platform,
static void
platform_query_devices (NMManager *self)
{
GArray *links_array;
NMPlatformLink *links;
gs_unref_ptrarray GPtrArray *links = NULL;
int i;
gboolean guess_assume;
const char *order;
@ -2489,21 +2489,21 @@ platform_query_devices (NMManager *self)
NM_CONFIG_KEYFILE_GROUP_MAIN,
NM_CONFIG_KEYFILE_KEY_MAIN_SLAVES_ORDER,
NM_CONFIG_GET_VALUE_STRIP);
links_array = nm_platform_link_get_all (NM_PLATFORM_GET, !nm_streq0 (order, "index"));
links = (NMPlatformLink *) links_array->data;
for (i = 0; i < links_array->len; i++) {
links = nm_platform_link_get_all (NM_PLATFORM_GET, !nm_streq0 (order, "index"));
if (!links)
return;
for (i = 0; i < links->len; i++) {
const NMPlatformLink *link = NMP_OBJECT_CAST_LINK (links->pdata[i]);
gs_free NMConfigDeviceStateData *dev_state = NULL;
dev_state = nm_config_device_state_load (links[i].ifindex);
dev_state = nm_config_device_state_load (link->ifindex);
platform_link_added (self,
links[i].ifindex,
&links[i],
link->ifindex,
link,
guess_assume && (!dev_state || !dev_state->connection_uuid),
dev_state);
}
g_array_unref (links_array);
}
static void

View file

@ -1,473 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2015 Red Hat, Inc.
*/
#include "nm-default.h"
#include "nm-multi-index.h"
#include <string.h>
struct NMMultiIndex {
NMMultiIndexFuncEqual equal_fcn;
NMMultiIndexFuncClone clone_fcn;
GHashTable *hash;
};
typedef struct {
/* when storing the first item for a multi-index id, we don't yet create
* the hashtable @index. Instead we store it inplace to @value0. Note that
* &values_data->value0 is a NULL terminated array with one item that is
* suitable to be returned directly from nm_multi_index_lookup(). */
union {
gpointer value0;
gpointer *values;
};
GHashTable *index;
} ValuesData;
/*****************************************************************************/
static void
_values_data_destroy (ValuesData *values_data)
{
if (values_data->index) {
g_free (values_data->values);
g_hash_table_unref (values_data->index);
}
g_slice_free (ValuesData, values_data);
}
static gboolean
_values_data_contains (ValuesData *values_data, gconstpointer value)
{
return values_data->index
? g_hash_table_contains (values_data->index, value)
: value == values_data->value0;
}
static void
_values_data_get_data (ValuesData *values_data,
void *const**out_data,
guint *out_len)
{
guint i, len;
gpointer *values;
GHashTableIter iter;
nm_assert (values_data);
if (!values_data->index) {
NM_SET_OUT (out_data, &values_data->value0);
NM_SET_OUT (out_len, 1);
return;
}
nm_assert (values_data->index && g_hash_table_size (values_data->index) > 0);
if (!values_data->values) {
len = g_hash_table_size (values_data->index);
values = g_new (gpointer, len + 1);
g_hash_table_iter_init (&iter, values_data->index);
for (i = 0; g_hash_table_iter_next (&iter, &values[i], NULL); i++)
nm_assert (i < len);
nm_assert (i == len);
values[i] = NULL;
values_data->values = values;
NM_SET_OUT (out_len, len);
} else if (out_len)
NM_SET_OUT (out_len, g_hash_table_size (values_data->index));
NM_SET_OUT (out_data, values_data->values);
}
/*****************************************************************************/
/**
* nm_multi_index_lookup():
* @index:
* @id:
* @out_len: (allow-none): output the number of values
* that are returned.
*
* Returns: (transfer none): %NULL if there are no values
* or a %NULL terminated array of pointers.
*/
void *const*
nm_multi_index_lookup (const NMMultiIndex *index,
const NMMultiIndexId *id,
guint *out_len)
{
ValuesData *values_data;
void *const*values;
g_return_val_if_fail (index, NULL);
g_return_val_if_fail (id, NULL);
values_data = g_hash_table_lookup (index->hash, id);
if (!values_data) {
if (out_len)
*out_len = 0;
return NULL;
}
_values_data_get_data (values_data, &values, out_len);
return values;
}
gboolean
nm_multi_index_contains (const NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
ValuesData *values_data;
g_return_val_if_fail (index, FALSE);
g_return_val_if_fail (id, FALSE);
g_return_val_if_fail (value, FALSE);
values_data = g_hash_table_lookup (index->hash, id);
return values_data && _values_data_contains (values_data, value);
}
const NMMultiIndexId *
nm_multi_index_lookup_first_by_value (const NMMultiIndex *index,
gconstpointer value)
{
GHashTableIter iter;
const NMMultiIndexId *id;
ValuesData *values_data;
g_return_val_if_fail (index, NULL);
g_return_val_if_fail (value, NULL);
/* reverse-lookup needs to iterate over all hash tables. It should
* still be fairly quick, if the number of hash tables is small.
* There is no O(1) reverse lookup implemented, because this access
* pattern is not what NMMultiIndex is here for.
* You are supposed to use NMMultiIndex by always knowing which @id
* a @value has.
*/
g_hash_table_iter_init (&iter, index->hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &id, (gpointer *) &values_data)) {
if (_values_data_contains (values_data, value))
return id;
}
return NULL;
}
void
nm_multi_index_foreach (const NMMultiIndex *index,
gconstpointer value,
NMMultiIndexFuncForeach foreach_func,
gpointer user_data)
{
GHashTableIter iter;
const NMMultiIndexId *id;
ValuesData *values_data;
guint len;
void *const*values;
g_return_if_fail (index);
g_return_if_fail (foreach_func);
g_hash_table_iter_init (&iter, index->hash);
while (g_hash_table_iter_next (&iter, (gpointer *) &id, (gpointer *) &values_data)) {
if (value && !_values_data_contains (values_data, value))
continue;
_values_data_get_data (values_data, &values, &len);
if (!foreach_func (id, values, len, user_data))
return;
}
}
void
nm_multi_index_iter_init (NMMultiIndexIter *iter,
const NMMultiIndex *index,
gconstpointer value)
{
g_return_if_fail (index);
g_return_if_fail (iter);
g_hash_table_iter_init (&iter->_iter, index->hash);
iter->_index = index;
iter->_value = value;
}
gboolean
nm_multi_index_iter_next (NMMultiIndexIter *iter,
const NMMultiIndexId **out_id,
void *const**out_values,
guint *out_len)
{
const NMMultiIndexId *id;
ValuesData *values_data;
g_return_val_if_fail (iter, FALSE);
while (g_hash_table_iter_next (&iter->_iter, (gpointer *) &id, (gpointer *) &values_data)) {
if ( !iter->_value
|| _values_data_contains (values_data, iter->_value)) {
if (out_values || out_len)
_values_data_get_data (values_data, out_values, out_len);
if (out_id)
*out_id = id;
return TRUE;
}
}
return FALSE;
}
/*****************************************************************************/
void
nm_multi_index_id_iter_init (NMMultiIndexIdIter *iter,
const NMMultiIndex *index,
const NMMultiIndexId *id)
{
ValuesData *values_data;
g_return_if_fail (index);
g_return_if_fail (iter);
g_return_if_fail (id);
values_data = g_hash_table_lookup (index->hash, id);
if (!values_data)
iter->_state = 2;
else if (values_data->index) {
iter->_state = 1;
g_hash_table_iter_init (&iter->_iter, values_data->index);
} else {
iter->_state = 0;
iter->_value = values_data->value0;
}
}
gboolean
nm_multi_index_id_iter_next (NMMultiIndexIdIter *iter,
void **out_value)
{
g_return_val_if_fail (iter, FALSE);
switch (iter->_state) {
case 0:
iter->_state = 2;
NM_SET_OUT (out_value, iter->_value);
return TRUE;
case 1:
return g_hash_table_iter_next (&iter->_iter, out_value, NULL);
case 2:
iter->_state = 3;
return FALSE;
default:
g_return_val_if_reached (FALSE);
}
}
/*****************************************************************************/
static gboolean
_do_add (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
ValuesData *values_data;
values_data = g_hash_table_lookup (index->hash, id);
if (!values_data) {
NMMultiIndexId *id_new;
/* Contrary to GHashTable, we don't take ownership of the @id that was
* provided to nm_multi_index_add(). Instead we clone it via @clone_fcn
* when needed.
*
* The reason is, that we expect in most cases that there exists
* already a @id so that we don't need ownership of it (or clone it).
* By doing this, the caller can pass a stack allocated @id or
* reuse the @id for other insertions.
*/
id_new = index->clone_fcn (id);
if (!id_new)
g_return_val_if_reached (FALSE);
values_data = g_slice_new0 (ValuesData);
values_data->value0 = (gpointer) value;
g_hash_table_insert (index->hash, id_new, values_data);
} else {
if (!values_data->index) {
if (values_data->value0 == value)
return FALSE;
values_data->index = g_hash_table_new (NULL, NULL);
g_hash_table_replace (values_data->index, (gpointer) value, (gpointer) value);
g_hash_table_replace (values_data->index, values_data->value0, values_data->value0);
values_data->values = NULL;
} else {
if (!nm_g_hash_table_replace (values_data->index, (gpointer) value, (gpointer) value))
return FALSE;
g_clear_pointer (&values_data->values, g_free);
}
}
return TRUE;
}
static gboolean
_do_remove (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
ValuesData *values_data;
values_data = g_hash_table_lookup (index->hash, id);
if (!values_data)
return FALSE;
if (values_data->index) {
if (!g_hash_table_remove (values_data->index, value))
return FALSE;
if (g_hash_table_size (values_data->index) == 0)
g_hash_table_remove (index->hash, id);
else
g_clear_pointer (&values_data->values, g_free);
} else {
if (values_data->value0 != value)
return FALSE;
g_hash_table_remove (index->hash, id);
}
return TRUE;
}
gboolean
nm_multi_index_add (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
g_return_val_if_fail (index, FALSE);
g_return_val_if_fail (id, FALSE);
g_return_val_if_fail (value, FALSE);
return _do_add (index, id, value);
}
gboolean
nm_multi_index_remove (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value)
{
g_return_val_if_fail (index, FALSE);
g_return_val_if_fail (value, FALSE);
if (!id)
g_return_val_if_reached (FALSE);
return _do_remove (index, id, value);
}
/**
* nm_multi_index_move:
* @index:
* @id_old: (allow-none): remove @value at @id_old
* @id_new: (allow-none): add @value under @id_new
* @value: the value to add
*
* Similar to a remove(), followed by an add(). The difference
* is, that we allow %NULL for both @id_old and @id_new.
* And the return value indicates whether @value was successfully
* removed *and* added.
*
* Returns: %TRUE, if the value was removed from @id_old and added
* as %id_new. %FALSE could mean, that @value was not added to @id_old
* before, or that that @value was already part of @id_new. */
gboolean
nm_multi_index_move (NMMultiIndex *index,
const NMMultiIndexId *id_old,
const NMMultiIndexId *id_new,
gconstpointer value)
{
g_return_val_if_fail (index, FALSE);
g_return_val_if_fail (value, FALSE);
if (!id_old && !id_new) {
/* nothing to do, @value was and is not in @index. */
return TRUE;
} if (!id_old) {
/* add @value to @index with @id_new */
return _do_add (index, id_new, value);
} else if (!id_new) {
/* remove @value from @index with @id_old */
return _do_remove (index, id_old, value);
} else if (index->equal_fcn (id_old, id_new)) {
if (_do_add (index, id_new, value)) {
/* we would expect, that @value is already in @index,
* Return %FALSE, if it wasn't. */
return FALSE;
}
return TRUE;
} else {
gboolean did_remove;
did_remove = _do_remove (index, id_old, value);
return _do_add (index, id_new, value) && did_remove;
}
}
/*****************************************************************************/
guint
nm_multi_index_get_num_groups (const NMMultiIndex *index)
{
g_return_val_if_fail (index, 0);
return g_hash_table_size (index->hash);
}
NMMultiIndex *
nm_multi_index_new (NMMultiIndexFuncHash hash_fcn,
NMMultiIndexFuncEqual equal_fcn,
NMMultiIndexFuncClone clone_fcn,
NMMultiIndexFuncDestroy destroy_fcn)
{
NMMultiIndex *index;
g_return_val_if_fail (hash_fcn, NULL);
g_return_val_if_fail (equal_fcn, NULL);
g_return_val_if_fail (clone_fcn, NULL);
g_return_val_if_fail (destroy_fcn, NULL);
index = g_new (NMMultiIndex, 1);
index->equal_fcn = equal_fcn;
index->clone_fcn = clone_fcn;
index->hash = g_hash_table_new_full ((GHashFunc) hash_fcn,
(GEqualFunc) equal_fcn,
(GDestroyNotify) destroy_fcn,
(GDestroyNotify) _values_data_destroy);
return index;
}
void
nm_multi_index_free (NMMultiIndex *index)
{
g_return_if_fail (index);
g_hash_table_unref (index->hash);
g_free (index);
}

View file

@ -1,105 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2015 Red Hat, Inc.
*/
#ifndef __NM_MULTI_INDEX__
#define __NM_MULTI_INDEX__
typedef struct {
char _dummy;
} NMMultiIndexId;
typedef struct NMMultiIndex NMMultiIndex;
typedef struct {
GHashTableIter _iter;
const NMMultiIndex *_index;
gconstpointer _value;
} NMMultiIndexIter;
typedef struct {
union {
GHashTableIter _iter;
gpointer _value;
};
guint _state;
} NMMultiIndexIdIter;
typedef gboolean (*NMMultiIndexFuncEqual) (const NMMultiIndexId *id_a, const NMMultiIndexId *id_b);
typedef guint (*NMMultiIndexFuncHash) (const NMMultiIndexId *id);
typedef NMMultiIndexId *(*NMMultiIndexFuncClone) (const NMMultiIndexId *id);
typedef void (*NMMultiIndexFuncDestroy) (NMMultiIndexId *id);
typedef gboolean (*NMMultiIndexFuncForeach) (const NMMultiIndexId *id, void *const* values, guint len, gpointer user_data);
NMMultiIndex *nm_multi_index_new (NMMultiIndexFuncHash hash_fcn,
NMMultiIndexFuncEqual equal_fcn,
NMMultiIndexFuncClone clone_fcn,
NMMultiIndexFuncDestroy destroy_fcn);
void nm_multi_index_free (NMMultiIndex *index);
gboolean nm_multi_index_add (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value);
gboolean nm_multi_index_remove (NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value);
gboolean nm_multi_index_move (NMMultiIndex *index,
const NMMultiIndexId *id_old,
const NMMultiIndexId *id_new,
gconstpointer value);
guint nm_multi_index_get_num_groups (const NMMultiIndex *index);
void *const*nm_multi_index_lookup (const NMMultiIndex *index,
const NMMultiIndexId *id,
guint *out_len);
gboolean nm_multi_index_contains (const NMMultiIndex *index,
const NMMultiIndexId *id,
gconstpointer value);
const NMMultiIndexId *nm_multi_index_lookup_first_by_value (const NMMultiIndex *index,
gconstpointer value);
void nm_multi_index_foreach (const NMMultiIndex *index,
gconstpointer value,
NMMultiIndexFuncForeach foreach_func,
gpointer user_data);
void nm_multi_index_iter_init (NMMultiIndexIter *iter,
const NMMultiIndex *index,
gconstpointer value);
gboolean nm_multi_index_iter_next (NMMultiIndexIter *iter,
const NMMultiIndexId **out_id,
void *const**out_values,
guint *out_len);
void nm_multi_index_id_iter_init (NMMultiIndexIdIter *iter,
const NMMultiIndex *index,
const NMMultiIndexId *id);
gboolean nm_multi_index_id_iter_next (NMMultiIndexIdIter *iter,
void **out_value);
#endif /* __NM_MULTI_INDEX__ */

View file

@ -22,6 +22,8 @@
#include "nm-netns.h"
#include "nm-utils/nm-dedup-multi.h"
#include "platform/nm-platform.h"
#include "platform/nmp-netns.h"
#include "nm-route-manager.h"
@ -74,6 +76,12 @@ nm_netns_get_platform (NMNetns *self)
return NM_NETNS_GET_PRIVATE (self)->platform;
}
NMDedupMultiIndex *
nm_netns_get_multi_idx (NMNetns *self)
{
return nm_platform_get_multi_idx (NM_NETNS_GET_PRIVATE (self)->platform);
}
NMDefaultRouteManager *
nm_netns_get_default_route_manager (NMNetns *self)
{

View file

@ -42,6 +42,8 @@ NMPNetns *nm_netns_get_platform_netns (NMNetns *self);
NMRouteManager *nm_netns_get_route_manager (NMNetns *self);
NMDefaultRouteManager *nm_netns_get_default_route_manager (NMNetns *self);
struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self);
#define NM_NETNS_GET (nm_netns_get ())
#endif /* __NM_NETNS_H__ */

View file

@ -168,8 +168,10 @@ add_proxy_config (GVariantBuilder *proxy_data, const NMProxyConfig *proxy_config
static void
get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4)
{
NMDedupMultiIter ipconf_iter;
char *cidr;
int i;
const NMPlatformIP4Route *routes;
guint i;
/* Extract searches */
for (i = 0; i < nm_ip4_config_get_num_searches (ip4); i++)
@ -189,9 +191,7 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4)
g_ptr_array_add (domains, cidr);
}
for (i = 0; i < nm_ip4_config_get_num_routes (ip4); i++) {
const NMPlatformIP4Route *routes = nm_ip4_config_get_route (ip4, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &routes) {
cidr = g_strdup_printf ("%s/%u",
nm_utils_inet4_ntop (routes->network, NULL),
routes->plen);
@ -202,8 +202,10 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4)
static void
get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6)
{
NMDedupMultiIter ipconf_iter;
char *cidr;
int i;
const NMPlatformIP6Route *routes;
guint i;
/* Extract searches */
for (i = 0; i < nm_ip6_config_get_num_searches (ip6); i++)
@ -223,9 +225,7 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6)
g_ptr_array_add (domains, cidr);
}
for (i = 0; i < nm_ip6_config_get_num_routes (ip6); i++) {
const NMPlatformIP6Route *routes = nm_ip6_config_get_route (ip6, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) {
cidr = g_strdup_printf ("%s/%u",
nm_utils_inet6_ntop (&routes->network, NULL),
routes->plen);

View file

@ -306,6 +306,55 @@ _route_index_create (const VTableIP *vtable, const GArray *routes)
return index;
}
static RouteIndex *
_route_index_create_from_platform (const VTableIP *vtable,
NMPlatform *platform,
int ifindex,
gboolean ignore_kernel_routes,
GPtrArray **out_storage)
{
RouteIndex *index;
guint i, j, len;
GPtrArray *storage;
nm_assert (out_storage && !*out_storage);
storage = nm_platform_lookup_route_visible_clone (platform,
vtable->vt->obj_type,
ifindex,
FALSE,
NULL,
NULL);
if (!storage)
return _route_index_create (vtable, NULL);
len = storage->len;
index = g_malloc (sizeof (RouteIndex) + len * sizeof (NMPlatformIPXRoute *));
j = 0;
for (i = 0; i < len; i++) {
const NMPlatformIPXRoute *ipx_route = NMP_OBJECT_CAST_IPX_ROUTE (storage->pdata[i]);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (ipx_route))
continue;
/* we cast away the const-ness of the NMPObjects. The caller must
* ensure not to modify the object via index->entries. */
index->entries[j++] = (NMPlatformIPXRoute *) ipx_route;
}
index->entries[j] = NULL;
index->len = j;
/* this is a stable sort, which is very important at this point. */
g_qsort_with_data (index->entries,
index->len,
sizeof (NMPlatformIPXRoute *),
(GCompareDataFunc) _route_index_create_sort,
(gpointer) vtable);
*out_storage = storage;
return index;
}
static int
_vx_route_id_cmp_full (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2, const VTableIP *vtable)
{
@ -458,7 +507,7 @@ static gboolean
_vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync)
{
NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
GArray *plat_routes;
gs_unref_ptrarray GPtrArray *plat_routes = NULL;
RouteEntries *ipx_routes;
RouteIndex *plat_routes_idx, *known_routes_idx;
gboolean success = TRUE;
@ -475,16 +524,15 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
nm_platform_process_events (priv->platform);
ipx_routes = vtable->vt->is_ip4 ? &priv->ip4_routes : &priv->ip6_routes;
plat_routes = vtable->vt->route_get_all (priv->platform, ifindex,
ignore_kernel_routes
? NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT
: NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL);
plat_routes_idx = _route_index_create (vtable, plat_routes);
/* the objects referenced by play_routes_idx are shared from the platform cache. They
* must not be modified. */
plat_routes_idx = _route_index_create_from_platform (vtable, priv->platform, ifindex, ignore_kernel_routes, &plat_routes);
known_routes_idx = _route_index_create (vtable, known_routes);
effective_metrics = &g_array_index (ipx_routes->effective_metrics, gint64, 0);
ASSERT_route_index_valid (vtable, plat_routes, plat_routes_idx, TRUE);
ASSERT_route_index_valid (vtable, known_routes, known_routes_idx, FALSE);
_LOGD (vtable->vt->addr_family, "%3d: sync %u IPv%c routes", ifindex, known_routes_idx->len, vtable->vt->is_ip4 ? '4' : '6');
@ -918,7 +966,6 @@ next:
g_free (known_routes_idx);
g_free (plat_routes_idx);
g_array_unref (plat_routes);
return success;
}
@ -1173,7 +1220,7 @@ nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *sel
? "update" : "new",
nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
g_hash_table_replace (priv->ip4_device_routes.entries,
nmp_object_ref (entry->obj),
(NMPObject *) nmp_object_ref (entry->obj),
entry);
}
if (priv->ip4_device_routes.gc_id == 0) {

View file

@ -226,6 +226,25 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP
}
}
#ifdef __NMP_OBJECT_H__
static inline void
nmtst_platform_ip4_routes_equal_aptr (const NMPObject *const*a, const NMPlatformIP4Route *b, gsize len, gboolean ignore_order)
{
gsize i;
gs_free NMPlatformIP4Route *c_a = NULL;
g_assert (len > 0);
g_assert (a);
c_a = g_new (NMPlatformIP4Route, len);
for (i = 0; i < len; i++)
c_a[i] = *NMP_OBJECT_CAST_IP4_ROUTE (a[i]);
nmtst_platform_ip4_routes_equal (c_a, b, len, ignore_order);
}
#endif
static inline int
_nmtst_platform_ip6_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data)
{
@ -260,18 +279,48 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP
}
}
#ifdef __NMP_OBJECT_H__
static inline void
nmtst_platform_ip6_routes_equal_aptr (const NMPObject *const*a, const NMPlatformIP6Route *b, gsize len, gboolean ignore_order)
{
gsize i;
gs_free NMPlatformIP6Route *c_a = NULL;
g_assert (len > 0);
g_assert (a);
c_a = g_new (NMPlatformIP6Route, len);
for (i = 0; i < len; i++)
c_a[i] = *NMP_OBJECT_CAST_IP6_ROUTE (a[i]);
nmtst_platform_ip6_routes_equal (c_a, b, len, ignore_order);
}
#endif
#endif
#ifdef __NETWORKMANAGER_IP4_CONFIG_H__
#include "nm-utils/nm-dedup-multi.h"
static inline NMIP4Config *
nmtst_ip4_config_new (int ifindex)
{
nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new ();
return nm_ip4_config_new (multi_idx, ifindex);
}
static inline NMIP4Config *
nmtst_ip4_config_clone (NMIP4Config *config)
{
NMIP4Config *copy = nm_ip4_config_new (-1);
NMIP4Config *copy;
g_assert (copy);
g_assert (config);
copy = nm_ip4_config_new (nm_ip4_config_get_multi_idx (config), -1);
g_assert (copy);
nm_ip4_config_replace (copy, config, NULL);
return copy;
}
@ -281,13 +330,24 @@ nmtst_ip4_config_clone (NMIP4Config *config)
#ifdef __NETWORKMANAGER_IP6_CONFIG_H__
#include "nm-utils/nm-dedup-multi.h"
static inline NMIP6Config *
nmtst_ip6_config_new (int ifindex)
{
nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = nm_dedup_multi_index_new ();
return nm_ip6_config_new (multi_idx, ifindex);
}
static inline NMIP6Config *
nmtst_ip6_config_clone (NMIP6Config *config)
{
NMIP6Config *copy = nm_ip6_config_new (-1);
NMIP6Config *copy;
g_assert (copy);
g_assert (config);
copy = nm_ip6_config_new (nm_ip6_config_get_multi_idx (config), -1);
g_assert (copy);
nm_ip6_config_replace (copy, config, NULL);
return copy;
}

View file

@ -56,6 +56,8 @@ typedef struct _NMSleepMonitor NMSleepMonitor;
typedef struct _NMLldpListener NMLldpListener;
typedef struct _NMConfigDeviceStateData NMConfigDeviceStateData;
struct _NMDedupMultiIndex;
/*****************************************************************************/
typedef enum {

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -39,10 +39,4 @@ NMPlatform *nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support
void nm_linux_platform_setup (void);
struct _NMPCacheId;
const NMPlatformObject *const *nm_linux_platform_lookup (NMPlatform *platform,
const struct _NMPCacheId *cache_id,
guint *out_len);
#endif /* __NETWORKMANAGER_LINUX_PLATFORM_H__ */

View file

@ -0,0 +1,42 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* nm-platform.c - Handle runtime kernel networking configuration
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2017 Red Hat, Inc.
*/
#ifndef __NM_PLATFORM_PRIVATE_H__
#define __NM_PLATFORM_PRIVATE_H__
#include "nm-platform.h"
#include "nmp-object.h"
NMPCache *nm_platform_get_cache (NMPlatform *self);
#define NMTST_ASSERT_PLATFORM_NETNS_CURRENT(platform) \
G_STMT_START { \
NMPlatform *_platform = (platform); \
\
nm_assert (NM_IS_PLATFORM (_platform)); \
nm_assert (NM_IN_SET (nm_platform_netns_get (_platform), NULL, nmp_netns_get_current ())); \
} G_STMT_END
void nm_platform_cache_update_emit_signal (NMPlatform *platform,
NMPCacheOpsType cache_op,
const NMPObject *obj_old,
const NMPObject *obj_new);
#endif /* __NM_PLATFORM_PRIVATE_H__ */

File diff suppressed because it is too large Load diff

View file

@ -45,6 +45,7 @@
/*****************************************************************************/
#define NM_PLATFORM_NETNS_SUPPORT "netns-support"
#define NM_PLATFORM_USE_UDEV "use-udev"
#define NM_PLATFORM_LOG_WITH_PTR "log-with-ptr"
/*****************************************************************************/
@ -172,18 +173,6 @@ typedef enum {
NM_PLATFORM_SIGNAL_REMOVED,
} NMPlatformSignalChangeType;
typedef enum { /*< skip >*/
NM_PLATFORM_GET_ROUTE_FLAGS_NONE = 0,
/* Whether to include default-routes/non-default-routes. Omitting
* both WITH_DEFAULT and WITH_NON_DEFAULT, is equal to specifying
* both of them. */
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT = (1LL << 0),
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT = (1LL << 1),
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL = (1LL << 2),
} NMPlatformGetRouteFlags;
typedef struct {
__NMPlatformObject_COMMON;
} NMPlatformObject;
@ -372,11 +361,11 @@ typedef union {
typedef struct {
gboolean is_ip4;
NMPObjectType obj_type;
int addr_family;
gsize sizeof_route;
int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part);
const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len);
GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric);
gboolean (*route_delete) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route);
gboolean (*route_delete_default) (NMPlatform *self, int ifindex, guint32 metric);
@ -426,7 +415,7 @@ typedef struct {
typedef struct {
int parent_ifindex;
guint64 sci; /* host byte order */
guint64 sci; /* host byte order */
guint64 cipher_suite;
guint32 window;
guint8 icv_length;
@ -517,13 +506,6 @@ typedef struct {
gboolean (*sysctl_set) (NMPlatform *, const char *pathid, int dirfd, const char *path, const char *value);
char * (*sysctl_get) (NMPlatform *, const char *pathid, int dirfd, const char *path);
const NMPlatformLink *(*link_get) (NMPlatform *platform, int ifindex);
const NMPlatformLink *(*link_get_by_ifname) (NMPlatform *platform, const char *ifname);
const NMPlatformLink *(*link_get_by_address) (NMPlatform *platform, gconstpointer address, size_t length);
const NMPObject *(*link_get_lnk) (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link);
GArray *(*link_get_all) (NMPlatform *);
gboolean (*link_add) (NMPlatform *,
const char *name,
NMLinkType type,
@ -532,8 +514,6 @@ typedef struct {
size_t address_len,
const NMPlatformLink **out_link);
gboolean (*link_delete) (NMPlatform *, int ifindex);
const char *(*link_get_type_name) (NMPlatform *, int ifindex);
gboolean (*link_get_unmanaged) (NMPlatform *, int ifindex, gboolean *unmanaged);
gboolean (*link_refresh) (NMPlatform *, int ifindex);
@ -642,8 +622,6 @@ typedef struct {
gboolean (*mesh_set_channel) (NMPlatform *, int ifindex, guint32 channel);
gboolean (*mesh_set_ssid) (NMPlatform *, int ifindex, const guint8 *ssid, gsize len);
GArray * (*ip4_address_get_all) (NMPlatform *, int ifindex);
GArray * (*ip6_address_get_all) (NMPlatform *, int ifindex);
gboolean (*ip4_address_add) (NMPlatform *,
int ifindex,
in_addr_t address,
@ -663,17 +641,11 @@ typedef struct {
guint32 flags);
gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address);
gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, guint8 plen);
const NMPlatformIP4Address *(*ip4_address_get) (NMPlatform *, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address);
const NMPlatformIP6Address *(*ip6_address_get) (NMPlatform *, int ifindex, struct in6_addr address);
GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags);
GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags);
gboolean (*ip4_route_add) (NMPlatform *, const NMPlatformIP4Route *route);
gboolean (*ip6_route_add) (NMPlatform *, const NMPlatformIP6Route *route);
gboolean (*ip4_route_delete) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
gboolean (*ip6_route_delete) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
const NMPlatformIP4Route *(*ip4_route_get) (NMPlatform *, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
const NMPlatformIP6Route *(*ip6_route_get) (NMPlatform *, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *);
gboolean (*check_support_user_ipv6ll) (NMPlatform *);
@ -726,6 +698,7 @@ _nm_platform_uint8_inv (guint8 scope)
return (guint8) ~scope;
}
gboolean nm_platform_get_use_udev (NMPlatform *self);
gboolean nm_platform_get_log_with_ptr (NMPlatform *self);
NMPNetns *nm_platform_netns_get (NMPlatform *self);
@ -760,11 +733,14 @@ gboolean nm_platform_sysctl_set_ip6_hop_limit_safe (NMPlatform *self, const char
const char *nm_platform_if_indextoname (NMPlatform *self, int ifindex, char *out_ifname/* of size IFNAMSIZ */);
int nm_platform_if_nametoindex (NMPlatform *self, const char *ifname);
const NMPObject *nm_platform_link_get_obj (NMPlatform *self,
int ifindex,
gboolean visible_only);
const NMPlatformLink *nm_platform_link_get (NMPlatform *self, int ifindex);
const NMPlatformLink *nm_platform_link_get_by_ifname (NMPlatform *self, const char *ifname);
const NMPlatformLink *nm_platform_link_get_by_address (NMPlatform *self, gconstpointer address, size_t length);
GArray *nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name);
GPtrArray *nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name);
NMPlatformError nm_platform_link_dummy_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link);
NMPlatformError nm_platform_link_bridge_add (NMPlatform *self, const char *name, const void *address, size_t address_len, const NMPlatformLink **out_link);
NMPlatformError nm_platform_link_bond_add (NMPlatform *self, const char *name, const NMPlatformLink **out_link);
@ -775,6 +751,19 @@ gboolean nm_platform_link_delete (NMPlatform *self, int ifindex);
gboolean nm_platform_link_set_netns (NMPlatform *self, int ifindex, int netns_fd);
struct _NMDedupMultiHeadEntry;
struct _NMPLookup;
const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *platform,
const struct _NMPLookup *lookup);
gboolean nm_platform_lookup_predicate_routes_skip_rtprot_kernel (const NMPObject *obj,
gpointer user_data);
GPtrArray *nm_platform_lookup_clone (NMPlatform *platform,
const struct _NMPLookup *lookup,
gboolean (*predicate) (const NMPObject *obj, gpointer user_data),
gpointer user_data);
/* convienience methods to lookup the link and access fields of NMPlatformLink. */
int nm_platform_link_get_ifindex (NMPlatform *self, const char *name);
const char *nm_platform_link_get_name (NMPlatform *self, int ifindex);
@ -969,8 +958,6 @@ gboolean nm_platform_address_flush (NMPlatform *self, int ifindex);
const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
gboolean nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route);
gboolean nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route);
gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
@ -1024,6 +1011,21 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route
return nm_platform_ip6_route_cmp_full (a, b, TRUE);
}
guint nm_platform_link_hash (const NMPlatformLink *obj);
guint nm_platform_ip4_address_hash (const NMPlatformIP4Address *obj);
guint nm_platform_ip6_address_hash (const NMPlatformIP6Address *obj);
guint nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj);
guint nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj);
guint nm_platform_lnk_gre_hash (const NMPlatformLnkGre *obj);
guint nm_platform_lnk_infiniband_hash (const NMPlatformLnkInfiniband *obj);
guint nm_platform_lnk_ip6tnl_hash (const NMPlatformLnkIp6Tnl *obj);
guint nm_platform_lnk_ipip_hash (const NMPlatformLnkIpIp *obj);
guint nm_platform_lnk_macsec_hash (const NMPlatformLnkMacsec *obj);
guint nm_platform_lnk_macvlan_hash (const NMPlatformLnkMacvlan *obj);
guint nm_platform_lnk_sit_hash (const NMPlatformLnkSit *obj);
guint nm_platform_lnk_vlan_hash (const NMPlatformLnkVlan *obj);
guint nm_platform_lnk_vxlan_hash (const NMPlatformLnkVxlan *obj);
gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self);
gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self);
@ -1038,4 +1040,6 @@ gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, int ifindex, NMS
gboolean nm_platform_ethtool_set_link_settings (NMPlatform *self, int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
gboolean nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
struct _NMDedupMultiIndex *nm_platform_get_multi_idx (NMPlatform *self);
#endif /* __NETWORKMANAGER_PLATFORM_H__ */

File diff suppressed because it is too large Load diff

View file

@ -21,8 +21,9 @@
#ifndef __NMP_OBJECT_H__
#define __NMP_OBJECT_H__
#include "nm-utils/nm-obj.h"
#include "nm-utils/nm-dedup-multi.h"
#include "nm-platform.h"
#include "nm-multi-index.h"
struct udev_device;
@ -47,36 +48,42 @@ typedef enum { /*< skip >*/
* but only route objects can be indexed by NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT.
*
* Of one index type, there can be multiple indexes or not.
* For example, of the index type NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX there
* For example, of the index type NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX there
* are multiple instances (for different route/addresses, v4/v6, per-ifindex).
*
* But one object, can only be indexed by one particular index of a
* type. For example, a certain address instance is only indexed by
* the index NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX with
* the index NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX with
* matching v4/v6 and ifindex -- or maybe not at all if it isn't visible.
* */
typedef enum { /*< skip >*/
NMP_CACHE_ID_TYPE_NONE,
/* all the objects of a certain type */
/* all the objects of a certain type.
*
* This index is special. It is the only one that contains *all* object.
* Other indexes may consider some object as non "partitionable", hence
* they don't track all objects.
*
* Hence, this index type is used when looking at all objects (still
* partitioned by type).
*
* Also, note that links may be considered invisible. This index type
* expose all links, even invisible ones. For addresses/routes, this
* distiction doesn't exist, as all addresses/routes that are alive
* are visible as well. */
NMP_CACHE_ID_TYPE_OBJECT_TYPE,
/* index for the link objects by ifname. */
NMP_CACHE_ID_TYPE_LINK_BY_IFNAME,
/* all the visible objects of a certain type */
NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY,
/* indeces for the visible default-routes, ignoring ifindex.
* This index only contains two partitions: all visible default-routes,
* separate for IPv4 and IPv6. */
NMP_CACHE_ID_TYPE_DEFAULT_ROUTES,
/* indeces for the visible routes, ignoring ifindex. */
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT,
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT,
/* all the visible addresses/routes (by object-type) for an ifindex. */
NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX,
/* three indeces for the visible routes, per ifindex. */
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT,
NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT,
/* all the addresses/routes (by object-type) for an ifindex. */
NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX,
/* Consider all the destination fields of a route, that is, the ID without the ifindex
* and gateway (meaning: network/plen,metric).
@ -86,65 +93,21 @@ typedef enum { /*< skip >*/
* sends one RTM_NEWADDR notification without notifying about the deletion. We detect
* that by having this index to contain overlapping routes which require special
* cache-resync. */
NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP4,
NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6,
NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION,
__NMP_CACHE_ID_TYPE_MAX,
NMP_CACHE_ID_TYPE_MAX = __NMP_CACHE_ID_TYPE_MAX - 1,
} NMPCacheIdType;
typedef struct _NMPCacheId NMPCacheId;
struct _NMPCacheId {
union {
NMMultiIndexId base;
guint8 _id_type; /* NMPCacheIdType as guint8 */
struct _nm_packed {
/* NMP_CACHE_ID_TYPE_OBJECT_TYPE */
/* NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY */
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT */
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT */
guint8 _id_type;
guint8 obj_type; /* NMPObjectType as guint8 */
} object_type;
struct _nm_packed {
/* NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX */
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT */
/* NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT */
guint8 _id_type;
guint8 obj_type; /* NMPObjectType as guint8 */
int _misaligned_ifindex;
} object_type_by_ifindex;
struct _nm_packed {
/* NMP_CACHE_ID_TYPE_LINK_BY_IFNAME */
guint8 _id_type;
char ifname_short[IFNAMSIZ - 1]; /* don't include the trailing NUL so the struct fits in 4 bytes. */
} link_by_ifname;
struct _nm_packed {
/* NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP4 */
guint8 _id_type;
guint8 plen;
guint32 _misaligned_metric;
guint32 _misaligned_network;
} routes_by_destination_ip4;
struct _nm_packed {
/* NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6 */
guint8 _id_type;
guint8 plen;
guint32 _misaligned_metric;
struct in6_addr _misaligned_network;
} routes_by_destination_ip6;
};
};
typedef struct {
NMDedupMultiObjClass parent;
const char *obj_type_name;
int sizeof_data;
int sizeof_public;
NMPObjectType obj_type;
int addr_family;
int rtm_gettype;
int sizeof_data;
int sizeof_public;
NMPlatformSignalIdType signal_type_id;
const char *obj_type_name;
const char *signal_type;
const guint8 *supported_cache_ids;
@ -152,10 +115,7 @@ typedef struct {
/* Only for NMPObjectLnk* types. */
NMLinkType lnk_link_type;
/* returns %FALSE, if the obj type would never have an entry for index type @id_type. If @obj has an index,
* initialize @id and set @out_id to it. Otherwise, @out_id is NULL. */
gboolean (*cmd_obj_init_cache_id) (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id);
guint (*cmd_obj_hash) (const NMPObject *obj);
int (*cmd_obj_cmp) (const NMPObject *obj1, const NMPObject *obj2);
void (*cmd_obj_copy) (NMPObject *dst, const NMPObject *src);
void (*cmd_obj_stackinit_id) (NMPObject *obj, const NMPObject *src);
@ -170,6 +130,7 @@ typedef struct {
guint (*cmd_plobj_id_hash) (const NMPlatformObject *obj);
const char *(*cmd_plobj_to_string_id) (const NMPlatformObject *obj, char *buf, gsize buf_size);
const char *(*cmd_plobj_to_string) (const NMPlatformObject *obj, char *buf, gsize len);
guint (*cmd_plobj_hash) (const NMPlatformObject *obj);
int (*cmd_plobj_cmp) (const NMPlatformObject *obj1, const NMPlatformObject *obj2);
} NMPClass;
@ -182,7 +143,7 @@ typedef struct {
bool is_in_netlink;
/* Additional data that depends on the link-type (IFLA_INFO_DATA) */
NMPObject *lnk;
const NMPObject *lnk;
} netlink;
struct {
@ -266,9 +227,10 @@ typedef struct {
} NMPObjectIP6Route;
struct _NMPObject {
const NMPClass *_class;
int _ref_count;
bool is_cached;
union {
NMDedupMultiObj parent;
const NMPClass *_class;
};
union {
NMPlatformObject object;
@ -326,8 +288,6 @@ NMP_CLASS_IS_VALID (const NMPClass *klass)
&& ((((char *) klass) - ((char *) _nmp_classes)) % (sizeof (_nmp_classes[0]))) == 0;
}
#define NMP_REF_COUNT_STACKINIT (G_MAXINT)
static inline NMPObject *
NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj)
{
@ -336,7 +296,7 @@ NMP_OBJECT_UP_CAST(const NMPlatformObject *plobj)
obj = plobj
? (NMPObject *) ( &(((char *) plobj)[-((int) G_STRUCT_OFFSET (NMPObject, object))]) )
: NULL;
nm_assert (!obj || (obj->_ref_count > 0 && NMP_CLASS_IS_VALID (obj->_class)));
nm_assert (!obj || (obj->parent._ref_count > 0 && NMP_CLASS_IS_VALID (obj->_class)));
return obj;
}
#define NMP_OBJECT_UP_CAST(plobj) (NMP_OBJECT_UP_CAST ((const NMPlatformObject *) (plobj)))
@ -345,7 +305,7 @@ static inline gboolean
NMP_OBJECT_IS_VALID (const NMPObject *obj)
{
nm_assert (!obj || ( obj
&& obj->_ref_count > 0
&& obj->parent._ref_count > 0
&& NMP_CLASS_IS_VALID (obj->_class)));
/* There isn't really much to check. Either @obj is NULL, or we must
@ -358,7 +318,7 @@ NMP_OBJECT_IS_STACKINIT (const NMPObject *obj)
{
nm_assert (!obj || NMP_OBJECT_IS_VALID (obj));
return obj && obj->_ref_count == NMP_REF_COUNT_STACKINIT;
return obj && obj->parent._ref_count == NM_OBJ_REF_COUNT_STACKINIT;
}
static inline const NMPClass *
@ -377,12 +337,84 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN;
}
#define NMP_OBJECT_CAST_LINK(obj) \
({ \
typeof (obj) _obj = (obj); \
\
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_LINK); \
_obj ? &_NM_CONSTCAST (NMPObject, _obj)->link : NULL; \
})
#define NMP_OBJECT_CAST_IP4_ADDRESS(obj) \
({ \
typeof (obj) _obj = (obj); \
\
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \
_obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip4_address : NULL; \
})
#define NMP_OBJECT_CAST_IP6_ADDRESS(obj) \
({ \
typeof (obj) _obj = (obj); \
\
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \
_obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip6_address : NULL; \
})
#define NMP_OBJECT_CAST_IPX_ROUTE(obj) \
({ \
typeof (obj) _obj = (obj); \
\
nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \
_obj ? &_NM_CONSTCAST (NMPObject, _obj)->ipx_route : NULL; \
})
#define NMP_OBJECT_CAST_IP_ROUTE(obj) \
({ \
typeof (obj) _obj = (obj); \
\
nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \
_obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip_route : NULL; \
})
#define NMP_OBJECT_CAST_IP4_ROUTE(obj) \
({ \
typeof (obj) _obj = (obj); \
\
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP4_ROUTE); \
_obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip4_route : NULL; \
})
#define NMP_OBJECT_CAST_IP6_ROUTE(obj) \
({ \
typeof (obj) _obj = (obj); \
\
nm_assert (!_obj || NMP_OBJECT_GET_TYPE ((const NMPObject *) _obj) == NMP_OBJECT_TYPE_IP6_ROUTE); \
_obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip6_route : NULL; \
})
const NMPClass *nmp_class_from_type (NMPObjectType obj_type);
NMPObject *nmp_object_ref (NMPObject *object);
void nmp_object_unref (NMPObject *object);
static inline const NMPObject *
nmp_object_ref (const NMPObject *obj)
{
/* ref and unref accept const pointers. NMPObject is supposed to be shared
* and kept immutable. Disallowing to take/retrun a reference to a const
* NMPObject is cumbersome, because callers are precisely expected to
* keep a ref on the otherwise immutable object. */
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), NULL);
g_return_val_if_fail (obj->parent._ref_count != NM_OBJ_REF_COUNT_STACKINIT, NULL);
return (const NMPObject *) nm_dedup_multi_obj_ref ((const NMDedupMultiObj *) obj);
}
static inline const NMPObject *
nmp_object_unref (const NMPObject *obj)
{
nm_dedup_multi_obj_unref ((const NMDedupMultiObj *) obj);
return NULL;
}
NMPObject *nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plob);
NMPObject *nmp_object_new_link (int ifindex);
@ -395,6 +427,7 @@ const NMPObject *nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex,
const NMPObject *nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric);
const char *nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size);
guint nmp_object_hash (const NMPObject *obj);
int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2);
gboolean nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2);
void nmp_object_copy (NMPObject *dst, const NMPObject *src, gboolean id_only);
@ -404,13 +437,13 @@ guint nmp_object_id_hash (const NMPObject *obj);
gboolean nmp_object_is_alive (const NMPObject *obj);
gboolean nmp_object_is_visible (const NMPObject *obj);
void _nmp_object_fixup_link_udev_fields (NMPObject *obj, gboolean use_udev);
void _nmp_object_fixup_link_udev_fields (NMPObject **obj_new, NMPObject *obj_orig, gboolean use_udev);
#define nm_auto_nmpobj __attribute__((cleanup(_nm_auto_nmpobj_cleanup)))
static inline void
_nm_auto_nmpobj_cleanup (NMPObject **pobj)
_nm_auto_nmpobj_cleanup (gpointer p)
{
nmp_object_unref (*pobj);
nmp_object_unref (*((const NMPObject **) p));
}
typedef struct _NMPCache NMPCache;
@ -418,23 +451,88 @@ typedef struct _NMPCache NMPCache;
typedef void (*NMPCachePreHook) (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
typedef gboolean (*NMPObjectMatchFn) (const NMPObject *obj, gpointer user_data);
gboolean nmp_cache_id_equal (const NMPCacheId *a, const NMPCacheId *b);
guint nmp_cache_id_hash (const NMPCacheId *id);
NMPCacheId *nmp_cache_id_clone (const NMPCacheId *id);
void nmp_cache_id_destroy (NMPCacheId *id);
const NMDedupMultiEntry *nmp_cache_lookup_entry_link (const NMPCache *cache, int ifindex);
NMPCacheId *nmp_cache_id_init_object_type (NMPCacheId *id, NMPObjectType obj_type, gboolean visible_only);
NMPCacheId *nmp_cache_id_init_addrroute_visible_by_ifindex (NMPCacheId *id, NMPObjectType obj_type, int ifindex);
NMPCacheId *nmp_cache_id_init_routes_visible (NMPCacheId *id, NMPObjectType obj_type, gboolean with_default, gboolean with_non_default, int ifindex);
NMPCacheId *nmp_cache_id_init_link_by_ifname (NMPCacheId *id, const char *ifname);
NMPCacheId *nmp_cache_id_init_routes_by_destination_ip4 (NMPCacheId *id, guint32 network, guint8 plen, guint32 metric);
NMPCacheId *nmp_cache_id_init_routes_by_destination_ip6 (NMPCacheId *id, const struct in6_addr *network, guint8 plen, guint32 metric);
const NMPlatformObject *const *nmp_cache_lookup_multi (const NMPCache *cache, const NMPCacheId *cache_id, guint *out_len);
GArray *nmp_cache_lookup_multi_to_array (const NMPCache *cache, NMPObjectType obj_type, const NMPCacheId *cache_id);
const NMPObject *nmp_cache_lookup_obj (const NMPCache *cache, const NMPObject *obj);
const NMPObject *nmp_cache_lookup_link (const NMPCache *cache, int ifindex);
typedef struct _NMPLookup NMPLookup;
struct _NMPLookup {
NMPCacheIdType cache_id_type;
NMPObject selector_obj;
};
const NMDedupMultiHeadEntry *nmp_cache_lookup_all (const NMPCache *cache,
NMPCacheIdType cache_id_type,
const NMPObject *select_obj);
static inline const NMDedupMultiHeadEntry *
nmp_cache_lookup (const NMPCache *cache,
const NMPLookup *lookup)
{
return nmp_cache_lookup_all (cache, lookup->cache_id_type, &lookup->selector_obj);
}
const NMPLookup *nmp_lookup_init_obj_type (NMPLookup *lookup,
NMPObjectType obj_type);
const NMPLookup *nmp_lookup_init_link_by_ifname (NMPLookup *lookup,
const char *ifname);
const NMPLookup *nmp_lookup_init_addrroute (NMPLookup *lookup,
NMPObjectType obj_type,
int ifindex);
const NMPLookup *nmp_lookup_init_route_visible (NMPLookup *lookup,
NMPObjectType obj_type,
int ifindex,
gboolean only_default);
const NMPLookup *nmp_lookup_init_route_by_dest (NMPLookup *lookup,
int addr_family,
gconstpointer network,
guint plen,
guint32 metric);
GArray *nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry,
NMPObjectType obj_type,
gboolean visible_only);
static inline gboolean
nmp_cache_iter_next (NMDedupMultiIter *iter, const NMPObject **out_obj)
{
gboolean has_next;
has_next = nm_dedup_multi_iter_next (iter);
if (has_next) {
nm_assert (NMP_OBJECT_IS_VALID (iter->current->obj));
NM_SET_OUT (out_obj, iter->current->obj);
}
return has_next;
}
static inline gboolean
nmp_cache_iter_next_link (NMDedupMultiIter *iter, const NMPlatformLink **out_obj)
{
gboolean has_next;
has_next = nm_dedup_multi_iter_next (iter);
if (has_next) {
nm_assert (NMP_OBJECT_GET_TYPE (iter->current->obj) == NMP_OBJECT_TYPE_LINK);
NM_SET_OUT (out_obj, &(((const NMPObject *) iter->current->obj)->link));
}
return has_next;
}
#define nmp_cache_iter_for_each(iter, head, obj) \
for (nm_dedup_multi_iter_init ((iter), \
(head)); \
nmp_cache_iter_next ((iter), (obj)); \
)
#define nmp_cache_iter_for_each_link(iter, head, obj) \
for (nm_dedup_multi_iter_init ((iter), \
(head)); \
nmp_cache_iter_next_link ((iter), (obj)); \
)
const NMPObject *nmp_cache_find_other_route_for_same_destination (const NMPCache *cache, const NMPObject *route);
const NMPObject *nmp_cache_lookup_link_full (const NMPCache *cache,
@ -444,10 +542,8 @@ const NMPObject *nmp_cache_lookup_link_full (const NMPCache *cache,
NMLinkType link_type,
NMPObjectMatchFn match_fn,
gpointer user_data);
GHashTable *nmp_cache_lookup_all_to_hash (const NMPCache *cache,
NMPCacheId *cache_id,
GHashTable *hash);
gboolean nmp_cache_link_connected_for_slave (int ifindex_master, const NMPObject *slave);
gboolean nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *master, const NMPObject *potential_slave, const NMPObject *ignore_slave);
const NMPObject *nmp_cache_link_connected_needs_toggle_by_ifindex (const NMPCache *cache, int master_ifindex, const NMPObject *potential_slave, const NMPObject *ignore_slave);
@ -455,13 +551,141 @@ gboolean nmp_cache_use_udev_get (const NMPCache *cache);
void ASSERT_nmp_cache_is_consistent (const NMPCache *cache);
NMPCacheOpsType nmp_cache_remove (NMPCache *cache, const NMPObject *obj, gboolean equals_by_ptr, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, struct udev_device *udevice, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data);
NMPCacheOpsType nmp_cache_remove (NMPCache *cache,
const NMPObject *obj_needle,
gboolean equals_by_ptr,
const NMPObject **out_obj_old);
NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache,
const NMPObject *obj_needle,
const NMPObject **out_obj_old,
const NMPObject **out_obj_new);
NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache,
NMPObject *obj,
const NMPObject **out_obj_old,
const NMPObject **out_obj_new);
NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache,
int ifindex,
struct udev_device *udevice,
const NMPObject **out_obj_old,
const NMPObject **out_obj_new);
NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache,
int ifindex,
const NMPObject **out_obj_old,
const NMPObject **out_obj_new);
NMPCache *nmp_cache_new (gboolean use_udev);
void nmp_cache_dirty_set_all (NMPCache *cache, NMPObjectType obj_type);
NMPCache *nmp_cache_new (NMDedupMultiIndex *multi_idx, gboolean use_udev);
void nmp_cache_free (NMPCache *cache);
static inline void
ASSERT_nmp_cache_ops (const NMPCache *cache,
NMPCacheOpsType ops_type,
const NMPObject *obj_old,
const NMPObject *obj_new)
{
#if NM_MORE_ASSERTS
nm_assert (cache);
nm_assert (obj_old || obj_new);
nm_assert (!obj_old || ( NMP_OBJECT_IS_VALID (obj_old)
&& !NMP_OBJECT_IS_STACKINIT (obj_old)
&& nmp_object_is_alive (obj_old)));
nm_assert (!obj_new || ( NMP_OBJECT_IS_VALID (obj_new)
&& !NMP_OBJECT_IS_STACKINIT (obj_new)
&& nmp_object_is_alive (obj_new)));
switch (ops_type) {
case NMP_CACHE_OPS_UNCHANGED:
nm_assert (obj_old == obj_new);
break;
case NMP_CACHE_OPS_ADDED:
nm_assert (!obj_old && obj_new);
break;
case NMP_CACHE_OPS_UPDATED:
nm_assert (obj_old && obj_new && obj_old != obj_new);
break;
case NMP_CACHE_OPS_REMOVED:
nm_assert (obj_old && !obj_new);
break;
default:
nm_assert_not_reached ();
}
nm_assert (obj_new == NULL || obj_old == NULL || nmp_object_id_equal (obj_new, obj_old));
nm_assert (!obj_old || !obj_new || NMP_OBJECT_GET_CLASS (obj_old) == NMP_OBJECT_GET_CLASS (obj_new));
nm_assert (obj_new == nmp_cache_lookup_obj (cache, obj_new ?: obj_old));
#endif
}
static inline const NMDedupMultiHeadEntry *
nm_platform_lookup_obj_type (NMPlatform *platform,
NMPObjectType obj_type)
{
NMPLookup lookup;
nmp_lookup_init_obj_type (&lookup, obj_type);
return nm_platform_lookup (platform, &lookup);
}
static inline const NMDedupMultiHeadEntry *
nm_platform_lookup_link_by_ifname (NMPlatform *platform,
const char *ifname)
{
NMPLookup lookup;
nmp_lookup_init_link_by_ifname (&lookup, ifname);
return nm_platform_lookup (platform, &lookup);
}
static inline const NMDedupMultiHeadEntry *
nm_platform_lookup_addrroute (NMPlatform *platform,
NMPObjectType obj_type,
int ifindex)
{
NMPLookup lookup;
nmp_lookup_init_addrroute (&lookup, obj_type, ifindex);
return nm_platform_lookup (platform, &lookup);
}
static inline const NMDedupMultiHeadEntry *
nm_platform_lookup_route_visible (NMPlatform *platform,
NMPObjectType obj_type,
int ifindex,
gboolean only_default)
{
NMPLookup lookup;
nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, only_default);
return nm_platform_lookup (platform, &lookup);
}
static inline GPtrArray *
nm_platform_lookup_route_visible_clone (NMPlatform *platform,
NMPObjectType obj_type,
int ifindex,
gboolean only_default,
gboolean (*predicate) (const NMPObject *obj, gpointer user_data),
gpointer user_data)
{
NMPLookup lookup;
nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, only_default);
return nm_platform_lookup_clone (platform, &lookup, predicate, user_data);
}
static inline const NMDedupMultiHeadEntry *
nm_platform_lookup_route_by_dest (NMPlatform *platform,
int addr_family,
gconstpointer network,
guint plen,
guint32 metric)
{
NMPLookup lookup;
nmp_lookup_init_route_by_dest (&lookup, addr_family, network, plen, metric);
return nm_platform_lookup (platform, &lookup);
}
#endif /* __NMP_OBJECT_H__ */

View file

@ -29,8 +29,8 @@ test_cleanup_internal (void)
int ifindex;
GArray *addresses4;
GArray *addresses6;
GArray *routes4;
GArray *routes6;
GPtrArray *routes4;
GPtrArray *routes6;
in_addr_t addr4;
in_addr_t network4;
int plen4 = 24;
@ -72,8 +72,8 @@ test_cleanup_internal (void)
addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
routes4 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
routes4 = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex);
routes6 = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, ifindex);
g_assert_cmpint (addresses4->len, ==, 1);
g_assert_cmpint (addresses6->len, ==, 2); /* also has a IPv6 LL address. */
@ -82,26 +82,24 @@ test_cleanup_internal (void)
g_array_unref (addresses4);
g_array_unref (addresses6);
g_array_unref (routes4);
g_array_unref (routes6);
g_ptr_array_unref (routes4);
g_ptr_array_unref (routes6);
/* Delete interface with all addresses and routes */
g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
routes4 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
routes4 = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex);
routes6 = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, ifindex);
g_assert_cmpint (addresses4->len, ==, 0);
g_assert_cmpint (addresses6->len, ==, 0);
g_assert_cmpint (routes4->len, ==, 0);
g_assert_cmpint (routes6->len, ==, 0);
g_assert (!routes4);
g_assert (!routes6);
g_array_unref (addresses4);
g_array_unref (addresses6);
g_array_unref (routes4);
g_array_unref (routes6);
}
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;

View file

@ -156,9 +156,9 @@ link_callback (NMPlatform *platform, int obj_type_i, int ifindex, NMPlatformLink
{
const NMPObjectType obj_type = obj_type_i;
const NMPlatformSignalChangeType change_type = change_type_i;
GArray *links;
NMPlatformLink *cached;
int i;
NMPLookup lookup;
NMDedupMultiIter iter;
const NMPlatformLink *cached;
g_assert_cmpint (obj_type, ==, NMP_OBJECT_TYPE_LINK);
g_assert (received);
@ -188,19 +188,21 @@ link_callback (NMPlatform *platform, int obj_type_i, int ifindex, NMPlatformLink
/* Check the data */
g_assert (received->ifindex > 0);
links = nm_platform_link_get_all (NM_PLATFORM_GET, TRUE);
for (i = 0; i < links->len; i++) {
cached = &g_array_index (links, NMPlatformLink, i);
nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK);
nmp_cache_iter_for_each_link (&iter,
nm_platform_lookup (platform, &lookup),
&cached) {
if (!nmp_object_is_visible (NMP_OBJECT_UP_CAST (cached)))
continue;
if (cached->ifindex == received->ifindex) {
g_assert_cmpint (nm_platform_link_cmp (cached, received), ==, 0);
g_assert (!memcmp (cached, received, sizeof (*cached)));
if (data->change_type == NM_PLATFORM_SIGNAL_REMOVED)
g_error ("Deleted link still found in the local cache.");
g_array_unref (links);
return;
}
}
g_array_unref (links);
if (data->change_type != NM_PLATFORM_SIGNAL_REMOVED)
g_error ("Added/changed link not found in the local cache.");

View file

@ -5,6 +5,7 @@
#include <arpa/inet.h>
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
#include "platform/nm-fake-platform.h"
#include "platform/nm-linux-platform.h"
@ -187,6 +188,30 @@ void nmtstp_ip6_route_add (NMPlatform *platform,
guint32 metric,
guint32 mss);
static inline GPtrArray *
nmtstp_ip4_route_get_all (NMPlatform *platform,
int ifindex)
{
return nm_platform_lookup_route_visible_clone (platform,
NMP_OBJECT_TYPE_IP4_ROUTE,
ifindex,
FALSE,
nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
NULL);
}
static inline GPtrArray *
nmtstp_ip6_route_get_all (NMPlatform *platform,
int ifindex)
{
return nm_platform_lookup_route_visible_clone (platform,
NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex,
FALSE,
nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
NULL);
}
/*****************************************************************************/
const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type);

View file

@ -44,7 +44,7 @@ static void
test_link_get_all (void)
{
gs_unref_object NMPlatform *platform = NULL;
gs_unref_array GArray *links = NULL;
gs_unref_ptrarray GPtrArray *links = NULL;
platform = nm_linux_platform_new (TRUE, NM_PLATFORM_NETNS_SUPPORT_DEFAULT);

View file

@ -264,7 +264,8 @@ test_slave (int master, int type, SignalData *master_changed)
}
g_assert (!nm_platform_link_is_up (NM_PLATFORM_GET, ifindex));
g_assert (!nm_platform_link_is_connected (NM_PLATFORM_GET, ifindex));
if (nm_platform_link_is_connected (NM_PLATFORM_GET, master)) {
if ( nmtstp_is_root_test ()
&& nm_platform_link_is_connected (NM_PLATFORM_GET, master)) {
if (nm_platform_link_get_type (NM_PLATFORM_GET, master) == NM_LINK_TYPE_TEAM) {
/* Older team versions (e.g. Fedora 17) have a bug that team master stays
* IFF_LOWER_UP even if its slave is down. Double check it with iproute2 and if
@ -285,7 +286,7 @@ test_slave (int master, int type, SignalData *master_changed)
g_assert (nm_platform_link_is_connected (NM_PLATFORM_GET, master));
accept_signals (link_changed, 1, 3);
/* NM running, can cause additional change of addrgenmode */
accept_signals (master_changed, 1, 2);
accept_signals (master_changed, 0, 2);
/* Enslave again
*
@ -327,7 +328,7 @@ test_slave (int master, int type, SignalData *master_changed)
ensure_no_signal (link_changed);
accept_signal (link_removed);
}
accept_signals (master_changed, 1, 2);
accept_signals (master_changed, 0, 2);
ensure_no_signal (master_changed);

View file

@ -33,6 +33,60 @@ struct {
/*****************************************************************************/
static void
test_obj_base (void)
{
static const union {
GObject g;
NMPObject k;
} x = { };
static const union {
GTypeClass k;
NMPClass c;
} l = { };
static const GObject *g = &x.g;
static const GTypeClass *k = &l.k;
static const NMPObject *o = &x.k;
static const NMPClass *c = &l.c;
NMObjBaseInst *obj;
gs_unref_object GCancellable *obj_cancellable = g_cancellable_new ();
nm_auto_nmpobj NMPObject *obj_link = nmp_object_new_link (10);
#define STATIC_ASSERT(cond) \
G_STMT_START { \
G_STATIC_ASSERT (cond); \
G_STATIC_ASSERT_EXPR (cond); \
g_assert (cond); \
} G_STMT_END
STATIC_ASSERT (&g->g_type_instance == (void *) &o->_class);
STATIC_ASSERT (&g->g_type_instance.g_class == (void *) &o->_class);
STATIC_ASSERT (sizeof (o->parent.parent) == sizeof (GTypeInstance));
STATIC_ASSERT (&c->parent == (void *) c);
STATIC_ASSERT (&c->parent.parent.g_type_class == (void *) c);
STATIC_ASSERT (&c->parent.parent.g_type == (void *) c);
STATIC_ASSERT (&c->parent.parent.g_type == &k->g_type);
STATIC_ASSERT (sizeof (c->parent.parent) == sizeof (GTypeClass));
STATIC_ASSERT (&o->parent == (void *) o);
STATIC_ASSERT (&o->parent.klass == (void *) &o->_class);
obj = (NMObjBaseInst *) obj_cancellable;
g_assert (!NMP_CLASS_IS_VALID ((NMPClass *) obj->klass));
g_assert (G_TYPE_CHECK_INSTANCE_TYPE (obj, G_TYPE_CANCELLABLE));
obj = (NMObjBaseInst *) obj_link;
g_assert (NMP_CLASS_IS_VALID ((NMPClass *) obj->klass));
g_assert (!G_TYPE_CHECK_INSTANCE_TYPE (obj, G_TYPE_CANCELLABLE));
}
/*****************************************************************************/
static gboolean
_nmp_object_id_equal (const NMPObject *a, const NMPObject *b)
{
@ -56,150 +110,144 @@ _nmp_object_equal (const NMPObject *a, const NMPObject *b)
/*****************************************************************************/
static void
_assert_cache_multi_lookup_contains (const NMPCache *cache, const NMPCacheId *cache_id, const NMPObject *obj, gboolean contains)
_assert_cache_multi_lookup_contains (const NMPCache *cache, const NMDedupMultiHeadEntry *head_entry, const NMPObject *obj, gboolean visible_only, gboolean contains)
{
const NMPlatformObject *const *objects;
guint i, len;
NMDedupMultiIter iter;
gboolean found;
guint i, len;
const NMPObject *o;
g_assert (cache_id);
g_assert (NMP_OBJECT_IS_VALID (obj));
g_assert (nmp_cache_lookup_obj (cache, obj) == obj);
g_assert (!head_entry || (head_entry->len > 0 && c_list_length (&head_entry->lst_entries_head) == head_entry->len));
objects = nmp_cache_lookup_multi (cache, cache_id, &len);
g_assert ((len == 0 && !objects) || (len > 0 && objects && !objects[len]));
len = head_entry ? head_entry->len : 0;
found = FALSE;
for (i = 0; i < len; i++) {
NMPObject *o;
g_assert (objects[i]);
o = NMP_OBJECT_UP_CAST (objects[i]);
i = 0;
nmp_cache_iter_for_each (&iter,
head_entry,
&o) {
g_assert (NMP_OBJECT_IS_VALID (o));
if (obj == o) {
g_assert (!found);
found = TRUE;
if ( !visible_only
|| nmp_object_is_visible (o)) {
g_assert (!found);
found = TRUE;
}
}
i++;
}
g_assert (len == i);
g_assert (!!contains == found);
}
static void
_assert_cache_multi_lookup_contains_link (const NMPCache *cache,
gboolean visible_only,
const NMPObject *obj,
gboolean contains)
{
const NMDedupMultiHeadEntry *head_entry;
NMPLookup lookup;
g_assert (cache);
nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK);
head_entry = nmp_cache_lookup (cache, &lookup);
_assert_cache_multi_lookup_contains (cache, head_entry, obj, visible_only, contains);
}
/*****************************************************************************/
typedef struct {
NMPCache *cache;
NMPCacheOpsType expected_ops_type;
const NMPObject *obj_clone;
NMPObject *new_clone;
gboolean was_visible;
gboolean called;
} _NMPCacheUpdateData;
static void
_nmp_cache_update_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data)
ops_post_check (NMPCache *cache,
NMPCacheOpsType ops_type,
const NMPObject *obj_old,
const NMPObject *obj_new,
const NMPObject *obj_new_expected,
NMPCacheOpsType expected_ops_type)
{
_NMPCacheUpdateData *data = user_data;
g_assert (cache);
g_assert (data);
g_assert (!data->called);
g_assert (data->cache == cache);
g_assert_cmpint (data->expected_ops_type, ==, ops_type);
g_assert_cmpint (expected_ops_type, ==, ops_type);
switch (ops_type) {
case NMP_CACHE_OPS_ADDED:
g_assert (!old);
g_assert (NMP_OBJECT_IS_VALID (new));
g_assert (nmp_object_is_alive (new));
g_assert (nmp_object_id_equal (data->obj_clone, new));
g_assert (nmp_object_equal (data->obj_clone, new));
g_assert (!obj_old);
g_assert (NMP_OBJECT_IS_VALID (obj_new));
g_assert (nmp_object_is_alive (obj_new));
g_assert (nmp_object_id_equal (obj_new_expected, obj_new));
g_assert (nmp_object_equal (obj_new_expected, obj_new));
break;
case NMP_CACHE_OPS_UPDATED:
g_assert (NMP_OBJECT_IS_VALID (old));
g_assert (NMP_OBJECT_IS_VALID (new));
g_assert (nmp_object_is_alive (old));
g_assert (nmp_object_is_alive (new));
g_assert (nmp_object_id_equal (data->obj_clone, new));
g_assert (nmp_object_id_equal (data->obj_clone, old));
g_assert (nmp_object_id_equal (old, new));
g_assert (nmp_object_equal (data->obj_clone, new));
g_assert (!nmp_object_equal (data->obj_clone, old));
g_assert (!nmp_object_equal (old, new));
g_assert (obj_old != obj_new);
g_assert (NMP_OBJECT_IS_VALID (obj_old));
g_assert (NMP_OBJECT_IS_VALID (obj_new));
g_assert (nmp_object_is_alive (obj_old));
g_assert (nmp_object_is_alive (obj_new));
g_assert (nmp_object_id_equal (obj_new_expected, obj_new));
g_assert (nmp_object_id_equal (obj_new_expected, obj_old));
g_assert (nmp_object_id_equal (obj_old, obj_new));
g_assert (nmp_object_equal (obj_new_expected, obj_new));
g_assert (!nmp_object_equal (obj_new_expected, obj_old));
g_assert (!nmp_object_equal (obj_old, obj_new));
break;
case NMP_CACHE_OPS_REMOVED:
g_assert (!new);
g_assert (NMP_OBJECT_IS_VALID (old));
g_assert (nmp_object_is_alive (old));
g_assert (nmp_object_id_equal (data->obj_clone, old));
g_assert (!obj_new);
g_assert (NMP_OBJECT_IS_VALID (obj_old));
g_assert (nmp_object_is_alive (obj_old));
if (obj_new_expected)
g_assert (nmp_object_id_equal (obj_new_expected, obj_old));
break;
case NMP_CACHE_OPS_UNCHANGED:
g_assert (obj_old == obj_new);
if (obj_old) {
g_assert (NMP_OBJECT_IS_VALID (obj_old));
g_assert (nmp_object_is_alive (obj_old));
g_assert (nmp_object_equal (obj_old, obj_new));
g_assert (nmp_object_id_equal (obj_new_expected, obj_new));
} else
g_assert (!obj_new_expected);
break;
default:
g_assert_not_reached ();
}
data->was_visible = old ? nmp_object_is_visible (old) : FALSE;
data->new_clone = new ? nmp_object_clone (new, FALSE) : NULL;
data->called = TRUE;
}
static void
_nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCacheOpsType expected_ops_type)
_nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, const NMPObject **out_obj_old, const NMPObject **out_obj_new, NMPCacheOpsType expected_ops_type)
{
NMPCacheOpsType ops_type;
NMPObject *obj2;
gboolean was_visible;
nm_auto_nmpobj NMPObject *obj_clone = nmp_object_clone (obj, FALSE);
nm_auto_nmpobj NMPObject *new_clone = NULL;
const NMPObject *obj_prev;
const NMPObject *obj_old;
_NMPCacheUpdateData data = {
.cache = cache,
.expected_ops_type = expected_ops_type,
.obj_clone = obj_clone,
};
obj_old = nmp_cache_lookup_link (cache, obj->object.ifindex);
if (obj_old && obj_old->_link.udev.device)
obj_clone->_link.udev.device = udev_device_ref (obj_old->_link.udev.device);
_nmp_object_fixup_link_udev_fields (obj_clone, nmp_cache_use_udev_get (cache));
const NMPObject *obj_new;
nm_auto_nmpobj NMPObject *obj_new_expected = NULL;
g_assert (cache);
g_assert (NMP_OBJECT_IS_VALID (obj));
ops_type = nmp_cache_update_netlink (cache, obj, &obj2, &was_visible, _nmp_cache_update_hook, &data);
obj_prev = nmp_cache_lookup_link (cache, obj->object.ifindex);
obj_new_expected = nmp_object_clone (obj, FALSE);
if (obj_prev && obj_prev->_link.udev.device)
obj_new_expected->_link.udev.device = udev_device_ref (obj_prev->_link.udev.device);
_nmp_object_fixup_link_udev_fields (&obj_new_expected, NULL, nmp_cache_use_udev_get (cache));
new_clone = data.new_clone;
ops_type = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new);
ops_post_check (cache, ops_type, obj_old, obj_new,
nmp_object_is_alive (obj_new_expected) ? obj_new_expected : NULL,
expected_ops_type);
g_assert_cmpint (ops_type, ==, expected_ops_type);
if (ops_type != NMP_CACHE_OPS_UNCHANGED) {
g_assert (NMP_OBJECT_IS_VALID (obj2));
g_assert (data.called);
g_assert_cmpint (data.was_visible, ==, was_visible);
if (ops_type == NMP_CACHE_OPS_REMOVED)
g_assert (!data.new_clone);
else {
g_assert (data.new_clone);
g_assert (nmp_object_equal (obj2, data.new_clone));
}
} else {
g_assert (!data.called);
g_assert (!obj2 || was_visible == nmp_object_is_visible (obj2));
}
g_assert (!obj2 || nmp_object_id_equal (obj, obj2));
if (ops_type != NMP_CACHE_OPS_REMOVED && obj2)
g_assert (nmp_object_equal (obj, obj2));
if (out_obj)
*out_obj = obj2;
if (out_obj_new)
*out_obj_new = obj_new;
else
nmp_object_unref (obj2);
if (out_was_visible)
*out_was_visible = was_visible;
nmp_object_unref (obj_new);
if (out_obj_old)
*out_obj_old = obj_old;
else
nmp_object_unref (obj_old);
}
static const NMPlatformLink pl_link_2 = {
@ -218,168 +266,189 @@ static void
test_cache_link (void)
{
NMPCache *cache;
NMPObject *obj1, *obj2;
NMPObject *objm1;
const NMPObject *obj_old, *obj_new;
NMPObject objs1;
gboolean was_visible;
NMPCacheId cache_id_storage;
struct udev_device *udev_device_2 = g_list_nth_data (global.udev_devices, 0);
struct udev_device *udev_device_3 = g_list_nth_data (global.udev_devices, 0);
NMPCacheOpsType ops_type;
nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = NULL;
cache = nmp_cache_new (nmtst_get_rand_int () % 2);
multi_idx = nm_dedup_multi_index_new ();
cache = nmp_cache_new (multi_idx, nmtst_get_rand_int () % 2);
/* if we have a link, and don't set is_in_netlink, adding it has no effect. */
obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
g_assert (NMP_OBJECT_UP_CAST (&obj1->object) == obj1);
g_assert (!nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED);
objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
g_assert (NMP_OBJECT_UP_CAST (&objm1->object) == objm1);
g_assert (!nmp_object_is_alive (objm1));
_nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_UNCHANGED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (!obj2);
g_assert (!was_visible);
g_assert (!nmp_cache_lookup_obj (cache, obj1));
g_assert (!obj_old);
g_assert (!obj_new);
g_assert (!nmp_cache_lookup_obj (cache, objm1));
g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)));
nmp_object_unref (obj1);
nmp_object_unref (objm1);
/* Only when setting @is_in_netlink the link is added. */
obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
obj1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_ADDED);
objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
objm1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (objm1));
_nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_ADDED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (nmp_object_equal (obj1, obj2));
g_assert (!was_visible);
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
g_assert (nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
nmp_object_unref (obj1);
nmp_object_unref (obj2);
g_assert (!obj_old);
g_assert (obj_new);
g_assert (objm1 == obj_new);
g_assert (nmp_object_equal (objm1, obj_new));
g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new);
g_assert (nmp_object_is_visible (obj_new));
_assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE);
_assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, TRUE);
nmp_object_unref (objm1);
nmp_object_unref (obj_new);
/* updating the same link with identical value, has no effect. */
obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
obj1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED);
objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
objm1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (objm1));
_nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_UNCHANGED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (obj2 != obj1);
g_assert (nmp_object_equal (obj1, obj2));
g_assert (was_visible);
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
nmp_object_unref (obj1);
nmp_object_unref (obj2);
g_assert (obj_old);
g_assert (obj_new);
g_assert (obj_new != objm1);
g_assert (nmp_object_equal (objm1, obj_new));
g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new);
nmp_object_unref (objm1);
nmp_object_unref (obj_new);
nmp_object_unref (obj_new);
/* remove the link from netlink */
obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
g_assert (!nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_REMOVED);
objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
g_assert (!nmp_object_is_alive (objm1));
_nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_REMOVED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (obj2 != obj1);
g_assert (was_visible);
g_assert (!nmp_cache_lookup_obj (cache, obj1));
g_assert (obj_old);
g_assert (!obj_new);
g_assert (!nmp_cache_lookup_obj (cache, objm1));
g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)));
nmp_object_unref (obj1);
nmp_object_unref (obj2);
nmp_object_unref (objm1);
nmp_object_unref (obj_old);
nmp_object_unref (obj_new);
if (udev_device_2) {
/* now add the link only with aspect UDEV. */
ops_type = nmp_cache_update_link_udev (cache, pl_link_2.ifindex, udev_device_2, &obj2, &was_visible, NULL, NULL);
ops_type = nmp_cache_update_link_udev (cache, pl_link_2.ifindex, udev_device_2, &obj_old, &obj_new);
ASSERT_nmp_cache_is_consistent (cache);
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED);
g_assert (!was_visible);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
g_assert (!nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
nmp_object_unref (obj2);
g_assert (!obj_old);
g_assert (obj_new);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new);
g_assert (!nmp_object_is_visible (obj_new));
_assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, FALSE);
_assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE);
nmp_object_unref (obj_new);
}
/* add it in netlink too. */
obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
obj1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_ADDED);
objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
objm1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (objm1));
_nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_ADDED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (nmp_object_equal (obj1, obj2));
g_assert (!was_visible);
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
g_assert (nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
nmp_object_unref (obj1);
nmp_object_unref (obj2);
if (udev_device_2) {
g_assert (obj_old);
g_assert (!nmp_object_is_visible (obj_old));
} else
g_assert (!obj_old);
g_assert (nmp_object_equal (objm1, obj_new));
g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new);
g_assert (nmp_object_is_visible (obj_new));
_assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, TRUE);
_assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE);
nmp_object_unref (objm1);
nmp_object_unref (obj_old);
nmp_object_unref (obj_new);
/* remove again from netlink. */
obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
obj1->_link.netlink.is_in_netlink = FALSE;
g_assert (!nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_REMOVED);
objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2);
objm1->_link.netlink.is_in_netlink = FALSE;
g_assert (!nmp_object_is_alive (objm1));
_nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_REMOVED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (obj2 != obj1);
g_assert (was_visible);
if (udev_device_2)
g_assert (obj_new == objm1);
else
g_assert (!obj_new);
g_assert (obj_old);
g_assert (nmp_object_is_alive (obj_old));
if (udev_device_2) {
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2);
g_assert (!nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new);
g_assert (!nmp_object_is_visible (obj_new));
_assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, FALSE);
_assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE);
} else {
g_assert (nmp_cache_lookup_obj (cache, obj1) == NULL);
g_assert (nmp_cache_lookup_obj (cache, objm1) == NULL);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == NULL);
g_assert (nmp_object_is_visible (obj2));
g_assert (nmp_object_is_visible (obj_new));
}
nmp_object_unref (obj1);
nmp_object_unref (obj2);
nmp_object_unref (objm1);
nmp_object_unref (obj_old);
nmp_object_unref (obj_new);
/* now another link only with aspect UDEV. */
if (udev_device_3) {
/* now add the link only with aspect UDEV. */
ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, udev_device_3, &obj2, &was_visible, NULL, NULL);
ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, udev_device_3, &obj_old, &obj_new);
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (NMP_OBJECT_IS_VALID (obj2));
g_assert (!was_visible);
g_assert (!nmp_object_is_visible (obj2));
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, FALSE);
g_assert_cmpint (obj2->link.initialized, ==, FALSE);
nmp_object_unref (obj2);
g_assert (NMP_OBJECT_IS_VALID (obj_new));
g_assert (!obj_old);
g_assert (!nmp_object_is_visible (obj_new));
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj_new);
_assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, FALSE);
_assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE);
g_assert_cmpint (obj_new->_link.netlink.is_in_netlink, ==, FALSE);
g_assert_cmpint (obj_new->link.initialized, ==, FALSE);
nmp_object_unref (obj_new);
/* add it in netlink too. */
obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_3);
obj1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (obj1));
_nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UPDATED);
objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_3);
objm1->_link.netlink.is_in_netlink = TRUE;
g_assert (nmp_object_is_alive (objm1));
_nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_UPDATED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (obj2 != obj1);
g_assert (nmp_object_equal (obj1, obj2));
g_assert (!was_visible);
g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
g_assert (nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE);
g_assert_cmpint (obj2->link.initialized, ==, TRUE);
nmp_object_unref (obj1);
nmp_object_unref (obj2);
g_assert (obj_old);
g_assert (obj_new == objm1);
g_assert (nmp_object_equal (objm1, obj_new));
g_assert (!obj_old || !nmp_object_is_visible (obj_old));
g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj_new);
g_assert (nmp_object_is_visible (obj_new));
_assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, TRUE);
_assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE);
g_assert_cmpint (obj_new->_link.netlink.is_in_netlink, ==, TRUE);
g_assert_cmpint (obj_new->link.initialized, ==, TRUE);
nmp_object_unref (objm1);
nmp_object_unref (obj_old);
nmp_object_unref (obj_new);
/* remove UDEV. */
ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, NULL, &obj2, &was_visible, NULL, NULL);
ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, NULL, &obj_old, &obj_new);
g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_UPDATED);
ASSERT_nmp_cache_is_consistent (cache);
g_assert (was_visible);
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2);
g_assert (nmp_object_is_visible (obj2));
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE);
_assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE);
g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE);
g_assert_cmpint (obj2->link.initialized, ==, !nmp_cache_use_udev_get (cache));
nmp_object_unref (obj2);
g_assert (obj_old && nmp_object_is_visible (obj_old));
g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj_new);
g_assert (nmp_object_is_visible (obj_new));
_assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, TRUE);
_assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE);
g_assert_cmpint (obj_new->_link.netlink.is_in_netlink, ==, TRUE);
g_assert_cmpint (obj_new->link.initialized, ==, !nmp_cache_use_udev_get (cache));
nmp_object_unref (obj_new);
nmp_object_unref (obj_old);
}
nmp_cache_free (cache);
@ -429,6 +498,7 @@ main (int argc, char **argv)
udev_enumerate_unref (enumerator);
}
g_test_add_func ("/nmp-object/obj-base", test_obj_base);
g_test_add_func ("/nmp-object/cache_link", test_cache_link);
result = g_test_run ();

View file

@ -182,7 +182,7 @@ test_ip4_route (void)
SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip4_route_callback);
SignalData *route_changed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip4_route_callback);
SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip4_route_callback);
GArray *routes;
GPtrArray *routes;
NMPlatformIP4Route rts[3];
in_addr_t network;
guint8 plen = 24;
@ -219,7 +219,7 @@ test_ip4_route (void)
accept_signals (route_changed, 0, 1);
/* Test route listing */
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex);
memset (rts, 0, sizeof (rts));
rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
rts[0].network = gateway;
@ -246,8 +246,8 @@ test_ip4_route (void)
rts[2].mss = mss;
rts[2].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE);
g_assert_cmpint (routes->len, ==, 3);
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE);
g_array_unref (routes);
nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE);
g_ptr_array_unref (routes);
/* Remove route */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
@ -277,7 +277,7 @@ test_ip6_route (void)
SignalData *route_added = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_ADDED, ip6_route_callback);
SignalData *route_changed = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, ip6_route_callback);
SignalData *route_removed = add_signal (NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, ip6_route_callback);
GArray *routes;
GPtrArray *routes;
NMPlatformIP6Route rts[3];
struct in6_addr network;
guint8 plen = 64;
@ -321,7 +321,7 @@ test_ip6_route (void)
accept_signals (route_changed, 0, 1);
/* Test route listing */
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, ifindex);
memset (rts, 0, sizeof (rts));
rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
rts[0].network = gateway;
@ -348,8 +348,8 @@ test_ip6_route (void)
rts[2].metric = nm_utils_ip6_route_metric_normalize (metric);
rts[2].mss = mss;
g_assert_cmpint (routes->len, ==, 3);
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, rts, routes->len, TRUE);
g_array_unref (routes);
nmtst_platform_ip6_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE);
g_ptr_array_unref (routes);
/* Remove route */
g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric));
@ -400,7 +400,7 @@ test_ip4_route_options (void)
int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
NMPlatformIP4Route route = { };
in_addr_t network;
GArray *routes;
GPtrArray *routes;
NMPlatformIP4Route rts[1];
inet_pton (AF_INET, "172.16.1.0", &network);
@ -421,9 +421,7 @@ test_ip4_route_options (void)
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, &route));
/* Test route listing */
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT |
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex);
memset (rts, 0, sizeof (rts));
rts[0].rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
rts[0].scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK);
@ -438,14 +436,12 @@ test_ip4_route_options (void)
rts[0].initrwnd = 50;
rts[0].mtu = 1350;
rts[0].lock_cwnd = TRUE;
g_assert_cmpint (routes->len, ==, 1);
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, rts, routes->len, TRUE);
nmtst_platform_ip4_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts, routes->len, TRUE);
g_ptr_array_unref (routes);
/* Remove route */
g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, 24, 20));
g_array_unref (routes);
}
@ -454,7 +450,7 @@ test_ip6_route_options (gconstpointer test_data)
{
const int TEST_IDX = GPOINTER_TO_INT (test_data);
const int IFINDEX = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
gs_unref_array GArray *routes = NULL;
GPtrArray *routes;
#define RTS_MAX 1
NMPlatformIP6Route rts_add[RTS_MAX] = { };
NMPlatformIP6Route rts_cmp[RTS_MAX] = { };
@ -523,9 +519,7 @@ test_ip6_route_options (gconstpointer test_data)
for (i = 0; i < rts_n; i++)
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, &rts_add[i]));
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT |
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX);
switch (TEST_IDX) {
case 1:
case 2:
@ -537,9 +531,9 @@ test_ip6_route_options (gconstpointer test_data)
default:
g_assert_not_reached ();
}
g_assert_cmpint (routes->len, ==, rts_n);
nmtst_platform_ip6_routes_equal ((const NMPlatformIP6Route *) routes->data, rts_cmp, rts_n, TRUE);
nmtst_platform_ip6_routes_equal_aptr ((const NMPObject *const*) routes->pdata, rts_cmp, routes->len, TRUE);
g_ptr_array_unref (routes);
for (i = 0; i < rts_n; i++) {
g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, IFINDEX,

View file

@ -409,7 +409,8 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
nm_clear_g_source (&priv->ppp_timeout_handler);
config = nm_ip4_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface));
config = nm_ip4_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface));
memset (&address, 0, sizeof (address));
address.plen = 32;
@ -505,7 +506,8 @@ impl_ppp_manager_set_ip6_config (NMPPPManager *manager,
nm_clear_g_source (&priv->ppp_timeout_handler);
config = nm_ip6_config_new (nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface));
config = nm_ip6_config_new (nm_platform_get_multi_idx (NM_PLATFORM_GET),
nm_platform_link_get_ifindex (NM_PLATFORM_GET, priv->ip_iface));
memset (&addr, 0, sizeof (addr));
addr.plen = 64;

View file

@ -29,7 +29,6 @@
#include <fcntl.h>
#include "NetworkManagerUtils.h"
#include "nm-multi-index.h"
#include "nm-test-utils-core.h"
@ -499,362 +498,6 @@ test_nm_ethernet_address_is_valid (void)
/*****************************************************************************/
typedef struct {
union {
NMMultiIndexId id_base;
guint bucket;
};
} NMMultiIndexIdTest;
typedef struct {
guint64 buckets;
gpointer ptr_value;
} NMMultiIndexTestValue;
static gboolean
_mi_value_bucket_has (const NMMultiIndexTestValue *value, guint bucket)
{
g_assert (value);
g_assert (bucket < 64);
return (value->buckets & (((guint64) 0x01) << bucket)) != 0;
}
static gboolean
_mi_value_bucket_set (NMMultiIndexTestValue *value, guint bucket)
{
g_assert (value);
g_assert (bucket < 64);
if (_mi_value_bucket_has (value, bucket))
return FALSE;
value->buckets |= (((guint64) 0x01) << bucket);
return TRUE;
}
static gboolean
_mi_value_bucket_unset (NMMultiIndexTestValue *value, guint bucket)
{
g_assert (value);
g_assert (bucket < 64);
if (!_mi_value_bucket_has (value, bucket))
return FALSE;
value->buckets &= ~(((guint64) 0x01) << bucket);
return TRUE;
}
static guint
_mi_idx_hash (const NMMultiIndexIdTest *id)
{
g_assert (id && id->bucket < 64);
return id->bucket;
}
static gboolean
_mi_idx_equal (const NMMultiIndexIdTest *a, const NMMultiIndexIdTest *b)
{
g_assert (a && a->bucket < 64);
g_assert (b && b->bucket < 64);
return a->bucket == b->bucket;
}
static NMMultiIndexIdTest *
_mi_idx_clone (const NMMultiIndexIdTest *id)
{
NMMultiIndexIdTest *n;
g_assert (id && id->bucket < 64);
n = g_new0 (NMMultiIndexIdTest, 1);
n->bucket = id->bucket;
return n;
}
static void
_mi_idx_destroy (NMMultiIndexIdTest *id)
{
g_assert (id && id->bucket < 64);
g_free (id);
}
static NMMultiIndexTestValue *
_mi_create_array (guint num_values)
{
NMMultiIndexTestValue *array = g_new0 (NMMultiIndexTestValue, num_values);
guint i;
g_assert (num_values > 0);
for (i = 0; i < num_values; i++) {
array[i].buckets = 0;
array[i].ptr_value = GUINT_TO_POINTER (i + 1);
}
return array;
}
typedef struct {
guint num_values;
guint num_buckets;
NMMultiIndexTestValue *array;
int test_idx;
} NMMultiIndexAssertData;
static gboolean
_mi_assert_index_equals_array_cb (const NMMultiIndexIdTest *id, void *const* values, guint len, NMMultiIndexAssertData *data)
{
guint i;
gboolean has_test_idx = FALSE;
g_assert (id && id->bucket < 64);
g_assert (data);
g_assert (values);
g_assert (len > 0);
g_assert (values[len] == NULL);
g_assert (data->test_idx >= -1 || data->test_idx < data->num_buckets);
g_assert (id->bucket < data->num_buckets);
for (i = 0; i < data->num_values; i++)
g_assert (!_mi_value_bucket_has (&data->array[i], id->bucket));
for (i = 0; i < len; i++) {
guint vi = GPOINTER_TO_UINT (values[i]);
g_assert (vi >= 1);
g_assert (vi <= data->num_values);
vi--;
if (data->test_idx == vi)
has_test_idx = TRUE;
g_assert (data->array[vi].ptr_value == values[i]);
if (!_mi_value_bucket_set (&data->array[vi], id->bucket))
g_assert_not_reached ();
}
g_assert ((data->test_idx == -1 && !has_test_idx) || has_test_idx);
return TRUE;
}
static void
_mi_assert_index_equals_array (guint num_values, guint num_buckets, int test_idx, const NMMultiIndexTestValue *array, const NMMultiIndex *index)
{
NMMultiIndexAssertData data = {
.num_values = num_values,
.num_buckets = num_buckets,
.test_idx = test_idx,
};
NMMultiIndexIter iter;
const NMMultiIndexIdTest *id;
void *const* values;
guint len;
NMMultiIndexTestValue *v;
data.array = _mi_create_array (num_values);
v = test_idx >= 0 ? data.array[test_idx].ptr_value : NULL;
nm_multi_index_foreach (index, v, (NMMultiIndexFuncForeach) _mi_assert_index_equals_array_cb, &data);
if (test_idx >= 0)
g_assert (memcmp (&data.array[test_idx], &array[test_idx], sizeof (NMMultiIndexTestValue)) == 0);
else
g_assert (memcmp (data.array, array, sizeof (NMMultiIndexTestValue) * num_values) == 0);
g_free (data.array);
data.array = _mi_create_array (num_values);
v = test_idx >= 0 ? data.array[test_idx].ptr_value : NULL;
nm_multi_index_iter_init (&iter, index, v);
while (nm_multi_index_iter_next (&iter, (gpointer) &id, &values, &len))
_mi_assert_index_equals_array_cb (id, values, len, &data);
if (test_idx >= 0)
g_assert (memcmp (&data.array[test_idx], &array[test_idx], sizeof (NMMultiIndexTestValue)) == 0);
else
g_assert (memcmp (data.array, array, sizeof (NMMultiIndexTestValue) * num_values) == 0);
g_free (data.array);
}
typedef enum {
MI_OP_ADD,
MI_OP_REMOVE,
MI_OP_MOVE,
} NMMultiIndexOperation;
static void
_mi_rebucket (GRand *rand, guint num_values, guint num_buckets, NMMultiIndexOperation op, guint bucket, guint bucket_old, guint array_idx, NMMultiIndexTestValue *array, NMMultiIndex *index)
{
NMMultiIndexTestValue *v;
NMMultiIndexIdTest id, id_old;
const NMMultiIndexIdTest *id_reverse;
guint64 buckets_old;
guint i;
gboolean had_bucket, had_bucket_old;
g_assert (array_idx < num_values);
g_assert (bucket < (int) num_buckets);
v = &array[array_idx];
buckets_old = v->buckets;
if (op == MI_OP_MOVE)
had_bucket_old = _mi_value_bucket_has (v, bucket_old);
else
had_bucket_old = FALSE;
had_bucket = _mi_value_bucket_has (v, bucket);
switch (op) {
case MI_OP_ADD:
_mi_value_bucket_set (v, bucket);
id.bucket = bucket;
if (nm_multi_index_add (index, &id.id_base, v->ptr_value))
g_assert (!had_bucket);
else
g_assert (had_bucket);
break;
case MI_OP_REMOVE:
_mi_value_bucket_unset (v, bucket);
id.bucket = bucket;
if (nm_multi_index_remove (index, &id.id_base, v->ptr_value))
g_assert (had_bucket);
else
g_assert (!had_bucket);
break;
case MI_OP_MOVE:
_mi_value_bucket_unset (v, bucket_old);
_mi_value_bucket_set (v, bucket);
id.bucket = bucket;
id_old.bucket = bucket_old;
if (nm_multi_index_move (index, &id_old.id_base, &id.id_base, v->ptr_value)) {
if (bucket == bucket_old)
g_assert (had_bucket_old && had_bucket);
else
g_assert (had_bucket_old && !had_bucket);
} else {
if (bucket == bucket_old)
g_assert (!had_bucket_old && !had_bucket);
else
g_assert (!had_bucket_old || had_bucket);
}
break;
default:
g_assert_not_reached ();
}
#if 0
g_print (">>> rebucket: idx=%3u, op=%3s, bucket=%3i%c -> %3i%c, buckets=%08llx -> %08llx %s\n", array_idx,
op == MI_OP_ADD ? "ADD" : (op == MI_OP_REMOVE ? "REM" : "MOV"),
bucket_old, had_bucket_old ? '*' : ' ',
bucket, had_bucket ? '*' : ' ',
(unsigned long long) buckets_old, (unsigned long long) v->buckets,
buckets_old != v->buckets ? "(changed)" : "(unchanged)");
#endif
id_reverse = (const NMMultiIndexIdTest *) nm_multi_index_lookup_first_by_value (index, v->ptr_value);
if (id_reverse)
g_assert (_mi_value_bucket_has (v, id_reverse->bucket));
else
g_assert (v->buckets == 0);
for (i = 0; i < 64; i++) {
id.bucket = i;
if (nm_multi_index_contains (index, &id.id_base, v->ptr_value))
g_assert (_mi_value_bucket_has (v, i));
else
g_assert (!_mi_value_bucket_has (v, i));
}
_mi_assert_index_equals_array (num_values, num_buckets, -1, array, index);
_mi_assert_index_equals_array (num_values, num_buckets, array_idx, array, index);
_mi_assert_index_equals_array (num_values, num_buckets, g_rand_int_range (rand, 0, num_values), array, index);
}
static void
_mi_test_run (guint num_values, guint num_buckets)
{
NMMultiIndex *index = nm_multi_index_new ((NMMultiIndexFuncHash) _mi_idx_hash,
(NMMultiIndexFuncEqual) _mi_idx_equal,
(NMMultiIndexFuncClone) _mi_idx_clone,
(NMMultiIndexFuncDestroy) _mi_idx_destroy);
gs_free NMMultiIndexTestValue *array = _mi_create_array (num_values);
GRand *rand = nmtst_get_rand ();
guint i, i_rd, i_idx, i_bucket;
guint num_buckets_all = num_values * num_buckets;
g_assert (array[0].ptr_value == GUINT_TO_POINTER (1));
_mi_assert_index_equals_array (num_values, num_buckets, -1, array, index);
_mi_rebucket (rand, num_values, num_buckets, MI_OP_ADD, 0, 0, 0, array, index);
_mi_rebucket (rand, num_values, num_buckets, MI_OP_REMOVE, 0, 0, 0, array, index);
if (num_buckets >= 3) {
_mi_rebucket (rand, num_values, num_buckets, MI_OP_ADD, 0, 0, 0, array, index);
_mi_rebucket (rand, num_values, num_buckets, MI_OP_MOVE, 2, 0, 0, array, index);
_mi_rebucket (rand, num_values, num_buckets, MI_OP_REMOVE, 2, 0, 0, array, index);
}
g_assert (nm_multi_index_get_num_groups (index) == 0);
/* randomly change the bucket of entries. */
for (i = 0; i < 5 * num_values; i++) {
guint array_idx = g_rand_int_range (rand, 0, num_values);
guint bucket = g_rand_int_range (rand, 0, num_buckets);
NMMultiIndexOperation op = g_rand_int_range (rand, 0, MI_OP_MOVE + 1);
guint bucket_old = 0;
if (op == MI_OP_MOVE) {
if ((g_rand_int (rand) % 2) && array[array_idx].buckets != 0) {
guint64 b;
/* choose the highest (existing) bucket. */
bucket_old = 0;
for (b = array[array_idx].buckets; b; b >>= 1)
bucket_old++;
} else {
/* choose a random bucket (even if the item is currently not in that bucket). */
bucket_old = g_rand_int_range (rand, 0, num_buckets);
}
}
_mi_rebucket (rand, num_values, num_buckets, op, bucket, bucket_old, array_idx, array, index);
}
/* remove all elements from all buckets */
i_rd = g_rand_int (rand);
for (i = 0; i < num_buckets_all; i++) {
i_rd = (i_rd + 101) % num_buckets_all;
i_idx = i_rd / num_buckets;
i_bucket = i_rd % num_buckets;
if (_mi_value_bucket_has (&array[i_idx], i_bucket))
_mi_rebucket (rand, num_values, num_buckets, MI_OP_REMOVE, i_bucket, 0, i_idx, array, index);
}
g_assert (nm_multi_index_get_num_groups (index) == 0);
nm_multi_index_free (index);
}
static void
test_nm_multi_index (void)
{
guint i, j;
for (i = 1; i < 7; i++) {
for (j = 1; j < 6; j++)
_mi_test_run (i, j);
}
_mi_test_run (50, 3);
_mi_test_run (50, 18);
}
/*****************************************************************************/
static void
test_nm_utils_new_vlan_name (void)
{
@ -909,7 +552,6 @@ main (int argc, char **argv)
g_test_add_func ("/general/nm_utils_kill_child", test_nm_utils_kill_child);
g_test_add_func ("/general/nm_utils_array_remove_at_indexes", test_nm_utils_array_remove_at_indexes);
g_test_add_func ("/general/nm_ethernet_address_is_valid", test_nm_ethernet_address_is_valid);
g_test_add_func ("/general/nm_multi_index", test_nm_multi_index);
g_test_add_func ("/general/nm_utils_new_vlan_name", test_nm_utils_new_vlan_name);
return g_test_run ();

View file

@ -36,7 +36,7 @@ build_test_config (void)
NMPlatformIP4Route route;
/* Build up the config to subtract */
config = nm_ip4_config_new (1);
config = nmtst_ip4_config_new (1);
addr = *nmtst_platform_ip4_address ("192.168.1.10", "1.2.3.4", 24);
nm_ip4_config_add_address (config, &addr);
@ -121,7 +121,7 @@ test_subtract (void)
g_assert_cmpuint (nm_ip4_config_get_gateway (dst), ==, 0);
g_assert_cmpuint (nm_ip4_config_get_num_routes (dst), ==, 1);
test_route = nm_ip4_config_get_route (dst, 0);
test_route = _nmtst_nm_ip4_config_get_route (dst, 0);
g_assert (test_route != NULL);
g_assert_cmpuint (test_route->network, ==, nmtst_inet4_from_string (expected_route_dest));
g_assert_cmpuint (test_route->plen, ==, expected_route_plen);
@ -156,8 +156,8 @@ test_compare_with_source (void)
NMPlatformIP4Address addr;
NMPlatformIP4Route route;
a = nm_ip4_config_new (1);
b = nm_ip4_config_new (2);
a = nmtst_ip4_config_new (1);
b = nmtst_ip4_config_new (2);
/* Address */
addr = *nmtst_platform_ip4_address ("1.2.3.4", NULL, 24);
@ -189,7 +189,7 @@ test_add_address_with_source (void)
NMPlatformIP4Address addr;
const NMPlatformIP4Address *test_addr;
a = nm_ip4_config_new (1);
a = nmtst_ip4_config_new (1);
/* Test that a higher priority source is not overwritten */
addr = *nmtst_platform_ip4_address ("1.2.3.4", NULL, 24);
@ -229,34 +229,34 @@ test_add_route_with_source (void)
NMPlatformIP4Route route;
const NMPlatformIP4Route *test_route;
a = nm_ip4_config_new (1);
a = nmtst_ip4_config_new (1);
/* Test that a higher priority source is not overwritten */
route = *nmtst_platform_ip4_route ("1.2.3.4", 24, "1.2.3.1");
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_ip4_config_add_route (a, &route);
test_route = nm_ip4_config_get_route (a, 0);
test_route = _nmtst_nm_ip4_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
route.rt_source = NM_IP_CONFIG_SOURCE_VPN;
nm_ip4_config_add_route (a, &route);
test_route = nm_ip4_config_get_route (a, 0);
test_route = _nmtst_nm_ip4_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
/* Test that a lower priority address source is overwritten */
nm_ip4_config_del_route (a, 0);
_nmtst_nm_ip4_config_del_route (a, 0);
route.rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
nm_ip4_config_add_route (a, &route);
test_route = nm_ip4_config_get_route (a, 0);
test_route = _nmtst_nm_ip4_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_KERNEL);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_ip4_config_add_route (a, &route);
test_route = nm_ip4_config_get_route (a, 0);
test_route = _nmtst_nm_ip4_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
g_object_unref (a);
@ -306,7 +306,7 @@ test_strip_search_trailing_dot (void)
{
NMIP4Config *config;
config = nm_ip4_config_new (1);
config = nmtst_ip4_config_new (1);
nm_ip4_config_add_search (config, ".");
nm_ip4_config_add_search (config, "foo");

View file

@ -34,7 +34,7 @@ build_test_config (void)
NMIP6Config *config;
/* Build up the config to subtract */
config = nm_ip6_config_new (1);
config = nmtst_ip6_config_new (1);
nm_ip6_config_add_address (config, nmtst_platform_ip6_address ("abcd:1234:4321::cdde", "1:2:3:4::5", 64));
nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL));
@ -98,7 +98,7 @@ test_subtract (void)
g_assert (nm_ip6_config_get_gateway (dst) == NULL);
g_assert_cmpuint (nm_ip6_config_get_num_routes (dst), ==, 1);
test_route = nm_ip6_config_get_route (dst, 0);
test_route = _nmtst_ip6_config_get_route (dst, 0);
g_assert (test_route != NULL);
tmp = *nmtst_inet6_from_string (expected_route_dest);
@ -127,8 +127,8 @@ test_compare_with_source (void)
NMPlatformIP6Address addr;
NMPlatformIP6Route route;
a = nm_ip6_config_new (1);
b = nm_ip6_config_new (2);
a = nmtst_ip6_config_new (1);
b = nmtst_ip6_config_new (2);
/* Address */
addr = *nmtst_platform_ip6_address ("1122:3344:5566::7788", NULL, 64);
@ -160,7 +160,7 @@ test_add_address_with_source (void)
NMPlatformIP6Address addr;
const NMPlatformIP6Address *test_addr;
a = nm_ip6_config_new (1);
a = nmtst_ip6_config_new (1);
/* Test that a higher priority source is not overwritten */
addr = *nmtst_platform_ip6_address ("1122:3344:5566::7788", NULL, 64);
@ -200,34 +200,34 @@ test_add_route_with_source (void)
NMPlatformIP6Route route;
const NMPlatformIP6Route *test_route;
a = nm_ip6_config_new (1);
a = nmtst_ip6_config_new (1);
/* Test that a higher priority source is not overwritten */
route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_ip6_config_add_route (a, &route);
test_route = nm_ip6_config_get_route (a, 0);
test_route = _nmtst_ip6_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
route.rt_source = NM_IP_CONFIG_SOURCE_VPN;
nm_ip6_config_add_route (a, &route);
test_route = nm_ip6_config_get_route (a, 0);
test_route = _nmtst_ip6_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
/* Test that a lower priority address source is overwritten */
nm_ip6_config_del_route (a, 0);
_nmtst_ip6_config_del_route (a, 0);
route.rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
nm_ip6_config_add_route (a, &route);
test_route = nm_ip6_config_get_route (a, 0);
test_route = _nmtst_ip6_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_KERNEL);
route.rt_source = NM_IP_CONFIG_SOURCE_USER;
nm_ip6_config_add_route (a, &route);
test_route = nm_ip6_config_get_route (a, 0);
test_route = _nmtst_ip6_config_get_route (a, 0);
g_assert_cmpint (test_route->rt_source, ==, NM_IP_CONFIG_SOURCE_USER);
g_object_unref (a);
@ -327,7 +327,7 @@ test_strip_search_trailing_dot (void)
{
NMIP6Config *config;
config = nm_ip6_config_new (1);
config = nmtst_ip6_config_new (1);
nm_ip6_config_add_search (config, ".");
nm_ip6_config_add_search (config, "foo");

View file

@ -143,17 +143,45 @@ update_dev0_ip4 (int ifindex)
static GArray *
ip4_routes (test_fixture *fixture)
ip_routes (test_fixture *fixture, NMPObjectType obj_type)
{
GArray *routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET,
fixture->ifindex0,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
GArray *routes1 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET,
fixture->ifindex1,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
const NMPClass *klass;
GArray *routes;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
guint i;
g_array_append_vals (routes, routes1->data, routes1->len);
g_array_free (routes1, TRUE);
g_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
klass = nmp_class_from_type (obj_type);
routes = g_array_new (FALSE, FALSE, klass->sizeof_public);
for (i = 0; i < 2; i++) {
int ifindex;
if (i == 0)
ifindex = fixture->ifindex0;
else
ifindex = fixture->ifindex1;
pl_head_entry = nm_platform_lookup_route_visible (NM_PLATFORM_GET,
obj_type,
ifindex,
FALSE);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r))
continue;
if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
g_assert (r->ifindex == ifindex);
g_assert (nmp_object_is_visible (plobj));
g_array_append_vals (routes, r, 1);
}
}
return routes;
}
@ -323,7 +351,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
* - 7.0.0.0/8 route, metric 21021 added
* - 7.0.0.0/8 route, metric 22 added
* - 8.0.0.0/8 could be added. */
routes = ip4_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state1, routes->len, TRUE);
g_array_free (routes, TRUE);
@ -334,7 +362,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
setup_dev0_ip4 (fixture->ifindex0, 0, 21);
/* Ensure nothing changed. */
routes = ip4_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
state1[0].mss = 0;
state1[1].metric = 21;
@ -344,7 +372,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
update_dev0_ip4 (fixture->ifindex0);
/* minor changes in the routes. Quite similar to state1. */
routes = ip4_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state2));
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state2, routes->len, TRUE);
g_array_free (routes, TRUE);
@ -356,7 +384,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
* 7.0.0.0/8 gone from dev0, still present on dev1
* 8.0.0.0/8 is present on dev1
* No dev0 routes left. */
routes = ip4_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state3));
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state3, routes->len, TRUE);
g_array_free (routes, TRUE);
@ -364,7 +392,7 @@ test_ip4 (test_fixture *fixture, gconstpointer user_data)
nm_route_manager_route_flush (route_manager_get (), fixture->ifindex1);
/* No routes left. */
routes = ip4_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, 0);
g_array_free (routes, TRUE);
}
@ -521,22 +549,6 @@ update_dev0_ip6 (int ifindex)
g_array_free (routes, TRUE);
}
static GArray *
ip6_routes (test_fixture *fixture)
{
GArray *routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET,
fixture->ifindex0,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
GArray *routes1 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET,
fixture->ifindex1,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
g_array_append_vals (routes, routes1->data, routes1->len);
g_array_free (routes1, TRUE);
return routes;
}
static void
test_ip6 (test_fixture *fixture, gconstpointer user_data)
{
@ -739,7 +751,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data)
* 2001:db8:d34d::/64 on dev1 could not be added
* 2001:db8:1337::/48 on dev0 won over 2001:db8:1337::/48 on dev1 and has metric 1024
* 2001:db8:abad:c0de::/64 routes did not clash */
routes = ip6_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state1, routes->len, TRUE);
g_array_free (routes, TRUE);
@ -750,7 +762,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data)
setup_dev0_ip6 (fixture->ifindex0);
/* Ensure nothing changed. */
routes = ip6_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state1, routes->len, TRUE);
g_array_free (routes, TRUE);
@ -758,7 +770,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data)
update_dev0_ip6 (fixture->ifindex0);
/* 2001:db8:abad:c0de::/64 on dev0 was updated for gateway removal*/
routes = ip6_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state2));
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state2, routes->len, TRUE);
g_array_free (routes, TRUE);
@ -770,7 +782,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data)
* 2001:db8:1337::/48 is now on dev1, metric of 1024 still applies
* 2001:db8:d34d::/64 is present now that 2001:db8:8086::/48 is on dev1
* No dev0 routes left. */
routes = ip6_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state3));
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state3, routes->len, TRUE);
g_array_free (routes, TRUE);
@ -778,7 +790,7 @@ test_ip6 (test_fixture *fixture, gconstpointer user_data)
nm_route_manager_route_flush (route_manager_get (), fixture->ifindex1);
/* No routes left. */
routes = ip6_routes (fixture);
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, 0);
g_array_free (routes, TRUE);
}

View file

@ -942,6 +942,7 @@ print_vpn_config (NMVpnConnection *self)
char *dns_domain = NULL;
guint32 num, i;
char buf[NM_UTILS_INET_ADDRSTRLEN];
NMDedupMultiIter ipconf_iter;
if (priv->ip4_external_gw) {
_LOGI ("Data: VPN Gateway: %s",
@ -954,6 +955,8 @@ print_vpn_config (NMVpnConnection *self)
_LOGI ("Data: Tunnel Device: %s%s%s", NM_PRINT_FMT_QUOTE_STRING (priv->ip_iface));
if (priv->ip4_config) {
const NMPlatformIP4Route *route;
_LOGI ("Data: IPv4 configuration:");
address4 = nm_ip4_config_get_address (priv->ip4_config, 0);
@ -965,10 +968,7 @@ print_vpn_config (NMVpnConnection *self)
_LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet4_ntop (address4->peer_address, NULL));
_LOGI ("Data: Maximum Segment Size (MSS): %d", nm_ip4_config_get_mss (priv->ip4_config));
num = nm_ip4_config_get_num_routes (priv->ip4_config);
for (i = 0; i < num; i++) {
const NMPlatformIP4Route *route = nm_ip4_config_get_route (priv->ip4_config, i);
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) {
_LOGI ("Data: Static Route: %s/%d Next Hop: %s",
nm_utils_inet4_ntop (route->network, NULL),
route->plen,
@ -992,6 +992,8 @@ print_vpn_config (NMVpnConnection *self)
_LOGI ("Data: No IPv4 configuration");
if (priv->ip6_config) {
const NMPlatformIP6Route *route;
_LOGI ("Data: IPv6 configuration:");
address6 = nm_ip6_config_get_address (priv->ip6_config, 0);
@ -1003,10 +1005,7 @@ print_vpn_config (NMVpnConnection *self)
_LOGI ("Data: Internal Point-to-Point Address: %s", nm_utils_inet6_ntop (&address6->peer_address, NULL));
_LOGI ("Data: Maximum Segment Size (MSS): %d", nm_ip6_config_get_mss (priv->ip6_config));
num = nm_ip6_config_get_num_routes (priv->ip6_config);
for (i = 0; i < num; i++) {
const NMPlatformIP6Route *route = nm_ip6_config_get_route (priv->ip6_config, i);
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) {
_LOGI ("Data: Static Route: %s/%d Next Hop: %s",
nm_utils_inet6_ntop (&route->network, NULL),
route->plen,
@ -1046,10 +1045,14 @@ apply_parent_device_config (NMVpnConnection *self)
NMIP6Config *vpn6_parent_config = NULL;
if (priv->ip_ifindex > 0) {
if (priv->ip4_config)
vpn4_parent_config = nm_ip4_config_new (priv->ip_ifindex);
if (priv->ip6_config)
vpn6_parent_config = nm_ip6_config_new (priv->ip_ifindex);
if (priv->ip4_config) {
vpn4_parent_config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns),
priv->ip_ifindex);
}
if (priv->ip6_config) {
vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns),
priv->ip_ifindex);
}
} else {
int ifindex;
@ -1063,11 +1066,13 @@ apply_parent_device_config (NMVpnConnection *self)
* default route. */
ifindex = nm_device_get_ip_ifindex (parent_dev);
if (priv->ip4_config) {
vpn4_parent_config = nm_ip4_config_new (ifindex);
vpn4_parent_config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns),
ifindex);
nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_NO_DNS);
}
if (priv->ip6_config) {
vpn6_parent_config = nm_ip6_config_new (ifindex);
vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns),
ifindex);
nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS);
nm_ip6_config_set_gateway (vpn6_parent_config, NULL);
}
@ -1398,7 +1403,6 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
const char *str;
GVariant *v;
gboolean b;
guint i, n;
int ip_ifindex;
g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT));
@ -1436,7 +1440,8 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
if (ip_ifindex <= 0)
g_return_if_reached ();
config = nm_ip4_config_new (ip_ifindex);
config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns),
ip_ifindex);
nm_ip4_config_set_dns_priority (config, NM_DNS_PRIORITY_DEFAULT_VPN);
memset (&address, 0, sizeof (address));
@ -1498,9 +1503,11 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PRESERVE_ROUTES, "b", &b)
&& b) {
if (priv->ip4_config) {
n = nm_ip4_config_get_num_routes (priv->ip4_config);
for (i = 0; i < n; i++)
nm_ip4_config_add_route (config, nm_ip4_config_get_route (priv->ip4_config, i));
NMDedupMultiIter ipconf_iter;
const NMPlatformIP4Route *route;
nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route)
nm_ip4_config_add_route (config, route);
}
} else if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_ROUTES, "aau", &iter)) {
while (g_variant_iter_next (iter, "@au", &v)) {
@ -1570,7 +1577,6 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
const char *str;
GVariant *v;
gboolean b;
guint i, n;
int ip_ifindex;
g_return_if_fail (dict && g_variant_is_of_type (dict, G_VARIANT_TYPE_VARDICT));
@ -1595,7 +1601,8 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
if (ip_ifindex <= 0)
g_return_if_reached ();
config = nm_ip6_config_new (ip_ifindex);
config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns),
ip_ifindex);
nm_ip6_config_set_dns_priority (config, NM_DNS_PRIORITY_DEFAULT_VPN);
memset (&address, 0, sizeof (address));
@ -1660,9 +1667,11 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict)
if ( g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_PRESERVE_ROUTES, "b", &b)
&& b) {
if (priv->ip6_config) {
n = nm_ip6_config_get_num_routes (priv->ip6_config);
for (i = 0; i < n; i++)
nm_ip6_config_add_route (config, nm_ip6_config_get_route (priv->ip6_config, i));
NMDedupMultiIter ipconf_iter;
const NMPlatformIP6Route *route;
nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route)
nm_ip6_config_add_route (config, route);
}
} else if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP6_CONFIG_ROUTES, "a(ayuayu)", &iter)) {
GVariant *dest, *next_hop;