From 26f04fd886b9dc72e567608f5efefde0bca3df71 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 5 Jun 2017 14:39:10 +0200 Subject: [PATCH 01/36] shared: update c-list Reimport c-list from upstream. It allows iterating over const-list. Upstream commit is 17e7781b3fe26e06bbe3817e8ed7418d80f63feb "build: update NEWS". --- shared/nm-utils/c-list.h | 165 +++++++++++++++------------------------ 1 file changed, 63 insertions(+), 102 deletions(-) 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. + * + * On return, the source list will be empty. */ static inline void c_list_splice(CList *target, CList *source) { - if (c_list_is_empty(source)) - return; + if (!c_list_is_empty(source)) { + /* attach the front of @source to the tail of @target */ + source->next->prev = target->prev; + target->prev->next = source->next; - /* attach the front of @source to the tail of @target */ - source->next->prev = target->prev; - target->prev->next = source->next; + /* attach the tail of @source to the front of @target */ + source->prev->next = target; + target->prev = source->prev; - /* attach the tail of @source to the front of @target */ - source->prev->next = target; - target->prev = source->prev; -} - -/** - * c_list_loop_first() - return first list element, or head if empty - * @list: list to operate on - * - * This is an O(1) accessor to the first list element. If the list is empty, - * this returns a pointer to the list head. Hence, this never returns NULL. - * - * Return: Pointer to first list element, or pointer to head if empty. - */ -static inline CList *c_list_loop_first(CList *list) { - return list->next; -} - -/** - * c_list_loop_last() - return last list element, or head if empty - * @list: list to operate on - * - * This is an O(1) accessor to the last list element. If the list is empty, - * this returns a pointer to the list head. Hence, this never returns NULL. - * - * Return: Pointer to last list element, or pointer to head if empty. - */ -static inline CList *c_list_loop_last(CList *list) { - return list->prev; -} - -/** - * c_list_loop_next() - return next list element, or head if none - * @what: list entry to operate on - * - * This is an O(1) accessor to the next list element. If @what is the list tail - * this will return a pointer to the list head. Hence, this never returns NULL. - * - * Return: Pointer to next list element, or pointer to head if none. - */ -static inline CList *c_list_loop_next(CList *what) { - return what->next; -} - -/** - * c_list_loop_prev() - return previous list element, or head if none - * @what: list entry to operate on - * - * This is an O(1) accessor to the previous list element. If @what is the list - * front this will return a pointer to the list head. Hence, this never returns - * NULL. - * - * Return: Pointer to previous list element, or pointer to head if none. - */ -static inline CList *c_list_loop_prev(CList *what) { - return what->prev; + /* clear source */ + *source = (CList)C_LIST_INIT(*source); + } } /** @@ -281,10 +232,10 @@ static inline CList *c_list_loop_prev(CList *what) { * This is a macro to use as for-loop to iterate an entire list. It is meant as * convenience macro. Feel free to code your own loop iterator. */ -#define c_list_for_each(_iter, _list) \ - for (_iter = c_list_loop_first(_list); \ - _iter != (_list); \ - _iter = c_list_loop_next(_iter)) +#define c_list_for_each(_iter, _list) \ + for (_iter = (_list)->next; \ + (_iter) != (_list); \ + _iter = (_iter)->next) /** @@ -302,10 +253,10 @@ static inline CList *c_list_loop_prev(CList *what) { * havoc if you remove other list entries. You better not modify anything but * the current list entry. */ -#define c_list_for_each_safe(_iter, _safe, _list) \ - for (_iter = c_list_loop_first(_list), _safe = c_list_loop_next(_iter); \ - _iter != (_list); \ - _iter = _safe, _safe = c_list_loop_next(_safe)) +#define c_list_for_each_safe(_iter, _safe, _list) \ + for (_iter = (_list)->next, _safe = (_iter)->next; \ + (_iter) != (_list); \ + _iter = (_safe), _safe = (_safe)->next) /** * c_list_for_each_entry() - loop over all list entries @@ -316,10 +267,10 @@ static inline CList *c_list_loop_prev(CList *what) { * This combines c_list_for_each() with c_list_entry(), making it easy to * iterate over a list of a specific type. */ -#define c_list_for_each_entry(_iter, _list, _m) \ - for (_iter = c_list_entry(c_list_loop_first(_list), __typeof__(*_iter), _m); \ - &_iter->_m != (_list); \ - _iter = c_list_entry(c_list_loop_next(&_iter->_m), __typeof__(*_iter), _m)) +#define c_list_for_each_entry(_iter, _list, _m) \ + for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m); \ + &(_iter)->_m != (_list); \ + _iter = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m)) /** * c_list_for_each_entry_safe() - loop over all list entries, safe for removal @@ -331,12 +282,12 @@ static inline CList *c_list_loop_prev(CList *what) { * This combines c_list_for_each_safe() with c_list_entry(), making it easy to * iterate over a list of a specific type. */ -#define c_list_for_each_entry_safe(_iter, _safe, _list, _m) \ - for (_iter = c_list_entry(c_list_loop_first(_list), __typeof__(*_iter), _m), \ - _safe = c_list_entry(c_list_loop_next(&_iter->_m), __typeof__(*_iter), _m);\ - &_iter->_m != (_list); \ - _iter = _safe, \ - _safe = c_list_entry(c_list_loop_next(&_safe->_m), __typeof__(*_iter), _m)) +#define c_list_for_each_entry_safe(_iter, _safe, _list, _m) \ + for (_iter = c_list_entry((_list)->next, __typeof__(*_iter), _m), \ + _safe = c_list_entry((_iter)->_m.next, __typeof__(*_iter), _m); \ + &(_iter)->_m != (_list); \ + _iter = (_safe), \ + _safe = c_list_entry((_safe)->_m.next, __typeof__(*_iter), _m)) \ /** * c_list_first() - return pointer to first element, or NULL if empty @@ -391,44 +342,54 @@ static inline CList *c_list_last(CList *list) { c_list_entry(c_list_last(_list), _t, _m) /** - * c_list_length() - return the number of linked entries, excluding the head + * c_list_length() - return number of linked entries, excluding the head * @list: list to operate on * - * Returns the number of entires in the list, excluding the list head - * @list. That is, for a list that is empty according to c_list_is_empty(), - * the returned length is 0. This requires to iterate the list and has - * thus O(n) runtime. + * Returns the number of entries in the list, excluding the list head @list. + * That is, for a list that is empty according to c_list_is_empty(), the + * returned length is 0. This requires to iterate the list and has thus O(n) + * runtime. * - * Return: the number of items in the list + * Note that this function is meant for debugging purposes only. If you need + * the list size during normal operation, you should maintain a counter + * separately. + * + * Return: Number of items in @list. */ -static inline size_t c_list_length(const CList *list) { - CList *iter; - size_t n = 0; +static inline unsigned long c_list_length(const CList *list) { + unsigned long n = 0; + const CList *iter; + + c_list_for_each(iter, list) + ++n; - c_list_for_each(iter, (CList *)list) - n++; return n; } /** - * c_list_contains() - whether an item is linked in a certain list + * c_list_contains() - check whether an entry is linked in a certain list * @list: list to operate on - * @what: the list entry to find + * @what: entry to look for * - * Searches @list whether @what is a linked entry of the list - * in O(n). For the head @list, this also returns True. + * This checks whether @what is linked into @list. This requires a linear + * search through the list, as such runs in O(n). Note that the list-head is + * considered part of the list, and hence this returns true if @what equals + * @list. * - * Return: True if @what is in @list + * Note that this function is meant for debugging purposes, and consistency + * checks. You should always be aware whether your objects are linked in a + * specific list. + * + * Return: True if @what is in @list, false otherwise. */ static inline _Bool c_list_contains(const CList *list, const CList *what) { - const CList *iter = list; + const CList *iter; - do { - if (iter == what) + c_list_for_each(iter, list) + if (what == iter) return 1; - iter = iter->next; - } while (iter != list); - return 0; + + return what == list; } #ifdef __cplusplus From b002357f5f77887d5bc11e0534ddaa46664f1af2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 27 Jun 2017 19:42:44 +0200 Subject: [PATCH 02/36] platform: fix nm_platform_lnk_macvlan_cmp() to consider "tap" field --- src/platform/nm-platform.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 7f12fb743b..a1a7888976 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4236,7 +4236,8 @@ nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkM { _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; } From 489e346e87d8c63e563bda2e001039121b805771 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 20 Jun 2017 10:19:37 +0200 Subject: [PATCH 03/36] shared: add NM_HASH_COMBINE() function --- shared/nm-utils/nm-macros-internal.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 011f45d0ee..05e3ed7631 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -381,6 +381,15 @@ _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; +} + +/*****************************************************************************/ + /* NM_CACHED_QUARK() returns the GQuark for @string, but caches * it in a static variable to speed up future lookups. * From 3f76b5b7eb418caaa47897c8b8169877a5fdf757 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 20 Jun 2017 10:29:40 +0200 Subject: [PATCH 04/36] core: use NM_HASH_COMBINE() function --- libnm-core/nm-utils.c | 8 +++---- src/devices/nm-lldp-listener.c | 10 ++++---- src/platform/nmp-object.c | 42 +++++++++++++++++----------------- 3 files changed, 30 insertions(+), 30 deletions(-) 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/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/platform/nmp-object.c b/src/platform/nmp-object.c index 3ea3fbba4f..2d77824bf9 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -81,7 +81,7 @@ _id_hash_ip6_addr (const struct in6_addr *addr) int i; for (i = 0; i < sizeof (*addr); i++) - hash = (hash * 33) + ((const guint8 *) addr)[i]; + hash = NM_HASH_COMBINE (hash, ((const guint8 *) addr)[i]); return hash; } @@ -846,39 +846,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, _id_hash_ip6_addr (&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; + _id_hash_ip6_addr (nm_utils_ip6_address_clear_host_address (&n1, &obj->network, obj->plen)); + })); }) gboolean @@ -989,7 +989,7 @@ nmp_cache_id_hash (const NMPCacheId *id) 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 */ + hash = NM_HASH_COMBINE (hash, ((char *) id)[i]); return hash; } From b8bc80bcdb4f384d6b151691eefbbf9001f5f993 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 4 Jun 2017 20:45:23 +0200 Subject: [PATCH 05/36] all: add base object type in "nm-obj.h" Platform has it's own, simple implementation of object types: NMPObject. Extract a base type and move it to "shared/nm-utils/nm-obj.h" so it can be reused. The base type is trival, but it allows us to implement other objects which are compatible with NMPObjects. Currently there is no API for generic NMObjBaseInst type, so compatible in this case only means, that they can be used in the same context (see example below). The only thing that you can do with a NMObjBaseInst is check it's NMObjBaseClass. Incidentally, NMObjBaseInst is also made compatible to GTypeInstance. It means, an NMObjBaseInst is not necessarily a valid GTypeInstance (like NMPObject is not), but it could be implemented as such. For example, you could do: if (NMP_CLASS_IS_VALID ((NMPClass *) obj->klass)) { /* is an NMPObject */ } else if (G_TYPE_CHECK_INSTANCE_TYPE (obj, NM_TYPE_SOMETHING)) { /* it a NMSometing GType */ } else { /* something else? */ } The reason why NMPObject is not implemented as proper GTypeInstance is because it would require us to register a GType (like g_type_register_fundamental). However, then the NMPClass struct can no longer be const and immutable memory. But we could. NMObjBaseInst may or may not be a GTypeInstance. In a sense, it's a base type of GTypeInstance and all our objects should be based on it (optionally, they we may make them valid GTypes too). --- Makefile.am | 1 + shared/nm-utils/nm-obj.h | 82 ++++++++++++++++++++++++++++ src/platform/nmp-object.c | 12 ++-- src/platform/nmp-object.h | 19 ++++--- src/platform/tests/test-nmp-object.c | 51 +++++++++++++++++ 5 files changed, 151 insertions(+), 14 deletions(-) create mode 100644 shared/nm-utils/nm-obj.h diff --git a/Makefile.am b/Makefile.am index f25fc02711..336fbd5a7a 100644 --- a/Makefile.am +++ b/Makefile.am @@ -4444,6 +4444,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/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/platform/nmp-object.c b/src/platform/nmp-object.c index 2d77824bf9..4bf2b9f8fd 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -208,7 +208,7 @@ 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); + g_return_val_if_fail (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT, NULL); obj->_ref_count++; return obj; @@ -219,7 +219,7 @@ 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); + g_return_if_fail (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT); if (--obj->_ref_count <= 0) { const NMPClass *klass = obj->_class; @@ -294,7 +294,7 @@ _nmp_object_stackinit_from_class (NMPObject *obj, const NMPClass *klass) memset (obj, 0, sizeof (NMPObject)); obj->_class = klass; - obj->_ref_count = NMP_REF_COUNT_STACKINIT; + obj->_ref_count = NM_OBJ_REF_COUNT_STACKINIT; return obj; } @@ -434,7 +434,7 @@ 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]", + "[%s,%p,%u,%ccache,%calive,%cvisible; %s]", klass->obj_type_name, obj, obj->_ref_count, obj->is_cached ? '+' : '-', nmp_object_is_alive (obj) ? '+' : '-', @@ -461,7 +461,7 @@ _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]", + "[%s,%p,%u,%ccache,%calive,%cvisible,%cin-nl,%p; %s]", klass->obj_type_name, obj, obj->_ref_count, obj->is_cached ? '+' : '-', nmp_object_is_alive (obj) ? '+' : '-', @@ -502,7 +502,7 @@ _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]", + "[%s,%p,%u,%ccache,%calive,%cvisible; %s]", klass->obj_type_name, obj, obj->_ref_count, obj->is_cached ? '+' : '-', nmp_object_is_alive (obj) ? '+' : '-', diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index fb7f713f31..a21d6fd192 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -21,6 +21,7 @@ #ifndef __NMP_OBJECT_H__ #define __NMP_OBJECT_H__ +#include "nm-utils/nm-obj.h" #include "nm-platform.h" #include "nm-multi-index.h" @@ -138,13 +139,14 @@ struct _NMPCacheId { }; typedef struct { + NMObjBaseClass 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; @@ -266,8 +268,11 @@ typedef struct { } NMPObjectIP6Route; struct _NMPObject { - const NMPClass *_class; - int _ref_count; + union { + NMObjBaseInst parent; + const NMPClass *_class; + }; + guint _ref_count; bool is_cached; union { NMPlatformObject object; @@ -326,8 +331,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) { @@ -358,7 +361,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->_ref_count == NM_OBJ_REF_COUNT_STACKINIT; } static inline const NMPClass * diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index 42dfc572e6..adc006e6f2 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -33,6 +33,56 @@ struct { /*****************************************************************************/ +static void +test_obj_base (void) +{ + static const GObject *g = NULL; + static const GTypeClass *k = NULL; + static const NMPObject *o = NULL; + static const NMPClass *c = NULL; + + 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 (&g->ref_count == (void *) &o->_ref_count); + + STATIC_ASSERT (sizeof (o->parent) == sizeof (GTypeInstance)); + + STATIC_ASSERT (&c->parent == (void *) c); + STATIC_ASSERT (&c->parent.g_type_class == (void *) c); + STATIC_ASSERT (&c->parent.g_type == (void *) c); + STATIC_ASSERT (&c->parent.g_type == &k->g_type); + + STATIC_ASSERT (sizeof (c->parent) == sizeof (GTypeClass)); + + STATIC_ASSERT (&o->parent == (void *) o); + STATIC_ASSERT (&o->parent.klass == (void *) &o->_class); + + STATIC_ASSERT (G_STRUCT_OFFSET (NMPObject, _ref_count) == sizeof (NMObjBaseInst)); + STATIC_ASSERT (G_STRUCT_OFFSET (NMPClass, obj_type_name) == sizeof (NMObjBaseClass)); + + 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) { @@ -429,6 +479,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 (); From 343c967e662ce6525cfdeeab3af3bdbbca3791ec Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 7 Jun 2017 14:43:58 +0200 Subject: [PATCH 06/36] clients: make meta data subtypes of NMObjBaseInst Yes, this wastes 4 times an unused GType instance in the class structure. --- clients/cli/utils.h | 5 ++++- clients/common/nm-meta-setting-desc.h | 17 ++++++++++++++--- 2 files changed, 18 insertions(+), 4 deletions(-) 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; From f9202c2ac120152f047845f859bac22759e634f3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 4 Jun 2017 22:43:21 +0200 Subject: [PATCH 07/36] shared: add NMDedupMultiIndex "nm-dedup-multi.h" Add the NMDedupMultiIndex cache. It basically tracks objects as doubly linked list. With the addition that each object and the list head is indexed by a hash table. Also, it supports tracking multiple distinct lists, all indexed by the idx-type instance. It also deduplicates the tracked objects and shares them. - the objects that can be put into the cache must be immutable and ref-counted. That is, the cache will deduplicate them and share the reference. Also, as these objects are immutable and ref-counted, it is safe that users outside the cache own them too (as long as they keep them immutable and manage their reference properly). The deduplication uses obj_id_hash_func() and obj_id_equal_func(). These functions must cover *every* aspect of the objects when comparing equality. For example nm_platform_ip4_route_cmp() would be a function that qualifies as obj_id_equal_func(). The cache creates references to the objects as needed and gives them back. This happens via obj_get_ref() and obj_put_ref(). Note that obj_get_ref() is free to create a new object, for example to convert a stack-allocated object to a (ref-counted) heap allocated one. The deduplication process creates NMDedupIndexBox instances which are the ref-counted entity. In principle, the objects themself don't need to be ref-counted as that is handled by the boxing instance. - The cache doesn't only do deduplication. It is a multi-index, meaning, callers add objects using a index handle NMDedupMultiIdxType. The NMDedupMultiIdxType instance is the access handle to lookup the list and objects inside the cache. Note that the idx-type instance may partition the objects in distinct lists. For all operations there are cross-references and hash table lookups. Hence, every operation of this data structure is O(1) and the memory overhead for an index tracking an object is constant. The cache preserves ordering (due to linked list) and exposes the list as public API. This allows users to iterate the list without any additional copying of elements. --- Makefile.am | 3 + libnm-core/tests/test-general.c | 305 +++++++++- shared/nm-utils/nm-dedup-multi.c | 988 +++++++++++++++++++++++++++++++ shared/nm-utils/nm-dedup-multi.h | 365 ++++++++++++ 4 files changed, 1660 insertions(+), 1 deletion(-) create mode 100644 shared/nm-utils/nm-dedup-multi.c create mode 100644 shared/nm-utils/nm-dedup-multi.h diff --git a/Makefile.am b/Makefile.am index 336fbd5a7a..98b717021e 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,6 +1273,7 @@ $(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 \ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index b8c3dc8e12..a897fe5a4e 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,308 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int)); /*****************************************************************************/ +typedef struct { + NMDedupMultiObj parent; + int ref_count; + 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->ref_count > 0); + g_assert (o->val > 0); + return o; +} + +static NMDedupMultiObj * +_dedup_obj_get_ref (const NMDedupMultiObj *obj) +{ + DedupObj *o, *o2; + + o = _dedup_obj_assert (obj); + if (o->ref_count == NM_OBJ_REF_COUNT_STACKINIT) { + o2 = g_slice_new0 (DedupObj); + o2->parent.klass = &dedup_obj_class; + o2->ref_count = 1; + o2->val = o->val; + o2->other = o->other; + return (NMDedupMultiObj *) o2; + } + + o->ref_count++; + return (NMDedupMultiObj *) o; +} + +static void +_dedup_obj_put_ref (NMDedupMultiObj *obj) +{ + DedupObj *o; + + o = _dedup_obj_assert (obj); + g_assert (o->ref_count != NM_OBJ_REF_COUNT_STACKINIT); + if (--o->ref_count == 0) + 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_get_ref = _dedup_obj_get_ref, + .obj_put_ref = _dedup_obj_put_ref, + .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->box->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->box->obj, + c_list_entry (entry->head->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->box->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_box_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1))); + g_assert (!nm_dedup_multi_box_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_box_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1))); + g_assert (nm_dedup_multi_box_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 +6085,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/nm-dedup-multi.c b/shared/nm-utils/nm-dedup-multi.c new file mode 100644 index 0000000000..6e949f9066 --- /dev/null +++ b/shared/nm-utils/nm-dedup-multi.c @@ -0,0 +1,988 @@ +/* -*- 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 { + NMDedupMultiBox parent; + int ref_count; +} Box; + +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_box; +}; + +/*****************************************************************************/ + +static void _box_unref (NMDedupMultiIndex *self, + Box *box); + +/*****************************************************************************/ + +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, box) == 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)->box->obj; + *out_idx_type = head_entry->idx_type; + *out_lookup_head = TRUE; + } else { + *out_obj = entry->box->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 NMDedupMultiBox *box_existing, + const NMDedupMultiEntry **out_entry, + const NMDedupMultiBox **out_old_box) +{ + NMDedupMultiHeadEntry *head_entry; + const NMDedupMultiBox *box, *box_new; + 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 (!box_existing || box_existing == nm_dedup_multi_box_find (self, obj)); + 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->box->obj + || obj->klass->obj_full_equal (obj, + entry->box->obj)) { + NM_SET_OUT (out_entry, entry); + NM_SET_OUT (out_old_box, nm_dedup_multi_box_ref (entry->box)); + return FALSE; + } + + if (box_existing) + box_new = nm_dedup_multi_box_ref (box_existing); + else + box_new = nm_dedup_multi_box_new (self, obj); + + box = entry->box; + entry->box = box_new; + + NM_SET_OUT (out_entry, entry); + if (out_old_box) + *out_old_box = box; + else + _box_unref (self, (Box *) box); + 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_old_box, NULL); + return FALSE; + } + + if (box_existing) + box_new = nm_dedup_multi_box_ref (box_existing); + else + box_new = nm_dedup_multi_box_new (self, obj); + obj = box_new->obj; + + if (!head_existing) + head_entry = _entry_lookup_head (self, idx_type, obj); + 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->box = box_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_old_box, 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 NMDedupMultiBox **out_old_box) +{ + 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, NULL, + out_entry, out_old_box); +} + +/* 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 + * @box_existing: optional argument to safe the box lookup. If given, @obj and the boxed + * object must be identical, and @box_existing must be tracked by @self. This is to safe + * the additional lookup. + * @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_old_box: if given, return the previously contained boxed object. It only + * returns a boxed object, if a matching entry was tracked previously, not if a + * new entry was created. Note that when passing @out_old_box you obtain a reference + * to the boxed object and MUST return it with nm_dedup_multi_box_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 NMDedupMultiBox *box_existing, + const NMDedupMultiEntry **out_entry, + const NMDedupMultiBox **out_old_box) +{ + 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, + box_existing, + out_entry, out_old_box); +} + +/*****************************************************************************/ + +static void +_remove_entry (NMDedupMultiIndex *self, + NMDedupMultiEntry *entry, + gboolean *out_head_entry_removed) +{ + Box *box; + NMDedupMultiHeadEntry *head_entry; + NMDedupMultiIdxType *idx_type; + + nm_assert (self); + nm_assert (entry); + nm_assert (entry->box); + 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; + box = (Box *) entry->box; + + 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); + } + + _box_unref (self, box); +} + +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_box_hash (const Box *box) +{ + const NMDedupMultiObj *obj = box->parent.obj; + + return obj->klass->obj_full_hash (obj); +} + +static gboolean +_dict_idx_box_equal (const Box *box_a, + const Box *box_b) +{ + const NMDedupMultiObjClass *klass; + const NMDedupMultiObj *obj_a = box_a->parent.obj; + const NMDedupMultiObj *obj_b = box_b->parent.obj; + + 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); +} + +static void +_box_unref (NMDedupMultiIndex *self, + Box *box) +{ + nm_assert (box); + nm_assert (box->ref_count > 0); + nm_assert (g_hash_table_lookup (self->idx_box, box) == box); + + if (--box->ref_count > 0) + return; + + if (!g_hash_table_remove (self->idx_box, box)) + nm_assert_not_reached (); + + ((NMDedupMultiObj *) box->parent.obj)->klass->obj_put_ref ((NMDedupMultiObj *) box->parent.obj); + g_slice_free (Box, box); +} + +#define BOX_INIT(obj) \ + (&((const Box) { .parent = { .obj = obj, }, })) + +static Box * +_box_find (NMDedupMultiIndex *index, + /* const NMDedupMultiObj * */ gconstpointer obj) +{ + nm_assert (index); + nm_assert (obj); + + return g_hash_table_lookup (index->idx_box, BOX_INIT (obj)); +} + +const NMDedupMultiBox * +nm_dedup_multi_box_find (NMDedupMultiIndex *index, + /* const NMDedupMultiObj * */ gconstpointer obj) +{ + g_return_val_if_fail (index, NULL); + g_return_val_if_fail (obj, NULL); + + return (NMDedupMultiBox *) _box_find (index, obj); +} + +const NMDedupMultiBox * +nm_dedup_multi_box_new (NMDedupMultiIndex *index, + /* const NMDedupMultiObj * */ gconstpointer obj) +{ + Box *box; + const NMDedupMultiObj *o; + + g_return_val_if_fail (index, NULL); + g_return_val_if_fail (obj, NULL); + + box = _box_find (index, obj); + if (box) { + box->ref_count++; + return (NMDedupMultiBox *) box; + } + + o = ((const NMDedupMultiObj *) obj)->klass->obj_get_ref (obj); + if (!o) + g_return_val_if_reached (NULL); + + box = g_slice_new (Box); + box->parent.obj = o; + box->ref_count = 1; + + nm_assert (_dict_idx_box_equal (box, BOX_INIT (obj))); + nm_assert (_dict_idx_box_equal (BOX_INIT (obj), box)); + nm_assert (_dict_idx_box_hash (BOX_INIT (obj)) == _dict_idx_box_hash (box)); + + if (!nm_g_hash_table_add (index->idx_box, box)) + nm_assert_not_reached (); + + return &box->parent; +} + +const NMDedupMultiBox * +nm_dedup_multi_box_ref (const NMDedupMultiBox *box) +{ + Box *b; + + b = (Box *) box; + + g_return_val_if_fail (b, NULL); + g_return_val_if_fail (b->ref_count > 0, NULL); + + b->ref_count++; + return box; +} + +const NMDedupMultiBox * +nm_dedup_multi_box_unref (NMDedupMultiIndex *self, + const NMDedupMultiBox *box) +{ + g_return_val_if_fail (self, NULL); + g_return_val_if_fail (box, NULL); + g_return_val_if_fail (((Box *) box)->ref_count > 0, NULL); + + _box_unref (self, (Box *) box); + return NULL; +} + +/*****************************************************************************/ + +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_box = g_hash_table_new ((GHashFunc) _dict_idx_box_hash, (GEqualFunc) _dict_idx_box_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; + + 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); + + /* If callers took references to NMDedupMultiBox instances, they + * must keep NMDedupMultiIndex alive for as long as they keep + * the boxed reference. */ + nm_assert (g_hash_table_size (self->idx_box) == 0); + + g_hash_table_unref (self->idx_entries); + g_hash_table_unref (self->idx_box); + + 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..fc4283a808 --- /dev/null +++ b/shared/nm-utils/nm-dedup-multi.h @@ -0,0 +1,365 @@ +/* -*- 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 _NMDedupMultiBox NMDedupMultiBox; +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; + }; +}; + +struct _NMDedupMultiObjClass { + NMObjBaseClass parent; + + /* obj_get_ref() may just increase the ref-count, or it may allocate a new object. + * In any case, it returns ownership of an equal object to @obj. */ + NMDedupMultiObj *(*obj_get_ref) (const NMDedupMultiObj *obj); + + void (*obj_put_ref) (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); +}; + +/*****************************************************************************/ + +struct _NMDedupMultiBox { + gconstpointer obj; +}; + +const NMDedupMultiBox *nm_dedup_multi_box_new (NMDedupMultiIndex *index, /* const NMDedupMultiObj * */ gconstpointer obj); +const NMDedupMultiBox *nm_dedup_multi_box_find (NMDedupMultiIndex *index, /* const NMDedupMultiObj * */ gconstpointer obj); +const NMDedupMultiBox *nm_dedup_multi_box_ref (const NMDedupMultiBox *box); +const NMDedupMultiBox *nm_dedup_multi_box_unref (NMDedupMultiIndex *index, const NMDedupMultiBox *box); + +/*****************************************************************************/ + +/* 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; + + /* the object instance. It is ref-counted and shared. + * Note that this instance must be immutable once it + * is added to the list. + * + * For head entries, @box is NULL and @head points to itself. */ + const NMDedupMultiBox *box; + + 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 NMDedupMultiBox *box_existing, + const NMDedupMultiEntry **out_entry, + const NMDedupMultiBox **out_old_box); + +gboolean nm_dedup_multi_index_add (NMDedupMultiIndex *self, + NMDedupMultiIdxType *idx_type, + /*const NMDedupMultiObj * */ gconstpointer obj, + NMDedupMultiIdxMode mode, + const NMDedupMultiEntry **out_entry, + const NMDedupMultiBox **out_old_box); + +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); +} + +/*****************************************************************************/ + +#endif /* __NM_DEDUP_MULTI_H__ */ From 6d9c3eab385fa809996a41bceb923e353addab37 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 12 Jun 2017 18:39:53 +0200 Subject: [PATCH 08/36] platform: let NMPObject implement NMDedupIndexObj --- src/nm-core-utils.c | 13 ++++ src/nm-core-utils.h | 2 + src/platform/nm-platform.c | 102 +++++++++++++++++++++++++ src/platform/nm-platform.h | 5 ++ src/platform/nmp-object.c | 109 +++++++++++++++++++++++---- src/platform/nmp-object.h | 8 +- src/platform/tests/test-nmp-object.c | 11 +-- 7 files changed, 228 insertions(+), 22 deletions(-) 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..f621393460 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -109,6 +109,8 @@ extern const NMIPAddr nm_ip_addr_zero; /*****************************************************************************/ +guint nm_utils_in6_addr_hash (const struct in6_addr *addr); + 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/platform/nm-platform.c b/src/platform/nm-platform.c index a1a7888976..7cc582e863 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4290,6 +4290,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) { @@ -4307,6 +4327,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) { @@ -4327,6 +4366,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) { @@ -4360,6 +4430,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) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 97c8f6ccf2..b7dcb4caca 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -1024,6 +1024,11 @@ nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route return nm_platform_ip6_route_cmp_full (a, b, TRUE); } +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); + gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self); gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 4bf2b9f8fd..751160f6f3 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -74,17 +74,6 @@ struct _NMPCache { /*****************************************************************************/ -static inline guint -_id_hash_ip6_addr (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; -} - static int _vlan_xgress_qos_mappings_cmp (guint n_map, const NMVlanQosMapping *map1, @@ -566,6 +555,37 @@ _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; + + 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) + return klass->cmd_obj_hash (obj); + if (klass->cmd_plobj_hash) + return klass->cmd_plobj_hash (&obj->object); + return GPOINTER_TO_UINT (obj); +} + +static guint +_vt_cmd_obj_hash_not_implemented (const NMPObject *obj) +{ + g_return_val_if_reached (0); +} + +static guint +_vt_cmd_plobj_hash_not_implemented (const NMPlatformObject *obj) +{ + g_return_val_if_reached (0); +} + int nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2) { @@ -860,7 +880,7 @@ _vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, { hash = (guint) 2907861637u; hash = hash + ((guint) obj->ifindex); /* for IPv6 addresses, the prefix length is not part of the primary identifier. */ - hash = NM_HASH_COMBINE (hash, _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; @@ -877,7 +897,7 @@ _vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, { hash = NM_HASH_COMBINE (hash, ({ struct in6_addr n1; - _id_hash_ip6_addr (nm_utils_ip6_address_clear_host_address (&n1, &obj->network, obj->plen)); + nm_utils_in6_addr_hash (nm_utils_ip6_address_clear_host_address (&n1, &obj->network, obj->plen)); })); }) @@ -1306,6 +1326,48 @@ _vt_cmd_obj_init_cache_id_ipx_route (const NMPObject *obj, NMPCacheIdType id_typ /*****************************************************************************/ +static NMDedupMultiObj * +_vt_dedup_obj_get_ref (const NMDedupMultiObj *obj) +{ + NMPObject *o = (NMPObject *) obj; + + if (NMP_OBJECT_IS_STACKINIT (o)) { + return (NMDedupMultiObj *) nmp_object_new (NMP_OBJECT_GET_TYPE (o), + &o->object); + } + return (NMDedupMultiObj *) nmp_object_ref (o); +} + +static void +_vt_dedup_obj_put_ref (NMDedupMultiObj *obj) +{ + nmp_object_unref ((NMPObject *) obj); +} + +static guint +_vt_dedup_obj_full_hash (const NMDedupMultiObj *obj) +{ + return nmp_object_hash ((NMPObject *) obj); +} + +static gboolean +_vt_dedup_obj_full_equal (const NMDedupMultiObj *obj_a, + const NMDedupMultiObj *obj_b) +{ + return nmp_object_equal ((NMPObject *) obj_a, + (NMPObject *) obj_b); +} + +#define DEDUP_MULTI_OBJ_CLASS_INIT() \ + { \ + .obj_get_ref = _vt_dedup_obj_get_ref, \ + .obj_put_ref = _vt_dedup_obj_put_ref, \ + .obj_full_hash = _vt_dedup_obj_full_hash, \ + .obj_full_equal = _vt_dedup_obj_full_equal, \ + } + +/*****************************************************************************/ + gboolean nmp_cache_use_udev_get (const NMPCache *cache) { @@ -2115,6 +2177,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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_not_implemented, .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 +2190,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 = _vt_cmd_plobj_hash_not_implemented, .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), @@ -2147,9 +2212,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), @@ -2167,9 +2234,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), @@ -2187,9 +2256,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), @@ -2207,6 +2278,7 @@ 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] = { @@ -2216,6 +2288,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp, }, [NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = { @@ -2225,6 +2298,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_infiniband_cmp, }, [NMP_OBJECT_TYPE_LNK_IP6TNL - 1] = { @@ -2234,6 +2308,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ip6tnl_cmp, }, [NMP_OBJECT_TYPE_LNK_IPIP - 1] = { @@ -2243,6 +2318,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_ipip_cmp, }, [NMP_OBJECT_TYPE_LNK_MACSEC - 1] = { @@ -2252,6 +2328,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macsec_cmp, }, [NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = { @@ -2261,6 +2338,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp, }, [NMP_OBJECT_TYPE_LNK_MACVTAP - 1] = { @@ -2270,6 +2348,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp, }, [NMP_OBJECT_TYPE_LNK_SIT - 1] = { @@ -2279,6 +2358,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_sit_cmp, }, [NMP_OBJECT_TYPE_LNK_VLAN - 1] = { @@ -2287,11 +2367,13 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_public = sizeof (NMPlatformLnkVlan), .obj_type_name = "vlan", .lnk_link_type = NM_LINK_TYPE_VLAN, + .cmd_obj_hash = _vt_cmd_obj_hash_not_implemented, .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 = _vt_cmd_plobj_hash_not_implemented, .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp, }, [NMP_OBJECT_TYPE_LNK_VXLAN - 1] = { @@ -2301,6 +2383,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, .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 a21d6fd192..7664a43817 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -22,6 +22,7 @@ #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" @@ -139,7 +140,7 @@ struct _NMPCacheId { }; typedef struct { - NMObjBaseClass parent; + NMDedupMultiObjClass parent; const char *obj_type_name; int sizeof_data; int sizeof_public; @@ -158,6 +159,7 @@ typedef struct { * 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); @@ -172,6 +174,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; @@ -269,7 +272,7 @@ typedef struct { struct _NMPObject { union { - NMObjBaseInst parent; + NMDedupMultiObj parent; const NMPClass *_class; }; guint _ref_count; @@ -398,6 +401,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); diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index adc006e6f2..300a0cb464 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -59,18 +59,15 @@ test_obj_base (void) STATIC_ASSERT (sizeof (o->parent) == sizeof (GTypeInstance)); STATIC_ASSERT (&c->parent == (void *) c); - STATIC_ASSERT (&c->parent.g_type_class == (void *) c); - STATIC_ASSERT (&c->parent.g_type == (void *) c); - STATIC_ASSERT (&c->parent.g_type == &k->g_type); + 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) == sizeof (GTypeClass)); + STATIC_ASSERT (sizeof (c->parent.parent) == sizeof (GTypeClass)); STATIC_ASSERT (&o->parent == (void *) o); STATIC_ASSERT (&o->parent.klass == (void *) &o->_class); - STATIC_ASSERT (G_STRUCT_OFFSET (NMPObject, _ref_count) == sizeof (NMObjBaseInst)); - STATIC_ASSERT (G_STRUCT_OFFSET (NMPClass, obj_type_name) == sizeof (NMObjBaseClass)); - obj = (NMObjBaseInst *) obj_cancellable; g_assert (!NMP_CLASS_IS_VALID ((NMPClass *) obj->klass)); g_assert (G_TYPE_CHECK_INSTANCE_TYPE (obj, G_TYPE_CANCELLABLE)); From 89385bd9683c521fbc85b5e452459c3d46d4528d Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 12 Jun 2017 08:16:47 +0200 Subject: [PATCH 09/36] core: pass NMDedupMultiIndex instance to NMIP4Config and other NMIP4Config, NMIP6Config, and NMPlatform shall share one NMDedupMultiIndex instance. For that, pass an NMDedupMultiIndex instance to NMPlatform and NMNetns. NMNetns than passes it on to NMDevice, NMDhcpClient, NMIP4Config and NMIP6Config. So currently NMNetns is the access point to the shared NMDedupMultiIndex instance, and it gets it from it's NMPlatform instance. The NMDedupMultiIndex instance is really a singleton, we don't want multiple instances of it. However, for testing, instead of adding a singleton instance, pass the instance explicitly around. --- src/devices/nm-device.c | 79 +++++++++++++++++++-------- src/devices/nm-device.h | 1 + src/devices/wwan/nm-modem-broadband.c | 6 +- src/devices/wwan/nm-modem-ofono.c | 3 +- src/dhcp/nm-dhcp-client.c | 33 ++++++++++- src/dhcp/nm-dhcp-client.h | 6 +- src/dhcp/nm-dhcp-dhclient-utils.c | 8 ++- src/dhcp/nm-dhcp-dhclient-utils.h | 3 +- src/dhcp/nm-dhcp-dhclient.c | 7 ++- src/dhcp/nm-dhcp-manager.c | 13 ++++- src/dhcp/nm-dhcp-manager.h | 3 + src/dhcp/nm-dhcp-systemd.c | 23 +++++--- src/dhcp/nm-dhcp-utils.c | 12 ++-- src/dhcp/nm-dhcp-utils.h | 6 +- src/dhcp/tests/test-dhcp-dhclient.c | 11 +++- src/dhcp/tests/test-dhcp-utils.c | 72 ++++++++++++------------ src/nm-iface-helper.c | 16 ++++-- src/nm-ip4-config.c | 31 ++++++++++- src/nm-ip4-config.h | 7 ++- src/nm-ip6-config.c | 34 ++++++++++-- src/nm-ip6-config.h | 7 ++- src/nm-netns.c | 8 +++ src/nm-netns.h | 2 + src/nm-test-utils-core.h | 30 ++++++++-- src/nm-types.h | 2 + src/platform/nm-platform.c | 22 ++++++++ src/platform/nm-platform.h | 2 + src/ppp/nm-ppp-manager.c | 6 +- src/tests/test-ip4-config.c | 12 ++-- src/tests/test-ip6-config.c | 12 ++-- src/vpn/nm-vpn-connection.c | 24 +++++--- 31 files changed, 366 insertions(+), 135 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 3abf46cb10..dd9c96cf91 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -35,6 +35,8 @@ #include #include +#include "nm-utils/nm-dedup-multi.h" + #include "nm-common-macros.h" #include "nm-device-private.h" #include "NetworkManagerUtils.h" @@ -647,12 +649,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 +5080,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 +5237,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)); @@ -5430,7 +5452,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 +5461,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 +5477,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 +5486,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 +5568,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 +5845,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 +5926,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 +6034,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 +6195,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 +6295,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 +6307,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 +6725,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 +6854,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 +6884,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 +7304,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 +7826,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 +7901,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 +7948,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 +8535,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 +8950,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 +8992,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 +10587,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 +10706,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 +10782,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/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 #include +#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 #include +#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 #include +#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 #include +#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 #include +#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 #include +#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 #include +#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..0d4e7f78e1 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -23,6 +23,7 @@ #include #include +#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); @@ -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); } @@ -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/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..9ec7eebb95 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -26,6 +26,8 @@ #include #include +#include "nm-utils/nm-dedup-multi.h" + #include "nm-utils.h" #include "platform/nm-platform.h" #include "platform/nm-platform-utils.h" @@ -44,6 +46,7 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF); /*****************************************************************************/ NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config, + PROP_MULTI_IDX, PROP_IFINDEX, PROP_ADDRESS_DATA, PROP_ADDRESSES, @@ -80,6 +83,7 @@ typedef struct { GArray *wins; GVariant *address_data_variant; GVariant *addresses_variant; + NMDedupMultiIndex *multi_idx; } NMIP4ConfigPrivate; struct _NMIP4Config { @@ -103,6 +107,12 @@ 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 @@ -259,7 +269,7 @@ 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; @@ -272,7 +282,7 @@ nm_ip4_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resol 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); @@ -2467,6 +2477,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); @@ -2496,10 +2513,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); } @@ -2523,6 +2541,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 +2557,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..1a336968fd 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -34,6 +34,7 @@ typedef struct _NMIP4ConfigClass NMIP4ConfigClass; /* internal */ +#define NM_IP4_CONFIG_MULTI_IDX "multi-idx" #define NM_IP4_CONFIG_IFINDEX "ifindex" /* public*/ @@ -54,12 +55,14 @@ typedef struct _NMIP4ConfigClass NMIP4ConfigClass; GType nm_ip4_config_get_type (void); -NMIP4Config * nm_ip4_config_new (int ifindex); +NMIP4Config * nm_ip4_config_new (struct _NMDedupMultiIndex *multi_idx, + int ifindex); int nm_ip4_config_get_ifindex (const NMIP4Config *config); +struct _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 (struct _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); diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index af88b21c74..7724ad4831 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -26,6 +26,8 @@ #include #include +#include "nm-utils/nm-dedup-multi.h" + #include "nm-utils.h" #include "platform/nm-platform.h" #include "platform/nm-platform-utils.h" @@ -53,6 +55,7 @@ typedef struct { GPtrArray *dns_options; GVariant *address_data_variant; GVariant *addresses_variant; + NMDedupMultiIndex *multi_idx; } NMIP6ConfigPrivate; struct _NMIP6Config { @@ -69,6 +72,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, @@ -90,6 +94,12 @@ 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) { @@ -301,7 +311,7 @@ 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; @@ -315,7 +325,7 @@ nm_ip6_config_capture (NMPlatform *platform, int ifindex, gboolean capture_resol 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); @@ -2229,6 +2239,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); @@ -2256,10 +2273,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 +2289,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; } @@ -2292,6 +2311,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 +2327,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..5dadf796f6 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -36,6 +36,7 @@ typedef struct _NMIP6ConfigClass NMIP6ConfigClass; /* internal */ +#define NM_IP6_CONFIG_MULTI_IDX "multi-idx" #define NM_IP6_CONFIG_IFINDEX "ifindex" /* public */ @@ -55,13 +56,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, 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-test-utils-core.h b/src/nm-test-utils-core.h index 4e8e2f98e0..8ee7205de8 100644 --- a/src/nm-test-utils-core.h +++ b/src/nm-test-utils-core.h @@ -265,13 +265,24 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP #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 +292,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-platform.c b/src/platform/nm-platform.c index 7cc582e863..80e2efd147 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -35,6 +35,7 @@ #include "nm-utils.h" #include "nm-core-internal.h" +#include "nm-utils/nm-dedup-multi.h" #include "nm-core-utils.h" #include "nm-platform-utils.h" @@ -85,6 +86,7 @@ enum { typedef struct _NMPlatformPrivate { bool log_with_ptr:1; + NMDedupMultiIndex *multi_idx; } NMPlatformPrivate; G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT) @@ -193,6 +195,23 @@ nm_platform_get () /*****************************************************************************/ +NMDedupMultiIndex * +nm_platform_get_multi_idx (NMPlatform *self) +{ + NMPlatformPrivate *priv; + + g_return_val_if_fail (NM_IS_PLATFORM (self), NULL); + + priv = NM_PLATFORM_GET_PRIVATE (self); + + if (G_UNLIKELY (!priv->multi_idx)) + priv->multi_idx = nm_dedup_multi_index_new (); + + return priv->multi_idx; +} + +/*****************************************************************************/ + /** * _nm_platform_error_to_string: * @error_code: the error code to stringify. @@ -4755,7 +4774,10 @@ static void finalize (GObject *object) { NMPlatform *self = NM_PLATFORM (object); + NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE (self); + if (priv->multi_idx) + nm_dedup_multi_index_unref (priv->multi_idx); g_clear_object (&self->_netns); } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index b7dcb4caca..71dd7f9ff6 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -1043,4 +1043,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/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-ip4-config.c b/src/tests/test-ip4-config.c index cd5b108903..d9afb4c6ac 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); @@ -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,7 +229,7 @@ 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"); @@ -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..bbb3278bc9 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)); @@ -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,7 +200,7 @@ 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); @@ -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/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index ecc820685c..9a0de7ebfe 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -1046,10 +1046,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 +1067,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); } @@ -1436,7 +1442,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)); @@ -1595,7 +1602,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)); From 935411e5c03dcb62d5b2a85e67bf3220c75d0f5e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 12 Jun 2017 18:40:14 +0200 Subject: [PATCH 10/36] core: refactor NMIP4Config to use dedup-index for IPv4 routes Eventually, every NMPlatformIP4Route, NMPlatformIP6Route, NMPlatformIP4Address and NMPlatformIP6Address should be shared an deduplicated via the global NMDedupMultiIndex instance. As first proof of concept, refactor NMIP4Config to track IPv4 routes via the shared multi_idx. There is later potential for improvement, when we pass (deduplicated) NMPObject instances around instead of plain NMPlatformIP4Route, which needs still a lot of comparing and cloning. --- src/dhcp/tests/test-dhcp-utils.c | 6 +- src/dns/nm-dns-dnsmasq.c | 9 +- src/nm-dispatcher.c | 5 +- src/nm-ip4-config.c | 506 +++++++++++++++++++++---------- src/nm-ip4-config.h | 31 +- src/nm-pacrunner-manager.c | 8 +- src/tests/test-ip4-config.c | 12 +- src/vpn/nm-vpn-connection.c | 17 +- 8 files changed, 408 insertions(+), 186 deletions(-) diff --git a/src/dhcp/tests/test-dhcp-utils.c b/src/dhcp/tests/test-dhcp-utils.c index 0d4e7f78e1..f3fa963e52 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -135,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); @@ -144,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); @@ -221,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); diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index a6204ae4a0..730134b5e1 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); diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 0d482e0cad..6bea925488 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; diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 9ec7eebb95..1f0d86d30e 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -29,6 +29,7 @@ #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" @@ -45,6 +46,78 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF); /*****************************************************************************/ +static gboolean +_idx_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; +} + +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->ip4_route.plen); + break; + case NMP_OBJECT_TYPE_IP6_ROUTE: + g_return_val_if_reached (0); + 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 _idx_obj_id_equal_ip4_route (&o_a->ip4_route, &o_b->ip4_route); + case NMP_OBJECT_TYPE_IP6_ROUTE: + g_return_val_if_reached (FALSE); + 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, @@ -73,7 +146,6 @@ typedef struct { gint dns_priority; gint64 route_metric; GArray *addresses; - GArray *routes; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; @@ -84,6 +156,7 @@ typedef struct { GVariant *address_data_variant; GVariant *addresses_variant; NMDedupMultiIndex *multi_idx; + NMDedupMultiIdxType idx_ip4_routes; } NMIP4ConfigPrivate; struct _NMIP4Config { @@ -101,6 +174,10 @@ 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) { @@ -124,6 +201,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 = (NMPObject *) e->box->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->box->obj) == NMP_OBJECT_TYPE_IP4_ROUTE); + NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->box->obj)->ip4_route)); + } + return has_next; +} + +/*****************************************************************************/ + /** * nm_ip4_config_capture_resolv_conf(): * @nameservers: array of guint32 @@ -196,13 +316,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 @@ -277,6 +390,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i guint32 lowest_metric = G_MAXUINT32; guint32 old_gateway = 0; gboolean old_has_gateway = FALSE; + gs_unref_array GArray *routes = NULL; /* Slaves have no IP configuration */ if (nm_platform_link_get_master (platform, ifindex) > 0) @@ -286,18 +400,17 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i 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); + routes = nm_platform_ip4_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT); /* 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); + for (i = 0; i < routes->len; ) { + const NMPlatformIP4Route *route = &g_array_index (routes, NMPlatformIP4Route, i); if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { if (route->metric < lowest_metric) { @@ -306,7 +419,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i } priv->has_gateway = TRUE; /* Remove the default route from the list */ - g_array_remove_index_fast (priv->routes, i); + g_array_remove_index_fast (routes, i); continue; } i++; @@ -320,18 +433,21 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i * 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); + for (i = 0; i < routes->len; i++) { + const NMPlatformIP4Route *route = &g_array_index (routes, NMPlatformIP4Route, i); if ( (route->plen == 32) && (route->network == priv->gateway) && (route->gateway == 0)) { - g_array_remove_index (priv->routes, i); + g_array_remove_index (routes, i); i--; } } } + for (i = 0; i < routes->len; i++) + _add_route (config, NULL, &g_array_index (routes, NMPlatformIP4Route, i)); + /* If the interface has the default route, and has IPv4 addresses, capture * nameservers from /etc/resolv.conf. */ @@ -367,11 +483,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) { @@ -414,20 +534,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; } @@ -547,7 +662,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 */ @@ -583,10 +698,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 ()); @@ -599,7 +716,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); @@ -646,8 +762,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. */ @@ -700,6 +815,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); @@ -725,8 +841,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) @@ -821,22 +939,6 @@ _nameservers_get_index (const NMIP4Config *self, guint32 ns) return -1; } -static int -_routes_get_index (const NMIP4Config *self, const NMPlatformIP4Route *route) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); - guint i; - - for (i = 0; i < priv->routes->len; i++) { - const NMPlatformIP4Route *r = &g_array_index (priv->routes, NMPlatformIP4Route, i); - - if ( route->network == r->network - && route->plen == r->plen) - return (int) i; - } - return -1; -} - static int _domains_get_index (const NMIP4Config *self, const char *domain) { @@ -924,12 +1026,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 */ @@ -957,10 +1064,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 */ @@ -1020,14 +1127,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)); @@ -1048,12 +1162,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 */ @@ -1091,7 +1208,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); @@ -1158,26 +1275,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 (!_idx_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 */ @@ -1339,8 +1475,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); @@ -1370,8 +1509,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++) @@ -1621,13 +1760,88 @@ 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; + const NMDedupMultiBox *box_old; + + 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, + &box_old)) { + if (box_old) + nm_dedup_multi_box_unref (priv->multi_idx, box_old); + return; + } + + if (box_old) { + NMIPConfigSource old_source; + + old_source = ((const NMPObject *) box_old->obj)->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 (); + } + nm_dedup_multi_box_unref (priv->multi_idx, box_old); + } + + _notify (config, PROP_ROUTE_DATA); + _notify (config, PROP_ROUTES); +} + /** * nm_ip4_config_add_route: * @config: the #NMIP4Config @@ -1641,76 +1855,70 @@ nm_ip4_config_reset_routes (NMIP4Config *config) void nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - NMIPConfigSource old_source; - int i; - - g_return_if_fail (new != NULL); + g_return_if_fail (config); + g_return_if_fail (new); g_return_if_fail (new->plen > 0 && new->plen <= 32); - g_return_if_fail (priv->ifindex > 0); + g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (config)->ifindex > 0); - for (i = 0; i < priv->routes->len; i++ ) { - NMPlatformIP4Route *item = &g_array_index (priv->routes, NMPlatformIP4Route, i); - - if (routes_are_duplicate (item, new, FALSE)) { - if (nm_platform_ip4_route_cmp (item, new) == 0) - return; - old_source = item->rt_source; - memcpy (item, new, sizeof (*item)); - /* Restore highest priority source */ - item->rt_source = MAX (old_source, new->rt_source); - item->ifindex = priv->ifindex; - goto NOTIFY; - } - } - - g_array_append_val (priv->routes, *new); - g_array_index (priv->routes, NMPlatformIP4Route, priv->routes->len - 1).ifindex = priv->ifindex; -NOTIFY: - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); + _add_route (config, NULL, new); } void -nm_ip4_config_del_route (NMIP4Config *config, guint i) +_nmtst_nm_ip4_config_del_route (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + const NMPlatformIP4Route *r; - g_return_if_fail (i < priv->routes->len); + r = _nmtst_nm_ip4_config_get_route (self, i); + g_return_if_fail (r); - g_array_remove_index (priv->routes, i); - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); + if (nm_dedup_multi_index_remove_obj (priv->multi_idx, + &priv->idx_ip4_routes, + NMP_OBJECT_UP_CAST (r)) != 1) + g_return_if_reached (); + _notify (self, PROP_ROUTE_DATA); + _notify (self, PROP_ROUTES); } guint -nm_ip4_config_get_num_routes (const NMIP4Config *config) +nm_ip4_config_get_num_routes (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMDedupMultiHeadEntry *head_entry; - return priv->routes->len; + head_entry = _idx_ip4_routes (self); + nm_assert ((head_entry ? head_entry->len : 0) == c_list_length (&head_entry->lst_entries_head)); + return head_entry ? head_entry->len : 0; } const NMPlatformIP4Route * -nm_ip4_config_get_route (const NMIP4Config *config, guint i) +_nmtst_nm_ip4_config_get_route (const NMIP4Config *self, guint i) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMDedupMultiHeadEntry *head_entry; + CList *iter; + guint j; - return &g_array_index (priv->routes, NMPlatformIP4Route, i); + head_entry = _idx_ip4_routes (self); + if (head_entry) { + j = 0; + c_list_for_each (iter, &head_entry->lst_entries_head) { + if (i == j) + return _entry_iter_get_ip4_route (iter); + j++; + } + } + g_return_val_if_reached (NULL); } const NMPlatformIP4Route * -nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host) +nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, guint32 host) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - guint i; - NMPlatformIP4Route *best_route = NULL; + const NMPlatformIP4Route *best_route = NULL; + const NMPlatformIP4Route *item; + NMDedupMultiIter ipconf_iter; g_return_val_if_fail (host, NULL); - for (i = 0; i < priv->routes->len; i++) { - NMPlatformIP4Route *item = &g_array_index (priv->routes, NMPlatformIP4Route, i); - + nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, self, &item) { if (item->gateway != 0) continue; @@ -1725,7 +1933,6 @@ nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host best_route = item; } - return best_route; } @@ -2193,6 +2400,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); @@ -2208,9 +2417,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); @@ -2295,6 +2503,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: @@ -2303,7 +2514,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; @@ -2370,14 +2580,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", @@ -2402,13 +2606,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 @@ -2501,8 +2700,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); @@ -2528,10 +2729,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); diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index 1a336968fd..f1f2979232 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -24,6 +24,27 @@ #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)); \ + ) + +/*****************************************************************************/ + #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)) @@ -55,14 +76,14 @@ typedef struct _NMIP4ConfigClass NMIP4ConfigClass; GType nm_ip4_config_get_type (void); -NMIP4Config * nm_ip4_config_new (struct _NMDedupMultiIndex *multi_idx, +NMIP4Config * nm_ip4_config_new (NMDedupMultiIndex *multi_idx, int ifindex); int nm_ip4_config_get_ifindex (const NMIP4Config *config); -struct _NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self); +NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self); -NMIP4Config *nm_ip4_config_capture (struct _NMDedupMultiIndex *multi_idx, 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); @@ -93,9 +114,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-pacrunner-manager.c b/src/nm-pacrunner-manager.c index 0a1cd823f4..a4c345e5d7 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); diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index d9afb4c6ac..e865f5f26a 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -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); @@ -236,27 +236,27 @@ test_add_route_with_source (void) 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); diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 9a0de7ebfe..7c8f06ced6 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, @@ -1404,7 +1404,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)); @@ -1505,9 +1504,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)) { From 8822c454535e633b07cb070acdb32ab45f7f7308 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 21 Jun 2017 10:53:30 +0200 Subject: [PATCH 11/36] platform: use NM_SET_OUT() macro --- src/platform/nmp-object.c | 43 +++++++++++++++------------------------ 1 file changed, 16 insertions(+), 27 deletions(-) diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 751160f6f3..65610b5cdc 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -1858,10 +1858,8 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, old = g_hash_table_lookup (cache->idx_main, obj); - if (out_obj) - *out_obj = NULL; - if (out_was_visible) - *out_was_visible = FALSE; + NM_SET_OUT (out_obj, NULL); + NM_SET_OUT (out_was_visible, FALSE); if (!old) { if (!nmp_object_is_alive (obj)) @@ -1872,8 +1870,7 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, _nmp_object_fixup_link_udev_fields (obj, cache->use_udev); } - if (out_obj) - *out_obj = nmp_object_ref (obj); + NM_SET_OUT (out_obj, nmp_object_ref (obj)); if (pre_hook) pre_hook (cache, NULL, obj, NMP_CACHE_OPS_ADDED, user_data); @@ -1904,15 +1901,12 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, 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); + NM_SET_OUT (out_obj, nmp_object_ref (old)); + NM_SET_OUT (out_was_visible, nmp_object_is_visible (old)); return NMP_CACHE_OPS_UNCHANGED; } if (old->_link.udev.device) { @@ -1941,6 +1935,9 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, } else is_alive = nmp_object_is_alive (obj); + NM_SET_OUT (out_obj, nmp_object_ref (old)); + NM_SET_OUT (out_was_visible, nmp_object_is_visible (old)); + if (!is_alive) { /* the update would make @old invalid. Remove it. */ if (pre_hook) @@ -1967,10 +1964,8 @@ nmp_cache_update_link_udev (NMPCache *cache, int ifindex, struct udev_device *ud old = (NMPObject *) nmp_cache_lookup_link (cache, ifindex); - if (out_obj) - *out_obj = NULL; - if (out_was_visible) - *out_was_visible = FALSE; + NM_SET_OUT (out_obj, NULL); + NM_SET_OUT (out_was_visible, FALSE); if (!old) { if (!udevice) @@ -1994,10 +1989,8 @@ nmp_cache_update_link_udev (NMPCache *cache, int ifindex, struct udev_device *ud } 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); + NM_SET_OUT (out_obj, nmp_object_ref (old)); + NM_SET_OUT (out_was_visible, nmp_object_is_visible (old)); if (old->_link.udev.device == udevice) return NMP_CACHE_OPS_UNCHANGED; @@ -2035,20 +2028,16 @@ nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject old = (NMPObject *) nmp_cache_lookup_link (cache, ifindex); if (!old) { - if (out_obj) - *out_obj = NULL; - if (out_was_visible) - *out_was_visible = FALSE; + NM_SET_OUT (out_obj, NULL); + NM_SET_OUT (out_was_visible, FALSE); return NMP_CACHE_OPS_UNCHANGED; } 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); + NM_SET_OUT (out_obj, nmp_object_ref (old)); + NM_SET_OUT (out_was_visible, nmp_object_is_visible (old)); if (!nmp_cache_link_connected_needs_toggle (cache, old, NULL, NULL)) return NMP_CACHE_OPS_UNCHANGED; From 0b060d9bc5f8922924c625c69ac617dd3ac6d9bf Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 23 Jun 2017 15:46:40 +0200 Subject: [PATCH 12/36] platform/trivial: rename variable --- src/platform/nm-linux-platform.c | 188 +++++++++++++++---------------- 1 file changed, 94 insertions(+), 94 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 8d4df98616..18bb159243 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -255,7 +255,7 @@ 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_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType cache_op, gpointer user_data); static void cache_prune_candidates_prune (NMPlatform *platform); static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_for_acks); static void ASSERT_NETNS_CURRENT (NMPlatform *platform); @@ -2925,7 +2925,7 @@ process_events (NMPlatform *platform) /*****************************************************************************/ static void -do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cache_op, gboolean was_visible) +do_emit_signal (NMPlatform *platform, const NMPObject *obj_new, NMPCacheOpsType cache_op, gboolean was_visible) { gboolean is_visible; NMPObject obj_clone; @@ -2933,24 +2933,24 @@ do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cach 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)); + nm_assert (obj_new || cache_op == NMP_CACHE_OPS_UNCHANGED); + nm_assert (!obj_new || cache_op == NMP_CACHE_OPS_REMOVED || obj_new == nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj_new)); + nm_assert (!obj_new || cache_op != NMP_CACHE_OPS_REMOVED || obj_new != nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj_new)); ASSERT_NETNS_CURRENT (platform); switch (cache_op) { case NMP_CACHE_OPS_ADDED: - if (!nmp_object_is_visible (obj)) + if (!nmp_object_is_visible (obj_new)) return; break; case NMP_CACHE_OPS_UPDATED: - is_visible = nmp_object_is_visible (obj); + is_visible = nmp_object_is_visible (obj_new); 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 + * We raise a removed signal, but contrary to a real 'remove', @obj_new 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 @@ -2972,16 +2972,16 @@ do_emit_signal (NMPlatform *platform, const NMPObject *obj, NMPCacheOpsType cach return; } - klass = NMP_OBJECT_GET_CLASS (obj); + klass = NMP_OBJECT_GET_CLASS (obj_new); _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)); + nmp_object_to_string (obj_new, 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); + /* don't expose @obj_new directly, but clone the public fields. A signal handler might + * call back into NMPlatform which could invalidate (or modify) @obj_new. */ + memcpy (&obj_clone.object, &obj_new->object, klass->sizeof_public); g_signal_emit (platform, _nm_platform_signal_id_get (klass->signal_type_id), 0, @@ -3428,7 +3428,7 @@ cache_prune_candidates_prune (NMPlatform *platform) } static void -cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data) +cache_pre_hook (NMPCache *cache, const NMPObject *obj_old, const NMPObject *obj_new, NMPCacheOpsType cache_op, gpointer user_data) { NMPlatform *platform = user_data; NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); @@ -3436,63 +3436,63 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP char str_buf[sizeof (_nm_utils_to_string_buffer)]; char str_buf2[sizeof (_nm_utils_to_string_buffer)]; - 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)); + nm_assert (obj_old || obj_new); + nm_assert (NM_IN_SET (cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_REMOVED, NMP_CACHE_OPS_UPDATED)); + nm_assert (cache_op != NMP_CACHE_OPS_ADDED || (obj_old == NULL && NMP_OBJECT_IS_VALID (obj_new) && nmp_object_is_alive (obj_new))); + nm_assert (cache_op != NMP_CACHE_OPS_REMOVED || (obj_new == NULL && NMP_OBJECT_IS_VALID (obj_old) && nmp_object_is_alive (obj_old))); + nm_assert (cache_op != NMP_CACHE_OPS_UPDATED || (NMP_OBJECT_IS_VALID (obj_old) && nmp_object_is_alive (obj_old) && NMP_OBJECT_IS_VALID (obj_new) && nmp_object_is_alive (obj_new))); + 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)); - klass = old ? NMP_OBJECT_GET_CLASS (old) : NMP_OBJECT_GET_CLASS (new); + klass = obj_old ? NMP_OBJECT_GET_CLASS (obj_old) : NMP_OBJECT_GET_CLASS (obj_new); - nm_assert (klass == (new ? NMP_OBJECT_GET_CLASS (new) : NMP_OBJECT_GET_CLASS (old))); + nm_assert (klass == (obj_new ? NMP_OBJECT_GET_CLASS (obj_new) : NMP_OBJECT_GET_CLASS (obj_old))); _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 (priv->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 (priv->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,15 +3511,15 @@ 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; @@ -3537,14 +3537,14 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP } { /* 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 +3554,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 +3575,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 +3601,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 +3609,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 +3625,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 +3646,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 From 3edf2bff3dd84b3235b6393b406cfb44f5c14cf1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 27 Jun 2017 10:40:28 +0200 Subject: [PATCH 13/36] platform: fix lookup of all routes unrestricted to an ifindex Need to use the right NMPCacheIdType when looking up routes across all ifindexes. Fixes: 8f9dac01ac01a6a401a101f264b4f280c9ad4b9d --- src/platform/nmp-object.c | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 65610b5cdc..0f0ca36e95 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -1110,10 +1110,20 @@ nmp_cache_id_init_routes_visible (NMPCacheId *id, return nmp_cache_id_init_object_type (id, obj_type, TRUE); return nmp_cache_id_init_addrroute_visible_by_ifindex (id, obj_type, ifindex); } + if (ifindex <= 0) { + _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT); + id->object_type.obj_type = obj_type; + return id; + } _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT); - } else if (with_non_default) + } else if (with_non_default) { + if (ifindex <= 0) { + _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT); + id->object_type.obj_type = obj_type; + return id; + } _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT); - else + } else g_return_val_if_reached (NULL); id->object_type_by_ifindex.obj_type = obj_type; From 9440eefb6dc4939752bf049d1669a0a4d37213c2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 21 Jun 2017 10:53:34 +0200 Subject: [PATCH 14/36] platform: use NMDedupMultiIndex for routes in NMPCache Rework platform object cache to use NMDedupMultiIndex. Already previously, NMPCache used NMMultiIndex and had thus O(1) for most operations. What is new is: - Contrary to NMMultiIndex, NMDedupMultiIndex preserves the order of the cached items. That is crucial to handle routes properly as kernel will replace the first matching route based on network/plen/metric properties. See related bug rh#1337855. Without tracking the order of routes as they are exposed by kernel, we cannot properly maintain the route cache. - All NMPObject instances are now treated immutable, refcounted and get de-duplicated via NMDedupMultiIndex. This allows to have a global NMDedupMultiIndex that can be shared with NMIP4Config and NMRouteManager. It also allows to share the objects themselves. Immutable objects are so much nicer. We can get rid of the update pre-hook callback, which was required previously because we would mutate the object inplace. Now, we can just update the cache, and compare obj_old and obj_new after the fact. - NMMultiIndex was treated as an internal of NMPCache. On the other hand, NMDedupMultiIndex exposes NMDedupMultiHeadEntry, which is basically an object that allows to iterate over all related objects. That means, we can now lookup objects in the cache and give the NMDedupMultiHeadEntry instance to the caller, which then can iterate the list on it's own -- without need for copying anything. Currently, at various places we still create copies of lookup results. That can be improved later. The ability to share NMPObject instances should enable us to significantly improve performance and scale with large number of routes. Of course there is a memory overhead of having an index for each list entry. Each NMPObject may also require an NMDedupMultiEntry, NMDedupMultiHeadEntry, and NMDedupMultiBox item, which are tracked in a GHashTable. Optimally, one NMDedupMultiHeadEntry is the head for multiple objects, and NMDedupMultiBox is able to deduplicate several NMPObjects, so that there is a net saving. Also, each object type has several indexes of type NMPCacheIdType. So, worst case an NMPlatformIP4Route in the platform cache is tracked by 8 NMPCacheIdType indexes, for each we require a NMDedupMultiEntry, plus the shared NMDedupMultiHeadEntry. The NMDedupMultiBox instance is shared between the 8 indexes (and possibly other). --- src/nm-route-manager.c | 2 +- src/platform/nm-linux-platform.c | 423 +++--- src/platform/nm-linux-platform.h | 6 - src/platform/nm-platform.c | 33 + src/platform/nm-platform.h | 1 + src/platform/nmp-object.c | 1854 +++++++++++++++----------- src/platform/nmp-object.h | 237 ++-- src/platform/tests/test-nmp-object.c | 432 +++--- 8 files changed, 1691 insertions(+), 1297 deletions(-) diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index b58cdeb069..6c1f78ac96 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -1173,7 +1173,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/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 18bb159243..6edf38baa9 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -255,8 +255,11 @@ 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 cache_op, 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); @@ -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; @@ -2574,7 +2577,9 @@ typedef struct { 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 +2600,6 @@ typedef struct { gint is_handling; } delayed_action; - GHashTable *prune_candidates; - GHashTable *wifi_data; } NMLinuxPlatformPrivate; @@ -2913,29 +2916,20 @@ 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_new, NMPCacheOpsType cache_op, gboolean was_visible) +do_emit_signal (NMPlatform *platform, + NMPCacheOpsType cache_op, + const NMPObject *obj_old, + const NMPObject *obj_new) { - gboolean is_visible; - NMPObject obj_clone; + 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)); - nm_assert (obj_new || cache_op == NMP_CACHE_OPS_UNCHANGED); - nm_assert (!obj_new || cache_op == NMP_CACHE_OPS_REMOVED || obj_new == nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj_new)); - nm_assert (!obj_new || cache_op != NMP_CACHE_OPS_REMOVED || obj_new != nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj_new)); + ASSERT_nmp_cache_ops (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, cache_op, obj_old, obj_new); ASSERT_NETNS_CURRENT (platform); @@ -2943,52 +2937,49 @@ do_emit_signal (NMPlatform *platform, const NMPObject *obj_new, NMPCacheOpsType case NMP_CACHE_OPS_ADDED: if (!nmp_object_is_visible (obj_new)) return; + o = obj_new; break; case NMP_CACHE_OPS_UPDATED: - is_visible = nmp_object_is_visible (obj_new); - if (!was_visible && is_visible) + 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 (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_new 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). - */ + } else if (visible_old && !visible_new) { + o = obj_old; cache_op = NMP_CACHE_OPS_REMOVED; - } else if (!is_visible) + } 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 (!was_visible) + if (!nmp_object_is_visible (obj_old)) return; + o = obj_old; break; default: - g_assert (cache_op == NMP_CACHE_OPS_UNCHANGED); + nm_assert (cache_op == NMP_CACHE_OPS_UNCHANGED); return; } - klass = NMP_OBJECT_GET_CLASS (obj_new); + 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 (obj_new, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + nmp_object_to_string (o, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - /* don't expose @obj_new directly, but clone the public fields. A signal handler might - * call back into NMPlatform which could invalidate (or modify) @obj_new. */ - memcpy (&obj_clone.object, &obj_new->object, klass->sizeof_public); + nmp_object_ref (o); 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, + o->object.ifindex, + &o->object, (int) cache_op); + nmp_object_unref (o); } /*****************************************************************************/ @@ -3164,12 +3155,15 @@ 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 (priv->cache, master_ifindex, &obj_old, &obj_new); + if (cache_op == NMP_CACHE_OPS_UNCHANGED) + return; + cache_on_change (platform, cache_op, obj_old, obj_new); + do_emit_signal (platform, cache_op, obj_old, obj_new); } static void @@ -3290,7 +3284,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,101 +3347,69 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, /*****************************************************************************/ static void -cache_prune_candidates_record_all (NMPlatform *platform, NMPObjectType obj_type) +cache_prune_one_type (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) -{ - 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); - } -} - -static void -cache_prune_candidates_prune (NMPlatform *platform) -{ - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - GHashTable *prune_candidates; - GHashTableIter iter; + NMDedupMultiIter iter; const NMPObject *obj; - gboolean was_visible; NMPCacheOpsType cache_op; + NMPLookup lookup; - if (!priv->prune_candidates) - return; + nmp_lookup_init_obj_type (&lookup, + obj_type, + FALSE); + nm_dedup_multi_iter_init (&iter, + nmp_cache_lookup (priv->cache, + &lookup)); + while (nm_dedup_multi_iter_next (&iter)) { + if (iter.current->dirty) { + nm_auto_nmpobj const NMPObject *obj_old = NULL; - prune_candidates = priv->prune_candidates; - priv->prune_candidates = NULL; - - 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; - - _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); + obj = iter.current->box->obj; + _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_old); + nm_assert (cache_op == NMP_CACHE_OPS_REMOVED); + cache_on_change (platform, cache_op, obj_old, NULL); + do_emit_signal (platform, cache_op, obj_old, NULL); + } } - - g_hash_table_unref (prune_candidates); } static void -cache_pre_hook (NMPCache *cache, const NMPObject *obj_old, const NMPObject *obj_new, NMPCacheOpsType cache_op, gpointer user_data) +cache_prune_all (NMPlatform *platform) +{ + NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); + DelayedActionType iflags, action_type; + + 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)]; + + if (*p) { + *p = FALSE; + cache_prune_one_type (platform, delayed_action_refresh_to_object_type (iflags)); + } + } +} + +static void +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)]; - nm_assert (obj_old || obj_new); - nm_assert (NM_IN_SET (cache_op, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_REMOVED, NMP_CACHE_OPS_UPDATED)); - nm_assert (cache_op != NMP_CACHE_OPS_ADDED || (obj_old == NULL && NMP_OBJECT_IS_VALID (obj_new) && nmp_object_is_alive (obj_new))); - nm_assert (cache_op != NMP_CACHE_OPS_REMOVED || (obj_new == NULL && NMP_OBJECT_IS_VALID (obj_old) && nmp_object_is_alive (obj_old))); - nm_assert (cache_op != NMP_CACHE_OPS_UPDATED || (NMP_OBJECT_IS_VALID (obj_old) && nmp_object_is_alive (obj_old) && NMP_OBJECT_IS_VALID (obj_new) && nmp_object_is_alive (obj_new))); - 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)); + ASSERT_nmp_cache_ops (priv->cache, cache_op, obj_old, obj_new); + + if (cache_op == NMP_CACHE_OPS_UNCHANGED) + return; klass = obj_old ? NMP_OBJECT_GET_CLASS (obj_old) : NMP_OBJECT_GET_CLASS (obj_new); - nm_assert (klass == (obj_new ? NMP_OBJECT_GET_CLASS (obj_new) : NMP_OBJECT_GET_CLASS (obj_old))); - _LOGt ("update-cache-%s: %s: %s%s%s", klass->obj_type_name, (cache_op == NMP_CACHE_OPS_UPDATED @@ -3478,7 +3440,7 @@ cache_pre_hook (NMPCache *cache, const NMPObject *obj_old, const NMPObject *obj_ { /* check whether we are about to change a master link that needs toggling connected state. */ if ( obj_new /* <-- nonsensical, make coverity happy */ - && nmp_cache_link_connected_needs_toggle (cache, obj_new, obj_new, obj_old)) + && nmp_cache_link_connected_needs_toggle (priv->cache, obj_new, obj_new, obj_old)) delayed_action_schedule (platform, DELAYED_ACTION_TYPE_MASTER_CONNECTED, GINT_TO_POINTER (obj_new->link.ifindex)); } { @@ -3522,16 +3484,16 @@ cache_pre_hook (NMPCache *cache, const NMPObject *obj_old, const NMPObject *obj_ ifindex = obj_new->link.ifindex; if (ifindex > 0) { - const NMPlatformLink *const *links; + NMPLookup lookup; + NMDedupMultiIter iter; + const NMPlatformLink *l; - 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)); - } + nmp_lookup_init_link (&lookup, FALSE); + nmp_cache_iter_for_each_link (&iter, + nmp_cache_lookup (priv->cache, &lookup), + &l) { + if (l->parent == ifindex) + delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (l->ifindex)); } } } @@ -3664,14 +3626,12 @@ 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; @@ -3739,8 +3699,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 (priv->cache, 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 +3737,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 (priv->cache, + delayed_action_refresh_to_object_type (iflags)); } FOR_EACH_DELAYED_ACTION (iflags, action_type) { @@ -3898,12 +3865,10 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event { 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; msghdr = nlmsg_hdr (msg); @@ -3932,31 +3897,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) { + { + nm_auto_nmpobj const NMPObject *obj_old = NULL; + nm_auto_nmpobj const NMPObject *obj_new = NULL; - 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); + switch (msghdr->nlmsg_type) { - cache_post (platform, msghdr, cache_op, obj, obj_cache); + case RTM_NEWLINK: + case RTM_NEWADDR: + case RTM_NEWROUTE: + case RTM_GETLINK: + cache_op = nmp_cache_update_netlink (priv->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); + do_emit_signal (platform, cache_op, obj_old, obj_new); + break; - 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_old, &obj_new); + if (cache_op != NMP_CACHE_OPS_UNCHANGED) { + cache_on_change (platform, cache_op, obj_old, obj_new); + do_emit_signal (platform, cache_op, obj_old, obj_new); + } + 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; + default: + break; + } } - - cache_prune_candidates_drop (platform, obj_cache); } /*****************************************************************************/ @@ -3973,25 +3943,15 @@ cache_lookup_link (NMPlatform *platform, int ifindex) 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; + NMPLookup lookup; - 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)); + nmp_lookup_init_link (&lookup, TRUE); + return nmp_cache_lookup_to_array (nmp_cache_lookup (priv->cache, &lookup), + NMP_OBJECT_TYPE_LINK); } static const NMPlatformLink * @@ -5733,10 +5693,9 @@ 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; if (ifindex <= 0) return FALSE; @@ -5751,21 +5710,23 @@ 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, + TRUE); + if (nmp_cache_lookup (priv->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)) + nmp_lookup_init_addrroute (&lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex, + TRUE); + nmp_cache_iter_for_each (&iter, + nmp_cache_lookup (priv->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; } @@ -5844,15 +5805,15 @@ static GArray * ipx_address_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - NMPCacheId cache_id; + NMPLookup lookup; 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)); + nmp_lookup_init_addrroute (&lookup, + obj_type, + ifindex, + TRUE); + return nmp_cache_lookup_to_array (nmp_cache_lookup (priv->cache, &lookup), + obj_type); } static GArray * @@ -6010,12 +5971,13 @@ 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; + NMDedupMultiIter iter; + NMPLookup lookup; + const NMDedupMultiHeadEntry *head_entry; GArray *array; const NMPClass *klass; + const NMPObject *o; gboolean with_rtprot_kernel; - guint i, len; nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); @@ -6024,23 +5986,24 @@ ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NM 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); + head_entry = nmp_cache_lookup (priv->cache, + nmp_lookup_init_route_visible (&lookup, + obj_type, + ifindex, + NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT), + NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))); - routes = (const NMPlatformIPRoute *const*) nmp_cache_lookup_multi (priv->cache, &cache_id, &len); - - array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len); + array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, head_entry ? head_entry->len : 0); 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); + nmp_cache_iter_for_each (&iter, + head_entry, + &o) { + nm_assert (NMP_OBJECT_GET_CLASS (o) == klass); if ( with_rtprot_kernel - || routes[i]->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) - g_array_append_vals (array, routes[i], 1); + || o->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + g_array_append_vals (array, &o->ip_route, 1); } return array; } @@ -6634,18 +6597,19 @@ cache_update_link_udev (NMPlatform *platform, 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 (priv->cache, 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); + do_emit_signal (platform, cache_op, obj_old, obj_new); } } @@ -6753,19 +6717,15 @@ 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) { + if ( nmp_netns_is_initial () + && access ("/sys", W_OK) == 0) { priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL }, handle_udev_event, self); } @@ -6782,6 +6742,9 @@ constructed (GObject *_object) nm_assert (!platform->_netns || platform->_netns == nmp_netns_get_current ()); + priv->cache = nmp_cache_new (nm_platform_get_multi_idx (platform), + priv->udev_client != NULL); + _LOGD ("create (%s netns, %s, %s udev)", !platform->_netns ? "ignore" : "use", !platform->_netns && nmp_netns_is_initial () @@ -6892,8 +6855,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); } 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.c b/src/platform/nm-platform.c index 80e2efd147..12dd232e3b 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4149,6 +4149,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) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 71dd7f9ff6..aaa549aeb2 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -1024,6 +1024,7 @@ 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); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 0f0ca36e95..c63d3f2c51 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,14 +71,319 @@ 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 const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class; + +static guint +_idx_obj_id_hash (const NMDedupMultiIdxType *idx_type, + const NMDedupMultiObj *obj) +{ + 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; + + /* 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_OBJECT_TYPE_VISIBLE_ONLY: + if (!nmp_object_is_visible (obj_a)) + return 0; + if (obj_b) { + return NMP_OBJECT_GET_TYPE (obj_a) == NMP_OBJECT_GET_TYPE (obj_b) + && 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_ROUTES_VISIBLE_NO_DEFAULT: + 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_ROUTES_VISIBLE_ONLY_DEFAULT: + 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_VISIBLE_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_VISIBLE_BY_IFINDEX_NO_DEFAULT: + 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) + || obj_a->object.ifindex <= 0 + || !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) + && 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_VISIBLE_BY_IFINDEX_ONLY_DEFAULT: + 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) + || obj_a->object.ifindex <= 0 + || !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) + && 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_IP4: + if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ROUTE) + || obj_a->object.ifindex <= 0) + return 0; + if (obj_b) { + return NMP_OBJECT_GET_TYPE (obj_a) == 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_a->ip4_route.network == obj_b->ip4_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_a->ip4_route.network); + return _HASH_NON_ZERO (h); + } + return 1; + + case NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6: + if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP6_ROUTE) + || obj_a->object.ifindex <= 0) + return 0; + if (obj_b) { + return NMP_OBJECT_GET_TYPE (obj_a) == 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 + && 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, 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; +} + +/*****************************************************************************/ + static int _vlan_xgress_qos_mappings_cmp (guint n_map, const NMVlanQosMapping *map1, @@ -139,12 +449,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 */ @@ -168,17 +484,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; - if (nmp_cache_link_connected_needs_toggle (cache, obj, NULL, NULL)) + 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 (!*obj_new) + obj = *obj_new = nmp_object_clone (obj, FALSE); obj->link.connected = !obj->link.connected; + } } /*****************************************************************************/ @@ -193,29 +526,34 @@ nmp_class_from_type (NMPObjectType obj_type) /*****************************************************************************/ -NMPObject * -nmp_object_ref (NMPObject *obj) +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->_ref_count != NM_OBJ_REF_COUNT_STACKINIT, NULL); - obj->_ref_count++; + ((NMPObject *) obj)->_ref_count++; return obj; } void -nmp_object_unref (NMPObject *obj) +nmp_object_unref (const NMPObject *obj) { if (obj) { - g_return_if_fail (obj->_ref_count > 0); - g_return_if_fail (obj->_ref_count != NM_OBJ_REF_COUNT_STACKINIT); - if (--obj->_ref_count <= 0) { - const NMPClass *klass = obj->_class; + NMPObject *o = (NMPObject *) obj; + + g_return_if_fail (o->_ref_count > 0); + g_return_if_fail (o->_ref_count != NM_OBJ_REF_COUNT_STACKINIT); + if (--o->_ref_count <= 0) { + const NMPClass *klass = o->_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); + klass->cmd_obj_dispose (o); + g_slice_free1 (klass->sizeof_data + G_STRUCT_OFFSET (NMPObject, object), o); } } } @@ -276,9 +614,24 @@ 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->_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)); @@ -308,7 +661,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; @@ -317,7 +670,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; } @@ -331,7 +684,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; @@ -348,7 +701,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; @@ -364,7 +717,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; @@ -381,7 +734,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; @@ -423,9 +776,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,%u,%ccache,%calive,%cvisible; %s]", + "[%s,%p,%u,%calive,%cvisible; %s]", klass->obj_type_name, obj, obj->_ref_count, - obj->is_cached ? '+' : '-', nmp_object_is_alive (obj) ? '+' : '-', nmp_object_is_visible (obj) ? '+' : '-', NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2))); @@ -450,9 +802,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,%u,%ccache,%calive,%cvisible,%cin-nl,%p; %s]", + "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; %s]", klass->obj_type_name, obj, obj->_ref_count, - obj->is_cached ? '+' : '-', nmp_object_is_alive (obj) ? '+' : '-', nmp_object_is_visible (obj) ? '+' : '-', obj->_link.netlink.is_in_netlink ? '+' : '-', @@ -491,9 +842,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,%u,%ccache,%calive,%cvisible; %s]", + "[%s,%p,%u,%calive,%cvisible; %s]", klass->obj_type_name, obj, obj->_ref_count, - obj->is_cached ? '+' : '-', nmp_object_is_alive (obj) ? '+' : '-', nmp_object_is_visible (obj) ? '+' : '-', nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2))); @@ -580,6 +930,21 @@ _vt_cmd_obj_hash_not_implemented (const NMPObject *obj) g_return_val_if_reached (0); } +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); + /* TODO: properly hash lnk objects. */ + h = NM_HASH_COMBINE (h, !!obj->_link.netlink.lnk); + h = NM_HASH_COMBINE (h, GPOINTER_TO_UINT (obj->_link.udev.device)); + return h; +} + static guint _vt_cmd_plobj_hash_not_implemented (const NMPlatformObject *obj) { @@ -977,228 +1342,6 @@ _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 = NM_HASH_COMBINE (hash, ((char *) id)[i]); - 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; -} - -void -nmp_cache_id_destroy (NMPCacheId *id) -{ - guint n; - - n = _nmp_cache_id_size_by_type (id->_id_type); - g_slice_free1 (n, id); -} - -/*****************************************************************************/ - -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) -{ - _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); - - if (ifindex <= 0) - return nmp_cache_id_init_object_type (id, obj_type, TRUE); - - _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; -} - -NMPCacheId * -nmp_cache_id_init_routes_visible (NMPCacheId *id, - NMPObjectType obj_type, - gboolean with_default, - gboolean with_non_default, - int ifindex) -{ - 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); - } - if (ifindex <= 0) { - _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT); - id->object_type.obj_type = obj_type; - return id; - } - _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT); - } else if (with_non_default) { - if (ifindex <= 0) { - _nmp_cache_id_init (id, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT); - id->object_type.obj_type = obj_type; - return id; - } - _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; -} - -NMPCacheId * -nmp_cache_id_init_link_by_ifname (NMPCacheId *id, - const char *ifname) -{ - 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; -} - -NMPCacheId * -nmp_cache_id_init_routes_by_destination_ip4 (NMPCacheId *id, - guint32 network, - guint8 plen, - guint32 metric) -{ - _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; -} - -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; -} - -/*****************************************************************************/ - -static gboolean -_nmp_object_init_cache_id (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id) -{ - const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); - - 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); - } -} - static const guint8 _supported_cache_ids_link[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY, @@ -1206,23 +1349,6 @@ static const guint8 _supported_cache_ids_link[] = { 0, }; -static gboolean -_vt_cmd_obj_init_cache_id_link (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id) -{ - 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, @@ -1230,24 +1356,6 @@ static const guint8 _supported_cache_ids_ipx_address[] = { 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, @@ -1272,68 +1380,6 @@ static const guint8 _supported_cache_ids_ip6_route[] = { 0, }; -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; -} - /*****************************************************************************/ static NMDedupMultiObj * @@ -1378,6 +1424,18 @@ _vt_dedup_obj_full_equal (const NMDedupMultiObj *obj_a, /*****************************************************************************/ +static NMDedupMultiIdxType * +_idx_type_get (const NMPCache *cache, NMPCacheIdType cache_id_type) +{ + 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)); + + return (NMDedupMultiIdxType *) &cache->idx_types[cache_id_type - 1]; +} + gboolean nmp_cache_use_udev_get (const NMPCache *cache) { @@ -1412,9 +1470,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 @@ -1438,15 +1494,16 @@ nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *m && potential_slave->link.connected) { is_lower_up = TRUE; } else { - NMPCacheId cache_id; + NMPLookup lookup; + NMDedupMultiIter iter; + const NMPlatformLink *link = NULL; - 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]; + nmp_cache_iter_for_each_link (&iter, + nmp_cache_lookup (cache, + nmp_lookup_init_link (&lookup, FALSE)), + &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 @@ -1495,40 +1552,40 @@ 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); -} + nm_assert (cache); + nm_assert (NMP_OBJECT_IS_VALID (obj)); -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); - - objects = nmp_cache_lookup_multi (cache, cache_id, &len); - array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len); - - 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; + return nm_dedup_multi_index_lookup_obj (cache->multi_idx, + _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE), + obj); } 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->box->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 * @@ -1539,6 +1596,234 @@ 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, + gboolean visible_only) +{ + 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); + if (visible_only) { + lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY; + o->object.ifindex = 1; + if (obj_type == NMP_OBJECT_TYPE_LINK) { + o->_link.netlink.is_in_netlink = TRUE; + o->link.name[0] = 'x'; + } + } else { + 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 (NMPLookup *lookup, + gboolean visible_only) +{ + return nmp_lookup_init_obj_type (lookup, + NMP_OBJECT_TYPE_LINK, + visible_only); +} + +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, + gboolean visible_only) +{ + 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, + visible_only); + } + + if (!visible_only) { + /* some match combinations are not implemented, as they would require + * an additional index which is expensive to maintain. */ + g_return_val_if_reached (NULL); + } + + o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); + o->object.ifindex = ifindex; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX; + return _L (lookup); +} + +const NMPLookup * +nmp_lookup_init_route_visible (NMPLookup *lookup, + NMPObjectType obj_type, + int ifindex, + gboolean with_default, + gboolean with_non_default) +{ + NMPObject *o; + + nm_assert (lookup); + nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)); + + if (with_default) { + if (with_non_default) { + return nmp_lookup_init_addrroute (lookup, + obj_type, + ifindex, + TRUE); + } + o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); + if (ifindex <= 0) { + o->object.ifindex = 1; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT; + } else { + o->object.ifindex = ifindex; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT; + } + return _L (lookup); + } else if (with_non_default) { + o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); + o->ip_route.plen = 1; + if (ifindex <= 0) { + o->object.ifindex = 1; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT; + } else { + o->object.ifindex = ifindex; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT; + } + return _L (lookup); + } else + g_return_val_if_reached (NULL); +} + +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_IP4; + 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_IP6; + break; + default: + nm_assert_not_reached (); + return NULL; + } + return _L (lookup); +} + +/*****************************************************************************/ + +GArray * +nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry, + NMPObjectType obj_type) +{ + 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); + g_array_append_vals (array, &o->object, 1); + } + return array; +} + +/*****************************************************************************/ + /** * nmp_cache_find_other_route_for_same_destination: * @cache: @@ -1554,32 +1839,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); + nmp_cache_iter_for_each (&iter, nmp_cache_lookup (cache, &lookup), &o) { + nm_assert (NMP_OBJECT_GET_CLASS (route) == NMP_OBJECT_GET_CLASS (o)); - nm_assert (NMP_OBJECT_GET_CLASS (route) == NMP_OBJECT_GET_CLASS (candidate)); - - if (!nmp_object_id_equal (route, candidate)) - return candidate; - } + if (!nmp_object_id_equal (route, o)) + return o; } return NULL; } @@ -1595,9 +1884,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)); @@ -1612,18 +1902,19 @@ 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); + nmp_lookup_init_link (&lookup, visible_only); visible_only = FALSE; } - 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; @@ -1640,190 +1931,264 @@ 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) +_idxcache_update_box_move (NMPCache *cache, + NMPCacheIdType cache_id_type, + const NMDedupMultiBox *box_old, + const NMDedupMultiBox *box_new) { - const guint8 *id_type; + const NMDedupMultiEntry *entry_new; + const NMDedupMultiEntry *entry_old; + const NMDedupMultiEntry *entry_order; + NMDedupMultiIdxType *idx_type; + const NMPObject *new, *old; - for (id_type = NMP_OBJECT_GET_CLASS (obj)->supported_cache_ids; *id_type; id_type++) { - NMPCacheId cache_id_storage; - const NMPCacheId *cache_id; + new = box_new ? box_new->obj : NULL; + old = box_old ? box_old->obj : NULL; - if (!_nmp_object_init_cache_id (obj, *id_type, &cache_id_storage, &cache_id)) - continue; - if (!cache_id) - continue; + nm_assert (new || old); + nm_assert (!new || NMP_OBJECT_GET_TYPE (new) != NMP_OBJECT_TYPE_UNKNOWN); + nm_assert (!old || NMP_OBJECT_GET_TYPE (old) != NMP_OBJECT_TYPE_UNKNOWN); + nm_assert (!old || !new || NMP_OBJECT_GET_CLASS (new) == NMP_OBJECT_GET_CLASS (old)); + nm_assert (!old || !new || !nmp_object_equal (new, old)); + nm_assert (!box_new || box_new == nm_dedup_multi_box_find (cache->multi_idx, new)); + nm_assert (!box_old || box_old == nm_dedup_multi_box_find (cache->multi_idx, old)); - /* 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. */ + idx_type = _idx_type_get (cache, cache_id_type); - if (remove) { - if (!nm_multi_index_remove (cache->idx_multi, &cache_id->base, &obj->object)) - g_assert_not_reached (); - } else { - if (!nm_multi_index_add (cache->idx_multi, &cache_id->base, &obj->object)) - g_assert_not_reached (); + if (old) { + entry_old = nm_dedup_multi_index_lookup_obj (cache->multi_idx, + idx_type, + old); + if (!new) { + if (entry_old) + nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old); + return; } - } + } else + entry_old = NULL; + + if (new) { + if ( old + && nm_dedup_multi_idx_type_id_equal (idx_type, old, new) + && nm_dedup_multi_idx_type_partition_equal (idx_type, old, new)) { + /* optimize. We just looked up the @old entry and @new compares equal + * according to idx_obj_id_equal(). entry_new is the same as entry_old. */ + entry_new = entry_old; + } else { + entry_new = nm_dedup_multi_index_lookup_obj (cache->multi_idx, + idx_type, + new); + } + + if (entry_new) + entry_order = entry_new; + else if ( entry_old + && nm_dedup_multi_idx_type_partition_equal (idx_type, entry_old->box->obj, new)) + entry_order = entry_old; + else + entry_order = NULL; + nm_dedup_multi_index_add_full (cache->multi_idx, + idx_type, + 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), + box_new, + &entry_new, + NULL); + +#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->box->obj)); + nm_assert (idx_type->klass->idx_obj_partition_equal (idx_type, (gpointer) new, entry_new->box->obj)); + } +#endif + } else + entry_new = NULL; + + if ( entry_old + && entry_old != entry_new) + nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old); } static void -_nmp_cache_update_add (NMPCache *cache, NMPObject *obj) +_idxcache_update (NMPCache *cache, + const NMDedupMultiEntry *entry_old, + NMPObject *obj_new, + const NMDedupMultiEntry **out_entry_new) { - 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); -} + 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; + const NMDedupMultiBox *box_old; + const NMDedupMultiBox *box_old2 = 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 (); + /* 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. */ - /* @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)); -} + 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->box->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->box->obj, obj_new)); + nm_assert ( !entry_old + || !obj_new + || nm_dedup_multi_idx_type_id_equal (idx_type_o, entry_old->box->obj, obj_new)); + nm_assert ( !entry_old + || !obj_new + || ( obj_new->parent.klass == ((const NMPObject *) entry_old->box->obj)->parent.klass + && !obj_new->parent.klass->obj_full_equal ((NMDedupMultiObj *) obj_new, entry_old->box->obj))); -static void -_nmp_cache_update_update (NMPCache *cache, NMPObject *obj, const NMPObject *new) -{ - const guint8 *id_type; + /* keep a boxed reference to the pre-existing entry */ + box_old = entry_old ? nm_dedup_multi_box_ref (entry_old->box) : NULL; - nm_assert (NMP_OBJECT_GET_CLASS (obj) == NMP_OBJECT_GET_CLASS (new)); - nm_assert (obj->is_cached); - nm_assert (!new->is_cached); + /* 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_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, + NULL, + &entry_new, + &box_old2); + nm_assert (entry_new); + nm_assert (box_old == box_old2); + nm_assert (!entry_old || entry_old == entry_new); + if (box_old2) + nm_dedup_multi_box_unref (cache->multi_idx, box_old2); + } else + nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old); - 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; + /* 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->box->obj : box_old->obj); + for (i_idx_type = klass->supported_cache_ids; *i_idx_type; i_idx_type++) { + NMPCacheIdType id_type = *i_idx_type; - if (!_nmp_object_init_cache_id (obj, *id_type, &cache_id_storage_obj, &cache_id_obj)) + 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, + box_old, + entry_new ? entry_new->box : NULL); } - nmp_object_copy (obj, new, FALSE); + + NM_SET_OUT (out_entry_new, entry_new); + + if (box_old) + nm_dedup_multi_box_unref (cache->multi_idx, box_old); } 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->box->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->box->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; + NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old)); + + 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 (out_obj) - *out_obj = nmp_object_ref (old); - if (out_was_visible) - *out_was_visible = nmp_object_is_visible (old); - - if (!old->_link.netlink.is_in_netlink) { - nm_assert (old->_link.udev.device); - 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->box->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; } /** @@ -1851,233 +2216,246 @@ 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 (({ + const NMDedupMultiBox *_b = nm_dedup_multi_box_find (cache->multi_idx, obj_hand_over); + !_b || obj_hand_over != _b->obj; + })); - old = g_hash_table_lookup (cache->idx_main, obj); + entry_old = _lookup_obj (cache, obj_hand_over); - NM_SET_OUT (out_obj, NULL); - NM_SET_OUT (out_was_visible, FALSE); + if (!entry_old) { - if (!old) { - if (!nmp_object_is_alive (obj)) + NM_SET_OUT (out_obj_old, NULL); + + if (!nmp_object_is_alive (obj_hand_over)) { + NM_SET_OUT (out_obj_new, NULL); return NMP_CACHE_OPS_UNCHANGED; - - 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); } - NM_SET_OUT (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->box->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); + obj_old = entry_old->box->obj; - 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); - NM_SET_OUT (out_obj, nmp_object_ref (old)); - NM_SET_OUT (out_was_visible, nmp_object_is_visible (old)); - 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); - - /* 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; - NM_SET_OUT (out_obj, nmp_object_ref (old)); - NM_SET_OUT (out_was_visible, nmp_object_is_visible (old)); + if (is_alive) { + _nmp_object_fixup_link_master_connected (&obj_hand_over, NULL, cache); - 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; + /* 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); } + } 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->box->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; + const NMPObject *obj_old; + nm_auto_nmpobj NMPObject *obj_new = NULL; + const NMDedupMultiEntry *entry_old; + const NMDedupMultiEntry *entry_new; - old = (NMPObject *) nmp_cache_lookup_link (cache, ifindex); + entry_old = nmp_cache_lookup_entry_link (cache, ifindex); - NM_SET_OUT (out_obj, NULL); - NM_SET_OUT (out_was_visible, FALSE); - - 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); + obj_new = nmp_object_new (NMP_OBJECT_TYPE_LINK, NULL); + obj_new->link.ifindex = ifindex; + obj_new->_link.udev.device = udev_device_ref (udevice); - _nmp_object_fixup_link_udev_fields (obj, cache->use_udev); + _nmp_object_fixup_link_udev_fields (&obj_new, NULL, cache->use_udev); - nm_assert (nmp_object_is_alive (obj)); - - if (out_obj) - *out_obj = nmp_object_ref (obj); - - 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->box->obj)); return NMP_CACHE_OPS_ADDED; } else { - nm_assert (old->is_cached); + obj_old = entry_old->box->obj; + NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old)); - NM_SET_OUT (out_obj, nmp_object_ref (old)); - NM_SET_OUT (out_was_visible, nmp_object_is_visible (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); + obj_new = nmp_object_clone (obj_old, FALSE); - udev_device_unref (obj->_link.udev.device); - obj->_link.udev.device = udevice ? udev_device_ref (udevice) : NULL; + udev_device_unref (obj_new->_link.udev.device); + obj_new->_link.udev.device = udevice ? udev_device_ref (udevice) : NULL; - _nmp_object_fixup_link_udev_fields (obj, cache->use_udev); + _nmp_object_fixup_link_udev_fields (&obj_new, NULL, cache->use_udev); - nm_assert (nmp_object_is_alive (obj)); - - 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->box->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; - old = (NMPObject *) nmp_cache_lookup_link (cache, ifindex); - - if (!old) { - NM_SET_OUT (out_obj, NULL); - NM_SET_OUT (out_was_visible, FALSE); + entry_old = nmp_cache_lookup_entry_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; } - nm_assert (old->is_cached); + obj_old = entry_old->box->obj; - NM_SET_OUT (out_obj, nmp_object_ref (old)); - NM_SET_OUT (out_was_visible, nmp_object_is_visible (old)); - - if (!nmp_cache_link_connected_needs_toggle (cache, old, NULL, NULL)) + 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; + } - obj = nmp_object_clone (old, FALSE); - obj->link.connected = !old->link.connected; + obj_new = nmp_object_clone (obj_old, FALSE); + obj_new->link.connected = !obj_old->link.connected; - nm_assert (nmp_object_is_alive (obj)); - - if (pre_hook) - pre_hook (cache, old, obj, NMP_CACHE_OPS_UPDATED, user_data); - _nmp_cache_update_update (cache, old, obj); + 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->box->obj)); return NMP_CACHE_OPS_UPDATED; } /*****************************************************************************/ -NMPCache * -nmp_cache_new (gboolean use_udev) +void +nmp_cache_dirty_set_all (NMPCache *cache, NMPObjectType obj_type) { - NMPCache *cache = g_new (NMPCache, 1); + NMPObject obj_needle; + + nm_assert (cache); + + 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 (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->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); cache->use_udev = !!use_udev; return cache; } @@ -2085,23 +2463,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); } /*****************************************************************************/ @@ -2109,63 +2478,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), @@ -2175,8 +2494,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_not_implemented, + .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, @@ -2203,7 +2521,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, @@ -2225,7 +2542,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, @@ -2247,7 +2563,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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, .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, @@ -2269,7 +2584,6 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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, .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, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 7664a43817..b63a96e043 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -24,7 +24,6 @@ #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; @@ -60,7 +59,14 @@ typedef enum { /*< skip >*/ 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). */ NMP_CACHE_ID_TYPE_OBJECT_TYPE, /* index for the link objects by ifname. */ @@ -76,7 +82,7 @@ typedef enum { /*< skip >*/ /* 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. */ + /* 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, @@ -95,50 +101,6 @@ typedef enum { /*< skip >*/ 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; @@ -155,10 +117,6 @@ 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); @@ -276,7 +234,6 @@ struct _NMPObject { const NMPClass *_class; }; guint _ref_count; - bool is_cached; union { NMPlatformObject object; @@ -387,8 +344,8 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) const NMPClass *nmp_class_from_type (NMPObjectType obj_type); -NMPObject *nmp_object_ref (NMPObject *object); -void nmp_object_unref (NMPObject *object); +const NMPObject *nmp_object_ref (const NMPObject *object); +void nmp_object_unref (const NMPObject *object); NMPObject *nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plob); NMPObject *nmp_object_new_link (int ifindex); @@ -411,13 +368,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; @@ -425,23 +382,90 @@ typedef struct _NMPCache NMPCache; typedef void (*NMPCachePreHook) (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data); typedef gboolean (*NMPObjectMatchFn) (const NMPObject *obj, gpointer user_data); -gboolean nmp_cache_id_equal (const NMPCacheId *a, const NMPCacheId *b); -guint nmp_cache_id_hash (const NMPCacheId *id); -NMPCacheId *nmp_cache_id_clone (const NMPCacheId *id); -void nmp_cache_id_destroy (NMPCacheId *id); +const NMDedupMultiEntry *nmp_cache_lookup_entry_link (const NMPCache *cache, int ifindex); -NMPCacheId *nmp_cache_id_init_object_type (NMPCacheId *id, NMPObjectType obj_type, gboolean visible_only); -NMPCacheId *nmp_cache_id_init_addrroute_visible_by_ifindex (NMPCacheId *id, NMPObjectType obj_type, int ifindex); -NMPCacheId *nmp_cache_id_init_routes_visible (NMPCacheId *id, NMPObjectType obj_type, gboolean with_default, gboolean with_non_default, int ifindex); -NMPCacheId *nmp_cache_id_init_link_by_ifname (NMPCacheId *id, const char *ifname); -NMPCacheId *nmp_cache_id_init_routes_by_destination_ip4 (NMPCacheId *id, guint32 network, guint8 plen, guint32 metric); -NMPCacheId *nmp_cache_id_init_routes_by_destination_ip6 (NMPCacheId *id, const struct in6_addr *network, guint8 plen, guint32 metric); - -const NMPlatformObject *const *nmp_cache_lookup_multi (const NMPCache *cache, const NMPCacheId *cache_id, guint *out_len); -GArray *nmp_cache_lookup_multi_to_array (const NMPCache *cache, NMPObjectType obj_type, const NMPCacheId *cache_id); const NMPObject *nmp_cache_lookup_obj (const NMPCache *cache, const NMPObject *obj); const NMPObject *nmp_cache_lookup_link (const NMPCache *cache, int ifindex); +typedef struct { + NMPCacheIdType cache_id_type; + NMPObject selector_obj; +} NMPLookup; + +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, + gboolean visible_only); +const NMPLookup *nmp_lookup_init_link (NMPLookup *lookup, + gboolean visible_only); +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, + gboolean visible_only); +const NMPLookup *nmp_lookup_init_route_visible (NMPLookup *lookup, + NMPObjectType obj_type, + int ifindex, + gboolean with_default, + gboolean with_non_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); + +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->box->obj)); + NM_SET_OUT (out_obj, iter->current->box->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->box->obj) == NMP_OBJECT_TYPE_LINK); + NM_SET_OUT (out_obj, &(((const NMPObject *) iter->current->box->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, @@ -451,9 +475,6 @@ 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_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); @@ -462,13 +483,71 @@ gboolean nmp_cache_use_udev_get (const NMPCache *cache); void ASSERT_nmp_cache_is_consistent (const NMPCache *cache); -NMPCacheOpsType nmp_cache_remove (NMPCache *cache, const NMPObject *obj, gboolean equals_by_ptr, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); -NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache, const NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); -NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); -NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, int ifindex, struct udev_device *udevice, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); -NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifindex, NMPObject **out_obj, gboolean *out_was_visible, NMPCachePreHook pre_hook, gpointer user_data); +NMPCacheOpsType nmp_cache_remove (NMPCache *cache, + const NMPObject *obj_needle, + gboolean equals_by_ptr, + const NMPObject **out_obj_old); +NMPCacheOpsType nmp_cache_remove_netlink (NMPCache *cache, + const NMPObject *obj_needle, + const NMPObject **out_obj_old, + const NMPObject **out_obj_new); +NMPCacheOpsType nmp_cache_update_netlink (NMPCache *cache, + NMPObject *obj, + const NMPObject **out_obj_old, + const NMPObject **out_obj_new); +NMPCacheOpsType nmp_cache_update_link_udev (NMPCache *cache, + int ifindex, + struct udev_device *udevice, + const NMPObject **out_obj_old, + const NMPObject **out_obj_new); +NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, + int ifindex, + const NMPObject **out_obj_old, + const NMPObject **out_obj_new); -NMPCache *nmp_cache_new (gboolean use_udev); +void nmp_cache_dirty_set_all (NMPCache *cache, NMPObjectType obj_type); + +NMPCache *nmp_cache_new (NMDedupMultiIndex *multi_idx, gboolean use_udev); void nmp_cache_free (NMPCache *cache); +static inline void +ASSERT_nmp_cache_ops (const NMPCache *cache, + NMPCacheOpsType ops_type, + const NMPObject *obj_old, + const NMPObject *obj_new) +{ +#if NM_MORE_ASSERTS + nm_assert (cache); + nm_assert (obj_old || obj_new); + nm_assert (!obj_old || ( NMP_OBJECT_IS_VALID (obj_old) + && !NMP_OBJECT_IS_STACKINIT (obj_old) + && nmp_object_is_alive (obj_old))); + nm_assert (!obj_new || ( NMP_OBJECT_IS_VALID (obj_new) + && !NMP_OBJECT_IS_STACKINIT (obj_new) + && nmp_object_is_alive (obj_new))); + + switch (ops_type) { + case NMP_CACHE_OPS_UNCHANGED: + nm_assert (obj_old == obj_new); + break; + case NMP_CACHE_OPS_ADDED: + nm_assert (!obj_old && obj_new); + break; + case NMP_CACHE_OPS_UPDATED: + nm_assert (obj_old && obj_new && obj_old != obj_new); + break; + case NMP_CACHE_OPS_REMOVED: + nm_assert (obj_old && !obj_new); + break; + default: + nm_assert_not_reached (); + } + + nm_assert (obj_new == NULL || obj_old == NULL || nmp_object_id_equal (obj_new, obj_old)); + nm_assert (!obj_old || !obj_new || NMP_OBJECT_GET_CLASS (obj_old) == NMP_OBJECT_GET_CLASS (obj_new)); + + nm_assert (obj_new == nmp_cache_lookup_obj (cache, obj_new ?: obj_old)); +#endif +} + #endif /* __NMP_OBJECT_H__ */ diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index 300a0cb464..24e790c32c 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -103,150 +103,141 @@ _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 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; } + i++; } + g_assert (len == i); g_assert (!!contains == found); } +static void +_assert_cache_multi_lookup_contains_link (const NMPCache *cache, + gboolean visible_only, + const NMPObject *obj, + gboolean contains) +{ + const NMDedupMultiHeadEntry *head_entry; + NMPLookup lookup; + + g_assert (cache); + + nmp_lookup_init_link (&lookup, visible_only); + head_entry = nmp_cache_lookup (cache, &lookup); + _assert_cache_multi_lookup_contains (cache, head_entry, obj, contains); +} + /*****************************************************************************/ -typedef struct { - NMPCache *cache; - NMPCacheOpsType expected_ops_type; - const NMPObject *obj_clone; - NMPObject *new_clone; - gboolean was_visible; - gboolean called; -} _NMPCacheUpdateData; - static void -_nmp_cache_update_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data) +ops_post_check (NMPCache *cache, + NMPCacheOpsType ops_type, + const NMPObject *obj_old, + const NMPObject *obj_new, + const NMPObject *obj_new_expected, + NMPCacheOpsType expected_ops_type) { - _NMPCacheUpdateData *data = user_data; + g_assert (cache); - g_assert (data); - g_assert (!data->called); - g_assert (data->cache == cache); - - g_assert_cmpint (data->expected_ops_type, ==, ops_type); + g_assert_cmpint (expected_ops_type, ==, ops_type); switch (ops_type) { case NMP_CACHE_OPS_ADDED: - g_assert (!old); - g_assert (NMP_OBJECT_IS_VALID (new)); - g_assert (nmp_object_is_alive (new)); - g_assert (nmp_object_id_equal (data->obj_clone, new)); - g_assert (nmp_object_equal (data->obj_clone, new)); + g_assert (!obj_old); + g_assert (NMP_OBJECT_IS_VALID (obj_new)); + g_assert (nmp_object_is_alive (obj_new)); + g_assert (nmp_object_id_equal (obj_new_expected, obj_new)); + g_assert (nmp_object_equal (obj_new_expected, obj_new)); break; case NMP_CACHE_OPS_UPDATED: - g_assert (NMP_OBJECT_IS_VALID (old)); - g_assert (NMP_OBJECT_IS_VALID (new)); - g_assert (nmp_object_is_alive (old)); - g_assert (nmp_object_is_alive (new)); - g_assert (nmp_object_id_equal (data->obj_clone, new)); - g_assert (nmp_object_id_equal (data->obj_clone, old)); - g_assert (nmp_object_id_equal (old, new)); - g_assert (nmp_object_equal (data->obj_clone, new)); - g_assert (!nmp_object_equal (data->obj_clone, old)); - g_assert (!nmp_object_equal (old, new)); + g_assert (obj_old != obj_new); + g_assert (NMP_OBJECT_IS_VALID (obj_old)); + g_assert (NMP_OBJECT_IS_VALID (obj_new)); + g_assert (nmp_object_is_alive (obj_old)); + g_assert (nmp_object_is_alive (obj_new)); + g_assert (nmp_object_id_equal (obj_new_expected, obj_new)); + g_assert (nmp_object_id_equal (obj_new_expected, obj_old)); + g_assert (nmp_object_id_equal (obj_old, obj_new)); + g_assert (nmp_object_equal (obj_new_expected, obj_new)); + g_assert (!nmp_object_equal (obj_new_expected, obj_old)); + g_assert (!nmp_object_equal (obj_old, obj_new)); break; case NMP_CACHE_OPS_REMOVED: - g_assert (!new); - g_assert (NMP_OBJECT_IS_VALID (old)); - g_assert (nmp_object_is_alive (old)); - g_assert (nmp_object_id_equal (data->obj_clone, old)); + g_assert (!obj_new); + g_assert (NMP_OBJECT_IS_VALID (obj_old)); + g_assert (nmp_object_is_alive (obj_old)); + if (obj_new_expected) + g_assert (nmp_object_id_equal (obj_new_expected, obj_old)); + break; + case NMP_CACHE_OPS_UNCHANGED: + g_assert (obj_old == obj_new); + if (obj_old) { + g_assert (NMP_OBJECT_IS_VALID (obj_old)); + g_assert (nmp_object_is_alive (obj_old)); + g_assert (nmp_object_equal (obj_old, obj_new)); + g_assert (nmp_object_id_equal (obj_new_expected, obj_new)); + } else + g_assert (!obj_new_expected); break; default: g_assert_not_reached (); } - - data->was_visible = old ? nmp_object_is_visible (old) : FALSE; - data->new_clone = new ? nmp_object_clone (new, FALSE) : NULL; - data->called = TRUE; } static void -_nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj, gboolean *out_was_visible, NMPCacheOpsType expected_ops_type) +_nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, const NMPObject **out_obj_old, const NMPObject **out_obj_new, NMPCacheOpsType expected_ops_type) { NMPCacheOpsType ops_type; - NMPObject *obj2; - gboolean was_visible; - nm_auto_nmpobj NMPObject *obj_clone = nmp_object_clone (obj, FALSE); - nm_auto_nmpobj NMPObject *new_clone = NULL; + const NMPObject *obj_prev; const NMPObject *obj_old; - _NMPCacheUpdateData data = { - .cache = cache, - .expected_ops_type = expected_ops_type, - .obj_clone = obj_clone, - }; - - obj_old = nmp_cache_lookup_link (cache, obj->object.ifindex); - if (obj_old && obj_old->_link.udev.device) - obj_clone->_link.udev.device = udev_device_ref (obj_old->_link.udev.device); - _nmp_object_fixup_link_udev_fields (obj_clone, nmp_cache_use_udev_get (cache)); + const NMPObject *obj_new; + nm_auto_nmpobj NMPObject *obj_new_expected = NULL; g_assert (cache); g_assert (NMP_OBJECT_IS_VALID (obj)); - ops_type = nmp_cache_update_netlink (cache, obj, &obj2, &was_visible, _nmp_cache_update_hook, &data); + obj_prev = nmp_cache_lookup_link (cache, obj->object.ifindex); + obj_new_expected = nmp_object_clone (obj, FALSE); + if (obj_prev && obj_prev->_link.udev.device) + obj_new_expected->_link.udev.device = udev_device_ref (obj_prev->_link.udev.device); + _nmp_object_fixup_link_udev_fields (&obj_new_expected, NULL, nmp_cache_use_udev_get (cache)); - new_clone = data.new_clone; + ops_type = nmp_cache_update_netlink (cache, obj, &obj_old, &obj_new); + ops_post_check (cache, ops_type, obj_old, obj_new, + nmp_object_is_alive (obj_new_expected) ? obj_new_expected : NULL, + expected_ops_type); - g_assert_cmpint (ops_type, ==, expected_ops_type); - - if (ops_type != NMP_CACHE_OPS_UNCHANGED) { - g_assert (NMP_OBJECT_IS_VALID (obj2)); - g_assert (data.called); - g_assert_cmpint (data.was_visible, ==, was_visible); - - if (ops_type == NMP_CACHE_OPS_REMOVED) - g_assert (!data.new_clone); - else { - g_assert (data.new_clone); - g_assert (nmp_object_equal (obj2, data.new_clone)); - } - } else { - g_assert (!data.called); - g_assert (!obj2 || was_visible == nmp_object_is_visible (obj2)); - } - - g_assert (!obj2 || nmp_object_id_equal (obj, obj2)); - if (ops_type != NMP_CACHE_OPS_REMOVED && obj2) - g_assert (nmp_object_equal (obj, obj2)); - - if (out_obj) - *out_obj = obj2; + if (out_obj_new) + *out_obj_new = obj_new; else - nmp_object_unref (obj2); - if (out_was_visible) - *out_was_visible = was_visible; + nmp_object_unref (obj_new); + if (out_obj_old) + *out_obj_old = obj_old; + else + nmp_object_unref (obj_old); } static const NMPlatformLink pl_link_2 = { @@ -265,168 +256,189 @@ static void test_cache_link (void) { NMPCache *cache; - NMPObject *obj1, *obj2; + NMPObject *objm1; + const NMPObject *obj_old, *obj_new; NMPObject objs1; - gboolean was_visible; - NMPCacheId cache_id_storage; struct udev_device *udev_device_2 = g_list_nth_data (global.udev_devices, 0); struct udev_device *udev_device_3 = g_list_nth_data (global.udev_devices, 0); NMPCacheOpsType ops_type; + nm_auto_unref_dedup_multi_index NMDedupMultiIndex *multi_idx = NULL; - cache = nmp_cache_new (nmtst_get_rand_int () % 2); + multi_idx = nm_dedup_multi_index_new (); + + cache = nmp_cache_new (multi_idx, nmtst_get_rand_int () % 2); /* if we have a link, and don't set is_in_netlink, adding it has no effect. */ - obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); - g_assert (NMP_OBJECT_UP_CAST (&obj1->object) == obj1); - g_assert (!nmp_object_is_alive (obj1)); - _nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED); + objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); + g_assert (NMP_OBJECT_UP_CAST (&objm1->object) == objm1); + g_assert (!nmp_object_is_alive (objm1)); + _nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_UNCHANGED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (!obj2); - g_assert (!was_visible); - g_assert (!nmp_cache_lookup_obj (cache, obj1)); + g_assert (!obj_old); + g_assert (!obj_new); + g_assert (!nmp_cache_lookup_obj (cache, objm1)); g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex))); - nmp_object_unref (obj1); + nmp_object_unref (objm1); /* Only when setting @is_in_netlink the link is added. */ - obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); - obj1->_link.netlink.is_in_netlink = TRUE; - g_assert (nmp_object_is_alive (obj1)); - _nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_ADDED); + objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); + objm1->_link.netlink.is_in_netlink = TRUE; + g_assert (nmp_object_is_alive (objm1)); + _nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_ADDED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (nmp_object_equal (obj1, obj2)); - g_assert (!was_visible); - g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2); - g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2); - g_assert (nmp_object_is_visible (obj2)); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE); - nmp_object_unref (obj1); - nmp_object_unref (obj2); + g_assert (!obj_old); + g_assert (obj_new); + g_assert (objm1 == obj_new); + g_assert (nmp_object_equal (objm1, obj_new)); + g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new); + g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new); + g_assert (nmp_object_is_visible (obj_new)); + _assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE); + _assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, TRUE); + nmp_object_unref (objm1); + nmp_object_unref (obj_new); /* updating the same link with identical value, has no effect. */ - obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); - obj1->_link.netlink.is_in_netlink = TRUE; - g_assert (nmp_object_is_alive (obj1)); - _nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UNCHANGED); + objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); + objm1->_link.netlink.is_in_netlink = TRUE; + g_assert (nmp_object_is_alive (objm1)); + _nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_UNCHANGED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (obj2 != obj1); - g_assert (nmp_object_equal (obj1, obj2)); - g_assert (was_visible); - g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2); - g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2); - nmp_object_unref (obj1); - nmp_object_unref (obj2); + g_assert (obj_old); + g_assert (obj_new); + g_assert (obj_new != objm1); + g_assert (nmp_object_equal (objm1, obj_new)); + g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new); + g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new); + nmp_object_unref (objm1); + nmp_object_unref (obj_new); + nmp_object_unref (obj_new); /* remove the link from netlink */ - obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); - g_assert (!nmp_object_is_alive (obj1)); - _nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_REMOVED); + objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); + g_assert (!nmp_object_is_alive (objm1)); + _nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_REMOVED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (obj2 != obj1); - g_assert (was_visible); - g_assert (!nmp_cache_lookup_obj (cache, obj1)); + g_assert (obj_old); + g_assert (!obj_new); + g_assert (!nmp_cache_lookup_obj (cache, objm1)); g_assert (!nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex))); - nmp_object_unref (obj1); - nmp_object_unref (obj2); + nmp_object_unref (objm1); + nmp_object_unref (obj_old); + nmp_object_unref (obj_new); if (udev_device_2) { /* now add the link only with aspect UDEV. */ - ops_type = nmp_cache_update_link_udev (cache, pl_link_2.ifindex, udev_device_2, &obj2, &was_visible, NULL, NULL); + ops_type = nmp_cache_update_link_udev (cache, pl_link_2.ifindex, udev_device_2, &obj_old, &obj_new); ASSERT_nmp_cache_is_consistent (cache); g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED); - g_assert (!was_visible); - g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2); - g_assert (!nmp_object_is_visible (obj2)); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE); - nmp_object_unref (obj2); + g_assert (!obj_old); + g_assert (obj_new); + g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new); + g_assert (!nmp_object_is_visible (obj_new)); + _assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, FALSE); + _assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE); + nmp_object_unref (obj_new); } /* add it in netlink too. */ - obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); - obj1->_link.netlink.is_in_netlink = TRUE; - g_assert (nmp_object_is_alive (obj1)); - _nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_ADDED); + objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); + objm1->_link.netlink.is_in_netlink = TRUE; + g_assert (nmp_object_is_alive (objm1)); + _nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_ADDED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (nmp_object_equal (obj1, obj2)); - g_assert (!was_visible); - g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2); - g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2); - g_assert (nmp_object_is_visible (obj2)); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE); - nmp_object_unref (obj1); - nmp_object_unref (obj2); + if (udev_device_2) { + g_assert (obj_old); + g_assert (!nmp_object_is_visible (obj_old)); + } else + g_assert (!obj_old); + g_assert (nmp_object_equal (objm1, obj_new)); + g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new); + g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new); + g_assert (nmp_object_is_visible (obj_new)); + _assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, TRUE); + _assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE); + nmp_object_unref (objm1); + nmp_object_unref (obj_old); + nmp_object_unref (obj_new); /* remove again from netlink. */ - obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); - obj1->_link.netlink.is_in_netlink = FALSE; - g_assert (!nmp_object_is_alive (obj1)); - _nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_REMOVED); + objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_2); + objm1->_link.netlink.is_in_netlink = FALSE; + g_assert (!nmp_object_is_alive (objm1)); + _nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, udev_device_2 ? NMP_CACHE_OPS_UPDATED : NMP_CACHE_OPS_REMOVED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (obj2 != obj1); - g_assert (was_visible); + if (udev_device_2) + g_assert (obj_new == objm1); + else + g_assert (!obj_new); + g_assert (obj_old); + g_assert (nmp_object_is_alive (obj_old)); if (udev_device_2) { - g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2); - g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj2); - g_assert (!nmp_object_is_visible (obj2)); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE); + g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new); + g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == obj_new); + g_assert (!nmp_object_is_visible (obj_new)); + _assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, FALSE); + _assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE); } else { - g_assert (nmp_cache_lookup_obj (cache, obj1) == NULL); + g_assert (nmp_cache_lookup_obj (cache, objm1) == NULL); g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_2.ifindex)) == NULL); - g_assert (nmp_object_is_visible (obj2)); + g_assert (nmp_object_is_visible (obj_new)); } - nmp_object_unref (obj1); - nmp_object_unref (obj2); + nmp_object_unref (objm1); + nmp_object_unref (obj_old); + nmp_object_unref (obj_new); /* now another link only with aspect UDEV. */ if (udev_device_3) { /* now add the link only with aspect UDEV. */ - ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, udev_device_3, &obj2, &was_visible, NULL, NULL); + ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, udev_device_3, &obj_old, &obj_new); g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_ADDED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (NMP_OBJECT_IS_VALID (obj2)); - g_assert (!was_visible); - g_assert (!nmp_object_is_visible (obj2)); - g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, FALSE); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE); - g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, FALSE); - g_assert_cmpint (obj2->link.initialized, ==, FALSE); - nmp_object_unref (obj2); + g_assert (NMP_OBJECT_IS_VALID (obj_new)); + g_assert (!obj_old); + g_assert (!nmp_object_is_visible (obj_new)); + g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj_new); + _assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, FALSE); + _assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE); + g_assert_cmpint (obj_new->_link.netlink.is_in_netlink, ==, FALSE); + g_assert_cmpint (obj_new->link.initialized, ==, FALSE); + nmp_object_unref (obj_new); /* add it in netlink too. */ - obj1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_3); - obj1->_link.netlink.is_in_netlink = TRUE; - g_assert (nmp_object_is_alive (obj1)); - _nmp_cache_update_netlink (cache, obj1, &obj2, &was_visible, NMP_CACHE_OPS_UPDATED); + objm1 = nmp_object_new (NMP_OBJECT_TYPE_LINK, (NMPlatformObject *) &pl_link_3); + objm1->_link.netlink.is_in_netlink = TRUE; + g_assert (nmp_object_is_alive (objm1)); + _nmp_cache_update_netlink (cache, objm1, &obj_old, &obj_new, NMP_CACHE_OPS_UPDATED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (obj2 != obj1); - g_assert (nmp_object_equal (obj1, obj2)); - g_assert (!was_visible); - g_assert (nmp_cache_lookup_obj (cache, obj1) == obj2); - g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2); - g_assert (nmp_object_is_visible (obj2)); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE); - g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE); - g_assert_cmpint (obj2->link.initialized, ==, TRUE); - nmp_object_unref (obj1); - nmp_object_unref (obj2); + g_assert (obj_old); + g_assert (obj_new == objm1); + g_assert (nmp_object_equal (objm1, obj_new)); + g_assert (!obj_old || !nmp_object_is_visible (obj_old)); + g_assert (nmp_cache_lookup_obj (cache, objm1) == obj_new); + g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj_new); + g_assert (nmp_object_is_visible (obj_new)); + _assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, TRUE); + _assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE); + g_assert_cmpint (obj_new->_link.netlink.is_in_netlink, ==, TRUE); + g_assert_cmpint (obj_new->link.initialized, ==, TRUE); + nmp_object_unref (objm1); + nmp_object_unref (obj_old); + nmp_object_unref (obj_new); /* remove UDEV. */ - ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, NULL, &obj2, &was_visible, NULL, NULL); + ops_type = nmp_cache_update_link_udev (cache, pl_link_3.ifindex, NULL, &obj_old, &obj_new); g_assert_cmpint (ops_type, ==, NMP_CACHE_OPS_UPDATED); ASSERT_nmp_cache_is_consistent (cache); - g_assert (was_visible); - g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj2); - g_assert (nmp_object_is_visible (obj2)); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, TRUE), obj2, TRUE); - _assert_cache_multi_lookup_contains (cache, nmp_cache_id_init_object_type (&cache_id_storage, NMP_OBJECT_TYPE_LINK, FALSE), obj2, TRUE); - g_assert_cmpint (obj2->_link.netlink.is_in_netlink, ==, TRUE); - g_assert_cmpint (obj2->link.initialized, ==, !nmp_cache_use_udev_get (cache)); - nmp_object_unref (obj2); + g_assert (obj_old && nmp_object_is_visible (obj_old)); + g_assert (nmp_cache_lookup_obj (cache, nmp_object_stackinit_id_link (&objs1, pl_link_3.ifindex)) == obj_new); + g_assert (nmp_object_is_visible (obj_new)); + _assert_cache_multi_lookup_contains_link (cache, TRUE, obj_new, TRUE); + _assert_cache_multi_lookup_contains_link (cache, FALSE, obj_new, TRUE); + g_assert_cmpint (obj_new->_link.netlink.is_in_netlink, ==, TRUE); + g_assert_cmpint (obj_new->link.initialized, ==, !nmp_cache_use_udev_get (cache)); + nmp_object_unref (obj_new); + nmp_object_unref (obj_old); } nmp_cache_free (cache); From 6324b779b21edea016f337bd7dc93401353598d6 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 26 Jun 2017 17:30:32 +0200 Subject: [PATCH 15/36] platform: merge NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_*_DEFAULT indexes Maintaining an index is expensive. We can merge indexes that are strictly distinct, because one index can just partition the objects into distinct sets. --- src/platform/nmp-object.c | 94 +++++++++------------------------------ src/platform/nmp-object.h | 12 ++--- 2 files changed, 27 insertions(+), 79 deletions(-) diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index c63d3f2c51..5e3a9bf68e 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -190,38 +190,20 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, } return 1; - case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT: + case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT: 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_ROUTES_VISIBLE_ONLY_DEFAULT: - 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) + && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_a->ip_route) == 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)); + h = NM_HASH_COMBINE (h, NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_a->ip_route)); return _HASH_NON_ZERO (h); } return 1; @@ -247,41 +229,21 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, } return 1; - case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT: + case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT: 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) || obj_a->object.ifindex <= 0 || !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) - && 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_VISIBLE_BY_IFINDEX_ONLY_DEFAULT: - 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) - || obj_a->object.ifindex <= 0 - || !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) && obj_a->object.ifindex == obj_b->object.ifindex + && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_a->ip_route) == 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)); + h = NM_HASH_COMBINE (h, NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_a->ip_route)); h = NM_HASH_COMBINE (h, obj_a->object.ifindex); return _HASH_NON_ZERO (h); } @@ -1360,10 +1322,8 @@ 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_VISIBLE_BY_DEFAULT, + NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT, NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP4, 0, }; @@ -1372,10 +1332,8 @@ 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_VISIBLE_BY_DEFAULT, + NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT, NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6, 0, }; @@ -1736,28 +1694,18 @@ nmp_lookup_init_route_visible (NMPLookup *lookup, ifindex, TRUE); } - o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); - if (ifindex <= 0) { - o->object.ifindex = 1; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT; - } else { - o->object.ifindex = ifindex; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_ONLY_DEFAULT; - } - return _L (lookup); - } else if (with_non_default) { - o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); - o->ip_route.plen = 1; - if (ifindex <= 0) { - o->object.ifindex = 1; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT; - } else { - o->object.ifindex = ifindex; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_NO_DEFAULT; - } - return _L (lookup); - } else + } else if (!with_non_default) g_return_val_if_reached (NULL); + o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); + o->ip_route.plen = with_default ? 0 : 1; + if (ifindex <= 0) { + o->object.ifindex = 1; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT; + } else { + o->object.ifindex = ifindex; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT; + } + return _L (lookup); } const NMPLookup * diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index b63a96e043..efdc7781af 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -75,16 +75,16 @@ typedef enum { /*< skip >*/ /* all the visible objects of a certain type */ NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY, - /* indeces for the visible routes, ignoring ifindex. */ - NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_NO_DEFAULT, - NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_ONLY_DEFAULT, + /* indeces for the visible routes, ignoring ifindex. + * The index separates default routes from non-default routes. */ + NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT, /* all the visible addresses/routes (by object-type) for an ifindex. */ NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX, - /* 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, + /* indeces for the visible routes, per ifindex. + * The index separates default routes from non-default routes. */ + NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT, /* Consider all the destination fields of a route, that is, the ID without the ifindex * and gateway (meaning: network/plen,metric). From 35502807b5cef64e562e41b40bc213aea3cbb35b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 26 Jun 2017 17:30:32 +0200 Subject: [PATCH 16/36] platform: merge NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION* index In this case, not much is saved, because previously IPv4 and IPv6 routes had completely distinct indexes. --- src/platform/nmp-object.c | 61 +++++++++++++-------------------------- src/platform/nmp-object.h | 3 +- 2 files changed, 21 insertions(+), 43 deletions(-) diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 5e3a9bf68e..48fb81ffad 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -132,6 +132,7 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, 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(). */ @@ -249,42 +250,30 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, } return 1; - case NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP4: - if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ROUTE) + 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 NMP_OBJECT_GET_TYPE (obj_a) == NMP_OBJECT_GET_TYPE (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_a->ip4_route.network == obj_b->ip4_route.network; + && (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_a->ip4_route.network); - return _HASH_NON_ZERO (h); - } - return 1; - - case NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6: - if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP6_ROUTE) - || obj_a->object.ifindex <= 0) - return 0; - if (obj_b) { - return NMP_OBJECT_GET_TYPE (obj_a) == 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 - && 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, nm_utils_in6_addr_hash (&obj_a->ip6_route.network)); + 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; @@ -1318,23 +1307,13 @@ static const guint8 _supported_cache_ids_ipx_address[] = { 0, }; -static const guint8 _supported_cache_ids_ip4_route[] = { +static const guint8 _supported_cache_ids_ipx_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_BY_DEFAULT, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_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_BY_DEFAULT, - NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT, - NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION_IP6, + NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION, 0, }; @@ -1727,7 +1706,7 @@ nmp_lookup_init_route_by_dest (NMPLookup *lookup, 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_IP4; + 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); @@ -1736,7 +1715,7 @@ nmp_lookup_init_route_by_dest (NMPLookup *lookup, 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_IP6; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION; break; default: nm_assert_not_reached (); @@ -2510,7 +2489,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, + .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, @@ -2531,7 +2510,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, + .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, diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index efdc7781af..225276e4b8 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -94,8 +94,7 @@ 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, From bb009630a1ebf6de2b82e8afb986c90be3806318 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 26 Jun 2017 17:46:43 +0200 Subject: [PATCH 17/36] core: remove NMMultiIndex It's unused now. --- Makefile.am | 2 - src/nm-multi-index.c | 473 --------------------------- src/nm-multi-index.h | 105 ------ src/tests/test-general-with-expect.c | 358 -------------------- 4 files changed, 938 deletions(-) delete mode 100644 src/nm-multi-index.c delete mode 100644 src/nm-multi-index.h diff --git a/Makefile.am b/Makefile.am index 98b717021e..7e88e3f328 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1279,8 +1279,6 @@ src_libNetworkManagerBase_la_SOURCES = \ src/nm-logging.c \ src/nm-logging.h \ \ - src/nm-multi-index.c \ - src/nm-multi-index.h \ src/NetworkManagerUtils.c \ src/NetworkManagerUtils.h \ \ 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 - -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/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 #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 (); From d2f856fb95d5945282858bdc7fa3585b9a59aa81 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 27 Jun 2017 19:02:47 +0200 Subject: [PATCH 18/36] platform: fix nmp_object_hash() to include object type NMPlatformLnkMacvtap is a typedef of NMPlatformLnkMacvlan, hence, their plobj implementation is idential. nmp_object_equal() already correctly compares the object type, so we should hash it too. --- src/platform/nmp-object.c | 17 +++++++---------- 1 file changed, 7 insertions(+), 10 deletions(-) diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index 48fb81ffad..b698b838a1 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -860,6 +860,7 @@ guint nmp_object_hash (const NMPObject *obj) { const NMPClass *klass; + guint h; if (!obj) return 0; @@ -869,16 +870,12 @@ nmp_object_hash (const NMPObject *obj) klass = NMP_OBJECT_GET_CLASS (obj); if (klass->cmd_obj_hash) - return klass->cmd_obj_hash (obj); - if (klass->cmd_plobj_hash) - return klass->cmd_plobj_hash (&obj->object); - return GPOINTER_TO_UINT (obj); -} - -static guint -_vt_cmd_obj_hash_not_implemented (const NMPObject *obj) -{ - g_return_val_if_reached (0); + 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 From 55e66cc7e617345a39c9a9f929ce12f3f377e6b7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 27 Jun 2017 19:08:05 +0200 Subject: [PATCH 19/36] platform: implement hash function for NMPlatformLnk types --- shared/nm-utils/nm-macros-internal.h | 6 ++ src/nm-core-utils.h | 6 ++ src/platform/nm-platform.c | 142 +++++++++++++++++++++++++++ src/platform/nm-platform.h | 11 ++- src/platform/nmp-object.c | 55 ++++++++--- 5 files changed, 203 insertions(+), 17 deletions(-) diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 05e3ed7631..12794c3473 100644 --- a/shared/nm-utils/nm-macros-internal.h +++ b/shared/nm-utils/nm-macros-internal.h @@ -388,6 +388,12 @@ NM_HASH_COMBINE (guint h, guint val) 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 diff --git a/src/nm-core-utils.h b/src/nm-core-utils.h index f621393460..20df8d7e96 100644 --- a/src/nm-core-utils.h +++ b/src/nm-core-utils.h @@ -111,6 +111,12 @@ 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/platform/nm-platform.c b/src/platform/nm-platform.c index 12dd232e3b..e1fa923bb4 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4210,6 +4210,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) { @@ -4227,6 +4245,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) { @@ -4236,6 +4265,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) { @@ -4251,6 +4296,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) { @@ -4264,6 +4323,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) { @@ -4283,6 +4362,17 @@ 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) { @@ -4293,6 +4383,22 @@ nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkM 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) { @@ -4308,6 +4414,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) { @@ -4317,6 +4433,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) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index aaa549aeb2..9a38298030 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -426,7 +426,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; @@ -1029,6 +1029,15 @@ 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); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index b698b838a1..e310d26363 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -335,6 +335,20 @@ _dedup_multi_idx_type_init (DedupMultiIdxType *idx_type, NMPCacheIdType cache_id /*****************************************************************************/ +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 _vlan_xgress_qos_mappings_cmp (guint n_map, const NMVlanQosMapping *map1, @@ -887,16 +901,25 @@ _vt_cmd_obj_hash_link (const NMPObject *obj) h = NM_HASH_COMBINE (h, nm_platform_link_hash (&obj->link)); h = NM_HASH_COMBINE (h, obj->_link.netlink.is_in_netlink); - /* TODO: properly hash lnk objects. */ - h = NM_HASH_COMBINE (h, !!obj->_link.netlink.lnk); + 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_plobj_hash_not_implemented (const NMPlatformObject *obj) +_vt_cmd_obj_hash_lnk_vlan (const NMPObject *obj) { - g_return_val_if_reached (0); + 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 @@ -2431,7 +2454,7 @@ 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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2525,7 +2548,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2535,7 +2558,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2545,7 +2568,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2555,7 +2578,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2565,7 +2588,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2575,7 +2598,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2585,7 +2608,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2595,7 +2618,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2604,13 +2627,13 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .sizeof_public = sizeof (NMPlatformLnkVlan), .obj_type_name = "vlan", .lnk_link_type = NM_LINK_TYPE_VLAN, - .cmd_obj_hash = _vt_cmd_obj_hash_not_implemented, + .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 = _vt_cmd_plobj_hash_not_implemented, + .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] = { @@ -2620,7 +2643,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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 = _vt_cmd_plobj_hash_not_implemented, + .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, }, }; From 485551286c3a7e457972cc4445f4fdf0446d64a8 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 29 Jun 2017 10:51:38 +0200 Subject: [PATCH 20/36] platform: add use-udev property for NMPlatform We want to move the multi_idx from NMLinuxPlatform to NMPlatform, so that it can be used by NMFakePlatform as well. For that, we need to know whether NMPlatform will use udev or not. Add a constrctor property. --- src/platform/nm-linux-platform.c | 18 ++++++++++++------ src/platform/nm-platform.c | 20 ++++++++++++++++++++ src/platform/nm-platform.h | 2 ++ 3 files changed, 34 insertions(+), 6 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 6edf38baa9..fe08b985e9 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2619,8 +2619,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); } @@ -6723,12 +6730,6 @@ nm_linux_platform_init (NMLinuxPlatform *self) 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 ( nmp_netns_is_initial () - && access ("/sys", W_OK) == 0) { - priv->udev_client = nm_udev_client_new ((const char *[]) { "net", NULL }, - handle_udev_event, self); - } } static void @@ -6742,6 +6743,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); + } + priv->cache = nmp_cache_new (nm_platform_get_multi_idx (platform), priv->udev_client != NULL); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index e1fa923bb4..661cb40fa2 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -80,11 +80,13 @@ 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; } NMPlatformPrivate; @@ -95,6 +97,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) { @@ -4929,6 +4937,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); @@ -4976,6 +4988,14 @@ nm_platform_class_init (NMPlatformClass *platform_class) G_PARAM_CONSTRUCT_ONLY | 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, "", "", diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 9a38298030..b9ddc239b6 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" /*****************************************************************************/ @@ -726,6 +727,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); From e160928b9ed3ca00e81bb0a6e24d8f1f7d088bc5 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 29 Jun 2017 11:18:10 +0200 Subject: [PATCH 21/36] platform: move the NMPCache from linux platform to NMPlatform We want to expose the NMPLookup and NMDedupMultiHeadEntry to the users of NMPlatform, so that they can iterate the cache directly. That means, NMPCache becames an integral part of NMPlatform's API and must also be implemented by NMFakePlatform. --- Makefile.am | 1 + src/platform/nm-linux-platform.c | 129 +++++++++++++---------------- src/platform/nm-platform-private.h | 29 +++++++ src/platform/nm-platform.c | 44 +++++++--- 4 files changed, 121 insertions(+), 82 deletions(-) create mode 100644 src/platform/nm-platform-private.h diff --git a/Makefile.am b/Makefile.am index 7e88e3f328..b97da487fc 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1290,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 \ diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index fe08b985e9..135d325cce 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" @@ -2573,7 +2574,6 @@ typedef struct { guint32 nlh_seq_last_handled; #endif guint32 nlh_seq_last_seen; - NMPCache *cache; GIOChannel *event_channel; guint event_id; @@ -2936,7 +2936,7 @@ do_emit_signal (NMPlatform *platform, 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_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, cache_op, obj_old, obj_new); + ASSERT_nmp_cache_ops (nm_platform_get_cache (platform), cache_op, obj_old, obj_new); ASSERT_NETNS_CURRENT (platform); @@ -3161,12 +3161,11 @@ 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 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_old, &obj_new); + 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); @@ -3356,17 +3355,17 @@ delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform, static void cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); 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, FALSE); nm_dedup_multi_iter_init (&iter, - nmp_cache_lookup (priv->cache, + nmp_cache_lookup (cache, &lookup)); while (nm_dedup_multi_iter_next (&iter)) { if (iter.current->dirty) { @@ -3374,7 +3373,7 @@ cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type) obj = iter.current->box->obj; _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_old); + 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); do_emit_signal (platform, cache_op, obj_old, NULL); @@ -3405,12 +3404,12 @@ cache_on_change (NMPlatform *platform, const NMPObject *obj_old, const NMPObject *obj_new) { - 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); - ASSERT_nmp_cache_ops (priv->cache, cache_op, obj_old, obj_new); + ASSERT_nmp_cache_ops (cache, cache_op, obj_old, obj_new); if (cache_op == NMP_CACHE_OPS_UNCHANGED) return; @@ -3437,17 +3436,17 @@ cache_on_change (NMPlatform *platform, { /* check whether changing a slave link can cause a master link (bridge or bond) to go up/down */ if ( obj_old - && nmp_cache_link_connected_needs_toggle_by_ifindex (priv->cache, obj_old->link.master, obj_new, 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 (priv->cache, obj_new->link.master, obj_new, obj_old)) + && 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 ( obj_new /* <-- nonsensical, make coverity happy */ - && nmp_cache_link_connected_needs_toggle (priv->cache, obj_new, obj_new, obj_old)) + && 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)); } { @@ -3497,7 +3496,7 @@ cache_on_change (NMPlatform *platform, nmp_lookup_init_link (&lookup, FALSE); nmp_cache_iter_for_each_link (&iter, - nmp_cache_lookup (priv->cache, &lookup), + nmp_cache_lookup (cache, &lookup), &l) { if (l->parent == ifindex) delayed_action_schedule (platform, DELAYED_ACTION_TYPE_REFRESH_LINK, GINT_TO_POINTER (l->ifindex)); @@ -3637,8 +3636,6 @@ cache_post (NMPlatform *platform, const NMPObject *obj_old, const NMPObject *obj_new) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); - if (msghdr->nlmsg_type == RTM_NEWROUTE) { DelayedActionType action_type; @@ -3646,7 +3643,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 @@ -3708,7 +3705,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha if (ifindex > 0) { const NMDedupMultiEntry *entry; - entry = nmp_cache_lookup_entry_link (priv->cache, ifindex); + 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); @@ -3745,7 +3742,7 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio FOR_EACH_DELAYED_ACTION (iflags, action_type) { priv->pruning[delayed_action_refresh_all_to_idx (iflags)] = TRUE; - nmp_cache_dirty_set_all (priv->cache, + nmp_cache_dirty_set_all (nm_platform_get_cache (platform), delayed_action_refresh_to_object_type (iflags)); } @@ -3870,12 +3867,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; NMPCacheOpsType cache_op; struct nlmsghdr *msghdr; char buf_nlmsg_type[16]; gboolean id_only = FALSE; + NMPCache *cache = nm_platform_get_cache (platform); msghdr = nlmsg_hdr (msg); @@ -3891,7 +3888,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)), @@ -3914,7 +3911,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_NEWADDR: case RTM_NEWROUTE: case RTM_GETLINK: - cache_op = nmp_cache_update_netlink (priv->cache, obj, &obj_old, &obj_new); + 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); do_emit_signal (platform, cache_op, obj_old, obj_new); @@ -3923,7 +3920,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event case RTM_DELLINK: case RTM_DELADDR: case RTM_DELROUTE: - cache_op = nmp_cache_remove_netlink (priv->cache, obj, &obj_old, &obj_new); + 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); do_emit_signal (platform, cache_op, obj_old, obj_new); @@ -3943,7 +3940,7 @@ 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); + obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex); if (!nmp_object_is_visible (obj_cache)) return NULL; @@ -3953,11 +3950,10 @@ cache_lookup_link (NMPlatform *platform, int ifindex) static GArray * link_get_all (NMPlatform *platform) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); NMPLookup lookup; nmp_lookup_init_link (&lookup, TRUE); - return nmp_cache_lookup_to_array (nmp_cache_lookup (priv->cache, &lookup), + return nmp_cache_lookup_to_array (nmp_cache_lookup (nm_platform_get_cache (platform), &lookup), NMP_OBJECT_TYPE_LINK); } @@ -3977,7 +3973,7 @@ _nm_platform_link_get_by_ifname (NMPlatform *platform, const NMPObject *obj = NULL; if (ifname && *ifname) { - 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, ifname, TRUE, NM_LINK_TYPE_NONE, NULL, NULL); } return obj ? &obj->link : NULL; @@ -4010,7 +4006,7 @@ _nm_platform_link_get_by_address (NMPlatform *platform, if (!address) return NULL; - 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, TRUE, NM_LINK_TYPE_NONE, (NMPObjectMatchFn) _nm_platform_link_get_by_address_match_link, &d); return obj ? &obj->link : NULL; @@ -4047,19 +4043,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, @@ -4091,13 +4087,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) @@ -4108,11 +4104,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, @@ -4150,10 +4146,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 @@ -4164,12 +4160,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); @@ -4208,13 +4204,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 @@ -4349,11 +4345,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; @@ -4392,12 +4387,11 @@ link_get_type_name (NMPlatform *platform, int ifindex) 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); + link = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex); if (!link) return FALSE; @@ -4523,7 +4517,7 @@ link_get_udev_device (NMPlatform *platform, int ifindex) * 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); + obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex); return obj_cache ? obj_cache->_link.udev.device : NULL; } @@ -4661,7 +4655,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) { @@ -5344,7 +5338,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; @@ -5356,7 +5349,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"); @@ -5475,7 +5468,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); @@ -5525,7 +5518,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; @@ -5561,7 +5553,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; @@ -5699,10 +5691,10 @@ 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); NMPLookup lookup; const NMPObject *link, *o; NMDedupMultiIter iter; + NMPCache *cache = nm_platform_get_cache (platform); if (ifindex <= 0) return FALSE; @@ -5721,7 +5713,7 @@ link_can_assume (NMPlatform *platform, int ifindex) NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, TRUE); - if (nmp_cache_lookup (priv->cache, &lookup)) + if (nmp_cache_lookup (cache, &lookup)) return TRUE; nmp_lookup_init_addrroute (&lookup, @@ -5729,7 +5721,7 @@ link_can_assume (NMPlatform *platform, int ifindex) ifindex, TRUE); nmp_cache_iter_for_each (&iter, - nmp_cache_lookup (priv->cache, &lookup), + 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)) @@ -5811,7 +5803,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); NMPLookup lookup; nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); @@ -5819,7 +5810,7 @@ ipx_address_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type) obj_type, ifindex, TRUE); - return nmp_cache_lookup_to_array (nmp_cache_lookup (priv->cache, &lookup), + return nmp_cache_lookup_to_array (nmp_cache_lookup (nm_platform_get_cache (platform), &lookup), obj_type); } @@ -5953,7 +5944,7 @@ ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, guint8 plen, 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); + obj = nmp_cache_lookup_obj (nm_platform_get_cache (platform), &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip4_address; return NULL; @@ -5966,7 +5957,7 @@ ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr) 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); + obj = nmp_cache_lookup_obj (nm_platform_get_cache (platform), &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip6_address; return NULL; @@ -5977,7 +5968,6 @@ ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr) static GArray * ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); NMDedupMultiIter iter; NMPLookup lookup; const NMDedupMultiHeadEntry *head_entry; @@ -5993,7 +5983,7 @@ ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NM klass = nmp_class_from_type (obj_type); - head_entry = nmp_cache_lookup (priv->cache, + head_entry = nmp_cache_lookup (nm_platform_get_cache (platform), nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, @@ -6112,7 +6102,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; @@ -6121,6 +6110,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. @@ -6129,7 +6120,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. @@ -6144,7 +6135,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; } } @@ -6222,7 +6213,7 @@ ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen 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); + obj = nmp_cache_lookup_obj (nm_platform_get_cache (platform), &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip4_route; return NULL; @@ -6237,7 +6228,7 @@ ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, guint 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); + obj = nmp_cache_lookup_obj (nm_platform_get_cache (platform), &obj_id); if (nmp_object_is_visible (obj)) return &obj->ip6_route; return NULL; @@ -6603,12 +6594,11 @@ cache_update_link_udev (NMPlatform *platform, int ifindex, struct udev_device *udevice) { - NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); 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_old, &obj_new); + 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; @@ -6672,7 +6662,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; @@ -6748,9 +6738,6 @@ constructed (GObject *_object) handle_udev_event, platform); } - priv->cache = nmp_cache_new (nm_platform_get_multi_idx (platform), - priv->udev_client != NULL); - _LOGD ("create (%s netns, %s, %s udev)", !platform->_netns ? "ignore" : "use", !platform->_netns && nmp_netns_is_initial () @@ -6760,7 +6747,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); @@ -6869,8 +6856,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); diff --git a/src/platform/nm-platform-private.h b/src/platform/nm-platform-private.h new file mode 100644 index 0000000000..10799f36bd --- /dev/null +++ b/src/platform/nm-platform-private.h @@ -0,0 +1,29 @@ +/* -*- 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); + +#endif /* __NM_PLATFORM_PRIVATE_H__ */ diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 661cb40fa2..5c45a19c2f 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -39,6 +39,7 @@ #include "nm-core-utils.h" #include "nm-platform-utils.h" +#include "nm-platform-private.h" #include "nmp-object.h" #include "nmp-netns.h" @@ -89,6 +90,7 @@ 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) @@ -206,16 +208,9 @@ nm_platform_get () NMDedupMultiIndex * nm_platform_get_multi_idx (NMPlatform *self) { - NMPlatformPrivate *priv; - g_return_val_if_fail (NM_IS_PLATFORM (self), NULL); - priv = NM_PLATFORM_GET_PRIVATE (self); - - if (G_UNLIKELY (!priv->multi_idx)) - priv->multi_idx = nm_dedup_multi_index_new (); - - return priv->multi_idx; + return NM_PLATFORM_GET_PRIVATE (self)->multi_idx; } /*****************************************************************************/ @@ -4800,6 +4795,12 @@ log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatform /*****************************************************************************/ +NMPCache * +nm_platform_get_cache (NMPlatform *self) +{ + return NM_PLATFORM_GET_PRIVATE (self)->cache; +} + NMPNetns * nm_platform_netns_get (NMPlatform *self) { @@ -4957,15 +4958,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); - if (priv->multi_idx) - nm_dedup_multi_index_unref (priv->multi_idx); g_clear_object (&self->_netns); + nm_dedup_multi_index_unref (priv->multi_idx); + nmp_cache_free (priv->cache); } static void @@ -4975,6 +4998,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; From c5af191dbfaeee5c8508549a7bcdedff30a2ff13 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 29 Jun 2017 13:13:54 +0200 Subject: [PATCH 22/36] platform: expose emit-signal function from platform It will be used by NMFakePlatform too. --- src/platform/nm-linux-platform.c | 88 ++---------------------------- src/platform/nm-platform-private.h | 13 +++++ src/platform/nm-platform.c | 68 +++++++++++++++++++++++ 3 files changed, 87 insertions(+), 82 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 135d325cce..4a7531fd9d 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -262,7 +262,6 @@ static void cache_on_change (NMPlatform *platform, 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); /*****************************************************************************/ @@ -632,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) { @@ -2638,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) \ @@ -2923,74 +2915,6 @@ process_events (NMPlatform *platform) /*****************************************************************************/ -static void -do_emit_signal (NMPlatform *platform, - 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 (platform), cache_op, obj_old, obj_new); - - ASSERT_NETNS_CURRENT (platform); - - 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 (platform, - _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); -} - -/*****************************************************************************/ - _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), @@ -3169,7 +3093,7 @@ delayed_action_handle_MASTER_CONNECTED (NMPlatform *platform, int master_ifindex if (cache_op == NMP_CACHE_OPS_UNCHANGED) return; cache_on_change (platform, cache_op, obj_old, obj_new); - do_emit_signal (platform, cache_op, obj_old, obj_new); + nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); } static void @@ -3376,7 +3300,7 @@ cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type) 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); - do_emit_signal (platform, cache_op, obj_old, NULL); + nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, NULL); } } } @@ -3914,7 +3838,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event 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); - do_emit_signal (platform, cache_op, obj_old, obj_new); + nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); break; case RTM_DELLINK: @@ -3923,7 +3847,7 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event 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); - do_emit_signal (platform, cache_op, obj_old, obj_new); + nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); } break; @@ -6606,7 +6530,7 @@ cache_update_link_udev (NMPlatform *platform, cache_on_change (platform, cache_op, obj_old, obj_new); if (!nm_platform_netns_push (platform, &netns)) return; - do_emit_signal (platform, cache_op, obj_old, obj_new); + nm_platform_cache_update_emit_signal (platform, cache_op, obj_old, obj_new); } } diff --git a/src/platform/nm-platform-private.h b/src/platform/nm-platform-private.h index 10799f36bd..b6c94baaf7 100644 --- a/src/platform/nm-platform-private.h +++ b/src/platform/nm-platform-private.h @@ -26,4 +26,17 @@ 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 5c45a19c2f..8c1b6ceca5 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -4795,6 +4795,74 @@ 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) { From 16aefdd865361bba2a11a9245cdfdda83f061198 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 29 Jun 2017 14:46:32 +0200 Subject: [PATCH 23/36] platform: expose index lookup for objects in public API --- src/platform/nm-platform.c | 8 ++++ src/platform/nm-platform.h | 5 +++ src/platform/nmp-object.h | 75 +++++++++++++++++++++++++++++++++++++- 3 files changed, 86 insertions(+), 2 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 8c1b6ceca5..d19dc7cca3 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2651,6 +2651,14 @@ nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean * /*****************************************************************************/ +const NMDedupMultiHeadEntry * +nm_platform_lookup (NMPlatform *platform, + const NMPLookup *lookup) +{ + return nmp_cache_lookup (nm_platform_get_cache (platform), + lookup); +} + void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, guint8 plen) { diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index b9ddc239b6..b14a75a71a 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -777,6 +777,11 @@ 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); + /* 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); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 225276e4b8..914e756daf 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -386,10 +386,12 @@ const NMDedupMultiEntry *nmp_cache_lookup_entry_link (const NMPCache *cache, int 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 { +typedef struct _NMPLookup NMPLookup; + +struct _NMPLookup { NMPCacheIdType cache_id_type; NMPObject selector_obj; -} NMPLookup; +}; const NMDedupMultiHeadEntry *nmp_cache_lookup_all (const NMPCache *cache, NMPCacheIdType cache_id_type, @@ -549,4 +551,73 @@ ASSERT_nmp_cache_ops (const NMPCache *cache, #endif } +static inline const NMDedupMultiHeadEntry * +nm_platform_lookup_obj_type (NMPlatform *platform, + NMPObjectType obj_type, + gboolean visible_only) +{ + NMPLookup lookup; + + nmp_lookup_init_obj_type (&lookup, obj_type, visible_only); + return nm_platform_lookup (platform, &lookup); +} + +static inline const NMDedupMultiHeadEntry * +nm_platform_lookup_link (NMPlatform *platform, + gboolean visible_only) +{ + NMPLookup lookup; + + nmp_lookup_init_link (&lookup, visible_only); + 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, + gboolean visible_only) +{ + NMPLookup lookup; + + nmp_lookup_init_addrroute (&lookup, obj_type, ifindex, visible_only); + return nm_platform_lookup (platform, &lookup); +} + +static inline const NMDedupMultiHeadEntry * +nm_platform_lookup_route_visible (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + gboolean with_default, + gboolean with_non_default) +{ + NMPLookup lookup; + + nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, with_default, with_non_default); + return nm_platform_lookup (platform, &lookup); +} + +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__ */ From c9cd6d995482b9c7d1a06e0601d321968abcf9f7 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 29 Jun 2017 13:05:52 +0200 Subject: [PATCH 24/36] platform: track routes in NMFakePlatform via NMPCache NMPlatform's cache should be directly accessible to the users, at least the NMPLookup part and the fact that the cache contains ref-counted, immutable NMPObjects. This allows users to inspect the cache with zero overhead. Meaning, they can obtain an NMDedupMultiHeadEntry and iterate the objects themself. It also means, the are free to take and keep references of the NMPObject instances (of course, without modifying them!). NMFakePlatform will use the very same cache. The fake platform should only differ when modifying the objects. Another reason why this makes sense is because NMFakePlatform is for one a test-stup but also tests behavior of platform itself. Using a separate internal implementation for the caching is a pointless excecise, because only the real NMPCache's implementation really matters for production. So, either NMFakePlatform behaves idential, or it is buggy. Reuse it. Port fake platform's tracking of routes to NMPCache and move duplicate code from NMLinuxPlatform to the base class. This commit only ports IP routes, eventually also addresses and links should be tracked via the NMPCache instance. --- src/platform/nm-fake-platform.c | 392 +++++++++++-------------------- src/platform/nm-linux-platform.c | 84 ------- src/platform/nm-platform.c | 64 ++++- src/platform/nm-platform.h | 4 - src/platform/nmp-object.h | 16 ++ 5 files changed, 218 insertions(+), 342 deletions(-) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 27fde50d61..028931c8c8 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" @@ -51,8 +52,6 @@ typedef struct { GArray *links; GArray *ip4_addresses; GArray *ip6_addresses; - GArray *ip4_routes; - GArray *ip6_routes; } NMFakePlatformPrivate; struct _NMFakePlatform { @@ -98,6 +97,13 @@ G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM) static void link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_signal); +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, struct in6_addr addr, @@ -399,18 +405,8 @@ link_delete (NMPlatform *platform, int ifindex) 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); - - if (route->ifindex == ifindex) - memset (route, 0, sizeof (*route)); - } - 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)); - } + ipx_route_delete (platform, AF_INET, ifindex, NULL, NULL, NULL); + ipx_route_delete (platform, AF_INET6, ifindex, NULL, NULL, NULL); g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, (int) NMP_OBJECT_TYPE_LINK, ifindex, &deleted_device, (int) NM_PLATFORM_SIGNAL_REMOVED); @@ -1152,270 +1148,174 @@ ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr) /*****************************************************************************/ -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)); + g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - 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; + 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, + FALSE), + &o) { + const NMPObject *obj_old = NULL; - /* 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); - } + 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; } + + 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; -} - -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); - } - } + for (i = 0; i < objs->len; i++) { + nm_platform_cache_update_emit_signal (platform, + NMP_CACHE_OPS_REMOVED, + objs->pdata[i], + NULL); } - - return routes; + 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); + return ipx_route_delete (platform, AF_INET6, ifindex, &network, &plen, &metric); +} - for (i = 0; i < priv->ip6_routes->len; i++) { - NMPlatformIP6Route *route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i); - NMPlatformIP6Route deleted_route; +static gboolean +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; - if ( route->ifindex != ifindex - || !IN6_ARE_ADDR_EQUAL (&route->network, &network) - || route->plen != plen - || route->metric != metric) - continue; + g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - 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); + 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; } + 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, + FALSE), + &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); + + if ( rt->ifindex == item->ifindex + && nm_utils_ip6_address_same_prefix (&rt6->gateway, &item->network, item->plen)) { + has_route_to_gw = TRUE; + break; + } + } + } + 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; + } + } + + 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 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; - } - } - - 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; + return ipx_route_add (platform, AF_INET, (const NMPlatformObject *) route); } static gboolean ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) { - NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); - NMPlatformIP6Route rt = *route; - guint i; - - 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 (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); - 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); - - return TRUE; -} - -static const NMPlatformIP4Route * -ip4_route_get (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); - - if (route->ifindex == ifindex - && route->network == network - && route->plen == plen - && route->metric == metric) - return route; - } - - return NULL; -} - -static const NMPlatformIP6Route * -ip6_route_get (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); - - 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); } /*****************************************************************************/ @@ -1429,8 +1329,6 @@ nm_fake_platform_init (NMFakePlatform *fake_platform) 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 @@ -1472,8 +1370,6 @@ finalize (GObject *object) 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); } @@ -1550,10 +1446,6 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) 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 4a7531fd9d..65dc6e0168 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -5889,58 +5889,6 @@ ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr) /*****************************************************************************/ -static GArray * -ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags) -{ - NMDedupMultiIter iter; - NMPLookup lookup; - const NMDedupMultiHeadEntry *head_entry; - GArray *array; - const NMPClass *klass; - const NMPObject *o; - gboolean with_rtprot_kernel; - - 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); - - head_entry = nmp_cache_lookup (nm_platform_get_cache (platform), - nmp_lookup_init_route_visible (&lookup, - obj_type, - ifindex, - NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT), - NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))); - - array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, head_entry ? head_entry->len : 0); - - with_rtprot_kernel = NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); - - nmp_cache_iter_for_each (&iter, - head_entry, - &o) { - nm_assert (NMP_OBJECT_GET_CLASS (o) == klass); - if ( with_rtprot_kernel - || o->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) - g_array_append_vals (array, &o->ip_route, 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) { @@ -6130,34 +6078,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_platform_get_cache (platform), &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_platform_get_cache (platform), &obj_id); - if (nmp_object_is_visible (obj)) - return &obj->ip6_route; - return NULL; -} - /*****************************************************************************/ #define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI)) @@ -6898,10 +6818,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) 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-platform.c b/src/platform/nm-platform.c index d19dc7cca3..d529cdd713 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3160,6 +3160,46 @@ nm_platform_address_flush (NMPlatform *self, int ifindex) /*****************************************************************************/ +static GArray * +ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags) +{ + NMDedupMultiIter iter; + NMPLookup lookup; + const NMDedupMultiHeadEntry *head_entry; + GArray *array; + const NMPClass *klass; + const NMPObject *o; + gboolean with_rtprot_kernel; + + 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); + + head_entry = nmp_cache_lookup (nm_platform_get_cache (platform), + nmp_lookup_init_route_visible (&lookup, + obj_type, + ifindex, + NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT), + NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))); + + array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, head_entry ? head_entry->len : 0); + + with_rtprot_kernel = NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); + + nmp_cache_iter_for_each (&iter, + head_entry, + &o) { + nm_assert (NMP_OBJECT_GET_CLASS (o) == klass); + if ( with_rtprot_kernel + || o->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + g_array_append_vals (array, &o->ip_route, 1); + } + return array; +} + GArray * nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags) { @@ -3167,7 +3207,7 @@ nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute g_return_val_if_fail (ifindex >= 0, NULL); - return klass->ip4_route_get_all (self, ifindex, flags); + return ipx_route_get_all (self, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags); } GArray * @@ -3177,7 +3217,7 @@ nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRoute g_return_val_if_fail (ifindex >= 0, NULL); - return klass->ip6_route_get_all (self, ifindex, flags); + return ipx_route_get_all (self, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags); } /** @@ -3258,17 +3298,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; } /*****************************************************************************/ diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index b14a75a71a..bbb43269f2 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -667,14 +667,10 @@ typedef struct { 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 *); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 914e756daf..18c9220ab8 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -339,7 +339,23 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN; } +#define NMP_OBJECT_CAST_IP4_ROUTE(obj) \ + ({ \ + typeof (*(obj)) *_obj = (obj); \ + _nm_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ROUTE); \ + &_obj->ip4_route; \ + }) +#define NMP_OBJECT_CAST_IP6_ROUTE(obj) \ + ({ \ + typeof (*(obj)) *_obj = (obj); \ + _nm_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ROUTE); \ + &_obj->ip6_route; \ + }) const NMPClass *nmp_class_from_type (NMPObjectType obj_type); From 667c50f5d920e91d798d51c61e63e3ce87e277d3 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 29 Jun 2017 15:19:35 +0200 Subject: [PATCH 25/36] core: avoid cloning platform routes but iterate the cache directly --- src/devices/nm-device.c | 64 +++++++++++----------- src/nm-default-route-manager.c | 91 +++++++++++++++++-------------- src/nm-ip4-config.c | 59 +++++++++++--------- src/nm-route-manager.c | 58 +++++++++++++++++--- src/nm-test-utils-core.h | 38 +++++++++++++ src/platform/nm-platform.c | 72 ++++++++++++++++++++---- src/platform/nm-platform.h | 11 +++- src/platform/nmp-object.h | 33 +++++++++++ src/platform/tests/test-cleanup.c | 22 ++++---- src/platform/tests/test-common.h | 27 +++++++++ src/platform/tests/test-route.c | 28 ++++------ src/tests/test-route-manager.c | 39 ++++++++++--- 12 files changed, 387 insertions(+), 155 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index dd9c96cf91..db59171b02 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -42,6 +42,7 @@ #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" @@ -5405,45 +5406,46 @@ ipv4ll_start (NMDevice *self) static gboolean _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route) { - gboolean success = FALSE; int ifindex = nm_device_get_ip_ifindex (self); - GArray *routes; + const NMDedupMultiHeadEntry *pl_head_entry; + NMDedupMultiIter iter; + const NMPObject *plobj = NULL; + const NMPlatformIPRoute *route = NULL; + guint32 route_metric = G_MAXUINT32; - if (addr_family == AF_INET) - routes = nm_platform_ip4_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); - else - routes = nm_platform_ip6_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT); + pl_head_entry = nm_platform_lookup_route_visible (nm_device_get_platform (self), + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex, + TRUE, + FALSE); + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + guint32 m; + const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj); - if (routes) { - guint route_metric = G_MAXUINT32, m; - const NMPlatformIPRoute *route = NULL, *r; - guint i; + if (r->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; } /*****************************************************************************/ diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index 609c1658ef..fb61ef751c 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 ((NMPObject *) 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 ((NMPObject *) routes->pdata[i]); route.rx.rt_source = r->rt_source; if (nm_platform_ip6_route_cmp (r, &route.r6) == 0) @@ -331,19 +326,28 @@ _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, + FALSE, + 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 ((NMPObject *) routes->pdata[i]); /* look at all entries and see if the route for this ifindex pair is * a known entry. */ @@ -372,7 +376,6 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, changed = TRUE; } } - g_array_free (routes, TRUE); return changed; } @@ -419,7 +422,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 +438,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 ((NMPObject *) 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 +498,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 +516,13 @@ _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, + FALSE, + nm_platform_lookup_predicate_routes_skip_rtprot_kernel, + NULL); assumed_metrics = _get_assumed_interface_metrics (vtable, self, routes); @@ -560,13 +571,15 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c * If there are any, we have to pick another effective_metric. */ /* However, if there is a matching route (ifindex+metric) for our current entry, we are done. */ - for (j = 0; j < routes->len; j++) { - const NMPlatformIPRoute *r = _vt_route_index (vtable, routes, i); + if (routes) { + for (j = 0; j < routes->len; j++) { + const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE ((NMPObject *) routes->pdata[i]); - if ( r->metric == expected_metric - && r->ifindex == entry->route.rx.ifindex) { - has_metric_for_ifindex = TRUE; - break; + if ( r->metric == expected_metric + && r->ifindex == entry->route.rx.ifindex) { + has_metric_for_ifindex = TRUE; + break; + } } } if (has_metric_for_ifindex) @@ -611,8 +624,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-ip4-config.c b/src/nm-ip4-config.c index 1f0d86d30e..50000e6275 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -386,11 +386,12 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i { NMIP4Config *config; NMIP4ConfigPrivate *priv; - guint i; - guint32 lowest_metric = G_MAXUINT32; + guint32 lowest_metric; guint32 old_gateway = 0; gboolean old_has_gateway = FALSE; - gs_unref_array GArray *routes = NULL; + 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) @@ -404,50 +405,56 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i priv->addresses = nm_platform_ip4_address_get_all (platform, ifindex); g_array_sort (priv->addresses, sort_captured_addresses); - 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, + TRUE, + TRUE); /* Extract gateway from default route */ old_gateway = priv->gateway; old_has_gateway = priv->has_gateway; - for (i = 0; i < routes->len; ) { - const NMPlatformIP4Route *route = &g_array_index (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 (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 < routes->len; i++) { - const NMPlatformIP4Route *route = &g_array_index (routes, NMPlatformIP4Route, i); + nm_dedup_multi_iter_rewind (&iter); + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj); - if ( (route->plen == 32) - && (route->network == priv->gateway) - && (route->gateway == 0)) { - g_array_remove_index (routes, i); - i--; - } + if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + continue; + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + continue; + + if ( priv->has_gateway + && route->plen == 32 + && route->network == priv->gateway + && route->gateway == 0) { + /* If there is a host route to the gateway, ignore that route. It is + * automatically added by NetworkManager when needed. + */ + continue; } + _add_route (config, plobj, NULL); } - for (i = 0; i < routes->len; i++) - _add_route (config, NULL, &g_array_index (routes, NMPlatformIP4Route, i)); - /* If the interface has the default route, and has IPv4 addresses, capture * nameservers from /etc/resolv.conf. */ diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 6c1f78ac96..574493d990 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -306,6 +306,50 @@ _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, len; + GPtrArray *storage; + + nm_assert (out_storage && !*out_storage); + + storage = nm_platform_lookup_route_visible_clone (platform, + vtable->vt->obj_type, + ifindex, + FALSE, + TRUE, + NULL, + NULL); + if (!storage) + return _route_index_create (vtable, NULL); + + len = storage->len; + index = g_malloc (sizeof (RouteIndex) + len * sizeof (NMPlatformIPXRoute *)); + + index->len = len; + for (i = 0; i < len; i++) { + /* we cast away the const-ness of the NMPObjects. The caller must + * ensure not to modify the object via index->entries. */ + index->entries[i] = NMP_OBJECT_CAST_IPX_ROUTE ((NMPObject *) storage->pdata[i]); + } + index->entries[i] = NULL; + + /* this is a stable sort, which is very important at this point. */ + g_qsort_with_data (index->entries, + 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 +502,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 +519,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 +961,6 @@ next: g_free (known_routes_idx); g_free (plat_routes_idx); - g_array_unref (plat_routes); return success; } diff --git a/src/nm-test-utils-core.h b/src/nm-test-utils-core.h index 8ee7205de8..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,6 +279,25 @@ 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 diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index d529cdd713..c8008216b2 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2659,6 +2659,64 @@ nm_platform_lookup (NMPlatform *platform, 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: + * @platform: + * @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 *platform, + const NMPLookup *lookup, + gboolean (*predicate) (const NMPObject *obj, gpointer user_data), + gpointer user_data) +{ + const NMDedupMultiHeadEntry *head_entry; + GPtrArray *result; + NMDedupMultiIter iter; + const NMPObject *plobj = NULL; + + head_entry = nm_platform_lookup (platform, lookup); + if (!head_entry) + return NULL; + + result = g_ptr_array_new_full (head_entry->len, + (GDestroyNotify) nmp_object_unref); + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + if ( predicate + && !predicate (plobj, user_data)) + continue; + g_ptr_array_add (result, (gpointer) nmp_object_ref (plobj)); + } + + if (result->len == 0) { + g_ptr_array_unref (result); + return NULL; + } + return result; +} + void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, guint8 plen) { @@ -3200,16 +3258,6 @@ ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NM return array; } -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 ipx_route_get_all (self, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags); -} - GArray * nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags) { @@ -5026,11 +5074,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, @@ -5039,11 +5087,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, diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index bbb43269f2..f4c499787e 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -373,11 +373,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); @@ -778,6 +778,14 @@ 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); @@ -972,7 +980,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); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 18c9220ab8..6c0098bfce 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -339,6 +339,24 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN; } +#define NMP_OBJECT_CAST_IPX_ROUTE(obj) \ + ({ \ + typeof (*(obj)) *_obj = (obj); \ + _nm_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ + &_obj->ipx_route; \ + }) + +#define NMP_OBJECT_CAST_IP_ROUTE(obj) \ + ({ \ + typeof (*(obj)) *_obj = (obj); \ + _nm_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ + &_obj->ip_route; \ + }) + #define NMP_OBJECT_CAST_IP4_ROUTE(obj) \ ({ \ typeof (*(obj)) *_obj = (obj); \ @@ -623,6 +641,21 @@ nm_platform_lookup_route_visible (NMPlatform *platform, return nm_platform_lookup (platform, &lookup); } +static inline GPtrArray * +nm_platform_lookup_route_visible_clone (NMPlatform *platform, + NMPObjectType obj_type, + int ifindex, + gboolean with_default, + gboolean with_non_default, + gboolean (*predicate) (const NMPObject *obj, gpointer user_data), + gpointer user_data) +{ + NMPLookup lookup; + + nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, with_default, with_non_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, 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.h b/src/platform/tests/test-common.h index b4ed0682ea..e047705fd3 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -5,6 +5,7 @@ #include #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,32 @@ 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, + TRUE, + TRUE, + 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, + TRUE, + TRUE, + 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-route.c b/src/platform/tests/test-route.c index c96af93e51..f4ac2a6e6c 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); } diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index 6650d26c43..f647cc7494 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -145,15 +145,38 @@ update_dev0_ip4 (int ifindex) static GArray * ip4_routes (test_fixture *fixture) { - 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); + GArray *routes; + const NMDedupMultiHeadEntry *pl_head_entry; + NMDedupMultiIter iter; + const NMPObject *plobj = NULL; + guint i; - g_array_append_vals (routes, routes1->data, routes1->len); - g_array_free (routes1, TRUE); + routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); + + 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, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex, + FALSE, + TRUE); + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (plobj); + + if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + continue; + g_assert (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)); + g_assert (r->ifindex == ifindex); + g_assert (nmp_object_is_visible (plobj)); + g_array_append_vals (routes, r, 1); + } + } return routes; } From 28340588d9cbca3eed1f75a9d10b6a0b19068004 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Sun, 2 Jul 2017 23:46:06 +0200 Subject: [PATCH 26/36] core: remove NMDedupMultiBox object and track NMDedupMultiObj instances directly Implement the reference counting of NMPObject as part of NMDedupMultiObj and get rid of NMDedupMultiBox. With this change, the NMPObject is aware in which NMDedupMultiIndex instance it is tracked. - this saves an additional GSlice allocation for the NMDedupMultiBox. - it is immediately known, whether an NMPObject is tracked by a certain NMDedupMultiIndex or not. This saves an additional hash lookup. - previously, when all idx-types cease to reference an NMDedupMultiObj instance, it was removed. Now, a tracked objects stays in the NMDedupMultiIndex until it's last reference is deleted. This possibly extends the lifetime of the object and we may reuse it better. - it is no longer possible to add one object to more then one NMDedupMultiIndex instance. As we anyway want to have only one instance to deduplicate the objects, this is fine. - the ref-counting implementation is now part of NMDedupMultiObj. Previously, NMDedupMultiIndex could also track objects that were not ref-counted. Hoever, the object anyway *must* implement the NMDedupMultiObj API, so this flexibility is unneeded and was not used. - a downside is, that NMPObject grows by one pointer size, even if it isn't tracked in the NMDedupMultiIndex. But we really want to put all objects into the index for sharing and deduplication. So this downside should be acceptable. Still, code like nmp_object_stackinit*() needs to handle a larger object. --- libnm-core/tests/test-general.c | 54 ++--- shared/nm-utils/nm-dedup-multi.c | 327 ++++++++++++++------------- shared/nm-utils/nm-dedup-multi.h | 42 ++-- src/nm-ip4-config.c | 18 +- src/platform/nm-linux-platform.c | 2 +- src/platform/nmp-object.c | 214 ++++++++---------- src/platform/nmp-object.h | 39 +++- src/platform/tests/test-nmp-object.c | 19 +- 8 files changed, 360 insertions(+), 355 deletions(-) diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index a897fe5a4e..db261adfec 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -78,7 +78,6 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int)); typedef struct { NMDedupMultiObj parent; - int ref_count; guint val; guint other; } DedupObj; @@ -93,39 +92,34 @@ _dedup_obj_assert (const NMDedupMultiObj *obj) g_assert (obj); o = (DedupObj *) obj; g_assert (o->parent.klass == &dedup_obj_class); - g_assert (o->ref_count > 0); + g_assert (o->parent._ref_count > 0); g_assert (o->val > 0); return o; } -static NMDedupMultiObj * -_dedup_obj_get_ref (const NMDedupMultiObj *obj) +static const NMDedupMultiObj * +_dedup_obj_clone (const NMDedupMultiObj *obj) { DedupObj *o, *o2; o = _dedup_obj_assert (obj); - if (o->ref_count == NM_OBJ_REF_COUNT_STACKINIT) { - o2 = g_slice_new0 (DedupObj); - o2->parent.klass = &dedup_obj_class; - o2->ref_count = 1; - o2->val = o->val; - o2->other = o->other; - return (NMDedupMultiObj *) o2; - } - - o->ref_count++; - return (NMDedupMultiObj *) o; + 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_put_ref (NMDedupMultiObj *obj) +_dedup_obj_destroy (NMDedupMultiObj *obj) { - DedupObj *o; + DedupObj *o = (DedupObj *) obj; + nm_assert (o->parent._ref_count == 0); + o->parent._ref_count = 1; o = _dedup_obj_assert (obj); - g_assert (o->ref_count != NM_OBJ_REF_COUNT_STACKINIT); - if (--o->ref_count == 0) - g_slice_free (DedupObj, o); + g_slice_free (DedupObj, o); } static guint @@ -149,8 +143,8 @@ _dedup_obj_full_equal (const NMDedupMultiObj *obj_a, } static const NMDedupMultiObjClass dedup_obj_class = { - .obj_get_ref = _dedup_obj_get_ref, - .obj_put_ref = _dedup_obj_put_ref, + .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, @@ -160,8 +154,8 @@ static const NMDedupMultiObjClass dedup_obj_class = { (&((DedupObj) { \ .parent = { \ .klass = &dedup_obj_class, \ + ._ref_count = NM_OBJ_REF_COUNT_STACKINIT, \ }, \ - .ref_count = NM_OBJ_REF_COUNT_STACKINIT, \ .val = (val_val), \ .other = (other_other), \ })) @@ -295,7 +289,7 @@ _dedup_entry_assert (const NMDedupMultiEntry *entry) g_assert (!entry->is_head); g_assert (entry->head != (gpointer) entry); _dedup_head_entry_assert (entry->head); - return _dedup_obj_assert (entry->box->obj); + return _dedup_obj_assert (entry->obj); } static const DedupIdxType * @@ -341,8 +335,8 @@ _dedup_entry_assert_all (const NMDedupMultiEntry *entry, gssize expected_idx, co if (expected_idx == i) g_assert (entry_current == entry); g_assert (idx_type->parent.klass->idx_obj_partition_equal (&idx_type->parent, - entry_current->box->obj, - c_list_entry (entry->head->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->box->obj)); + entry_current->obj, + c_list_entry (entry->head->lst_entries_head.next, NMDedupMultiEntry, lst_entries)->obj)); i++; } } @@ -361,14 +355,14 @@ test_dedup_multi (void) 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_box_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1))); - g_assert (!nm_dedup_multi_box_find (idx, (NMDedupMultiObj *) 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 (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_box_find (idx, (NMDedupMultiObj *) DEDUP_OBJ_INIT (1, 1))); - g_assert (nm_dedup_multi_box_find (idx, (NMDedupMultiObj *) 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)); diff --git a/shared/nm-utils/nm-dedup-multi.c b/shared/nm-utils/nm-dedup-multi.c index 6e949f9066..6a276ae4f1 100644 --- a/shared/nm-utils/nm-dedup-multi.c +++ b/shared/nm-utils/nm-dedup-multi.c @@ -25,11 +25,6 @@ /*****************************************************************************/ -typedef struct { - NMDedupMultiBox parent; - int ref_count; -} Box; - typedef struct { /* the stack-allocated lookup entry. It has a compatible * memory layout with NMDedupMultiEntry and NMDedupMultiHeadEntry. @@ -47,16 +42,11 @@ typedef struct { struct _NMDedupMultiIndex { int ref_count; GHashTable *idx_entries; - GHashTable *idx_box; + GHashTable *idx_objs; }; /*****************************************************************************/ -static void _box_unref (NMDedupMultiIndex *self, - Box *box); - -/*****************************************************************************/ - static void ASSERT_idx_type (const NMDedupMultiIdxType *idx_type) { @@ -142,7 +132,7 @@ _entry_unpack (const NMDedupMultiEntry *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, box) == G_STRUCT_OFFSET (NMDedupMultiHeadEntry, idx_type)); + 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) { @@ -154,11 +144,11 @@ _entry_unpack (const NMDedupMultiEntry *entry, } 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)->box->obj; + *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->box->obj; + *out_obj = entry->obj; *out_idx_type = entry->head->idx_type; *out_lookup_head = FALSE; } @@ -223,12 +213,11 @@ _add (NMDedupMultiIndex *self, NMDedupMultiIdxMode mode, const NMDedupMultiEntry *entry_order, NMDedupMultiHeadEntry *head_existing, - const NMDedupMultiBox *box_existing, const NMDedupMultiEntry **out_entry, - const NMDedupMultiBox **out_old_box) + const NMDedupMultiObj **out_obj_old) { NMDedupMultiHeadEntry *head_entry; - const NMDedupMultiBox *box, *box_new; + const NMDedupMultiObj *obj_new, *obj_old; gboolean add_head_entry = FALSE; nm_assert (self); @@ -239,7 +228,6 @@ _add (NMDedupMultiIndex *self, NM_DEDUP_MULTI_IDX_MODE_PREPEND_FORCE, NM_DEDUP_MULTI_IDX_MODE_APPEND, NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE)); - nm_assert (!box_existing || box_existing == nm_dedup_multi_box_find (self, obj)); nm_assert (!head_existing || head_existing->idx_type == idx_type); nm_assert (({ const NMDedupMultiHeadEntry *_h; @@ -299,27 +287,24 @@ _add (NMDedupMultiIndex *self, break; }; - if ( obj == entry->box->obj + if ( obj == entry->obj || obj->klass->obj_full_equal (obj, - entry->box->obj)) { + entry->obj)) { NM_SET_OUT (out_entry, entry); - NM_SET_OUT (out_old_box, nm_dedup_multi_box_ref (entry->box)); + NM_SET_OUT (out_obj_old, nm_dedup_multi_obj_ref (entry->obj)); return FALSE; } - if (box_existing) - box_new = nm_dedup_multi_box_ref (box_existing); - else - box_new = nm_dedup_multi_box_new (self, obj); + obj_new = nm_dedup_multi_index_obj_intern (self, obj); - box = entry->box; - entry->box = box_new; + obj_old = entry->obj; + entry->obj = obj_new; NM_SET_OUT (out_entry, entry); - if (out_old_box) - *out_old_box = box; + if (out_obj_old) + *out_obj_old = obj_old; else - _box_unref (self, (Box *) box); + nm_dedup_multi_obj_unref (obj_old); return TRUE; } @@ -328,18 +313,14 @@ _add (NMDedupMultiIndex *self, /* 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_old_box, NULL); + NM_SET_OUT (out_obj_old, NULL); return FALSE; } - if (box_existing) - box_new = nm_dedup_multi_box_ref (box_existing); - else - box_new = nm_dedup_multi_box_new (self, obj); - obj = box_new->obj; + obj_new = nm_dedup_multi_index_obj_intern (self, obj); if (!head_existing) - head_entry = _entry_lookup_head (self, idx_type, obj); + head_entry = _entry_lookup_head (self, idx_type, obj_new); else if (head_existing == NM_DEDUP_MULTI_HEAD_ENTRY_MISSING) head_entry = NULL; else @@ -363,7 +344,7 @@ _add (NMDedupMultiIndex *self, } entry = g_slice_new0 (NMDedupMultiEntry); - entry->box = box_new; + entry->obj = obj_new; entry->head = head_entry; switch (mode) { @@ -393,7 +374,7 @@ _add (NMDedupMultiIndex *self, nm_assert_not_reached (); NM_SET_OUT (out_entry, entry); - NM_SET_OUT (out_old_box, NULL); + NM_SET_OUT (out_obj_old, NULL); return TRUE; } @@ -403,7 +384,7 @@ nm_dedup_multi_index_add (NMDedupMultiIndex *self, /*const NMDedupMultiObj * */ gconstpointer obj, NMDedupMultiIdxMode mode, const NMDedupMultiEntry **out_entry, - const NMDedupMultiBox **out_old_box) + /* const NMDedupMultiObj ** */ gpointer out_obj_old) { NMDedupMultiEntry *entry; @@ -419,9 +400,9 @@ nm_dedup_multi_index_add (NMDedupMultiIndex *self, entry = _entry_lookup_obj (self, idx_type, obj); return _add (self, idx_type, obj, - entry, mode, NULL, + entry, mode, NULL, NULL, - out_entry, out_old_box); + out_entry, out_obj_old); } /* nm_dedup_multi_index_add_full: @@ -446,16 +427,13 @@ nm_dedup_multi_index_add (NMDedupMultiIndex *self, * @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 - * @box_existing: optional argument to safe the box lookup. If given, @obj and the boxed - * object must be identical, and @box_existing must be tracked by @self. This is to safe - * the additional lookup. * @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_old_box: if given, return the previously contained boxed object. It only - * returns a boxed object, if a matching entry was tracked previously, not if a - * new entry was created. Note that when passing @out_old_box you obtain a reference - * to the boxed object and MUST return it with nm_dedup_multi_box_unref(). + * @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. * @@ -469,9 +447,8 @@ nm_dedup_multi_index_add_full (NMDedupMultiIndex *self, const NMDedupMultiEntry *entry_order, const NMDedupMultiEntry *entry_existing, const NMDedupMultiHeadEntry *head_existing, - const NMDedupMultiBox *box_existing, const NMDedupMultiEntry **out_entry, - const NMDedupMultiBox **out_old_box) + /* const NMDedupMultiObj ** */ gpointer out_obj_old) { NMDedupMultiEntry *entry; @@ -498,8 +475,7 @@ nm_dedup_multi_index_add_full (NMDedupMultiIndex *self, entry, mode, entry_order, (NMDedupMultiHeadEntry *) head_existing, - box_existing, - out_entry, out_old_box); + out_entry, out_obj_old); } /*****************************************************************************/ @@ -509,19 +485,19 @@ _remove_entry (NMDedupMultiIndex *self, NMDedupMultiEntry *entry, gboolean *out_head_entry_removed) { - Box *box; + const NMDedupMultiObj *obj; NMDedupMultiHeadEntry *head_entry; NMDedupMultiIdxType *idx_type; nm_assert (self); nm_assert (entry); - nm_assert (entry->box); + 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; - box = (Box *) entry->box; + obj = entry->obj; nm_assert (head_entry); nm_assert (head_entry->len > 0); @@ -555,7 +531,7 @@ _remove_entry (NMDedupMultiIndex *self, g_slice_free (NMDedupMultiHeadEntry, head_entry); } - _box_unref (self, box); + nm_dedup_multi_obj_unref (obj); } static guint @@ -791,20 +767,16 @@ nm_dedup_multi_index_dirty_remove_idx (NMDedupMultiIndex *self, /*****************************************************************************/ static guint -_dict_idx_box_hash (const Box *box) +_dict_idx_objs_hash (const NMDedupMultiObj *obj) { - const NMDedupMultiObj *obj = box->parent.obj; - return obj->klass->obj_full_hash (obj); } static gboolean -_dict_idx_box_equal (const Box *box_a, - const Box *box_b) +_dict_idx_objs_equal (const NMDedupMultiObj *obj_a, + const NMDedupMultiObj *obj_b) { const NMDedupMultiObjClass *klass; - const NMDedupMultiObj *obj_a = box_a->parent.obj; - const NMDedupMultiObj *obj_b = box_b->parent.obj; klass = obj_a->klass; @@ -824,107 +796,141 @@ _dict_idx_box_equal (const Box *box_a, return klass->obj_full_equal (obj_a, obj_b); } -static void -_box_unref (NMDedupMultiIndex *self, - Box *box) +void +nm_dedup_multi_index_obj_release (NMDedupMultiIndex *self, + /* const NMDedupMultiObj * */ gconstpointer obj) { - nm_assert (box); - nm_assert (box->ref_count > 0); - nm_assert (g_hash_table_lookup (self->idx_box, box) == box); - - if (--box->ref_count > 0) - return; - - if (!g_hash_table_remove (self->idx_box, box)) - nm_assert_not_reached (); - - ((NMDedupMultiObj *) box->parent.obj)->klass->obj_put_ref ((NMDedupMultiObj *) box->parent.obj); - g_slice_free (Box, box); -} - -#define BOX_INIT(obj) \ - (&((const Box) { .parent = { .obj = obj, }, })) - -static Box * -_box_find (NMDedupMultiIndex *index, - /* const NMDedupMultiObj * */ gconstpointer obj) -{ - nm_assert (index); + 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); - return g_hash_table_lookup (index->idx_box, BOX_INIT (obj)); -} - -const NMDedupMultiBox * -nm_dedup_multi_box_find (NMDedupMultiIndex *index, - /* const NMDedupMultiObj * */ gconstpointer obj) -{ - g_return_val_if_fail (index, NULL); - g_return_val_if_fail (obj, NULL); - - return (NMDedupMultiBox *) _box_find (index, obj); -} - -const NMDedupMultiBox * -nm_dedup_multi_box_new (NMDedupMultiIndex *index, - /* const NMDedupMultiObj * */ gconstpointer obj) -{ - Box *box; - const NMDedupMultiObj *o; - - g_return_val_if_fail (index, NULL); - g_return_val_if_fail (obj, NULL); - - box = _box_find (index, obj); - if (box) { - box->ref_count++; - return (NMDedupMultiBox *) box; - } - - o = ((const NMDedupMultiObj *) obj)->klass->obj_get_ref (obj); - if (!o) - g_return_val_if_reached (NULL); - - box = g_slice_new (Box); - box->parent.obj = o; - box->ref_count = 1; - - nm_assert (_dict_idx_box_equal (box, BOX_INIT (obj))); - nm_assert (_dict_idx_box_equal (BOX_INIT (obj), box)); - nm_assert (_dict_idx_box_hash (BOX_INIT (obj)) == _dict_idx_box_hash (box)); - - if (!nm_g_hash_table_add (index->idx_box, box)) + ((NMDedupMultiObj *) obj)->_multi_idx = NULL; + if (!g_hash_table_remove (self->idx_objs, obj)) nm_assert_not_reached (); - - return &box->parent; } -const NMDedupMultiBox * -nm_dedup_multi_box_ref (const NMDedupMultiBox *box) -{ - Box *b; - - b = (Box *) box; - - g_return_val_if_fail (b, NULL); - g_return_val_if_fail (b->ref_count > 0, NULL); - - b->ref_count++; - return box; -} - -const NMDedupMultiBox * -nm_dedup_multi_box_unref (NMDedupMultiIndex *self, - const NMDedupMultiBox *box) +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 (box, NULL); - g_return_val_if_fail (((Box *) box)->ref_count > 0, 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); + } + } - _box_unref (self, (Box *) box); 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; +} + /*****************************************************************************/ NMDedupMultiIndex * @@ -935,7 +941,7 @@ nm_dedup_multi_index_new (void) 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_box = g_hash_table_new ((GHashFunc) _dict_idx_box_hash, (GEqualFunc) _dict_idx_box_equal); + self->idx_objs = g_hash_table_new ((GHashFunc) _dict_idx_objs_hash, (GEqualFunc) _dict_idx_objs_equal); return self; } @@ -955,6 +961,7 @@ 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); @@ -975,13 +982,15 @@ more: nm_assert (g_hash_table_size (self->idx_entries) == 0); - /* If callers took references to NMDedupMultiBox instances, they - * must keep NMDedupMultiIndex alive for as long as they keep - * the boxed reference. */ - nm_assert (g_hash_table_size (self->idx_box) == 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_box); + 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 index fc4283a808..090cc743a0 100644 --- a/shared/nm-utils/nm-dedup-multi.h +++ b/shared/nm-utils/nm-dedup-multi.h @@ -29,7 +29,6 @@ typedef struct _NMDedupMultiObj NMDedupMultiObj; typedef struct _NMDedupMultiObjClass NMDedupMultiObjClass; -typedef struct _NMDedupMultiBox NMDedupMultiBox; typedef struct _NMDedupMultiIdxType NMDedupMultiIdxType; typedef struct _NMDedupMultiIdxTypeClass NMDedupMultiIdxTypeClass; typedef struct _NMDedupMultiEntry NMDedupMultiEntry; @@ -57,16 +56,18 @@ struct _NMDedupMultiObj { NMObjBaseInst parent; const NMDedupMultiObjClass *klass; }; + NMDedupMultiIndex *_multi_idx; + guint _ref_count; }; struct _NMDedupMultiObjClass { NMObjBaseClass parent; - /* obj_get_ref() may just increase the ref-count, or it may allocate a new object. - * In any case, it returns ownership of an equal object to @obj. */ - NMDedupMultiObj *(*obj_get_ref) (const NMDedupMultiObj *obj); + const NMDedupMultiObj *(*obj_clone) (const NMDedupMultiObj *obj); - void (*obj_put_ref) (NMDedupMultiObj *obj); + gboolean (*obj_needs_clone) (const NMDedupMultiObj *obj); + + void (*obj_destroy) (NMDedupMultiObj *obj); gboolean obj_full_equality_allows_different_class; @@ -79,14 +80,19 @@ struct _NMDedupMultiObjClass { /*****************************************************************************/ -struct _NMDedupMultiBox { - gconstpointer obj; -}; +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); -const NMDedupMultiBox *nm_dedup_multi_box_new (NMDedupMultiIndex *index, /* const NMDedupMultiObj * */ gconstpointer obj); -const NMDedupMultiBox *nm_dedup_multi_box_find (NMDedupMultiIndex *index, /* const NMDedupMultiObj * */ gconstpointer obj); -const NMDedupMultiBox *nm_dedup_multi_box_ref (const NMDedupMultiBox *box); -const NMDedupMultiBox *nm_dedup_multi_box_unref (NMDedupMultiIndex *index, const NMDedupMultiBox *box); +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); /*****************************************************************************/ @@ -190,12 +196,7 @@ struct _NMDedupMultiEntry { * All entries compare equal according to idx_obj_partition_equal(). */ CList lst_entries; - /* the object instance. It is ref-counted and shared. - * Note that this instance must be immutable once it - * is added to the list. - * - * For head entries, @box is NULL and @head points to itself. */ - const NMDedupMultiBox *box; + /* const NMDedupMultiObj * */ gconstpointer obj; bool is_head; bool dirty; @@ -255,16 +256,15 @@ gboolean nm_dedup_multi_index_add_full (NMDedupMultiIndex *self, const NMDedupMultiEntry *entry_order, const NMDedupMultiEntry *entry_existing, const NMDedupMultiHeadEntry *head_existing, - const NMDedupMultiBox *box_existing, const NMDedupMultiEntry **out_entry, - const NMDedupMultiBox **out_old_box); + /* 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 NMDedupMultiBox **out_old_box); + /* const NMDedupMultiObj ** */ gpointer out_obj_old); const NMDedupMultiEntry *nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self, const NMDedupMultiIdxType *idx_type, diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index 50000e6275..eca46085ad 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -215,7 +215,7 @@ static const NMPlatformIP4Route * _entry_iter_get_ip4_route (const CList *iter) { const NMDedupMultiEntry *e = c_list_entry (iter, NMDedupMultiEntry, lst_entries); - const NMPObject *o = (NMPObject *) e->box->obj; + const NMPObject *o = e->obj; nm_assert (o); nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_TYPE_IP4_ROUTE); @@ -236,8 +236,8 @@ nm_ip4_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatfo has_next = nm_dedup_multi_iter_next (ipconf_iter); if (has_next) { - nm_assert (NMP_OBJECT_GET_TYPE (ipconf_iter->current->box->obj) == NMP_OBJECT_TYPE_IP4_ROUTE); - NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->box->obj)->ip4_route)); + 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; } @@ -1779,7 +1779,7 @@ _add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Rout { NMIP4ConfigPrivate *priv; NMPObject o_new_storage; - const NMDedupMultiBox *box_old; + nm_auto_nmpobj const NMPObject *obj_old = NULL; nm_assert (NM_IS_IP4_CONFIG (config)); @@ -1812,16 +1812,13 @@ _add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Rout o_new, NM_DEDUP_MULTI_IDX_MODE_APPEND, NULL, - &box_old)) { - if (box_old) - nm_dedup_multi_box_unref (priv->multi_idx, box_old); + &obj_old)) return; - } - if (box_old) { + if (obj_old) { NMIPConfigSource old_source; - old_source = ((const NMPObject *) box_old->obj)->ip_route.rt_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 @@ -1842,7 +1839,6 @@ _add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Rout NULL)) nm_assert_not_reached (); } - nm_dedup_multi_box_unref (priv->multi_idx, box_old); } _notify (config, PROP_ROUTE_DATA); diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 65dc6e0168..f4cd591771 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3295,7 +3295,7 @@ cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type) if (iter.current->dirty) { nm_auto_nmpobj const NMPObject *obj_old = NULL; - obj = iter.current->box->obj; + 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); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index e310d26363..dd3445e2f8 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -491,38 +491,6 @@ nmp_class_from_type (NMPObjectType obj_type) /*****************************************************************************/ -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->_ref_count != NM_OBJ_REF_COUNT_STACKINIT, NULL); - ((NMPObject *) obj)->_ref_count++; - - return obj; -} - -void -nmp_object_unref (const NMPObject *obj) -{ - if (obj) { - NMPObject *o = (NMPObject *) obj; - - g_return_if_fail (o->_ref_count > 0); - g_return_if_fail (o->_ref_count != NM_OBJ_REF_COUNT_STACKINIT); - if (--o->_ref_count <= 0) { - const NMPClass *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); - } - } -} - static void _vt_cmd_obj_dispose_link (NMPObject *obj) { @@ -551,7 +519,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; } @@ -587,7 +555,7 @@ _nmp_object_stackinit_from_class (NMPObject *obj, const NMPClass *klass) memset (obj, 0, sizeof (NMPObject)); obj->_class = klass; - obj->_ref_count = NM_OBJ_REF_COUNT_STACKINIT; + obj->parent._ref_count = NM_OBJ_REF_COUNT_STACKINIT; } static NMPObject * @@ -601,7 +569,7 @@ _nmp_object_stackinit_from_type (NMPObject *obj, NMPObjectType obj_type) memset (obj, 0, sizeof (NMPObject)); obj->_class = klass; - obj->_ref_count = NM_OBJ_REF_COUNT_STACKINIT; + obj->parent._ref_count = NM_OBJ_REF_COUNT_STACKINIT; return obj; } @@ -742,7 +710,7 @@ nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode case NMP_OBJECT_TO_STRING_ALL: g_snprintf (buf, buf_size, "[%s,%p,%u,%calive,%cvisible; %s]", - klass->obj_type_name, obj, obj->_ref_count, + 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))); @@ -768,7 +736,7 @@ _vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_strin case NMP_OBJECT_TO_STRING_ALL: g_snprintf (buf, buf_size, "[%s,%p,%u,%calive,%cvisible,%cin-nl,%p; %s]", - klass->obj_type_name, obj, obj->_ref_count, + 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 ? '+' : '-', @@ -808,7 +776,7 @@ _vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_s g_snprintf (buf, buf_size, "[%s,%p,%u,%calive,%cvisible; %s]", - klass->obj_type_name, obj, obj->_ref_count, + 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))); @@ -1339,22 +1307,25 @@ static const guint8 _supported_cache_ids_ipx_route[] = { /*****************************************************************************/ -static NMDedupMultiObj * -_vt_dedup_obj_get_ref (const NMDedupMultiObj *obj) +static void +_vt_dedup_obj_destroy (NMDedupMultiObj *obj) { NMPObject *o = (NMPObject *) obj; + const NMPClass *klass; - if (NMP_OBJECT_IS_STACKINIT (o)) { - return (NMDedupMultiObj *) nmp_object_new (NMP_OBJECT_GET_TYPE (o), - &o->object); - } - return (NMDedupMultiObj *) nmp_object_ref (o); + nm_assert (o->parent._ref_count == 0); + nm_assert (!o->parent._multi_idx); + + 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); } -static void -_vt_dedup_obj_put_ref (NMDedupMultiObj *obj) +static const NMDedupMultiObj * +_vt_dedup_obj_clone (const NMDedupMultiObj *obj) { - nmp_object_unref ((NMPObject *) obj); + return (const NMDedupMultiObj *) nmp_object_clone ((const NMPObject *) obj, FALSE); } static guint @@ -1373,8 +1344,8 @@ _vt_dedup_obj_full_equal (const NMDedupMultiObj *obj_a, #define DEDUP_MULTI_OBJ_CLASS_INIT() \ { \ - .obj_get_ref = _vt_dedup_obj_get_ref, \ - .obj_put_ref = _vt_dedup_obj_put_ref, \ + .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, \ } @@ -1512,12 +1483,18 @@ nmp_cache_link_connected_needs_toggle_by_ifindex (const NMPCache *cache, int mas static const NMDedupMultiEntry * _lookup_obj (const NMPCache *cache, const NMPObject *obj) { + const NMDedupMultiEntry *entry; + nm_assert (cache); nm_assert (NMP_OBJECT_IS_VALID (obj)); - return nm_dedup_multi_index_lookup_obj (cache->multi_idx, - _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE), - obj); + 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 * @@ -1529,7 +1506,7 @@ nmp_cache_lookup_obj (const NMPCache *cache, const NMPObject *obj) g_return_val_if_fail (obj, NULL); entry = _lookup_obj (cache, obj); - return entry ? entry->box->obj : NULL; + return entry ? entry->obj : NULL; } const NMDedupMultiEntry * @@ -1883,33 +1860,29 @@ nmp_cache_lookup_link_full (const NMPCache *cache, static void _idxcache_update_box_move (NMPCache *cache, NMPCacheIdType cache_id_type, - const NMDedupMultiBox *box_old, - const NMDedupMultiBox *box_new) + const NMPObject *obj_old, + const NMPObject *obj_new) { const NMDedupMultiEntry *entry_new; const NMDedupMultiEntry *entry_old; const NMDedupMultiEntry *entry_order; NMDedupMultiIdxType *idx_type; - const NMPObject *new, *old; - new = box_new ? box_new->obj : NULL; - old = box_old ? box_old->obj : NULL; - - nm_assert (new || old); - nm_assert (!new || NMP_OBJECT_GET_TYPE (new) != NMP_OBJECT_TYPE_UNKNOWN); - nm_assert (!old || NMP_OBJECT_GET_TYPE (old) != NMP_OBJECT_TYPE_UNKNOWN); - nm_assert (!old || !new || NMP_OBJECT_GET_CLASS (new) == NMP_OBJECT_GET_CLASS (old)); - nm_assert (!old || !new || !nmp_object_equal (new, old)); - nm_assert (!box_new || box_new == nm_dedup_multi_box_find (cache->multi_idx, new)); - nm_assert (!box_old || box_old == nm_dedup_multi_box_find (cache->multi_idx, old)); + 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 (old) { + if (obj_old) { entry_old = nm_dedup_multi_index_lookup_obj (cache->multi_idx, idx_type, - old); - if (!new) { + obj_old); + if (!obj_new) { if (entry_old) nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old); return; @@ -1917,34 +1890,33 @@ _idxcache_update_box_move (NMPCache *cache, } else entry_old = NULL; - if (new) { - if ( old - && nm_dedup_multi_idx_type_id_equal (idx_type, old, new) - && nm_dedup_multi_idx_type_partition_equal (idx_type, old, new)) { - /* optimize. We just looked up the @old entry and @new compares equal + 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 { entry_new = nm_dedup_multi_index_lookup_obj (cache->multi_idx, idx_type, - new); + obj_new); } if (entry_new) entry_order = entry_new; else if ( entry_old - && nm_dedup_multi_idx_type_partition_equal (idx_type, entry_old->box->obj, new)) + && 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, - new, + 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), - box_new, &entry_new, NULL); @@ -1952,8 +1924,8 @@ _idxcache_update_box_move (NMPCache *cache, 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->box->obj)); - nm_assert (idx_type->klass->idx_obj_partition_equal (idx_type, (gpointer) new, entry_new->box->obj)); + 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 @@ -1974,8 +1946,7 @@ _idxcache_update (NMPCache *cache, const guint8 *i_idx_type; NMDedupMultiIdxType *idx_type_o = _idx_type_get (cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE); const NMDedupMultiEntry *entry_new = NULL; - const NMDedupMultiBox *box_old; - const NMDedupMultiBox *box_old2 = NULL; + nm_auto_nmpobj const NMPObject *obj_old = NULL; /* we update an object in the cache. * @@ -1985,22 +1956,23 @@ _idxcache_update (NMPCache *cache, 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->box->obj)); + 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->box->obj, 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->box->obj, 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->box->obj)->parent.klass - && !obj_new->parent.klass->obj_full_equal ((NMDedupMultiObj *) obj_new, entry_old->box->obj))); + || ( 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 boxed reference to the pre-existing entry */ - box_old = entry_old ? nm_dedup_multi_box_ref (entry_old->box) : NULL; + /* 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 @@ -2009,6 +1981,8 @@ _idxcache_update (NMPCache *cache, * * 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, @@ -2016,34 +1990,28 @@ _idxcache_update (NMPCache *cache, NULL, entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING, NULL, - NULL, &entry_new, - &box_old2); + (const NMDedupMultiObj **) &obj_old2); nm_assert (entry_new); - nm_assert (box_old == box_old2); + nm_assert (obj_old == obj_old2); nm_assert (!entry_old || entry_old == entry_new); - if (box_old2) - nm_dedup_multi_box_unref (cache->multi_idx, box_old2); } else nm_dedup_multi_index_remove_entry (cache->multi_idx, entry_old); /* 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->box->obj : box_old->obj); + 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; _idxcache_update_box_move (cache, id_type, - box_old, - entry_new ? entry_new->box : NULL); + obj_old, + entry_new ? entry_new->obj : NULL); } NM_SET_OUT (out_entry_new, entry_new); - - if (box_old) - nm_dedup_multi_box_unref (cache->multi_idx, box_old); } NMPCacheOpsType @@ -2062,7 +2030,7 @@ nmp_cache_remove (NMPCache *cache, return NMP_CACHE_OPS_UNCHANGED; } - obj_old = entry_old->box->obj; + obj_old = entry_old->obj; NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old)); @@ -2095,7 +2063,7 @@ nmp_cache_remove_netlink (NMPCache *cache, return NMP_CACHE_OPS_UNCHANGED; } - obj_old = entry_old->box->obj; + 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 @@ -2128,7 +2096,7 @@ nmp_cache_remove_netlink (NMPCache *cache, entry_old, obj_new, &entry_new); - NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj)); + NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); return NMP_CACHE_OPS_UPDATED; } @@ -2182,10 +2150,7 @@ nmp_cache_update_netlink (NMPCache *cache, 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 (({ - const NMDedupMultiBox *_b = nm_dedup_multi_box_find (cache->multi_idx, obj_hand_over); - !_b || obj_hand_over != _b->obj; - })); + nm_assert (nm_dedup_multi_index_obj_find (cache->multi_idx, obj_hand_over) != obj_hand_over); entry_old = _lookup_obj (cache, obj_hand_over); @@ -2207,11 +2172,11 @@ nmp_cache_update_netlink (NMPCache *cache, entry_old, obj_hand_over, &entry_new); - NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj)); + NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); return NMP_CACHE_OPS_ADDED; } - obj_old = entry_old->box->obj; + obj_old = entry_old->obj; if (NMP_OBJECT_GET_TYPE (obj_hand_over) == NMP_OBJECT_TYPE_LINK) { if (!obj_hand_over->_link.netlink.is_in_netlink) { @@ -2244,6 +2209,13 @@ nmp_cache_update_netlink (NMPCache *cache, 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); @@ -2267,7 +2239,7 @@ nmp_cache_update_netlink (NMPCache *cache, entry_old, obj_hand_over, &entry_new); - NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj)); + NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); return NMP_CACHE_OPS_UPDATED; } @@ -2303,10 +2275,10 @@ nmp_cache_update_link_udev (NMPCache *cache, obj_new, &entry_new); NM_SET_OUT (out_obj_old, NULL); - NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj)); + NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); return NMP_CACHE_OPS_ADDED; } else { - obj_old = entry_old->box->obj; + obj_old = entry_old->obj; NM_SET_OUT (out_obj_old, nmp_object_ref (obj_old)); if (obj_old->_link.udev.device == udevice) { @@ -2332,7 +2304,7 @@ nmp_cache_update_link_udev (NMPCache *cache, entry_old, obj_new, &entry_new); - NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj)); + NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); return NMP_CACHE_OPS_UPDATED; } } @@ -2356,7 +2328,7 @@ nmp_cache_update_link_master_connected (NMPCache *cache, return NMP_CACHE_OPS_UNCHANGED; } - obj_old = entry_old->box->obj; + 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)); @@ -2372,7 +2344,7 @@ nmp_cache_update_link_master_connected (NMPCache *cache, entry_old, obj_new, &entry_new); - NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->box->obj)); + NM_SET_OUT (out_obj_new, nmp_object_ref (entry_new->obj)); return NMP_CACHE_OPS_UPDATED; } @@ -2542,6 +2514,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2552,6 +2525,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2562,6 +2536,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2572,6 +2547,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2582,6 +2558,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2592,6 +2569,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2602,6 +2580,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2612,6 +2591,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2622,6 +2602,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), @@ -2637,6 +2618,7 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = { .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), diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 6c0098bfce..5574e0b3b6 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -144,7 +144,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 { @@ -232,7 +232,6 @@ struct _NMPObject { NMDedupMultiObj parent; const NMPClass *_class; }; - guint _ref_count; union { NMPlatformObject object; @@ -298,7 +297,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))) @@ -307,7 +306,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 @@ -320,7 +319,7 @@ NMP_OBJECT_IS_STACKINIT (const NMPObject *obj) { nm_assert (!obj || NMP_OBJECT_IS_VALID (obj)); - return obj && obj->_ref_count == NM_OBJ_REF_COUNT_STACKINIT; + return obj && obj->parent._ref_count == NM_OBJ_REF_COUNT_STACKINIT; } static inline const NMPClass * @@ -377,8 +376,26 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) const NMPClass *nmp_class_from_type (NMPObjectType obj_type); -const NMPObject *nmp_object_ref (const NMPObject *object); -void nmp_object_unref (const 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); @@ -470,8 +487,8 @@ nmp_cache_iter_next (NMDedupMultiIter *iter, const NMPObject **out_obj) has_next = nm_dedup_multi_iter_next (iter); if (has_next) { - nm_assert (NMP_OBJECT_IS_VALID (iter->current->box->obj)); - NM_SET_OUT (out_obj, iter->current->box->obj); + nm_assert (NMP_OBJECT_IS_VALID (iter->current->obj)); + NM_SET_OUT (out_obj, iter->current->obj); } return has_next; } @@ -483,8 +500,8 @@ nmp_cache_iter_next_link (NMDedupMultiIter *iter, const NMPlatformLink **out_obj has_next = nm_dedup_multi_iter_next (iter); if (has_next) { - nm_assert (NMP_OBJECT_GET_TYPE (iter->current->box->obj) == NMP_OBJECT_TYPE_LINK); - NM_SET_OUT (out_obj, &(((const NMPObject *) iter->current->box->obj)->link)); + 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; } diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index 24e790c32c..40d876a65b 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -36,10 +36,18 @@ struct { static void test_obj_base (void) { - static const GObject *g = NULL; - static const GTypeClass *k = NULL; - static const NMPObject *o = NULL; - static const NMPClass *c = NULL; + 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 (); @@ -54,9 +62,8 @@ test_obj_base (void) STATIC_ASSERT (&g->g_type_instance == (void *) &o->_class); STATIC_ASSERT (&g->g_type_instance.g_class == (void *) &o->_class); - STATIC_ASSERT (&g->ref_count == (void *) &o->_ref_count); - STATIC_ASSERT (sizeof (o->parent) == sizeof (GTypeInstance)); + STATIC_ASSERT (sizeof (o->parent.parent) == sizeof (GTypeInstance)); STATIC_ASSERT (&c->parent == (void *) c); STATIC_ASSERT (&c->parent.parent.g_type_class == (void *) c); From cfd1851c0067773211524c2b648330b6ee7a066c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 3 Jul 2017 17:03:54 +0200 Subject: [PATCH 27/36] core: refactor NMIP6Config to use dedup-index for IPv6 routes --- src/dns/nm-dns-dnsmasq.c | 9 +- src/nm-dispatcher.c | 5 +- src/nm-ip4-config.c | 27 ++- src/nm-ip4-config.h | 5 + src/nm-ip6-config.c | 464 +++++++++++++++++++++++------------- src/nm-ip6-config.h | 18 +- src/nm-pacrunner-manager.c | 8 +- src/tests/test-ip6-config.c | 12 +- src/vpn/nm-vpn-connection.c | 16 +- 9 files changed, 363 insertions(+), 201 deletions(-) diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index 730134b5e1..d5b51af25e 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -111,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); @@ -123,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-dispatcher.c b/src/nm-dispatcher.c index 6bea925488..2393e8035f 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -182,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; @@ -230,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-ip4-config.c b/src/nm-ip4-config.c index eca46085ad..d5df277b14 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -46,14 +46,22 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF); /*****************************************************************************/ -static gboolean -_idx_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a, - const NMPlatformIP4Route *r_b) +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) @@ -68,10 +76,13 @@ _idx_obj_id_hash (const NMDedupMultiIdxType *idx_type, case NMP_OBJECT_TYPE_IP4_ROUTE: h = 40303327; h = NM_HASH_COMBINE (h, o->ip4_route.network); - h = NM_HASH_COMBINE (h, o->ip4_route.plen); + h = NM_HASH_COMBINE (h, o->ip_route.plen); break; case NMP_OBJECT_TYPE_IP6_ROUTE: - g_return_val_if_reached (0); + 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); }; @@ -94,9 +105,9 @@ _idx_obj_id_equal (const NMDedupMultiIdxType *idx_type, case NMP_OBJECT_TYPE_IP6_ADDRESS: g_return_val_if_reached (FALSE); case NMP_OBJECT_TYPE_IP4_ROUTE: - return _idx_obj_id_equal_ip4_route (&o_a->ip4_route, &o_b->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: - g_return_val_if_reached (FALSE); + return nm_ip_config_obj_id_equal_ip6_route (&o_a->ip6_route, &o_b->ip6_route); default: g_return_val_if_reached (FALSE); }; @@ -1300,7 +1311,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev if (nm_platform_ip4_route_cmp (r_src, r_dst) != 0) { are_equal = FALSE; - if (!_idx_obj_id_equal_ip4_route (r_src, r_dst)) { + if (!nm_ip_config_obj_id_equal_ip4_route (r_src, r_dst)) { has_relevant_changes = TRUE; break; } diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h index f1f2979232..7049f9e5f3 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -43,6 +43,11 @@ gboolean nm_ip4_config_iter_ip4_route_next (NMDedupMultiIter *iter, const NMPlat 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 ()) diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 7724ad4831..0dc7adcad2 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -29,11 +29,13 @@ #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" @@ -48,7 +50,6 @@ typedef struct { gint64 route_metric; struct in6_addr gateway; GArray *addresses; - GArray *routes; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; @@ -56,6 +57,7 @@ typedef struct { GVariant *address_data_variant; GVariant *addresses_variant; NMDedupMultiIndex *multi_idx; + NMDedupMultiIdxType idx_ip6_routes; } NMIP6ConfigPrivate; struct _NMIP6Config { @@ -88,6 +90,10 @@ 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) { @@ -110,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) { @@ -193,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) { @@ -315,10 +355,12 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i { 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 */ @@ -329,47 +371,56 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i 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, + TRUE, + TRUE); /* Extract gateway from default route */ old_gateway = priv->gateway; - for (i = 0; i < priv->routes->len; ) { - const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i); - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) { + lowest_metric = G_MAXUINT32; + has_gateway = FALSE; + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj); + + if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route) + && route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) { if (route->metric < lowest_metric) { priv->gateway = route->gateway; lowest_metric = route->metric; } has_gateway = TRUE; - /* Remove the default route from the list */ - g_array_remove_index_fast (priv->routes, i); - continue; } - i++; } /* we detect the route metric based on the default route. All non-default * routes have their route metrics explicitly set. */ priv->route_metric = has_gateway ? (gint64) lowest_metric : (gint64) -1; - /* If there is a host route to the gateway, ignore that route. It is - * automatically added by NetworkManager when needed. - */ - if (has_gateway) { - for (i = 0; i < priv->routes->len; i++) { - const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i); + nm_dedup_multi_iter_rewind (&iter); + nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj); - if ( route->plen == 128 - && IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway) - && IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) { - g_array_remove_index (priv->routes, i); - i--; - } + if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) + continue; + if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) + continue; + + if ( has_gateway + && route->plen == 128 + && IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway) + && IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) { + /* If there is a host route to the gateway, ignore that route. It is + * automatically added by NetworkManager when needed. + */ + continue; } + _add_route (config, plobj, NULL); } /* If the interface has the default route, and has IPv6 addresses, capture @@ -403,7 +454,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); @@ -413,21 +463,24 @@ nm_ip6_config_commit (const NMIP6Config *config, /* Routes */ { - guint i; - guint count = nm_ip6_config_get_num_routes (config); - GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), count); - const NMPlatformIP6Route *route; + const NMDedupMultiHeadEntry *head_entry; + gs_unref_array GArray *routes = NULL; + const CList *iter; - for (i = 0; i < count; i++) { - route = nm_ip6_config_get_route (config, i); - g_array_append_vals (routes, route, 1); + head_entry = _idx_ip6_routes (config); + + routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), head_entry ? head_entry->len : 0); + + if (head_entry) { + c_list_for_each (iter, &head_entry->lst_entries_head) + g_array_append_vals (routes, _entry_iter_get_ip6_route (iter), 1); } - success = nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync); - g_array_unref (routes); + if (!nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync)) + return FALSE; } - return success; + return TRUE; } static void @@ -558,7 +611,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 */ @@ -594,10 +647,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 ()); @@ -610,7 +665,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); @@ -661,8 +715,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. */ @@ -718,6 +771,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); @@ -743,8 +797,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) @@ -833,21 +889,6 @@ _nameservers_get_index (const NMIP6Config *self, const struct in6_addr *ns) return -1; } -static int -_routes_get_index (const NMIP6Config *self, const NMPlatformIP6Route *route) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); - guint i; - - for (i = 0; i < priv->routes->len; i++) { - const NMPlatformIP6Route *r = &g_array_index (priv->routes, NMPlatformIP6Route, i); - - if (routes_are_duplicate (route, r, FALSE)) - return (int) i; - } - return -1; -} - static int _domains_get_index (const NMIP6Config *self, const char *domain) { @@ -905,13 +946,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 */ @@ -940,10 +986,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 */ @@ -980,12 +1026,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)); @@ -1012,12 +1065,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 */ @@ -1052,7 +1108,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); @@ -1117,26 +1173,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 */ @@ -1252,6 +1327,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); @@ -1277,8 +1354,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++) @@ -1524,13 +1601,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 @@ -1544,76 +1692,70 @@ nm_ip6_config_reset_routes (NMIP6Config *config) void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - NMIPConfigSource old_source; - int i; - - g_return_if_fail (new != NULL); + g_return_if_fail (config); + g_return_if_fail (new); g_return_if_fail (new->plen > 0 && new->plen <= 128); - g_return_if_fail (priv->ifindex > 0); + g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex > 0); - for (i = 0; i < priv->routes->len; i++ ) { - NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i); - - if (routes_are_duplicate (item, new, FALSE)) { - if (nm_platform_ip6_route_cmp (item, new) == 0) - return; - old_source = item->rt_source; - *item = *new; - /* Restore highest priority source */ - item->rt_source = MAX (old_source, new->rt_source); - item->ifindex = priv->ifindex; - goto NOTIFY; - } - } - - g_array_append_val (priv->routes, *new); - g_array_index (priv->routes, NMPlatformIP6Route, priv->routes->len - 1).ifindex = priv->ifindex; -NOTIFY: - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); + _add_route (config, NULL, new); } void -nm_ip6_config_del_route (NMIP6Config *config, guint i) +_nmtst_ip6_config_del_route (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + const NMPlatformIP6Route *r; - g_return_if_fail (i < priv->routes->len); + r = _nmtst_ip6_config_get_route (self, i); + g_return_if_fail (r); - g_array_remove_index (priv->routes, i); - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); + if (nm_dedup_multi_index_remove_obj (priv->multi_idx, + &priv->idx_ip6_routes, + NMP_OBJECT_UP_CAST (r)) != 1) + g_return_if_reached (); + _notify (self, PROP_ROUTE_DATA); + _notify (self, PROP_ROUTES); } guint -nm_ip6_config_get_num_routes (const NMIP6Config *config) +nm_ip6_config_get_num_routes (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMDedupMultiHeadEntry *head_entry; - return priv->routes->len; + head_entry = _idx_ip6_routes (self); + nm_assert ((head_entry ? head_entry->len : 0) == c_list_length (&head_entry->lst_entries_head)); + return head_entry ? head_entry->len : 0; } const NMPlatformIP6Route * -nm_ip6_config_get_route (const NMIP6Config *config, guint i) +_nmtst_ip6_config_get_route (const NMIP6Config *self, guint i) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMDedupMultiHeadEntry *head_entry; + CList *iter; + guint j; - return &g_array_index (priv->routes, NMPlatformIP6Route, i); + head_entry = _idx_ip6_routes (self); + if (head_entry) { + j = 0; + c_list_for_each (iter, &head_entry->lst_entries_head) { + if (i == j) + return _entry_iter_get_ip6_route (iter); + j++; + } + } + g_return_val_if_reached (NULL); } const NMPlatformIP6Route * -nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct in6_addr *host) +nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct in6_addr *host) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - guint i; - NMPlatformIP6Route *best_route = NULL; + const NMPlatformIP6Route *best_route = NULL; + const NMPlatformIP6Route *item; + NMDedupMultiIter ipconf_iter; g_return_val_if_fail (host && !IN6_IS_ADDR_UNSPECIFIED (host), NULL); - for (i = 0; i < priv->routes->len; i++) { - NMPlatformIP6Route *item = &g_array_index (priv->routes, NMPlatformIP6Route, i); - + nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, self, &item) { if (!IN6_IS_ADDR_UNSPECIFIED (&item->gateway)) continue; @@ -1629,7 +1771,6 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *config, const struct best_route = item; } - return best_route; } @@ -1963,6 +2104,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); @@ -1977,9 +2120,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); @@ -2074,6 +2215,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: @@ -2082,7 +2226,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; @@ -2144,14 +2287,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", @@ -2177,14 +2314,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)) @@ -2263,8 +2394,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); @@ -2301,8 +2434,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); diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index 5dadf796f6..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)) @@ -101,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-pacrunner-manager.c b/src/nm-pacrunner-manager.c index a4c345e5d7..d9095cce5b 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -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/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index bbb3278bc9..0887e9da98 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -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); @@ -207,27 +207,27 @@ test_add_route_with_source (void) 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); diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index 7c8f06ced6..ab6103d497 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -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, @@ -1578,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)); @@ -1669,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; From aeaa1b3b98d0728d9b220a8d16eaa017a2bfa8b4 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Jul 2017 09:57:06 +0200 Subject: [PATCH 28/36] platform: refactor nm_dedup_multi_objs_to_ptr_array_head() by moving the core functionality to "nm-dedup-multi.c". As the ref-counting mechanism now is part of "nm-dedup-multi.c", this works better and is reusable outside of platform. --- shared/nm-utils/nm-dedup-multi.c | 28 ++++++++++++++++++++++++++++ shared/nm-utils/nm-dedup-multi.h | 14 ++++++++++++++ src/platform/nm-platform.c | 26 +++----------------------- 3 files changed, 45 insertions(+), 23 deletions(-) diff --git a/shared/nm-utils/nm-dedup-multi.c b/shared/nm-utils/nm-dedup-multi.c index 6a276ae4f1..92dba89936 100644 --- a/shared/nm-utils/nm-dedup-multi.c +++ b/shared/nm-utils/nm-dedup-multi.c @@ -931,6 +931,34 @@ nm_dedup_multi_obj_clone (const NMDedupMultiObj *obj) 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 * diff --git a/shared/nm-utils/nm-dedup-multi.h b/shared/nm-utils/nm-dedup-multi.h index 090cc743a0..77a2fd122d 100644 --- a/shared/nm-utils/nm-dedup-multi.h +++ b/shared/nm-utils/nm-dedup-multi.h @@ -360,6 +360,20 @@ nm_dedup_multi_iter_rewind (NMDedupMultiIter *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/src/platform/nm-platform.c b/src/platform/nm-platform.c index c8008216b2..de5ac3cf40 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2692,29 +2692,9 @@ nm_platform_lookup_clone (NMPlatform *platform, gboolean (*predicate) (const NMPObject *obj, gpointer user_data), gpointer user_data) { - const NMDedupMultiHeadEntry *head_entry; - GPtrArray *result; - NMDedupMultiIter iter; - const NMPObject *plobj = NULL; - - head_entry = nm_platform_lookup (platform, lookup); - if (!head_entry) - return NULL; - - result = g_ptr_array_new_full (head_entry->len, - (GDestroyNotify) nmp_object_unref); - nmp_cache_iter_for_each (&iter, head_entry, &plobj) { - if ( predicate - && !predicate (plobj, user_data)) - continue; - g_ptr_array_add (result, (gpointer) nmp_object_ref (plobj)); - } - - if (result->len == 0) { - g_ptr_array_unref (result); - return NULL; - } - return result; + return nm_dedup_multi_objs_to_ptr_array_head (nm_platform_lookup (platform, lookup), + (NMDedupMultiFcnSelectPredicate) predicate, + user_data); } void From 35f52aafc1331ee51ca16dec9a10bf8dbc62d136 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Jul 2017 10:40:52 +0200 Subject: [PATCH 29/36] platform: drop nm_platform_ip6_route_get_all() We no longer need a full clone of routes. The only remaining uses are in test code. Rework it. --- src/platform/nm-platform.c | 50 --------------------------------- src/platform/nm-platform.h | 13 --------- src/platform/tests/test-route.c | 10 +++---- src/tests/test-route-manager.c | 49 +++++++++++++------------------- 4 files changed, 23 insertions(+), 99 deletions(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index de5ac3cf40..912f498437 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -3198,56 +3198,6 @@ nm_platform_address_flush (NMPlatform *self, int ifindex) /*****************************************************************************/ -static GArray * -ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags) -{ - NMDedupMultiIter iter; - NMPLookup lookup; - const NMDedupMultiHeadEntry *head_entry; - GArray *array; - const NMPClass *klass; - const NMPObject *o; - gboolean with_rtprot_kernel; - - 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); - - head_entry = nmp_cache_lookup (nm_platform_get_cache (platform), - nmp_lookup_init_route_visible (&lookup, - obj_type, - ifindex, - NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT), - NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))); - - array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, head_entry ? head_entry->len : 0); - - with_rtprot_kernel = NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); - - nmp_cache_iter_for_each (&iter, - head_entry, - &o) { - nm_assert (NMP_OBJECT_GET_CLASS (o) == klass); - if ( with_rtprot_kernel - || o->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) - g_array_append_vals (array, &o->ip_route, 1); - } - return array; -} - -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 ipx_route_get_all (self, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags); -} - /** * nm_platform_ip4_route_add: * @self: diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index f4c499787e..4074fb8a49 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -173,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; @@ -980,7 +968,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_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); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index f4ac2a6e6c..3fe0f3128a 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -450,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] = { }; @@ -519,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: @@ -533,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/tests/test-route-manager.c b/src/tests/test-route-manager.c index f647cc7494..275d898641 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -143,15 +143,20 @@ update_dev0_ip4 (int ifindex) static GArray * -ip4_routes (test_fixture *fixture) +ip_routes (test_fixture *fixture, NMPObjectType obj_type) { + const NMPClass *klass; GArray *routes; const NMDedupMultiHeadEntry *pl_head_entry; NMDedupMultiIter iter; const NMPObject *plobj = NULL; guint i; - routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); + 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; @@ -162,12 +167,12 @@ ip4_routes (test_fixture *fixture) ifindex = fixture->ifindex1; pl_head_entry = nm_platform_lookup_route_visible (NM_PLATFORM_GET, - NMP_OBJECT_TYPE_IP4_ROUTE, + obj_type, ifindex, FALSE, TRUE); nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { - const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (plobj); + const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj); if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) continue; @@ -346,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); @@ -357,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; @@ -367,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); @@ -379,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); @@ -387,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); } @@ -544,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) { @@ -762,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); @@ -773,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); @@ -781,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); @@ -793,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); @@ -801,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); } From beb0b9b1ad98014bb83617513ba3dea25d6431f1 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Jul 2017 10:55:19 +0200 Subject: [PATCH 30/36] platform: reduce number of route indexes Maintaining an index is expensive.Not so much in term of runtime, but in term of memory. Drop some indexes, and require the caller to use a more broad index (and filter out unwanted elements). Dropped: - can no longer lookup visible default-routes by ifindex. If you care about default-routes, lookup all and search for the desired ifindex. The overall number of default-routes is expected to be small. We drop NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT entirely. - no longer have a separate index for non-default routes. We expect that the most routes are non-default routes. So, don't have an index without default-routes, instead let the caller just lookup all routes, and reject default-routes themself. We keep NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT, but it now no longer tracks non-default routes. This drops 1 out of 6 route indexes, and modifes another one, so that we expect that there are almost no entires tracked by it. --- src/devices/nm-device.c | 7 ++-- src/nm-default-route-manager.c | 2 -- src/nm-ip4-config.c | 3 +- src/nm-ip6-config.c | 3 +- src/nm-route-manager.c | 17 +++++---- src/platform/nmp-object.c | 60 ++++++++++---------------------- src/platform/nmp-object.h | 22 +++++------- src/platform/tests/test-common.h | 6 ++-- src/tests/test-route-manager.c | 6 ++-- 9 files changed, 48 insertions(+), 78 deletions(-) diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index db59171b02..4bf34cd5b2 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -5417,13 +5417,14 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat addr_family == AF_INET ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex, - TRUE, - FALSE); + 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; diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index fb61ef751c..f0dc75cfd1 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -336,7 +336,6 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, vtable->vt->obj_type, 0, TRUE, - FALSE, nm_platform_lookup_predicate_routes_skip_rtprot_kernel, NULL); if (!routes) @@ -520,7 +519,6 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c vtable->vt->obj_type, 0, TRUE, - FALSE, nm_platform_lookup_predicate_routes_skip_rtprot_kernel, NULL); diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c index d5df277b14..1ec3115d4e 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -419,8 +419,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i pl_head_entry = nm_platform_lookup_route_visible (platform, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, - TRUE, - TRUE); + FALSE); /* Extract gateway from default route */ old_gateway = priv->gateway; diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index 0dc7adcad2..dde62e9501 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -377,8 +377,7 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i pl_head_entry = nm_platform_lookup_route_visible (platform, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, - TRUE, - TRUE); + FALSE); /* Extract gateway from default route */ old_gateway = priv->gateway; diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 574493d990..8372d65234 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -314,7 +314,7 @@ _route_index_create_from_platform (const VTableIP *vtable, GPtrArray **out_storage) { RouteIndex *index; - guint i, len; + guint i, j, len; GPtrArray *storage; nm_assert (out_storage && !*out_storage); @@ -323,7 +323,6 @@ _route_index_create_from_platform (const VTableIP *vtable, vtable->vt->obj_type, ifindex, FALSE, - TRUE, NULL, NULL); if (!storage) @@ -332,17 +331,23 @@ _route_index_create_from_platform (const VTableIP *vtable, len = storage->len; index = g_malloc (sizeof (RouteIndex) + len * sizeof (NMPlatformIPXRoute *)); - index->len = len; + j = 0; for (i = 0; i < len; i++) { + const NMPlatformIPXRoute *ipx_route = NMP_OBJECT_CAST_IPX_ROUTE ((NMPObject *) 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[i] = NMP_OBJECT_CAST_IPX_ROUTE ((NMPObject *) storage->pdata[i]); + index->entries[j++] = (NMPlatformIPXRoute *) ipx_route; } - index->entries[i] = NULL; + 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, - len, + index->len, sizeof (NMPlatformIPXRoute *), (GCompareDataFunc) _route_index_create_sort, (gpointer) vtable); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index dd3445e2f8..ac5ee20e1d 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -194,17 +194,17 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT: 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_a->ip_route) == NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_b->ip_route) + && 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)); - h = NM_HASH_COMBINE (h, NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_a->ip_route)); return _HASH_NON_ZERO (h); } return 1; @@ -230,26 +230,6 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, } return 1; - case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT: - if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) - || obj_a->object.ifindex <= 0 - || !nmp_object_is_visible (obj_a)) - return 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 - && NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_a->ip_route) == 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)); - h = NM_HASH_COMBINE (h, NM_PLATFORM_IP_ROUTE_IS_DEFAULT (&obj_a->ip_route)); - 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, @@ -1300,7 +1280,6 @@ static const guint8 _supported_cache_ids_ipx_route[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY, NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX, NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT, - NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT, NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION, 0, }; @@ -1654,8 +1633,7 @@ const NMPLookup * nmp_lookup_init_route_visible (NMPLookup *lookup, NMPObjectType obj_type, int ifindex, - gboolean with_default, - gboolean with_non_default) + gboolean only_default) { NMPObject *o; @@ -1663,24 +1641,22 @@ nmp_lookup_init_route_visible (NMPLookup *lookup, nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); - if (with_default) { - if (with_non_default) { - return nmp_lookup_init_addrroute (lookup, - obj_type, - ifindex, - TRUE); - } - } else if (!with_non_default) - g_return_val_if_reached (NULL); - o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); - o->ip_route.plen = with_default ? 0 : 1; - if (ifindex <= 0) { - o->object.ifindex = 1; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT; - } else { - o->object.ifindex = ifindex; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT; + if (!only_default) { + return nmp_lookup_init_addrroute (lookup, + obj_type, + ifindex, + TRUE); } + + 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_ROUTES_VISIBLE_BY_DEFAULT; return _L (lookup); } diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 5574e0b3b6..1cff049555 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -75,17 +75,14 @@ typedef enum { /*< skip >*/ /* all the visible objects of a certain type */ NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY, - /* indeces for the visible routes, ignoring ifindex. - * The index separates default routes from non-default routes. */ + /* 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_ROUTES_VISIBLE_BY_DEFAULT, /* all the visible addresses/routes (by object-type) for an ifindex. */ NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX, - /* indeces for the visible routes, per ifindex. - * The index separates default routes from non-default routes. */ - NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_IFINDEX_WITH_DEFAULT, - /* Consider all the destination fields of a route, that is, the ID without the ifindex * and gateway (meaning: network/plen,metric). * The reason for this is that `ip route change` can replace an existing route @@ -469,8 +466,7 @@ const NMPLookup *nmp_lookup_init_addrroute (NMPLookup *lookup, const NMPLookup *nmp_lookup_init_route_visible (NMPLookup *lookup, NMPObjectType obj_type, int ifindex, - gboolean with_default, - gboolean with_non_default); + gboolean only_default); const NMPLookup *nmp_lookup_init_route_by_dest (NMPLookup *lookup, int addr_family, gconstpointer network, @@ -649,12 +645,11 @@ static inline const NMDedupMultiHeadEntry * nm_platform_lookup_route_visible (NMPlatform *platform, NMPObjectType obj_type, int ifindex, - gboolean with_default, - gboolean with_non_default) + gboolean only_default) { NMPLookup lookup; - nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, with_default, with_non_default); + nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, only_default); return nm_platform_lookup (platform, &lookup); } @@ -662,14 +657,13 @@ static inline GPtrArray * nm_platform_lookup_route_visible_clone (NMPlatform *platform, NMPObjectType obj_type, int ifindex, - gboolean with_default, - gboolean with_non_default, + 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, with_default, with_non_default); + nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, only_default); return nm_platform_lookup_clone (platform, &lookup, predicate, user_data); } diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index e047705fd3..b9e879ff62 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -195,8 +195,7 @@ nmtstp_ip4_route_get_all (NMPlatform *platform, return nm_platform_lookup_route_visible_clone (platform, NMP_OBJECT_TYPE_IP4_ROUTE, ifindex, - TRUE, - TRUE, + FALSE, nm_platform_lookup_predicate_routes_skip_rtprot_kernel, NULL); } @@ -208,8 +207,7 @@ nmtstp_ip6_route_get_all (NMPlatform *platform, return nm_platform_lookup_route_visible_clone (platform, NMP_OBJECT_TYPE_IP6_ROUTE, ifindex, - TRUE, - TRUE, + FALSE, nm_platform_lookup_predicate_routes_skip_rtprot_kernel, NULL); } diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c index 275d898641..cf771f80ea 100644 --- a/src/tests/test-route-manager.c +++ b/src/tests/test-route-manager.c @@ -169,14 +169,14 @@ ip_routes (test_fixture *fixture, NMPObjectType obj_type) pl_head_entry = nm_platform_lookup_route_visible (NM_PLATFORM_GET, obj_type, ifindex, - FALSE, - TRUE); + 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 (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)); g_assert (r->ifindex == ifindex); g_assert (nmp_object_is_visible (plobj)); g_array_append_vals (routes, r, 1); From 17f02318add85410ab8e75f982932633154e2a5e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Jul 2017 11:44:27 +0200 Subject: [PATCH 31/36] platform: drop separate index for visible objects Routes and addresses don't implement cmd_obj_is_visible(), hence they are always visible, and NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY is identical to NMP_CACHE_ID_TYPE_OBJECT_TYPE. Only link objects can be alive but invisible. Still, drop the index for looking up visible links entirely. Let callers do the filtering, if they care. --- src/platform/nm-fake-platform.c | 6 +-- src/platform/nm-linux-platform.c | 22 ++++----- src/platform/nmp-object.c | 70 ++++++---------------------- src/platform/nmp-object.h | 41 ++++++---------- src/platform/tests/test-nmp-object.c | 13 ++++-- 5 files changed, 48 insertions(+), 104 deletions(-) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 028931c8c8..3f57afa789 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -1168,8 +1168,7 @@ ipx_route_delete (NMPlatform *platform, addr_family == AF_INET ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, - 0, - FALSE), + 0), &o) { const NMPObject *obj_old = NULL; @@ -1266,8 +1265,7 @@ ipx_route_add (NMPlatform *platform, int addr_family, const NMPlatformObject *ro nmp_cache_iter_for_each (&iter, nm_platform_lookup_addrroute (platform, NMP_OBJECT_GET_TYPE (obj), - 0, - FALSE), + 0), &o) { if (addr_family == AF_INET) { const NMPlatformIP4Route *item = NMP_OBJECT_CAST_IP4_ROUTE (o); diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index f4cd591771..5367bdc5ae 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3286,8 +3286,7 @@ cache_prune_one_type (NMPlatform *platform, NMPObjectType obj_type) NMPCache *cache = nm_platform_get_cache (platform); nmp_lookup_init_obj_type (&lookup, - obj_type, - FALSE); + obj_type); nm_dedup_multi_iter_init (&iter, nmp_cache_lookup (cache, &lookup)); @@ -3418,7 +3417,7 @@ cache_on_change (NMPlatform *platform, NMDedupMultiIter iter; const NMPlatformLink *l; - nmp_lookup_init_link (&lookup, FALSE); + nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK); nmp_cache_iter_for_each_link (&iter, nmp_cache_lookup (cache, &lookup), &l) { @@ -3876,9 +3875,10 @@ link_get_all (NMPlatform *platform) { NMPLookup lookup; - nmp_lookup_init_link (&lookup, TRUE); + nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK); return nmp_cache_lookup_to_array (nmp_cache_lookup (nm_platform_get_cache (platform), &lookup), - NMP_OBJECT_TYPE_LINK); + NMP_OBJECT_TYPE_LINK, + TRUE); } static const NMPlatformLink * @@ -5635,15 +5635,13 @@ link_can_assume (NMPlatform *platform, int ifindex) nmp_lookup_init_addrroute (&lookup, NMP_OBJECT_TYPE_IP4_ADDRESS, - ifindex, - TRUE); + ifindex); if (nmp_cache_lookup (cache, &lookup)) return TRUE; nmp_lookup_init_addrroute (&lookup, NMP_OBJECT_TYPE_IP6_ADDRESS, - ifindex, - TRUE); + ifindex); nmp_cache_iter_for_each (&iter, nmp_cache_lookup (cache, &lookup), &o) { @@ -5732,10 +5730,10 @@ ipx_address_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type) 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, - TRUE); + ifindex); return nmp_cache_lookup_to_array (nmp_cache_lookup (nm_platform_get_cache (platform), &lookup), - obj_type); + obj_type, + FALSE /*addresses are always visible. */); } static GArray * diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index ac5ee20e1d..cf82514a50 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -177,20 +177,6 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, /* just return 1, to indicate that obj_a is partitionable by this idx_type. */ return 1; - case NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY: - if (!nmp_object_is_visible (obj_a)) - return 0; - if (obj_b) { - return NMP_OBJECT_GET_TYPE (obj_a) == NMP_OBJECT_GET_TYPE (obj_b) - && 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_ROUTES_VISIBLE_BY_DEFAULT: if ( !NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_a), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE) @@ -1263,21 +1249,18 @@ _vt_cmd_obj_is_visible_link (const NMPObject *obj) 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 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 const guint8 _supported_cache_ids_ipx_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_BY_DEFAULT, NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION, @@ -1407,7 +1390,8 @@ nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *m nmp_cache_iter_for_each_link (&iter, nmp_cache_lookup (cache, - nmp_lookup_init_link (&lookup, FALSE)), + nmp_lookup_init_obj_type (&lookup, + NMP_OBJECT_TYPE_LINK)), &link) { const NMPObject *obj = NMP_OBJECT_UP_CAST ((NMPlatformObject *) link); @@ -1540,8 +1524,7 @@ _L (const NMPLookup *lookup) const NMPLookup * nmp_lookup_init_obj_type (NMPLookup *lookup, - NMPObjectType obj_type, - gboolean visible_only) + NMPObjectType obj_type) { NMPObject *o; @@ -1554,16 +1537,7 @@ nmp_lookup_init_obj_type (NMPLookup *lookup, case NMP_OBJECT_TYPE_IP4_ROUTE: case NMP_OBJECT_TYPE_IP6_ROUTE: o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); - if (visible_only) { - lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE_VISIBLE_ONLY; - o->object.ifindex = 1; - if (obj_type == NMP_OBJECT_TYPE_LINK) { - o->_link.netlink.is_in_netlink = TRUE; - o->link.name[0] = 'x'; - } - } else { - lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; - } + lookup->cache_id_type = NMP_CACHE_ID_TYPE_OBJECT_TYPE; return _L (lookup); default: nm_assert_not_reached (); @@ -1571,15 +1545,6 @@ nmp_lookup_init_obj_type (NMPLookup *lookup, } } -const NMPLookup * -nmp_lookup_init_link (NMPLookup *lookup, - gboolean visible_only) -{ - return nmp_lookup_init_obj_type (lookup, - NMP_OBJECT_TYPE_LINK, - visible_only); -} - const NMPLookup * nmp_lookup_init_link_by_ifname (NMPLookup *lookup, const char *ifname) @@ -1600,8 +1565,7 @@ nmp_lookup_init_link_by_ifname (NMPLookup *lookup, const NMPLookup * nmp_lookup_init_addrroute (NMPLookup *lookup, NMPObjectType obj_type, - int ifindex, - gboolean visible_only) + int ifindex) { NMPObject *o; @@ -1613,14 +1577,7 @@ nmp_lookup_init_addrroute (NMPLookup *lookup, if (ifindex <= 0) { return nmp_lookup_init_obj_type (lookup, - obj_type, - visible_only); - } - - if (!visible_only) { - /* some match combinations are not implemented, as they would require - * an additional index which is expensive to maintain. */ - g_return_val_if_reached (NULL); + obj_type); } o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); @@ -1644,8 +1601,7 @@ nmp_lookup_init_route_visible (NMPLookup *lookup, if (!only_default) { return nmp_lookup_init_addrroute (lookup, obj_type, - ifindex, - TRUE); + ifindex); } if (ifindex > 0) { @@ -1701,7 +1657,8 @@ nmp_lookup_init_route_by_dest (NMPLookup *lookup, GArray * nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry, - NMPObjectType obj_type) + NMPObjectType obj_type, + gboolean visible_only) { const NMPClass *klass = nmp_class_from_type (obj_type); NMDedupMultiIter iter; @@ -1717,6 +1674,9 @@ nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry, 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; @@ -1807,10 +1767,8 @@ nmp_cache_lookup_link_full (const NMPCache *cache, return NULL; nmp_lookup_init_link_by_ifname (&lookup, ifname); ifname = NULL; - } else { - nmp_lookup_init_link (&lookup, visible_only); - visible_only = FALSE; - } + } else + nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK); head_entry = nmp_cache_lookup (cache, &lookup); nmp_cache_iter_for_each_link (&iter, head_entry, &link) { diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 1cff049555..605a131b3c 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -66,15 +66,17 @@ typedef enum { /*< skip >*/ * they don't track all objects. * * Hence, this index type is used when looking at all objects (still - * partitioned by type). */ + * 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. */ @@ -453,16 +455,12 @@ nmp_cache_lookup (const NMPCache *cache, } const NMPLookup *nmp_lookup_init_obj_type (NMPLookup *lookup, - NMPObjectType obj_type, - gboolean visible_only); -const NMPLookup *nmp_lookup_init_link (NMPLookup *lookup, - gboolean visible_only); + 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, - gboolean visible_only); + int ifindex); const NMPLookup *nmp_lookup_init_route_visible (NMPLookup *lookup, NMPObjectType obj_type, int ifindex, @@ -474,7 +472,8 @@ const NMPLookup *nmp_lookup_init_route_by_dest (NMPLookup *lookup, guint32 metric); GArray *nmp_cache_lookup_to_array (const NMDedupMultiHeadEntry *head_entry, - NMPObjectType obj_type); + NMPObjectType obj_type, + gboolean visible_only); static inline gboolean nmp_cache_iter_next (NMDedupMultiIter *iter, const NMPObject **out_obj) @@ -600,22 +599,11 @@ ASSERT_nmp_cache_ops (const NMPCache *cache, static inline const NMDedupMultiHeadEntry * nm_platform_lookup_obj_type (NMPlatform *platform, - NMPObjectType obj_type, - gboolean visible_only) + NMPObjectType obj_type) { NMPLookup lookup; - nmp_lookup_init_obj_type (&lookup, obj_type, visible_only); - return nm_platform_lookup (platform, &lookup); -} - -static inline const NMDedupMultiHeadEntry * -nm_platform_lookup_link (NMPlatform *platform, - gboolean visible_only) -{ - NMPLookup lookup; - - nmp_lookup_init_link (&lookup, visible_only); + nmp_lookup_init_obj_type (&lookup, obj_type); return nm_platform_lookup (platform, &lookup); } @@ -632,12 +620,11 @@ nm_platform_lookup_link_by_ifname (NMPlatform *platform, static inline const NMDedupMultiHeadEntry * nm_platform_lookup_addrroute (NMPlatform *platform, NMPObjectType obj_type, - int ifindex, - gboolean visible_only) + int ifindex) { NMPLookup lookup; - nmp_lookup_init_addrroute (&lookup, obj_type, ifindex, visible_only); + nmp_lookup_init_addrroute (&lookup, obj_type, ifindex); return nm_platform_lookup (platform, &lookup); } diff --git a/src/platform/tests/test-nmp-object.c b/src/platform/tests/test-nmp-object.c index 40d876a65b..11fc59e24b 100644 --- a/src/platform/tests/test-nmp-object.c +++ b/src/platform/tests/test-nmp-object.c @@ -110,7 +110,7 @@ _nmp_object_equal (const NMPObject *a, const NMPObject *b) /*****************************************************************************/ static void -_assert_cache_multi_lookup_contains (const NMPCache *cache, const NMDedupMultiHeadEntry *head_entry, 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) { NMDedupMultiIter iter; gboolean found; @@ -131,8 +131,11 @@ _assert_cache_multi_lookup_contains (const NMPCache *cache, const NMDedupMultiHe &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++; } @@ -152,9 +155,9 @@ _assert_cache_multi_lookup_contains_link (const NMPCache *cache, g_assert (cache); - nmp_lookup_init_link (&lookup, visible_only); + 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, contains); + _assert_cache_multi_lookup_contains (cache, head_entry, obj, visible_only, contains); } /*****************************************************************************/ From 8b3b148fda8456dee817d369640f409c8e0cec57 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Jul 2017 12:05:07 +0200 Subject: [PATCH 32/36] platform/trivial: rename cache-id-type indexes --- src/platform/nmp-object.c | 14 +++++++------- src/platform/nmp-object.h | 10 +++++----- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index cf82514a50..b6f542d089 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -177,7 +177,7 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, /* just return 1, to indicate that obj_a is partitionable by this idx_type. */ return 1; - case NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT: + 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) @@ -195,7 +195,7 @@ _idx_obj_part (const DedupMultiIdxType *idx_type, } return 1; - case NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX: + 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, @@ -1255,14 +1255,14 @@ static const guint8 _supported_cache_ids_link[] = { static const guint8 _supported_cache_ids_ipx_address[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX, + NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX, 0, }; static const guint8 _supported_cache_ids_ipx_route[] = { NMP_CACHE_ID_TYPE_OBJECT_TYPE, - NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX, - NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT, + NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX, + NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, NMP_CACHE_ID_TYPE_ROUTES_BY_DESTINATION, 0, }; @@ -1582,7 +1582,7 @@ nmp_lookup_init_addrroute (NMPLookup *lookup, o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); o->object.ifindex = ifindex; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_ADDRROUTE_BY_IFINDEX; return _L (lookup); } @@ -1612,7 +1612,7 @@ nmp_lookup_init_route_visible (NMPLookup *lookup, o = _nmp_object_stackinit_from_type (&lookup->selector_obj, obj_type); o->object.ifindex = 1; - lookup->cache_id_type = NMP_CACHE_ID_TYPE_ROUTES_VISIBLE_BY_DEFAULT; + lookup->cache_id_type = NMP_CACHE_ID_TYPE_DEFAULT_ROUTES; return _L (lookup); } diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 605a131b3c..b3353116ee 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -48,12 +48,12 @@ 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 >*/ @@ -80,10 +80,10 @@ typedef enum { /*< skip >*/ /* 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_ROUTES_VISIBLE_BY_DEFAULT, + NMP_CACHE_ID_TYPE_DEFAULT_ROUTES, - /* all the visible addresses/routes (by object-type) for an ifindex. */ - NMP_CACHE_ID_TYPE_ADDRROUTE_VISIBLE_BY_IFINDEX, + /* 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). From 71cf60e852dc04df22b1c127fef00138e6d3a115 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Jul 2017 12:49:47 +0200 Subject: [PATCH 33/36] platform: refactor fake platform to use NMPCache for addresses And move some code from NMLinuxPlatform to NMPlatform, where it belongs. The advantage is that we reuse (and test!) the NMPCache implementation for tracking addresses. Also, we now always expose proper NMPObjects from both linux and fake platform. For example, obj = NMP_OBJECT_UP_CAST (nm_platform_ip4_address_get (...)); will work as expected. Also, the caller is now by NMPlatform API allowed to take and keep a reference to the returned objects. --- src/platform/nm-fake-platform.c | 282 ++++++++++--------------------- src/platform/nm-linux-platform.c | 56 ------ src/platform/nm-platform.c | 54 ++++-- src/platform/nm-platform.h | 4 - src/platform/nmp-object.h | 18 ++ 5 files changed, 144 insertions(+), 270 deletions(-) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 3f57afa789..96475a9a2f 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -50,8 +50,6 @@ typedef struct { typedef struct { GHashTable *options; GArray *links; - GArray *ip4_addresses; - GArray *ip6_addresses; } NMFakePlatformPrivate; struct _NMFakePlatform { @@ -97,6 +95,13 @@ G_DEFINE_TYPE (NMFakePlatform, nm_fake_platform, NM_TYPE_PLATFORM) static void link_changed (NMPlatform *platform, NMFakePlatformLink *device, gboolean raise_signal); +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, @@ -116,14 +121,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); \ @@ -379,10 +376,8 @@ link_add (NMPlatform *platform, 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; if (!device || !device->link.ifindex) return FALSE; @@ -393,18 +388,8 @@ link_delete (NMPlatform *platform, int ifindex) g_clear_pointer (&device->udi, g_free); /* 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); - - 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); - - if (address->ifindex == ifindex) - memset (address, 0, sizeof (*address)); - } + 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); @@ -907,59 +892,25 @@ mesh_set_ssid (NMPlatform *platform, int ifindex, const guint8 *ssid, gsize len) /*****************************************************************************/ -static GArray * -ip4_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; - NMPlatformIP4Address *address; - int count = 0, i; + 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); - /* 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++; - } + g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP4Address), count); + obj = nmp_object_new (addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ADDRESS + : NMP_OBJECT_TYPE_IP6_ADDRESS, + address); - /* 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) -{ - 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++; - } - - addresses = g_array_sized_new (TRUE, TRUE, sizeof (NMPlatformIP6Address), count); - - /* 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); - } - - 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 @@ -973,9 +924,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; @@ -990,28 +939,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 @@ -1024,9 +952,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; @@ -1039,111 +965,83 @@ 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; + return ipx_address_add (platform, AF_INET6, (const NMPlatformObject *) &address); +} - if ( item->ifindex != address.ifindex - || !IN6_ARE_ADDR_EQUAL (&item->address, &address.address)) - continue; +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; - changed = !nm_platform_ip6_address_cmp (item, &address); + g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); - 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; + 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; + } + + 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); } /*****************************************************************************/ @@ -1325,8 +1223,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)); } void @@ -1366,8 +1262,6 @@ finalize (GObject *object) g_clear_pointer (&device->lnk, nmp_object_unref); } g_array_unref (priv->links); - g_array_unref (priv->ip4_addresses); - g_array_unref (priv->ip6_addresses); G_OBJECT_CLASS (nm_fake_platform_parent_class)->finalize (object); } @@ -1435,10 +1329,6 @@ 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; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 5367bdc5ae..6fc24acdcb 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -5722,32 +5722,6 @@ link_get_driver_info (NMPlatform *platform, /*****************************************************************************/ -static GArray * -ipx_address_get_all (NMPlatform *platform, 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 (platform), &lookup), - obj_type, - FALSE /*addresses are always visible. */); -} - -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, @@ -5859,32 +5833,6 @@ 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_platform_get_cache (platform), &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_platform_get_cache (platform), &obj_id); - if (nmp_object_is_visible (obj)) - return &obj->ip6_address; - return NULL; -} - /*****************************************************************************/ static guint32 @@ -6807,10 +6755,6 @@ 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; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 912f498437..235cdb9c21 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2652,10 +2652,10 @@ nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean * /*****************************************************************************/ const NMDedupMultiHeadEntry * -nm_platform_lookup (NMPlatform *platform, +nm_platform_lookup (NMPlatform *self, const NMPLookup *lookup) { - return nmp_cache_lookup (nm_platform_get_cache (platform), + return nmp_cache_lookup (nm_platform_get_cache (self), lookup); } @@ -2670,7 +2670,7 @@ nm_platform_lookup_predicate_routes_skip_rtprot_kernel (const NMPObject *obj, /** * nm_platform_lookup_clone: - * @platform: + * @self: * @lookup: * @predicate: if given, only objects for which @predicate returns %TRUE are included * in the result. @@ -2687,12 +2687,12 @@ nm_platform_lookup_predicate_routes_skip_rtprot_kernel (const NMPObject *obj, * Returns: the result of the lookup. */ GPtrArray * -nm_platform_lookup_clone (NMPlatform *platform, +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 (platform, lookup), + return nm_dedup_multi_objs_to_ptr_array_head (nm_platform_lookup (self, lookup), (NMDedupMultiFcnSelectPredicate) predicate, user_data); } @@ -2716,6 +2716,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) { @@ -2723,7 +2737,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 * @@ -2733,7 +2747,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 @@ -2848,19 +2862,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 (nmp_object_is_visible (obj)); + return &obj->ip4_address; } 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 (nmp_object_is_visible (obj)); + return &obj->ip6_address; } static const NMPlatformIP4Address * @@ -4920,17 +4946,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; } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 4074fb8a49..ed95f99bed 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -631,8 +631,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, @@ -652,8 +650,6 @@ 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); gboolean (*ip4_route_add) (NMPlatform *, const NMPlatformIP4Route *route); gboolean (*ip6_route_add) (NMPlatform *, const NMPlatformIP6Route *route); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index b3353116ee..c3095178ae 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -337,6 +337,24 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN; } +#define NMP_OBJECT_CAST_IP4_ADDRESS(obj) \ + ({ \ + typeof (*(obj)) *_obj = (obj); \ + _nm_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \ + &_obj->ip4_address; \ + }) + +#define NMP_OBJECT_CAST_IP6_ADDRESS(obj) \ + ({ \ + typeof (*(obj)) *_obj = (obj); \ + _nm_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \ + &_obj->ip6_address; \ + }) + #define NMP_OBJECT_CAST_IPX_ROUTE(obj) \ ({ \ typeof (*(obj)) *_obj = (obj); \ From ac60b0ce60c8f3535f9b46f31db0fb0b1e4b67ea Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Jul 2017 12:49:47 +0200 Subject: [PATCH 34/36] platform: move link accessors to NMPlatform base class and refactor NMFakePlatform to also track links via NMPCache. For one, now NMFakePlatform also tests NMPCache, increasing the coverage of what we care about. Also, all our NMPlatform implementations now use NMPObject and NMPCache. That means, we can expose those as part of the public API. Which is great, because callers can keep a reference to the NMPObject object and make use of generic functions like nmp_object_to_string(). --- src/platform/nm-fake-platform.c | 707 +++++++++++++++++-------------- src/platform/nm-linux-platform.c | 179 +------- src/platform/nm-platform.c | 158 +++++-- src/platform/nm-platform.h | 12 +- src/platform/nmp-object.c | 23 +- src/platform/nmp-object.h | 18 +- src/platform/tests/test-link.c | 7 +- 7 files changed, 552 insertions(+), 552 deletions(-) diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 96475a9a2f..718ee974ae 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -40,10 +40,8 @@ /*****************************************************************************/ typedef struct { - NMPlatformLink link; - + const NMPObject *obj; char *udi; - NMPObject *lnk; struct in6_addr ip6_lladdr; } NMFakePlatformLink; @@ -93,7 +91,10 @@ 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, @@ -161,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; + gboolean connected; - 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); + /* 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; - return links; -} + 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; -static const NMPlatformLink * -_nm_platform_link_get (NMPlatform *platform, int ifindex) -{ - NMFakePlatformLink *device = link_get (platform, ifindex); - - return device ? &device->link : NULL; -} - -static const NMPlatformLink * -_nm_platform_link_get_by_ifname (NMPlatform *platform, const char *ifname) -{ - NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); - guint i; - - for (i = 0; i < priv->links->len; i++) { - NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); - - if (!strcmp (device->link.name, ifname)) - return &device->link; - } - return NULL; -} - -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; - - if ( length == 0 - || length > NM_UTILS_HWADDR_LEN_MAX - || !address) - g_return_val_if_reached (NULL); - - for (i = 0; i < priv->links->len; i++) { - NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i); - - if ( device->link.addr.len == length - && memcmp (device->link.addr.data, address, length) == 0) { - return &device->link; + 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; + } + } } - } - return NULL; + } else + connected = NM_FLAGS_HAS (obj_tmp->link.n_ifi_flags, IFF_UP); + + 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 NMPObject * -link_get_lnk (NMPlatform *platform, - int ifindex, - NMLinkType link_type, - const NMPlatformLink **out_link) +static NMFakePlatformLink * +link_add_pre (NMPlatform *platform, + const char *name, + NMLinkType type, + const void *address, + size_t address_len) { - NMFakePlatformLink *device = link_get (platform, ifindex); + NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE ((NMFakePlatform *) platform); + NMFakePlatformLink *device; + int ifindex; + NMPObject *o; + NMPlatformLink *link; + gs_free char *ip6_lladdr = NULL; - if (!device) - return NULL; + g_assert (!name || strlen (name) < IFNAMSIZ); - NM_SET_OUT (out_link, &device->link); + 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; - if (!device->lnk) - return NULL; + memset (device, 0, sizeof (*device)); - if (link_type == NM_LINK_TYPE_NONE) - return device->lnk; + o = nmp_object_new_link (ifindex); + link = NMP_OBJECT_CAST_LINK (o); - if ( link_type != device->link.type - || link_type != NMP_OBJECT_GET_CLASS (device->lnk)->lnk_link_type) - return NULL; + ip6_lladdr = ifindex > 0 ? g_strdup_printf ("fe80::fa1e:%0x:%0x", ifindex / 256, ifindex % 256) : NULL; - return device->lnk; + 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; + } + + o->_link.netlink.is_in_netlink = TRUE; + + 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); + + device->obj = o; + device->udi = g_strdup_printf ("fake:%d", ifindex); + device->ip6_lladdr = *nmtst_inet6_from_string (ip6_lladdr); + + return device; } static gboolean @@ -331,113 +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; + 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; - 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; - } - - 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, new_device, FALSE); - } - - 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); - - link_changed (platform, &g_array_index (priv->links, NMFakePlatformLink, priv->links->len - 1), FALSE); - } + link_changed (platform, device, cache_op, NULL); + if (veth_peer) + link_changed (platform, device_veth, cache_op_veth, NULL); return TRUE; } +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; + + device = link_add_pre (platform, name, NM_LINK_TYPE_VLAN, NULL, 0); + + 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) { NMFakePlatformLink *device = link_get (platform, ifindex); - NMPlatformLink deleted_device; + 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 */ 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); - g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, (int) NMP_OBJECT_TYPE_LINK, ifindex, &deleted_device, (int) NM_PLATFORM_SIGNAL_REMOVED); - + nm_platform_cache_update_emit_signal (platform, + cache_op, + obj_old2, + NULL); return TRUE; } -static const char * -link_get_type_name (NMPlatform *platform, int ifindex) +static void +link_set_obj (NMPlatform *platform, + NMFakePlatformLink *device, + NMPObject *obj_tmp) { - return type_to_type_name (nm_platform_link_get_type (platform, ifindex)); + 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; + + g_assert (device); + g_assert (NMP_OBJECT_GET_TYPE (device->obj) == NMP_OBJECT_TYPE_LINK); + + if (!obj_tmp) { + obj_tmp_tmp = nmp_object_clone (device->obj, FALSE); + obj_tmp = obj_tmp_tmp; + } + + g_assert (NMP_OBJECT_GET_TYPE (obj_tmp) == NMP_OBJECT_TYPE_LINK); + + 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); + + nmp_object_unref (device->obj); + device->obj = nmp_object_ref (obj_new); + + 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); + obj_tmp = nmp_object_clone (device->obj, FALSE); + obj_tmp->link.n_ifi_flags = n_ifi_flags; + link_set_obj (platform, device, obj_tmp); +} + +static void +link_changed (NMPlatform *platform, + NMFakePlatformLink *device, + NMPCacheOpsType cache_op, + const NMPObject *obj_old) +{ + g_assert (device->obj); + + g_assert (!nmp_cache_link_connected_needs_toggle (nm_platform_get_cache (platform), + device->obj, NULL, NULL)); + + nm_platform_cache_update_emit_signal (platform, + cache_op, + obj_old, + device->obj); + + 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->link.ifindex, device->ip6_lladdr, 64); + ip6_address_delete (platform, device->obj->link.ifindex, device->ip6_lladdr, 64); } - if (device->link.master) { - gboolean connected = FALSE; + if (device->obj->link.master) { + NMFakePlatformLink *master; - NMFakePlatformLink *master = link_get (platform, device->link.master); - - g_return_if_fail (master && master != device); - - for (i = 0; i < priv->links->len; i++) { - NMFakePlatformLink *slave = &g_array_index (priv->links, NMFakePlatformLink, i); - - if (slave && slave->link.master == master->link.ifindex && slave->link.connected) - connected = TRUE; - } - - 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); } } @@ -445,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; @@ -455,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; } @@ -491,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; } @@ -511,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; } @@ -528,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; } @@ -539,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; } @@ -561,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 @@ -612,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: @@ -628,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: @@ -644,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: @@ -661,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 (device->obj->link.master != master) { + nm_auto_nmpobj NMPObject *obj_tmp = NULL; - 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; - } - - 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; @@ -680,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; } +struct vlan_add_data { + guint32 vlan_flags; + int parent; + int vlan_id; +}; + +static void +_vlan_add_prepare (NMPlatform *platform, + NMFakePlatformLink *device, + gconstpointer user_data) +{ + const struct vlan_add_data *d = user_data; + NMPObject *obj_tmp; + NMPObject *lnk; + + obj_tmp = (NMPObject *) device->obj; + + lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL); + lnk->lnk_vlan.id = d->vlan_id; + lnk->lnk_vlan.flags = d->vlan_flags; + + obj_tmp->link.parent = d->parent; + obj_tmp->_link.netlink.lnk = lnk; +} + static gboolean vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint32 vlan_flags, const NMPlatformLink **out_link) { - NMFakePlatformLink *device; + const struct vlan_add_data d = { + .parent = parent, + .vlan_id = vlan_id, + .vlan_flags = vlan_flags, + }; - if (!link_add (platform, name, NM_LINK_TYPE_VLAN, 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); - - device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL); - device->lnk->lnk_vlan.id = vlan_id; - device->link.parent = parent; - - if (out_link) - *out_link = &device->link; + link_add_one (platform, name, NM_LINK_TYPE_VLAN, + _vlan_add_prepare, &d, out_link); return TRUE; } @@ -732,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; - - if (!link_add (platform, name, NM_LINK_TYPE_VXLAN, 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); - - device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL); - device->lnk->lnk_vxlan = *props; - device->link.parent = props->parent_ifindex; - - if (out_link) - *out_link = &device->link; + link_add_one (platform, name, NM_LINK_TYPE_VXLAN, + _vxlan_add_prepare, props, out_link); return TRUE; } +struct infiniband_add_data { + int parent; + int p_key; +}; + +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; + + obj_tmp = (NMPObject *) device->obj; + + lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL); + lnk->lnk_infiniband.p_key = d->p_key; + lnk->lnk_infiniband.mode = "datagram"; + + 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); + nm_utils_new_infiniband_name (name, parent_device->obj->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); - - 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; } @@ -791,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)); } @@ -802,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) { @@ -1236,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); @@ -1259,7 +1321,7 @@ 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); @@ -1277,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; diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 6fc24acdcb..6a4210de90 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -3858,108 +3858,6 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event /*****************************************************************************/ -static const NMPObject * -cache_lookup_link (NMPlatform *platform, int ifindex) -{ - const NMPObject *obj_cache; - - obj_cache = nmp_cache_lookup_link (nm_platform_get_cache (platform), ifindex); - if (!nmp_object_is_visible (obj_cache)) - return NULL; - - return obj_cache; -} - -static GArray * -link_get_all (NMPlatform *platform) -{ - NMPLookup lookup; - - nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK); - return nmp_cache_lookup_to_array (nmp_cache_lookup (nm_platform_get_cache (platform), &lookup), - 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; -} - -static const NMPlatformLink * -_nm_platform_link_get_by_ifname (NMPlatform *platform, - const char *ifname) -{ - const NMPObject *obj = NULL; - - if (ifname && *ifname) { - obj = nmp_cache_lookup_link_full (nm_platform_get_cache (platform), - 0, ifname, TRUE, NM_LINK_TYPE_NONE, NULL, NULL); - } - 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_platform_get_cache (platform), - 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; -} - -/*****************************************************************************/ - static gboolean do_add_link_with_lookup (NMPlatform *platform, NMLinkType link_type, @@ -4287,55 +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) -{ - const NMPObject *link; - struct udev_device *udevice = NULL; - const char *uproperty; - - link = nmp_cache_lookup_link (nm_platform_get_cache (platform), 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 @@ -4422,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 @@ -4431,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_platform_get_cache (platform), ifindex); - return obj_cache ? obj_cache->_link.udev.device : NULL; -} - static NMPlatformError link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled) { @@ -4509,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) @@ -5623,7 +5463,7 @@ link_can_assume (NMPlatform *platform, int ifindex) if (ifindex <= 0) return FALSE; - link = cache_lookup_link (platform, ifindex); + link = nm_platform_link_get_obj (platform, ifindex, TRUE); if (!link) return FALSE; @@ -5647,7 +5487,7 @@ link_can_assume (NMPlatform *platform, int ifindex) &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 TRUE; } return FALSE; } @@ -6679,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; @@ -6700,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; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 235cdb9c21..85a7b7c175 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -32,10 +32,12 @@ #include #include #include +#include #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" @@ -497,10 +499,14 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) guint i, j, nresult; GHashTable *unseen; 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 = nmp_cache_lookup_to_array (nmp_cache_lookup (nm_platform_get_cache (self), &lookup), + NMP_OBJECT_TYPE_LINK, + TRUE); if (!links || links->len == 0) return links; @@ -518,7 +524,7 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) 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); @@ -589,6 +595,25 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) 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 @@ -604,11 +629,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); } /** @@ -621,11 +650,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); } /** @@ -642,15 +687,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 @@ -880,9 +936,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"; } /** @@ -897,11 +970,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; } /** @@ -1047,13 +1135,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; } /** @@ -1553,13 +1642,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 @@ -2871,8 +2975,8 @@ nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, g 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 (nmp_object_is_visible (obj)); - return &obj->ip4_address; + nm_assert (!obj || nmp_object_is_visible (obj)); + return NMP_OBJECT_CAST_IP4_ADDRESS (obj); } const NMPlatformIP6Address * @@ -2885,8 +2989,8 @@ nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr addr nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &address); obj = nmp_cache_lookup_obj (nm_platform_get_cache (self), &obj_id); - nm_assert (nmp_object_is_visible (obj)); - return &obj->ip6_address; + nm_assert (!obj || nmp_object_is_visible (obj)); + return NMP_OBJECT_CAST_IP6_ADDRESS (obj); } static const NMPlatformIP4Address * diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index ed95f99bed..20c8e0d9f8 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -506,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, @@ -521,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); @@ -742,6 +733,9 @@ 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); diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c index b6f542d089..b6a51e58bc 100644 --- a/src/platform/nmp-object.c +++ b/src/platform/nmp-object.c @@ -1336,6 +1336,17 @@ nmp_cache_use_udev_get (const NMPCache *cache) /*****************************************************************************/ +gboolean +nmp_cache_link_connected_for_slave (int ifindex_master, const NMPObject *slave) +{ + nm_assert (NMP_OBJECT_GET_TYPE (slave) == NMP_OBJECT_TYPE_LINK); + + 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 @@ -1378,12 +1389,9 @@ 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 { + else { NMPLookup lookup; NMDedupMultiIter iter; const NMPlatformLink *link = NULL; @@ -1397,10 +1405,7 @@ nmp_cache_link_connected_needs_toggle (const NMPCache *cache, const NMPObject *m 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; } diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index c3095178ae..9ea5a78ae5 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -337,13 +337,22 @@ 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_unused const NMPObject *_obj_type_check = _obj; \ + \ + nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_LINK); \ + _obj ? &_obj->link : NULL; \ + }) + #define NMP_OBJECT_CAST_IP4_ADDRESS(obj) \ ({ \ typeof (*(obj)) *_obj = (obj); \ _nm_unused const NMPObject *_obj_type_check = _obj; \ \ - nm_assert (NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \ - &_obj->ip4_address; \ + nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \ + _obj ? &_obj->ip4_address : NULL; \ }) #define NMP_OBJECT_CAST_IP6_ADDRESS(obj) \ @@ -351,8 +360,8 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) typeof (*(obj)) *_obj = (obj); \ _nm_unused const NMPObject *_obj_type_check = _obj; \ \ - nm_assert (NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \ - &_obj->ip6_address; \ + nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \ + _obj ? &_obj->ip6_address : NULL; \ }) #define NMP_OBJECT_CAST_IPX_ROUTE(obj) \ @@ -541,6 +550,7 @@ const NMPObject *nmp_cache_lookup_link_full (const NMPCache *cache, NMPObjectMatchFn match_fn, gpointer user_data); +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); 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); From 06598700feda25dfb05e14254c57c6f746b92b7b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 4 Jul 2017 22:29:27 +0200 Subject: [PATCH 35/36] platform: refactor nm_platform_link_get_all() to return GPtrArray Instead of doing a full clone, return a pointer array (with references owned). The NMPlatformLink instances are now immutable. --- src/nm-manager.c | 20 +++---- src/platform/nm-platform.c | 93 +++++++++++++++++-------------- src/platform/nm-platform.h | 2 +- src/platform/tests/test-common.c | 18 +++--- src/platform/tests/test-general.c | 2 +- 5 files changed, 74 insertions(+), 61 deletions(-) diff --git a/src/nm-manager.c b/src/nm-manager.c index 90ad66403e..dd168fd0be 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 ((const NMPObject *) 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/platform/nm-platform.c b/src/platform/nm-platform.c index 85a7b7c175..73e508ff00 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -464,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) @@ -487,38 +487,47 @@ _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); nmp_lookup_init_obj_type (&lookup, NMP_OBJECT_TYPE_LINK); - links = nmp_cache_lookup_to_array (nmp_cache_lookup (nm_platform_get_cache (self), &lookup), - NMP_OBJECT_TYPE_LINK, - TRUE); + 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 ((const NMPObject *) 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 (); @@ -527,7 +536,7 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) #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 ((const NMPObject *) links->pdata[i]); if (!item->ifindex) continue; @@ -547,50 +556,52 @@ 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 ((const NMPObject *) 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 ((const NMPObject *) 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; } diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 20c8e0d9f8..6e7a8b0658 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -740,7 +740,7 @@ 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); 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-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); From b2112ff471f0fd171646e5d0cd159626cb3a9fe6 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Wed, 5 Jul 2017 11:12:59 +0200 Subject: [PATCH 36/36] platform: refactor NMPObject cast macros using _Generic() This way, we also accept void pointers, while preserving constness. --- shared/nm-utils/nm-macros-internal.h | 37 ++++++++++++++++++--- src/nm-default-route-manager.c | 10 +++--- src/nm-manager.c | 2 +- src/nm-route-manager.c | 2 +- src/platform/nm-platform.c | 8 ++--- src/platform/nmp-object.h | 49 ++++++++++++---------------- 6 files changed, 65 insertions(+), 43 deletions(-) diff --git a/shared/nm-utils/nm-macros-internal.h b/shared/nm-utils/nm-macros-internal.h index 12794c3473..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__) @@ -537,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 */ \ @@ -547,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/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index f0dc75cfd1..f6362bccf6 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -209,7 +209,7 @@ _vt_routes_has_entry (const VTableIP *vtable, const GPtrArray *routes, const Ent if (vtable->vt->is_ip4) { for (i = 0; i < routes->len; i++) { - const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE ((NMPObject *) routes->pdata[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) @@ -217,7 +217,7 @@ _vt_routes_has_entry (const VTableIP *vtable, const GPtrArray *routes, const Ent } } else { for (i = 0; i < routes->len; i++) { - const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE ((NMPObject *) routes->pdata[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) @@ -346,7 +346,7 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, gboolean has_ifindex_synced = FALSE; Entry *entry = NULL; - route = NMP_OBJECT_CAST_IP_ROUTE ((NMPObject *) routes->pdata[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. */ @@ -442,7 +442,7 @@ _get_assumed_interface_metrics (const VTableIP *vtable, NMDefaultRouteManager *s gboolean ifindex_has_synced_entry = FALSE; const NMPlatformIPRoute *route; - route = NMP_OBJECT_CAST_IP_ROUTE ((NMPObject *) routes->pdata[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); @@ -571,7 +571,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c /* However, if there is a matching route (ifindex+metric) for our current entry, we are done. */ if (routes) { for (j = 0; j < routes->len; j++) { - const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE ((NMPObject *) routes->pdata[i]); + const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (routes->pdata[i]); if ( r->metric == expected_metric && r->ifindex == entry->route.rx.ifindex) { diff --git a/src/nm-manager.c b/src/nm-manager.c index dd168fd0be..3a8ada4360 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -2493,7 +2493,7 @@ platform_query_devices (NMManager *self) if (!links) return; for (i = 0; i < links->len; i++) { - const NMPlatformLink *link = NMP_OBJECT_CAST_LINK ((const NMPObject *) links->pdata[i]); + const NMPlatformLink *link = NMP_OBJECT_CAST_LINK (links->pdata[i]); gs_free NMConfigDeviceStateData *dev_state = NULL; dev_state = nm_config_device_state_load (link->ifindex); diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 8372d65234..e980cfe0a6 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -333,7 +333,7 @@ _route_index_create_from_platform (const VTableIP *vtable, j = 0; for (i = 0; i < len; i++) { - const NMPlatformIPXRoute *ipx_route = NMP_OBJECT_CAST_IPX_ROUTE ((NMPObject *) storage->pdata[i]); + const NMPlatformIPXRoute *ipx_route = NMP_OBJECT_CAST_IPX_ROUTE (storage->pdata[i]); if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (ipx_route)) continue; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 73e508ff00..176f377bdb 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -527,7 +527,7 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) unseen = g_hash_table_new (g_direct_hash, g_direct_equal); for (i = 0; i < links->len; i++) { - item = NMP_OBJECT_CAST_LINK ((const NMPObject *) links->pdata[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 (); @@ -536,7 +536,7 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) #if NM_MORE_ASSERTS /* Ensure that link_get_all returns a consistent and valid result. */ for (i = 0; i < links->len; i++) { - item = NMP_OBJECT_CAST_LINK ((const NMPObject *) links->pdata[i]); + item = NMP_OBJECT_CAST_LINK (links->pdata[i]); if (!item->ifindex) continue; @@ -565,7 +565,7 @@ nm_platform_link_get_all (NMPlatform *self, gboolean sort_by_name) guint first_idx = G_MAXUINT; for (i = 0; i < links->len; i++) { - item = NMP_OBJECT_CAST_LINK ((const NMPObject *) links->pdata[i]); + item = NMP_OBJECT_CAST_LINK (links->pdata[i]); if (!item) continue; @@ -594,7 +594,7 @@ skip: 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 = NMP_OBJECT_CAST_LINK ((const NMPObject *) links->pdata[first_idx]); + item = NMP_OBJECT_CAST_LINK (links->pdata[first_idx]); g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex)); g_ptr_array_add (result, links->pdata[first_idx]); links->pdata[first_idx] = NULL; diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 9ea5a78ae5..9cdad2e808 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -339,65 +339,58 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) #define NMP_OBJECT_CAST_LINK(obj) \ ({ \ - typeof (*(obj)) *_obj = (obj); \ - _nm_unused const NMPObject *_obj_type_check = _obj; \ + typeof (obj) _obj = (obj); \ \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_LINK); \ - _obj ? &_obj->link : NULL; \ + 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_unused const NMPObject *_obj_type_check = _obj; \ + typeof (obj) _obj = (obj); \ \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ADDRESS); \ - _obj ? &_obj->ip4_address : NULL; \ + 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_unused const NMPObject *_obj_type_check = _obj; \ + typeof (obj) _obj = (obj); \ \ - nm_assert (!_obj || NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ADDRESS); \ - _obj ? &_obj->ip6_address : NULL; \ + 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_unused const NMPObject *_obj_type_check = _obj; \ + typeof (obj) _obj = (obj); \ \ - nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ - &_obj->ipx_route; \ + 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_unused const NMPObject *_obj_type_check = _obj; \ + typeof (obj) _obj = (obj); \ \ - nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \ - &_obj->ip_route; \ + 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_unused const NMPObject *_obj_type_check = _obj; \ + typeof (obj) _obj = (obj); \ \ - nm_assert (NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP4_ROUTE); \ - &_obj->ip4_route; \ + 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_unused const NMPObject *_obj_type_check = _obj; \ + typeof (obj) _obj = (obj); \ \ - nm_assert (NMP_OBJECT_GET_TYPE (_obj) == NMP_OBJECT_TYPE_IP6_ROUTE); \ - &_obj->ip6_route; \ + 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);