summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2017-07-07 10:21:58 +0200
committerThomas Haller <thaller@redhat.com>2017-07-07 10:21:58 +0200
commit22cd73d3aa89b8db3f5ecf32232cd09ca329ed93 (patch)
tree2deea6c5f0b2b96439bb79757f8a445b7eba0ec4
parent348959cfa26b8896e7c0bafa4abae0ae77c7767c (diff)
parentb2112ff471f0fd171646e5d0cd159626cb3a9fe6 (diff)
downloadNetworkManager-22cd73d3aa89b8db3f5ecf32232cd09ca329ed93.tar.gz
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
-rw-r--r--Makefile.am7
-rw-r--r--clients/cli/utils.h5
-rw-r--r--clients/common/nm-meta-setting-desc.h17
-rw-r--r--libnm-core/nm-utils.c8
-rw-r--r--libnm-core/tests/test-general.c299
-rw-r--r--shared/nm-utils/c-list.h165
-rw-r--r--shared/nm-utils/nm-dedup-multi.c1025
-rw-r--r--shared/nm-utils/nm-dedup-multi.h379
-rw-r--r--shared/nm-utils/nm-macros-internal.h52
-rw-r--r--shared/nm-utils/nm-obj.h82
-rw-r--r--src/devices/nm-device.c148
-rw-r--r--src/devices/nm-device.h1
-rw-r--r--src/devices/nm-lldp-listener.c10
-rw-r--r--src/devices/wwan/nm-modem-broadband.c6
-rw-r--r--src/devices/wwan/nm-modem-ofono.c3
-rw-r--r--src/dhcp/nm-dhcp-client.c33
-rw-r--r--src/dhcp/nm-dhcp-client.h6
-rw-r--r--src/dhcp/nm-dhcp-dhclient-utils.c8
-rw-r--r--src/dhcp/nm-dhcp-dhclient-utils.h3
-rw-r--r--src/dhcp/nm-dhcp-dhclient.c7
-rw-r--r--src/dhcp/nm-dhcp-manager.c13
-rw-r--r--src/dhcp/nm-dhcp-manager.h3
-rw-r--r--src/dhcp/nm-dhcp-systemd.c23
-rw-r--r--src/dhcp/nm-dhcp-utils.c12
-rw-r--r--src/dhcp/nm-dhcp-utils.h6
-rw-r--r--src/dhcp/tests/test-dhcp-dhclient.c11
-rw-r--r--src/dhcp/tests/test-dhcp-utils.c78
-rw-r--r--src/dns/nm-dns-dnsmasq.c18
-rw-r--r--src/nm-core-utils.c13
-rw-r--r--src/nm-core-utils.h8
-rw-r--r--src/nm-default-route-manager.c91
-rw-r--r--src/nm-dispatcher.c10
-rw-r--r--src/nm-iface-helper.c16
-rw-r--r--src/nm-ip4-config.c586
-rw-r--r--src/nm-ip4-config.h37
-rw-r--r--src/nm-ip6-config.c503
-rw-r--r--src/nm-ip6-config.h25
-rw-r--r--src/nm-manager.c20
-rw-r--r--src/nm-multi-index.c473
-rw-r--r--src/nm-multi-index.h105
-rw-r--r--src/nm-netns.c8
-rw-r--r--src/nm-netns.h2
-rw-r--r--src/nm-pacrunner-manager.c16
-rw-r--r--src/nm-route-manager.c65
-rw-r--r--src/nm-test-utils-core.h68
-rw-r--r--src/nm-types.h2
-rw-r--r--src/platform/nm-fake-platform.c1345
-rw-r--r--src/platform/nm-linux-platform.c923
-rw-r--r--src/platform/nm-linux-platform.h6
-rw-r--r--src/platform/nm-platform-private.h42
-rw-r--r--src/platform/nm-platform.c785
-rw-r--r--src/platform/nm-platform.h72
-rw-r--r--src/platform/nmp-object.c1958
-rw-r--r--src/platform/nmp-object.h438
-rw-r--r--src/platform/tests/test-cleanup.c22
-rw-r--r--src/platform/tests/test-common.c18
-rw-r--r--src/platform/tests/test-common.h25
-rw-r--r--src/platform/tests/test-general.c2
-rw-r--r--src/platform/tests/test-link.c7
-rw-r--r--src/platform/tests/test-nmp-object.c494
-rw-r--r--src/platform/tests/test-route.c38
-rw-r--r--src/ppp/nm-ppp-manager.c6
-rw-r--r--src/tests/test-general-with-expect.c358
-rw-r--r--src/tests/test-ip4-config.c24
-rw-r--r--src/tests/test-ip6-config.c24
-rw-r--r--src/tests/test-route-manager.c84
-rw-r--r--src/vpn/nm-vpn-connection.c57
67 files changed, 6704 insertions, 4500 deletions
diff --git a/Makefile.am b/Makefile.am
index f25fc02711..b97da487fc 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 \
diff --git a/clients/cli/utils.h b/clients/cli/utils.h
index 1724d4391e..19145974ea 100644
--- a/clients/cli/utils.h
+++ b/clients/cli/utils.h
@@ -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;
diff --git a/clients/common/nm-meta-setting-desc.h b/clients/common/nm-meta-setting-desc.h
index c1fd902210..e61b1fc4a6 100644
--- a/clients/common/nm-meta-setting-desc.h
+++ b/clients/common/nm-meta-setting-desc.h
@@ -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;
diff --git a/libnm-core/nm-utils.c b/libnm-core/nm-utils.c
index c52948bd7b..2958cd90d9 100644
--- a/libnm-core/nm-utils.c
+++ b/libnm-core/nm-utils.c
@@ -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);
}
}
}
diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c
index b8c3dc8e12..db261adfec 100644
--- a/libnm-core/tests/test-general.c
+++ b/libnm-core/tests/test-general.c
@@ -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);
diff --git a/shared/nm-utils/c-list.h b/shared/nm-utils/c-list.h
index 07e3f3cecd..557862b6ff 100644
--- a/shared/nm-utils/c-list.h
+++ b/shared/nm-utils/c-list.h
@@ -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.
- */
-static inline void c_list_splice(CList *target, CList *source) {
- if (c_list_is_empty(source))
- return;
-
- /* 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;
-}
-
-/**
- * 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.
+ * On return, the source list will be empty.
*/
-static inline CList *c_list_loop_last(CList *list) {
- return list->prev;
-}
+static inline void c_list_splice(CList *target, CList *source) {
+ 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;
-/**
- * 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;
-}
+ /* attach the tail of @source to the front of @target */
+ source->prev->next = target;
+ target->prev = source->prev;
-/**
- * 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
diff --git a/shared/nm-utils/nm-dedup-multi.c b/shared/nm-utils/nm-dedup-multi.c
new file mode 100644
index 0000000000..92dba89936
--- /dev/null
+++ b/shared/nm-utils/nm-dedup-multi.c
@@ -0,0 +1,1025 @@
+/* -*- 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.
+ */
+
+#include "nm-default.h"
+
+#include "nm-dedup-multi.h"
+
+/*****************************************************************************/
+
+typedef struct {
+ /* the stack-allocated lookup entry. It has a compatible
+ * memory layout with NMDedupMultiEntry and NMDedupMultiHeadEntry.
+ *
+ * It is recognizable by having lst_entries_sentinel.next set to NULL.
+ * Contrary to the other entries, which have lst_entries.next
+ * always non-NULL.
+ * */
+ CList lst_entries_sentinel;
+ const NMDedupMultiObj *obj;
+ const NMDedupMultiIdxType *idx_type;
+ bool lookup_head;
+} LookupEntry;
+
+struct _NMDedupMultiIndex {
+ int ref_count;
+ GHashTable *idx_entries;
+ GHashTable *idx_objs;
+};
+
+/*****************************************************************************/
+
+static void
+ASSERT_idx_type (const NMDedupMultiIdxType *idx_type)
+{
+ nm_assert (idx_type);
+#if NM_MORE_ASSERTS > 10
+ nm_assert (idx_type->klass);
+ nm_assert (idx_type->klass->idx_obj_id_hash);
+ nm_assert (idx_type->klass->idx_obj_id_equal);
+ nm_assert (!!idx_type->klass->idx_obj_partition_hash == !!idx_type->klass->idx_obj_partition_equal);
+ nm_assert (idx_type->lst_idx_head.next);
+#endif
+}
+
+void
+nm_dedup_multi_idx_type_init (NMDedupMultiIdxType *idx_type,
+ const NMDedupMultiIdxTypeClass *klass)
+{
+ nm_assert (idx_type);
+ nm_assert (klass);
+
+ memset (idx_type, 0, sizeof (*idx_type));
+ idx_type->klass = klass;
+ c_list_init (&idx_type->lst_idx_head);
+
+ ASSERT_idx_type (idx_type);
+}
+
+/*****************************************************************************/
+
+static NMDedupMultiEntry *
+_entry_lookup_obj (NMDedupMultiIndex *self,
+ const NMDedupMultiIdxType *idx_type,
+ const NMDedupMultiObj *obj)
+{
+ const LookupEntry stack_entry = {
+ .obj = obj,
+ .idx_type = idx_type,
+ .lookup_head = FALSE,
+ };
+
+ ASSERT_idx_type (idx_type);
+ return g_hash_table_lookup (self->idx_entries, &stack_entry);
+}
+
+static NMDedupMultiHeadEntry *
+_entry_lookup_head (NMDedupMultiIndex *self,
+ const NMDedupMultiIdxType *idx_type,
+ const NMDedupMultiObj *obj)
+{
+ NMDedupMultiHeadEntry *head_entry;
+ const LookupEntry stack_entry = {
+ .obj = obj,
+ .idx_type = idx_type,
+ .lookup_head = TRUE,
+ };
+
+ ASSERT_idx_type (idx_type);
+
+ if (!idx_type->klass->idx_obj_partition_equal) {
+ if (c_list_is_empty (&idx_type->lst_idx_head))
+ head_entry = NULL;
+ else {
+ nm_assert (c_list_length (&idx_type->lst_idx_head) == 1);
+ head_entry = c_list_entry (idx_type->lst_idx_head.next, NMDedupMultiHeadEntry, lst_idx);
+ }
+ nm_assert (head_entry == g_hash_table_lookup (self->idx_entries, &stack_entry));
+ return head_entry;
+ }
+
+ return g_hash_table_lookup (self->idx_entries, &stack_entry);
+}
+
+static void
+_entry_unpack (const NMDedupMultiEntry *entry,
+ const NMDedupMultiIdxType **out_idx_type,
+ const NMDedupMultiObj **out_obj,
+ gboolean *out_lookup_head)
+{
+ const NMDedupMultiHeadEntry *head_entry;
+ const LookupEntry *lookup_entry;
+
+ nm_assert (entry);
+
+ G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (LookupEntry, lst_entries_sentinel) == G_STRUCT_OFFSET (NMDedupMultiEntry, lst_entries));
+ G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, lst_entries) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, lst_entries_head));
+ G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, obj) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, idx_type));
+ G_STATIC_ASSERT_EXPR (G_STRUCT_OFFSET (NMDedupMultiEntry, is_head) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, is_head));
+
+ if (!entry->lst_entries.next) {
+ /* the entry is stack-allocated by _entry_lookup(). */
+ lookup_entry = (LookupEntry *) entry;
+ *out_obj = lookup_entry->obj;
+ *out_idx_type = lookup_entry->idx_type;
+ *out_lookup_head = lookup_entry->lookup_head;
+ } else if (entry->is_head) {
+ head_entry = (NMDedupMultiHeadEntry *) entry;
+ nm_assert (!c_list_is_empty (&head_entry->lst_entries_head));
+ *out_obj = c_list_entry (head_entry->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->obj;
+ *out_idx_type = head_entry->idx_type;
+ *out_lookup_head = TRUE;
+ } else {
+ *out_obj = entry->obj;
+ *out_idx_type = entry->head->idx_type;
+ *out_lookup_head = FALSE;
+ }
+
+ nm_assert (NM_IN_SET (*out_lookup_head, FALSE, TRUE));
+ ASSERT_idx_type (*out_idx_type);
+}
+
+static guint
+_dict_idx_entries_hash (const NMDedupMultiEntry *entry)
+{
+ const NMDedupMultiIdxType *idx_type;
+ const NMDedupMultiObj *obj;
+ gboolean lookup_head;
+ guint h;
+
+ _entry_unpack (entry, &idx_type, &obj, &lookup_head);
+
+ if (idx_type->klass->idx_obj_partition_hash) {
+ nm_assert (obj);
+ h = idx_type->klass->idx_obj_partition_hash (idx_type, obj);
+ } else
+ h = 1914869417;
+
+ if (!lookup_head)
+ h = idx_type->klass->idx_obj_id_hash (idx_type, obj);
+
+ h = NM_HASH_COMBINE (h, GPOINTER_TO_UINT (idx_type));
+ h = NM_HASH_COMBINE (h, lookup_head);
+ return h;
+}
+
+static gboolean
+_dict_idx_entries_equal (const NMDedupMultiEntry *entry_a,
+ const NMDedupMultiEntry *entry_b)
+{
+ const NMDedupMultiIdxType *idx_type_a, *idx_type_b;
+ const NMDedupMultiObj *obj_a, *obj_b;
+ gboolean lookup_head_a, lookup_head_b;
+
+ _entry_unpack (entry_a, &idx_type_a, &obj_a, &lookup_head_a);
+ _entry_unpack (entry_b, &idx_type_b, &obj_b, &lookup_head_b);
+
+ if ( idx_type_a != idx_type_b
+ || lookup_head_a != lookup_head_b)
+ return FALSE;
+ if (!nm_dedup_multi_idx_type_partition_equal (idx_type_a, obj_a, obj_b))
+ return FALSE;
+ if ( !lookup_head_a
+ && !nm_dedup_multi_idx_type_id_equal (idx_type_a, obj_a, obj_b))
+ return FALSE;
+ return TRUE;
+}
+
+/*****************************************************************************/
+
+static gboolean
+_add (NMDedupMultiIndex *self,
+ NMDedupMultiIdxType *idx_type,
+ const NMDedupMultiObj *obj,
+ NMDedupMultiEntry *entry,
+ NMDedupMultiIdxMode mode,
+ const NMDedupMultiEntry *entry_order,
+ NMDedupMultiHeadEntry *head_existing,
+ const NMDedupMultiEntry **out_entry,
+ const NMDedupMultiObj **out_obj_old)
+{
+ NMDedupMultiHeadEntry *head_entry;
+ const NMDedupMultiObj *obj_new, *obj_old;
+ gboolean add_head_entry = FALSE;
+
+ nm_assert (self);
+ ASSERT_idx_type (idx_type);
+ nm_assert (obj);
+ nm_assert (NM_IN_SET (mode,
+ NM_DEDUP_MULTI_IDX_MODE_PREPEND,
+ NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
+ NM_DEDUP_MULTI_IDX_MODE_APPEND,
+ NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE));
+ nm_assert (!head_existing || head_existing->idx_type == idx_type);
+ nm_assert (({
+ const NMDedupMultiHeadEntry *_h;
+ gboolean _ok = TRUE;
+ if (head_existing) {
+ _h = nm_dedup_multi_index_lookup_head (self, idx_type, obj);
+ if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING)
+ _ok = (_h == NULL);
+ else
+ _ok = (_h == head_existing);
+ }
+ _ok;
+ }));
+
+ if (entry) {
+ nm_dedup_multi_entry_set_dirty (entry, FALSE);
+
+ nm_assert (!head_existing || entry->head == head_existing);
+
+ if (entry_order) {
+ nm_assert (entry_order->head == entry->head);
+ nm_assert (c_list_contains (&entry->lst_entries, &entry_order->lst_entries));
+ nm_assert (c_list_contains (&entry_order->lst_entries, &entry->lst_entries));
+ }
+
+ switch (mode) {
+ case NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE:
+ if (entry_order) {
+ if ( entry_order != entry
+ && entry->lst_entries.next != &entry_order->lst_entries) {
+ c_list_unlink (&entry->lst_entries);
+ c_list_link_before ((CList *) &entry_order->lst_entries, &entry->lst_entries);
+ }
+ } else {
+ if (entry->lst_entries.prev != &entry->head->lst_entries_head) {
+ c_list_unlink (&entry->lst_entries);
+ c_list_link_front ((CList *) &entry->head->lst_entries_head, &entry->lst_entries);
+ }
+ }
+ break;
+ case NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE:
+ if (entry_order) {
+ if ( entry_order != entry
+ && entry->lst_entries.prev != &entry_order->lst_entries) {
+ c_list_unlink (&entry->lst_entries);
+ c_list_link_after ((CList *) &entry_order->lst_entries, &entry->lst_entries);
+ }
+ } else {
+ if (entry->lst_entries.next != &entry->head->lst_entries_head) {
+ c_list_unlink (&entry->lst_entries);
+ c_list_link_tail ((CList *) &entry->head->lst_entries_head, &entry->lst_entries);
+ }
+ }
+ break;
+ case NM_DEDUP_MULTI_IDX_MODE_PREPEND:
+ case NM_DEDUP_MULTI_IDX_MODE_APPEND:
+ break;
+ };
+
+ if ( obj == entry->obj
+ || obj->klass->obj_full_equal (obj,
+ entry->obj)) {
+ NM_SET_OUT (out_entry, entry);
+ NM_SET_OUT (out_obj_old, nm_dedup_multi_obj_ref (entry->obj));
+ return FALSE;
+ }
+
+ obj_new = nm_dedup_multi_index_obj_intern (self, obj);
+
+ obj_old = entry->obj;
+ entry->obj = obj_new;
+
+ NM_SET_OUT (out_entry, entry);
+ if (out_obj_old)
+ *out_obj_old = obj_old;
+ else
+ nm_dedup_multi_obj_unref (obj_old);
+ return TRUE;
+ }
+
+ if ( idx_type->klass->idx_obj_partitionable
+ && !idx_type->klass->idx_obj_partitionable (idx_type, obj)) {
+ /* this object cannot be partitioned by this idx_type. */
+ nm_assert (!head_existing || head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING);
+ NM_SET_OUT (out_entry, NULL);
+ NM_SET_OUT (out_obj_old, NULL);
+ return FALSE;
+ }
+
+ obj_new = nm_dedup_multi_index_obj_intern (self, obj);
+
+ if (!head_existing)
+ head_entry = _entry_lookup_head (self, idx_type, obj_new);
+ else if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING)
+ head_entry = NULL;
+ else
+ head_entry = head_existing;
+
+ if (!head_entry) {
+ head_entry = g_slice_new0 (NMDedupMultiHeadEntry);
+ head_entry->is_head = TRUE;
+ head_entry->idx_type = idx_type;
+ c_list_init (&head_entry->lst_entries_head);
+ c_list_link_tail (&idx_type->lst_idx_head, &head_entry->lst_idx);
+ add_head_entry = TRUE;
+ } else
+ nm_assert (c_list_contains (&idx_type->lst_idx_head, &head_entry->lst_idx));
+
+ if (entry_order) {
+ nm_assert (!add_head_entry);
+ nm_assert (entry_order->head == head_entry);
+ nm_assert (c_list_contains (&head_entry->lst_entries_head, &entry_order->lst_entries));
+ nm_assert (c_list_contains (&entry_order->lst_entries, &head_entry->lst_entries_head));
+ }
+
+ entry = g_slice_new0 (NMDedupMultiEntry);
+ entry->obj = obj_new;
+ entry->head = head_entry;
+
+ switch (mode) {
+ case NM_DEDUP_MULTI_IDX_MODE_PREPEND:
+ case NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE:
+ if (entry_order)
+ c_list_link_before ((CList *) &entry_order->lst_entries, &entry->lst_entries);
+ else
+ c_list_link_front (&head_entry->lst_entries_head, &entry->lst_entries);
+ break;
+ default:
+ if (entry_order)
+ c_list_link_after ((CList *) &entry_order->lst_entries, &entry->lst_entries);
+ else
+ c_list_link_tail (&head_entry->lst_entries_head, &entry->lst_entries);
+ break;
+ };
+
+ idx_type->len++;
+ head_entry->len++;
+
+ if ( add_head_entry
+ && !nm_g_hash_table_add (self->idx_entries, head_entry))
+ nm_assert_not_reached ();
+
+ if (!nm_g_hash_table_add (self->idx_entries, entry))
+ nm_assert_not_reached ();
+
+ NM_SET_OUT (out_entry, entry);
+ NM_SET_OUT (out_obj_old, NULL);
+ return TRUE;
+}
+
+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)
+{
+ NMDedupMultiEntry *entry;
+
+ g_return_val_if_fail (self, FALSE);
+ g_return_val_if_fail (idx_type, FALSE);
+ g_return_val_if_fail (obj, FALSE);
+ g_return_val_if_fail (NM_IN_SET (mode,
+ NM_DEDUP_MULTI_IDX_MODE_PREPEND,
+ NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
+ NM_DEDUP_MULTI_IDX_MODE_APPEND,
+ NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE),
+ FALSE);
+
+ entry = _entry_lookup_obj (self, idx_type, obj);
+ return _add (self, idx_type, obj,
+ entry, mode,
+ NULL, NULL,
+ out_entry, out_obj_old);
+}
+
+/* nm_dedup_multi_index_add_full:
+ * @self: the index instance.
+ * @idx_type: the index handle for storing @obj.
+ * @obj: the NMDedupMultiObj instance to add.
+ * @mode: whether to append or prepend the new item. If @entry_order is given,
+ * the entry will be sorted after/before, instead of appending/prepending to
+ * the entire list. If a comparable object is already tracked, then it may
+ * still be resorted by specifying one of the "FORCE" modes.
+ * @entry_order: if not NULL, the new entry will be sorted before or after @entry_order.
+ * If given, @entry_order MUST be tracked by @self, and the object it points to MUST
+ * be in the same partition tracked by @idx_type. That is, they must have the same
+ * head_entry and it means, you must ensure that @entry_order and the created/modified
+ * entry will share the same head.
+ * @entry_existing: if not NULL, it safes a hash lookup of the entry where the
+ * object will be placed in. You can omit this, and it will be automatically
+ * detected (at the expense of an additional hash lookup).
+ * Basically, this is the result of nm_dedup_multi_index_lookup_obj(),
+ * with the pecularity that if you know that @obj is not yet tracked,
+ * you may specify %NM_DEDUP_MULTI_ENTRY_MISSING.
+ * @head_existing: an optional argument to safe a lookup for the head. If specified,
+ * it must be identical to nm_dedup_multi_index_lookup_head(), with the pecularity
+ * that if the head is not yet tracked, you may specify %NM_DEDUP_MULTI_HEAD_ENTRY_MISSING
+ * @out_entry: if give, return the added entry. This entry may have already exists (update)
+ * or be newly created. If @obj is not partitionable according to @idx_type, @obj
+ * is not to be added and it returns %NULL.
+ * @out_obj_old: if given, return the previously contained object. It only
+ * returns a object, if a matching entry was tracked previously, not if a
+ * new entry was created. Note that when passing @out_obj_old you obtain a reference
+ * to the boxed object and MUST return it with nm_dedup_multi_obj_unref().
+ *
+ * Adds and object to the index.
+ *
+ * Return: %TRUE if anything changed, %FALSE if nothing changed.
+ */
+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)
+{
+ NMDedupMultiEntry *entry;
+
+ g_return_val_if_fail (self, FALSE);
+ g_return_val_if_fail (idx_type, FALSE);
+ g_return_val_if_fail (obj, FALSE);
+ g_return_val_if_fail (NM_IN_SET (mode,
+ NM_DEDUP_MULTI_IDX_MODE_PREPEND,
+ NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE,
+ NM_DEDUP_MULTI_IDX_MODE_APPEND,
+ NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE),
+ FALSE);
+
+ if (entry_existing == NULL)
+ entry = _entry_lookup_obj (self, idx_type, obj);
+ else if (entry_existing == NM_DEDUP_MULTI_ENTRY_MISSING) {
+ nm_assert (!_entry_lookup_obj (self, idx_type, obj));
+ entry = NULL;
+ } else {
+ nm_assert (entry_existing == _entry_lookup_obj (self, idx_type, obj));
+ entry = (NMDedupMultiEntry *) entry_existing;
+ }
+ return _add (self, idx_type, obj,
+ entry,
+ mode, entry_order,
+ (NMDedupMultiHeadEntry *) head_existing,
+ out_entry, out_obj_old);
+}
+
+/*****************************************************************************/
+
+static void
+_remove_entry (NMDedupMultiIndex *self,
+ NMDedupMultiEntry *entry,
+ gboolean *out_head_entry_removed)
+{
+ const NMDedupMultiObj *obj;
+ NMDedupMultiHeadEntry *head_entry;
+ NMDedupMultiIdxType *idx_type;
+
+ nm_assert (self);
+ nm_assert (entry);
+ nm_assert (entry->obj);
+ nm_assert (entry->head);
+ nm_assert (!c_list_is_empty (&entry->lst_entries));
+ nm_assert (g_hash_table_lookup (self->idx_entries, entry) == entry);
+
+ head_entry = (NMDedupMultiHeadEntry *) entry->head;
+ obj = entry->obj;
+
+ nm_assert (head_entry);
+ nm_assert (head_entry->len > 0);
+ nm_assert (g_hash_table_lookup (self->idx_entries, head_entry) == head_entry);
+
+ idx_type = (NMDedupMultiIdxType *) head_entry->idx_type;
+ ASSERT_idx_type (idx_type);
+
+ nm_assert (idx_type->len >= head_entry->len);
+ if (--head_entry->len > 0) {
+ nm_assert (idx_type->len > 1);
+ idx_type->len--;
+ head_entry = NULL;
+ }
+
+ NM_SET_OUT (out_head_entry_removed, head_entry != NULL);
+
+ if (!g_hash_table_remove (self->idx_entries, entry))
+ nm_assert_not_reached ();
+
+ if ( head_entry
+ && !g_hash_table_remove (self->idx_entries, head_entry))
+ nm_assert_not_reached ();
+
+ c_list_unlink (&entry->lst_entries);
+ g_slice_free (NMDedupMultiEntry, entry);
+
+ if (head_entry) {
+ nm_assert (c_list_is_empty (&head_entry->lst_entries_head));
+ c_list_unlink (&head_entry->lst_idx);
+ g_slice_free (NMDedupMultiHeadEntry, head_entry);
+ }
+
+ nm_dedup_multi_obj_unref (obj);
+}
+
+static guint
+_remove_head (NMDedupMultiIndex *self,
+ NMDedupMultiHeadEntry *head_entry,
+ gboolean remove_all /* otherwise just dirty ones */,
+ gboolean mark_survivors_dirty)
+{
+ guint n;
+ gboolean head_entry_removed;
+ CList *iter_entry, *iter_entry_safe;
+
+ nm_assert (self);
+ nm_assert (head_entry);
+ nm_assert (head_entry->len > 0);
+ nm_assert (head_entry->len == c_list_length (&head_entry->lst_entries_head));
+ nm_assert (g_hash_table_lookup (self->idx_entries, head_entry) == head_entry);
+
+ n = 0;
+ c_list_for_each_safe (iter_entry, iter_entry_safe, &head_entry->lst_entries_head) {
+ NMDedupMultiEntry *entry;
+
+ entry = c_list_entry (iter_entry, NMDedupMultiEntry, lst_entries);
+ if ( remove_all
+ || entry->dirty) {
+ _remove_entry (self,
+ entry,
+ &head_entry_removed);
+ n++;
+ if (head_entry_removed)
+ break;
+ } else if (mark_survivors_dirty)
+ nm_dedup_multi_entry_set_dirty (entry, TRUE);
+ }
+
+ return n;
+}
+
+static guint
+_remove_idx_entry (NMDedupMultiIndex *self,
+ NMDedupMultiIdxType *idx_type,
+ gboolean remove_all /* otherwise just dirty ones */,
+ gboolean mark_survivors_dirty)
+{
+ guint n;
+ CList *iter_idx, *iter_idx_safe;
+
+ nm_assert (self);
+ ASSERT_idx_type (idx_type);
+
+ n = 0;
+ c_list_for_each_safe (iter_idx, iter_idx_safe, &idx_type->lst_idx_head) {
+ n += _remove_head (self,
+ c_list_entry (iter_idx, NMDedupMultiHeadEntry, lst_idx),
+ remove_all, mark_survivors_dirty);
+ }
+ return n;
+}
+
+guint
+nm_dedup_multi_index_remove_entry (NMDedupMultiIndex *self,
+ gconstpointer entry)
+{
+ g_return_val_if_fail (self, 0);
+
+ nm_assert (entry);
+
+ if (!((NMDedupMultiEntry *) entry)->is_head) {
+ _remove_entry (self, (NMDedupMultiEntry *) entry, NULL);
+ return 1;
+ }
+ return _remove_head (self, (NMDedupMultiHeadEntry *) entry, TRUE, FALSE);
+}
+
+guint
+nm_dedup_multi_index_remove_obj (NMDedupMultiIndex *self,
+ NMDedupMultiIdxType *idx_type,
+ /*const NMDedupMultiObj * */ gconstpointer obj)
+{
+ const NMDedupMultiEntry *entry;
+
+ entry = nm_dedup_multi_index_lookup_obj (self, idx_type, obj);
+ if (!entry)
+ return 0;
+ _remove_entry (self, (NMDedupMultiEntry *) entry, NULL);
+ return 1;
+}
+
+guint
+nm_dedup_multi_index_remove_head (NMDedupMultiIndex *self,
+ NMDedupMultiIdxType *idx_type,
+ /*const NMDedupMultiObj * */ gconstpointer obj)
+{
+ const NMDedupMultiHeadEntry *entry;
+
+ entry = nm_dedup_multi_index_lookup_head (self, idx_type, obj);
+ return entry
+ ? _remove_head (self, (NMDedupMultiHeadEntry *) entry, TRUE, FALSE)
+ : 0;
+}
+
+guint
+nm_dedup_multi_index_remove_idx (NMDedupMultiIndex *self,
+ NMDedupMultiIdxType *idx_type)
+{
+ g_return_val_if_fail (self, 0);
+ g_return_val_if_fail (idx_type, 0);
+
+ return _remove_idx_entry (self, idx_type, TRUE, FALSE);
+}
+
+/*****************************************************************************/
+
+/**
+ * nm_dedup_multi_index_lookup_obj:
+ * @self: the index cache
+ * @idx_type: the lookup index type
+ * @obj: the object to lookup. This means the match is performed
+ * according to NMDedupMultiIdxTypeClass's idx_obj_id_equal()
+ * of @idx_type.
+ *
+ * Returns: the cache entry or %NULL if the entry wasn't found.
+ */
+const NMDedupMultiEntry *
+nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
+ const NMDedupMultiIdxType *idx_type,
+ /*const NMDedupMultiObj * */ gconstpointer obj)
+{
+ g_return_val_if_fail (self, FALSE);
+ g_return_val_if_fail (idx_type, FALSE);
+ g_return_val_if_fail (obj, FALSE);
+
+ nm_assert (idx_type && idx_type->klass);
+ return _entry_lookup_obj (self, idx_type, obj);
+}
+
+/**
+ * nm_dedup_multi_index_lookup_head:
+ * @self: the index cache
+ * @idx_type: the lookup index type
+ * @obj: the object to lookup, of type "const NMDedupMultiObj *".
+ * Depending on the idx_type, you *must* also provide a selector
+ * object, even when looking up the list head. That is, because
+ * the idx_type implementation may choose to partition the objects
+ * in distinct list, so you need a selector object to know which
+ * list head to lookup.
+ *
+ * Returns: the cache entry or %NULL if the entry wasn't found.
+ */
+const NMDedupMultiHeadEntry *
+nm_dedup_multi_index_lookup_head (NMDedupMultiIndex *self,
+ const NMDedupMultiIdxType *idx_type,
+ /*const NMDedupMultiObj * */ gconstpointer obj)
+{
+ g_return_val_if_fail (self, FALSE);
+ g_return_val_if_fail (idx_type, FALSE);
+
+ return _entry_lookup_head (self, idx_type, obj);
+}
+
+/*****************************************************************************/
+
+void
+nm_dedup_multi_index_dirty_set_head (NMDedupMultiIndex *self,
+ const NMDedupMultiIdxType *idx_type,
+ /*const NMDedupMultiObj * */ gconstpointer obj)
+{
+ NMDedupMultiHeadEntry *head_entry;
+ CList *iter_entry;
+
+ g_return_if_fail (self);
+ g_return_if_fail (idx_type);
+
+ head_entry = _entry_lookup_head (self, idx_type, obj);
+ if (!head_entry)
+ return;
+
+ c_list_for_each (iter_entry, &head_entry->lst_entries_head) {
+ NMDedupMultiEntry *entry;
+
+ entry = c_list_entry (iter_entry, NMDedupMultiEntry, lst_entries);
+ nm_dedup_multi_entry_set_dirty (entry, TRUE);
+ }
+}
+
+void
+nm_dedup_multi_index_dirty_set_idx (NMDedupMultiIndex *self,
+ const NMDedupMultiIdxType *idx_type)
+{
+ CList *iter_idx, *iter_entry;
+
+ g_return_if_fail (self);
+ g_return_if_fail (idx_type);
+
+ c_list_for_each (iter_idx, &idx_type->lst_idx_head) {
+ NMDedupMultiHeadEntry *head_entry;
+
+ head_entry = c_list_entry (iter_idx, NMDedupMultiHeadEntry, lst_idx);
+ c_list_for_each (iter_entry, &head_entry->lst_entries_head) {
+ NMDedupMultiEntry *entry;
+
+ entry = c_list_entry (iter_entry, NMDedupMultiEntry, lst_entries);
+ nm_dedup_multi_entry_set_dirty (entry, TRUE);
+ }
+ }
+}
+
+/**
+ * nm_dedup_multi_index_dirty_remove_idx:
+ * @self: the index instance
+ * @idx_type: the index-type to select the objects.
+ * @mark_survivors_dirty: while the function removes all entries that are
+ * marked as dirty, if @set_dirty is true, the surviving objects
+ * will be marked dirty right away.
+ *
+ * Deletes all entries for @idx_type that are marked dirty. Only
+ * non-dirty objects survive. If @mark_survivors_dirty is set to TRUE, the survivors
+ * are marked as dirty right away.
+ *
+ * Returns: number of deleted entries.
+ */
+guint
+nm_dedup_multi_index_dirty_remove_idx (NMDedupMultiIndex *self,
+ NMDedupMultiIdxType *idx_type,
+ gboolean mark_survivors_dirty)
+{
+ g_return_val_if_fail (self, 0);
+ g_return_val_if_fail (idx_type, 0);
+
+ return _remove_idx_entry (self, idx_type, FALSE, mark_survivors_dirty);
+}
+
+/*****************************************************************************/
+
+static guint
+_dict_idx_objs_hash (const NMDedupMultiObj *obj)
+{
+ return obj->klass->obj_full_hash (obj);
+}
+
+static gboolean
+_dict_idx_objs_equal (const NMDedupMultiObj *obj_a,
+ const NMDedupMultiObj *obj_b)
+{
+ const NMDedupMultiObjClass *klass;
+
+ klass = obj_a->klass;
+
+ /* if the class differs, but at least one of them supports calls with
+ * differing klass, choose it.
+ *
+ * Implementing a klass that can compare equality for multiple
+ * types is hard to get right. E.g. hash(), equal() and get_ref()
+ * must all agree so that instances of different types look identical. */
+ if ( klass != obj_b->klass
+ && !klass->obj_full_equality_allows_different_class) {
+ klass = obj_b->klass;
+ if (!klass->obj_full_equality_allows_different_class)
+ return FALSE;
+ }
+
+ return klass->obj_full_equal (obj_a, obj_b);
+}
+
+void
+nm_dedup_multi_index_obj_release (NMDedupMultiIndex *self,
+ /* const NMDedupMultiObj * */ gconstpointer obj)
+{
+ nm_assert (self);
+ nm_assert (obj);
+ nm_assert (g_hash_table_lookup (self->idx_objs, obj) == obj);
+ nm_assert (((const NMDedupMultiObj *) obj)->_multi_idx == self);
+
+ ((NMDedupMultiObj *) obj)->_multi_idx = NULL;
+ if (!g_hash_table_remove (self->idx_objs, obj))
+ nm_assert_not_reached ();
+}
+
+gconstpointer
+nm_dedup_multi_index_obj_find (NMDedupMultiIndex *self,
+ /* const NMDedupMultiObj * */ gconstpointer obj)
+{
+ g_return_val_if_fail (self, NULL);
+ g_return_val_if_fail (obj, NULL);
+
+ return g_hash_table_lookup (self->idx_objs, obj);
+}
+
+gconstpointer
+nm_dedup_multi_index_obj_intern (NMDedupMultiIndex *self,
+ /* const NMDedupMultiObj * */ gconstpointer obj)
+{
+ const NMDedupMultiObj *obj_new = obj;
+ const NMDedupMultiObj *obj_old;
+
+ nm_assert (self);
+ nm_assert (obj_new);
+
+ if (obj_new->_multi_idx == self) {
+ nm_assert (g_hash_table_lookup (self->idx_objs, obj_new) == obj_new);
+ nm_dedup_multi_obj_ref (obj_new);
+ return obj_new;
+ }
+
+ obj_old = g_hash_table_lookup (self->idx_objs, obj_new);
+ nm_assert (obj_old != obj_new);
+
+ if (obj_old) {
+ nm_assert (obj_old->_multi_idx == self);
+ nm_dedup_multi_obj_ref (obj_old);
+ return obj_old;
+ }
+
+ if (nm_dedup_multi_obj_needs_clone (obj_new))
+ obj_new = nm_dedup_multi_obj_clone (obj_new);
+ else
+ obj_new = nm_dedup_multi_obj_ref (obj_new);
+
+ nm_assert (obj_new);
+ nm_assert (!obj_new->_multi_idx);
+
+ if (!nm_g_hash_table_add (self->idx_objs, (gpointer) obj_new))
+ nm_assert_not_reached ();
+
+ ((NMDedupMultiObj *) obj_new)->_multi_idx = self;
+ return obj_new;
+}
+
+const NMDedupMultiObj *
+nm_dedup_multi_obj_ref (const NMDedupMultiObj *obj)
+{
+ /* ref and unref accept const pointers. Objects 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. */
+
+ nm_assert (obj);
+ nm_assert (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT);
+ nm_assert (obj->_ref_count > 0);
+
+ ((NMDedupMultiObj *) obj)->_ref_count++;
+ return obj;
+}
+
+const NMDedupMultiObj *
+nm_dedup_multi_obj_unref (const NMDedupMultiObj *obj)
+{
+ if (obj) {
+ nm_assert (obj->_ref_count > 0);
+ nm_assert (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT);
+
+again:
+ if (--(((NMDedupMultiObj *) obj)->_ref_count) <= 0) {
+ if (obj->_multi_idx) {
+ /* restore the ref-count to 1 and release the object first
+ * from the index. Then, retry again to unref. */
+ ((NMDedupMultiObj *) obj)->_ref_count++;
+ nm_dedup_multi_index_obj_release (obj->_multi_idx, obj);
+ nm_assert (obj->_ref_count == 1);
+ nm_assert (!obj->_multi_idx);
+ goto again;
+ }
+
+ obj->klass->obj_destroy ((NMDedupMultiObj *) obj);
+ }
+ }
+
+ return NULL;
+}
+
+gboolean
+nm_dedup_multi_obj_needs_clone (const NMDedupMultiObj *obj)
+{
+ nm_assert (obj);
+
+ if ( obj->_multi_idx
+ || obj->_ref_count == NM_OBJ_REF_COUNT_STACKINIT)
+ return TRUE;
+
+ if ( obj->klass->obj_needs_clone
+ && obj->klass->obj_needs_clone (obj))
+ return TRUE;
+
+ return FALSE;
+}
+
+const NMDedupMultiObj *
+nm_dedup_multi_obj_clone (const NMDedupMultiObj *obj)
+{
+ const NMDedupMultiObj *o;
+
+ nm_assert (obj);
+
+ o = obj->klass->obj_clone (obj);
+ nm_assert (o);
+ nm_assert (o->_ref_count == 1);
+ return o;
+}
+
+GPtrArray *
+nm_dedup_multi_objs_to_ptr_array_head (const NMDedupMultiHeadEntry *head_entry,
+ NMDedupMultiFcnSelectPredicate predicate,
+ gpointer user_data)
+{
+ GPtrArray *result;
+ NMDedupMultiIter iter;
+
+ if (!head_entry)
+ return NULL;
+
+ result = g_ptr_array_new_full (head_entry->len,
+ (GDestroyNotify) nm_dedup_multi_obj_unref);
+ nm_dedup_multi_iter_for_each (&iter, head_entry) {
+ const NMDedupMultiObj *obj = iter.current->obj;
+
+ if ( !predicate
+ || predicate (obj, user_data))
+ g_ptr_array_add (result, (gpointer) nm_dedup_multi_obj_ref (obj));
+ }
+
+ if (result->len == 0) {
+ g_ptr_array_unref (result);
+ return NULL;
+ }
+ return result;
+}
+
+/*****************************************************************************/
+
+NMDedupMultiIndex *
+nm_dedup_multi_index_new (void)
+{
+ NMDedupMultiIndex *self;
+
+ self = g_slice_new0 (NMDedupMultiIndex);
+ self->ref_count = 1;
+ self->idx_entries = g_hash_table_new ((GHashFunc) _dict_idx_entries_hash, (GEqualFunc) _dict_idx_entries_equal);
+ self->idx_objs = g_hash_table_new ((GHashFunc) _dict_idx_objs_hash, (GEqualFunc) _dict_idx_objs_equal);
+ return self;
+}
+
+NMDedupMultiIndex *
+nm_dedup_multi_index_ref (NMDedupMultiIndex *self)
+{
+ g_return_val_if_fail (self, NULL);
+ g_return_val_if_fail (self->ref_count > 0, NULL);
+
+ self->ref_count++;
+ return self;
+}
+
+NMDedupMultiIndex *
+nm_dedup_multi_index_unref (NMDedupMultiIndex *self)
+{
+ GHashTableIter iter;
+ const NMDedupMultiIdxType *idx_type;
+ NMDedupMultiEntry *entry;
+ const NMDedupMultiObj *obj;
+
+ g_return_val_if_fail (self, NULL);
+ g_return_val_if_fail (self->ref_count > 0, NULL);
+
+ if (--self->ref_count > 0)
+ return NULL;
+
+more:
+ g_hash_table_iter_init (&iter, self->idx_entries);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &entry, NULL)) {
+ if (entry->is_head)
+ idx_type = ((NMDedupMultiHeadEntry *) entry)->idx_type;
+ else
+ idx_type = entry->head->idx_type;
+ _remove_idx_entry (self, (NMDedupMultiIdxType *) idx_type, TRUE, FALSE);
+ goto more;
+ }
+
+ nm_assert (g_hash_table_size (self->idx_entries) == 0);
+
+ g_hash_table_iter_init (&iter, self->idx_objs);
+ while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) {
+ nm_assert (obj->_multi_idx == self);
+ ((NMDedupMultiObj * )obj)->_multi_idx = NULL;
+ }
+ g_hash_table_remove_all (self->idx_objs);
+
+ g_hash_table_unref (self->idx_entries);
+ g_hash_table_unref (self->idx_objs);
+
+ g_slice_free (NMDedupMultiIndex, self);
+ return NULL;
+}
diff --git a/shared/nm-utils/nm-dedup-multi.h b/shared/nm-utils/nm-dedup-multi.h
new file mode 100644
index 0000000000..77a2fd122d
--- /dev/null
+++ b/shared/nm-utils/nm-dedup-multi.h
@@ -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__ */
diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h
index 011f45d0ee..66b4aa8d60 100644
--- a/shared/nm-utils/nm-macros-internal.h
+++ b/shared/nm-utils/nm-macros-internal.h
@@ -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) \
({ \
diff --git a/shared/nm-utils/nm-obj.h b/shared/nm-utils/nm-obj.h
new file mode 100644
index 0000000000..1a9d48681a
--- /dev/null
+++ b/shared/nm-utils/nm-obj.h
@@ -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__ */
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 3abf46cb10..4bf34cd5b2 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -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;
-
- 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);
-
- if (routes) {
- guint route_metric = G_MAXUINT32, m;
- const NMPlatformIPRoute *route = NULL, *r;
- guint i;
+ const NMDedupMultiHeadEntry *pl_head_entry;
+ NMDedupMultiIter iter;
+ const NMPObject *plobj = NULL;
+ const NMPlatformIPRoute *route = NULL;
+ guint32 route_metric = G_MAXUINT32;
+
+ 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 (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);
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index fb87de896a..358b59af20 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -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);
diff --git a/src/devices/nm-lldp-listener.c b/src/devices/nm-lldp-listener.c
index bfd631f0fd..8f12fd8595 100644
--- a/src/devices/nm-lldp-listener.c
+++ b/src/devices/nm-lldp-listener.c
@@ -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;
}
diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c
index 4b16fb1440..819ff2a171 100644
--- a/src/devices/wwan/nm-modem-broadband.c
+++ b/src/devices/wwan/nm-modem-broadband.c
@@ -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)
diff --git a/src/devices/wwan/nm-modem-ofono.c b/src/devices/wwan/nm-modem-ofono.c
index d1ad016a91..e0b45e07ca 100644
--- a/src/devices/wwan/nm-modem-ofono.c
+++ b/src/devices/wwan/nm-modem-ofono.c
@@ -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! */
diff --git a/src/dhcp/nm-dhcp-client.c b/src/dhcp/nm-dhcp-client.c
index 0906f5beba..b08e05051d 100644
--- a/src/dhcp/nm-dhcp-client.c
+++ b/src/dhcp/nm-dhcp-client.c
@@ -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,
diff --git a/src/dhcp/nm-dhcp-client.h b/src/dhcp/nm-dhcp-client.h
index e41a59a265..890c5ff595 100644
--- a/src/dhcp/nm-dhcp-client.h
+++ b/src/dhcp/nm-dhcp-client.h
@@ -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,
diff --git a/src/dhcp/nm-dhcp-dhclient-utils.c b/src/dhcp/nm-dhcp-dhclient-utils.c
index 11f868e260..6b4ac1f436 100644
--- a/src/dhcp/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp/nm-dhcp-dhclient-utils.c
@@ -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);
diff --git a/src/dhcp/nm-dhcp-dhclient-utils.h b/src/dhcp/nm-dhcp-dhclient-utils.h
index 994b1b9f02..dd276bea45 100644
--- a/src/dhcp/nm-dhcp-dhclient-utils.h
+++ b/src/dhcp/nm-dhcp-dhclient-utils.h
@@ -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,
diff --git a/src/dhcp/nm-dhcp-dhclient.c b/src/dhcp/nm-dhcp-dhclient.c
index 8a3f642a72..f9b6f879cd 100644
--- a/src/dhcp/nm-dhcp-dhclient.c
+++ b/src/dhcp/nm-dhcp-dhclient.c
@@ -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);
diff --git a/src/dhcp/nm-dhcp-manager.c b/src/dhcp/nm-dhcp-manager.c
index fff9f9ec30..42ec390860 100644
--- a/src/dhcp/nm-dhcp-manager.c
+++ b/src/dhcp/nm-dhcp-manager.c
@@ -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;
}
diff --git a/src/dhcp/nm-dhcp-manager.h b/src/dhcp/nm-dhcp-manager.h
index 66fdd145db..2376ea8921 100644
--- a/src/dhcp/nm-dhcp-manager.h
+++ b/src/dhcp/nm-dhcp-manager.h
@@ -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,
diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c
index b909475552..2dca9c83d8 100644
--- a/src/dhcp/nm-dhcp-systemd.c
+++ b/src/dhcp/nm-dhcp-systemd.c
@@ -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,
diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c
index e55a21b49a..3f17110410 100644
--- a/src/dhcp/nm-dhcp-utils.c
+++ b/src/dhcp/nm-dhcp-utils.c
@@ -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) {
diff --git a/src/dhcp/nm-dhcp-utils.h b/src/dhcp/nm-dhcp-utils.h
index 05982b166d..3cd0dbc405 100644
--- a/src/dhcp/nm-dhcp-utils.h
+++ b/src/dhcp/nm-dhcp-utils.h
@@ -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,
diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c
index 2308cf75fa..e90a7976d2 100644
--- a/src/dhcp/tests/test-dhcp-dhclient.c
+++ b/src/dhcp/tests/test-dhcp-dhclient.c
@@ -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);
diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c
index ffd6349361..f3fa963e52 100644
--- a/src/dhcp/tests/test-dhcp-utils.c
+++ b/src/dhcp/tests/test-dhcp-utils.c
@@ -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);
diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c
index a6204ae4a0..d5b51af25e 100644
--- a/src/dns/nm-dns-dnsmasq.c
+++ b/src/dns/nm-dns-dnsmasq.c
@@ -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);
diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c
index 8b330a5a0d..81a58ad3ab 100644
--- a/src/nm-core-utils.c
+++ b/src/nm-core-utils.c
@@ -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
diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h
index 51a0c9cff7..20df8d7e96 100644
--- a/src/nm-core-utils.h
+++ b/src/nm-core-utils.h
@@ -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);
diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c
index 609c1658ef..f6362bccf6 100644
--- a/src/nm-default-route-manager.c
+++ b/src/nm-default-route-manager.c
@@ -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 ( r->metric == expected_metric
- && r->ifindex == entry->route.rx.ifindex) {
- has_metric_for_ifindex = TRUE;
- break;
+ 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 (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++) {
diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c
index 0d482e0cad..2393e8035f 100644
--- a/src/nm-dispatcher.c
+++ b/src/nm-dispatcher.c
@@ -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);
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index f8df2b9a7f..3b60e0d64f 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -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,
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index ae6af9c350..1ec3115d4e 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -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);
-
- if ( (route->plen == 32)
- && (route->network == priv->gateway)
- && (route->gateway == 0)) {
- g_array_remove_index (priv->routes, i);
- 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->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)
@@ -812,22 +957,6 @@ _nameservers_get_index (const NMIP4Config *self, guint32 ns)
}
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)
{
const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self);
@@ -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);
-
- for (i = 0; i < priv->routes->len; i++ ) {
- NMPlatformIP4Route *item = &g_array_index (priv->routes, NMPlatformIP4Route, i);
+ g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (config)->ifindex > 0);
- 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)
-{
- const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
-
- return &g_array_index (priv->routes, NMPlatformIP4Route, i);
+_nmtst_nm_ip4_config_get_route (const NMIP4Config *self, guint i)
+{
+ const NMDedupMultiHeadEntry *head_entry;
+ CList *iter;
+ guint j;
+
+ 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,
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index ceb52ac547..7049f9e5f3 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -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);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index af88b21c74..dde62e9501 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -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);
-
- 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--;
- }
+ 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->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;
+
+ head_entry = _idx_ip6_routes (config);
- for (i = 0; i < count; i++) {
- route = nm_ip6_config_get_route (config, i);
- g_array_append_vals (routes, route, 1);
+ 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)
@@ -824,21 +889,6 @@ _nameservers_get_index (const NMIP6Config *self, const struct in6_addr *ns)
}
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)
{
const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self);
@@ -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);
-
- 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_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex > 0);
- 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)
-{
- const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config);
-
- return &g_array_index (priv->routes, NMPlatformIP6Route, i);
+_nmtst_ip6_config_get_route (const NMIP6Config *self, guint i)
+{
+ const NMDedupMultiHeadEntry *head_entry;
+ CList *iter;
+ guint j;
+
+ 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,
diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h
index 557041c958..a390ff1c23 100644
--- a/src/nm-ip6-config.h
+++ b/src/nm-ip6-config.h
@@ -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);
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 90ad66403e..3a8ada4360 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -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
diff --git a/src/nm-multi-index.c b/src/nm-multi-index.c
deleted file mode 100644
index 6ae4c21fab..0000000000
--- a/src/nm-multi-index.c
+++ /dev/null
@@ -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);
-}
-
diff --git a/src/nm-multi-index.h b/src/nm-multi-index.h
deleted file mode 100644
index fb102574a1..0000000000
--- a/src/nm-multi-index.h
+++ /dev/null
@@ -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__ */
-
diff --git a/src/nm-netns.c b/src/nm-netns.c
index a81aa696ee..f5e6b0014d 100644
--- a/src/nm-netns.c
+++ b/src/nm-netns.c
@@ -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)
{
diff --git a/src/nm-netns.h b/src/nm-netns.h
index fd5daf47ff..ebe9d1f2a8 100644
--- a/src/nm-netns.h
+++ b/src/nm-netns.h
@@ -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__ */
diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c
index 0a1cd823f4..d9095cce5b 100644
--- a/src/nm-pacrunner-manager.c
+++ b/src/nm-pacrunner-manager.c
@@ -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);
diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c
index b58cdeb069..e980cfe0a6 100644
--- a/src/nm-route-manager.c
+++ b/src/nm-route-manager.c
@@ -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) {
diff --git a/src/nm-test-utils-core.h b/src/nm-test-utils-core.h
index 4e8e2f98e0..879e9190af 100644
--- a/src/nm-test-utils-core.h
+++ b/src/nm-test-utils-core.h
@@ -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;
}
diff --git a/src/nm-types.h b/src/nm-types.h
index 44b4fecbb3..36a624de8b 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -56,6 +56,8 @@ typedef struct _NMSleepMonitor NMSleepMonitor;
typedef struct _NMLldpListener NMLldpListener;
typedef struct _NMConfigDeviceStateData NMConfigDeviceStateData;
+struct _NMDedupMultiIndex;
+
/*****************************************************************************/
typedef enum {
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index 27fde50d61..718ee974ae 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -32,6 +32,7 @@
#include "nm-core-utils.h"
#include "nm-platform-utils.h"
+#include "nm-platform-private.h"
#include "nmp-object.h"
#include "nm-test-utils-core.h"
@@ -39,20 +40,14 @@
/*****************************************************************************/
typedef struct {
- NMPlatformLink link;
-
+ const NMPObject *obj;
char *udi;
- NMPObject *lnk;
struct in6_addr ip6_lladdr;
} NMFakePlatformLink;
typedef struct {
GHashTable *options;
GArray *links;
- GArray *ip4_addresses;
- GArray *ip6_addresses;
- GArray *ip4_routes;
- GArray *ip6_routes;
} NMFakePlatformPrivate;
struct _NMFakePlatform {
@@ -96,7 +91,24 @@ G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM)
/*****************************************************************************/
-static void link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_signal);
+static void link_changed (NMPlatform *platform,
+ NMFakePlatformLink *device,
+ NMPCacheOpsType cache_op,
+ const NMPObject *obj_old);
+
+static gboolean ipx_address_delete (NMPlatform *platform,
+ int addr_family,
+ int ifindex,
+ gconstpointer addr,
+ const guint8 *plen,
+ gconstpointer peer_addr);
+
+static gboolean ipx_route_delete (NMPlatform *platform,
+ int addr_family,
+ int ifindex,
+ gconstpointer network,
+ const guint8 *plen,
+ const guint32 *metric);
static gboolean ip6_address_add (NMPlatform *platform,
int ifindex,
@@ -110,14 +122,6 @@ static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in
/*****************************************************************************/
-static gboolean
-_ip4_address_equal_peer_net (in_addr_t peer1, in_addr_t peer2, guint8 plen)
-{
- return ((peer1 ^ peer2) & nm_utils_ip4_prefix_to_netmask (plen)) == 0;
-}
-
-/*****************************************************************************/
-
#define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \
G_STMT_START { \
const char *const _pathid = (pathid); \
@@ -158,165 +162,126 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
return g_strdup (g_hash_table_lookup (priv->options, path));
}
-static const char *
-type_to_type_name (NMLinkType type)
-{
- switch (type) {
- case NM_LINK_TYPE_UNKNOWN:
- return "unknown";
- case NM_LINK_TYPE_LOOPBACK:
- return "loopback";
- case NM_LINK_TYPE_ETHERNET:
- return "ethernet";
- case NM_LINK_TYPE_DUMMY:
- return "dummy";
- case NM_LINK_TYPE_BRIDGE:
- return "bridge";
- case NM_LINK_TYPE_BOND:
- return "bond";
- case NM_LINK_TYPE_TEAM:
- return "team";
- case NM_LINK_TYPE_VLAN:
- return "vlan";
- case NM_LINK_TYPE_NONE:
- default:
- return NULL;
- }
-}
-
-static void
-link_init (NMFakePlatformLink *device, int ifindex, int type, const char *name)
-{
- gs_free char *ip6_lladdr = NULL;
-
- g_assert (!name || strlen (name) < sizeof(device->link.name));
-
- memset (device, 0, sizeof (*device));
-
- ip6_lladdr = ifindex > 0 ? g_strdup_printf ("fe80::fa1e:%0x:%0x", ifindex / 256, ifindex % 256) : NULL;
-
- device->link.ifindex = name ? ifindex : 0;
- device->link.type = type;
- device->link.kind = type_to_type_name (type);
- device->link.driver = type_to_type_name (type);
- device->udi = g_strdup_printf ("fake:%d", ifindex);
- device->link.initialized = TRUE;
- device->ip6_lladdr = *nmtst_inet6_from_string (ip6_lladdr);
- if (name)
- strcpy (device->link.name, name);
- switch (device->link.type) {
- case NM_LINK_TYPE_DUMMY:
- device->link.n_ifi_flags = NM_FLAGS_SET (device->link.n_ifi_flags, IFF_NOARP);
- break;
- default:
- device->link.n_ifi_flags = NM_FLAGS_UNSET (device->link.n_ifi_flags, IFF_NOARP);
- break;
- }
-}
-
static NMFakePlatformLink *
link_get (NMPlatform *platform, int ifindex)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
NMFakePlatformLink *device;
+ int idx;
- if (ifindex >= priv->links->len)
+ if (ifindex <= 0)
+ g_return_val_if_reached (NULL);
+
+ idx = ifindex - 1;
+ if (idx >= priv->links->len)
goto not_found;
- device = &g_array_index (priv->links, NMFakePlatformLink, ifindex);
- if (!device->link.ifindex)
+
+ device = &g_array_index (priv->links, NMFakePlatformLink, idx);
+ if (!device->obj)
goto not_found;
+ g_assert (ifindex == NMP_OBJECT_CAST_LINK (device->obj)->ifindex);
+ g_assert (device->obj == nm_platform_link_get_obj (platform, ifindex, FALSE));
+
return device;
not_found:
_LOGD ("link not found: %d", ifindex);
return NULL;
}
-static GArray *
-link_get_all (NMPlatform *platform)
+static void
+link_add_prepare (NMPlatform *platform,
+ NMFakePlatformLink *device,
+ NMPObject *obj_tmp)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- GArray *links = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformLink), priv->links->len);
- int i;
-
- for (i = 0; i < priv->links->len; i++)
- if (g_array_index (priv->links, NMFakePlatformLink, i).link.ifindex)
- g_array_append_val (links, g_array_index (priv->links, NMFakePlatformLink, i).link);
+ gboolean connected;
- return links;
-}
+ /* we must clear the driver, because platform cache want's to set it */
+ g_assert (obj_tmp->link.driver == g_intern_string (obj_tmp->link.driver));
+ obj_tmp->link.driver = NULL;
-static const NMPlatformLink *
-_nm_platform_link_get (NMPlatform *platform, int ifindex)
-{
- NMFakePlatformLink *device = link_get (platform, ifindex);
+ if (NM_IN_SET (obj_tmp->link.type, NM_LINK_TYPE_BRIDGE,
+ NM_LINK_TYPE_BOND)) {
+ connected = FALSE;
+ if (NM_FLAGS_HAS (obj_tmp->link.n_ifi_flags, IFF_UP)) {
+ NMPLookup lookup;
+ NMDedupMultiIter iter;
+ const NMPObject *slave_candidate = NULL;
+
+ nmp_cache_iter_for_each (&iter,
+ nmp_cache_lookup (nm_platform_get_cache (platform),
+ nmp_lookup_init_obj_type (&lookup,
+ NMP_OBJECT_TYPE_LINK)),
+ &slave_candidate) {
+ if (nmp_cache_link_connected_for_slave (obj_tmp->link.ifindex, slave_candidate)) {
+ connected = TRUE;
+ break;
+ }
+ }
+ }
+ } else
+ connected = NM_FLAGS_HAS (obj_tmp->link.n_ifi_flags, IFF_UP);
- return device ? &device->link : NULL;
+ obj_tmp->link.n_ifi_flags = NM_FLAGS_ASSIGN (obj_tmp->link.n_ifi_flags, IFF_LOWER_UP, connected);
+ obj_tmp->link.connected = connected;
}
-static const NMPlatformLink *
-_nm_platform_link_get_by_ifname (NMPlatform *platform, const char *ifname)
+static NMFakePlatformLink *
+link_add_pre (NMPlatform *platform,
+ const char *name,
+ NMLinkType type,
+ const void *address,
+ size_t address_len)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- guint i;
+ NMFakePlatformLink *device;
+ int ifindex;
+ NMPObject *o;
+ NMPlatformLink *link;
+ gs_free char *ip6_lladdr = NULL;
- for (i = 0; i < priv->links->len; i++) {
- NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i);
+ g_assert (!name || strlen (name) < IFNAMSIZ);
- if (!strcmp (device->link.name, ifname))
- return &device->link;
- }
- return NULL;
-}
+ g_array_set_size (priv->links, priv->links->len + 1);
+ device = &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 1);
+ ifindex = priv->links->len;
-static const NMPlatformLink *
-_nm_platform_link_get_by_address (NMPlatform *platform,
- gconstpointer address,
- size_t length)
-{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- guint i;
+ memset (device, 0, sizeof (*device));
- if ( length == 0
- || length > NM_UTILS_HWADDR_LEN_MAX
- || !address)
- g_return_val_if_reached (NULL);
+ o = nmp_object_new_link (ifindex);
+ link = NMP_OBJECT_CAST_LINK (o);
- for (i = 0; i < priv->links->len; i++) {
- NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i);
+ ip6_lladdr = ifindex > 0 ? g_strdup_printf ("fe80::fa1e:%0x:%0x", ifindex / 256, ifindex % 256) : NULL;
- if ( device->link.addr.len == length
- && memcmp (device->link.addr.data, address, length) == 0) {
- return &device->link;
- }
+ link->ifindex = name ? ifindex : 0;
+ link->type = type;
+ link->kind = g_intern_string (nm_link_type_to_string (type));
+ link->initialized = TRUE;
+ if (name)
+ strcpy (link->name, name);
+ switch (link->type) {
+ case NM_LINK_TYPE_DUMMY:
+ link->n_ifi_flags = NM_FLAGS_SET (link->n_ifi_flags, IFF_NOARP);
+ break;
+ default:
+ link->n_ifi_flags = NM_FLAGS_UNSET (link->n_ifi_flags, IFF_NOARP);
+ break;
}
- return NULL;
-}
-
-static const NMPObject *
-link_get_lnk (NMPlatform *platform,
- int ifindex,
- NMLinkType link_type,
- const NMPlatformLink **out_link)
-{
- NMFakePlatformLink *device = link_get (platform, ifindex);
-
- if (!device)
- return NULL;
- NM_SET_OUT (out_link, &device->link);
+ o->_link.netlink.is_in_netlink = TRUE;
- if (!device->lnk)
- return NULL;
-
- if (link_type == NM_LINK_TYPE_NONE)
- return device->lnk;
+ if (address) {
+ g_assert (address_len > 0 && address_len <= sizeof (link->addr.data));
+ memcpy (link->addr.data, address, address_len);
+ link->addr.len = address_len;
+ } else
+ g_assert (address_len == 0);
- if ( link_type != device->link.type
- || link_type != NMP_OBJECT_GET_CLASS (device->lnk)->lnk_link_type)
- return NULL;
+ device->obj = o;
+ device->udi = g_strdup_printf ("fake:%d", ifindex);
+ device->ip6_lladdr = *nmtst_inet6_from_string (ip6_lladdr);
- return device->lnk;
+ return device;
}
static gboolean
@@ -328,135 +293,201 @@ link_add (NMPlatform *platform,
size_t address_len,
const NMPlatformLink **out_link)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- NMFakePlatformLink device;
- NMFakePlatformLink device_veth = { };
- NMFakePlatformLink *new_device;
-
- link_init (&device, priv->links->len, type, name);
-
- if (address) {
- g_return_val_if_fail (address_len > 0 && address_len <= sizeof (device.link.addr.data), FALSE);
- memcpy (device.link.addr.data, address, address_len);
- device.link.addr.len = address_len;
- }
+ NMFakePlatformLink *device;
+ NMFakePlatformLink *device_veth = NULL;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
+ nm_auto_nmpobj const NMPObject *obj_old_veth = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new_veth = NULL;
+ NMPCacheOpsType cache_op;
+ NMPCacheOpsType cache_op_veth = NMP_CACHE_OPS_UNCHANGED;
- g_array_append_val (priv->links, device);
- new_device = &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 1);
+ device = link_add_pre (platform, name, type, address, address_len);
if (veth_peer) {
- link_init (&device_veth, priv->links->len, type, veth_peer);
- g_array_append_val (priv->links, device_veth);
- new_device = &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 2);
+ g_assert (type == NM_LINK_TYPE_VETH);
+ device_veth = link_add_pre (platform, veth_peer, type, NULL, 0);
} else
g_assert (type != NM_LINK_TYPE_VETH);
+ link_add_prepare (platform, device, (NMPObject *) device->obj);
+ cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
+ (NMPObject *) device->obj,
+ &obj_old, &obj_new);
+ g_assert (cache_op == NMP_CACHE_OPS_ADDED);
+ nmp_object_unref (device->obj);
+ device->obj = nmp_object_ref (obj_new);
+ if (veth_peer) {
+ link_add_prepare (platform, device_veth, (NMPObject *) device_veth->obj);
+ cache_op_veth = nmp_cache_update_netlink (nm_platform_get_cache (platform),
+ (NMPObject *) device_veth->obj,
+ &obj_old_veth, &obj_new_veth);
+ g_assert (cache_op == NMP_CACHE_OPS_ADDED);
+ nmp_object_unref (device->obj);
+ device->obj = nmp_object_ref (obj_new);
+ }
if (out_link)
- *out_link = &new_device->link;
+ *out_link = NMP_OBJECT_CAST_LINK (device->obj);
- if (device.link.ifindex) {
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, (int) NMP_OBJECT_TYPE_LINK, device.link.ifindex, &device, (int) NM_PLATFORM_SIGNAL_ADDED);
+ link_changed (platform, device, cache_op, NULL);
+ if (veth_peer)
+ link_changed (platform, device_veth, cache_op_veth, NULL);
- link_changed (platform, new_device, FALSE);
- }
+ return TRUE;
+}
- if (veth_peer) {
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, (int) NMP_OBJECT_TYPE_LINK, device_veth.link.ifindex, &device_veth, (int) NM_PLATFORM_SIGNAL_ADDED);
+static NMFakePlatformLink *
+link_add_one (NMPlatform *platform,
+ const char *name,
+ NMLinkType link_type,
+ void (*prepare_fcn) (NMPlatform *platform, NMFakePlatformLink *device, gconstpointer user_data),
+ gconstpointer user_data,
+ const NMPlatformLink **out_link)
+{
+ NMFakePlatformLink *device;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
+ NMPCacheOpsType cache_op;
+ int ifindex;
- link_changed (platform, &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 1), FALSE);
- }
+ device = link_add_pre (platform, name, NM_LINK_TYPE_VLAN, NULL, 0);
- return TRUE;
+ ifindex = NMP_OBJECT_CAST_LINK (device->obj)->ifindex;
+
+ if (prepare_fcn)
+ prepare_fcn (platform, device, user_data);
+
+ link_add_prepare (platform, device, (NMPObject *) device->obj);
+ cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
+ (NMPObject *) device->obj,
+ &obj_old, &obj_new);
+ g_assert (cache_op == NMP_CACHE_OPS_ADDED);
+ nmp_object_unref (device->obj);
+ device->obj = nmp_object_ref (obj_new);
+
+ link_changed (platform, device, cache_op, obj_old);
+
+ device = link_get (platform, ifindex);
+ if (!device)
+ g_assert_not_reached ();
+
+ NM_SET_OUT (out_link, NMP_OBJECT_CAST_LINK (device->obj));
+ return device;
}
static gboolean
link_delete (NMPlatform *platform, int ifindex)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
NMFakePlatformLink *device = link_get (platform, ifindex);
- NMPlatformLink deleted_device;
- int i;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_old2 = NULL;
+ NMPCacheOpsType cache_op;
- if (!device || !device->link.ifindex)
+ if (!device)
return FALSE;
- memcpy (&deleted_device, &device->link, sizeof (deleted_device));
- memset (&device->link, 0, sizeof (device->link));
- g_clear_pointer (&device->lnk, nmp_object_unref);
+ obj_old = g_steal_pointer (&device->obj);
g_clear_pointer (&device->udi, g_free);
+ cache_op = nmp_cache_remove (nm_platform_get_cache (platform),
+ obj_old,
+ FALSE,
+ &obj_old2);
+ g_assert (cache_op == NMP_CACHE_OPS_REMOVED);
+ g_assert (obj_old2);
+ g_assert (obj_old == obj_old2);
+
/* Remove addresses and routes which belong to the deleted interface */
- for (i = 0; i < priv->ip4_addresses->len; i++) {
- NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
+ ipx_address_delete (platform, AF_INET, ifindex, NULL, NULL, NULL);
+ ipx_address_delete (platform, AF_INET6, ifindex, NULL, NULL, NULL);
+ ipx_route_delete (platform, AF_INET, ifindex, NULL, NULL, NULL);
+ ipx_route_delete (platform, AF_INET6, ifindex, NULL, NULL, NULL);
+
+ nm_platform_cache_update_emit_signal (platform,
+ cache_op,
+ obj_old2,
+ NULL);
+ return TRUE;
+}
- if (address->ifindex == ifindex)
- memset (address, 0, sizeof (*address));
- }
- for (i = 0; i < priv->ip6_addresses->len; i++) {
- NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
+static void
+link_set_obj (NMPlatform *platform,
+ NMFakePlatformLink *device,
+ NMPObject *obj_tmp)
+{
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj NMPObject *obj_tmp_tmp = NULL;
+ NMPCacheOpsType cache_op;
- if (address->ifindex == ifindex)
- memset (address, 0, sizeof (*address));
- }
- for (i = 0; i < priv->ip4_routes->len; i++) {
- NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
+ g_assert (device);
+ g_assert (NMP_OBJECT_GET_TYPE (device->obj) == NMP_OBJECT_TYPE_LINK);
- if (route->ifindex == ifindex)
- memset (route, 0, sizeof (*route));
+ if (!obj_tmp) {
+ obj_tmp_tmp = nmp_object_clone (device->obj, FALSE);
+ obj_tmp = obj_tmp_tmp;
}
- for (i = 0; i < priv->ip6_routes->len; i++) {
- NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
- if (route->ifindex == ifindex)
- memset (route, 0, sizeof (*route));
- }
+ g_assert (NMP_OBJECT_GET_TYPE (obj_tmp) == NMP_OBJECT_TYPE_LINK);
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, (int) NMP_OBJECT_TYPE_LINK, ifindex, &deleted_device, (int) NM_PLATFORM_SIGNAL_REMOVED);
+ link_add_prepare (platform, device, obj_tmp);
+ cache_op = nmp_cache_update_netlink (nm_platform_get_cache (platform),
+ obj_tmp, &obj_old, &obj_new);
+ g_assert (NM_IN_SET (cache_op, NMP_CACHE_OPS_UNCHANGED,
+ NMP_CACHE_OPS_UPDATED));
+ g_assert (obj_old == device->obj);
+ g_assert (obj_new);
- return TRUE;
-}
+ nmp_object_unref (device->obj);
+ device->obj = nmp_object_ref (obj_new);
-static const char *
-link_get_type_name (NMPlatform *platform, int ifindex)
-{
- return type_to_type_name (nm_platform_link_get_type (platform, ifindex));
+ link_changed (platform, device, cache_op, obj_old);
}
static void
-link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_signal)
+link_set_flags (NMPlatform *platform,
+ NMFakePlatformLink *device,
+ guint n_ifi_flags)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
+ nm_auto_nmpobj NMPObject *obj_tmp = NULL;
- if (raise_signal)
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, (int) NMP_OBJECT_TYPE_LINK, device->link.ifindex, &device->link, (int) NM_PLATFORM_SIGNAL_CHANGED);
+ g_assert (device);
+ g_assert (NMP_OBJECT_GET_TYPE (device->obj) == NMP_OBJECT_TYPE_LINK);
- if (device->link.ifindex && !IN6_IS_ADDR_UNSPECIFIED (&device->ip6_lladdr)) {
- if (device->link.connected)
- ip6_address_add (platform, device->link.ifindex, in6addr_any, 64, device->ip6_lladdr, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0);
- else
- ip6_address_delete (platform, device->link.ifindex, device->ip6_lladdr, 64);
- }
+ obj_tmp = nmp_object_clone (device->obj, FALSE);
+ obj_tmp->link.n_ifi_flags = n_ifi_flags;
+ link_set_obj (platform, device, obj_tmp);
+}
- if (device->link.master) {
- gboolean connected = FALSE;
+static void
+link_changed (NMPlatform *platform,
+ NMFakePlatformLink *device,
+ NMPCacheOpsType cache_op,
+ const NMPObject *obj_old)
+{
+ g_assert (device->obj);
- NMFakePlatformLink *master = link_get (platform, device->link.master);
+ g_assert (!nmp_cache_link_connected_needs_toggle (nm_platform_get_cache (platform),
+ device->obj, NULL, NULL));
- g_return_if_fail (master && master != device);
+ nm_platform_cache_update_emit_signal (platform,
+ cache_op,
+ obj_old,
+ device->obj);
- for (i = 0; i < priv->links->len; i++) {
- NMFakePlatformLink *slave = &g_array_index (priv->links, NMFakePlatformLink, i);
+ if (!IN6_IS_ADDR_UNSPECIFIED (&device->ip6_lladdr)) {
+ if (device->obj->link.connected)
+ ip6_address_add (platform, device->obj->link.ifindex, in6addr_any, 64, device->ip6_lladdr, NM_PLATFORM_LIFETIME_PERMANENT, NM_PLATFORM_LIFETIME_PERMANENT, 0);
+ else
+ ip6_address_delete (platform, device->obj->link.ifindex, device->ip6_lladdr, 64);
+ }
- if (slave && slave->link.master == master->link.ifindex && slave->link.connected)
- connected = TRUE;
- }
+ if (device->obj->link.master) {
+ NMFakePlatformLink *master;
- if (master->link.connected != connected) {
- master->link.connected = connected;
- link_changed (platform, master, TRUE);
- }
+ master = link_get (platform, device->obj->link.master);
+ link_set_obj (platform, master, NULL);
}
}
@@ -464,7 +495,6 @@ static gboolean
link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
- gboolean up, connected;
if (out_no_firmware)
*out_no_firmware = FALSE;
@@ -474,29 +504,9 @@ link_set_up (NMPlatform *platform, int ifindex, gboolean *out_no_firmware)
return FALSE;
}
- up = TRUE;
- connected = TRUE;
- switch (device->link.type) {
- case NM_LINK_TYPE_DUMMY:
- case NM_LINK_TYPE_VLAN:
- break;
- case NM_LINK_TYPE_BRIDGE:
- case NM_LINK_TYPE_BOND:
- case NM_LINK_TYPE_TEAM:
- connected = FALSE;
- break;
- default:
- connected = FALSE;
- g_error ("Unexpected device type: %d", device->link.type);
- }
-
- if ( NM_FLAGS_HAS (device->link.n_ifi_flags, IFF_UP) != !!up
- || device->link.connected != connected) {
- device->link.n_ifi_flags = NM_FLAGS_ASSIGN (device->link.n_ifi_flags, IFF_UP, up);
- device->link.connected = connected;
- link_changed (platform, device, TRUE);
- }
-
+ link_set_flags (platform,
+ device,
+ NM_FLAGS_ASSIGN (device->obj->link.n_ifi_flags, IFF_UP, TRUE));
return TRUE;
}
@@ -510,13 +520,9 @@ link_set_down (NMPlatform *platform, int ifindex)
return FALSE;
}
- if (NM_FLAGS_HAS (device->link.n_ifi_flags, IFF_UP) || device->link.connected) {
- device->link.n_ifi_flags = NM_FLAGS_UNSET (device->link.n_ifi_flags, IFF_UP);
- device->link.connected = FALSE;
-
- link_changed (platform, device, TRUE);
- }
-
+ link_set_flags (platform,
+ device,
+ NM_FLAGS_UNSET (device->obj->link.n_ifi_flags, IFF_UP));
return TRUE;
}
@@ -530,10 +536,9 @@ link_set_arp (NMPlatform *platform, int ifindex)
return FALSE;
}
- device->link.n_ifi_flags = NM_FLAGS_UNSET (device->link.n_ifi_flags, IFF_NOARP);
-
- link_changed (platform, device, TRUE);
-
+ link_set_flags (platform,
+ device,
+ NM_FLAGS_UNSET (device->obj->link.n_ifi_flags, IFF_NOARP));
return TRUE;
}
@@ -547,10 +552,9 @@ link_set_noarp (NMPlatform *platform, int ifindex)
return FALSE;
}
- device->link.n_ifi_flags = NM_FLAGS_SET (device->link.n_ifi_flags, IFF_NOARP);
-
- link_changed (platform, device, TRUE);
-
+ link_set_flags (platform,
+ device,
+ NM_FLAGS_SET (device->obj->link.n_ifi_flags, IFF_NOARP));
return TRUE;
}
@@ -558,21 +562,22 @@ static NMPlatformError
link_set_address (NMPlatform *platform, int ifindex, gconstpointer addr, size_t len)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
+ nm_auto_nmpobj NMPObject *obj_tmp = NULL;
- if ( !device
- || len == 0
+ if ( len == 0
|| len > NM_UTILS_HWADDR_LEN_MAX
|| !addr)
g_return_val_if_reached (NM_PLATFORM_ERROR_BUG);
- if ( device->link.addr.len != len
- || ( len > 0
- && memcmp (device->link.addr.data, addr, len) != 0)) {
- memcpy (device->link.addr.data, addr, len);
- device->link.addr.len = len;
- link_changed (platform, link_get (platform, ifindex), TRUE);
- }
+ if (!device)
+ return NM_PLATFORM_ERROR_EXISTS;
+
+ obj_tmp = nmp_object_clone (device->obj, FALSE);
+ obj_tmp->link.addr.len = len;
+ memset (obj_tmp->link.addr.data, 0, sizeof (obj_tmp->link.addr.data));
+ memcpy (obj_tmp->link.addr.data, addr, len);
+ link_set_obj (platform, device, obj_tmp);
return NM_PLATFORM_ERROR_SUCCESS;
}
@@ -580,14 +585,17 @@ static gboolean
link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
+ nm_auto_nmpobj NMPObject *obj_tmp = NULL;
- if (device) {
- device->link.mtu = mtu;
- link_changed (platform, device, TRUE);
- } else
+ if (!device) {
_LOGE ("failure changing link: netlink error (No such device)");
+ return FALSE;
+ }
- return !!device;
+ obj_tmp = nmp_object_clone (device->obj, FALSE);
+ obj_tmp->link.mtu = mtu;
+ link_set_obj (platform, device, obj_tmp);
+ return TRUE;
}
static gboolean
@@ -631,7 +639,7 @@ link_supports_carrier_detect (NMPlatform *platform, int ifindex)
if (!device)
return FALSE;
- switch (device->link.type) {
+ switch (device->obj->link.type) {
case NM_LINK_TYPE_DUMMY:
return FALSE;
default:
@@ -647,7 +655,7 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
if (!device)
return FALSE;
- switch (device->link.type) {
+ switch (device->obj->link.type) {
case NM_LINK_TYPE_LOOPBACK:
return FALSE;
default:
@@ -663,7 +671,7 @@ link_supports_sriov (NMPlatform *platform, int ifindex)
if (!device)
return FALSE;
- switch (device->link.type) {
+ switch (device->obj->link.type) {
case NM_LINK_TYPE_LOOPBACK:
return FALSE;
default:
@@ -680,15 +688,14 @@ link_enslave (NMPlatform *platform, int master, int slave)
g_return_val_if_fail (device, FALSE);
g_return_val_if_fail (master_device, FALSE);
- if (device->link.master != master) {
- device->link.master = master;
-
- if (NM_IN_SET (master_device->link.type, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM)) {
- device->link.n_ifi_flags = NM_FLAGS_SET (device->link.n_ifi_flags, IFF_UP);
- device->link.connected = TRUE;
- }
+ if (device->obj->link.master != master) {
+ nm_auto_nmpobj NMPObject *obj_tmp = NULL;
- link_changed (platform, device, TRUE);
+ obj_tmp = nmp_object_clone (device->obj, FALSE);
+ obj_tmp->link.master = master;
+ if (NM_IN_SET (master_device->obj->link.type, NM_LINK_TYPE_BOND, NM_LINK_TYPE_TEAM))
+ obj_tmp->link.n_ifi_flags = NM_FLAGS_SET (device->obj->link.n_ifi_flags, IFF_UP);
+ link_set_obj (platform, device, obj_tmp);
}
return TRUE;
@@ -699,40 +706,56 @@ link_release (NMPlatform *platform, int master_idx, int slave_idx)
{
NMFakePlatformLink *master = link_get (platform, master_idx);
NMFakePlatformLink *slave = link_get (platform, slave_idx);
+ nm_auto_nmpobj NMPObject *obj_tmp = NULL;
g_return_val_if_fail (master, FALSE);
g_return_val_if_fail (slave, FALSE);
- if (slave->link.master != master->link.ifindex)
+ if (slave->obj->link.master != master->obj->link.ifindex)
return FALSE;
- slave->link.master = 0;
-
- link_changed (platform, slave, TRUE);
- link_changed (platform, master, TRUE);
-
+ obj_tmp = nmp_object_clone (slave->obj, FALSE);
+ obj_tmp->link.master = 0;
+ link_set_obj (platform, slave, obj_tmp);
return TRUE;
}
-static gboolean
-vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, const NMPlatformLink **out_link)
+struct vlan_add_data {
+ guint32 vlan_flags;
+ int parent;
+ int vlan_id;
+};
+
+static void
+_vlan_add_prepare (NMPlatform *platform,
+ NMFakePlatformLink *device,
+ gconstpointer user_data)
{
- NMFakePlatformLink *device;
+ const struct vlan_add_data *d = user_data;
+ NMPObject *obj_tmp;
+ NMPObject *lnk;
- if (!link_add (platform, name, NM_LINK_TYPE_VLAN, NULL, NULL, 0, out_link))
- return FALSE;
+ obj_tmp = (NMPObject *) device->obj;
- device = link_get (platform, nm_platform_link_get_ifindex (platform, name));
+ lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
+ lnk->lnk_vlan.id = d->vlan_id;
+ lnk->lnk_vlan.flags = d->vlan_flags;
- g_return_val_if_fail (device, FALSE);
- g_return_val_if_fail (!device->lnk, FALSE);
+ obj_tmp->link.parent = d->parent;
+ obj_tmp->_link.netlink.lnk = lnk;
+}
- device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
- device->lnk->lnk_vlan.id = vlan_id;
- device->link.parent = parent;
+static gboolean
+vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, const NMPlatformLink **out_link)
+{
+ const struct vlan_add_data d = {
+ .parent = parent,
+ .vlan_id = vlan_id,
+ .vlan_flags = vlan_flags,
+ };
- if (out_link)
- *out_link = &device->link;
+ link_add_one (platform, name, NM_LINK_TYPE_VLAN,
+ _vlan_add_prepare, &d, out_link);
return TRUE;
}
@@ -751,53 +774,76 @@ link_vlan_change (NMPlatform *platform,
return FALSE;
}
+static void
+_vxlan_add_prepare (NMPlatform *platform,
+ NMFakePlatformLink *device,
+ gconstpointer user_data)
+{
+ const NMPlatformLnkVxlan *props = user_data;
+ NMPObject *obj_tmp;
+ NMPObject *lnk;
+
+ obj_tmp = (NMPObject *) device->obj;
+
+ lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL);
+ lnk->lnk_vxlan = *props;
+
+ obj_tmp->link.parent = props->parent_ifindex;
+ obj_tmp->_link.netlink.lnk = lnk;
+}
+
static gboolean
link_vxlan_add (NMPlatform *platform,
const char *name,
const NMPlatformLnkVxlan *props,
const NMPlatformLink **out_link)
{
- NMFakePlatformLink *device;
+ link_add_one (platform, name, NM_LINK_TYPE_VXLAN,
+ _vxlan_add_prepare, props, out_link);
+ return TRUE;
+}
- if (!link_add (platform, name, NM_LINK_TYPE_VXLAN, NULL, NULL, 0, out_link))
- return FALSE;
+struct infiniband_add_data {
+ int parent;
+ int p_key;
+};
- device = link_get (platform, nm_platform_link_get_ifindex (platform, name));
+static void
+_infiniband_add_prepare (NMPlatform *platform,
+ NMFakePlatformLink *device,
+ gconstpointer user_data)
+{
+ const struct infiniband_add_data *d = user_data;
+ NMPObject *obj_tmp;
+ NMPObject *lnk;
- g_return_val_if_fail (device, FALSE);
- g_return_val_if_fail (!device->lnk, FALSE);
+ obj_tmp = (NMPObject *) device->obj;
- device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL);
- device->lnk->lnk_vxlan = *props;
- device->link.parent = props->parent_ifindex;
+ lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL);
+ lnk->lnk_infiniband.p_key = d->p_key;
+ lnk->lnk_infiniband.mode = "datagram";
- if (out_link)
- *out_link = &device->link;
- return TRUE;
+ obj_tmp->link.parent = d->parent;
+ obj_tmp->_link.netlink.lnk = lnk;
}
static gboolean
infiniband_partition_add (NMPlatform *platform, int parent, int p_key, const NMPlatformLink **out_link)
{
- NMFakePlatformLink *device, *parent_device;
+ NMFakePlatformLink *parent_device;
char name[IFNAMSIZ];
+ const struct infiniband_add_data d = {
+ .parent = parent,
+ .p_key = p_key,
+ };
parent_device = link_get (platform, parent);
g_return_val_if_fail (parent_device != NULL, FALSE);
- nm_utils_new_infiniband_name (name, parent_device->link.name, p_key);
-
- if (!link_add (platform, name, NM_LINK_TYPE_INFINIBAND, NULL, NULL, 0, out_link))
- return FALSE;
-
- device = link_get (platform, nm_platform_link_get_ifindex (platform, name));
- g_return_val_if_fail (device, FALSE);
- g_return_val_if_fail (!device->lnk, FALSE);
+ nm_utils_new_infiniband_name (name, parent_device->obj->link.name, p_key);
- device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
- device->lnk->lnk_infiniband.p_key = p_key;
- device->lnk->lnk_infiniband.mode = "datagram";
- device->link.parent = parent;
+ link_add_one (platform, name, NM_LINK_TYPE_INFINIBAND,
+ _infiniband_add_prepare, &d, out_link);
return TRUE;
}
@@ -810,7 +856,7 @@ infiniband_partition_delete (NMPlatform *platform, int parent, int p_key)
parent_device = link_get (platform, parent);
g_return_val_if_fail (parent_device != NULL, FALSE);
- nm_utils_new_infiniband_name (name, parent_device->link.name, p_key);
+ nm_utils_new_infiniband_name (name, parent_device->obj->link.name, p_key);
return link_delete (platform, nm_platform_link_get_ifindex (platform, name));
}
@@ -821,7 +867,7 @@ wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabiliti
g_return_val_if_fail (device, FALSE);
- if (device->link.type != NM_LINK_TYPE_WIFI)
+ if (device->obj->link.type != NM_LINK_TYPE_WIFI)
return FALSE;
if (caps) {
@@ -911,59 +957,25 @@ mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len)
/*****************************************************************************/
-static GArray *
-ip4_address_get_all (NMPlatform *platform, int ifindex)
-{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- GArray *addresses;
- NMPlatformIP4Address *address;
- int count = 0, i;
-
- /* Count addresses */
- for (i = 0; i < priv->ip4_addresses->len; i++) {
- address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
- if (address && address->ifindex == ifindex)
- count++;
- }
-
- addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Address), count);
-
- /* Fill addresses */
- for (i = 0; i < priv->ip4_addresses->len; i++) {
- address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
- if (address && address->ifindex == ifindex)
- g_array_append_val (addresses, *address);
- }
-
- return addresses;
-}
-
-static GArray *
-ip6_address_get_all (NMPlatform *platform, int ifindex)
+static gboolean
+ipx_address_add (NMPlatform *platform, int addr_family, const NMPlatformObject *address)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- GArray *addresses;
- NMPlatformIP6Address *address;
- int count = 0, i;
-
- /* Count addresses */
- for (i = 0; i < priv->ip6_addresses->len; i++) {
- address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
- if (address && address->ifindex == ifindex)
- count++;
- }
+ nm_auto_nmpobj NMPObject *obj = NULL;
+ NMPCacheOpsType cache_op;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
+ NMPCache *cache = nm_platform_get_cache (platform);
- addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Address), count);
+ g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
- /* Fill addresses */
- count = 0;
- for (i = 0; i < priv->ip6_addresses->len; i++) {
- address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
- if (address && address->ifindex == ifindex)
- g_array_append_val (addresses, *address);
- }
+ obj = nmp_object_new (addr_family == AF_INET
+ ? NMP_OBJECT_TYPE_IP4_ADDRESS
+ : NMP_OBJECT_TYPE_IP6_ADDRESS,
+ address);
- return addresses;
+ cache_op = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new);
+ nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
+ return TRUE;
}
static gboolean
@@ -977,9 +989,7 @@ ip4_address_add (NMPlatform *platform,
guint32 flags,
const char *label)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
NMPlatformIP4Address address;
- int i;
memset (&address, 0, sizeof (address));
address.addr_source = NM_IP_CONFIG_SOURCE_KERNEL;
@@ -994,28 +1004,7 @@ ip4_address_add (NMPlatform *platform,
if (label)
g_strlcpy (address.label, label, sizeof (address.label));
- for (i = 0; i < priv->ip4_addresses->len; i++) {
- NMPlatformIP4Address *item = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
- gboolean changed;
-
- if ( item->ifindex != address.ifindex
- || item->address != address.address
- || item->plen != address.plen
- || !_ip4_address_equal_peer_net (item->peer_address, address.peer_address, address.plen))
- continue;
-
- changed = !nm_platform_ip4_address_cmp (item, &address);
-
- memcpy (item, &address, sizeof (address));
- if (changed)
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, (int) NM_PLATFORM_SIGNAL_CHANGED);
- return TRUE;
- }
-
- g_array_append_val (priv->ip4_addresses, address);
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, (int) NM_PLATFORM_SIGNAL_ADDED);
-
- return TRUE;
+ return ipx_address_add (platform, AF_INET, (const NMPlatformObject *) &address);
}
static gboolean
@@ -1028,9 +1017,7 @@ ip6_address_add (NMPlatform *platform,
guint32 preferred,
guint32 flags)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
NMPlatformIP6Address address;
- int i;
memset (&address, 0, sizeof (address));
address.addr_source = NM_IP_CONFIG_SOURCE_KERNEL;
@@ -1043,379 +1030,253 @@ ip6_address_add (NMPlatform *platform,
address.preferred = preferred;
address.n_ifa_flags = flags;
- for (i = 0; i < priv->ip6_addresses->len; i++) {
- NMPlatformIP6Address *item = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
- gboolean changed;
-
- if ( item->ifindex != address.ifindex
- || !IN6_ARE_ADDR_EQUAL (&item->address, &address.address))
- continue;
+ return ipx_address_add (platform, AF_INET6, (const NMPlatformObject *) &address);
+}
- changed = !nm_platform_ip6_address_cmp (item, &address);
+static gboolean
+ipx_address_delete (NMPlatform *platform,
+ int addr_family,
+ int ifindex,
+ gconstpointer addr,
+ const guint8 *plen,
+ gconstpointer peer_addr)
+{
+ gs_unref_ptrarray GPtrArray *objs = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
+ NMDedupMultiIter iter;
+ const NMPObject *o = NULL;
+ guint i;
+ guint32 peer_addr_i;
+
+ g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
+
+ peer_addr_i = peer_addr ? *((guint32 *) peer_addr) : 0;
+
+ nmp_cache_iter_for_each (&iter,
+ nm_platform_lookup_addrroute (platform,
+ addr_family == AF_INET
+ ? NMP_OBJECT_TYPE_IP4_ADDRESS
+ : NMP_OBJECT_TYPE_IP6_ADDRESS,
+ 0),
+ &o) {
+ const NMPObject *obj_old = NULL;
+
+ if (addr_family == AF_INET) {
+ const NMPlatformIP4Address *address = NMP_OBJECT_CAST_IP4_ADDRESS (o);
+
+ if ( address->ifindex != ifindex
+ || (addr && address->address != *((guint32 *) addr))
+ || (plen && address->plen != *plen)
+ || ( peer_addr
+ && (((peer_addr_i ^ address->peer_address) & nm_utils_ip4_prefix_to_netmask (address->plen)) != 0)))
+ continue;
+ } else {
+ const NMPlatformIP6Address *address = NMP_OBJECT_CAST_IP6_ADDRESS (o);
+
+ g_assert (!peer_addr);
+ if ( address->ifindex != ifindex
+ || (addr && !IN6_ARE_ADDR_EQUAL (&address->address, addr))
+ || (plen && address->plen != *plen))
+ continue;
+ }
- memcpy (item, &address, sizeof (address));
- if (changed)
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, (int) NM_PLATFORM_SIGNAL_CHANGED);
- return TRUE;
+ if (nmp_cache_remove (nm_platform_get_cache (platform),
+ o,
+ TRUE,
+ &obj_old) != NMP_CACHE_OPS_REMOVED)
+ g_assert_not_reached ();
+ g_assert (obj_old);
+ g_ptr_array_add (objs, (gpointer) obj_old);
}
- g_array_append_val (priv->ip6_addresses, address);
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, (int) NM_PLATFORM_SIGNAL_ADDED);
-
+ for (i = 0; i < objs->len; i++) {
+ nm_platform_cache_update_emit_signal (platform,
+ NMP_CACHE_OPS_REMOVED,
+ objs->pdata[i],
+ NULL);
+ }
return TRUE;
}
static gboolean
ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, guint8 plen, in_addr_t peer_address)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
-
- for (i = 0; i < priv->ip4_addresses->len; i++) {
- NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
-
- if ( address->ifindex == ifindex
- && address->plen == plen
- && address->address == addr
- && ((peer_address ^ address->peer_address) & nm_utils_ip4_prefix_to_netmask (plen)) == 0) {
- NMPlatformIP4Address deleted_address;
-
- memcpy (&deleted_address, address, sizeof (deleted_address));
- memset (address, 0, sizeof (*address));
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &deleted_address, (int) NM_PLATFORM_SIGNAL_REMOVED);
- return TRUE;
- }
- }
-
- return TRUE;
+ return ipx_address_delete (platform, AF_INET, ifindex, &addr, &plen, &peer_address);
}
static gboolean
ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, guint8 plen)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
-
- for (i = 0; i < priv->ip6_addresses->len; i++) {
- NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
-
- if ( address->ifindex == ifindex
- && address->plen == plen
- && IN6_ARE_ADDR_EQUAL (&address->address, &addr)) {
- NMPlatformIP6Address deleted_address;
-
- memcpy (&deleted_address, address, sizeof (deleted_address));
- memset (address, 0, sizeof (*address));
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &deleted_address, (int) NM_PLATFORM_SIGNAL_REMOVED);
- return TRUE;
- }
- }
-
- return TRUE;
-}
-
-static const NMPlatformIP4Address *
-ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, guint8 plen, in_addr_t peer_address)
-{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
-
- for (i = 0; i < priv->ip4_addresses->len; i++) {
- NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
-
- if ( address->ifindex == ifindex
- && address->plen == plen
- && address->address == addr
- && _ip4_address_equal_peer_net (address->peer_address, peer_address, plen))
- return address;
- }
-
- return NULL;
-}
-
-static const NMPlatformIP6Address *
-ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr)
-{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
-
- for (i = 0; i < priv->ip6_addresses->len; i++) {
- NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
-
- if ( address->ifindex == ifindex
- && IN6_ARE_ADDR_EQUAL (&address->address, &addr))
- return address;
- }
-
- return NULL;
+ return ipx_address_delete (platform, AF_INET6, ifindex, &addr, &plen, NULL);
}
/*****************************************************************************/
-static GArray *
-ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
+static gboolean
+ipx_route_delete (NMPlatform *platform,
+ int addr_family,
+ int ifindex,
+ gconstpointer network,
+ const guint8 *plen,
+ const guint32 *metric)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- GArray *routes;
- NMPlatformIP4Route *route;
+ gs_unref_ptrarray GPtrArray *objs = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
+ NMDedupMultiIter iter;
+ const NMPObject *o = NULL;
guint i;
- routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route));
-
- if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
- flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT;
-
- /* Fill routes */
- for (i = 0; i < priv->ip4_routes->len; i++) {
- route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
- if (route && (!ifindex || route->ifindex == ifindex)) {
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
- if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT))
- g_array_append_val (routes, *route);
- } else {
- if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
- g_array_append_val (routes, *route);
- }
+ g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
+
+ nmp_cache_iter_for_each (&iter,
+ nm_platform_lookup_addrroute (platform,
+ addr_family == AF_INET
+ ? NMP_OBJECT_TYPE_IP4_ROUTE
+ : NMP_OBJECT_TYPE_IP6_ROUTE,
+ 0),
+ &o) {
+ const NMPObject *obj_old = NULL;
+
+ if (addr_family == AF_INET) {
+ const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (o);
+
+ if ( route->ifindex != ifindex
+ || (network && route->network != *((guint32 *) network))
+ || (plen && route->plen != *plen)
+ || (metric && route->metric != *metric))
+ continue;
+ } else {
+ const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (o);
+
+ if ( route->ifindex != ifindex
+ || (network && !IN6_ARE_ADDR_EQUAL (&route->network, network))
+ || (plen && route->plen != *plen)
+ || (metric && route->metric != *metric))
+ continue;
}
- }
-
- return routes;
-}
-
-static GArray *
-ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
-{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- GArray *routes;
- NMPlatformIP6Route *route;
- guint i;
-
- routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route));
- if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
- flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT;
-
- /* Fill routes */
- for (i = 0; i < priv->ip6_routes->len; i++) {
- route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
- if (route && (!ifindex || route->ifindex == ifindex)) {
- if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
- if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT))
- g_array_append_val (routes, *route);
- } else {
- if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
- g_array_append_val (routes, *route);
- }
- }
+ if (nmp_cache_remove (nm_platform_get_cache (platform),
+ o,
+ TRUE,
+ &obj_old) != NMP_CACHE_OPS_REMOVED)
+ g_assert_not_reached ();
+ g_assert (obj_old);
+ g_ptr_array_add (objs, (gpointer) obj_old);
}
- return routes;
+ for (i = 0; i < objs->len; i++) {
+ nm_platform_cache_update_emit_signal (platform,
+ NMP_CACHE_OPS_REMOVED,
+ objs->pdata[i],
+ NULL);
+ }
+ return TRUE;
}
static gboolean
ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
-
- for (i = 0; i < priv->ip4_routes->len; i++) {
- NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
- NMPlatformIP4Route deleted_route;
-
- if ( route->ifindex != ifindex
- || route->network != network
- || route->plen != plen
- || route->metric != metric)
- continue;
-
- memcpy (&deleted_route, route, sizeof (deleted_route));
- g_array_remove_index (priv->ip4_routes, i);
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, &deleted_route, (int) NM_PLATFORM_SIGNAL_REMOVED);
- }
-
- return TRUE;
+ return ipx_route_delete (platform, AF_INET, ifindex, &network, &plen, &metric);
}
static gboolean
ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
-
metric = nm_utils_ip6_route_metric_normalize (metric);
-
- for (i = 0; i < priv->ip6_routes->len; i++) {
- NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
- NMPlatformIP6Route deleted_route;
-
- if ( route->ifindex != ifindex
- || !IN6_ARE_ADDR_EQUAL (&route->network, &network)
- || route->plen != plen
- || route->metric != metric)
- continue;
-
- memcpy (&deleted_route, route, sizeof (deleted_route));
- g_array_remove_index (priv->ip6_routes, i);
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, &deleted_route, (int) NM_PLATFORM_SIGNAL_REMOVED);
- }
-
- return TRUE;
+ return ipx_route_delete (platform, AF_INET6, ifindex, &network, &plen, &metric);
}
static gboolean
-ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route)
-{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- NMPlatformIP4Route rt = *route;
- guint i;
-
- rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source);
- rt.network = nm_utils_ip4_address_clear_host_address (rt.network, rt.plen);
- rt.scope_inv = nm_platform_route_scope_inv (rt.gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK);
-
- if (rt.gateway) {
- for (i = 0; i < priv->ip4_routes->len; i++) {
- NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes,
- NMPlatformIP4Route, i);
- guint32 gate = ntohl (item->network) >> (32 - item->plen);
- guint32 host = ntohl (rt.gateway) >> (32 - item->plen);
-
- if (rt.ifindex == item->ifindex && gate == host)
- break;
- }
- if (i == priv->ip4_routes->len) {
- nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable",
- rt.ifindex, nm_utils_inet4_ntop (rt.network, NULL), rt.plen, rt.metric);
- return FALSE;
- }
+ipx_route_add (NMPlatform *platform, int addr_family, const NMPlatformObject *route)
+{
+ NMDedupMultiIter iter;
+ nm_auto_nmpobj NMPObject *obj = NULL;
+ NMPlatformIPRoute *rt;
+ NMPCacheOpsType cache_op;
+ const NMPObject *o = NULL;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
+ NMPCache *cache = nm_platform_get_cache (platform);
+ gboolean has_gateway = FALSE;
+ NMPlatformIP4Route *rt4 = NULL;
+ NMPlatformIP6Route *rt6 = NULL;
+
+ g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
+
+ obj = nmp_object_new (addr_family == AF_INET
+ ? NMP_OBJECT_TYPE_IP4_ROUTE
+ : NMP_OBJECT_TYPE_IP6_ROUTE,
+ route);
+ rt = &obj->ip_route;
+ rt->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt->rt_source);
+
+ if (addr_family == AF_INET) {
+ rt4 = NMP_OBJECT_CAST_IP4_ROUTE (obj);
+ rt4->scope_inv = nm_platform_route_scope_inv (rt4->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK);
+ rt4->network = nm_utils_ip4_address_clear_host_address (rt4->network, rt4->plen);
+ if (rt4->gateway)
+ has_gateway = TRUE;
+ } else {
+ rt6 = NMP_OBJECT_CAST_IP6_ROUTE (obj);
+ rt->metric = nm_utils_ip6_route_metric_normalize (rt->metric);
+ nm_utils_ip6_address_clear_host_address (&rt6->network, &rt6->network, rt->plen);
+ if (!IN6_IS_ADDR_UNSPECIFIED (&rt6->gateway))
+ has_gateway = TRUE;
}
- for (i = 0; i < priv->ip4_routes->len; i++) {
- NMPlatformIP4Route *item = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
-
- if (item->network != rt.network)
- continue;
- if (item->plen != rt.plen)
- continue;
- if (item->metric != rt.metric)
- continue;
-
- if (item->ifindex != rt.ifindex) {
- ip4_route_delete (platform, item->ifindex, item->network, item->plen, item->metric);
- i--;
- continue;
- }
-
- memcpy (item, &rt, sizeof (rt));
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE,
- rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED);
- return TRUE;
- }
-
- g_array_append_val (priv->ip4_routes, rt);
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP4_ROUTE,
- rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED);
-
- return TRUE;
-}
-
-static gboolean
-ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route)
-{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- NMPlatformIP6Route rt = *route;
- guint i;
+ if (has_gateway) {
+ gboolean has_route_to_gw = FALSE;
+
+ nmp_cache_iter_for_each (&iter,
+ nm_platform_lookup_addrroute (platform,
+ NMP_OBJECT_GET_TYPE (obj),
+ 0),
+ &o) {
+ if (addr_family == AF_INET) {
+ const NMPlatformIP4Route *item = NMP_OBJECT_CAST_IP4_ROUTE (o);
+ guint32 n = nm_utils_ip4_address_clear_host_address (item->network, item->plen);
+ guint32 g = nm_utils_ip4_address_clear_host_address (rt4->gateway, item->plen);
+
+ if ( rt->ifindex == item->ifindex
+ && n == g) {
+ has_route_to_gw = TRUE;
+ break;
+ }
+ } else {
+ const NMPlatformIP6Route *item = NMP_OBJECT_CAST_IP6_ROUTE (o);
- rt.metric = nm_utils_ip6_route_metric_normalize (rt.metric);
- rt.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt.rt_source);
- nm_utils_ip6_address_clear_host_address (&rt.network, &rt.network, rt.plen);
-
- if (!IN6_IS_ADDR_UNSPECIFIED (&rt.gateway)) {
- for (i = 0; i < priv->ip6_routes->len; i++) {
- NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes,
- NMPlatformIP6Route, i);
- guint8 gate_bits = rt.gateway.s6_addr[item->plen / 8] >> (8 - item->plen % 8);
- guint8 host_bits = item->network.s6_addr[item->plen / 8] >> (8 - item->plen % 8);
-
- if ( rt.ifindex == item->ifindex
- && memcmp (&rt.gateway, &item->network, item->plen / 8) == 0
- && gate_bits == host_bits)
- break;
+ if ( rt->ifindex == item->ifindex
+ && nm_utils_ip6_address_same_prefix (&rt6->gateway, &item->network, item->plen)) {
+ has_route_to_gw = TRUE;
+ break;
+ }
+ }
}
- if (i == priv->ip6_routes->len) {
- nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable",
- rt.ifindex, nm_utils_inet6_ntop (&rt.network, NULL), rt.plen, rt.metric);
+ if (!has_route_to_gw) {
+ if (addr_family == AF_INET) {
+ nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip4-route '%d: %s/%d %d': Network Unreachable",
+ rt->ifindex, nm_utils_inet4_ntop (rt4->network, NULL), rt->plen, rt->metric);
+ } else {
+ nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable",
+ rt->ifindex, nm_utils_inet6_ntop (&rt6->network, NULL), rt->plen, rt->metric);
+ }
return FALSE;
}
}
- for (i = 0; i < priv->ip6_routes->len; i++) {
- NMPlatformIP6Route *item = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
-
- if (!IN6_ARE_ADDR_EQUAL (&item->network, &rt.network))
- continue;
- if (item->plen != rt.plen)
- continue;
- if (item->metric != rt.metric)
- continue;
-
- if (item->ifindex != rt.ifindex) {
- ip6_route_delete (platform, item->ifindex, item->network, item->plen, item->metric);
- i--;
- continue;
- }
-
- memcpy (item, &rt, sizeof (rt));
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE,
- rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_CHANGED);
- return TRUE;
- }
-
- g_array_append_val (priv->ip6_routes, rt);
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, (int) NMP_OBJECT_TYPE_IP6_ROUTE,
- rt.ifindex, &rt, (int) NM_PLATFORM_SIGNAL_ADDED);
-
+ cache_op = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new);
+ nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
return TRUE;
}
-static const NMPlatformIP4Route *
-ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric)
+static gboolean
+ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
-
- for (i = 0; i < priv->ip4_routes->len; i++) {
- NMPlatformIP4Route *route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
-
- if (route->ifindex == ifindex
- && route->network == network
- && route->plen == plen
- && route->metric == metric)
- return route;
- }
-
- return NULL;
+ return ipx_route_add (platform, AF_INET, (const NMPlatformObject *) route);
}
-static const NMPlatformIP6Route *
-ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric)
+static gboolean
+ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route)
{
- NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform);
- int i;
-
- metric = nm_utils_ip6_route_metric_normalize (metric);
-
- for (i = 0; i < priv->ip6_routes->len; i++) {
- NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
-
- if (route->ifindex == ifindex
- && IN6_ARE_ADDR_EQUAL (&route->network, &network)
- && route->plen == plen
- && route->metric == metric)
- return route;
- }
-
- return NULL;
+ return ipx_route_add (platform, AF_INET6, (const NMPlatformObject *) route);
}
/*****************************************************************************/
@@ -1427,10 +1288,6 @@ nm_fake_platform_init (NMFakePlatform *fake_platform)
priv->options = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
priv->links = g_array_new (TRUE, TRUE, sizeof (NMFakePlatformLink));
- priv->ip4_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Address));
- priv->ip6_addresses = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Address));
- priv->ip4_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route));
- priv->ip6_routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route));
}
void
@@ -1444,9 +1301,6 @@ nm_fake_platform_setup (void)
nm_platform_setup (platform);
- /* skip zero element */
- link_add (platform, NULL, NM_LINK_TYPE_NONE, NULL, NULL, 0, NULL);
-
/* add loopback interface */
link_add (platform, "lo", NM_LINK_TYPE_LOOPBACK, NULL, NULL, 0, NULL);
@@ -1467,13 +1321,9 @@ finalize (GObject *object)
NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i);
g_free (device->udi);
- g_clear_pointer (&device->lnk, nmp_object_unref);
+ g_clear_pointer (&device->obj, nmp_object_unref);
}
g_array_unref (priv->links);
- g_array_unref (priv->ip4_addresses);
- g_array_unref (priv->ip6_addresses);
- g_array_unref (priv->ip4_routes);
- g_array_unref (priv->ip6_routes);
G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object);
}
@@ -1489,15 +1339,8 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->sysctl_set = sysctl_set;
platform_class->sysctl_get = sysctl_get;
- platform_class->link_get = _nm_platform_link_get;
- platform_class->link_get_by_ifname = _nm_platform_link_get_by_ifname;
- platform_class->link_get_by_address = _nm_platform_link_get_by_address;
- platform_class->link_get_all = link_get_all;
platform_class->link_add = link_add;
platform_class->link_delete = link_delete;
- platform_class->link_get_type_name = link_get_type_name;
-
- platform_class->link_get_lnk = link_get_lnk;
platform_class->link_get_udi = link_get_udi;
@@ -1541,19 +1384,11 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->mesh_set_channel = mesh_set_channel;
platform_class->mesh_set_ssid = mesh_set_ssid;
- platform_class->ip4_address_get = ip4_address_get;
- platform_class->ip6_address_get = ip6_address_get;
- platform_class->ip4_address_get_all = ip4_address_get_all;
- platform_class->ip6_address_get_all = ip6_address_get_all;
platform_class->ip4_address_add = ip4_address_add;
platform_class->ip6_address_add = ip6_address_add;
platform_class->ip4_address_delete = ip4_address_delete;
platform_class->ip6_address_delete = ip6_address_delete;
- platform_class->ip4_route_get = ip4_route_get;
- platform_class->ip6_route_get = ip6_route_get;
- platform_class->ip4_route_get_all = ip4_route_get_all;
- platform_class->ip6_route_get_all = ip6_route_get_all;
platform_class->ip4_route_add = ip4_route_add;
platform_class->ip6_route_add = ip6_route_add;
platform_class->ip4_route_delete = ip4_route_delete;
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index 8d4df98616..6a4210de90 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -48,6 +48,7 @@
#include "nmp-object.h"
#include "nmp-netns.h"
#include "nm-platform-utils.h"
+#include "nm-platform-private.h"
#include "wifi/wifi-utils.h"
#include "wifi/wifi-utils-wext.h"
#include "nm-utils/unaligned.h"
@@ -255,10 +256,12 @@ static void delayed_action_schedule (NMPlatform *platform, DelayedActionType act
static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink);
static void do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const char *name);
static void do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType action_type);
-static void cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
-static void cache_prune_candidates_prune (NMPlatform *platform);
+static void cache_on_change (NMPlatform *platform,
+ NMPCacheOpsType cache_op,
+ const NMPObject *obj_old,
+ const NMPObject *obj_new);
+static void cache_prune_all (NMPlatform *platform);
static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks);
-static void ASSERT_NETNS_CURRENT (NMPlatform *platform);
/*****************************************************************************/
@@ -628,7 +631,7 @@ _linktype_get_type (NMPlatform *platform,
{
guint i;
- ASSERT_NETNS_CURRENT (platform);
+ NMTST_ASSERT_PLATFORM_NETNS_CURRENT (platform);
nm_assert (ifname);
if (completed_from_cache) {
@@ -1680,7 +1683,7 @@ _new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr
* Also, sometimes the info-data is missing for updates. In this case
* we want to keep the previously received lnk_data. */
nmp_object_unref (lnk_data);
- lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk);
+ lnk_data = (NMPObject *) nmp_object_ref (link_cached->_link.netlink.lnk);
}
if (address_complete_from_cache)
obj->link.addr = link_cached->link.addr;
@@ -2570,11 +2573,12 @@ typedef struct {
guint32 nlh_seq_last_handled;
#endif
guint32 nlh_seq_last_seen;
- NMPCache *cache;
GIOChannel *event_channel;
guint event_id;
- gboolean sysctl_get_warned;
+ bool pruning[_DELAYED_ACTION_IDX_REFRESH_ALL_NUM];
+
+ bool sysctl_get_warned;
GHashTable *sysctl_get_prev_values;
NMUdevClient *udev_client;
@@ -2595,8 +2599,6 @@ typedef struct {
gint is_handling;
} delayed_action;
- GHashTable *prune_candidates;
-
GHashTable *wifi_data;
} NMLinuxPlatformPrivate;
@@ -2616,8 +2618,15 @@ G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
NMPlatform *
nm_linux_platform_new (gboolean log_with_ptr, gboolean netns_support)
{
+ gboolean use_udev = FALSE;
+
+ if ( nmp_netns_is_initial ()
+ && access ("/sys", W_OK) == 0)
+ use_udev = TRUE;
+
return g_object_new (NM_TYPE_LINUX_PLATFORM,
NM_PLATFORM_LOG_WITH_PTR, log_with_ptr,
+ NM_PLATFORM_USE_UDEV, use_udev,
NM_PLATFORM_NETNS_SUPPORT, netns_support,
NULL);
}
@@ -2628,13 +2637,6 @@ nm_linux_platform_setup (void)
nm_platform_setup (nm_linux_platform_new (FALSE, FALSE));
}
-static void
-ASSERT_NETNS_CURRENT (NMPlatform *platform)
-{
- nm_assert (NM_IS_LINUX_PLATFORM (platform));
- nm_assert (NM_IN_SET (nm_platform_netns_get (platform), NULL, nmp_netns_get_current ()));
-}
-
/*****************************************************************************/
#define ASSERT_SYSCTL_ARGS(pathid, dirfd, path) \
@@ -2913,86 +2915,6 @@ process_events (NMPlatform *platform)
/*****************************************************************************/
-#define cache_lookup_all_objects(type, platform, obj_type, visible_only) \
- ({ \
- NMPCacheId _cache_id; \
- \
- ((const type *const*) nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE ((platform))->cache, \
- nmp_cache_id_init_object_type (&_cache_id, (obj_type), (visible_only)), \
- NULL)); \
- })
-
-/*****************************************************************************/
-
-static void
-do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cache_op, gboolean was_visible)
-{
- gboolean is_visible;
- NMPObject obj_clone;
- const NMPClass *klass;
-
- nm_assert (NM_IN_SET ((NMPlatformSignalChangeType) cache_op, (NMPlatformSignalChangeType) NMP_CACHE_OPS_UNCHANGED, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_SIGNAL_REMOVED));
-
- nm_assert (obj || cache_op == NMP_CACHE_OPS_UNCHANGED);
- nm_assert (!obj || cache_op == NMP_CACHE_OPS_REMOVED || obj == nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
- nm_assert (!obj || cache_op != NMP_CACHE_OPS_REMOVED || obj != nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj));
-
- ASSERT_NETNS_CURRENT (platform);
-
- switch (cache_op) {
- case NMP_CACHE_OPS_ADDED:
- if (!nmp_object_is_visible (obj))
- return;
- break;
- case NMP_CACHE_OPS_UPDATED:
- is_visible = nmp_object_is_visible (obj);
- if (!was_visible && is_visible)
- cache_op = NMP_CACHE_OPS_ADDED;
- else if (was_visible && !is_visible) {
- /* This is a bit ugly. The object was visible and changed in a way that it became invisible.
- * We raise a removed signal, but contrary to a real 'remove', @obj is already changed to be
- * different from what it was when the user saw it the last time.
- *
- * The more correct solution would be to have cache_pre_hook() create a clone of the original
- * value before it was changed to become invisible.
- *
- * But, don't bother. Probably nobody depends on the original values and only cares about the
- * id properties (which are still correct).
- */
- cache_op = NMP_CACHE_OPS_REMOVED;
- } else if (!is_visible)
- return;
- break;
- case NMP_CACHE_OPS_REMOVED:
- if (!was_visible)
- return;
- break;
- default:
- g_assert (cache_op == NMP_CACHE_OPS_UNCHANGED);
- return;
- }
-
- klass = NMP_OBJECT_GET_CLASS (obj);
-
- _LOGt ("emit signal %s %s: %s",
- klass->signal_type,
- nm_platform_signal_change_type_to_string ((NMPlatformSignalChangeType) cache_op),
- nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
-
- /* don't expose @obj directly, but clone the public fields. A signal handler might
- * call back into NMPlatform which could invalidate (or modify) @obj. */
- memcpy (&obj_clone.object, &obj->object, klass->sizeof_public);
- g_signal_emit (platform,
- _nm_platform_signal_id_get (klass->signal_type_id),
- 0,
- (int) klass->obj_type,
- obj_clone.object.ifindex,
- &obj_clone.object,
- (int) cache_op);
-}
-
-/*****************************************************************************/
-
_NM_UTILS_LOOKUP_DEFINE (static, delayed_action_refresh_from_object_type, NMPObjectType, DelayedActionType,
NM_UTILS_LOOKUP_DEFAULT_NM_ASSERT (DELAYED_ACTION_TYPE_NONE),
NM_UTILS_LOOKUP_ITEM (NMP_OBJECT_TYPE_LINK, DELAYED_ACTION_TYPE_REFRESH_ALL_LINKS),
@@ -3163,13 +3085,15 @@ delayed_action_wait_for_nl_response_complete_all (NMPlatform *platform,
static void
delayed_action_handle_MASTER_CONNECTED (NMPlatform *platform, int master_ifindex)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- nm_auto_nmpobj NMPObject *obj_cache = NULL;
- gboolean was_visible;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
NMPCacheOpsType cache_op;
- cache_op = nmp_cache_update_link_master_connected (priv->cache, master_ifindex, &obj_cache, &was_visible, cache_pre_hook, platform);
- do_emit_signal (platform, obj_cache, cache_op, was_visible);
+ cache_op = nmp_cache_update_link_master_connected (nm_platform_get_cache (platform), master_ifindex, &obj_old, &obj_new);
+ if (cache_op == NMP_CACHE_OPS_UNCHANGED)
+ return;
+ cache_on_change (platform, cache_op, obj_old, obj_new);
+ nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
}
static void
@@ -3290,7 +3214,7 @@ delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink)
any = TRUE;
priv->delayed_action.is_handling--;
- cache_prune_candidates_prune (platform);
+ cache_prune_all (platform);
return any;
}
@@ -3353,146 +3277,113 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform,
/*****************************************************************************/
static void
-cache_prune_candidates_record_all (NMPlatform *platform, NMPObjectType obj_type)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- NMPCacheId cache_id;
-
- priv->prune_candidates = nmp_cache_lookup_all_to_hash (priv->cache,
- nmp_cache_id_init_object_type (&cache_id, obj_type, FALSE),
- priv->prune_candidates);
- _LOGt ("cache-prune: record %s (now %u candidates)", nmp_class_from_type (obj_type)->obj_type_name,
- priv->prune_candidates ? g_hash_table_size (priv->prune_candidates) : 0);
-}
-
-static void
-cache_prune_candidates_record_one (NMPlatform *platform, NMPObject *obj)
+cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type)
{
- NMLinuxPlatformPrivate *priv;
-
- if (!obj)
- return;
-
- priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
-
- if (!priv->prune_candidates)
- priv->prune_candidates = g_hash_table_new_full (NULL, NULL, (GDestroyNotify) nmp_object_unref, NULL);
-
- if (_LOGt_ENABLED () && !g_hash_table_contains (priv->prune_candidates, obj))
- _LOGt ("cache-prune: record-one: %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
- g_hash_table_add (priv->prune_candidates, nmp_object_ref (obj));
-}
-
-static void
-cache_prune_candidates_drop (NMPlatform *platform, const NMPObject *obj)
-{
- NMLinuxPlatformPrivate *priv;
-
- if (!obj)
- return;
-
- priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- if (priv->prune_candidates) {
- if (_LOGt_ENABLED () && g_hash_table_contains (priv->prune_candidates, obj))
- _LOGt ("cache-prune: drop-one: %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
- g_hash_table_remove (priv->prune_candidates, obj);
+ NMDedupMultiIter iter;
+ const NMPObject *obj;
+ NMPCacheOpsType cache_op;
+ NMPLookup lookup;
+ NMPCache *cache = nm_platform_get_cache (platform);
+
+ nmp_lookup_init_obj_type (&lookup,
+ obj_type);
+ nm_dedup_multi_iter_init (&iter,
+ nmp_cache_lookup (cache,
+ &lookup));
+ while (nm_dedup_multi_iter_next (&iter)) {
+ if (iter.current->dirty) {
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+
+ obj = iter.current->obj;
+ _LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
+ cache_op = nmp_cache_remove (cache, obj, TRUE, &obj_old);
+ nm_assert (cache_op == NMP_CACHE_OPS_REMOVED);
+ cache_on_change (platform, cache_op, obj_old, NULL);
+ nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, NULL);
+ }
}
}
static void
-cache_prune_candidates_prune (NMPlatform *platform)
+cache_prune_all (NMPlatform *platform)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- GHashTable *prune_candidates;
- GHashTableIter iter;
- const NMPObject *obj;
- gboolean was_visible;
- NMPCacheOpsType cache_op;
-
- if (!priv->prune_candidates)
- return;
-
- prune_candidates = priv->prune_candidates;
- priv->prune_candidates = NULL;
+ DelayedActionType iflags, action_type;
- g_hash_table_iter_init (&iter, prune_candidates);
- while (g_hash_table_iter_next (&iter, (gpointer *)&obj, NULL)) {
- nm_auto_nmpobj NMPObject *obj_cache = NULL;
+ action_type = DELAYED_ACTION_TYPE_REFRESH_ALL;
+ FOR_EACH_DELAYED_ACTION (iflags, action_type) {
+ bool *p = &priv->pruning[delayed_action_refresh_all_to_idx (iflags)];
- _LOGt ("cache-prune: prune %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ALL, NULL, 0));
- cache_op = nmp_cache_remove (priv->cache, obj, TRUE, &obj_cache, &was_visible, cache_pre_hook, platform);
- do_emit_signal (platform, obj_cache, cache_op, was_visible);
+ if (*p) {
+ *p = FALSE;
+ cache_prune_one_type (platform, delayed_action_refresh_to_object_type (iflags));
+ }
}
-
- g_hash_table_unref (prune_candidates);
}
static void
-cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data)
+cache_on_change (NMPlatform *platform,
+ NMPCacheOpsType cache_op,
+ const NMPObject *obj_old,
+ const NMPObject *obj_new)
{
- NMPlatform *platform = user_data;
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
const NMPClass *klass;
char str_buf[sizeof (_nm_utils_to_string_buffer)];
char str_buf2[sizeof (_nm_utils_to_string_buffer)];
+ NMPCache *cache = nm_platform_get_cache (platform);
- nm_assert (old || new);
- nm_assert (NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_REMOVED, NMP_CACHE_OPS_UPDATED));
- nm_assert (ops_type != NMP_CACHE_OPS_ADDED || (old == NULL && NMP_OBJECT_IS_VALID (new) && nmp_object_is_alive (new)));
- nm_assert (ops_type != NMP_CACHE_OPS_REMOVED || (new == NULL && NMP_OBJECT_IS_VALID (old) && nmp_object_is_alive (old)));
- nm_assert (ops_type != NMP_CACHE_OPS_UPDATED || (NMP_OBJECT_IS_VALID (old) && nmp_object_is_alive (old) && NMP_OBJECT_IS_VALID (new) && nmp_object_is_alive (new)));
- nm_assert (new == NULL || old == NULL || nmp_object_id_equal (new, old));
- nm_assert (!old || !new || NMP_OBJECT_GET_CLASS (old) == NMP_OBJECT_GET_CLASS (new));
+ ASSERT_nmp_cache_ops (cache, cache_op, obj_old, obj_new);
- klass = old ? NMP_OBJECT_GET_CLASS (old) : NMP_OBJECT_GET_CLASS (new);
+ if (cache_op == NMP_CACHE_OPS_UNCHANGED)
+ return;
- nm_assert (klass == (new ? NMP_OBJECT_GET_CLASS (new) : NMP_OBJECT_GET_CLASS (old)));
+ klass = obj_old ? NMP_OBJECT_GET_CLASS (obj_old) : NMP_OBJECT_GET_CLASS (obj_new);
_LOGt ("update-cache-%s: %s: %s%s%s",
klass->obj_type_name,
- (ops_type == NMP_CACHE_OPS_UPDATED
+ (cache_op == NMP_CACHE_OPS_UPDATED
? "UPDATE"
- : (ops_type == NMP_CACHE_OPS_REMOVED
+ : (cache_op == NMP_CACHE_OPS_REMOVED
? "REMOVE"
- : (ops_type == NMP_CACHE_OPS_ADDED) ? "ADD" : "???")),
- (ops_type != NMP_CACHE_OPS_ADDED
- ? nmp_object_to_string (old, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof (str_buf2))
- : nmp_object_to_string (new, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof (str_buf2))),
- (ops_type == NMP_CACHE_OPS_UPDATED) ? " -> " : "",
- (ops_type == NMP_CACHE_OPS_UPDATED
- ? nmp_object_to_string (new, NMP_OBJECT_TO_STRING_ALL, str_buf, sizeof (str_buf))
+ : (cache_op == NMP_CACHE_OPS_ADDED) ? "ADD" : "???")),
+ (cache_op != NMP_CACHE_OPS_ADDED
+ ? nmp_object_to_string (obj_old, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof (str_buf2))
+ : nmp_object_to_string (obj_new, NMP_OBJECT_TO_STRING_ALL, str_buf2, sizeof (str_buf2))),
+ (cache_op == NMP_CACHE_OPS_UPDATED) ? " -> " : "",
+ (cache_op == NMP_CACHE_OPS_UPDATED
+ ? nmp_object_to_string (obj_new, NMP_OBJECT_TO_STRING_ALL, str_buf, sizeof (str_buf))
: ""));
switch (klass->obj_type) {
case NMP_OBJECT_TYPE_LINK:
{
/* check whether changing a slave link can cause a master link (bridge or bond) to go up/down */
- if ( old
- && nmp_cache_link_connected_needs_toggle_by_ifindex (priv->cache, old->link.master, new, old))
- delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (old->link.master));
- if ( new
- && (!old || old->link.master != new->link.master)
- && nmp_cache_link_connected_needs_toggle_by_ifindex (priv->cache, new->link.master, new, old))
- delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (new->link.master));
+ if ( obj_old
+ && nmp_cache_link_connected_needs_toggle_by_ifindex (cache, obj_old->link.master, obj_new, obj_old))
+ delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (obj_old->link.master));
+ if ( obj_new
+ && (!obj_old || obj_old->link.master != obj_new->link.master)
+ && nmp_cache_link_connected_needs_toggle_by_ifindex (cache, obj_new->link.master, obj_new, obj_old))
+ delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (obj_new->link.master));
}
{
/* check whether we are about to change a master link that needs toggling connected state. */
- if ( new /* <-- nonsensical, make coverity happy */
- && nmp_cache_link_connected_needs_toggle (cache, new, new, old))
- delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (new->link.ifindex));
+ if ( obj_new /* <-- nonsensical, make coverity happy */
+ && nmp_cache_link_connected_needs_toggle (cache, obj_new, obj_new, obj_old))
+ delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (obj_new->link.ifindex));
}
{
int ifindex = 0;
/* if we remove a link (from netlink), we must refresh the addresses and routes */
- if ( ops_type == NMP_CACHE_OPS_REMOVED
- && old /* <-- nonsensical, make coverity happy */)
- ifindex = old->link.ifindex;
- else if ( ops_type == NMP_CACHE_OPS_UPDATED
- && old && new /* <-- nonsensical, make coverity happy */
- && !new->_link.netlink.is_in_netlink
- && new->_link.netlink.is_in_netlink != old->_link.netlink.is_in_netlink)
- ifindex = new->link.ifindex;
+ if ( cache_op == NMP_CACHE_OPS_REMOVED
+ && obj_old /* <-- nonsensical, make coverity happy */)
+ ifindex = obj_old->link.ifindex;
+ else if ( cache_op == NMP_CACHE_OPS_UPDATED
+ && obj_old && obj_new /* <-- nonsensical, make coverity happy */
+ && !obj_new->_link.netlink.is_in_netlink
+ && obj_new->_link.netlink.is_in_netlink != obj_old->_link.netlink.is_in_netlink)
+ ifindex = obj_new->link.ifindex;
if (ifindex > 0) {
delayed_action_schedule (platform,
@@ -3511,40 +3402,40 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
* Currently, kernel misses to sent us a notification in this case
* (https://bugzilla.redhat.com/show_bug.cgi?id=1262908). */
- if ( ops_type == NMP_CACHE_OPS_REMOVED
- && old /* <-- nonsensical, make coverity happy */
- && old->_link.netlink.is_in_netlink)
- ifindex = old->link.ifindex;
- else if ( ops_type == NMP_CACHE_OPS_UPDATED
- && old && new /* <-- nonsensical, make coverity happy */
- && old->_link.netlink.is_in_netlink
- && !new->_link.netlink.is_in_netlink)
- ifindex = new->link.ifindex;
+ if ( cache_op == NMP_CACHE_OPS_REMOVED
+ && obj_old /* <-- nonsensical, make coverity happy */
+ && obj_old->_link.netlink.is_in_netlink)
+ ifindex = obj_old->link.ifindex;
+ else if ( cache_op == NMP_CACHE_OPS_UPDATED
+ && obj_old && obj_new /* <-- nonsensical, make coverity happy */
+ && obj_old->_link.netlink.is_in_netlink
+ && !obj_new->_link.netlink.is_in_netlink)
+ ifindex = obj_new->link.ifindex;
if (ifindex > 0) {
- const NMPlatformLink *const *links;
-
- links = cache_lookup_all_objects (NMPlatformLink, platform, NMP_OBJECT_TYPE_LINK, FALSE);
- if (links) {
- for (; *links; links++) {
- const NMPlatformLink *l = (*links);
-
- if (l->parent == ifindex)
- delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (l->ifindex));
- }
+ NMPLookup lookup;
+ NMDedupMultiIter iter;
+ const NMPlatformLink *l;
+
+ nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK);
+ nmp_cache_iter_for_each_link (&iter,
+ nmp_cache_lookup (cache, &lookup),
+ &l) {
+ if (l->parent == ifindex)
+ delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (l->ifindex));
}
}
}
{
/* if a link goes down, we must refresh routes */
- if ( ops_type == NMP_CACHE_OPS_UPDATED
- && old && new /* <-- nonsensical, make coverity happy */
- && old->_link.netlink.is_in_netlink
- && new->_link.netlink.is_in_netlink
- && ( ( NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_UP)
- && !NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_UP))
- || ( NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_LOWER_UP)
- && !NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_LOWER_UP)))) {
+ if ( cache_op == NMP_CACHE_OPS_UPDATED
+ && obj_old && obj_new /* <-- nonsensical, make coverity happy */
+ && obj_old->_link.netlink.is_in_netlink
+ && obj_new->_link.netlink.is_in_netlink
+ && ( ( NM_FLAGS_HAS (obj_old->link.n_ifi_flags, IFF_UP)
+ && !NM_FLAGS_HAS (obj_new->link.n_ifi_flags, IFF_UP))
+ || ( NM_FLAGS_HAS (obj_old->link.n_ifi_flags, IFF_LOWER_UP)
+ && !NM_FLAGS_HAS (obj_new->link.n_ifi_flags, IFF_LOWER_UP)))) {
/* FIXME: I suspect that IFF_LOWER_UP must not be considered, and I
* think kernel does send RTM_DELROUTE events for IPv6 routes, so
* we might not need to refresh IPv6 routes. */
@@ -3554,17 +3445,17 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
NULL);
}
}
- if ( NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED)
- && (new && new->_link.netlink.is_in_netlink)
- && (!old || !old->_link.netlink.is_in_netlink))
+ if ( NM_IN_SET (cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_UPDATED)
+ && (obj_new && obj_new->_link.netlink.is_in_netlink)
+ && (!obj_old || !obj_old->_link.netlink.is_in_netlink))
{
- if (!new->_link.netlink.lnk) {
+ if (!obj_new->_link.netlink.lnk) {
/* certain link-types also come with a IFLA_INFO_DATA/lnk_data. It may happen that
* kernel didn't send this notification, thus when we first learn about a link
* that lacks an lnk_data we re-request it again.
*
* For example https://bugzilla.redhat.com/show_bug.cgi?id=1284001 */
- switch (new->link.type) {
+ switch (obj_new->link.type) {
case NM_LINK_TYPE_GRE:
case NM_LINK_TYPE_IP6TNL:
case NM_LINK_TYPE_INFINIBAND:
@@ -3575,23 +3466,23 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
case NM_LINK_TYPE_VXLAN:
delayed_action_schedule (platform,
DELAYED_ACTION_TYPE_REFRESH_LINK,
- GINT_TO_POINTER (new->link.ifindex));
+ GINT_TO_POINTER (obj_new->link.ifindex));
break;
default:
break;
}
}
- if ( new->link.type == NM_LINK_TYPE_VETH
- && new->link.parent == 0) {
+ if ( obj_new->link.type == NM_LINK_TYPE_VETH
+ && obj_new->link.parent == 0) {
/* the initial notification when adding a veth pair can lack the parent/IFLA_LINK
* (https://bugzilla.redhat.com/show_bug.cgi?id=1285827).
* Request it again. */
delayed_action_schedule (platform,
DELAYED_ACTION_TYPE_REFRESH_LINK,
- GINT_TO_POINTER (new->link.ifindex));
+ GINT_TO_POINTER (obj_new->link.ifindex));
}
- if ( new->link.type == NM_LINK_TYPE_ETHERNET
- && new->link.addr.len == 0) {
+ if ( obj_new->link.type == NM_LINK_TYPE_ETHERNET
+ && obj_new->link.addr.len == 0) {
/* Due to a kernel bug, we sometimes receive spurious NEWLINK
* messages after a wifi interface has disappeared. Since the
* link is not present anymore we can't determine its type and
@@ -3601,7 +3492,7 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
*/
delayed_action_schedule (platform,
DELAYED_ACTION_TYPE_REFRESH_LINK,
- GINT_TO_POINTER (new->link.ifindex));
+ GINT_TO_POINTER (obj_new->link.ifindex));
}
}
{
@@ -3609,14 +3500,14 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
int ifindex1 = 0, ifindex2 = 0;
gboolean changed_master, changed_connected;
- changed_master = (new && new->_link.netlink.is_in_netlink && new->link.master > 0 ? new->link.master : 0)
- != (old && old->_link.netlink.is_in_netlink && old->link.master > 0 ? old->link.master : 0);
- changed_connected = (new && new->_link.netlink.is_in_netlink ? NM_FLAGS_HAS (new->link.n_ifi_flags, IFF_LOWER_UP) : 2)
- != (old && old->_link.netlink.is_in_netlink ? NM_FLAGS_HAS (old->link.n_ifi_flags, IFF_LOWER_UP) : 2);
+ changed_master = (obj_new && obj_new->_link.netlink.is_in_netlink && obj_new->link.master > 0 ? obj_new->link.master : 0)
+ != (obj_old && obj_old->_link.netlink.is_in_netlink && obj_old->link.master > 0 ? obj_old->link.master : 0);
+ changed_connected = (obj_new && obj_new->_link.netlink.is_in_netlink ? NM_FLAGS_HAS (obj_new->link.n_ifi_flags, IFF_LOWER_UP) : 2)
+ != (obj_old && obj_old->_link.netlink.is_in_netlink ? NM_FLAGS_HAS (obj_old->link.n_ifi_flags, IFF_LOWER_UP) : 2);
if (changed_master || changed_connected) {
- ifindex1 = (old && old->_link.netlink.is_in_netlink && old->link.master > 0) ? old->link.master : 0;
- ifindex2 = (new && new->_link.netlink.is_in_netlink && new->link.master > 0) ? new->link.master : 0;
+ ifindex1 = (obj_old && obj_old->_link.netlink.is_in_netlink && obj_old->link.master > 0) ? obj_old->link.master : 0;
+ ifindex2 = (obj_new && obj_new->_link.netlink.is_in_netlink && obj_new->link.master > 0) ? obj_new->link.master : 0;
if (ifindex1 > 0)
delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (ifindex1));
@@ -3625,19 +3516,19 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
}
}
{
- if ( ( (ops_type == NMP_CACHE_OPS_REMOVED)
- || ( (ops_type == NMP_CACHE_OPS_UPDATED)
- && new
- && !new->_link.netlink.is_in_netlink))
- && old
- && old->_link.netlink.is_in_netlink
- && old->link.master) {
+ if ( ( (cache_op == NMP_CACHE_OPS_REMOVED)
+ || ( (cache_op == NMP_CACHE_OPS_UPDATED)
+ && obj_new
+ && !obj_new->_link.netlink.is_in_netlink))
+ && obj_old
+ && obj_old->_link.netlink.is_in_netlink
+ && obj_old->link.master) {
/* sometimes we receive a wrong RTM_DELLINK message when unslaving
* a device. Refetch the link again to check whether the device
* is really gone.
*
* https://bugzilla.redhat.com/show_bug.cgi?id=1285719#c2 */
- delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (old->link.ifindex));
+ delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (obj_old->link.ifindex));
}
}
break;
@@ -3646,7 +3537,7 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
{
/* Address deletion is sometimes accompanied by route deletion. We need to
* check all routes belonging to the same interface. */
- if (ops_type == NMP_CACHE_OPS_REMOVED) {
+ if (cache_op == NMP_CACHE_OPS_REMOVED) {
delayed_action_schedule (platform,
(klass->obj_type == NMP_OBJECT_TYPE_IP4_ADDRESS)
? DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES
@@ -3664,14 +3555,10 @@ static void
cache_post (NMPlatform *platform,
struct nlmsghdr *msghdr,
NMPCacheOpsType cache_op,
- NMPObject *obj,
- NMPObject *obj_cache)
+ const NMPObject *obj,
+ const NMPObject *obj_old,
+ const NMPObject *obj_new)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
-
- nm_assert (NMP_OBJECT_IS_VALID (obj));
- nm_assert (!obj_cache || nmp_object_id_equal (obj, obj_cache));
-
if (msghdr->nlmsg_type == RTM_NEWROUTE) {
DelayedActionType action_type;
@@ -3679,7 +3566,7 @@ cache_post (NMPlatform *platform,
? DELAYED_ACTION_TYPE_REFRESH_ALL_IP4_ROUTES
: DELAYED_ACTION_TYPE_REFRESH_ALL_IP6_ROUTES;
if ( !delayed_action_refresh_all_in_progress (platform, action_type)
- && nmp_cache_find_other_route_for_same_destination (priv->cache, obj)) {
+ && nmp_cache_find_other_route_for_same_destination (nm_platform_get_cache (platform), obj)) {
/* via `iproute route change` the user can update an existing route which effectively
* means that a new object (with a different ID) comes into existance, replacing the
* old on. In other words, as the ID of the object changes, we really see a new
@@ -3739,8 +3626,13 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha
_LOGD ("do-request-link: %d %s", ifindex, name ? name : "");
if (ifindex > 0) {
- cache_prune_candidates_record_one (platform,
- (NMPObject *) nmp_cache_lookup_link (priv->cache, ifindex));
+ const NMDedupMultiEntry *entry;
+
+ entry = nmp_cache_lookup_entry_link (nm_platform_get_cache (platform), ifindex);
+ if (entry) {
+ priv->pruning[DELAYED_ACTION_IDX_REFRESH_ALL_LINKS] = TRUE;
+ nm_dedup_multi_entry_set_dirty (entry, TRUE);
+ }
}
event_handler_read_netlink (platform, FALSE);
@@ -3772,7 +3664,9 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio
action_type &= DELAYED_ACTION_TYPE_REFRESH_ALL;
FOR_EACH_DELAYED_ACTION (iflags, action_type) {
- cache_prune_candidates_record_all (platform, delayed_action_refresh_to_object_type (iflags));
+ priv->pruning[delayed_action_refresh_all_to_idx (iflags)] = TRUE;
+ nmp_cache_dirty_set_all (nm_platform_get_cache (platform),
+ delayed_action_refresh_to_object_type (iflags));
}
FOR_EACH_DELAYED_ACTION (iflags, action_type) {
@@ -3896,14 +3790,12 @@ event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResu
static void
event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_events)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
nm_auto_nmpobj NMPObject *obj = NULL;
- nm_auto_nmpobj NMPObject *obj_cache = NULL;
NMPCacheOpsType cache_op;
struct nlmsghdr *msghdr;
char buf_nlmsg_type[16];
gboolean id_only = FALSE;
- gboolean was_visible;
+ NMPCache *cache = nm_platform_get_cache (platform);
msghdr = nlmsg_hdr (msg);
@@ -3919,7 +3811,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
id_only = TRUE;
}
- obj = nmp_object_new_from_nl (platform, priv->cache, msg, id_only);
+ obj = nmp_object_new_from_nl (platform, cache, msg, id_only);
if (!obj) {
_LOGT ("event-notification: %s, seq %u: ignore",
_nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)),
@@ -3932,143 +3824,36 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
msghdr->nlmsg_seq, nmp_object_to_string (obj,
id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
- switch (msghdr->nlmsg_type) {
-
- case RTM_NEWLINK:
- case RTM_NEWADDR:
- case RTM_NEWROUTE:
- case RTM_GETLINK:
- cache_op = nmp_cache_update_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform);
-
- cache_post (platform, msghdr, cache_op, obj, obj_cache);
-
- do_emit_signal (platform, obj_cache, cache_op, was_visible);
- break;
-
- case RTM_DELLINK:
- case RTM_DELADDR:
- case RTM_DELROUTE:
- cache_op = nmp_cache_remove_netlink (priv->cache, obj, &obj_cache, &was_visible, cache_pre_hook, platform);
- do_emit_signal (platform, obj_cache, cache_op, was_visible);
- break;
-
- default:
- break;
- }
-
- cache_prune_candidates_drop (platform, obj_cache);
-}
-
-/*****************************************************************************/
-
-static const NMPObject *
-cache_lookup_link (NMPlatform *platform, int ifindex)
-{
- const NMPObject *obj_cache;
-
- obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
- if (!nmp_object_is_visible (obj_cache))
- return NULL;
-
- return obj_cache;
-}
-
-const NMPlatformObject *const*
-nm_linux_platform_lookup (NMPlatform *platform, const NMPCacheId *cache_id, guint *out_len)
-{
- g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), NULL);
- g_return_val_if_fail (cache_id, NULL);
-
- return nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
- cache_id, out_len);
-}
-
-static GArray *
-link_get_all (NMPlatform *platform)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- NMPCacheId cache_id;
-
- return nmp_cache_lookup_multi_to_array (priv->cache,
- NMP_OBJECT_TYPE_LINK,
- nmp_cache_id_init_object_type (&cache_id, NMP_OBJECT_TYPE_LINK, TRUE));
-}
-
-static const NMPlatformLink *
-_nm_platform_link_get (NMPlatform *platform, int ifindex)
-{
- const NMPObject *obj;
-
- obj = cache_lookup_link (platform, ifindex);
- return obj ? &obj->link : NULL;
-}
+ {
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
+
+ switch (msghdr->nlmsg_type) {
+
+ case RTM_NEWLINK:
+ case RTM_NEWADDR:
+ case RTM_NEWROUTE:
+ case RTM_GETLINK:
+ cache_op = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new);
+ cache_on_change (platform, cache_op, obj_old, obj_new);
+ cache_post (platform, msghdr, cache_op, obj, obj_old, obj_new);
+ nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
+ break;
-static const NMPlatformLink *
-_nm_platform_link_get_by_ifname (NMPlatform *platform,
- const char *ifname)
-{
- const NMPObject *obj = NULL;
+ case RTM_DELLINK:
+ case RTM_DELADDR:
+ case RTM_DELROUTE:
+ cache_op = nmp_cache_remove_netlink (cache, obj, &obj_old, &obj_new);
+ if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
+ cache_on_change (platform, cache_op, obj_old, obj_new);
+ nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
+ }
+ break;
- if (ifname && *ifname) {
- obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
- 0, ifname, TRUE, NM_LINK_TYPE_NONE, NULL, NULL);
+ default:
+ break;
+ }
}
- return obj ? &obj->link : NULL;
-}
-
-struct _nm_platform_link_get_by_address_data {
- gconstpointer address;
- guint8 length;
-};
-
-static gboolean
-_nm_platform_link_get_by_address_match_link (const NMPObject *obj, struct _nm_platform_link_get_by_address_data *d)
-{
- return obj->link.addr.len == d->length && !memcmp (obj->link.addr.data, d->address, d->length);
-}
-
-static const NMPlatformLink *
-_nm_platform_link_get_by_address (NMPlatform *platform,
- gconstpointer address,
- size_t length)
-{
- const NMPObject *obj;
- struct _nm_platform_link_get_by_address_data d = {
- .address = address,
- .length = length,
- };
-
- if (length <= 0 || length > NM_UTILS_HWADDR_LEN_MAX)
- return NULL;
- if (!address)
- return NULL;
-
- obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
- 0, NULL, TRUE, NM_LINK_TYPE_NONE,
- (NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link, &d);
- return obj ? &obj->link : NULL;
-}
-
-/*****************************************************************************/
-
-static const NMPObject *
-link_get_lnk (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link)
-{
- const NMPObject *obj = cache_lookup_link (platform, ifindex);
-
- if (!obj)
- return NULL;
-
- NM_SET_OUT (out_link, &obj->link);
-
- if (!obj->_link.netlink.lnk)
- return NULL;
- if ( link_type != NM_LINK_TYPE_NONE
- && ( link_type != obj->link.type
- || link_type != NMP_OBJECT_GET_CLASS (obj->_link.netlink.lnk)->lnk_link_type))
- return NULL;
-
- return obj->_link.netlink.lnk;
}
/*****************************************************************************/
@@ -4080,19 +3865,19 @@ do_add_link_with_lookup (NMPlatform *platform,
struct nl_msg *nlmsg,
const NMPlatformLink **out_link)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
const NMPObject *obj = NULL;
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
int nle;
char s_buf[256];
+ NMPCache *cache = nm_platform_get_cache (platform);
event_handler_read_netlink (platform, FALSE);
- if (nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) {
+ if (nmp_cache_lookup_link_full (cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) {
/* hm, a link with such a name already exists. Try reloading first. */
do_request_link (platform, 0, name);
- obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL);
+ obj = nmp_cache_lookup_link_full (cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL);
if (obj) {
_LOGE ("do-add-link[%s/%s]: link already exists: %s",
name,
@@ -4124,13 +3909,13 @@ do_add_link_with_lookup (NMPlatform *platform,
wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)));
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
- obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, link_type, NULL, NULL);
+ obj = nmp_cache_lookup_link_full (cache, 0, name, FALSE, link_type, NULL, NULL);
if (!obj) {
/* either kernel signaled failure, or it signaled success and the link object
* is not (yet) in the cache. Try to reload it... */
do_request_link (platform, 0, name);
- obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE, link_type, NULL, NULL);
+ obj = nmp_cache_lookup_link_full (cache, 0, name, FALSE, link_type, NULL, NULL);
}
if (out_link)
@@ -4141,11 +3926,11 @@ do_add_link_with_lookup (NMPlatform *platform,
static gboolean
do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
int nle;
char s_buf[256];
const NMPObject *obj;
+ NMPCache *cache = nm_platform_get_cache (platform);
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id),
NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS,
@@ -4183,10 +3968,10 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
* FIXME: if the object already existed previously, we might not notice a
* missing update. It's not clear how to fix that reliably without refechting
* all the time. */
- obj = nmp_cache_lookup_obj (priv->cache, obj_id);
+ obj = nmp_cache_lookup_obj (cache, obj_id);
if (!obj) {
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
- obj = nmp_cache_lookup_obj (priv->cache, obj_id);
+ obj = nmp_cache_lookup_obj (cache, obj_id);
}
/* Adding is only successful, if kernel reported success *and* we have the
@@ -4197,12 +3982,12 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
static gboolean
do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
int nle;
char s_buf[256];
gboolean success = TRUE;
const char *log_detail = "";
+ NMPCache *cache = nm_platform_get_cache (platform);
event_handler_read_netlink (platform, FALSE);
@@ -4241,13 +4026,13 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
log_detail);
out:
- if (!nmp_cache_lookup_obj (priv->cache, obj_id))
+ if (!nmp_cache_lookup_obj (cache, obj_id))
return TRUE;
/* such an object still exists in the cache. To be sure, refetch it (and
* hope it's gone) */
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
- return !!nmp_cache_lookup_obj (priv->cache, obj_id);
+ return !!nmp_cache_lookup_obj (cache, obj_id);
}
static WaitForNlResponseResult
@@ -4382,11 +4167,10 @@ static gboolean
link_delete (NMPlatform *platform, int ifindex)
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
NMPObject obj_id;
const NMPObject *obj;
- obj = nmp_cache_lookup_link (priv->cache, ifindex);
+ obj = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex);
if (!obj || !obj->_link.netlink.is_in_netlink)
return FALSE;
@@ -4401,56 +4185,11 @@ link_delete (NMPlatform *platform, int ifindex)
return do_delete_object (platform, &obj_id, nlmsg);
}
-static const char *
-link_get_type_name (NMPlatform *platform, int ifindex)
-{
- const NMPObject *obj = cache_lookup_link (platform, ifindex);
-
- if (!obj)
- return NULL;
-
- if (obj->link.type != NM_LINK_TYPE_UNKNOWN) {
- /* We could detect the @link_type. In this case the function returns
- * our internel module names, which differs from rtnl_link_get_type():
- * - NM_LINK_TYPE_INFINIBAND (gives "infiniband", instead of "ipoib")
- * - NM_LINK_TYPE_TAP (gives "tap", instead of "tun").
- * Note that this functions is only used by NMDeviceGeneric to
- * set type_description. */
- return nm_link_type_to_string (obj->link.type);
- }
- /* Link type not detected. Fallback to rtnl_link_get_type()/IFLA_INFO_KIND. */
- return obj->link.kind ?: "unknown";
-}
-
-static gboolean
-link_get_unmanaged (NMPlatform *platform, int ifindex, gboolean *unmanaged)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- const NMPObject *link;
- struct udev_device *udevice = NULL;
- const char *uproperty;
-
- link = nmp_cache_lookup_link (priv->cache, ifindex);
- if (!link)
- return FALSE;
-
- udevice = link->_link.udev.device;
- if (!udevice)
- return FALSE;
-
- uproperty = udev_device_get_property_value (udevice, "NM_UNMANAGED");
- if (!uproperty)
- return FALSE;
-
- *unmanaged = nm_udev_utils_property_as_boolean (uproperty);
- return TRUE;
-}
-
static gboolean
link_refresh (NMPlatform *platform, int ifindex)
{
do_request_link (platform, ifindex, NULL);
- return !!cache_lookup_link (platform, ifindex);
+ return !!nm_platform_link_get_obj (platform, ifindex, TRUE);
}
static gboolean
@@ -4537,7 +4276,7 @@ link_set_noarp (NMPlatform *platform, int ifindex)
static const char *
link_get_udi (NMPlatform *platform, int ifindex)
{
- const NMPObject *obj = cache_lookup_link (platform, ifindex);
+ const NMPObject *obj = nm_platform_link_get_obj (platform, ifindex, TRUE);
if ( !obj
|| !obj->_link.netlink.is_in_netlink
@@ -4546,20 +4285,6 @@ link_get_udi (NMPlatform *platform, int ifindex)
return udev_device_get_syspath (obj->_link.udev.device);
}
-static struct udev_device *
-link_get_udev_device (NMPlatform *platform, int ifindex)
-{
- const NMPObject *obj_cache;
-
- /* we don't use cache_lookup_link() because this would return NULL
- * if the link is not visible in libnl. For link_get_udev_device()
- * we want to return whatever we have, even if the link itself
- * appears invisible via other platform functions. */
-
- obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
- return obj_cache ? obj_cache->_link.udev.device : NULL;
-}
-
static NMPlatformError
link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled)
{
@@ -4624,7 +4349,7 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
nm_auto_pop_netns NMPNetns *netns = NULL;
const NMPObject *obj;
- obj = cache_lookup_link (platform, ifindex);
+ obj = nm_platform_link_get_obj (platform, ifindex, TRUE);
/* Only ARPHRD_ETHER links can possibly support VLANs. */
if (!obj || obj->link.arptype != ARPHRD_ETHER)
@@ -4694,7 +4419,7 @@ link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size
/* workaround ENFILE which may be wrongly returned (bgo #770456).
* If the MAC address is as expected, assume success? */
- obj_cache = nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex);
+ obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex);
if ( obj_cache
&& obj_cache->link.addr.len == length
&& memcmp (obj_cache->link.addr.data, address, length) == 0) {
@@ -5377,7 +5102,6 @@ link_vlan_change (NMPlatform *platform,
const NMVlanQosMapping *egress_map,
gsize n_egress_map)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
const NMPObject *obj_cache;
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
const NMPObjectLnkVlan *lnk;
@@ -5389,7 +5113,7 @@ link_vlan_change (NMPlatform *platform,
char s_ingress[256];
char s_egress[256];
- obj_cache = nmp_cache_lookup_link (priv->cache, ifindex);
+ obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex);
if ( !obj_cache
|| !obj_cache->_link.netlink.is_in_netlink) {
_LOGD ("link: change %d: %s: link does not exist", ifindex, "vlan");
@@ -5508,7 +5232,7 @@ tun_add (NMPlatform *platform, const char *name, gboolean tap,
return FALSE;
}
do_request_link (platform, 0, name);
- obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
+ obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform),
0, name, FALSE,
tap ? NM_LINK_TYPE_TAP : NM_LINK_TYPE_TUN,
NULL, NULL);
@@ -5558,7 +5282,6 @@ _infiniband_partition_action (NMPlatform *platform,
int p_key,
const NMPlatformLink **out_link)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
nm_auto_close int dirfd = -1;
char ifname_parent[IFNAMSIZ];
const NMPObject *obj;
@@ -5594,7 +5317,7 @@ _infiniband_partition_action (NMPlatform *platform,
if (action == INFINIBAND_ACTION_DELETE_CHILD)
return TRUE;
- obj = nmp_cache_lookup_link_full (priv->cache, 0, name, FALSE,
+ obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform), 0, name, FALSE,
NM_LINK_TYPE_INFINIBAND, NULL, NULL);
if (out_link)
*out_link = obj ? &obj->link : NULL;
@@ -5732,16 +5455,15 @@ wifi_indicate_addressing_running (NMPlatform *platform, int ifindex, gboolean ru
static gboolean
link_can_assume (NMPlatform *platform, int ifindex)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- NMPCacheId cache_id;
- const NMPlatformObject *const *objs;
- guint i, len;
- const NMPObject *link;
+ NMPLookup lookup;
+ const NMPObject *link, *o;
+ NMDedupMultiIter iter;
+ NMPCache *cache = nm_platform_get_cache (platform);
if (ifindex <= 0)
return FALSE;
- link = cache_lookup_link (platform, ifindex);
+ link = nm_platform_link_get_obj (platform, ifindex, TRUE);
if (!link)
return FALSE;
@@ -5751,21 +5473,21 @@ link_can_assume (NMPlatform *platform, int ifindex)
if (link->link.master > 0)
return TRUE;
- if (nmp_cache_lookup_multi (priv->cache,
- nmp_cache_id_init_addrroute_visible_by_ifindex (&cache_id, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex),
- NULL))
+ nmp_lookup_init_addrroute (&lookup,
+ NMP_OBJECT_TYPE_IP4_ADDRESS,
+ ifindex);
+ if (nmp_cache_lookup (cache, &lookup))
return TRUE;
- objs = nmp_cache_lookup_multi (priv->cache,
- nmp_cache_id_init_addrroute_visible_by_ifindex (&cache_id, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex),
- &len);
- if (objs) {
- for (i = 0; i < len; i++) {
- const NMPlatformIP6Address *a = (NMPlatformIP6Address *) objs[i];
-
- if (!IN6_IS_ADDR_LINKLOCAL (&a->address))
- return TRUE;
- }
+ nmp_lookup_init_addrroute (&lookup,
+ NMP_OBJECT_TYPE_IP6_ADDRESS,
+ ifindex);
+ nmp_cache_iter_for_each (&iter,
+ nmp_cache_lookup (cache, &lookup),
+ &o) {
+ nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_TYPE_IP6_ADDRESS);
+ if (!IN6_IS_ADDR_LINKLOCAL (&o->ip6_address.address))
+ return TRUE;
}
return FALSE;
}
@@ -5840,33 +5562,6 @@ link_get_driver_info (NMPlatform *platform,
/*****************************************************************************/
-static GArray *
-ipx_address_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- NMPCacheId cache_id;
-
- nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS));
-
- return nmp_cache_lookup_multi_to_array (priv->cache,
- obj_type,
- nmp_cache_id_init_addrroute_visible_by_ifindex (&cache_id,
- obj_type,
- ifindex));
-}
-
-static GArray *
-ip4_address_get_all (NMPlatform *platform, int ifindex)
-{
- return ipx_address_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ADDRESS);
-}
-
-static GArray *
-ip6_address_get_all (NMPlatform *platform, int ifindex)
-{
- return ipx_address_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS);
-}
-
static gboolean
ip4_address_add (NMPlatform *platform,
int ifindex,
@@ -5978,85 +5673,8 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, gui
return do_delete_object (platform, &obj_id, nlmsg);
}
-static const NMPlatformIP4Address *
-ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, guint8 plen, in_addr_t peer_address)
-{
- NMPObject obj_id;
- const NMPObject *obj;
-
- nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address);
- obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
- if (nmp_object_is_visible (obj))
- return &obj->ip4_address;
- return NULL;
-}
-
-static const NMPlatformIP6Address *
-ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr)
-{
- NMPObject obj_id;
- const NMPObject *obj;
-
- nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr);
- obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
- if (nmp_object_is_visible (obj))
- return &obj->ip6_address;
- return NULL;
-}
-
/*****************************************************************************/
-static GArray *
-ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- NMPCacheId cache_id;
- const NMPlatformIPRoute *const* routes;
- GArray *array;
- const NMPClass *klass;
- gboolean with_rtprot_kernel;
- guint i, len;
-
- nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
-
- if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
- flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT;
-
- klass = nmp_class_from_type (obj_type);
-
- nmp_cache_id_init_routes_visible (&cache_id,
- obj_type,
- NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT),
- NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT),
- ifindex);
-
- routes = (const NMPlatformIPRoute *const*) nmp_cache_lookup_multi (priv->cache, &cache_id, &len);
-
- array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len);
-
- with_rtprot_kernel = NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL);
- for (i = 0; i < len; i++) {
- nm_assert (NMP_OBJECT_GET_CLASS (NMP_OBJECT_UP_CAST (routes[i])) == klass);
-
- if ( with_rtprot_kernel
- || routes[i]->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
- g_array_append_vals (array, routes[i], 1);
- }
- return array;
-}
-
-static GArray *
-ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
-{
- return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags);
-}
-
-static GArray *
-ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
-{
- return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags);
-}
-
static guint32
ip_route_get_lock_flag (NMPlatformIPRoute *route)
{
@@ -6142,7 +5760,6 @@ ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route)
static gboolean
ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
NMPObject obj_id;
@@ -6151,6 +5768,8 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
if (metric == 0) {
+ NMPCache *cache = nm_platform_get_cache (platform);
+
/* Deleting an IPv4 route with metric 0 does not only delete an exectly matching route.
* If no route with metric 0 exists, it might delete another route to the same destination.
* For nm_platform_ip4_route_delete() we don't want this semantic.
@@ -6159,7 +5778,7 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
* delayed actions (including re-reading data from netlink). */
delayed_action_handle_all (platform, TRUE);
- if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) {
+ if (!nmp_cache_lookup_obj (cache, &obj_id)) {
/* hmm... we are about to delete an IP4 route with metric 0. We must only
* send the delete request if such a route really exists. Above we refreshed
* the platform cache, still no such route exists.
@@ -6174,7 +5793,7 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p
* additional expensive cache-resync. */
do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE);
- if (!nmp_cache_lookup_obj (priv->cache, &obj_id))
+ if (!nmp_cache_lookup_obj (cache, &obj_id))
return TRUE;
}
}
@@ -6245,34 +5864,6 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu
return do_delete_object (platform, &obj_id, nlmsg);
}
-static const NMPlatformIP4Route *
-ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric)
-{
- NMPObject obj_id;
- const NMPObject *obj;
-
- nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
- obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
- if (nmp_object_is_visible (obj))
- return &obj->ip4_route;
- return NULL;
-}
-
-static const NMPlatformIP6Route *
-ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric)
-{
- NMPObject obj_id;
- const NMPObject *obj;
-
- metric = nm_utils_ip6_route_metric_normalize (metric);
-
- nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
- obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
- if (nmp_object_is_visible (obj))
- return &obj->ip6_route;
- return NULL;
-}
-
/*****************************************************************************/
#define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI))
@@ -6633,19 +6224,19 @@ cache_update_link_udev (NMPlatform *platform,
int ifindex,
struct udev_device *udevice)
{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- nm_auto_nmpobj NMPObject *obj_cache = NULL;
- gboolean was_visible;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
+ nm_auto_nmpobj const NMPObject *obj_new = NULL;
NMPCacheOpsType cache_op;
- cache_op = nmp_cache_update_link_udev (priv->cache, ifindex, udevice, &obj_cache, &was_visible, cache_pre_hook, platform);
+ cache_op = nmp_cache_update_link_udev (nm_platform_get_cache (platform), ifindex, udevice, &obj_old, &obj_new);
if (cache_op != NMP_CACHE_OPS_UNCHANGED) {
nm_auto_pop_netns NMPNetns *netns = NULL;
+ cache_on_change (platform, cache_op, obj_old, obj_new);
if (!nm_platform_netns_push (platform, &netns))
return;
- do_emit_signal (platform, obj_cache, cache_op, was_visible);
+ nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new);
}
}
@@ -6701,7 +6292,7 @@ udev_device_removed (NMPlatform *platform,
if (ifindex <= 0) {
const NMPObject *obj;
- obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
+ obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform),
0, NULL, FALSE, NM_LINK_TYPE_NONE, _udev_device_removed_match_link, udevice);
if (obj)
ifindex = obj->link.ifindex;
@@ -6753,22 +6344,12 @@ static void
nm_linux_platform_init (NMLinuxPlatform *self)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (self);
- gboolean use_udev;
-
- use_udev = nmp_netns_is_initial ()
- && access ("/sys", W_OK) == 0;
priv->nlh_seq_next = 1;
- priv->cache = nmp_cache_new (use_udev);
priv->delayed_action.list_master_connected = g_ptr_array_new ();
priv->delayed_action.list_refresh_link = g_ptr_array_new ();
priv->delayed_action.list_wait_for_nl_response = g_array_new (FALSE, TRUE, sizeof (DelayedActionWaitForNlResponseData));
priv->wifi_data = g_hash_table_new_full (NULL, NULL, NULL, (GDestroyNotify) wifi_utils_deinit);
-
- if (use_udev) {
- priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL },
- handle_udev_event, self);
- }
}
static void
@@ -6782,6 +6363,11 @@ constructed (GObject *_object)
nm_assert (!platform->_netns || platform->_netns == nmp_netns_get_current ());
+ if (nm_platform_get_use_udev (platform)) {
+ priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL },
+ handle_udev_event, platform);
+ }
+
_LOGD ("create (%s netns, %s, %s udev)",
!platform->_netns ? "ignore" : "use",
!platform->_netns && nmp_netns_is_initial ()
@@ -6791,7 +6377,7 @@ constructed (GObject *_object)
: nm_sprintf_bufa (100, "in netns[%p]%s",
nmp_netns_get_current (),
nmp_netns_get_current () == nmp_netns_get_initial () ? "/main" : "")),
- nmp_cache_use_udev_get (priv->cache) ? "use" : "no");
+ nm_platform_get_use_udev (platform) ? "use" : "no");
priv->nlh = nl_socket_alloc ();
g_assert (priv->nlh);
@@ -6892,8 +6478,6 @@ dispose (GObject *object)
g_ptr_array_set_size (priv->delayed_action.list_master_connected, 0);
g_ptr_array_set_size (priv->delayed_action.list_refresh_link, 0);
- g_clear_pointer (&priv->prune_candidates, g_hash_table_unref);
-
G_OBJECT_CLASS (nm_linux_platform_parent_class)->dispose (object);
}
@@ -6902,8 +6486,6 @@ finalize (GObject *object)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (object);
- nmp_cache_free (priv->cache);
-
g_ptr_array_unref (priv->delayed_action.list_master_connected);
g_ptr_array_unref (priv->delayed_action.list_refresh_link);
g_array_unref (priv->delayed_action.list_wait_for_nl_response);
@@ -6937,16 +6519,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->sysctl_set = sysctl_set;
platform_class->sysctl_get = sysctl_get;
- platform_class->link_get = _nm_platform_link_get;
- platform_class->link_get_by_ifname = _nm_platform_link_get_by_ifname;
- platform_class->link_get_by_address = _nm_platform_link_get_by_address;
- platform_class->link_get_all = link_get_all;
platform_class->link_add = link_add;
platform_class->link_delete = link_delete;
- platform_class->link_get_type_name = link_get_type_name;
- platform_class->link_get_unmanaged = link_get_unmanaged;
-
- platform_class->link_get_lnk = link_get_lnk;
platform_class->link_refresh = link_refresh;
@@ -6958,7 +6532,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_set_noarp = link_set_noarp;
platform_class->link_get_udi = link_get_udi;
- platform_class->link_get_udev_device = link_get_udev_device;
platform_class->link_set_user_ipv6ll_enabled = link_set_user_ipv6ll_enabled;
platform_class->link_set_token = link_set_token;
@@ -7013,19 +6586,11 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_ipip_add = link_ipip_add;
platform_class->link_sit_add = link_sit_add;
- platform_class->ip4_address_get = ip4_address_get;
- platform_class->ip6_address_get = ip6_address_get;
- platform_class->ip4_address_get_all = ip4_address_get_all;
- platform_class->ip6_address_get_all = ip6_address_get_all;
platform_class->ip4_address_add = ip4_address_add;
platform_class->ip6_address_add = ip6_address_add;
platform_class->ip4_address_delete = ip4_address_delete;
platform_class->ip6_address_delete = ip6_address_delete;
- platform_class->ip4_route_get = ip4_route_get;
- platform_class->ip6_route_get = ip6_route_get;
- platform_class->ip4_route_get_all = ip4_route_get_all;
- platform_class->ip6_route_get_all = ip6_route_get_all;
platform_class->ip4_route_add = ip4_route_add;
platform_class->ip6_route_add = ip6_route_add;
platform_class->ip4_route_delete = ip4_route_delete;
diff --git a/src/platform/nm-linux-platform.h b/src/platform/nm-linux-platform.h
index 6b66ea699c..bff6c00cc7 100644
--- a/src/platform/nm-linux-platform.h
+++ b/src/platform/nm-linux-platform.h
@@ -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__ */
diff --git a/src/platform/nm-platform-private.h b/src/platform/nm-platform-private.h
new file mode 100644
index 0000000000..b6c94baaf7
--- /dev/null
+++ b/src/platform/nm-platform-private.h
@@ -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__ */
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index 7f12fb743b..176f377bdb 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -32,12 +32,16 @@
#include <linux/if_tun.h>
#include <linux/if_tunnel.h>
#include <linux/rtnetlink.h>
+#include <libudev.h>
#include "nm-utils.h"
#include "nm-core-internal.h"
+#include "nm-utils/nm-dedup-multi.h"
+#include "nm-utils/nm-udev-utils.h"
#include "nm-core-utils.h"
#include "nm-platform-utils.h"
+#include "nm-platform-private.h"
#include "nmp-object.h"
#include "nmp-netns.h"
@@ -79,12 +83,16 @@ static guint signals[_NM_PLATFORM_SIGNAL_ID_LAST] = { 0 };
enum {
PROP_0,
PROP_NETNS_SUPPORT,
+ PROP_USE_UDEV,
PROP_LOG_WITH_PTR,
LAST_PROP,
};
typedef struct _NMPlatformPrivate {
+ bool use_udev:1;
bool log_with_ptr:1;
+ NMDedupMultiIndex *multi_idx;
+ NMPCache *cache;
} NMPlatformPrivate;
G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT)
@@ -94,6 +102,12 @@ G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT)
/*****************************************************************************/
gboolean
+nm_platform_get_use_udev (NMPlatform *self)
+{
+ return NM_PLATFORM_GET_PRIVATE (self)->use_udev;
+}
+
+gboolean
nm_platform_get_log_with_ptr (NMPlatform *self)
{
return NM_PLATFORM_GET_PRIVATE (self)->log_with_ptr;
@@ -193,6 +207,16 @@ nm_platform_get ()
/*****************************************************************************/
+NMDedupMultiIndex *
+nm_platform_get_multi_idx (NMPlatform *self)
+{
+ g_return_val_if_fail (NM_IS_PLATFORM (self), NULL);
+
+ return NM_PLATFORM_GET_PRIVATE (self)->multi_idx;
+}
+
+/*****************************************************************************/
+
/**
* _nm_platform_error_to_string:
* @error_code: the error code to stringify.
@@ -440,8 +464,8 @@ _link_get_all_presort (gconstpointer p_a,
gconstpointer p_b,
gpointer sort_by_name)
{
- const NMPlatformLink *a = p_a;
- const NMPlatformLink *b = p_b;
+ const NMPlatformLink *a = NMP_OBJECT_CAST_LINK (*((const NMPObject **) p_a));
+ const NMPlatformLink *b = NMP_OBJECT_CAST_LINK (*((const NMPObject **) p_b));
/* Loopback always first */
if (a->ifindex == 1)
@@ -463,43 +487,56 @@ _link_get_all_presort (gconstpointer p_a,
/**
* nm_platform_link_get_all:
- * self: platform instance
+ * @self: platform instance
+ * @sort_by_name: whether to sort by name or ifindex.
*
* Retrieve a snapshot of configuration for all links at once. The result is
- * owned by the caller and should be freed with g_array_unref().
+ * owned by the caller and should be freed with g_ptr_array_unref().
*/
-GArray *
+GPtrArray *
nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name)
{
- GArray *links, *result;
- guint i, j, nresult;
- GHashTable *unseen;
- NMPlatformLink *item;
+ gs_unref_ptrarray GPtrArray *links = NULL;
+ GPtrArray *result;
+ guint i, nresult;
+ gs_unref_hashtable GHashTable *unseen = NULL;
+ const NMPlatformLink *item;
+ NMPLookup lookup;
_CHECK_SELF (self, klass, NULL);
- links = klass->link_get_all (self);
+ nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK);
+ links = nm_dedup_multi_objs_to_ptr_array_head (nm_platform_lookup (self, &lookup),
+ NULL, NULL);
+ if (!links)
+ return NULL;
- if (!links || links->len == 0)
- return links;
+ for (i = 0; i < links->len; ) {
+ if (!nmp_object_is_visible (links->pdata[i]))
+ g_ptr_array_remove_index_fast (links, i);
+ else
+ i++;
+ }
+
+ if (links->len == 0)
+ return NULL;
/* first sort the links by their ifindex or name. Below we will sort
* further by moving children/slaves to the end. */
- g_array_sort_with_data (links, _link_get_all_presort, GINT_TO_POINTER (sort_by_name));
+ g_ptr_array_sort_with_data (links, _link_get_all_presort, GINT_TO_POINTER (sort_by_name));
unseen = g_hash_table_new (g_direct_hash, g_direct_equal);
for (i = 0; i < links->len; i++) {
- item = &g_array_index (links, NMPlatformLink, i);
-
+ item = NMP_OBJECT_CAST_LINK (links->pdata[i]);
nm_assert (item->ifindex > 0);
if (!nm_g_hash_table_insert (unseen, GINT_TO_POINTER (item->ifindex), NULL))
nm_assert_not_reached ();
}
-#ifndef G_DISABLE_ASSERT
+#if NM_MORE_ASSERTS
/* Ensure that link_get_all returns a consistent and valid result. */
for (i = 0; i < links->len; i++) {
- item = &g_array_index (links, NMPlatformLink, i);
+ item = NMP_OBJECT_CAST_LINK (links->pdata[i]);
if (!item->ifindex)
continue;
@@ -519,54 +556,75 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name)
#endif
/* Re-order the links list such that children/slaves come after all ancestors */
- nresult = g_hash_table_size (unseen);
- result = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformLink), nresult);
- g_array_set_size (result, nresult);
+ nm_assert (g_hash_table_size (unseen) == links->len);
+ nresult = links->len;
+ result = g_ptr_array_new_full (nresult, (GDestroyNotify) nmp_object_unref);
- j = 0;
- do {
+ while (TRUE) {
gboolean found_something = FALSE;
guint first_idx = G_MAXUINT;
for (i = 0; i < links->len; i++) {
- item = &g_array_index (links, NMPlatformLink, i);
+ item = NMP_OBJECT_CAST_LINK (links->pdata[i]);
- if (!item->ifindex)
+ if (!item)
continue;
- if (first_idx == G_MAXUINT)
- first_idx = i;
-
g_assert (g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex)));
if (item->master > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->master)))
- continue;
+ goto skip;
if (item->parent > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)))
- continue;
+ goto skip;
g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex));
- g_array_index (result, NMPlatformLink, j++) = *item;
- item->ifindex = 0;
+ g_ptr_array_add (result, links->pdata[i]);
+ links->pdata[i] = NULL;
found_something = TRUE;
+ continue;
+skip:
+ if (first_idx == G_MAXUINT)
+ first_idx = i;
}
- if (!found_something) {
+ if (found_something) {
+ if (first_idx == G_MAXUINT)
+ break;
+ } else {
+ nm_assert (first_idx != G_MAXUINT);
/* There is a loop, pop the first (remaining) element from the list.
* This can happen for veth pairs where each peer is parent of the other end. */
- item = &g_array_index (links, NMPlatformLink, first_idx);
-
+ item = NMP_OBJECT_CAST_LINK (links->pdata[first_idx]);
g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex));
- g_array_index (result, NMPlatformLink, j++) = *item;
- item->ifindex = 0;
+ g_ptr_array_add (result, links->pdata[first_idx]);
+ links->pdata[first_idx] = NULL;
}
- } while (j < nresult);
-
- g_hash_table_destroy (unseen);
- g_array_free (links, TRUE);
+ nm_assert (result->len < nresult);
+ }
+ nm_assert (result->len == nresult);
return result;
}
+/*****************************************************************************/
+
+const NMPObject *
+nm_platform_link_get_obj (NMPlatform *self,
+ int ifindex,
+ gboolean visible_only)
+{
+ const NMPObject *obj_cache;
+
+ obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (self), ifindex);
+ if ( !obj_cache
+ || ( visible_only
+ && !nmp_object_is_visible (obj_cache)))
+ return NULL;
+ return obj_cache;
+}
+
+/*****************************************************************************/
+
/**
* nm_platform_link_get:
* @self: platform instance
@@ -582,11 +640,15 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name)
const NMPlatformLink *
nm_platform_link_get (NMPlatform *self, int ifindex)
{
+ const NMPObject *obj;
+
_CHECK_SELF (self, klass, NULL);
- if (ifindex > 0)
- return klass->link_get (self, ifindex);
- return NULL;
+ if (ifindex <= 0)
+ return NULL;
+
+ obj = nm_platform_link_get_obj (self, ifindex, TRUE);
+ return NMP_OBJECT_CAST_LINK (obj);
}
/**
@@ -599,11 +661,27 @@ nm_platform_link_get (NMPlatform *self, int ifindex)
const NMPlatformLink *
nm_platform_link_get_by_ifname (NMPlatform *self, const char *ifname)
{
+ const NMPObject *obj;
+
_CHECK_SELF (self, klass, NULL);
- if (ifname && *ifname)
- return klass->link_get_by_ifname (self, ifname);
- return NULL;
+ if (!ifname || !*ifname)
+ return NULL;
+
+ obj = nmp_cache_lookup_link_full (nm_platform_get_cache (self),
+ 0, ifname, TRUE, NM_LINK_TYPE_NONE, NULL, NULL);
+ return NMP_OBJECT_CAST_LINK (obj);
+}
+
+struct _nm_platform_link_get_by_address_data {
+ gconstpointer address;
+ guint8 length;
+};
+
+static gboolean
+_nm_platform_link_get_by_address_match_link (const NMPObject *obj, struct _nm_platform_link_get_by_address_data *d)
+{
+ return obj->link.addr.len == d->length && !memcmp (obj->link.addr.data, d->address, d->length);
}
/**
@@ -620,15 +698,26 @@ nm_platform_link_get_by_address (NMPlatform *self,
gconstpointer address,
size_t length)
{
+ const NMPObject *obj;
+ struct _nm_platform_link_get_by_address_data d = {
+ .address = address,
+ .length = length,
+ };
+
_CHECK_SELF (self, klass, NULL);
- g_return_val_if_fail (length == 0 || address, NULL);
- if (length > 0) {
- if (length > NM_UTILS_HWADDR_LEN_MAX)
- g_return_val_if_reached (NULL);
- return klass->link_get_by_address (self, address, length);
- }
- return NULL;
+ if (length == 0)
+ return NULL;
+
+ if (length > NM_UTILS_HWADDR_LEN_MAX)
+ g_return_val_if_reached (NULL);
+ if (!address)
+ g_return_val_if_reached (NULL);
+
+ obj = nmp_cache_lookup_link_full (nm_platform_get_cache (self),
+ 0, NULL, TRUE, NM_LINK_TYPE_NONE,
+ (NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link, &d);
+ return NMP_OBJECT_CAST_LINK (obj);
}
static NMPlatformError
@@ -858,9 +947,26 @@ nm_platform_link_get_type (NMPlatform *self, int ifindex)
const char *
nm_platform_link_get_type_name (NMPlatform *self, int ifindex)
{
+ const NMPObject *obj;
+
_CHECK_SELF (self, klass, NULL);
- return klass->link_get_type_name (self, ifindex);
+ obj = nm_platform_link_get_obj (self, ifindex, TRUE);
+
+ if (!obj)
+ return NULL;
+
+ if (obj->link.type != NM_LINK_TYPE_UNKNOWN) {
+ /* We could detect the @link_type. In this case the function returns
+ * our internel module names, which differs from rtnl_link_get_type():
+ * - NM_LINK_TYPE_INFINIBAND (gives "infiniband", instead of "ipoib")
+ * - NM_LINK_TYPE_TAP (gives "tap", instead of "tun").
+ * Note that this functions is only used by NMDeviceGeneric to
+ * set type_description. */
+ return nm_link_type_to_string (obj->link.type);
+ }
+ /* Link type not detected. Fallback to rtnl_link_get_type()/IFLA_INFO_KIND. */
+ return obj->link.kind ?: "unknown";
}
/**
@@ -875,11 +981,26 @@ nm_platform_link_get_type_name (NMPlatform *self, int ifindex)
gboolean
nm_platform_link_get_unmanaged (NMPlatform *self, int ifindex, gboolean *unmanaged)
{
+ const NMPObject *link;
+ struct udev_device *udevice = NULL;
+ const char *uproperty;
+
_CHECK_SELF (self, klass, FALSE);
- if (klass->link_get_unmanaged)
- return klass->link_get_unmanaged (self, ifindex, unmanaged);
- return FALSE;
+ link = nmp_cache_lookup_link (nm_platform_get_cache (self), ifindex);
+ if (!link)
+ return FALSE;
+
+ udevice = link->_link.udev.device;
+ if (!udevice)
+ return FALSE;
+
+ uproperty = udev_device_get_property_value (udevice, "NM_UNMANAGED");
+ if (!uproperty)
+ return FALSE;
+
+ *unmanaged = nm_udev_utils_property_as_boolean (uproperty);
+ return TRUE;
}
/**
@@ -1025,13 +1146,14 @@ nm_platform_link_get_udi (NMPlatform *self, int ifindex)
struct udev_device *
nm_platform_link_get_udev_device (NMPlatform *self, int ifindex)
{
+ const NMPObject *obj_cache;
+
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex >= 0, NULL);
- if (klass->link_get_udev_device)
- return klass->link_get_udev_device (self, ifindex);
- return NULL;
+ obj_cache = nm_platform_link_get_obj (self, ifindex, FALSE);
+ return obj_cache ? obj_cache->_link.udev.device : NULL;
}
/**
@@ -1531,13 +1653,28 @@ nm_platform_link_can_assume (NMPlatform *self, int ifindex)
const NMPObject *
nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link)
{
+ const NMPObject *obj;
+
_CHECK_SELF (self, klass, FALSE);
NM_SET_OUT (out_link, NULL);
g_return_val_if_fail (ifindex > 0, NULL);
- return klass->link_get_lnk (self, ifindex, link_type, out_link);
+ obj = nm_platform_link_get_obj (self, ifindex, TRUE);
+ if (!obj)
+ return NULL;
+
+ NM_SET_OUT (out_link, &obj->link);
+
+ if (!obj->_link.netlink.lnk)
+ return NULL;
+ if ( link_type != NM_LINK_TYPE_NONE
+ && ( link_type != obj->link.type
+ || link_type != NMP_OBJECT_GET_CLASS (obj->_link.netlink.lnk)->lnk_link_type))
+ return NULL;
+
+ return obj->_link.netlink.lnk;
}
static gconstpointer
@@ -2629,6 +2766,52 @@ nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *
/*****************************************************************************/
+const NMDedupMultiHeadEntry *
+nm_platform_lookup (NMPlatform *self,
+ const NMPLookup *lookup)
+{
+ return nmp_cache_lookup (nm_platform_get_cache (self),
+ lookup);
+}
+
+gboolean
+nm_platform_lookup_predicate_routes_skip_rtprot_kernel (const NMPObject *obj,
+ gpointer user_data)
+{
+ nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
+ NMP_OBJECT_TYPE_IP6_ROUTE));
+ return obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
+}
+
+/**
+ * nm_platform_lookup_clone:
+ * @self:
+ * @lookup:
+ * @predicate: if given, only objects for which @predicate returns %TRUE are included
+ * in the result.
+ * @user_data: user data for @predicate
+ *
+ * Returns the result of lookup in a GPtrArray. The result array contains
+ * references objects from the cache, it's destroy function will unref them.
+ *
+ * The user must unref the GPtrArray, which will also unref the NMPObject
+ * elements.
+ *
+ * The elements in the array *must* not be modified.
+ *
+ * Returns: the result of the lookup.
+ */
+GPtrArray *
+nm_platform_lookup_clone (NMPlatform *self,
+ const NMPLookup *lookup,
+ gboolean (*predicate) (const NMPObject *obj, gpointer user_data),
+ gpointer user_data)
+{
+ return nm_dedup_multi_objs_to_ptr_array_head (nm_platform_lookup (self, lookup),
+ (NMDedupMultiFcnSelectPredicate) predicate,
+ user_data);
+}
+
void
nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, guint8 plen)
{
@@ -2648,6 +2831,20 @@ nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr)
return &addr->peer_address;
}
+static GArray *
+ipx_address_get_all (NMPlatform *self, int ifindex, NMPObjectType obj_type)
+{
+ NMPLookup lookup;
+
+ nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS));
+ nmp_lookup_init_addrroute (&lookup,
+ obj_type,
+ ifindex);
+ return nmp_cache_lookup_to_array (nmp_cache_lookup (nm_platform_get_cache (self), &lookup),
+ obj_type,
+ FALSE /*addresses are always visible. */);
+}
+
GArray *
nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex)
{
@@ -2655,7 +2852,7 @@ nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex)
g_return_val_if_fail (ifindex > 0, NULL);
- return klass->ip4_address_get_all (self, ifindex);
+ return ipx_address_get_all (self, ifindex, NMP_OBJECT_TYPE_IP4_ADDRESS);
}
GArray *
@@ -2665,7 +2862,7 @@ nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex)
g_return_val_if_fail (ifindex > 0, NULL);
- return klass->ip6_address_get_all (self, ifindex);
+ return ipx_address_get_all (self, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS);
}
gboolean
@@ -2780,19 +2977,31 @@ nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr a
const NMPlatformIP4Address *
nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, guint8 plen, guint32 peer_address)
{
+ NMPObject obj_id;
+ const NMPObject *obj;
+
_CHECK_SELF (self, klass, NULL);
g_return_val_if_fail (plen <= 32, NULL);
- return klass->ip4_address_get (self, ifindex, address, plen, peer_address);
+ nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, address, plen, peer_address);
+ obj = nmp_cache_lookup_obj (nm_platform_get_cache (self), &obj_id);
+ nm_assert (!obj || nmp_object_is_visible (obj));
+ return NMP_OBJECT_CAST_IP4_ADDRESS (obj);
}
const NMPlatformIP6Address *
nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address)
{
+ NMPObject obj_id;
+ const NMPObject *obj;
+
_CHECK_SELF (self, klass, NULL);
- return klass->ip6_address_get (self, ifindex, address);
+ nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &address);
+ obj = nmp_cache_lookup_obj (nm_platform_get_cache (self), &obj_id);
+ nm_assert (!obj || nmp_object_is_visible (obj));
+ return NMP_OBJECT_CAST_IP6_ADDRESS (obj);
}
static const NMPlatformIP4Address *
@@ -3130,26 +3339,6 @@ nm_platform_address_flush (NMPlatform *self, int ifindex)
/*****************************************************************************/
-GArray *
-nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags)
-{
- _CHECK_SELF (self, klass, NULL);
-
- g_return_val_if_fail (ifindex >= 0, NULL);
-
- return klass->ip4_route_get_all (self, ifindex, flags);
-}
-
-GArray *
-nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags)
-{
- _CHECK_SELF (self, klass, NULL);
-
- g_return_val_if_fail (ifindex >= 0, NULL);
-
- return klass->ip6_route_get_all (self, ifindex, flags);
-}
-
/**
* nm_platform_ip4_route_add:
* @self:
@@ -3228,17 +3417,33 @@ nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr net
const NMPlatformIP4Route *
nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric)
{
+ NMPObject obj_id;
+ const NMPObject *obj;
+
_CHECK_SELF (self, klass, FALSE);
- return klass->ip4_route_get (self ,ifindex, network, plen, metric);
+ nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
+ obj = nmp_cache_lookup_obj (nm_platform_get_cache (self), &obj_id);
+ if (nmp_object_is_visible (obj))
+ return &obj->ip4_route;
+ return NULL;
}
const NMPlatformIP6Route *
nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric)
{
+ NMPObject obj_id;
+ const NMPObject *obj;
+
_CHECK_SELF (self, klass, FALSE);
- return klass->ip6_route_get (self, ifindex, network, plen, metric);
+ metric = nm_utils_ip6_route_metric_normalize (metric);
+
+ nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
+ obj = nmp_cache_lookup_obj (nm_platform_get_cache (self), &obj_id);
+ if (nmp_object_is_visible (obj))
+ return &obj->ip6_route;
+ return NULL;
}
/*****************************************************************************/
@@ -4130,6 +4335,39 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsi
return c < 0 ? -1 : 1; \
} G_STMT_END
+guint
+nm_platform_link_hash (const NMPlatformLink *obj)
+{
+ guint h = 99413953;
+ guint8 i8;
+
+ h = NM_HASH_COMBINE (h, obj->ifindex);
+ h = NM_HASH_COMBINE (h, obj->type);
+ h = NM_HASH_COMBINE (h, g_str_hash (obj->name));
+ h = NM_HASH_COMBINE (h, obj->master);
+ h = NM_HASH_COMBINE (h, obj->parent);
+ h = NM_HASH_COMBINE (h, obj->n_ifi_flags);
+ h = NM_HASH_COMBINE (h, obj->connected);
+ h = NM_HASH_COMBINE (h, obj->mtu);
+ h = NM_HASH_COMBINE (h, !!obj->initialized);
+ h = NM_HASH_COMBINE (h, obj->arptype);
+ h = NM_HASH_COMBINE (h, obj->addr.len);
+ h = NM_HASH_COMBINE (h, obj->inet6_addr_gen_mode_inv);
+ if (obj->kind)
+ h = NM_HASH_COMBINE (h, g_str_hash (obj->kind));
+ if (obj->driver)
+ h = NM_HASH_COMBINE (h, g_str_hash (obj->driver));
+ for (i8 = 0; i8 < obj->addr.len; i8++)
+ h = NM_HASH_COMBINE (h, obj->addr.data[i8]);
+ for (i8 = 0; i8 < sizeof (obj->inet6_token); i8++)
+ h = NM_HASH_COMBINE (h, obj->inet6_token.id_u8[i8]);
+ h = NM_HASH_COMBINE (h, obj->rx_packets);
+ h = NM_HASH_COMBINE (h, obj->rx_bytes);
+ h = NM_HASH_COMBINE (h, obj->tx_packets);
+ h = NM_HASH_COMBINE (h, obj->tx_bytes);
+ return h;
+}
+
int
nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
{
@@ -4158,6 +4396,24 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
return 0;
}
+guint
+nm_platform_lnk_gre_hash (const NMPlatformLnkGre *obj)
+{
+ guint h = 1887023311;
+
+ h = NM_HASH_COMBINE (h, obj->parent_ifindex);
+ h = NM_HASH_COMBINE (h, obj->input_flags);
+ h = NM_HASH_COMBINE (h, obj->output_flags);
+ h = NM_HASH_COMBINE (h, obj->input_key);
+ h = NM_HASH_COMBINE (h, obj->output_key);
+ h = NM_HASH_COMBINE (h, obj->local);
+ h = NM_HASH_COMBINE (h, obj->remote);
+ h = NM_HASH_COMBINE (h, obj->ttl);
+ h = NM_HASH_COMBINE (h, obj->tos);
+ h = NM_HASH_COMBINE (h, !obj->path_mtu_discovery);
+ return h;
+}
+
int
nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b)
{
@@ -4175,6 +4431,17 @@ nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b)
return 0;
}
+guint
+nm_platform_lnk_infiniband_hash (const NMPlatformLnkInfiniband *obj)
+{
+ guint h = 1748638583;
+
+ h = NM_HASH_COMBINE (h, obj->p_key);
+ if (obj->mode)
+ h = NM_HASH_COMBINE (h, g_str_hash (obj->mode));
+ return h;
+}
+
int
nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b)
{
@@ -4184,6 +4451,22 @@ nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatfo
return 0;
}
+guint
+nm_platform_lnk_ip6tnl_hash (const NMPlatformLnkIp6Tnl *obj)
+{
+ guint h = 1651660009;
+
+ h = NM_HASH_COMBINE (h, obj->parent_ifindex);
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->local));
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->remote));
+ h = NM_HASH_COMBINE (h, obj->ttl);
+ h = NM_HASH_COMBINE (h, obj->tclass);
+ h = NM_HASH_COMBINE (h, obj->encap_limit);
+ h = NM_HASH_COMBINE (h, obj->flow_label);
+ h = NM_HASH_COMBINE (h, obj->proto);
+ return h;
+}
+
int
nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6Tnl *b)
{
@@ -4199,6 +4482,20 @@ nm_platform_lnk_ip6tnl_cmp (const NMPlatformLnkIp6Tnl *a, const NMPlatformLnkIp6
return 0;
}
+guint
+nm_platform_lnk_ipip_hash (const NMPlatformLnkIpIp *obj)
+{
+ guint h = 861934429;
+
+ h = NM_HASH_COMBINE (h, obj->parent_ifindex);
+ h = NM_HASH_COMBINE (h, obj->local);
+ h = NM_HASH_COMBINE (h, obj->remote);
+ h = NM_HASH_COMBINE (h, obj->ttl);
+ h = NM_HASH_COMBINE (h, obj->tos);
+ h = NM_HASH_COMBINE (h, obj->path_mtu_discovery);
+ return h;
+}
+
int
nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b)
{
@@ -4212,6 +4509,26 @@ nm_platform_lnk_ipip_cmp (const NMPlatformLnkIpIp *a, const NMPlatformLnkIpIp *b
return 0;
}
+guint
+nm_platform_lnk_macsec_hash (const NMPlatformLnkMacsec *obj)
+{
+ guint h = 226984267;
+
+ h = NM_HASH_COMBINE (h, obj->sci);
+ h = NM_HASH_COMBINE_UINT64 (h, obj->icv_length);
+ h = NM_HASH_COMBINE_UINT64 (h, obj->cipher_suite);
+ h = NM_HASH_COMBINE (h, obj->window);
+ h = NM_HASH_COMBINE (h, obj->encoding_sa);
+ h = NM_HASH_COMBINE (h, obj->validation);
+ h = NM_HASH_COMBINE (h, obj->encrypt);
+ h = NM_HASH_COMBINE (h, obj->protect);
+ h = NM_HASH_COMBINE (h, obj->include_sci);
+ h = NM_HASH_COMBINE (h, obj->es);
+ h = NM_HASH_COMBINE (h, obj->scb);
+ h = NM_HASH_COMBINE (h, obj->replay_protect);
+ return h;
+}
+
int
nm_platform_lnk_macsec_cmp (const NMPlatformLnkMacsec *a, const NMPlatformLnkMacsec *b)
{
@@ -4231,15 +4548,43 @@ nm_platform_lnk_macsec_cmp (const NMPlatformLnkMacsec *a, const NMPlatformLnkMac
return 0;
}
+guint
+nm_platform_lnk_macvlan_hash (const NMPlatformLnkMacvlan *obj)
+{
+ guint h = 771014989;
+
+ h = NM_HASH_COMBINE (h, obj->mode);
+ h = NM_HASH_COMBINE (h, obj->no_promisc);
+ h = NM_HASH_COMBINE (h, obj->tap);
+ return h;
+}
+
int
nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b)
{
_CMP_SELF (a, b);
_CMP_FIELD (a, b, mode);
- _CMP_FIELD_BOOL (a, b, no_promisc);
+ _CMP_FIELD (a, b, no_promisc);
+ _CMP_FIELD (a, b, tap);
return 0;
}
+guint
+nm_platform_lnk_sit_hash (const NMPlatformLnkSit *obj)
+{
+ guint h = 1690154969;
+
+ h = NM_HASH_COMBINE (h, obj->parent_ifindex);
+ h = NM_HASH_COMBINE (h, obj->local);
+ h = NM_HASH_COMBINE (h, obj->remote);
+ h = NM_HASH_COMBINE (h, obj->ttl);
+ h = NM_HASH_COMBINE (h, obj->tos);
+ h = NM_HASH_COMBINE (h, obj->path_mtu_discovery);
+ h = NM_HASH_COMBINE (h, obj->flags);
+ h = NM_HASH_COMBINE (h, obj->proto);
+ return h;
+}
+
int
nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b)
{
@@ -4255,6 +4600,16 @@ nm_platform_lnk_sit_cmp (const NMPlatformLnkSit *a, const NMPlatformLnkSit *b)
return 0;
}
+guint
+nm_platform_lnk_vlan_hash (const NMPlatformLnkVlan *obj)
+{
+ guint h = 58751383;
+
+ h = NM_HASH_COMBINE (h, obj->id);
+ h = NM_HASH_COMBINE (h, obj->flags);
+ return h;
+}
+
int
nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b)
{
@@ -4264,6 +4619,32 @@ nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b
return 0;
}
+guint
+nm_platform_lnk_vxlan_hash (const NMPlatformLnkVxlan *obj)
+{
+ guint h = 461041297;
+
+ h = NM_HASH_COMBINE (h, obj->parent_ifindex);
+ h = NM_HASH_COMBINE (h, obj->id);
+ h = NM_HASH_COMBINE (h, obj->group);
+ h = NM_HASH_COMBINE (h, obj->local);
+ h = NM_HASH_COMBINE_IN6_ADDR (h, &obj->group6);
+ h = NM_HASH_COMBINE_IN6_ADDR (h, &obj->local6);
+ h = NM_HASH_COMBINE (h, obj->tos);
+ h = NM_HASH_COMBINE (h, obj->ttl);
+ h = NM_HASH_COMBINE (h, obj->learning);
+ h = NM_HASH_COMBINE (h, obj->ageing);
+ h = NM_HASH_COMBINE (h, obj->limit);
+ h = NM_HASH_COMBINE (h, obj->dst_port);
+ h = NM_HASH_COMBINE (h, obj->src_port_min);
+ h = NM_HASH_COMBINE (h, obj->src_port_max);
+ h = NM_HASH_COMBINE (h, obj->proxy);
+ h = NM_HASH_COMBINE (h, obj->rsc);
+ h = NM_HASH_COMBINE (h, obj->l2miss);
+ h = NM_HASH_COMBINE (h, obj->l3miss);
+ return h;
+}
+
int
nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b)
{
@@ -4289,6 +4670,26 @@ nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan
return 0;
}
+guint
+nm_platform_ip4_address_hash (const NMPlatformIP4Address *obj)
+{
+ guint h = 469681301;
+
+ if (obj) {
+ h = NM_HASH_COMBINE (h, obj->ifindex);
+ h = NM_HASH_COMBINE (h, obj->address);
+ h = NM_HASH_COMBINE (h, obj->plen);
+ h = NM_HASH_COMBINE (h, obj->peer_address);
+ h = NM_HASH_COMBINE (h, obj->addr_source);
+ h = NM_HASH_COMBINE (h, obj->timestamp);
+ h = NM_HASH_COMBINE (h, obj->lifetime);
+ h = NM_HASH_COMBINE (h, obj->preferred);
+ h = NM_HASH_COMBINE (h, obj->n_ifa_flags);
+ h = NM_HASH_COMBINE (h, g_str_hash (obj->label));
+ }
+ return h;
+}
+
int
nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b)
{
@@ -4306,6 +4707,25 @@ nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4A
return 0;
}
+guint
+nm_platform_ip6_address_hash (const NMPlatformIP6Address *obj)
+{
+ guint h = 605908909;
+
+ if (obj) {
+ h = NM_HASH_COMBINE (h, obj->ifindex);
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->address));
+ h = NM_HASH_COMBINE (h, obj->plen);
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->peer_address));
+ h = NM_HASH_COMBINE (h, obj->addr_source);
+ h = NM_HASH_COMBINE (h, obj->timestamp);
+ h = NM_HASH_COMBINE (h, obj->lifetime);
+ h = NM_HASH_COMBINE (h, obj->preferred);
+ h = NM_HASH_COMBINE (h, obj->n_ifa_flags);
+ }
+ return h;
+}
+
int
nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b)
{
@@ -4326,6 +4746,37 @@ nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6A
return 0;
}
+guint
+nm_platform_ip4_route_hash (const NMPlatformIP4Route *obj)
+{
+ guint h = 1228913327;
+
+ if (obj) {
+ h = NM_HASH_COMBINE (h, obj->ifindex);
+ h = NM_HASH_COMBINE (h, obj->network);
+ h = NM_HASH_COMBINE (h, obj->plen);
+ h = NM_HASH_COMBINE (h, obj->metric);
+ h = NM_HASH_COMBINE (h, obj->gateway);
+ h = NM_HASH_COMBINE (h, obj->rt_source);
+ h = NM_HASH_COMBINE (h, obj->mss);
+ h = NM_HASH_COMBINE (h, obj->scope_inv);
+ h = NM_HASH_COMBINE (h, obj->pref_src);
+ h = NM_HASH_COMBINE (h, obj->rt_cloned);
+ h = NM_HASH_COMBINE (h, obj->tos);
+ h = NM_HASH_COMBINE (h, obj->lock_window);
+ h = NM_HASH_COMBINE (h, obj->lock_cwnd);
+ h = NM_HASH_COMBINE (h, obj->lock_initcwnd);
+ h = NM_HASH_COMBINE (h, obj->lock_initrwnd);
+ h = NM_HASH_COMBINE (h, obj->lock_mtu);
+ h = NM_HASH_COMBINE (h, obj->window);
+ h = NM_HASH_COMBINE (h, obj->cwnd);
+ h = NM_HASH_COMBINE (h, obj->initcwnd);
+ h = NM_HASH_COMBINE (h, obj->initrwnd);
+ h = NM_HASH_COMBINE (h, obj->mtu);
+ }
+ return h;
+}
+
int
nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b, gboolean consider_host_part)
{
@@ -4359,6 +4810,38 @@ nm_platform_ip4_route_cmp_full (const NMPlatformIP4Route *a, const NMPlatformIP4
return 0;
}
+guint
+nm_platform_ip6_route_hash (const NMPlatformIP6Route *obj)
+{
+ guint h = 1053326051;
+
+ if (obj) {
+ h = NM_HASH_COMBINE (h, obj->ifindex);
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->network));
+ h = NM_HASH_COMBINE (h, obj->plen);
+ h = NM_HASH_COMBINE (h, obj->metric);
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->gateway));
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->pref_src));
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj->src));
+ h = NM_HASH_COMBINE (h, obj->src_plen);
+ h = NM_HASH_COMBINE (h, obj->rt_source);
+ h = NM_HASH_COMBINE (h, obj->mss);
+ h = NM_HASH_COMBINE (h, obj->rt_cloned);
+ h = NM_HASH_COMBINE (h, obj->tos);
+ h = NM_HASH_COMBINE (h, obj->lock_window);
+ h = NM_HASH_COMBINE (h, obj->lock_cwnd);
+ h = NM_HASH_COMBINE (h, obj->lock_initcwnd);
+ h = NM_HASH_COMBINE (h, obj->lock_initrwnd);
+ h = NM_HASH_COMBINE (h, obj->lock_mtu);
+ h = NM_HASH_COMBINE (h, obj->window);
+ h = NM_HASH_COMBINE (h, obj->cwnd);
+ h = NM_HASH_COMBINE (h, obj->initcwnd);
+ h = NM_HASH_COMBINE (h, obj->initrwnd);
+ h = NM_HASH_COMBINE (h, obj->mtu);
+ }
+ return h;
+}
+
int
nm_platform_ip6_route_cmp_full (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b, gboolean consider_host_part)
{
@@ -4495,6 +4978,80 @@ log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatform
/*****************************************************************************/
+void
+nm_platform_cache_update_emit_signal (NMPlatform *self,
+ NMPCacheOpsType cache_op,
+ const NMPObject *obj_old,
+ const NMPObject *obj_new)
+{
+ gboolean visible_new;
+ gboolean visible_old;
+ const NMPObject *o;
+ const NMPClass *klass;
+
+ nm_assert (NM_IN_SET ((NMPlatformSignalChangeType) cache_op, (NMPlatformSignalChangeType) NMP_CACHE_OPS_UNCHANGED, NM_PLATFORM_SIGNAL_ADDED, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_SIGNAL_REMOVED));
+
+ ASSERT_nmp_cache_ops (nm_platform_get_cache (self), cache_op, obj_old, obj_new);
+
+ NMTST_ASSERT_PLATFORM_NETNS_CURRENT (self);
+
+ switch (cache_op) {
+ case NMP_CACHE_OPS_ADDED:
+ if (!nmp_object_is_visible (obj_new))
+ return;
+ o = obj_new;
+ break;
+ case NMP_CACHE_OPS_UPDATED:
+ visible_old = nmp_object_is_visible (obj_old);
+ visible_new = nmp_object_is_visible (obj_new);
+ if (!visible_old && visible_new) {
+ o = obj_new;
+ cache_op = NMP_CACHE_OPS_ADDED;
+ } else if (visible_old && !visible_new) {
+ o = obj_old;
+ cache_op = NMP_CACHE_OPS_REMOVED;
+ } else if (!visible_new) {
+ /* it was invisible and stayed invisible. Nothing to do. */
+ return;
+ } else
+ o = obj_new;
+ break;
+ case NMP_CACHE_OPS_REMOVED:
+ if (!nmp_object_is_visible (obj_old))
+ return;
+ o = obj_old;
+ break;
+ default:
+ nm_assert (cache_op == NMP_CACHE_OPS_UNCHANGED);
+ return;
+ }
+
+ klass = NMP_OBJECT_GET_CLASS (o);
+
+ _LOGt ("emit signal %s %s: %s",
+ klass->signal_type,
+ nm_platform_signal_change_type_to_string ((NMPlatformSignalChangeType) cache_op),
+ nmp_object_to_string (o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
+
+ nmp_object_ref (o);
+ g_signal_emit (self,
+ _nm_platform_signal_id_get (klass->signal_type_id),
+ 0,
+ (int) klass->obj_type,
+ o->object.ifindex,
+ &o->object,
+ (int) cache_op);
+ nmp_object_unref (o);
+}
+
+/*****************************************************************************/
+
+NMPCache *
+nm_platform_get_cache (NMPlatform *self)
+{
+ return NM_PLATFORM_GET_PRIVATE (self)->cache;
+}
+
NMPNetns *
nm_platform_netns_get (NMPlatform *self)
{
@@ -4504,17 +5061,17 @@ nm_platform_netns_get (NMPlatform *self)
}
gboolean
-nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns)
+nm_platform_netns_push (NMPlatform *self, NMPNetns **netns)
{
- g_return_val_if_fail (NM_IS_PLATFORM (platform), FALSE);
+ g_return_val_if_fail (NM_IS_PLATFORM (self), FALSE);
- if ( platform->_netns
- && !nmp_netns_push (platform->_netns)) {
+ if ( self->_netns
+ && !nmp_netns_push (self->_netns)) {
NM_SET_OUT (netns, NULL);
return FALSE;
}
- NM_SET_OUT (netns, platform->_netns);
+ NM_SET_OUT (netns, self->_netns);
return TRUE;
}
@@ -4588,11 +5145,11 @@ _vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric)
const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
.is_ip4 = TRUE,
+ .obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
.addr_family = AF_INET,
.sizeof_route = sizeof (NMPlatformIP4Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip4_route_cmp_full,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
- .route_get_all = nm_platform_ip4_route_get_all,
.route_add = _vtr_v4_route_add,
.route_delete = _vtr_v4_route_delete,
.route_delete_default = _vtr_v4_route_delete_default,
@@ -4601,11 +5158,11 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
.is_ip4 = FALSE,
+ .obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
.addr_family = AF_INET6,
.sizeof_route = sizeof (NMPlatformIP6Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip6_route_cmp_full,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string,
- .route_get_all = nm_platform_ip6_route_get_all,
.route_add = _vtr_v6_route_add,
.route_delete = _vtr_v6_route_delete,
.route_delete_default = _vtr_v6_route_delete_default,
@@ -4632,6 +5189,10 @@ set_property (GObject *object, guint prop_id,
self->_netns = g_object_ref (netns);
}
break;
+ case PROP_USE_UDEV:
+ /* construct-only */
+ priv->use_udev = g_value_get_boolean (value);
+ break;
case PROP_LOG_WITH_PTR:
/* construct-only */
priv->log_with_ptr = g_value_get_boolean (value);
@@ -4648,12 +5209,37 @@ nm_platform_init (NMPlatform *self)
self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_PLATFORM, NMPlatformPrivate);
}
+static GObject *
+constructor (GType type,
+ guint n_construct_params,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ NMPlatform *self;
+ NMPlatformPrivate *priv;
+
+ object = G_OBJECT_CLASS (nm_platform_parent_class)->constructor (type,
+ n_construct_params,
+ construct_params);
+ self = NM_PLATFORM (object);
+ priv = NM_PLATFORM_GET_PRIVATE (self);
+
+ priv->multi_idx = nm_dedup_multi_index_new ();
+
+ priv->cache = nmp_cache_new (nm_platform_get_multi_idx (self),
+ priv->use_udev);
+ return object;
+}
+
static void
finalize (GObject *object)
{
NMPlatform *self = NM_PLATFORM (object);
+ NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self);
g_clear_object (&self->_netns);
+ nm_dedup_multi_index_unref (priv->multi_idx);
+ nmp_cache_free (priv->cache);
}
static void
@@ -4663,6 +5249,7 @@ nm_platform_class_init (NMPlatformClass *platform_class)
g_type_class_add_private (object_class, sizeof (NMPlatformPrivate));
+ object_class->constructor = constructor;
object_class->set_property = set_property;
object_class->finalize = finalize;
@@ -4677,6 +5264,14 @@ nm_platform_class_init (NMPlatformClass *platform_class)
G_PARAM_STATIC_STRINGS));
g_object_class_install_property
+ (object_class, PROP_USE_UDEV,
+ g_param_spec_boolean (NM_PLATFORM_USE_UDEV, "", "",
+ FALSE,
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT_ONLY |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
(object_class, PROP_LOG_WITH_PTR,
g_param_spec_boolean (NM_PLATFORM_LOG_WITH_PTR, "", "",
TRUE,
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index 97c8f6ccf2..6e7a8b0658 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -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__ */
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index 3ea3fbba4f..b6a51e58bc 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -51,6 +51,11 @@
/*****************************************************************************/
+typedef struct {
+ NMDedupMultiIdxType parent;
+ NMPCacheIdType cache_id_type;
+} DedupMultiIdxType;
+
struct _NMPCache {
/* the cache contains only one hash table for all object types, and similarly
* it contains only one NMMultiIndex.
@@ -66,23 +71,248 @@ struct _NMPCache {
* This effectively merges the udev-device cache into the NMPCache.
*/
- GHashTable *idx_main;
- NMMultiIndex *idx_multi;
+ NMDedupMultiIndex *multi_idx;
+
+ /* an idx_type entry for each NMP_CACHE_ID_TYPE. Note that NONE (zero)
+ * is skipped, so the index is shifted by one: idx_type[cache_id_type - 1].
+ *
+ * Don't bother, use _idx_type_get() instead! */
+ DedupMultiIdxType idx_types[NMP_CACHE_ID_TYPE_MAX];
gboolean use_udev;
};
/*****************************************************************************/
-static inline guint
-_id_hash_ip6_addr (const struct in6_addr *addr)
+static const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class;
+
+static guint
+_idx_obj_id_hash (const NMDedupMultiIdxType *idx_type,
+ const NMDedupMultiObj *obj)
{
- guint hash = (guint) 0x897da53981a13ULL;
- int i;
+ const NMPObject *o = (NMPObject *) obj;
+
+ nm_assert (idx_type && idx_type->klass == &_dedup_multi_idx_type_class);
+ nm_assert (NMP_OBJECT_GET_TYPE (o) != NMP_OBJECT_TYPE_UNKNOWN);
+
+ return nmp_object_id_hash (o);
+}
+
+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 (idx_type && idx_type->klass == &_dedup_multi_idx_type_class);
+ nm_assert (NMP_OBJECT_GET_TYPE (o_a) != NMP_OBJECT_TYPE_UNKNOWN);
+ nm_assert (NMP_OBJECT_GET_TYPE (o_b) != NMP_OBJECT_TYPE_UNKNOWN);
+
+ return nmp_object_id_equal (o_a, o_b);
+}
+
+/* the return value of _idx_obj_part() encodes 3 things:
+ * 1) for idx_obj_partitionable(), it returns 0 or non-zero.
+ * 2) for idx_obj_partition_hash(), it returns the hash value (which
+ * must never be zero not to clash with idx_obj_partitionable().
+ * 3) for idx_obj_partition_equal(), returns 0 or 1 depending
+ * on whether the objects are equal.
+ *
+ * _HASH_NON_ZERO() is used to for case 2), to avoid that the a zero hash value
+ * is returned. */
+#define _HASH_NON_ZERO(h) \
+ ((h) ?: (1998098407 + __LINE__)) \
+
+static guint
+_idx_obj_part (const DedupMultiIdxType *idx_type,
+ gboolean request_hash,
+ const NMPObject *obj_a,
+ const NMPObject *obj_b)
+{
+ guint h;
+ NMPObjectType obj_type;
+
+ /* the hash/equals functions are strongly related. So, keep them
+ * side-by-side and do it all in _idx_obj_part(). */
+
+ nm_assert (idx_type);
+ nm_assert (idx_type->parent.klass == &_dedup_multi_idx_type_class);
+ nm_assert (obj_a);
+ nm_assert (NMP_OBJECT_GET_TYPE (obj_a) != NMP_OBJECT_TYPE_UNKNOWN);
+ nm_assert (!obj_b || (NMP_OBJECT_GET_TYPE (obj_b) != NMP_OBJECT_TYPE_UNKNOWN));
+ nm_assert (!request_hash || !obj_b);
+
+ switch (idx_type->cache_id_type) {
+
+ case NMP_CACHE_ID_TYPE_OBJECT_TYPE:
+ if (obj_b)
+ return NMP_OBJECT_GET_TYPE (obj_a) == NMP_OBJECT_GET_TYPE (obj_b);
+ if (request_hash) {
+ h = (guint) idx_type->cache_id_type;
+ h = NM_HASH_COMBINE (h, NMP_OBJECT_GET_TYPE (obj_a));
+ return _HASH_NON_ZERO (h);
+ }
+ return 1;
+
+ case NMP_CACHE_ID_TYPE_LINK_BY_IFNAME:
+ if (NMP_OBJECT_GET_TYPE (obj_a) != NMP_OBJECT_TYPE_LINK) {
+ /* first check, whether obj_a is suitable for this idx_type.
+ * If not, return 0 (which is correct for partitionable(), hash() and equal()
+ * functions. */
+ return 0;
+ }
+ if (obj_b) {
+ /* we are in equal() mode. Compare obj_b with obj_a. */
+ return NMP_OBJECT_GET_TYPE (obj_b) == NMP_OBJECT_TYPE_LINK
+ && nm_streq (obj_a->link.name, obj_b->link.name);
+ }
+ if (request_hash) {
+ /* we request a hash from obj_a. Hash the relevant parts. */
+ h = (guint) idx_type->cache_id_type;
+ h = NM_HASH_COMBINE (h, g_str_hash (obj_a->link.name));
+ return _HASH_NON_ZERO (h);
+ }
+ /* just return 1, to indicate that obj_a is partitionable by this idx_type. */
+ return 1;
+
+ case NMP_CACHE_ID_TYPE_DEFAULT_ROUTES:
+ if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ROUTE,
+ NMP_OBJECT_TYPE_IP6_ROUTE)
+ || !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_a->ip_route)
+ || !nmp_object_is_visible (obj_a))
+ return 0;
+ if (obj_b) {
+ return NMP_OBJECT_GET_TYPE (obj_a) == NMP_OBJECT_GET_TYPE (obj_b)
+ && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_b->ip_route)
+ && nmp_object_is_visible (obj_b);
+ }
+ if (request_hash) {
+ h = (guint) idx_type->cache_id_type;
+ h = NM_HASH_COMBINE (h, NMP_OBJECT_GET_TYPE (obj_a));
+ return _HASH_NON_ZERO (h);
+ }
+ return 1;
+
+ case NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX:
+ if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ADDRESS,
+ NMP_OBJECT_TYPE_IP6_ADDRESS,
+ NMP_OBJECT_TYPE_IP4_ROUTE,
+ NMP_OBJECT_TYPE_IP6_ROUTE)
+ || !nmp_object_is_visible (obj_a))
+ return 0;
+ nm_assert (obj_a->object.ifindex > 0);
+ if (obj_b) {
+ return NMP_OBJECT_GET_TYPE (obj_a) == NMP_OBJECT_GET_TYPE (obj_b)
+ && obj_a->object.ifindex == obj_b->object.ifindex
+ && nmp_object_is_visible (obj_b);
+ }
+ if (request_hash) {
+ h = (guint) idx_type->cache_id_type;
+ h = NM_HASH_COMBINE (h, NMP_OBJECT_GET_TYPE (obj_a));
+ h = NM_HASH_COMBINE (h, obj_a->object.ifindex);
+ return _HASH_NON_ZERO (h);
+ }
+ return 1;
+
+ case NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION:
+ obj_type = NMP_OBJECT_GET_TYPE (obj_a);
+ if ( !NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE,
+ NMP_OBJECT_TYPE_IP6_ROUTE)
+ || obj_a->object.ifindex <= 0)
+ return 0;
+ if (obj_b) {
+ return obj_type == NMP_OBJECT_GET_TYPE (obj_b)
+ && obj_b->object.ifindex > 0
+ && obj_a->ip_route.plen == obj_b->ip_route.plen
+ && obj_a->ip_route.metric == obj_b->ip_route.metric
+ && (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
+ ? obj_a->ip4_route.network == obj_b->ip4_route.network
+ : IN6_ARE_ADDR_EQUAL (&obj_a->ip6_route.network, &obj_b->ip6_route.network));
+ }
+ if (request_hash) {
+ h = (guint) idx_type->cache_id_type;
+ h = NM_HASH_COMBINE (h, obj_a->ip_route.plen);
+ h = NM_HASH_COMBINE (h, obj_a->ip_route.metric);
+ h = NM_HASH_COMBINE (h, obj_type);
+ if (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE)
+ h = NM_HASH_COMBINE (h, obj_a->ip4_route.network);
+ else
+ h = NM_HASH_COMBINE (h, nm_utils_in6_addr_hash (&obj_a->ip6_route.network));
+ return _HASH_NON_ZERO (h);
+ }
+ return 1;
+
+ case NMP_CACHE_ID_TYPE_NONE:
+ case __NMP_CACHE_ID_TYPE_MAX:
+ break;
+ }
+ nm_assert_not_reached ();
+ return 0;
+}
+
+static gboolean
+_idx_obj_partitionable (const NMDedupMultiIdxType *idx_type,
+ const NMDedupMultiObj *obj)
+{
+ return _idx_obj_part ((DedupMultiIdxType *) idx_type,
+ FALSE,
+ (NMPObject *) obj,
+ NULL) != 0;
+}
+
+static guint
+_idx_obj_partition_hash (const NMDedupMultiIdxType *idx_type,
+ const NMDedupMultiObj *obj)
+{
+ return _idx_obj_part ((DedupMultiIdxType *) idx_type,
+ TRUE,
+ (NMPObject *) obj,
+ NULL);
+}
+
+static gboolean
+_idx_obj_partition_equal (const NMDedupMultiIdxType *idx_type,
+ const NMDedupMultiObj *obj_a,
+ const NMDedupMultiObj *obj_b)
+{
+ return _idx_obj_part ((DedupMultiIdxType *) idx_type,
+ FALSE,
+ (NMPObject *) obj_a,
+ (NMPObject *) obj_b);
+}
+
+static const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class = {
+ .idx_obj_id_hash = _idx_obj_id_hash,
+ .idx_obj_id_equal = _idx_obj_id_equal,
+ .idx_obj_partitionable = _idx_obj_partitionable,
+ .idx_obj_partition_hash = _idx_obj_partition_hash,
+ .idx_obj_partition_equal = _idx_obj_partition_equal,
+};
+
+static void
+_dedup_multi_idx_type_init (DedupMultiIdxType *idx_type, NMPCacheIdType cache_id_type)
+{
+ nm_dedup_multi_idx_type_init ((NMDedupMultiIdxType *) idx_type,
+ &_dedup_multi_idx_type_class);
+ idx_type->cache_id_type = cache_id_type;
+}
- for (i = 0; i < sizeof (*addr); i++)
- hash = (hash * 33) + ((const guint8 *) addr)[i];
- return hash;
+/*****************************************************************************/
+
+static guint
+_vlan_xgress_qos_mappings_hash (guint n_map,
+ const NMVlanQosMapping *map)
+{
+ guint h = 1453577309;
+ guint i;
+
+ for (i = 0; i < n_map; i++) {
+ h = NM_HASH_COMBINE (h, map[i].from);
+ h = NM_HASH_COMBINE (h, map[i].to);
+ }
+ return h;
}
static int
@@ -150,12 +380,18 @@ _link_get_driver (struct udev_device *udevice, const char *kind, int ifindex)
}
void
-_nmp_object_fixup_link_udev_fields (NMPObject *obj, gboolean use_udev)
+_nmp_object_fixup_link_udev_fields (NMPObject **obj_new, NMPObject *obj_orig, gboolean use_udev)
{
const char *driver = NULL;
gboolean initialized = FALSE;
+ NMPObject *obj;
- nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK);
+ nm_assert (obj_orig || *obj_new);
+ nm_assert (obj_new);
+ nm_assert (!obj_orig || NMP_OBJECT_GET_TYPE (obj_orig) == NMP_OBJECT_TYPE_LINK);
+ nm_assert (!*obj_new || NMP_OBJECT_GET_TYPE (*obj_new) == NMP_OBJECT_TYPE_LINK);
+
+ obj = *obj_new ?: obj_orig;
/* The link contains internal fields that are combined by
* properties from netlink and udev. Update those properties */
@@ -179,17 +415,34 @@ _nmp_object_fixup_link_udev_fields (NMPObject *obj, gboolean use_udev)
}
}
+ if ( nm_streq0 (obj->link.driver, driver)
+ && obj->link.initialized == initialized)
+ return;
+
+ if (!*obj_new)
+ obj = *obj_new = nmp_object_clone (obj, FALSE);
+
obj->link.driver = driver;
obj->link.initialized = initialized;
}
static void
-_nmp_object_fixup_link_master_connected (NMPObject *obj, const NMPCache *cache)
+_nmp_object_fixup_link_master_connected (NMPObject **obj_new, NMPObject *obj_orig, const NMPCache *cache)
{
- nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK);
+ NMPObject *obj;
+
+ nm_assert (obj_orig || *obj_new);
+ nm_assert (obj_new);
+ nm_assert (!obj_orig || NMP_OBJECT_GET_TYPE (obj_orig) == NMP_OBJECT_TYPE_LINK);
+ nm_assert (!*obj_new || NMP_OBJECT_GET_TYPE (*obj_new) == NMP_OBJECT_TYPE_LINK);
+
+ obj = *obj_new ?: obj_orig;
- if (nmp_cache_link_connected_needs_toggle (cache, obj, NULL, NULL))
+ if (nmp_cache_link_connected_needs_toggle (cache, obj, NULL, NULL)) {
+ if (!*obj_new)
+ obj = *obj_new = nmp_object_clone (obj, FALSE);
obj->link.connected = !obj->link.connected;
+ }
}
/*****************************************************************************/
@@ -204,33 +457,6 @@ nmp_class_from_type (NMPObjectType obj_type)
/*****************************************************************************/
-NMPObject *
-nmp_object_ref (NMPObject *obj)
-{
- g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), NULL);
- g_return_val_if_fail (obj->_ref_count != NMP_REF_COUNT_STACKINIT, NULL);
- obj->_ref_count++;
-
- return obj;
-}
-
-void
-nmp_object_unref (NMPObject *obj)
-{
- if (obj) {
- g_return_if_fail (obj->_ref_count > 0);
- g_return_if_fail (obj->_ref_count != NMP_REF_COUNT_STACKINIT);
- if (--obj->_ref_count <= 0) {
- const NMPClass *klass = obj->_class;
-
- nm_assert (!obj->is_cached);
- if (klass->cmd_obj_dispose)
- klass->cmd_obj_dispose (obj);
- g_slice_free1 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object), obj);
- }
- }
-}
-
static void
_vt_cmd_obj_dispose_link (NMPObject *obj)
{
@@ -259,7 +485,7 @@ _nmp_object_new_from_class (const NMPClass *klass)
obj = g_slice_alloc0 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object));
obj->_class = klass;
- obj->_ref_count = 1;
+ obj->parent._ref_count = 1;
return obj;
}
@@ -287,14 +513,29 @@ nmp_object_new_link (int ifindex)
/*****************************************************************************/
-static const NMPObject *
+static void
_nmp_object_stackinit_from_class (NMPObject *obj, const NMPClass *klass)
{
+ nm_assert (obj);
+ nm_assert (klass);
+
+ memset (obj, 0, sizeof (NMPObject));
+ obj->_class = klass;
+ obj->parent._ref_count = NM_OBJ_REF_COUNT_STACKINIT;
+}
+
+static NMPObject *
+_nmp_object_stackinit_from_type (NMPObject *obj, NMPObjectType obj_type)
+{
+ const NMPClass *klass;
+
+ nm_assert (obj);
+ klass = nmp_class_from_type (obj_type);
nm_assert (klass);
memset (obj, 0, sizeof (NMPObject));
obj->_class = klass;
- obj->_ref_count = NMP_REF_COUNT_STACKINIT;
+ obj->parent._ref_count = NM_OBJ_REF_COUNT_STACKINIT;
return obj;
}
@@ -319,7 +560,7 @@ nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src)
klass = NMP_OBJECT_GET_CLASS (src);
if (!klass->cmd_obj_stackinit_id)
- nmp_object_stackinit (obj, klass->obj_type, NULL);
+ _nmp_object_stackinit_from_class (obj, klass);
else
klass->cmd_obj_stackinit_id (obj, src);
return obj;
@@ -328,7 +569,7 @@ nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src)
const NMPObject *
nmp_object_stackinit_id_link (NMPObject *obj, int ifindex)
{
- nmp_object_stackinit (obj, NMP_OBJECT_TYPE_LINK, NULL);
+ _nmp_object_stackinit_from_type (obj, NMP_OBJECT_TYPE_LINK);
obj->link.ifindex = ifindex;
return obj;
}
@@ -342,7 +583,7 @@ _vt_cmd_obj_stackinit_id_link (NMPObject *obj, const NMPObject *src)
const NMPObject *
nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, guint8 plen, guint32 peer_address)
{
- nmp_object_stackinit (obj, NMP_OBJECT_TYPE_IP4_ADDRESS, NULL);
+ _nmp_object_stackinit_from_type (obj, NMP_OBJECT_TYPE_IP4_ADDRESS);
obj->ip4_address.ifindex = ifindex;
obj->ip4_address.address = address;
obj->ip4_address.plen = plen;
@@ -359,7 +600,7 @@ _vt_cmd_obj_stackinit_id_ip4_address (NMPObject *obj, const NMPObject *src)
const NMPObject *
nmp_object_stackinit_id_ip6_address (NMPObject *obj, int ifindex, const struct in6_addr *address)
{
- nmp_object_stackinit (obj, NMP_OBJECT_TYPE_IP6_ADDRESS, NULL);
+ _nmp_object_stackinit_from_type (obj, NMP_OBJECT_TYPE_IP6_ADDRESS);
obj->ip4_address.ifindex = ifindex;
if (address)
obj->ip6_address.address = *address;
@@ -375,7 +616,7 @@ _vt_cmd_obj_stackinit_id_ip6_address (NMPObject *obj, const NMPObject *src)
const NMPObject *
nmp_object_stackinit_id_ip4_route (NMPObject *obj, int ifindex, guint32 network, guint8 plen, guint32 metric)
{
- nmp_object_stackinit (obj, NMP_OBJECT_TYPE_IP4_ROUTE, NULL);
+ _nmp_object_stackinit_from_type (obj, NMP_OBJECT_TYPE_IP4_ROUTE);
obj->ip4_route.ifindex = ifindex;
obj->ip4_route.network = network;
obj->ip4_route.plen = plen;
@@ -392,7 +633,7 @@ _vt_cmd_obj_stackinit_id_ip4_route (NMPObject *obj, const NMPObject *src)
const NMPObject *
nmp_object_stackinit_id_ip6_route (NMPObject *obj, int ifindex, const struct in6_addr *network, guint8 plen, guint32 metric)
{
- nmp_object_stackinit (obj, NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
+ _nmp_object_stackinit_from_type (obj, NMP_OBJECT_TYPE_IP6_ROUTE);
obj->ip6_route.ifindex = ifindex;
if (network)
obj->ip6_route.network = *network;
@@ -434,9 +675,8 @@ nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode
return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size);
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
- "[%s,%p,%d,%ccache,%calive,%cvisible; %s]",
- klass->obj_type_name, obj, obj->_ref_count,
- obj->is_cached ? '+' : '-',
+ "[%s,%p,%u,%calive,%cvisible; %s]",
+ klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2)));
@@ -461,9 +701,8 @@ _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_strin
return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size);
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
- "[%s,%p,%d,%ccache,%calive,%cvisible,%cin-nl,%p; %s]",
- klass->obj_type_name, obj, obj->_ref_count,
- obj->is_cached ? '+' : '-',
+ "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; %s]",
+ klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
obj->_link.netlink.is_in_netlink ? '+' : '-',
@@ -502,9 +741,8 @@ _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_s
case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
- "[%s,%p,%d,%ccache,%calive,%cvisible; %s]",
- klass->obj_type_name, obj, obj->_ref_count,
- obj->is_cached ? '+' : '-',
+ "[%s,%p,%u,%calive,%cvisible; %s]",
+ klass->obj_type_name, obj, obj->parent._ref_count,
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)));
@@ -566,6 +804,58 @@ _vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s",
_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric);
_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric);
+guint
+nmp_object_hash (const NMPObject *obj)
+{
+ const NMPClass *klass;
+ guint h;
+
+ if (!obj)
+ return 0;
+
+ g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), 0);
+
+ klass = NMP_OBJECT_GET_CLASS (obj);
+
+ if (klass->cmd_obj_hash)
+ h = klass->cmd_obj_hash (obj);
+ else if (klass->cmd_plobj_hash)
+ h = klass->cmd_plobj_hash (&obj->object);
+ else
+ return GPOINTER_TO_UINT (obj);
+ return NM_HASH_COMBINE (h, klass->obj_type);
+}
+
+static guint
+_vt_cmd_obj_hash_link (const NMPObject *obj)
+{
+ guint h = 1228913327;
+
+ nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK);
+
+ h = NM_HASH_COMBINE (h, nm_platform_link_hash (&obj->link));
+ h = NM_HASH_COMBINE (h, obj->_link.netlink.is_in_netlink);
+ if (obj->_link.netlink.lnk)
+ h = NM_HASH_COMBINE (h, nmp_object_hash (obj->_link.netlink.lnk));
+ h = NM_HASH_COMBINE (h, GPOINTER_TO_UINT (obj->_link.udev.device));
+ return h;
+}
+
+static guint
+_vt_cmd_obj_hash_lnk_vlan (const NMPObject *obj)
+{
+ guint h = 914932607;
+
+ nm_assert (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LNK_VLAN);
+
+ h = NM_HASH_COMBINE (h, nm_platform_lnk_vlan_hash (&obj->lnk_vlan));
+ h = NM_HASH_COMBINE (h, _vlan_xgress_qos_mappings_hash (obj->_lnk_vlan.n_ingress_qos_map,
+ obj->_lnk_vlan.ingress_qos_map));
+ h = NM_HASH_COMBINE (h, _vlan_xgress_qos_mappings_hash (obj->_lnk_vlan.n_egress_qos_map,
+ obj->_lnk_vlan.egress_qos_map));
+ return h;
+}
+
int
nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
{
@@ -846,39 +1136,39 @@ _vt_cmd_plobj_id_hash_##type (const NMPlatformObject *_obj) \
}
_vt_cmd_plobj_id_hash (link, NMPlatformLink, {
hash = (guint) 3982791431u;
- hash = hash + ((guint) obj->ifindex);
+ hash = hash + ((guint) obj->ifindex);
})
_vt_cmd_plobj_id_hash (ip4_address, NMPlatformIP4Address, {
hash = (guint) 3591309853u;
- hash = hash + ((guint) obj->ifindex);
- hash = hash * 33 + ((guint) obj->plen);
- hash = hash * 33 + ((guint) obj->address);
-
+ hash = hash + ((guint) obj->ifindex);
+ hash = NM_HASH_COMBINE (hash, obj->plen);
+ hash = NM_HASH_COMBINE (hash, obj->address);
/* for IPv4 we must also consider the net-part of the peer-address (IFA_ADDRESS) */
- hash = hash * 33 + ((guint) (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen)));
+ hash = NM_HASH_COMBINE (hash, (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen)));
})
_vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, {
hash = (guint) 2907861637u;
- hash = hash + ((guint) obj->ifindex);
+ hash = hash + ((guint) obj->ifindex);
/* for IPv6 addresses, the prefix length is not part of the primary identifier. */
- hash = hash * 33 + _id_hash_ip6_addr (&obj->address);
+ hash = NM_HASH_COMBINE (hash, nm_utils_in6_addr_hash (&obj->address));
})
_vt_cmd_plobj_id_hash (ip4_route, NMPlatformIP4Route, {
hash = (guint) 2569857221u;
- hash = hash + ((guint) obj->ifindex);
- hash = hash * 33 + ((guint) obj->plen);
- hash = hash * 33 + ((guint) obj->metric);
- hash = hash * 33 + ((guint) nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
+ hash = hash + ((guint) obj->ifindex);
+ hash = NM_HASH_COMBINE (hash, obj->plen);
+ hash = NM_HASH_COMBINE (hash, obj->metric);
+ hash = NM_HASH_COMBINE (hash, nm_utils_ip4_address_clear_host_address (obj->network, obj->plen));
})
_vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, {
hash = (guint) 3999787007u;
- hash = hash + ((guint) obj->ifindex);
- hash = hash * 33 + ((guint) obj->plen);
- hash = hash * 33 + ((guint) obj->metric);
- hash = hash * 33 + ({
- struct in6_addr n1;
- _id_hash_ip6_addr (nm_utils_ip6_address_clear_host_address (&n1, &obj->network, obj->plen));
- });
+ hash = hash + ((guint) obj->ifindex);
+ hash = NM_HASH_COMBINE (hash, obj->plen);
+ hash = NM_HASH_COMBINE (hash, obj->metric);
+ hash = NM_HASH_COMBINE (hash,
+ ({
+ struct in6_addr n1;
+ nm_utils_in6_addr_hash (nm_utils_ip6_address_clear_host_address (&n1, &obj->network, obj->plen));
+ }));
})
gboolean
@@ -957,365 +1247,106 @@ _vt_cmd_obj_is_visible_link (const NMPObject *obj)
/*****************************************************************************/
-_NM_UTILS_LOOKUP_DEFINE (static, _nmp_cache_id_size_by_type, NMPCacheIdType, guint,
- NM_UTILS_LOOKUP_DEFAULT (({ nm_assert_not_reached (); (guint) 0; })),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_OBJECT_TYPE, nm_offsetofend (NMPCacheId, object_type)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY, nm_offsetofend (NMPCacheId, object_type)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT, nm_offsetofend (NMPCacheId, object_type)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT, nm_offsetofend (NMPCacheId, object_type)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX, nm_offsetofend (NMPCacheId, object_type_by_ifindex)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT, nm_offsetofend (NMPCacheId, object_type_by_ifindex)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT, nm_offsetofend (NMPCacheId, object_type_by_ifindex)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_LINK_BY_IFNAME, nm_offsetofend (NMPCacheId, link_by_ifname)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP4, nm_offsetofend (NMPCacheId, routes_by_destination_ip4)),
- NM_UTILS_LOOKUP_ITEM (NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6, nm_offsetofend (NMPCacheId, routes_by_destination_ip6)),
- NM_UTILS_LOOKUP_ITEM_IGNORE (NMP_CACHE_ID_TYPE_NONE),
- NM_UTILS_LOOKUP_ITEM_IGNORE (__NMP_CACHE_ID_TYPE_MAX),
-);
-
-gboolean
-nmp_cache_id_equal (const NMPCacheId *a, const NMPCacheId *b)
-{
- if (a->_id_type != b->_id_type)
- return FALSE;
- return memcmp (a, b, _nmp_cache_id_size_by_type (a->_id_type)) == 0;
-}
-
-guint
-nmp_cache_id_hash (const NMPCacheId *id)
-{
- guint hash = 5381;
- guint i, n;
-
- n = _nmp_cache_id_size_by_type (id->_id_type);
- for (i = 0; i < n; i++)
- hash = ((hash << 5) + hash) + ((char *) id)[i]; /* hash * 33 + c */
- return hash;
-}
-
-NMPCacheId *
-nmp_cache_id_clone (const NMPCacheId *id)
-{
- NMPCacheId *id2;
- guint n;
-
- n = _nmp_cache_id_size_by_type (id->_id_type);
- id2 = g_slice_alloc (n);
- memcpy (id2, id, n);
- return id2;
-}
+static const guint8 _supported_cache_ids_link[] = {
+ NMP_CACHE_ID_TYPE_OBJECT_TYPE,
+ NMP_CACHE_ID_TYPE_LINK_BY_IFNAME,
+ 0,
+};
-void
-nmp_cache_id_destroy (NMPCacheId *id)
-{
- guint n;
+static const guint8 _supported_cache_ids_ipx_address[] = {
+ NMP_CACHE_ID_TYPE_OBJECT_TYPE,
+ NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX,
+ 0,
+};
- n = _nmp_cache_id_size_by_type (id->_id_type);
- g_slice_free1 (n, id);
-}
+static const guint8 _supported_cache_ids_ipx_route[] = {
+ NMP_CACHE_ID_TYPE_OBJECT_TYPE,
+ NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX,
+ NMP_CACHE_ID_TYPE_DEFAULT_ROUTES,
+ NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION,
+ 0,
+};
/*****************************************************************************/
static void
-_nmp_cache_id_init (NMPCacheId *id, NMPCacheIdType id_type)
-{
- /* there is no need to set the entire @id to zero when
- * initializing the ID.
- *
- * First, depending on the @id_type only part of the
- * @id is actually used (_nmp_cache_id_size_by_type).
- *
- * Second, the nmp_cache_id_init_*() *MUST* anyway make sure
- * that all relevant fields are set. Since it happens that
- * all structs have the packed attribute, there are no holes
- * due to alignment, and it becomes simple for nmp_cache_id_init_*()
- * to ensure that all fields are set. */
-
-#if NM_MORE_ASSERTS
- nm_assert (id);
- {
- guint i;
-
- /* initialized with some bogus canary to hopefully detect when we miss
- * to initialize a field of the cache-id. */
- for (i = 0; i < sizeof (*id); i++) {
- ((char *) id)[i] = GPOINTER_TO_UINT (id) ^ i;
- }
- }
-#endif
-
- id->_id_type = id_type;
-}
-
-NMPCacheId *
-nmp_cache_id_init_object_type (NMPCacheId *id, NMPObjectType obj_type, gboolean visible_only)
+_vt_dedup_obj_destroy (NMDedupMultiObj *obj)
{
- _nmp_cache_id_init (id, visible_only
- ? NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY
- : NMP_CACHE_ID_TYPE_OBJECT_TYPE);
- id->object_type.obj_type = obj_type;
- return id;
-}
-
-NMPCacheId *
-nmp_cache_id_init_addrroute_visible_by_ifindex (NMPCacheId *id,
- NMPObjectType obj_type,
- int ifindex)
-{
- g_return_val_if_fail (NM_IN_SET (obj_type,
- NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP4_ROUTE,
- NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP6_ROUTE), NULL);
+ NMPObject *o = (NMPObject *) obj;
+ const NMPClass *klass;
- if (ifindex <= 0)
- return nmp_cache_id_init_object_type (id, obj_type, TRUE);
+ nm_assert (o->parent._ref_count == 0);
+ nm_assert (!o->parent._multi_idx);
- _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX);
- id->object_type_by_ifindex.obj_type = obj_type;
- memcpy (&id->object_type_by_ifindex._misaligned_ifindex, &ifindex, sizeof (int));
- return id;
+ klass = o->_class;
+ if (klass->cmd_obj_dispose)
+ klass->cmd_obj_dispose (o);
+ g_slice_free1 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object), o);
}
-NMPCacheId *
-nmp_cache_id_init_routes_visible (NMPCacheId *id,
- NMPObjectType obj_type,
- gboolean with_default,
- gboolean with_non_default,
- int ifindex)
+static const NMDedupMultiObj *
+_vt_dedup_obj_clone (const NMDedupMultiObj *obj)
{
- g_return_val_if_fail (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE), NULL);
-
- if (with_default) {
- if (with_non_default) {
- if (ifindex <= 0)
- return nmp_cache_id_init_object_type (id, obj_type, TRUE);
- return nmp_cache_id_init_addrroute_visible_by_ifindex (id, obj_type, ifindex);
- }
- _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT);
- } else if (with_non_default)
- _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT);
- else
- g_return_val_if_reached (NULL);
-
- id->object_type_by_ifindex.obj_type = obj_type;
- memcpy (&id->object_type_by_ifindex._misaligned_ifindex, &ifindex, sizeof (int));
- return id;
+ return (const NMDedupMultiObj *) nmp_object_clone ((const NMPObject *) obj, FALSE);
}
-NMPCacheId *
-nmp_cache_id_init_link_by_ifname (NMPCacheId *id,
- const char *ifname)
+static guint
+_vt_dedup_obj_full_hash (const NMDedupMultiObj *obj)
{
- gsize l;
-
- if ( !ifname
- || (l = strlen (ifname)) > sizeof (id->link_by_ifname.ifname_short))
- g_return_val_if_reached (id);
-
- _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_LINK_BY_IFNAME);
-
- memset (id->link_by_ifname.ifname_short, 0, sizeof (id->link_by_ifname.ifname_short));
- /* the trailing NUL is dropped!! */
- memcpy (id->link_by_ifname.ifname_short, ifname, l);
-
- return id;
+ return nmp_object_hash ((NMPObject *) obj);
}
-NMPCacheId *
-nmp_cache_id_init_routes_by_destination_ip4 (NMPCacheId *id,
- guint32 network,
- guint8 plen,
- guint32 metric)
+static gboolean
+_vt_dedup_obj_full_equal (const NMDedupMultiObj *obj_a,
+ const NMDedupMultiObj *obj_b)
{
- _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP4);
- id->routes_by_destination_ip4.plen = plen;
- memcpy (&id->routes_by_destination_ip4._misaligned_metric, &metric, sizeof (guint32));
- memcpy (&id->routes_by_destination_ip4._misaligned_network, &network, sizeof (guint32));
- return id;
+ return nmp_object_equal ((NMPObject *) obj_a,
+ (NMPObject *) obj_b);
}
-NMPCacheId *
-nmp_cache_id_init_routes_by_destination_ip6 (NMPCacheId *id,
- const struct in6_addr *network,
- guint8 plen,
- guint32 metric)
-{
- _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6);
- id->routes_by_destination_ip4.plen = plen;
- memcpy (&id->routes_by_destination_ip6._misaligned_metric, &metric, sizeof (guint32));
- memcpy (&id->routes_by_destination_ip6._misaligned_network, network ?: &nm_ip_addr_zero.addr6, sizeof (struct in6_addr));
- return id;
-}
+#define DEDUP_MULTI_OBJ_CLASS_INIT() \
+ { \
+ .obj_clone = _vt_dedup_obj_clone, \
+ .obj_destroy = _vt_dedup_obj_destroy, \
+ .obj_full_hash = _vt_dedup_obj_full_hash, \
+ .obj_full_equal = _vt_dedup_obj_full_equal, \
+ }
/*****************************************************************************/
-static gboolean
-_nmp_object_init_cache_id (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id)
+static NMDedupMultiIdxType *
+_idx_type_get (const NMPCache *cache, NMPCacheIdType cache_id_type)
{
- const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj);
+ nm_assert (cache);
+ nm_assert (cache_id_type > NMP_CACHE_ID_TYPE_NONE);
+ nm_assert (cache_id_type <= NMP_CACHE_ID_TYPE_MAX);
+ nm_assert ((int) cache_id_type - 1 >= 0);
+ nm_assert ((int) cache_id_type - 1 < G_N_ELEMENTS (cache->idx_types));
- switch (id_type) {
- case NMP_CACHE_ID_TYPE_OBJECT_TYPE:
- *out_id = nmp_cache_id_init_object_type (id, klass->obj_type, FALSE);
- return TRUE;
- case NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY:
- if (nmp_object_is_visible (obj))
- *out_id = nmp_cache_id_init_object_type (id, klass->obj_type, TRUE);
- else
- *out_id = NULL;
- return TRUE;
- default:
- return klass->cmd_obj_init_cache_id
- && klass->cmd_obj_init_cache_id (obj, id_type, id, out_id);
- }
+ return (NMDedupMultiIdxType *) &cache->idx_types[cache_id_type - 1];
}
-static const guint8 _supported_cache_ids_link[] = {
- NMP_CACHE_ID_TYPE_OBJECT_TYPE,
- NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY,
- NMP_CACHE_ID_TYPE_LINK_BY_IFNAME,
- 0,
-};
-
-static gboolean
-_vt_cmd_obj_init_cache_id_link (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id)
+gboolean
+nmp_cache_use_udev_get (const NMPCache *cache)
{
- switch (id_type) {
- case NMP_CACHE_ID_TYPE_LINK_BY_IFNAME:
- if (obj->link.name[0]) {
- *out_id = nmp_cache_id_init_link_by_ifname (id, obj->link.name);
- return TRUE;
- }
- break;
- default:
- return FALSE;
- }
- *out_id = NULL;
- return TRUE;
-}
-
-static const guint8 _supported_cache_ids_ipx_address[] = {
- NMP_CACHE_ID_TYPE_OBJECT_TYPE,
- NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY,
- NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX,
- 0,
-};
-
-static gboolean
-_vt_cmd_obj_init_cache_id_ipx_address (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id)
-{
- switch (id_type) {
- case NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX:
- if (nmp_object_is_visible (obj)) {
- nm_assert (obj->object.ifindex > 0);
- *out_id = nmp_cache_id_init_addrroute_visible_by_ifindex (id, NMP_OBJECT_GET_TYPE (obj), obj->object.ifindex);
- return TRUE;
- }
- break;
- default:
- return FALSE;
- }
- *out_id = NULL;
- return TRUE;
-}
-
-static const guint8 _supported_cache_ids_ip4_route[] = {
- NMP_CACHE_ID_TYPE_OBJECT_TYPE,
- NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY,
- NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX,
- NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT,
- NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT,
- NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT,
- NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT,
- NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP4,
- 0,
-};
-
-static const guint8 _supported_cache_ids_ip6_route[] = {
- NMP_CACHE_ID_TYPE_OBJECT_TYPE,
- NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY,
- NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX,
- NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT,
- NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT,
- NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT,
- NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT,
- NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6,
- 0,
-};
+ g_return_val_if_fail (cache, TRUE);
-static gboolean
-_vt_cmd_obj_init_cache_id_ipx_route (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id)
-{
- switch (id_type) {
- case NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX:
- if (nmp_object_is_visible (obj)) {
- nm_assert (obj->object.ifindex > 0);
- *out_id = nmp_cache_id_init_addrroute_visible_by_ifindex (id, NMP_OBJECT_GET_TYPE (obj), obj->object.ifindex);
- return TRUE;
- }
- break;
- case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT:
- if ( nmp_object_is_visible (obj)
- && !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj->ip_route)) {
- nm_assert (obj->object.ifindex > 0);
- *out_id = nmp_cache_id_init_routes_visible (id, NMP_OBJECT_GET_TYPE (obj), FALSE, TRUE, 0);
- return TRUE;
- }
- break;
- case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT:
- if ( nmp_object_is_visible (obj)
- && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj->ip_route)) {
- nm_assert (obj->object.ifindex > 0);
- *out_id = nmp_cache_id_init_routes_visible (id, NMP_OBJECT_GET_TYPE (obj), TRUE, FALSE, 0);
- return TRUE;
- }
- break;
- case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT:
- if ( nmp_object_is_visible (obj)
- && !NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj->ip_route)) {
- nm_assert (obj->object.ifindex > 0);
- *out_id = nmp_cache_id_init_routes_visible (id, NMP_OBJECT_GET_TYPE (obj), FALSE, TRUE, obj->object.ifindex);
- return TRUE;
- }
- break;
- case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT:
- if ( nmp_object_is_visible (obj)
- && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj->ip_route)) {
- nm_assert (obj->object.ifindex > 0);
- *out_id = nmp_cache_id_init_routes_visible (id, NMP_OBJECT_GET_TYPE (obj), TRUE, FALSE, obj->object.ifindex);
- return TRUE;
- }
- break;
- case NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP4:
- if (NMP_OBJECT_GET_CLASS (obj)->obj_type == NMP_OBJECT_TYPE_IP4_ROUTE) {
- *out_id = nmp_cache_id_init_routes_by_destination_ip4 (id, obj->ip4_route.network, obj->ip_route.plen, obj->ip_route.metric);
- return TRUE;
- }
- return FALSE;
- case NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6:
- if (NMP_OBJECT_GET_CLASS (obj)->obj_type == NMP_OBJECT_TYPE_IP6_ROUTE) {
- *out_id = nmp_cache_id_init_routes_by_destination_ip6 (id, &obj->ip6_route.network, obj->ip_route.plen, obj->ip_route.metric);
- return TRUE;
- }
- return FALSE;
- default:
- return FALSE;
- }
- *out_id = NULL;
- return TRUE;
+ return cache->use_udev;
}
/*****************************************************************************/
gboolean
-nmp_cache_use_udev_get (const NMPCache *cache)
+nmp_cache_link_connected_for_slave (int ifindex_master, const NMPObject *slave)
{
- g_return_val_if_fail (cache, TRUE);
+ nm_assert (NMP_OBJECT_GET_TYPE (slave) == NMP_OBJECT_TYPE_LINK);
- return cache->use_udev;
+ return ifindex_master > 0
+ && slave->link.master == ifindex_master
+ && slave->link.connected
+ && nmp_object_is_visible (slave);
}
-/*****************************************************************************/
-
/**
* nmp_cache_link_connected_needs_toggle:
* @cache: the platform cache
@@ -1340,9 +1371,7 @@ nmp_cache_use_udev_get (const NMPCache *cache)
gboolean
nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *master, const NMPObject *potential_slave, const NMPObject *ignore_slave)
{
- const NMPlatformLink *const *links;
gboolean is_lower_up = FALSE;
- guint len, i;
if ( !master
|| NMP_OBJECT_GET_TYPE (master) != NMP_OBJECT_TYPE_LINK
@@ -1360,27 +1389,23 @@ nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *m
potential_slave = NULL;
if ( potential_slave
- && nmp_object_is_visible (potential_slave)
- && potential_slave->link.ifindex > 0
- && potential_slave->link.master == master->link.ifindex
- && potential_slave->link.connected) {
+ && nmp_cache_link_connected_for_slave (master->link.ifindex, potential_slave))
is_lower_up = TRUE;
- } else {
- NMPCacheId cache_id;
-
- links = (const NMPlatformLink *const *) nmp_cache_lookup_multi (cache, nmp_cache_id_init_object_type (&cache_id, NMP_OBJECT_TYPE_LINK, FALSE), &len);
- for (i = 0; i < len; i++) {
- const NMPlatformLink *link = links[i];
+ else {
+ NMPLookup lookup;
+ NMDedupMultiIter iter;
+ const NMPlatformLink *link = NULL;
+
+ nmp_cache_iter_for_each_link (&iter,
+ nmp_cache_lookup (cache,
+ nmp_lookup_init_obj_type (&lookup,
+ NMP_OBJECT_TYPE_LINK)),
+ &link) {
const NMPObject *obj = NMP_OBJECT_UP_CAST ((NMPlatformObject *) link);
- nm_assert (NMP_OBJECT_GET_TYPE (NMP_OBJECT_UP_CAST ((NMPlatformObject *) link)) == NMP_OBJECT_TYPE_LINK);
-
if ( (!potential_slave || potential_slave->link.ifindex != link->ifindex)
&& ignore_slave != obj
- && link->ifindex > 0
- && link->master == master->link.ifindex
- && nmp_object_is_visible (obj)
- && link->connected) {
+ && nmp_cache_link_connected_for_slave (master->link.ifindex, obj)) {
is_lower_up = TRUE;
break;
}
@@ -1423,40 +1448,46 @@ nmp_cache_link_connected_needs_toggle_by_ifindex (const NMPCache *cache, int mas
/*****************************************************************************/
-const NMPlatformObject *const *
-nmp_cache_lookup_multi (const NMPCache *cache, const NMPCacheId *cache_id, guint *out_len)
+static const NMDedupMultiEntry *
+_lookup_obj (const NMPCache *cache, const NMPObject *obj)
{
- return (const NMPlatformObject *const *) nm_multi_index_lookup (cache->idx_multi,
- (const NMMultiIndexId *) cache_id,
- out_len);
-}
-
-GArray *
-nmp_cache_lookup_multi_to_array (const NMPCache *cache, NMPObjectType obj_type, const NMPCacheId *cache_id)
-{
- const NMPClass *klass = nmp_class_from_type (obj_type);
- guint len, i;
- const NMPlatformObject *const *objects;
- GArray *array;
-
- g_return_val_if_fail (klass, NULL);
+ const NMDedupMultiEntry *entry;
- objects = nmp_cache_lookup_multi (cache, cache_id, &len);
- array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len);
+ nm_assert (cache);
+ nm_assert (NMP_OBJECT_IS_VALID (obj));
- for (i = 0; i < len; i++) {
- nm_assert (NMP_OBJECT_GET_CLASS (NMP_OBJECT_UP_CAST (objects[i])) == klass);
- g_array_append_vals (array, objects[i], 1);
- }
- return array;
+ entry = nm_dedup_multi_index_lookup_obj (cache->multi_idx,
+ _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE),
+ obj);
+ nm_assert (!entry
+ || ( NMP_OBJECT_IS_VALID (entry->obj)
+ && NMP_OBJECT_GET_CLASS (entry->obj) == NMP_OBJECT_GET_CLASS (obj)));
+ return entry;
}
const NMPObject *
nmp_cache_lookup_obj (const NMPCache *cache, const NMPObject *obj)
{
+ const NMDedupMultiEntry *entry;
+
+ g_return_val_if_fail (cache, NULL);
g_return_val_if_fail (obj, NULL);
- return g_hash_table_lookup (cache->idx_main, obj);
+ entry = _lookup_obj (cache, obj);
+ return entry ? entry->obj : NULL;
+}
+
+const NMDedupMultiEntry *
+nmp_cache_lookup_entry_link (const NMPCache *cache, int ifindex)
+{
+ NMPObject obj_needle;
+
+ nm_assert (cache);
+
+ nmp_object_stackinit_id_link (&obj_needle, ifindex);
+ return nm_dedup_multi_index_lookup_obj (cache->multi_idx,
+ _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE),
+ &obj_needle);
}
const NMPObject *
@@ -1467,6 +1498,197 @@ nmp_cache_lookup_link (const NMPCache *cache, int ifindex)
return nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&obj_needle, ifindex));
}
+/*****************************************************************************/
+
+const NMDedupMultiHeadEntry *
+nmp_cache_lookup_all (const NMPCache *cache,
+ NMPCacheIdType cache_id_type,
+ const NMPObject *select_obj)
+{
+ nm_assert (cache);
+ nm_assert (NMP_OBJECT_IS_VALID (select_obj));
+
+ return nm_dedup_multi_index_lookup_head (cache->multi_idx,
+ _idx_type_get (cache, cache_id_type),
+ select_obj);
+}
+
+static const NMPLookup *
+_L (const NMPLookup *lookup)
+{
+#if NM_MORE_ASSERTS
+ DedupMultiIdxType idx_type;
+
+ nm_assert (lookup);
+ _dedup_multi_idx_type_init (&idx_type, lookup->cache_id_type);
+ nm_assert (idx_type.parent.klass->idx_obj_partitionable ((NMDedupMultiIdxType *) &idx_type, (NMDedupMultiObj *) &lookup->selector_obj));
+ nm_assert (idx_type.parent.klass->idx_obj_partition_hash ((NMDedupMultiIdxType *) &idx_type, (NMDedupMultiObj *) &lookup->selector_obj) > 0);
+#endif
+ return lookup;
+}
+
+const NMPLookup *
+nmp_lookup_init_obj_type (NMPLookup *lookup,
+ NMPObjectType obj_type)
+{
+ NMPObject *o;
+
+ nm_assert (lookup);
+
+ switch (obj_type) {
+ case NMP_OBJECT_TYPE_LINK:
+ case NMP_OBJECT_TYPE_IP4_ADDRESS:
+ case NMP_OBJECT_TYPE_IP6_ADDRESS:
+ case NMP_OBJECT_TYPE_IP4_ROUTE:
+ case NMP_OBJECT_TYPE_IP6_ROUTE:
+ o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
+ lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE;
+ return _L (lookup);
+ default:
+ nm_assert_not_reached ();
+ return NULL;
+ }
+}
+
+const NMPLookup *
+nmp_lookup_init_link_by_ifname (NMPLookup *lookup,
+ const char *ifname)
+{
+ NMPObject *o;
+
+ nm_assert (lookup);
+ nm_assert (ifname);
+ nm_assert (strlen (ifname) < IFNAMSIZ);
+
+ o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_LINK);
+ if (g_strlcpy (o->link.name, ifname, sizeof (o->link.name)) >= sizeof (o->link.name))
+ g_return_val_if_reached (NULL);
+ lookup->cache_id_type = NMP_CACHE_ID_TYPE_LINK_BY_IFNAME;
+ return _L (lookup);
+}
+
+const NMPLookup *
+nmp_lookup_init_addrroute (NMPLookup *lookup,
+ NMPObjectType obj_type,
+ int ifindex)
+{
+ NMPObject *o;
+
+ nm_assert (lookup);
+ nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS,
+ NMP_OBJECT_TYPE_IP6_ADDRESS,
+ NMP_OBJECT_TYPE_IP4_ROUTE,
+ NMP_OBJECT_TYPE_IP6_ROUTE));
+
+ if (ifindex <= 0) {
+ return nmp_lookup_init_obj_type (lookup,
+ obj_type);
+ }
+
+ o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
+ o->object.ifindex = ifindex;
+ lookup->cache_id_type = NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX;
+ return _L (lookup);
+}
+
+const NMPLookup *
+nmp_lookup_init_route_visible (NMPLookup *lookup,
+ NMPObjectType obj_type,
+ int ifindex,
+ gboolean only_default)
+{
+ NMPObject *o;
+
+ nm_assert (lookup);
+ nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE,
+ NMP_OBJECT_TYPE_IP6_ROUTE));
+
+ if (!only_default) {
+ return nmp_lookup_init_addrroute (lookup,
+ obj_type,
+ ifindex);
+ }
+
+ if (ifindex > 0) {
+ /* there is no index to lookup a default-route by ifindex.
+ * You have to lookup all default-routes, and filter yourself */
+ g_return_val_if_reached (NULL);
+ }
+
+ o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type);
+ o->object.ifindex = 1;
+ lookup->cache_id_type = NMP_CACHE_ID_TYPE_DEFAULT_ROUTES;
+ return _L (lookup);
+}
+
+const NMPLookup *
+nmp_lookup_init_route_by_dest (NMPLookup *lookup,
+ int addr_family,
+ gconstpointer network,
+ guint plen,
+ guint32 metric)
+{
+ NMPObject *o;
+
+ nm_assert (lookup);
+
+ switch (addr_family) {
+ case AF_INET:
+ o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP4_ROUTE);
+ o->object.ifindex = 1;
+ o->ip_route.plen = plen;
+ o->ip_route.metric = metric;
+ if (network)
+ o->ip4_route.network = *((in_addr_t *) network);
+ lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION;
+ break;
+ case AF_INET6:
+ o = _nmp_object_stackinit_from_type (&lookup->selector_obj, NMP_OBJECT_TYPE_IP6_ROUTE);
+ o->object.ifindex = 1;
+ o->ip_route.plen = plen;
+ o->ip_route.metric = metric;
+ if (network)
+ o->ip6_route.network = *((struct in6_addr *) network);
+ lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION;
+ break;
+ default:
+ nm_assert_not_reached ();
+ return NULL;
+ }
+ return _L (lookup);
+}
+
+/*****************************************************************************/
+
+GArray *
+nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry,
+ NMPObjectType obj_type,
+ gboolean visible_only)
+{
+ const NMPClass *klass = nmp_class_from_type (obj_type);
+ NMDedupMultiIter iter;
+ const NMPObject *o;
+ GArray *array;
+
+ g_return_val_if_fail (klass, NULL);
+
+ array = g_array_sized_new (FALSE, FALSE,
+ klass->sizeof_public,
+ head_entry ? head_entry->len : 0);
+ nmp_cache_iter_for_each (&iter,
+ head_entry,
+ &o) {
+ nm_assert (NMP_OBJECT_GET_CLASS (o) == klass);
+ if ( visible_only
+ && !nmp_object_is_visible (o))
+ continue;
+ g_array_append_vals (array, &o->object, 1);
+ }
+ return array;
+}
+
+/*****************************************************************************/
+
/**
* nmp_cache_find_other_route_for_same_destination:
* @cache:
@@ -1482,32 +1704,36 @@ nmp_cache_lookup_link (const NMPCache *cache, int ifindex)
const NMPObject *
nmp_cache_find_other_route_for_same_destination (const NMPCache *cache, const NMPObject *route)
{
- NMPCacheId cache_id;
- const NMPlatformObject *const *list;
+ NMPLookup lookup;
+ NMDedupMultiIter iter;
+ const NMPObject *o = NULL;
nm_assert (cache);
switch (NMP_OBJECT_GET_TYPE (route)) {
case NMP_OBJECT_TYPE_IP4_ROUTE:
- nmp_cache_id_init_routes_by_destination_ip4 (&cache_id, route->ip4_route.network, route->ip_route.plen, route->ip_route.metric);
+ nmp_lookup_init_route_by_dest (&lookup,
+ AF_INET,
+ &route->ip4_route.network,
+ route->ip_route.plen,
+ route->ip_route.metric);
break;
case NMP_OBJECT_TYPE_IP6_ROUTE:
- nmp_cache_id_init_routes_by_destination_ip6 (&cache_id, &route->ip6_route.network, route->ip_route.plen, route->ip_route.metric);
+ nmp_lookup_init_route_by_dest (&lookup,
+ AF_INET6,
+ &route->ip6_route.network,
+ route->ip_route.plen,
+ route->ip_route.metric);
break;
default:
g_return_val_if_reached (NULL);
}
- list = nmp_cache_lookup_multi (cache, &cache_id, NULL);
- if (list) {
- for (; *list; list++) {
- const NMPObject *candidate = NMP_OBJECT_UP_CAST (*list);
-
- nm_assert (NMP_OBJECT_GET_CLASS (route) == NMP_OBJECT_GET_CLASS (candidate));
+ nmp_cache_iter_for_each (&iter, nmp_cache_lookup (cache, &lookup), &o) {
+ nm_assert (NMP_OBJECT_GET_CLASS (route) == NMP_OBJECT_GET_CLASS (o));
- if (!nmp_object_id_equal (route, candidate))
- return candidate;
- }
+ if (!nmp_object_id_equal (route, o))
+ return o;
}
return NULL;
}
@@ -1523,9 +1749,10 @@ nmp_cache_lookup_link_full (const NMPCache *cache,
{
NMPObject obj_needle;
const NMPObject *obj;
- const NMPlatformObject *const *list;
- guint i, len;
- NMPCacheId cache_id, *p_cache_id;
+ NMDedupMultiIter iter;
+ const NMDedupMultiHeadEntry *head_entry;
+ const NMPlatformLink *link = NULL;
+ NMPLookup lookup;
if (ifindex > 0) {
obj = nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&obj_needle, ifindex));
@@ -1540,18 +1767,17 @@ nmp_cache_lookup_link_full (const NMPCache *cache,
} else if (!ifname && !match_fn)
return NULL;
else {
- if ( ifname
- && strlen (ifname) <= sizeof (cache_id.link_by_ifname.ifname_short)) {
- p_cache_id = nmp_cache_id_init_link_by_ifname (&cache_id, ifname);
+ if (ifname) {
+ if (strlen (ifname) >= IFNAMSIZ)
+ return NULL;
+ nmp_lookup_init_link_by_ifname (&lookup, ifname);
ifname = NULL;
- } else {
- p_cache_id = nmp_cache_id_init_object_type (&cache_id, NMP_OBJECT_TYPE_LINK, visible_only);
- visible_only = FALSE;
- }
+ } else
+ nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK);
- list = nmp_cache_lookup_multi (cache, p_cache_id, &len);
- for (i = 0; i < len; i++) {
- obj = NMP_OBJECT_UP_CAST (list[i]);
+ head_entry = nmp_cache_lookup (cache, &lookup);
+ nmp_cache_iter_for_each_link (&iter, head_entry, &link) {
+ obj = NMP_OBJECT_UP_CAST (link);
if (visible_only && !nmp_object_is_visible (obj))
continue;
@@ -1568,190 +1794,255 @@ nmp_cache_lookup_link_full (const NMPCache *cache,
}
}
-GHashTable *
-nmp_cache_lookup_all_to_hash (const NMPCache *cache,
- NMPCacheId *cache_id,
- GHashTable *hash)
-{
- NMMultiIndexIdIter iter;
- gpointer plobj;
-
- nm_multi_index_id_iter_init (&iter, cache->idx_multi, (const NMMultiIndexId *) cache_id);
-
- if (nm_multi_index_id_iter_next (&iter, &plobj)) {
- if (!hash)
- hash = g_hash_table_new_full (NULL, NULL, (GDestroyNotify) nmp_object_unref, NULL);
-
- do {
- g_hash_table_add (hash, nmp_object_ref (NMP_OBJECT_UP_CAST (plobj)));
- } while (nm_multi_index_id_iter_next (&iter, &plobj));
- }
-
- return hash;
-}
-
/*****************************************************************************/
static void
-_nmp_cache_update_cache (NMPCache *cache, NMPObject *obj, gboolean remove)
-{
- const guint8 *id_type;
-
- for (id_type = NMP_OBJECT_GET_CLASS (obj)->supported_cache_ids; *id_type; id_type++) {
- NMPCacheId cache_id_storage;
- const NMPCacheId *cache_id;
-
- if (!_nmp_object_init_cache_id (obj, *id_type, &cache_id_storage, &cache_id))
- continue;
- if (!cache_id)
- continue;
-
- /* We don't put @obj itself into the multi index, but &obj->object. As of now, all
- * users expect a pointer to NMPlatformObject, not NMPObject.
- * You can use NMP_OBJECT_UP_CAST() to retrieve the original @obj pointer.
- *
- * If need be, we could determine based on @id_type which pointer we want to store. */
-
- if (remove) {
- if (!nm_multi_index_remove (cache->idx_multi, &cache_id->base, &obj->object))
- g_assert_not_reached ();
+_idxcache_update_box_move (NMPCache *cache,
+ NMPCacheIdType cache_id_type,
+ const NMPObject *obj_old,
+ const NMPObject *obj_new)
+{
+ const NMDedupMultiEntry *entry_new;
+ const NMDedupMultiEntry *entry_old;
+ const NMDedupMultiEntry *entry_order;
+ NMDedupMultiIdxType *idx_type;
+
+ nm_assert (obj_new || obj_old);
+ nm_assert (!obj_new || NMP_OBJECT_GET_TYPE (obj_new) != NMP_OBJECT_TYPE_UNKNOWN);
+ nm_assert (!obj_old || NMP_OBJECT_GET_TYPE (obj_old) != NMP_OBJECT_TYPE_UNKNOWN);
+ nm_assert (!obj_old || !obj_new || NMP_OBJECT_GET_CLASS (obj_new) == NMP_OBJECT_GET_CLASS (obj_old));
+ nm_assert (!obj_old || !obj_new || !nmp_object_equal (obj_new, obj_old));
+ nm_assert (!obj_new || obj_new == nm_dedup_multi_index_obj_find (cache->multi_idx, obj_new));
+ nm_assert (!obj_old || obj_old == nm_dedup_multi_index_obj_find (cache->multi_idx, obj_old));
+
+ idx_type = _idx_type_get (cache, cache_id_type);
+
+ if (obj_old) {
+ entry_old = nm_dedup_multi_index_lookup_obj (cache->multi_idx,
+ idx_type,
+ obj_old);
+ if (!obj_new) {
+ if (entry_old)
+ nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old);
+ return;
+ }
+ } else
+ entry_old = NULL;
+
+ if (obj_new) {
+ if ( obj_old
+ && nm_dedup_multi_idx_type_id_equal (idx_type, obj_old, obj_new)
+ && nm_dedup_multi_idx_type_partition_equal (idx_type, obj_old, obj_new)) {
+ /* optimize. We just looked up the @obj_old entry and @obj_new compares equal
+ * according to idx_obj_id_equal(). entry_new is the same as entry_old. */
+ entry_new = entry_old;
} else {
- if (!nm_multi_index_add (cache->idx_multi, &cache_id->base, &obj->object))
- g_assert_not_reached ();
+ entry_new = nm_dedup_multi_index_lookup_obj (cache->multi_idx,
+ idx_type,
+ obj_new);
}
- }
-}
-static void
-_nmp_cache_update_add (NMPCache *cache, NMPObject *obj)
-{
- nm_assert (!obj->is_cached);
- nmp_object_ref (obj);
- nm_assert (!nm_multi_index_lookup_first_by_value (cache->idx_multi, &obj->object));
- if (!nm_g_hash_table_add (cache->idx_main, obj))
- g_assert_not_reached ();
- obj->is_cached = TRUE;
- _nmp_cache_update_cache (cache, obj, FALSE);
-}
+ if (entry_new)
+ entry_order = entry_new;
+ else if ( entry_old
+ && nm_dedup_multi_idx_type_partition_equal (idx_type, entry_old->obj, obj_new))
+ entry_order = entry_old;
+ else
+ entry_order = NULL;
+ nm_dedup_multi_index_add_full (cache->multi_idx,
+ idx_type,
+ obj_new,
+ NM_DEDUP_MULTI_IDX_MODE_APPEND,
+ entry_order,
+ entry_new ?: NM_DEDUP_MULTI_ENTRY_MISSING,
+ entry_new ? entry_new->head : (entry_order ? entry_order->head : NULL),
+ &entry_new,
+ NULL);
-static void
-_nmp_cache_update_remove (NMPCache *cache, NMPObject *obj)
-{
- nm_assert (obj->is_cached);
- _nmp_cache_update_cache (cache, obj, TRUE);
- obj->is_cached = FALSE;
- if (!g_hash_table_remove (cache->idx_main, obj))
- g_assert_not_reached ();
+#if NM_MORE_ASSERTS
+ if (entry_new) {
+ nm_assert (idx_type->klass->idx_obj_partitionable);
+ nm_assert (idx_type->klass->idx_obj_partition_equal);
+ nm_assert (idx_type->klass->idx_obj_partitionable (idx_type, entry_new->obj));
+ nm_assert (idx_type->klass->idx_obj_partition_equal (idx_type, (gpointer) obj_new, entry_new->obj));
+ }
+#endif
+ } else
+ entry_new = NULL;
- /* @obj is possibly a dangling pointer at this point. No problem, multi-index doesn't dereference. */
- nm_assert (!nm_multi_index_lookup_first_by_value (cache->idx_multi, &obj->object));
+ if ( entry_old
+ && entry_old != entry_new)
+ nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old);
}
static void
-_nmp_cache_update_update (NMPCache *cache, NMPObject *obj, const NMPObject *new)
+_idxcache_update (NMPCache *cache,
+ const NMDedupMultiEntry *entry_old,
+ NMPObject *obj_new,
+ const NMDedupMultiEntry **out_entry_new)
{
- const guint8 *id_type;
+ const NMPClass *klass;
+ const guint8 *i_idx_type;
+ NMDedupMultiIdxType *idx_type_o = _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE);
+ const NMDedupMultiEntry *entry_new = NULL;
+ nm_auto_nmpobj const NMPObject *obj_old = NULL;
- nm_assert (NMP_OBJECT_GET_CLASS (obj) == NMP_OBJECT_GET_CLASS (new));
- nm_assert (obj->is_cached);
- nm_assert (!new->is_cached);
+ /* we update an object in the cache.
+ *
+ * Note that @entry_old MUST be what is currently tracked in multi_idx, and it must
+ * have the same ID as @obj_new. */
- for (id_type = NMP_OBJECT_GET_CLASS (obj)->supported_cache_ids; *id_type; id_type++) {
- NMPCacheId cache_id_storage_obj, cache_id_storage_new;
- const NMPCacheId *cache_id_obj, *cache_id_new;
+ nm_assert (cache);
+ nm_assert (entry_old || obj_new);
+ nm_assert (!obj_new || nmp_object_is_alive (obj_new));
+ nm_assert (!entry_old || entry_old == nm_dedup_multi_index_lookup_obj (cache->multi_idx, idx_type_o, entry_old->obj));
+ nm_assert (!obj_new || entry_old == nm_dedup_multi_index_lookup_obj (cache->multi_idx, idx_type_o, obj_new));
+ nm_assert (!entry_old || entry_old->head->idx_type == idx_type_o);
+ nm_assert ( !entry_old
+ || !obj_new
+ || nm_dedup_multi_idx_type_partition_equal (idx_type_o, entry_old->obj, obj_new));
+ nm_assert ( !entry_old
+ || !obj_new
+ || nm_dedup_multi_idx_type_id_equal (idx_type_o, entry_old->obj, obj_new));
+ nm_assert ( !entry_old
+ || !obj_new
+ || ( obj_new->parent.klass == ((const NMPObject *) entry_old->obj)->parent.klass
+ && !obj_new->parent.klass->obj_full_equal ((NMDedupMultiObj *) obj_new, entry_old->obj)));
+
+ /* keep a reference to the pre-existing entry */
+ if (entry_old)
+ obj_old = nmp_object_ref (entry_old->obj);
+
+ /* first update the main index NMP_CACHE_ID_TYPE_OBJECT_TYPE.
+ * We already know the pre-existing @entry old, so all that
+ * nm_dedup_multi_index_add_full() effectively does, is update the
+ * obj reference.
+ *
+ * We also get the new boxed object, which we need below. */
+ if (obj_new) {
+ nm_auto_nmpobj NMPObject *obj_old2 = NULL;
+
+ nm_dedup_multi_index_add_full (cache->multi_idx,
+ idx_type_o,
+ obj_new,
+ NM_DEDUP_MULTI_IDX_MODE_APPEND,
+ NULL,
+ entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING,
+ NULL,
+ &entry_new,
+ (const NMDedupMultiObj **) &obj_old2);
+ nm_assert (entry_new);
+ nm_assert (obj_old == obj_old2);
+ nm_assert (!entry_old || entry_old == entry_new);
+ } else
+ nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old);
- if (!_nmp_object_init_cache_id (obj, *id_type, &cache_id_storage_obj, &cache_id_obj))
+ /* now update all other indexes. We know the previously boxed entry, and the
+ * newly boxed one. */
+ klass = NMP_OBJECT_GET_CLASS (entry_new ? entry_new->obj : obj_old);
+ for (i_idx_type = klass->supported_cache_ids; *i_idx_type; i_idx_type++) {
+ NMPCacheIdType id_type = *i_idx_type;
+
+ if (id_type == NMP_CACHE_ID_TYPE_OBJECT_TYPE)
continue;
- if (!_nmp_object_init_cache_id (new, *id_type, &cache_id_storage_new, &cache_id_new))
- g_assert_not_reached ();
- if (!nm_multi_index_move (cache->idx_multi, (NMMultiIndexId *) cache_id_obj, (NMMultiIndexId *) cache_id_new, &obj->object))
- g_assert_not_reached ();
+ _idxcache_update_box_move (cache, id_type,
+ obj_old,
+ entry_new ? entry_new->obj : NULL);
}
- nmp_object_copy (obj, new, FALSE);
+
+ NM_SET_OUT (out_entry_new, entry_new);
}
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)
+nmp_cache_remove (NMPCache *cache,
+ const NMPObject *obj_needle,
+ gboolean equals_by_ptr,
+ const NMPObject **out_obj_old)
{
- NMPObject *old;
+ const NMDedupMultiEntry *entry_old;
+ const NMPObject *obj_old;
- nm_assert (NMP_OBJECT_IS_VALID (obj));
+ entry_old = _lookup_obj (cache, obj_needle);
- old = g_hash_table_lookup (cache->idx_main, obj);
- if (!old) {
- if (out_obj)
- *out_obj = NULL;
- if (out_was_visible)
- *out_was_visible = FALSE;
+ if (!entry_old) {
+ NM_SET_OUT (out_obj_old, NULL);
return NMP_CACHE_OPS_UNCHANGED;
}
- if (out_obj)
- *out_obj = nmp_object_ref (old);
- if (out_was_visible)
- *out_was_visible = nmp_object_is_visible (old);
- if (equals_by_ptr && old != obj) {
+ obj_old = entry_old->obj;
+
+ NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
+
+ if ( equals_by_ptr
+ && obj_old != obj_needle) {
/* We found an identical object, but we only delete it if it's the same pointer as
- * @obj. */
+ * @obj_needle. */
return NMP_CACHE_OPS_UNCHANGED;
}
- if (pre_hook)
- pre_hook (cache, old, NULL, NMP_CACHE_OPS_REMOVED, user_data);
- _nmp_cache_update_remove (cache, old);
+ _idxcache_update (cache, entry_old, NULL, NULL);
return NMP_CACHE_OPS_REMOVED;
}
NMPCacheOpsType
-nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj_needle, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data)
+nmp_cache_remove_netlink (NMPCache *cache,
+ const NMPObject *obj_needle,
+ const NMPObject **out_obj_old,
+ const NMPObject **out_obj_new)
{
- if (NMP_OBJECT_GET_TYPE (obj_needle) == NMP_OBJECT_TYPE_LINK) {
- NMPObject *old;
- nm_auto_nmpobj NMPObject *obj = NULL;
+ const NMDedupMultiEntry *entry_old;
+ const NMDedupMultiEntry *entry_new = NULL;
+ const NMPObject *obj_old;
+ NMPObject *obj_new;
+
+ entry_old = _lookup_obj (cache, obj_needle);
+
+ if (!entry_old) {
+ NM_SET_OUT (out_obj_old, NULL);
+ NM_SET_OUT (out_obj_new, NULL);
+ return NMP_CACHE_OPS_UNCHANGED;
+ }
+
+ obj_old = entry_old->obj;
+ if (NMP_OBJECT_GET_TYPE (obj_needle) == NMP_OBJECT_TYPE_LINK) {
/* For nmp_cache_remove_netlink() we have an incomplete @obj_needle instance to be
* removed from netlink. Link objects are alive without being in netlink when they
* have a udev-device. All we want to do in this case is clear the netlink.is_in_netlink
* flag. */
- old = (NMPObject *) nmp_cache_lookup_link (cache, obj_needle->link.ifindex);
- if (!old) {
- if (out_obj)
- *out_obj = NULL;
- if (out_was_visible)
- *out_was_visible = FALSE;
- return NMP_CACHE_OPS_UNCHANGED;
- }
-
- if (out_obj)
- *out_obj = nmp_object_ref (old);
- if (out_was_visible)
- *out_was_visible = nmp_object_is_visible (old);
+ NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
- if (!old->_link.netlink.is_in_netlink) {
- nm_assert (old->_link.udev.device);
+ if (!obj_old->_link.netlink.is_in_netlink) {
+ nm_assert (obj_old->_link.udev.device);
+ NM_SET_OUT (out_obj_new, nmp_object_ref (obj_old));
return NMP_CACHE_OPS_UNCHANGED;
}
- if (!old->_link.udev.device) {
- /* the update would make @old invalid. Remove it. */
- if (pre_hook)
- pre_hook (cache, old, NULL, NMP_CACHE_OPS_REMOVED, user_data);
- _nmp_cache_update_remove (cache, old);
+ if (!obj_old->_link.udev.device) {
+ /* the update would make @obj_old invalid. Remove it. */
+ _idxcache_update (cache, entry_old, NULL, NULL);
+ NM_SET_OUT (out_obj_new, NULL);
return NMP_CACHE_OPS_REMOVED;
}
- obj = nmp_object_clone (old, FALSE);
- obj->_link.netlink.is_in_netlink = FALSE;
+ obj_new = nmp_object_clone (obj_old, FALSE);
+ obj_new->_link.netlink.is_in_netlink = FALSE;
- _nmp_object_fixup_link_master_connected (obj, cache);
- _nmp_object_fixup_link_udev_fields (obj, cache->use_udev);
+ _nmp_object_fixup_link_master_connected (&obj_new, NULL, cache);
+ _nmp_object_fixup_link_udev_fields (&obj_new, NULL, cache->use_udev);
- if (pre_hook)
- pre_hook (cache, old, obj, NMP_CACHE_OPS_UPDATED, user_data);
- _nmp_cache_update_update (cache, old, obj);
+ _idxcache_update (cache,
+ entry_old,
+ obj_new,
+ &entry_new);
+ NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED;
- } else
- return nmp_cache_remove (cache, obj_needle, FALSE, out_obj, out_was_visible, pre_hook, user_data);
+ }
+
+ NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
+ NM_SET_OUT (out_obj_new, NULL);
+ _idxcache_update (cache, entry_old, NULL, NULL);
+ return NMP_CACHE_OPS_REMOVED;
}
/**
@@ -1779,244 +2070,250 @@ nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj_needle, NMPObjec
* Returns: how the cache changed.
**/
NMPCacheOpsType
-nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data)
+nmp_cache_update_netlink (NMPCache *cache,
+ NMPObject *obj_hand_over,
+ const NMPObject **out_obj_old,
+ const NMPObject **out_obj_new)
{
- NMPObject *old;
-
- nm_assert (NMP_OBJECT_IS_VALID (obj));
- nm_assert (!NMP_OBJECT_IS_STACKINIT (obj));
- nm_assert (!obj->is_cached);
+ const NMDedupMultiEntry *entry_old;
+ const NMDedupMultiEntry *entry_new;
+ const NMPObject *obj_old;
+ gboolean is_alive;
+ nm_assert (cache);
+ nm_assert (NMP_OBJECT_IS_VALID (obj_hand_over));
+ nm_assert (!NMP_OBJECT_IS_STACKINIT (obj_hand_over));
/* A link object from netlink must have the udev related fields unset.
* We could implement to handle that, but there is no need to support such
* a use-case */
- nm_assert (NMP_OBJECT_GET_TYPE (obj) != NMP_OBJECT_TYPE_LINK ||
- ( !obj->_link.udev.device
- && !obj->link.driver));
+ nm_assert (NMP_OBJECT_GET_TYPE (obj_hand_over) != NMP_OBJECT_TYPE_LINK ||
+ ( !obj_hand_over->_link.udev.device
+ && !obj_hand_over->link.driver));
+ nm_assert (nm_dedup_multi_index_obj_find (cache->multi_idx, obj_hand_over) != obj_hand_over);
- old = g_hash_table_lookup (cache->idx_main, obj);
+ entry_old = _lookup_obj (cache, obj_hand_over);
- if (out_obj)
- *out_obj = NULL;
- if (out_was_visible)
- *out_was_visible = FALSE;
+ if (!entry_old) {
- if (!old) {
- if (!nmp_object_is_alive (obj))
- return NMP_CACHE_OPS_UNCHANGED;
+ NM_SET_OUT (out_obj_old, NULL);
- if (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK) {
- _nmp_object_fixup_link_master_connected (obj, cache);
- _nmp_object_fixup_link_udev_fields (obj, cache->use_udev);
+ if (!nmp_object_is_alive (obj_hand_over)) {
+ NM_SET_OUT (out_obj_new, NULL);
+ return NMP_CACHE_OPS_UNCHANGED;
}
- if (out_obj)
- *out_obj = nmp_object_ref (obj);
+ if (NMP_OBJECT_GET_TYPE (obj_hand_over) == NMP_OBJECT_TYPE_LINK) {
+ _nmp_object_fixup_link_master_connected (&obj_hand_over, NULL, cache);
+ _nmp_object_fixup_link_udev_fields (&obj_hand_over, NULL, cache->use_udev);
+ }
- if (pre_hook)
- pre_hook (cache, NULL, obj, NMP_CACHE_OPS_ADDED, user_data);
- _nmp_cache_update_add (cache, obj);
+ _idxcache_update (cache,
+ entry_old,
+ obj_hand_over,
+ &entry_new);
+ NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_ADDED;
- } else if (old == obj) {
- /* updating a cached object inplace is not supported because the object contributes to hash-key
- * for NMMultiIndex. Modifying an object that is inside NMMultiIndex means that these
- * keys change.
- * The problem is, that for a given object NMMultiIndex does not support (efficient)
- * reverse lookup to get all the NMPCacheIds to which it belongs. If that would be implemented,
- * it would be possible to implement inplace-update.
- *
- * There is an un-optimized reverse lookup via nm_multi_index_iter_init(), but we don't want
- * that because we might have a large number of indexes to search.
- *
- * We could add efficient reverse lookup by adding a reverse index to NMMultiIndex. But that
- * also adds some cost to support an (uncommon?) usage pattern.
- *
- * Instead we just don't support it, instead we expect the user to
- * create a new instance from netlink.
- *
- * TL;DR: a cached object must never be modified.
- */
- g_assert_not_reached ();
- } else {
- gboolean is_alive = FALSE;
-
- nm_assert (old->is_cached);
-
- if (out_obj)
- *out_obj = nmp_object_ref (old);
- if (out_was_visible)
- *out_was_visible = nmp_object_is_visible (old);
-
- if (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK) {
- if (!obj->_link.netlink.is_in_netlink) {
- if (!old->_link.netlink.is_in_netlink) {
- nm_assert (old->_link.udev.device);
- return NMP_CACHE_OPS_UNCHANGED;
- }
- if (old->_link.udev.device) {
- /* @obj is not in netlink.
- *
- * This is similar to nmp_cache_remove_netlink(), but there we preserve the
- * preexisting netlink properties. The use case of that is when kernel_get_object()
- * cannot load an object (based on the id of a needle).
- *
- * Here we keep the data provided from @obj. The usecase is when receiving
- * a valid @obj instance from netlink with RTM_DELROUTE.
- */
- is_alive = TRUE;
- }
- } else
- is_alive = TRUE;
+ }
- if (is_alive) {
- _nmp_object_fixup_link_master_connected (obj, cache);
+ obj_old = entry_old->obj;
- /* Merge the netlink parts with what we have from udev. */
- udev_device_unref (obj->_link.udev.device);
- obj->_link.udev.device = old->_link.udev.device ? udev_device_ref (old->_link.udev.device) : NULL;
- _nmp_object_fixup_link_udev_fields (obj, cache->use_udev);
+ if (NMP_OBJECT_GET_TYPE (obj_hand_over) == NMP_OBJECT_TYPE_LINK) {
+ if (!obj_hand_over->_link.netlink.is_in_netlink) {
+ if (!obj_old->_link.netlink.is_in_netlink) {
+ nm_assert (obj_old->_link.udev.device);
+ NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
+ NM_SET_OUT (out_obj_new, nmp_object_ref (obj_old));
+ return NMP_CACHE_OPS_UNCHANGED;
}
+ if (obj_old->_link.udev.device) {
+ /* @obj_hand_over is not in netlink.
+ *
+ * This is similar to nmp_cache_remove_netlink(), but there we preserve the
+ * preexisting netlink properties. The use case of that is when kernel_get_object()
+ * cannot load an object (based on the id of a needle).
+ *
+ * Here we keep the data provided from @obj_hand_over. The usecase is when receiving
+ * a valid @obj_hand_over instance from netlink with RTM_DELROUTE.
+ */
+ is_alive = TRUE;
+ } else
+ is_alive = FALSE;
} else
- is_alive = nmp_object_is_alive (obj);
+ is_alive = TRUE;
- if (!is_alive) {
- /* the update would make @old invalid. Remove it. */
- if (pre_hook)
- pre_hook (cache, old, NULL, NMP_CACHE_OPS_REMOVED, user_data);
- _nmp_cache_update_remove (cache, old);
- return NMP_CACHE_OPS_REMOVED;
+ if (is_alive) {
+ _nmp_object_fixup_link_master_connected (&obj_hand_over, NULL, cache);
+
+ /* Merge the netlink parts with what we have from udev. */
+ udev_device_unref (obj_hand_over->_link.udev.device);
+ obj_hand_over->_link.udev.device = obj_old->_link.udev.device ? udev_device_ref (obj_old->_link.udev.device) : NULL;
+ _nmp_object_fixup_link_udev_fields (&obj_hand_over, NULL, cache->use_udev);
+
+ if (obj_hand_over->_link.netlink.lnk) {
+ nm_auto_nmpobj const NMPObject *lnk_old = obj_hand_over->_link.netlink.lnk;
+
+ /* let's dedup/intern the lnk object. */
+ obj_hand_over->_link.netlink.lnk = nm_dedup_multi_index_obj_intern (cache->multi_idx, lnk_old);
+ }
}
+ } else
+ is_alive = nmp_object_is_alive (obj_hand_over);
- if (nmp_object_equal (old, obj))
- return NMP_CACHE_OPS_UNCHANGED;
+ NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
- if (pre_hook)
- pre_hook (cache, old, obj, NMP_CACHE_OPS_UPDATED, user_data);
- _nmp_cache_update_update (cache, old, obj);
- return NMP_CACHE_OPS_UPDATED;
+ if (!is_alive) {
+ /* the update would make @obj_old invalid. Remove it. */
+ _idxcache_update (cache, entry_old, NULL, NULL);
+ NM_SET_OUT (out_obj_new, NULL);
+ return NMP_CACHE_OPS_REMOVED;
+ }
+
+ if (nmp_object_equal (obj_old, obj_hand_over)) {
+ nm_dedup_multi_entry_set_dirty (entry_old, FALSE);
+ NM_SET_OUT (out_obj_new, nmp_object_ref (obj_old));
+ return NMP_CACHE_OPS_UNCHANGED;
}
+
+ _idxcache_update (cache,
+ entry_old,
+ obj_hand_over,
+ &entry_new);
+ NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
+ return NMP_CACHE_OPS_UPDATED;
}
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)
+nmp_cache_update_link_udev (NMPCache *cache,
+ int ifindex,
+ struct udev_device *udevice,
+ const NMPObject **out_obj_old,
+ const NMPObject **out_obj_new)
{
- NMPObject *old;
- nm_auto_nmpobj NMPObject *obj = NULL;
-
- old = (NMPObject *) nmp_cache_lookup_link (cache, ifindex);
+ const NMPObject *obj_old;
+ nm_auto_nmpobj NMPObject *obj_new = NULL;
+ const NMDedupMultiEntry *entry_old;
+ const NMDedupMultiEntry *entry_new;
- if (out_obj)
- *out_obj = NULL;
- if (out_was_visible)
- *out_was_visible = FALSE;
+ entry_old = nmp_cache_lookup_entry_link (cache, ifindex);
- if (!old) {
- if (!udevice)
+ if (!entry_old) {
+ if (!udevice) {
+ NM_SET_OUT (out_obj_old, NULL);
+ NM_SET_OUT (out_obj_new, NULL);
return NMP_CACHE_OPS_UNCHANGED;
+ }
- obj = nmp_object_new (NMP_OBJECT_TYPE_LINK, NULL);
- obj->link.ifindex = ifindex;
- obj->_link.udev.device = udev_device_ref (udevice);
-
- _nmp_object_fixup_link_udev_fields (obj, cache->use_udev);
-
- nm_assert (nmp_object_is_alive (obj));
+ obj_new = nmp_object_new (NMP_OBJECT_TYPE_LINK, NULL);
+ obj_new->link.ifindex = ifindex;
+ obj_new->_link.udev.device = udev_device_ref (udevice);
- if (out_obj)
- *out_obj = nmp_object_ref (obj);
+ _nmp_object_fixup_link_udev_fields (&obj_new, NULL, cache->use_udev);
- if (pre_hook)
- pre_hook (cache, NULL, obj, NMP_CACHE_OPS_ADDED, user_data);
- _nmp_cache_update_add (cache, obj);
+ _idxcache_update (cache,
+ NULL,
+ obj_new,
+ &entry_new);
+ NM_SET_OUT (out_obj_old, NULL);
+ NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_ADDED;
} else {
- nm_assert (old->is_cached);
-
- if (out_obj)
- *out_obj = nmp_object_ref (old);
- if (out_was_visible)
- *out_was_visible = nmp_object_is_visible (old);
+ obj_old = entry_old->obj;
+ NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
- if (old->_link.udev.device == udevice)
+ if (obj_old->_link.udev.device == udevice) {
+ NM_SET_OUT (out_obj_new, nmp_object_ref (obj_old));
return NMP_CACHE_OPS_UNCHANGED;
+ }
- if (!udevice && !old->_link.netlink.is_in_netlink) {
- /* the update would make @old invalid. Remove it. */
- if (pre_hook)
- pre_hook (cache, old, NULL, NMP_CACHE_OPS_REMOVED, user_data);
- _nmp_cache_update_remove (cache, old);
+ if (!udevice && !obj_old->_link.netlink.is_in_netlink) {
+ /* the update would make @obj_old invalid. Remove it. */
+ _idxcache_update (cache, entry_old, NULL, NULL);
+ NM_SET_OUT (out_obj_new, NULL);
return NMP_CACHE_OPS_REMOVED;
}
- obj = nmp_object_clone (old, FALSE);
-
- udev_device_unref (obj->_link.udev.device);
- obj->_link.udev.device = udevice ? udev_device_ref (udevice) : NULL;
+ obj_new = nmp_object_clone (obj_old, FALSE);
- _nmp_object_fixup_link_udev_fields (obj, cache->use_udev);
+ udev_device_unref (obj_new->_link.udev.device);
+ obj_new->_link.udev.device = udevice ? udev_device_ref (udevice) : NULL;
- nm_assert (nmp_object_is_alive (obj));
+ _nmp_object_fixup_link_udev_fields (&obj_new, NULL, cache->use_udev);
- if (pre_hook)
- pre_hook (cache, old, obj, NMP_CACHE_OPS_UPDATED, user_data);
- _nmp_cache_update_update (cache, old, obj);
+ _idxcache_update (cache,
+ entry_old,
+ obj_new,
+ &entry_new);
+ NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
return NMP_CACHE_OPS_UPDATED;
}
}
NMPCacheOpsType
-nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data)
+nmp_cache_update_link_master_connected (NMPCache *cache,
+ int ifindex,
+ const NMPObject **out_obj_old,
+ const NMPObject **out_obj_new)
{
- NMPObject *old;
- nm_auto_nmpobj NMPObject *obj = NULL;
+ const NMDedupMultiEntry *entry_old;
+ const NMDedupMultiEntry *entry_new = NULL;
+ const NMPObject *obj_old;
+ nm_auto_nmpobj NMPObject *obj_new = NULL;
+
+ entry_old = nmp_cache_lookup_entry_link (cache, ifindex);
- old = (NMPObject *) nmp_cache_lookup_link (cache, ifindex);
+ if (!entry_old) {
+ NM_SET_OUT (out_obj_old, NULL);
+ NM_SET_OUT (out_obj_new, NULL);
+ return NMP_CACHE_OPS_UNCHANGED;
+ }
- if (!old) {
- if (out_obj)
- *out_obj = NULL;
- if (out_was_visible)
- *out_was_visible = FALSE;
+ obj_old = entry_old->obj;
+ if (!nmp_cache_link_connected_needs_toggle (cache, obj_old, NULL, NULL)) {
+ NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
+ NM_SET_OUT (out_obj_new, nmp_object_ref (obj_old));
return NMP_CACHE_OPS_UNCHANGED;
}
- nm_assert (old->is_cached);
+ obj_new = nmp_object_clone (obj_old, FALSE);
+ obj_new->link.connected = !obj_old->link.connected;
- if (out_obj)
- *out_obj = nmp_object_ref (old);
- if (out_was_visible)
- *out_was_visible = nmp_object_is_visible (old);
+ NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old));
+ _idxcache_update (cache,
+ entry_old,
+ obj_new,
+ &entry_new);
+ NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj));
+ return NMP_CACHE_OPS_UPDATED;
+}
- if (!nmp_cache_link_connected_needs_toggle (cache, old, NULL, NULL))
- return NMP_CACHE_OPS_UNCHANGED;
+/*****************************************************************************/
- obj = nmp_object_clone (old, FALSE);
- obj->link.connected = !old->link.connected;
+void
+nmp_cache_dirty_set_all (NMPCache *cache, NMPObjectType obj_type)
+{
+ NMPObject obj_needle;
- nm_assert (nmp_object_is_alive (obj));
+ nm_assert (cache);
- if (pre_hook)
- pre_hook (cache, old, obj, NMP_CACHE_OPS_UPDATED, user_data);
- _nmp_cache_update_update (cache, old, obj);
- return NMP_CACHE_OPS_UPDATED;
+ nm_dedup_multi_index_dirty_set_head (cache->multi_idx,
+ _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE),
+ _nmp_object_stackinit_from_type (&obj_needle, obj_type));
}
/*****************************************************************************/
NMPCache *
-nmp_cache_new (gboolean use_udev)
-{
- NMPCache *cache = g_new (NMPCache, 1);
-
- cache->idx_main = g_hash_table_new_full ((GHashFunc) nmp_object_id_hash,
- (GEqualFunc) nmp_object_id_equal,
- (GDestroyNotify) nmp_object_unref,
- NULL);
- cache->idx_multi = nm_multi_index_new ((NMMultiIndexFuncHash) nmp_cache_id_hash,
- (NMMultiIndexFuncEqual) nmp_cache_id_equal,
- (NMMultiIndexFuncClone) nmp_cache_id_clone,
- (NMMultiIndexFuncDestroy) nmp_cache_id_destroy);
+nmp_cache_new (NMDedupMultiIndex *multi_idx, gboolean use_udev)
+{
+ NMPCache *cache = g_slice_new0 (NMPCache);
+ guint i;
+
+ for (i = NMP_CACHE_ID_TYPE_NONE + 1; i <= NMP_CACHE_ID_TYPE_MAX; i++)
+ _dedup_multi_idx_type_init ((DedupMultiIdxType *) _idx_type_get (cache, i), i);
+
+ cache->multi_idx = nm_dedup_multi_index_ref (multi_idx);
+
cache->use_udev = !!use_udev;
return cache;
}
@@ -2024,23 +2321,14 @@ nmp_cache_new (gboolean use_udev)
void
nmp_cache_free (NMPCache *cache)
{
- GHashTableIter iter;
- NMPObject *obj;
+ guint i;
- /* No need to cumbersomely remove the objects properly. They are not hooked up
- * in a complicated way, we can just unref them together with cache->idx_main.
- *
- * But we must clear the @is_cached flag. */
- g_hash_table_iter_init (&iter, cache->idx_main);
- while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) {
- nm_assert (obj->is_cached);
- obj->is_cached = FALSE;
- }
+ for (i = NMP_CACHE_ID_TYPE_NONE + 1; i <= NMP_CACHE_ID_TYPE_MAX; i++)
+ nm_dedup_multi_index_remove_idx (cache->multi_idx, _idx_type_get (cache, i));
- nm_multi_index_free (cache->idx_multi);
- g_hash_table_unref (cache->idx_main);
+ nm_dedup_multi_index_unref (cache->multi_idx);
- g_free (cache);
+ g_slice_free (NMPCache, cache);
}
/*****************************************************************************/
@@ -2048,63 +2336,13 @@ nmp_cache_free (NMPCache *cache)
void
ASSERT_nmp_cache_is_consistent (const NMPCache *cache)
{
-#if NM_MORE_ASSERTS
- NMMultiIndexIter iter_multi;
- GHashTableIter iter_hash;
- guint i, len;
- NMPCacheId cache_id_storage;
- const NMPCacheId *cache_id, *cache_id2;
- const NMPlatformObject *const *objects;
- const NMPObject *obj;
-
- g_assert (cache);
-
- g_hash_table_iter_init (&iter_hash, cache->idx_main);
- while (g_hash_table_iter_next (&iter_hash, (gpointer *) &obj, NULL)) {
- const guint8 *id_type;
-
- g_assert (NMP_OBJECT_IS_VALID (obj));
- g_assert (nmp_object_is_alive (obj));
-
- for (id_type = NMP_OBJECT_GET_CLASS (obj)->supported_cache_ids; *id_type; id_type++) {
- if (!_nmp_object_init_cache_id (obj, *id_type, &cache_id_storage, &cache_id))
- continue;
- if (!cache_id)
- continue;
- g_assert (nm_multi_index_contains (cache->idx_multi, &cache_id->base, &obj->object));
- }
- }
-
- nm_multi_index_iter_init (&iter_multi, cache->idx_multi, NULL);
- while (nm_multi_index_iter_next (&iter_multi,
- (const NMMultiIndexId **) &cache_id,
- (void *const**) &objects,
- &len)) {
- g_assert (len > 0 && objects && objects[len] == NULL);
-
- for (i = 0; i < len; i++) {
- g_assert (objects[i]);
- obj = NMP_OBJECT_UP_CAST (objects[i]);
- g_assert (NMP_OBJECT_IS_VALID (obj));
-
- /* for now, enforce that all objects for a certain index are of the same type. */
- g_assert (NMP_OBJECT_GET_CLASS (obj) == NMP_OBJECT_GET_CLASS (NMP_OBJECT_UP_CAST (objects[0])));
-
- if (!_nmp_object_init_cache_id (obj, cache_id->_id_type, &cache_id_storage, &cache_id2))
- g_assert_not_reached ();
- g_assert (cache_id2);
- g_assert (nmp_cache_id_equal (cache_id, cache_id2));
- g_assert_cmpint (nmp_cache_id_hash (cache_id), ==, nmp_cache_id_hash (cache_id2));
-
- g_assert (obj == g_hash_table_lookup (cache->idx_main, obj));
- }
- }
-#endif
}
+
/*****************************************************************************/
const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
[NMP_OBJECT_TYPE_LINK - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LINK,
.sizeof_data = sizeof (NMPObjectLink),
.sizeof_public = sizeof (NMPlatformLink),
@@ -2114,7 +2352,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.signal_type_id = NM_PLATFORM_SIGNAL_ID_LINK,
.signal_type = NM_PLATFORM_SIGNAL_LINK_CHANGED,
.supported_cache_ids = _supported_cache_ids_link,
- .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_link,
+ .cmd_obj_hash = _vt_cmd_obj_hash_link,
.cmd_obj_cmp = _vt_cmd_obj_cmp_link,
.cmd_obj_copy = _vt_cmd_obj_copy_link,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_link,
@@ -2127,9 +2365,11 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_link,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_link,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_link_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_link_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_link_cmp,
},
[NMP_OBJECT_TYPE_IP4_ADDRESS - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_IP4_ADDRESS,
.sizeof_data = sizeof (NMPObjectIP4Address),
.sizeof_public = sizeof (NMPlatformIP4Address),
@@ -2139,7 +2379,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.signal_type_id = NM_PLATFORM_SIGNAL_ID_IP4_ADDRESS,
.signal_type = NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED,
.supported_cache_ids = _supported_cache_ids_ipx_address,
- .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_address,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip4_address,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_address,
@@ -2147,9 +2386,11 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_address,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_address,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_address_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip4_address_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_address_cmp,
},
[NMP_OBJECT_TYPE_IP6_ADDRESS - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_IP6_ADDRESS,
.sizeof_data = sizeof (NMPObjectIP6Address),
.sizeof_public = sizeof (NMPlatformIP6Address),
@@ -2159,7 +2400,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.signal_type_id = NM_PLATFORM_SIGNAL_ID_IP6_ADDRESS,
.signal_type = NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,
.supported_cache_ids = _supported_cache_ids_ipx_address,
- .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_address,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip6_address,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_address,
@@ -2167,9 +2407,11 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_address,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_address,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_address_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip6_address_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_address_cmp
},
[NMP_OBJECT_TYPE_IP4_ROUTE - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
.sizeof_data = sizeof (NMPObjectIP4Route),
.sizeof_public = sizeof (NMPlatformIP4Route),
@@ -2178,8 +2420,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.rtm_gettype = RTM_GETROUTE,
.signal_type_id = NM_PLATFORM_SIGNAL_ID_IP4_ROUTE,
.signal_type = NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED,
- .supported_cache_ids = _supported_cache_ids_ip4_route,
- .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_route,
+ .supported_cache_ids = _supported_cache_ids_ipx_route,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip4_route,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route,
@@ -2187,9 +2428,11 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_route,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_route,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip4_route_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_route_cmp,
},
[NMP_OBJECT_TYPE_IP6_ROUTE - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
.sizeof_data = sizeof (NMPObjectIP6Route),
.sizeof_public = sizeof (NMPlatformIP6Route),
@@ -2198,8 +2441,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.rtm_gettype = RTM_GETROUTE,
.signal_type_id = NM_PLATFORM_SIGNAL_ID_IP6_ROUTE,
.signal_type = NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED,
- .supported_cache_ids = _supported_cache_ids_ip6_route,
- .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_route,
+ .supported_cache_ids = _supported_cache_ids_ipx_route,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip6_route,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route,
@@ -2207,100 +2449,122 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_route,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_route,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_ip6_route_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp,
},
[NMP_OBJECT_TYPE_LNK_GRE - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_GRE,
.sizeof_data = sizeof (NMPObjectLnkGre),
.sizeof_public = sizeof (NMPlatformLnkGre),
.obj_type_name = "gre",
.lnk_link_type = NM_LINK_TYPE_GRE,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_gre_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_gre_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp,
},
[NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_INFINIBAND,
.sizeof_data = sizeof (NMPObjectLnkInfiniband),
.sizeof_public = sizeof (NMPlatformLnkInfiniband),
.obj_type_name = "infiniband",
.lnk_link_type = NM_LINK_TYPE_INFINIBAND,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_infiniband_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_infiniband_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_infiniband_cmp,
},
[NMP_OBJECT_TYPE_LNK_IP6TNL - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_IP6TNL,
.sizeof_data = sizeof (NMPObjectLnkIp6Tnl),
.sizeof_public = sizeof (NMPlatformLnkIp6Tnl),
.obj_type_name = "ip6tnl",
.lnk_link_type = NM_LINK_TYPE_IP6TNL,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ip6tnl_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_ip6tnl_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp,
},
[NMP_OBJECT_TYPE_LNK_IPIP - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_IPIP,
.sizeof_data = sizeof (NMPObjectLnkIpIp),
.sizeof_public = sizeof (NMPlatformLnkIpIp),
.obj_type_name = "ipip",
.lnk_link_type = NM_LINK_TYPE_IPIP,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_ipip_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_ipip_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ipip_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACSEC - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_MACSEC,
.sizeof_data = sizeof (NMPObjectLnkMacsec),
.sizeof_public = sizeof (NMPlatformLnkMacsec),
.obj_type_name = "macsec",
.lnk_link_type = NM_LINK_TYPE_MACSEC,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macsec_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_macsec_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macsec_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_MACVLAN,
.sizeof_data = sizeof (NMPObjectLnkMacvlan),
.sizeof_public = sizeof (NMPlatformLnkMacvlan),
.obj_type_name = "macvlan",
.lnk_link_type = NM_LINK_TYPE_MACVLAN,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_macvlan_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_MACVTAP - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_MACVTAP,
.sizeof_data = sizeof (NMPObjectLnkMacvtap),
.sizeof_public = sizeof (NMPlatformLnkMacvtap),
.obj_type_name = "macvtap",
.lnk_link_type = NM_LINK_TYPE_MACVTAP,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_macvlan_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_SIT - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_SIT,
.sizeof_data = sizeof (NMPObjectLnkSit),
.sizeof_public = sizeof (NMPlatformLnkSit),
.obj_type_name = "sit",
.lnk_link_type = NM_LINK_TYPE_SIT,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_sit_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_sit_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp,
},
[NMP_OBJECT_TYPE_LNK_VLAN - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_VLAN,
.sizeof_data = sizeof (NMPObjectLnkVlan),
.sizeof_public = sizeof (NMPlatformLnkVlan),
.obj_type_name = "vlan",
.lnk_link_type = NM_LINK_TYPE_VLAN,
+ .cmd_obj_hash = _vt_cmd_obj_hash_lnk_vlan,
.cmd_obj_cmp = _vt_cmd_obj_cmp_lnk_vlan,
.cmd_obj_copy = _vt_cmd_obj_copy_lnk_vlan,
.cmd_obj_dispose = _vt_cmd_obj_dispose_lnk_vlan,
.cmd_obj_to_string = _vt_cmd_obj_to_string_lnk_vlan,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vlan_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_vlan_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp,
},
[NMP_OBJECT_TYPE_LNK_VXLAN - 1] = {
+ .parent = DEDUP_MULTI_OBJ_CLASS_INIT(),
.obj_type = NMP_OBJECT_TYPE_LNK_VXLAN,
.sizeof_data = sizeof (NMPObjectLnkVxlan),
.sizeof_public = sizeof (NMPlatformLnkVxlan),
.obj_type_name = "vxlan",
.lnk_link_type = NM_LINK_TYPE_VXLAN,
.cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vxlan_to_string,
+ .cmd_plobj_hash = (guint (*) (const NMPlatformObject *obj)) nm_platform_lnk_vxlan_hash,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vxlan_cmp,
},
};
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index fb7f713f31..9cdad2e808 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -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);
-
-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 NMDedupMultiEntry *nmp_cache_lookup_entry_link (const NMPCache *cache, int ifindex);
-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);
-
-NMPCache *nmp_cache_new (gboolean use_udev);
+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);
+
+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__ */
diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c
index 26c8c2b4bd..690ba35a53 100644
--- a/src/platform/tests/test-cleanup.c
+++ b/src/platform/tests/test-cleanup.c
@@ -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;
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index eec92af1fd..62c2c83fd1 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -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.");
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index b4ed0682ea..b9e879ff62 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -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);
diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c
index e772662c37..342aa0d610 100644
--- a/src/platform/tests/test-general.c
+++ b/src/platform/tests/test-general.c
@@ -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);
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index df204b4683..0e5fcbe453 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -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);
diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c
index 42dfc572e6..11fc59e24b 100644
--- a/src/platform/tests/test-nmp-object.c
+++ b/src/platform/tests/test-nmp-object.c
@@ -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;
-typedef struct {
- NMPCache *cache;
- NMPCacheOpsType expected_ops_type;
- const NMPObject *obj_clone;
- NMPObject *new_clone;
- gboolean was_visible;
- gboolean called;
-} _NMPCacheUpdateData;
+ 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);
+}
+
+/*****************************************************************************/
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 (data);
- g_assert (!data->called);
- g_assert (data->cache == cache);
+ g_assert (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);
-
- new_clone = data.new_clone;
-
- g_assert_cmpint (ops_type, ==, expected_ops_type);
+ 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));
- 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);
+ 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);
- 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;
+
+ multi_idx = nm_dedup_multi_index_new ();
- cache = nmp_cache_new (nmtst_get_rand_int () % 2);
+ 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 ();
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c
index c96af93e51..3fe0f3128a 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -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,
diff --git a/src/ppp/nm-ppp-manager.c b/src/ppp/nm-ppp-manager.c
index 6343df8bf4..104adf5475 100644
--- a/src/ppp/nm-ppp-manager.c
+++ b/src/ppp/nm-ppp-manager.c
@@ -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;
diff --git a/src/tests/test-general-with-expect.c b/src/tests/test-general-with-expect.c
index 492e1b1f60..c5d26163fe 100644
--- a/src/tests/test-general-with-expect.c
+++ b/src/tests/test-general-with-expect.c
@@ -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 ();
diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c
index cd5b108903..e865f5f26a 100644
--- a/src/tests/test-ip4-config.c
+++ b/src/tests/test-ip4-config.c
@@ -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");
diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c
index 7e83625c5b..0887e9da98 100644
--- a/src/tests/test-ip6-config.c
+++ b/src/tests/test-ip6-config.c
@@ -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");
diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c
index 6650d26c43..cf771f80ea 100644
--- a/src/tests/test-route-manager.c
+++ b/src/tests/test-route-manager.c
@@ -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);
-
- g_array_append_vals (routes, routes1->data, routes1->len);
- g_array_free (routes1, TRUE);
+ const NMPClass *klass;
+ GArray *routes;
+ const NMDedupMultiHeadEntry *pl_head_entry;
+ NMDedupMultiIter iter;
+ const NMPObject *plobj = NULL;
+ guint i;
+
+ 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);
}
diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c
index ecc820685c..ab6103d497 100644
--- a/src/vpn/nm-vpn-connection.c
+++ b/src/vpn/nm-vpn-connection.c
@@ -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;