diff options
author | Thomas Haller <thaller@redhat.com> | 2017-07-25 06:44:34 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2017-07-25 06:44:34 +0200 |
commit | 394ed959f4addc957697633440dcdb3ebb5c0b7e (patch) | |
tree | 5f1ea30f0b8942a61299d20c9a9c8565422e16c4 | |
parent | c528a89519333c05a137a2fd8af5633361afdade (diff) | |
parent | 5f995123660cd4d0fe412aa4db0f4f767ec312a2 (diff) | |
download | NetworkManager-394ed959f4addc957697633440dcdb3ebb5c0b7e.tar.gz |
core: merge branch 'th/dedup-multi-v2-bgo785004'
https://bugzilla.gnome.org/show_bug.cgi?id=785004
38 files changed, 2663 insertions, 1925 deletions
diff --git a/Makefile.am b/Makefile.am index b540c0c2f7..ed9417a4d6 100644 --- a/Makefile.am +++ b/Makefile.am @@ -414,6 +414,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/c-list-util.h \ shared/nm-utils/nm-dedup-multi.h \ shared/nm-utils/nm-enum-utils.h \ shared/nm-utils/nm-shared-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/c-list-util.c \ shared/nm-utils/nm-dedup-multi.c \ shared/nm-utils/nm-enum-utils.c \ shared/nm-utils/nm-shared-utils.c \ @@ -4437,6 +4439,8 @@ EXTRA_DIST += \ shared/nm-test-libnm-utils.h \ shared/nm-test-utils-impl.c \ shared/nm-utils/c-list.h \ + shared/nm-utils/c-list-util.c \ + shared/nm-utils/c-list-util.h \ shared/nm-utils/gsystem-local-alloc.h \ shared/nm-utils/nm-glib.h \ shared/nm-utils/nm-obj.h \ diff --git a/libnm-core/tests/test-general.c b/libnm-core/tests/test-general.c index cdee4c574f..20b27de9f5 100644 --- a/libnm-core/tests/test-general.c +++ b/libnm-core/tests/test-general.c @@ -25,6 +25,8 @@ #include <string.h> +#include "nm-utils/c-list-util.h" + #include "nm-utils.h" #include "nm-setting-private.h" #include "nm-utils.h" @@ -77,6 +79,103 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int)); /*****************************************************************************/ typedef struct { + int val; + int idx; + CList lst; +} CListSort; + +static int +_c_list_sort_cmp (const CList *lst_a, const CList *lst_b, const void *user_data) +{ + const CListSort *a, *b; + + g_assert (lst_a); + g_assert (lst_b); + g_assert (lst_a != lst_b); + + a = c_list_entry (lst_a, CListSort, lst); + b = c_list_entry (lst_b, CListSort, lst); + + if (a->val < b->val) + return -1; + if (a->val > b->val) + return 1; + return 0; +} + +static void +test_c_list_sort (void) +{ + guint i, n_list, repeat, headless; + CList head, *iter, *iter_prev, *lst; + CListSort elements[30]; + const CListSort *el_prev; + + c_list_init (&head); + c_list_sort (&head, _c_list_sort_cmp, NULL); + g_assert (c_list_length (&head) == 0); + g_assert (c_list_is_empty (&head)); + + for (repeat = 0; repeat < 10; repeat++) { + for (n_list = 1; n_list < G_N_ELEMENTS (elements); n_list++) { + for (headless = 0; headless < 2; headless++) { + c_list_init (&head); + for (i = 0; i < n_list; i++) { + CListSort *el; + + el = &elements[i]; + el->val = nmtst_get_rand_int () % (2*n_list); + el->idx = i; + c_list_link_tail (&head, &el->lst); + } + + if (headless) { + lst = head.next; + c_list_unlink (&head); + lst = c_list_sort_headless (lst, _c_list_sort_cmp, NULL); + g_assert (lst); + g_assert (lst->next); + g_assert (lst->prev); + g_assert (c_list_length (lst) == n_list - 1); + iter_prev = lst->prev; + for (iter = lst; iter != lst; iter = iter->next) { + g_assert (iter); + g_assert (iter->next); + g_assert (iter->prev == iter_prev); + } + c_list_link_before (lst, &head); + } else { + c_list_sort (&head, _c_list_sort_cmp, NULL); + } + + g_assert (!c_list_is_empty (&head)); + g_assert (c_list_length (&head) == n_list); + + el_prev = NULL; + c_list_for_each (iter, &head) { + CListSort *el; + + el = c_list_entry (iter, CListSort, lst); + g_assert (el->idx >= 0 && el->idx < n_list); + g_assert (el == &elements[el->idx]); + if (el_prev) { + g_assert (el_prev->val <= el->val); + if (el_prev->val == el->val) + g_assert (el_prev->idx < el->idx); + g_assert (iter->prev == &el_prev->lst); + g_assert (el_prev->lst.next == iter); + } + el_prev = el; + } + g_assert (head.prev == &el_prev->lst); + } + } + } +} + +/*****************************************************************************/ + +typedef struct { NMDedupMultiObj parent; guint val; guint other; @@ -6078,6 +6177,7 @@ int main (int argc, char **argv) { nmtst_init (&argc, &argv, TRUE); + g_test_add_func ("/core/general/test_c_list_sort", test_c_list_sort); 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); diff --git a/shared/nm-utils/c-list-util.c b/shared/nm-utils/c-list-util.c new file mode 100644 index 0000000000..070323c69d --- /dev/null +++ b/shared/nm-utils/c-list-util.c @@ -0,0 +1,165 @@ +/* -*- 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 "c-list-util.h" + +/*****************************************************************************/ + +/** + * c_list_relink: + * @lst: the head list entry + * + * Takes an invalid list, that has undefined prev pointers. + * Only the next pointers are valid, and the tail's next + * pointer points to %NULL instead of the head. + * + * c_list_relink() fixes the list by updating all prev pointers + * and close the circular linking by pointing the tails' next + * pointer to @lst. + * + * The use of this function is to do a bulk update, that lets the + * list degredate by not updating the prev pointers. At the end, + * the list can be fixed by c_list_relink(). + */ +void +c_list_relink (CList *lst) +{ + CList *ls, *ls_prev; + + ls_prev = lst; + ls = lst->next; + do { + ls->prev = ls_prev; + ls_prev = ls; + ls = ls->next; + } while (ls); + ls_prev->next = lst; + lst->prev = ls_prev; +} + +/*****************************************************************************/ + +static CList * +_c_list_sort (CList *ls, + CListSortCmp cmp, + const void *user_data) +{ + CList *ls1, *ls2; + CList head; + + if (!ls->next) + return ls; + + /* split list in two halfs @ls1 and @ls2. */ + ls1 = ls; + ls2 = ls; + ls = ls->next; + while (ls) { + ls = ls->next; + if (!ls) + break; + ls = ls->next; + ls2 = ls2->next; + } + ls = ls2; + ls2 = ls->next; + ls->next = NULL; + + /* recurse */ + ls1 = _c_list_sort (ls1, cmp, user_data); + if (!ls2) + return ls1; + + ls2 = _c_list_sort (ls2, cmp, user_data); + + /* merge */ + ls = &head; + for (;;) { + /* while invoking the @cmp function, the list + * elements are not properly linked. Don't try to access + * their next/prev pointers. */ + if (cmp (ls1, ls2, user_data) <= 0) { + ls->next = ls1; + ls = ls1; + ls1 = ls1->next; + if (!ls1) + break; + } else { + ls->next = ls2; + ls = ls2; + ls2 = ls2->next; + if (!ls2) + break; + } + } + ls->next = ls1 ?: ls2; + + return head.next; +} + +/** + * c_list_sort_headless: + * @lst: the list. + * @cmp: compare function for sorting. While comparing two + * CList elements, their next/prev pointers are in undefined + * state. + * @user_data: user data for @cmp. + * + * Sorts the list @lst according to @cmp. Contrary to + * c_list_sort(), @lst is not the list head but a + * valid entry as well. This function returns the new + * list head. + */ +CList * +c_list_sort_headless (CList *lst, + CListSortCmp cmp, + const void *user_data) +{ + if (!c_list_is_empty (lst)) { + lst->prev->next = NULL; + lst = _c_list_sort (lst, cmp, user_data); + c_list_relink (lst); + } + return lst; +} + +/** + * c_list_sort: + * @head: the list head. + * @cmp: compare function for sorting. While comparing two + * CList elements, their next/prev pointers are in undefined + * state. + * @user_data: user data for @cmp. + * + * Sorts the list @head according to @cmp. + */ +void +c_list_sort (CList *head, + CListSortCmp cmp, + const void *user_data) +{ + if ( !c_list_is_empty (head) + && head->next->next != head) { + head->prev->next = NULL; + head->next = _c_list_sort (head->next, cmp, user_data); + c_list_relink (head); + } +} diff --git a/shared/nm-utils/c-list-util.h b/shared/nm-utils/c-list-util.h new file mode 100644 index 0000000000..199583cffc --- /dev/null +++ b/shared/nm-utils/c-list-util.h @@ -0,0 +1,43 @@ +/* -*- 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 __C_LIST_UTIL_H__ +#define __C_LIST_UTIL_H__ + +#include "c-list.h" + +/*****************************************************************************/ + +void c_list_relink (CList *lst); + +typedef int (*CListSortCmp) (const CList *a, + const CList *b, + const void *user_data); + +CList *c_list_sort_headless (CList *lst, + CListSortCmp cmp, + const void *user_data); + +void c_list_sort (CList *head, + CListSortCmp cmp, + const void *user_data); + +#endif /* __C_LIST_UTIL_H__ */ diff --git a/shared/nm-utils/nm-dedup-multi.c b/shared/nm-utils/nm-dedup-multi.c index f94bdf853e..000f8a7214 100644 --- a/shared/nm-utils/nm-dedup-multi.c +++ b/shared/nm-utils/nm-dedup-multi.c @@ -927,21 +927,60 @@ nm_dedup_multi_obj_clone (const NMDedupMultiObj *obj) return o; } +gconstpointer * +nm_dedup_multi_objs_to_array_head (const NMDedupMultiHeadEntry *head_entry, + NMDedupMultiFcnSelectPredicate predicate, + gpointer user_data, + guint *out_len) +{ + gconstpointer *result; + CList *iter; + guint i; + + if (!head_entry) { + NM_SET_OUT (out_len, 0); + return NULL; + } + + result = g_new (gconstpointer, head_entry->len + 1); + i = 0; + c_list_for_each (iter, &head_entry->lst_entries_head) { + const NMDedupMultiObj *obj = c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj; + + if ( !predicate + || predicate (obj, user_data)) { + nm_assert (i < head_entry->len); + result[i++] = obj; + } + } + + if (i == 0) { + g_free (result); + NM_SET_OUT (out_len, 0); + return NULL; + } + + nm_assert (i <= head_entry->len); + NM_SET_OUT (out_len, i); + result[i++] = NULL; + return result; +} + GPtrArray * nm_dedup_multi_objs_to_ptr_array_head (const NMDedupMultiHeadEntry *head_entry, NMDedupMultiFcnSelectPredicate predicate, gpointer user_data) { GPtrArray *result; - NMDedupMultiIter iter; + CList *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; + c_list_for_each (iter, &head_entry->lst_entries_head) { + const NMDedupMultiObj *obj = c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj; if ( !predicate || predicate (obj, user_data)) diff --git a/shared/nm-utils/nm-dedup-multi.h b/shared/nm-utils/nm-dedup-multi.h index e44fbe451b..4a9ceffd17 100644 --- a/shared/nm-utils/nm-dedup-multi.h +++ b/shared/nm-utils/nm-dedup-multi.h @@ -23,7 +23,7 @@ #define __NM_DEDUP_MULTI_H__ #include "nm-obj.h" -#include "c-list.h" +#include "c-list-util.h" /*****************************************************************************/ @@ -302,9 +302,9 @@ guint nm_dedup_multi_index_dirty_remove_idx (NMDedupMultiIndex *self, /*****************************************************************************/ typedef struct _NMDedupMultiIter { - const NMDedupMultiHeadEntry *head; + const CList *_head; + const CList *_next; const NMDedupMultiEntry *current; - const NMDedupMultiEntry *next; } NMDedupMultiIter; static inline void @@ -312,11 +312,14 @@ nm_dedup_multi_iter_init (NMDedupMultiIter *iter, const NMDedupMultiHeadEntry *h { g_return_if_fail (iter); - iter->head = head; + if (head && !c_list_is_empty (&head->lst_entries_head)) { + iter->_head = &head->lst_entries_head; + iter->_next = head->lst_entries_head.next; + } else { + iter->_head = NULL; + iter->_next = NULL; + } 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 @@ -324,42 +327,19 @@ nm_dedup_multi_iter_next (NMDedupMultiIter *iter) { g_return_val_if_fail (iter, FALSE); - if (!iter->next) + if (!iter->_next) return FALSE; - /* we always look ahead for the @next. This way, the user + /* 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; + iter->current = c_list_entry (iter->_next, NMDedupMultiEntry, lst_entries); + if (iter->_next->next == iter->_head) + iter->_next = NULL; else - iter->next = c_list_entry (iter->next->lst_entries.next, NMDedupMultiEntry, lst_entries); + iter->_next = iter->_next->next; return TRUE; } -static inline void -nm_dedup_multi_iter_rewind (NMDedupMultiIter *iter) -{ - /* rewind the iterator. - * - * In principle, you can always delete the current entry. - * However, if you delete *all* current entries, the list - * head becomes invalid too and rewinding will crash. - * - * So, either - * - don't modify the list - * - if you modify it: - * - only delete the current entry, don't delete other entries. - * - you may add more entries, however that may make iteration - * confusing. - * - you may rewind the iterator, but only if not all - * entires were deleted. - * - * Use with care. */ - g_return_if_fail (iter); - nm_dedup_multi_iter_init (iter, iter->head); -} - #define nm_dedup_multi_iter_for_each(iter, head_entry) \ for (nm_dedup_multi_iter_init ((iter), (head_entry)); \ nm_dedup_multi_iter_next ((iter)); \ @@ -370,10 +350,27 @@ nm_dedup_multi_iter_rewind (NMDedupMultiIter *iter) typedef gboolean (*NMDedupMultiFcnSelectPredicate) (/* const NMDedupMultiObj * */ gconstpointer obj, gpointer user_data); +gconstpointer *nm_dedup_multi_objs_to_array_head (const NMDedupMultiHeadEntry *head_entry, + NMDedupMultiFcnSelectPredicate predicate, + gpointer user_data, + guint *out_len); GPtrArray *nm_dedup_multi_objs_to_ptr_array_head (const NMDedupMultiHeadEntry *head_entry, NMDedupMultiFcnSelectPredicate predicate, gpointer user_data); +static inline void +nm_dedup_multi_head_entry_sort (const NMDedupMultiHeadEntry *head_entry, + CListSortCmp cmp, + gconstpointer user_data) +{ + if (head_entry) { + /* the head entry can be sorted directly without messing up the + * index to which it belongs. Of course, this does mess up any + * NMDedupMultiIter instances. */ + c_list_sort ((CList *) &head_entry->lst_entries_head, cmp, user_data); + } +} + /*****************************************************************************/ #endif /* __NM_DEDUP_MULTI_H__ */ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 4bf34cd5b2..503b87ed4b 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -2454,16 +2454,19 @@ ndisc_set_router_config (NMNDisc *ndisc, NMDevice *self) gint32 now; GArray *addresses, *dns_servers, *dns_domains; guint len, i; + const NMDedupMultiHeadEntry *head_entry; + NMDedupMultiIter ipconf_iter; if (nm_ndisc_get_node_type (ndisc) != NM_NDISC_NODE_TYPE_ROUTER) return; now = nm_utils_get_monotonic_timestamp_s (); - len = nm_ip6_config_get_num_addresses (priv->ip6_config); - addresses = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscAddress), len); - for (i = 0; i < len; i++) { - const NMPlatformIP6Address *addr = nm_ip6_config_get_address (priv->ip6_config, i); + head_entry = nm_ip6_config_lookup_addresses (priv->ip6_config); + addresses = g_array_sized_new (FALSE, TRUE, sizeof (NMNDiscAddress), + head_entry ? head_entry->len : 0); + nm_dedup_multi_iter_for_each (&ipconf_iter, head_entry) { + const NMPlatformIP6Address *addr = NMP_OBJECT_CAST_IP6_ADDRESS (ipconf_iter.current->obj); NMNDiscAddress *ndisc_addr; if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) @@ -5095,17 +5098,17 @@ arping_manager_probe_terminated (NMArpingManager *arping_manager, ArpingData *da { NMDevice *self; NMDevicePrivate *priv; + NMDedupMultiIter ipconf_iter; const NMPlatformIP4Address *address; gboolean result, success = TRUE; - int i, j; + int i; g_assert (data); self = data->device; priv = NM_DEVICE_GET_PRIVATE (self); for (i = 0; data->configs && data->configs[i]; i++) { - for (j = 0; j < nm_ip4_config_get_num_addresses (data->configs[i]); j++) { - address = nm_ip4_config_get_address (data->configs[i], j); + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, data->configs[i], &address) { result = nm_arping_manager_check_address (arping_manager, address->address); success &= result; @@ -5139,13 +5142,14 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); NMArpingManager *arping_manager; const NMPlatformIP4Address *address; + NMDedupMultiIter ipconf_iter; ArpingData *data; guint timeout; gboolean ret, addr_found; const guint8 *hw_addr; size_t hw_addr_len = 0; GError *error = NULL; - guint i, j; + guint i; g_return_if_fail (NM_IS_DEVICE (self)); g_return_if_fail (configs); @@ -5191,10 +5195,8 @@ ipv4_dad_start (NMDevice *self, NMIP4Config **configs, ArpingCallback cb) data->device = self; for (i = 0; configs[i]; i++) { - for (j = 0; j < nm_ip4_config_get_num_addresses (configs[i]); j++) { - address = nm_ip4_config_get_address (configs[i], j); + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, configs[i], &address) nm_arping_manager_add_address (arping_manager, address->address); - } } g_signal_connect_data (arping_manager, NM_ARPING_MANAGER_PROBE_TERMINATED, @@ -6618,7 +6620,6 @@ dhcp6_state_changed (NMDhcpClient *client, { NMDevice *self = NM_DEVICE (user_data); NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint i; g_return_if_fail (nm_dhcp_client_get_ipv6 (client) == TRUE); g_return_if_fail (!ip6_config || NM_IS_IP6_CONFIG (ip6_config)); @@ -6635,10 +6636,11 @@ dhcp6_state_changed (NMDhcpClient *client, && event_id && priv->dhcp6.event_id && !strcmp (event_id, priv->dhcp6.event_id)) { - for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) { - nm_ip6_config_add_address (priv->dhcp6.ip6_config, - nm_ip6_config_get_address (ip6_config, i)); - } + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *a; + + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6_config, &a) + nm_ip6_config_add_address (priv->dhcp6.ip6_config, a); } else { g_clear_object (&priv->dhcp6.ip6_config); g_clear_pointer (&priv->dhcp6.event_id, g_free); @@ -6978,7 +6980,6 @@ check_and_add_ipv6ll_addr (NMDevice *self) NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); int ip_ifindex = nm_device_get_ip_ifindex (self); struct in6_addr lladdr; - guint i, n; NMConnection *connection; NMSettingIP6Config *s_ip6 = NULL; GError *error = NULL; @@ -6987,11 +6988,10 @@ check_and_add_ipv6ll_addr (NMDevice *self) return; if (priv->ip6_config) { - n = nm_ip6_config_get_num_addresses (priv->ip6_config); - for (i = 0; i < n; i++) { - const NMPlatformIP6Address *addr; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *addr; - addr = nm_ip6_config_get_address (priv->ip6_config, i); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, priv->ip6_config, &addr) { if ( IN6_IS_ADDR_LINKLOCAL (&addr->address) && !(addr->n_ifa_flags & IFA_F_DADFAILED)) { /* Already have an LL address, nothing to do */ @@ -8292,15 +8292,15 @@ start_sharing (NMDevice *self, NMIP4Config *config) char str_addr[INET_ADDRSTRLEN + 1]; char str_mask[INET_ADDRSTRLEN + 1]; guint32 netmask, network; - const NMPlatformIP4Address *ip4_addr; + const NMPlatformIP4Address *ip4_addr = NULL; const char *ip_iface; g_return_val_if_fail (config != NULL, FALSE); ip_iface = nm_device_get_ip_iface (self); - ip4_addr = nm_ip4_config_get_address (config, 0); - if (!ip4_addr || !ip4_addr->address) + ip4_addr = nm_ip4_config_get_first_address (config); + if (ip4_addr || !ip4_addr->address) return FALSE; netmask = nm_utils_ip4_prefix_to_netmask (ip4_addr->plen); @@ -8513,7 +8513,8 @@ dad6_get_pending_addresses (NMDevice *self) priv->wwan_ip6_config }; const NMPlatformIP6Address *addr, *pl_addr; NMIP6Config *dad6_config = NULL; - guint i, j, num; + NMDedupMultiIter ipconf_iter; + guint i; int ifindex; ifindex = nm_device_get_ip_ifindex (self); @@ -8524,9 +8525,8 @@ dad6_get_pending_addresses (NMDevice *self) */ for (i = 0; i < G_N_ELEMENTS (confs); i++) { if (confs[i]) { - num = nm_ip6_config_get_num_addresses (confs[i]); - for (j = 0; j < num; j++) { - addr = nm_ip6_config_get_address (confs[i], j); + + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, confs[i], &addr) { pl_addr = nm_platform_ip6_address_get (nm_device_get_platform (self), ifindex, addr->address); @@ -8738,16 +8738,15 @@ static void _update_ip4_address (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint32 addr; + const NMPlatformIP4Address *address; g_return_if_fail (NM_IS_DEVICE (self)); if ( priv->ip4_config && ip_config_valid (priv->state) - && nm_ip4_config_get_num_addresses (priv->ip4_config)) { - addr = nm_ip4_config_get_address (priv->ip4_config, 0)->address; - if (addr != priv->ip4_address) { - priv->ip4_address = addr; + && (address = nm_ip4_config_get_first_address (priv->ip4_config))) { + if (address->address != priv->ip4_address) { + priv->ip4_address = address->address; _notify (self, PROP_IP4_ADDRESS); } } @@ -10598,7 +10597,7 @@ find_ip4_lease_config (NMDevice *self, nm_device_get_ip4_route_metric (self)); for (liter = leases; liter && !found; liter = liter->next) { NMIP4Config *lease_config = liter->data; - const NMPlatformIP4Address *address = nm_ip4_config_get_address (lease_config, 0); + const NMPlatformIP4Address *address = nm_ip4_config_get_first_address (lease_config); guint32 gateway = nm_ip4_config_get_gateway (lease_config); g_assert (address); @@ -10624,23 +10623,24 @@ capture_lease_config (NMDevice *self, NMSettingsConnection *const*connections; guint i; gboolean dhcp_used = FALSE; + NMDedupMultiIter ipconf_iter; /* Ensure at least one address on the device has a non-infinite lifetime, * otherwise DHCP cannot possibly be active on the device right now. */ if (ext_ip4_config && out_ip4_config) { - for (i = 0; i < nm_ip4_config_get_num_addresses (ext_ip4_config); i++) { - const NMPlatformIP4Address *addr = nm_ip4_config_get_address (ext_ip4_config, i); + const NMPlatformIP4Address *addr; + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ext_ip4_config, &addr) { if (addr->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) { dhcp_used = TRUE; break; } } } else if (ext_ip6_config && out_ip6_config) { - for (i = 0; i < nm_ip6_config_get_num_addresses (ext_ip6_config); i++) { - const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ext_ip6_config, i); + const NMPlatformIP6Address *addr; + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ext_ip6_config, &addr) { if (addr->lifetime != NM_PLATFORM_LIFETIME_PERMANENT) { dhcp_used = TRUE; break; @@ -12227,15 +12227,13 @@ static char * find_dhcp4_address (NMDevice *self) { NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); - guint i, n; + const NMPlatformIP4Address *a; + NMDedupMultiIter ipconf_iter; if (!priv->ip4_config) return NULL; - n = nm_ip4_config_get_num_addresses (priv->ip4_config); - for (i = 0; i < n; i++) { - const NMPlatformIP4Address *a = nm_ip4_config_get_address (priv->ip4_config, i); - + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, priv->ip4_config, &a) { if (a->addr_source == NM_IP_CONFIG_SOURCE_DHCP) return g_strdup (nm_utils_inet4_ntop (a->address, NULL)); } diff --git a/src/devices/wwan/nm-modem.c b/src/devices/wwan/nm-modem.c index c6885cef7d..76df89e58b 100644 --- a/src/devices/wwan/nm-modem.c +++ b/src/devices/wwan/nm-modem.c @@ -682,7 +682,7 @@ nm_modem_ip4_pre_commit (NMModem *modem, */ if ( priv->ip4_method == NM_MODEM_IP_METHOD_STATIC || priv->ip4_method == NM_MODEM_IP_METHOD_AUTO) { - const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, 0); + const NMPlatformIP4Address *address = nm_ip4_config_get_first_address (config); g_assert (address); if (address->plen == 32) @@ -698,7 +698,8 @@ nm_modem_emit_ip6_config_result (NMModem *self, GError *error) { NMModemPrivate *priv = NM_MODEM_GET_PRIVATE (self); - guint i, num; + NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *addr; gboolean do_slaac = TRUE; if (error) { @@ -710,11 +711,7 @@ nm_modem_emit_ip6_config_result (NMModem *self, /* If the IPv6 configuration only included a Link-Local address, then * we have to run SLAAC to get the full IPv6 configuration. */ - num = nm_ip6_config_get_num_addresses (config); - g_assert (num > 0); - for (i = 0; i < num; i++) { - const NMPlatformIP6Address * addr = nm_ip6_config_get_address (config, i); - + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, config, &addr) { if (IN6_IS_ADDR_LINKLOCAL (&addr->address)) { if (!priv->iid.id) priv->iid.id = ((guint64 *)(&addr->address.s6_addr))[1]; diff --git a/src/dhcp/nm-dhcp-systemd.c b/src/dhcp/nm-dhcp-systemd.c index 2dca9c83d8..e720400e5d 100644 --- a/src/dhcp/nm-dhcp-systemd.c +++ b/src/dhcp/nm-dhcp-systemd.c @@ -344,12 +344,13 @@ lease_to_ip4_config (NMDedupMultiIndex *multi_idx, if (sd_dhcp_route_get_destination (routes[i], &a) < 0) continue; - route.network = a.s_addr; if ( sd_dhcp_route_get_destination_prefix_length (routes[i], &plen) < 0 || plen > 32) continue; + route.plen = plen; + route.network = nm_utils_ip4_address_clear_host_address (a.s_addr, plen); if (sd_dhcp_route_get_gateway (routes[i], &a) < 0) continue; diff --git a/src/dhcp/nm-dhcp-utils.c b/src/dhcp/nm-dhcp-utils.c index 3f17110410..520046395a 100644 --- a/src/dhcp/nm-dhcp-utils.c +++ b/src/dhcp/nm-dhcp-utils.c @@ -86,7 +86,7 @@ ip4_process_dhcpcd_rfc3442_routes (const char *iface, } else { _LOG2I (LOGD_DHCP4, iface, " classless static route %s/%d gw %s", *r, rt_cidr, *(r + 1)); memset (&route, 0, sizeof (route)); - route.network = rt_addr; + route.network = nm_utils_ip4_address_clear_host_address (rt_addr, rt_cidr); route.plen = rt_cidr; route.gateway = rt_route; route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; @@ -144,8 +144,7 @@ process_dhclient_rfc3442_route (const char **octets, goto error; } g_free (str_addr); - tmp_addr &= nm_utils_ip4_prefix_to_netmask ((guint32) tmp); - route->network = tmp_addr; + route->network = nm_utils_ip4_address_clear_host_address (tmp_addr, tmp); } /* Handle next hop */ @@ -327,6 +326,8 @@ process_classful_routes (const char *iface, route.rt_source = NM_IP_CONFIG_SOURCE_DHCP; route.metric = priority; + route.network = nm_utils_ip4_address_clear_host_address (route.network, route.plen); + nm_ip4_config_add_route (ip4_config, &route); _LOG2I (LOGD_DHCP, iface, " static route %s", nm_platform_ip4_route_to_string (&route, NULL, 0)); diff --git a/src/dhcp/tests/test-dhcp-dhclient.c b/src/dhcp/tests/test-dhcp-dhclient.c index c8e225e441..2e68a6e081 100644 --- a/src/dhcp/tests/test-dhcp-dhclient.c +++ b/src/dhcp/tests/test-dhcp-dhclient.c @@ -37,6 +37,8 @@ #define DEBUG 1 +static const int IFINDEX = 5; + static void test_config (const char *orig, const char *expected, @@ -910,7 +912,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 (multi_idx, "wlan0", -1, contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, "wlan0", IFINDEX, contents, FALSE, now); g_assert_cmpint (g_slist_length (leases), ==, 2); /* IP4Config #1 */ @@ -920,7 +922,7 @@ test_read_lease_ip4_config_basic (void) /* Address */ g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); expected_addr = nmtst_inet4_from_string ("192.168.1.180"); - addr = nm_ip4_config_get_address (config, 0); + addr = _nmtst_nm_ip4_config_get_address (config, 0); g_assert_cmpint (addr->address, ==, expected_addr); g_assert_cmpint (addr->peer_address, ==, expected_addr); g_assert_cmpint (addr->plen, ==, 24); @@ -943,7 +945,7 @@ test_read_lease_ip4_config_basic (void) /* Address */ g_assert_cmpint (nm_ip4_config_get_num_addresses (config), ==, 1); expected_addr = nmtst_inet4_from_string ("10.77.52.141"); - addr = nm_ip4_config_get_address (config, 0); + addr = _nmtst_nm_ip4_config_get_address (config, 0); g_assert_cmpint (addr->address, ==, expected_addr); g_assert_cmpint (addr->peer_address, ==, expected_addr); g_assert_cmpint (addr->plen, ==, 8); @@ -985,7 +987,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 (multi_idx, "wlan0", -1, contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, "wlan0", IFINDEX, contents, FALSE, now); g_assert (leases == NULL); g_date_time_unref (now); @@ -1008,7 +1010,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 (multi_idx, "wlan0", -1, contents, FALSE, now); + leases = nm_dhcp_dhclient_read_lease_ip_configs (multi_idx, "wlan0", IFINDEX, 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 f3fa963e52..f31d7d6456 100644 --- a/src/dhcp/tests/test-dhcp-utils.c +++ b/src/dhcp/tests/test-dhcp-utils.c @@ -105,7 +105,7 @@ test_generic_options (void) /* IP4 address */ g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); - address = nm_ip4_config_get_address (ip4_config, 0); + address = _nmtst_nm_ip4_config_get_address (ip4_config, 0); g_assert (inet_pton (AF_INET, expected_addr, &tmp) > 0); g_assert (address->address == tmp); g_assert (address->peer_address == tmp); @@ -175,7 +175,7 @@ test_wins_options (void) /* IP4 address */ g_assert_cmpint (nm_ip4_config_get_num_addresses (ip4_config), ==, 1); - address = nm_ip4_config_get_address (ip4_config, 0); + address = _nmtst_nm_ip4_config_get_address (ip4_config, 0); g_assert (address); g_assert_cmpint (nm_ip4_config_get_num_wins (ip4_config), ==, 2); g_assert (inet_pton (AF_INET, expected_wins1, &tmp) > 0); @@ -624,7 +624,7 @@ test_ip4_missing_prefix (const char *ip, guint32 expected_prefix) 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); + address = _nmtst_nm_ip4_config_get_address (ip4_config, 0); g_assert (address); g_assert_cmpint (address->plen, ==, expected_prefix); @@ -668,7 +668,7 @@ test_ip4_prefix_classless (void) 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); + address = _nmtst_nm_ip4_config_get_address (ip4_config, 0); g_assert (address); g_assert_cmpint (address->plen, ==, 22); diff --git a/src/dns/nm-dns-dnsmasq.c b/src/dns/nm-dns-dnsmasq.c index d5b51af25e..cb311dffda 100644 --- a/src/dns/nm-dns-dnsmasq.c +++ b/src/dns/nm-dns-dnsmasq.c @@ -80,21 +80,18 @@ get_ip4_rdns_domains (NMIP4Config *ip4) { char **strv; GPtrArray *domains = NULL; - guint i; NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Address *address; const NMPlatformIP4Route *route; g_return_val_if_fail (ip4 != NULL, NULL); domains = g_ptr_array_sized_new (5); - for (i = 0; i < nm_ip4_config_get_num_addresses (ip4); i++) { - const NMPlatformIP4Address *address = nm_ip4_config_get_address (ip4, i); - + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) nm_utils_get_reverse_dns_domains_ip4 (address->address, address->plen, domains); - } - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) + nm_ip_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 */ @@ -111,21 +108,18 @@ get_ip6_rdns_domains (NMIP6Config *ip6) { char **strv; GPtrArray *domains = NULL; - guint i; NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *address; const NMPlatformIP6Route *route; g_return_val_if_fail (ip6 != NULL, NULL); domains = g_ptr_array_sized_new (5); - for (i = 0; i < nm_ip6_config_get_num_addresses (ip6); i++) { - const NMPlatformIP6Address *address = nm_ip6_config_get_address (ip6, i); - + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address) nm_utils_get_reverse_dns_domains_ip6 (&address->address, address->plen, domains); - } - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) + nm_ip_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 */ diff --git a/src/dnsmasq/nm-dnsmasq-manager.c b/src/dnsmasq/nm-dnsmasq-manager.c index f76c983dcd..3296cd0e73 100644 --- a/src/dnsmasq/nm-dnsmasq-manager.c +++ b/src/dnsmasq/nm-dnsmasq-manager.c @@ -162,7 +162,7 @@ create_dm_cmd_line (const char *iface, const NMPlatformIP4Address *listen_address; guint i, n; - listen_address = nm_ip4_config_get_address (ip4_config, 0); + listen_address = nm_ip4_config_get_first_address (ip4_config); g_return_val_if_fail (listen_address, NULL); dm_binary = nm_utils_find_helper ("dnsmasq", DNSMASQ_PATH, error); diff --git a/src/nm-core-utils.c b/src/nm-core-utils.c index 81a58ad3ab..2748619695 100644 --- a/src/nm-core-utils.c +++ b/src/nm-core-utils.c @@ -287,15 +287,17 @@ nm_utils_ip4_address_clear_host_address (in_addr_t addr, guint8 plen) * @plen: prefix length of network * * Note: this function is self assignment safe, to update @src inplace, set both - * @dst and @src to the same destination. + * @dst and @src to the same destination or set @src NULL. */ const struct in6_addr * nm_utils_ip6_address_clear_host_address (struct in6_addr *dst, const struct in6_addr *src, guint8 plen) { g_return_val_if_fail (plen <= 128, NULL); - g_return_val_if_fail (src, NULL); g_return_val_if_fail (dst, NULL); + if (!src) + src = dst; + if (plen < 128) { guint nbytes = plen / 8; guint nbits = plen % 8; diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c index f6362bccf6..fc209fc852 100644 --- a/src/nm-default-route-manager.c +++ b/src/nm-default-route-manager.c @@ -371,7 +371,7 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self, */ if ( !entry && (has_ifindex_synced || ifindex_to_flush == route->ifindex)) { - vtable->vt->route_delete_default (priv->platform, route->ifindex, route->metric); + nm_platform_ip_route_delete (priv->platform, NMP_OBJECT_UP_CAST (route)); changed = TRUE; } } diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c index 2393e8035f..cb7bb3c5a3 100644 --- a/src/nm-dispatcher.c +++ b/src/nm-dispatcher.c @@ -114,6 +114,7 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder) { GVariantBuilder int_builder; NMDedupMultiIter ipconf_iter; + gboolean first; guint n, i; const NMPlatformIP4Address *addr; const NMPlatformIP4Route *route; @@ -121,15 +122,15 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder) /* Addresses */ g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau")); - n = nm_ip4_config_get_num_addresses (ip4); - for (i = 0; i < n; i++) { - addr = nm_ip4_config_get_address (ip4, i); + first = TRUE; + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &addr) { array[0] = addr->address; array[1] = addr->plen; - array[2] = (i == 0) ? nm_ip4_config_get_gateway (ip4) : 0; + array[2] = first ? nm_ip4_config_get_gateway (ip4) : 0; g_variant_builder_add (&int_builder, "@au", g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, array, 3, sizeof (guint32))); + first = FALSE; } g_variant_builder_add (builder, "{sv}", "addresses", @@ -164,7 +165,7 @@ dump_ip4_to_props (NMIP4Config *ip4, GVariantBuilder *builder) /* Static routes */ g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("aau")); - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) { + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &route) { array[0] = route->network; array[1] = route->plen; array[2] = route->gateway; @@ -184,24 +185,26 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder) GVariantBuilder int_builder; NMDedupMultiIter ipconf_iter; guint n, i; + gboolean first; const NMPlatformIP6Address *addr; - const struct in6_addr *gw_bytes; const NMPlatformIP6Route *route; GVariant *ip, *gw; /* Addresses */ g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuay)")); - n = nm_ip6_config_get_num_addresses (ip6); - for (i = 0; i < n; i++) { - addr = nm_ip6_config_get_address (ip6, i); - gw_bytes = nm_ip6_config_get_gateway (ip6); + + first = TRUE; + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &addr) { ip = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &addr->address, sizeof (struct in6_addr), 1); gw = g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - (i == 0 && gw_bytes) ? gw_bytes : &in6addr_any, + first + ? (nm_ip6_config_get_gateway (ip6) ?: &in6addr_any) + : &in6addr_any, sizeof (struct in6_addr), 1); g_variant_builder_add (&int_builder, "(@ayu@ay)", ip, addr->plen, gw); + first = FALSE; } g_variant_builder_add (builder, "{sv}", "addresses", @@ -231,7 +234,7 @@ dump_ip6_to_props (NMIP6Config *ip6, GVariantBuilder *builder) /* Static routes */ g_variant_builder_init (&int_builder, G_VARIANT_TYPE ("a(ayuayu)")); - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &route) { + nm_ip_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 8b55a2cdc2..9300ea9010 100644 --- a/src/nm-ip4-config.c +++ b/src/nm-ip4-config.c @@ -46,6 +46,32 @@ G_STATIC_ASSERT (G_MAXUINT >= 0xFFFFFFFF); /*****************************************************************************/ +static gboolean +_route_valid (const NMPlatformIP4Route *r) +{ + return r + && r->plen <= 32 + && r->network == nm_utils_ip4_address_clear_host_address (r->network, r->plen); +} + +/*****************************************************************************/ + +gboolean +nm_ip_config_obj_id_equal_ip4_address (const NMPlatformIP4Address *a, + const NMPlatformIP4Address *b) +{ + return a->address == b->address + && a->plen == b->plen + && ((a->peer_address ^ b->peer_address) & nm_utils_ip4_prefix_to_netmask (a->plen)) == 0; +} + +gboolean +nm_ip_config_obj_id_equal_ip6_address (const NMPlatformIP6Address *a, + const NMPlatformIP6Address *b) +{ + return IN6_ARE_ADDR_EQUAL (&a->address, &b->address); +} + gboolean nm_ip_config_obj_id_equal_ip4_route (const NMPlatformIP4Route *r_a, const NMPlatformIP4Route *r_b) @@ -71,8 +97,15 @@ _idx_obj_id_hash (const NMDedupMultiIdxType *idx_type, switch (NMP_OBJECT_GET_TYPE (o)) { case NMP_OBJECT_TYPE_IP4_ADDRESS: + h = 1550630563; + h = NM_HASH_COMBINE (h, o->ip4_address.address); + h = NM_HASH_COMBINE (h, o->ip_address.plen); + h = NM_HASH_COMBINE (h, nm_utils_ip4_address_clear_host_address (o->ip4_address.peer_address, o->ip_address.plen)); + break; case NMP_OBJECT_TYPE_IP6_ADDRESS: - g_return_val_if_reached (0); + h = 851146661; + h = NM_HASH_COMBINE_IN6_ADDR (h, &o->ip6_address.address); + break; case NMP_OBJECT_TYPE_IP4_ROUTE: h = 40303327; h = NM_HASH_COMBINE (h, o->ip4_route.network); @@ -102,8 +135,9 @@ _idx_obj_id_equal (const NMDedupMultiIdxType *idx_type, switch (NMP_OBJECT_GET_TYPE (o_a)) { case NMP_OBJECT_TYPE_IP4_ADDRESS: + return nm_ip_config_obj_id_equal_ip4_address (NMP_OBJECT_CAST_IP4_ADDRESS (o_a), NMP_OBJECT_CAST_IP4_ADDRESS (o_b)); case NMP_OBJECT_TYPE_IP6_ADDRESS: - g_return_val_if_reached (FALSE); + return nm_ip_config_obj_id_equal_ip6_address (NMP_OBJECT_CAST_IP6_ADDRESS (o_a), NMP_OBJECT_CAST_IP6_ADDRESS (o_b)); case NMP_OBJECT_TYPE_IP4_ROUTE: return nm_ip_config_obj_id_equal_ip4_route (&o_a->ip4_route, &o_b->ip4_route); case NMP_OBJECT_TYPE_IP6_ROUTE: @@ -129,6 +163,120 @@ nm_ip_config_dedup_multi_idx_type_init (NMIPConfigDedupMultiIdxType *idx_type, /*****************************************************************************/ +gboolean +_nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx, + NMIPConfigDedupMultiIdxType *idx_type, + int ifindex, + const NMPObject *obj_new, + const NMPlatformObject *pl_new) +{ + NMPObject obj_new_stackinit; + const NMDedupMultiEntry *entry_old; + + nm_assert (multi_idx); + nm_assert (idx_type); + nm_assert (NM_IN_SET (idx_type->obj_type, NMP_OBJECT_TYPE_IP4_ADDRESS, + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ADDRESS, + NMP_OBJECT_TYPE_IP6_ROUTE)); + nm_assert (ifindex > 0); + + /* we go through extra lengths to accept a full obj_new object. That one, + * can be reused by increasing the ref-count. */ + if (!obj_new) { + nm_assert (pl_new); + obj_new = nmp_object_stackinit (&obj_new_stackinit, idx_type->obj_type, pl_new); + obj_new_stackinit.object.ifindex = ifindex; + } else { + nm_assert (!pl_new); + nm_assert (NMP_OBJECT_GET_TYPE (obj_new) == idx_type->obj_type); + if (obj_new->object.ifindex != ifindex) { + obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new); + obj_new_stackinit.object.ifindex = ifindex; + } + } + nm_assert (NMP_OBJECT_GET_TYPE (obj_new) == idx_type->obj_type); + nm_assert (nmp_object_is_alive (obj_new)); + + entry_old = nm_dedup_multi_index_lookup_obj (multi_idx, &idx_type->parent, obj_new); + + if (entry_old) { + gboolean modified = FALSE; + const NMPObject *obj_old = entry_old->obj; + + if (nmp_object_equal (obj_new, obj_old)) + return FALSE; + + switch (idx_type->obj_type) { + case NMP_OBJECT_TYPE_IP4_ADDRESS: + case NMP_OBJECT_TYPE_IP6_ADDRESS: + /* we want to keep the maximum addr_source. But since we expect + * that usually we already add the maxiumum right away, we first try to + * add the new address (replacing the old one). Only if we later + * find out that addr_source is now lower, we fix it. + */ + if (obj_new->ip_address.addr_source < obj_old->ip_address.addr_source) { + obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_address.addr_source = obj_old->ip_address.addr_source; + modified = TRUE; + } + + /* for addresses that we read from the kernel, we keep the timestamps as defined + * by the previous source (item_old). The reason is, that the other source configured the lifetimes + * with "what should be" and the kernel values are "what turned out after configuring it". + * + * For other sources, the longer lifetime wins. */ + if ( ( obj_new->ip_address.addr_source == NM_IP_CONFIG_SOURCE_KERNEL + && obj_old->ip_address.addr_source != NM_IP_CONFIG_SOURCE_KERNEL) + || nm_platform_ip_address_cmp_expiry (NMP_OBJECT_CAST_IP_ADDRESS (obj_old), NMP_OBJECT_CAST_IP_ADDRESS(obj_new)) > 0) { + obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_address.timestamp = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->timestamp; + obj_new_stackinit.ip_address.lifetime = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->lifetime; + obj_new_stackinit.ip_address.preferred = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->preferred; + modified = TRUE; + } + break; + case NMP_OBJECT_TYPE_IP4_ROUTE: + case NMP_OBJECT_TYPE_IP6_ROUTE: + /* 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 (obj_new->ip_route.rt_source < obj_old->ip_route.rt_source) { + obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new); + obj_new_stackinit.ip_route.rt_source = obj_old->ip_route.rt_source; + modified = TRUE; + } + break; + default: + nm_assert_not_reached (); + break; + } + + if ( modified + && nmp_object_equal (obj_new, obj_old)) + return FALSE; + } + + if (!nm_dedup_multi_index_add_full (multi_idx, + &idx_type->parent, + obj_new, + NM_DEDUP_MULTI_IDX_MODE_APPEND, + NULL, + entry_old ?: NM_DEDUP_MULTI_ENTRY_MISSING, + NULL, + NULL, + NULL)) { + nm_assert_not_reached (); + return FALSE; + } + + return TRUE; +} + +/*****************************************************************************/ + NM_GOBJECT_PROPERTIES_DEFINE (NMIP4Config, PROP_MULTI_IDX, PROP_IFINDEX, @@ -156,7 +304,6 @@ typedef struct { NMIPConfigSource mtu_source; gint dns_priority; gint64 route_metric; - GArray *addresses; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; @@ -166,8 +313,14 @@ typedef struct { GArray *wins; GVariant *address_data_variant; GVariant *addresses_variant; + GVariant *route_data_variant; + GVariant *routes_variant; NMDedupMultiIndex *multi_idx; union { + NMIPConfigDedupMultiIdxType idx_ip4_addresses_; + NMDedupMultiIdxType idx_ip4_addresses; + }; + union { NMIPConfigDedupMultiIdxType idx_ip4_routes_; NMDedupMultiIdxType idx_ip4_routes; }; @@ -188,20 +341,21 @@ G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_EXPORTED_OBJECT) /*****************************************************************************/ -static void _add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Route *new); +static void _add_address (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Address *new); +static void _add_route (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Route *new); /*****************************************************************************/ int -nm_ip4_config_get_ifindex (const NMIP4Config *config) +nm_ip4_config_get_ifindex (const NMIP4Config *self) { - return NM_IP4_CONFIG_GET_PRIVATE (config)->ifindex; + return NM_IP4_CONFIG_GET_PRIVATE (self)->ifindex; } NMDedupMultiIndex * -nm_ip4_config_get_multi_idx (const NMIP4Config *config) +nm_ip4_config_get_multi_idx (const NMIP4Config *self) { - return NM_IP4_CONFIG_GET_PRIVATE (config)->multi_idx; + return NM_IP4_CONFIG_GET_PRIVATE (self)->multi_idx; } /*****************************************************************************/ @@ -215,45 +369,64 @@ _ipv4_is_zeronet (in_addr_t network) /*****************************************************************************/ -static const NMDedupMultiHeadEntry * -_idx_ip4_routes (const NMIP4Config *self) +const NMDedupMultiHeadEntry * +nm_ip4_config_lookup_addresses (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, + &priv->idx_ip4_addresses, NULL); } -static const NMPlatformIP4Route * -_entry_iter_get_ip4_route (const CList *iter) +void +nm_ip_config_iter_ip4_address_init (NMDedupMultiIter *ipconf_iter, const NMIP4Config *self) { - const NMDedupMultiEntry *e = c_list_entry (iter, NMDedupMultiEntry, lst_entries); - const NMPObject *o = e->obj; + g_return_if_fail (NM_IS_IP4_CONFIG (self)); + nm_dedup_multi_iter_init (ipconf_iter, nm_ip4_config_lookup_addresses (self)); +} - nm_assert (o); - nm_assert (NMP_OBJECT_GET_TYPE (o) == NMP_OBJECT_TYPE_IP4_ROUTE); - return &o->ip4_route; +/*****************************************************************************/ + +const NMDedupMultiHeadEntry * +nm_ip4_config_lookup_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); } void -nm_ip4_config_iter_ip4_route_init (NMDedupMultiIter *ipconf_iter, const NMIP4Config *self) +nm_ip_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)); + nm_dedup_multi_iter_init (ipconf_iter, nm_ip4_config_lookup_routes (self)); } -gboolean -nm_ip4_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP4Route **out_route) +/*****************************************************************************/ + +static void +_notify_addresses (NMIP4Config *self) { - gboolean has_next; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); - has_next = nm_dedup_multi_iter_next (ipconf_iter); - if (has_next) { - nm_assert (NMP_OBJECT_GET_TYPE (ipconf_iter->current->obj) == NMP_OBJECT_TYPE_IP4_ROUTE); - NM_SET_OUT (out_route, &(((const NMPObject *) ipconf_iter->current->obj)->ip4_route)); - } - return has_next; + nm_clear_g_variant (&priv->address_data_variant); + nm_clear_g_variant (&priv->addresses_variant); + _notify (self, PROP_ADDRESS_DATA); + _notify (self, PROP_ADDRESSES); +} + +static void +_notify_routes (NMIP4Config *self) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + + nm_clear_g_variant (&priv->route_data_variant); + nm_clear_g_variant (&priv->routes_variant); + _notify (self, PROP_ROUTE_DATA); + _notify (self, PROP_ROUTES); } /*****************************************************************************/ @@ -322,14 +495,6 @@ nm_ip4_config_capture_resolv_conf (GArray *nameservers, return changed; } -static gboolean -addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b) -{ - return a->address == b->address - && a->plen == b->plen - && ((a->peer_address ^ b->peer_address) & nm_utils_ip4_prefix_to_netmask (a->plen)) == 0; -} - /*****************************************************************************/ static gint @@ -340,11 +505,12 @@ _addresses_sort_cmp_get_prio (in_addr_t addr) return 1; } -static gint -_addresses_sort_cmp (gconstpointer a, gconstpointer b) +static int +_addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data) { gint p1, p2; - const NMPlatformIP4Address *a1 = a, *a2 = b; + const NMPlatformIP4Address *a1 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) a)); + const NMPlatformIP4Address *a2 = NMP_OBJECT_CAST_IP4_ADDRESS (*((const NMPObject **) b)); guint32 n1, n2; /* Sort by address type. For example link local will @@ -374,21 +540,11 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b) /*****************************************************************************/ -static void -notify_addresses (NMIP4Config *self) -{ - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); - - nm_clear_g_variant (&priv->address_data_variant); - nm_clear_g_variant (&priv->addresses_variant); - _notify (self, PROP_ADDRESS_DATA); - _notify (self, PROP_ADDRESSES); -} - -static gint -sort_captured_addresses (gconstpointer a, gconstpointer b) +static int +sort_captured_addresses (const CList *lst_a, const CList *lst_b, gconstpointer user_data) { - const NMPlatformIP4Address *addr_a = a, *addr_b = b; + const NMPlatformIP4Address *addr_a = NMP_OBJECT_CAST_IP4_ADDRESS (c_list_entry (lst_a, NMDedupMultiEntry, lst_entries)->obj); + const NMPlatformIP4Address *addr_b = NMP_OBJECT_CAST_IP4_ADDRESS (c_list_entry (lst_b, NMDedupMultiEntry, lst_entries)->obj); /* Primary addresses first */ return NM_FLAGS_HAS (addr_a->n_ifa_flags, IFA_F_SECONDARY) - @@ -398,31 +554,50 @@ sort_captured_addresses (gconstpointer a, gconstpointer b) NMIP4Config * nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf) { - NMIP4Config *config; + NMIP4Config *self; NMIP4ConfigPrivate *priv; guint32 lowest_metric; guint32 old_gateway = 0; gboolean old_has_gateway = FALSE; - const NMDedupMultiHeadEntry *pl_head_entry; + const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter iter; const NMPObject *plobj = NULL; + gboolean has_addresses = FALSE; + + nm_assert (ifindex > 0); /* Slaves have no IP configuration */ if (nm_platform_link_get_master (platform, ifindex) > 0) return NULL; - config = nm_ip4_config_new (multi_idx, ifindex); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); + self = nm_ip4_config_new (multi_idx, ifindex); + priv = NM_IP4_CONFIG_GET_PRIVATE (self); - g_array_unref (priv->addresses); - - priv->addresses = nm_platform_ip4_address_get_all (platform, ifindex); - g_array_sort (priv->addresses, sort_captured_addresses); + head_entry = nm_platform_lookup_addrroute (platform, + NMP_OBJECT_TYPE_IP4_ADDRESS, + ifindex); + if (head_entry) { + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + if (!nm_dedup_multi_index_add (priv->multi_idx, + &priv->idx_ip4_addresses, + plobj, + NM_DEDUP_MULTI_IDX_MODE_APPEND, + NULL, + NULL)) + nm_assert_not_reached (); + } + head_entry = nm_ip4_config_lookup_addresses (self); + nm_assert (head_entry); + nm_dedup_multi_head_entry_sort (head_entry, + sort_captured_addresses, + NULL); + has_addresses = TRUE; + } - pl_head_entry = nm_platform_lookup_route_visible (platform, - NMP_OBJECT_TYPE_IP4_ROUTE, - ifindex, - FALSE); + head_entry = nm_platform_lookup_route_visible (platform, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex, + FALSE); /* Extract gateway from default route */ old_gateway = priv->gateway; @@ -430,7 +605,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i lowest_metric = G_MAXUINT32; priv->has_gateway = FALSE; - nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj); if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route) @@ -447,8 +622,7 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i * routes have their route metrics explicitly set. */ priv->route_metric = priv->has_gateway ? (gint64) lowest_metric : (gint64) -1; - nm_dedup_multi_iter_rewind (&iter); - nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj); if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) @@ -465,63 +639,66 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i */ continue; } - _add_route (config, plobj, NULL); + _add_route (self, plobj, NULL); } /* If the interface has the default route, and has IPv4 addresses, capture * nameservers from /etc/resolv.conf. */ - if (priv->addresses->len && priv->has_gateway && capture_resolv_conf) { + if (has_addresses && priv->has_gateway && capture_resolv_conf) { if (nm_ip4_config_capture_resolv_conf (priv->nameservers, priv->dns_options, NULL)) - _notify (config, PROP_NAMESERVERS); + _notify (self, PROP_NAMESERVERS); } /* actually, nobody should be connected to the signal, just to be sure, notify */ - _notify (config, PROP_ADDRESS_DATA); - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ADDRESSES); - _notify (config, PROP_ROUTES); + _notify_addresses (self); + _notify_routes (self); if ( priv->gateway != old_gateway || priv->has_gateway != old_has_gateway) - _notify (config, PROP_GATEWAY); + _notify (self, PROP_GATEWAY); - return config; + return self; } gboolean -nm_ip4_config_commit (const NMIP4Config *config, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric) +nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - gs_unref_ptrarray GPtrArray *added_addresses = NULL; + gs_unref_ptrarray GPtrArray *addresses = NULL; + const NMDedupMultiHeadEntry *head_entry; g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (config != NULL, FALSE); + g_return_val_if_fail (self != NULL, FALSE); - /* Addresses */ - nm_platform_ip4_address_sync (platform, ifindex, priv->addresses, - default_route_metric >= 0 ? &added_addresses : NULL); + addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_addresses (self), + NULL, NULL); + + nm_platform_ip4_address_sync (platform, ifindex, addresses); /* Routes */ { - const NMDedupMultiHeadEntry *head_entry; guint i; gs_unref_array GArray *routes = NULL; gs_unref_array GArray *device_route_purge_list = NULL; const CList *iter; - head_entry = _idx_ip4_routes (config); + head_entry = nm_ip4_config_lookup_routes (self); routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), head_entry ? head_entry->len : 0); if ( default_route_metric >= 0 - && added_addresses) { + && addresses) { /* For IPv6, we explicitly add the device-routes (onlink) to NMIP6Config. * As we don't do that for IPv4, add it here shortly before syncing * the routes. For NMRouteManager these routes are very much important. */ - for (i = 0; i < added_addresses->len; i++) { - const NMPlatformIP4Address *addr = added_addresses->pdata[i]; + for (i = 0; i < addresses->len; i++) { + const NMPObject *o = addresses->pdata[i]; + const NMPlatformIP4Address *addr; NMPlatformIP4Route route = { 0 }; + if (!o) + continue; + + addr = NMP_OBJECT_CAST_IP4_ADDRESS (o); if (addr->plen == 0) continue; @@ -555,8 +732,11 @@ nm_ip4_config_commit (const NMIP4Config *config, NMPlatform *platform, NMRouteMa } 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); + c_list_for_each (iter, &head_entry->lst_entries_head) { + g_array_append_vals (routes, + NMP_OBJECT_CAST_IP4_ROUTE (c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj), + 1); + } } nm_route_manager_ip4_route_register_device_route_purge_list (route_manager, device_route_purge_list); @@ -602,7 +782,7 @@ merge_route_attributes (NMIPRoute *s_route, NMPlatformIP4Route *r) } void -nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, guint32 default_route_metric) +nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric) { NMIP4ConfigPrivate *priv; guint naddresses, nroutes, nnameservers, nsearches; @@ -613,9 +793,9 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu g_return_if_fail (NM_IS_SETTING_IP4_CONFIG (setting)); - priv = NM_IP4_CONFIG_GET_PRIVATE (config); + priv = NM_IP4_CONFIG_GET_PRIVATE (self); - g_object_freeze_notify (G_OBJECT (config)); + g_object_freeze_notify (G_OBJECT (self)); naddresses = nm_setting_ip_config_get_num_addresses (setting); nroutes = nm_setting_ip_config_get_num_routes (setting); @@ -624,14 +804,14 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu /* Gateway */ if (nm_setting_ip_config_get_never_default (setting)) - nm_ip4_config_set_never_default (config, TRUE); + nm_ip4_config_set_never_default (self, TRUE); else if (nm_setting_ip_config_get_ignore_auto_routes (setting)) - nm_ip4_config_set_never_default (config, FALSE); + nm_ip4_config_set_never_default (self, FALSE); if (nm_setting_ip_config_get_gateway (setting)) { guint32 gateway; inet_pton (AF_INET, nm_setting_ip_config_get_gateway (setting), &gateway); - nm_ip4_config_set_gateway (config, gateway); + nm_ip4_config_set_gateway (self, gateway); } if (priv->route_metric == -1) @@ -656,12 +836,12 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu if (label) g_strlcpy (address.label, g_variant_get_string (label, NULL), sizeof (address.label)); - nm_ip4_config_add_address (config, &address); + _add_address (self, NULL, &address); } /* Routes */ if (nm_setting_ip_config_get_ignore_auto_routes (setting)) - nm_ip4_config_reset_routes (config); + nm_ip4_config_reset_routes (self); for (i = 0; i < nroutes; i++) { NMIPRoute *s_route = nm_setting_ip_config_get_route (setting, i); NMPlatformIP4Route route; @@ -681,69 +861,70 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu route.metric = nm_ip_route_get_metric (s_route); route.rt_source = NM_IP_CONFIG_SOURCE_USER; + route.network = nm_utils_ip4_address_clear_host_address (route.network, route.plen); + merge_route_attributes (s_route, &route); - _add_route (config, NULL, &route); + _add_route (self, NULL, &route); } /* DNS */ if (nm_setting_ip_config_get_ignore_auto_dns (setting)) { - nm_ip4_config_reset_nameservers (config); - nm_ip4_config_reset_domains (config); - nm_ip4_config_reset_searches (config); + nm_ip4_config_reset_nameservers (self); + nm_ip4_config_reset_domains (self); + nm_ip4_config_reset_searches (self); } for (i = 0; i < nnameservers; i++) { guint32 ip; if (inet_pton (AF_INET, nm_setting_ip_config_get_dns (setting, i), &ip) == 1) - nm_ip4_config_add_nameserver (config, ip); + nm_ip4_config_add_nameserver (self, ip); } for (i = 0; i < nsearches; i++) - nm_ip4_config_add_search (config, nm_setting_ip_config_get_dns_search (setting, i)); + nm_ip4_config_add_search (self, nm_setting_ip_config_get_dns_search (setting, i)); i = 0; while ((i = nm_setting_ip_config_next_valid_dns_option (setting, i)) >= 0) { - nm_ip4_config_add_dns_option (config, nm_setting_ip_config_get_dns_option (setting, i)); + nm_ip4_config_add_dns_option (self, nm_setting_ip_config_get_dns_option (setting, i)); i++; } priority = nm_setting_ip_config_get_dns_priority (setting); if (priority) - nm_ip4_config_set_dns_priority (config, priority); + nm_ip4_config_set_dns_priority (self, priority); - g_object_thaw_notify (G_OBJECT (config)); + g_object_thaw_notify (G_OBJECT (self)); } NMSetting * -nm_ip4_config_create_setting (const NMIP4Config *config) +nm_ip4_config_create_setting (const NMIP4Config *self) { NMSettingIPConfig *s_ip4; guint32 gateway; - guint naddresses, nnameservers, nsearches, noptions; + guint nnameservers, nsearches, noptions; const char *method = NULL; int i; gint64 route_metric; NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Address *address; const NMPlatformIP4Route *route; s_ip4 = NM_SETTING_IP_CONFIG (nm_setting_ip4_config_new ()); - if (!config) { + if (!self) { g_object_set (s_ip4, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP4_CONFIG_METHOD_DISABLED, NULL); return NM_SETTING (s_ip4); } - gateway = nm_ip4_config_get_gateway (config); - naddresses = nm_ip4_config_get_num_addresses (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); - route_metric = nm_ip4_config_get_route_metric (config); + gateway = nm_ip4_config_get_gateway (self); + nnameservers = nm_ip4_config_get_num_nameservers (self); + nsearches = nm_ip4_config_get_num_searches (self); + noptions = nm_ip4_config_get_num_dns_options (self); + route_metric = nm_ip4_config_get_route_metric (self); /* Addresses */ - for (i = 0; i < naddresses; i++) { - const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) { NMIPAddress *s_addr; /* Detect dynamic address */ @@ -765,7 +946,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config) } /* Gateway */ - if ( nm_ip4_config_has_gateway (config) + if ( nm_ip4_config_has_gateway (self) && nm_setting_ip_config_get_num_addresses (s_ip4) > 0) { g_object_set (s_ip4, NM_SETTING_IP_CONFIG_GATEWAY, nm_utils_inet4_ntop (gateway, NULL), @@ -782,7 +963,7 @@ nm_ip4_config_create_setting (const NMIP4Config *config) NULL); /* Routes */ - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, config, &route) { + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) { NMIPRoute *s_route; /* Ignore default route. */ @@ -803,25 +984,25 @@ nm_ip4_config_create_setting (const NMIP4Config *config) /* DNS */ for (i = 0; i < nnameservers; i++) { - guint32 nameserver = nm_ip4_config_get_nameserver (config, i); + guint32 nameserver = nm_ip4_config_get_nameserver (self, i); nm_setting_ip_config_add_dns (s_ip4, nm_utils_inet4_ntop (nameserver, NULL)); } for (i = 0; i < nsearches; i++) { - const char *search = nm_ip4_config_get_search (config, i); + const char *search = nm_ip4_config_get_search (self, i); nm_setting_ip_config_add_dns_search (s_ip4, search); } for (i = 0; i < noptions; i++) { - const char *option = nm_ip4_config_get_dns_option (config, i); + const char *option = nm_ip4_config_get_dns_option (self, i); nm_setting_ip_config_add_dns_option (s_ip4, option); } g_object_set (s_ip4, NM_SETTING_IP_CONFIG_DNS_PRIORITY, - nm_ip4_config_get_dns_priority (config), + nm_ip4_config_get_dns_priority (self), NULL); return NM_SETTING (s_ip4); @@ -836,6 +1017,7 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl const NMIP4ConfigPrivate *src_priv; guint32 i; NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Address *address = NULL; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -846,8 +1028,8 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++) - nm_ip4_config_add_address (dst, nm_ip4_config_get_address (src, i)); + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, src, &address) + _add_address (dst, NMP_OBJECT_UP_CAST (address), NULL); /* nameservers */ if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { @@ -863,7 +1045,7 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { const NMPlatformIP4Route *route; - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, src, &route) + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &route) _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL); } @@ -930,21 +1112,6 @@ nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFl /*****************************************************************************/ static int -_addresses_get_index (const NMIP4Config *self, const NMPlatformIP4Address *addr) -{ - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); - guint i; - - for (i = 0; i < priv->addresses->len; i++) { - const NMPlatformIP4Address *a = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - - if (addresses_are_duplicate (addr, a)) - return (int) i; - } - return -1; -} - -static int _nameservers_get_index (const NMIP4Config *self, guint32 ns) { const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); @@ -1049,8 +1216,10 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) NMIP4ConfigPrivate *priv_dst; guint i; gint idx; + const NMPlatformIP4Address *a; const NMPlatformIP4Route *r; NMDedupMultiIter ipconf_iter; + gboolean changed; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -1060,11 +1229,15 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - for (i = 0; i < nm_ip4_config_get_num_addresses (src); i++) { - idx = _addresses_get_index (dst, nm_ip4_config_get_address (src, i)); - if (idx >= 0) - nm_ip4_config_del_address (dst, idx); + changed = FALSE; + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, src, &a) { + if (nm_dedup_multi_index_remove_obj (priv_dst->multi_idx, + &priv_dst->idx_ip4_addresses, + NMP_OBJECT_UP_CAST (a))) + changed = TRUE; } + if (changed) + _notify_addresses (dst); /* nameservers */ for (i = 0; i < nm_ip4_config_get_num_nameservers (src); i++) { @@ -1084,11 +1257,15 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src) /* ignore route_metric */ /* routes */ - 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)); + changed = FALSE; + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) { + if (nm_dedup_multi_index_remove_obj (priv_dst->multi_idx, + &priv_dst->idx_ip4_routes, + NMP_OBJECT_UP_CAST (r))) + changed = TRUE; } + if (changed) + _notify_routes (dst); /* domains */ for (i = 0; i < nm_ip4_config_get_num_domains (src); i++) { @@ -1149,9 +1326,8 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) { NMIP4ConfigPrivate *priv_dst; const NMIP4ConfigPrivate *priv_src; - guint i; - gint idx; NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Address *a; const NMPlatformIP4Route *r; g_return_if_fail (src); @@ -1163,12 +1339,15 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) 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)); - if (idx < 0) - nm_ip4_config_del_address (dst, i); - else - i++; + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, dst, &a) { + if (nm_dedup_multi_index_lookup_obj (priv_src->multi_idx, + &priv_src->idx_ip4_addresses, + NMP_OBJECT_UP_CAST (a))) + continue; + + if (nm_dedup_multi_index_remove_entry (priv_dst->multi_idx, + ipconf_iter.current) != 1) + nm_assert_not_reached (); } /* ignore route_metric */ @@ -1182,7 +1361,7 @@ nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src) } /* routes */ - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, dst, &r) { + nm_ip_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))) @@ -1227,8 +1406,8 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev guint i, num; NMIP4ConfigPrivate *dst_priv; const NMIP4ConfigPrivate *src_priv; - const NMPlatformIP4Address *dst_addr, *src_addr; NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst; + const NMDedupMultiHeadEntry *head_entry_src; g_return_val_if_fail (src != NULL, FALSE); g_return_val_if_fail (dst != NULL, FALSE); @@ -1271,39 +1450,60 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev } /* addresses */ - num = nm_ip4_config_get_num_addresses (src); - are_equal = num == nm_ip4_config_get_num_addresses (dst); - if (are_equal) { - for (i = 0; i < num; i++ ) { - if (nm_platform_ip4_address_cmp (src_addr = nm_ip4_config_get_address (src, i), - dst_addr = nm_ip4_config_get_address (dst, i))) { - are_equal = FALSE; - if ( !addresses_are_duplicate (src_addr, dst_addr) - || src_addr->peer_address != dst_addr->peer_address) { - has_relevant_changes = TRUE; - break; - } + head_entry_src = nm_ip4_config_lookup_addresses (src); + nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src); + nm_ip_config_iter_ip4_address_init (&ipconf_iter_dst, dst); + are_equal = TRUE; + while (TRUE) { + gboolean has; + const NMPlatformIP4Address *r_src = NULL; + const NMPlatformIP4Address *r_dst = NULL; + + has = nm_ip_config_iter_ip4_address_next (&ipconf_iter_src, &r_src); + if (has != nm_ip_config_iter_ip4_address_next (&ipconf_iter_dst, &r_dst)) { + are_equal = FALSE; + has_relevant_changes = TRUE; + break; + } + if (!has) + break; + + if (nm_platform_ip4_address_cmp (r_src, r_dst) != 0) { + are_equal = FALSE; + if ( !nm_ip_config_obj_id_equal_ip4_address (r_src, r_dst) + || r_src->peer_address != r_dst->peer_address) { + has_relevant_changes = TRUE; + break; } } - } else - has_relevant_changes = TRUE; + } if (!are_equal) { - nm_ip4_config_reset_addresses (dst); - for (i = 0; i < num; i++) - nm_ip4_config_add_address (dst, nm_ip4_config_get_address (src, i)); + has_minor_changes = TRUE; + nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_addresses); + nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) { + nm_dedup_multi_index_add (dst_priv->multi_idx, + &dst_priv->idx_ip4_addresses, + ipconf_iter_src.current->obj, + NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, + NULL, + NULL); + } + nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip4_addresses, FALSE); } /* routes */ - nm_ip4_config_iter_ip4_route_init (&ipconf_iter_src, src); - nm_ip4_config_iter_ip4_route_init (&ipconf_iter_dst, dst); + head_entry_src = nm_ip4_config_lookup_routes (src); + nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src); + nm_ip_config_iter_ip4_route_init (&ipconf_iter_dst, dst); are_equal = TRUE; while (TRUE) { gboolean has; - const NMPlatformIP4Route *r_src, *r_dst; + const NMPlatformIP4Route *r_src = NULL; + const NMPlatformIP4Route *r_dst = NULL; - 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)) { + has = nm_ip_config_iter_ip4_route_next (&ipconf_iter_src, &r_src); + if (has != nm_ip_config_iter_ip4_route_next (&ipconf_iter_dst, &r_dst)) { are_equal = FALSE; has_relevant_changes = TRUE; break; @@ -1322,15 +1522,12 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev } } if (!are_equal) { - 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_iter_for_each (&ipconf_iter_src, head_entry_src) { nm_dedup_multi_index_add (dst_priv->multi_idx, &dst_priv->idx_ip4_routes, - NMP_OBJECT_UP_CAST (r_src), + ipconf_iter_src.current->obj, NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, NULL, NULL); @@ -1495,90 +1692,89 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev } void -nm_ip4_config_dump (const NMIP4Config *config, const char *detail) +nm_ip4_config_dump (const NMIP4Config *self, const char *detail) { guint32 tmp; guint i; const char *str; NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Address *address; const NMPlatformIP4Route *route; - g_message ("--------- NMIP4Config %p (%s)", config, detail); + g_message ("--------- NMIP4Config %p (%s)", self, detail); - if (config == NULL) { + if (self == NULL) { g_message (" (null)"); return; } - str = nm_exported_object_get_path (NM_EXPORTED_OBJECT (config)); + str = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self)); if (str) g_message (" path: %s", str); /* addresses */ - for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) - g_message (" a: %s", nm_platform_ip4_address_to_string (nm_ip4_config_get_address (config, i), NULL, 0)); + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) + g_message (" a: %s", nm_platform_ip4_address_to_string (address, NULL, 0)); /* default gateway */ - if (nm_ip4_config_has_gateway (config)) { - tmp = nm_ip4_config_get_gateway (config); + if (nm_ip4_config_has_gateway (self)) { + tmp = nm_ip4_config_get_gateway (self); g_message (" gw: %s", nm_utils_inet4_ntop (tmp, NULL)); } /* nameservers */ - for (i = 0; i < nm_ip4_config_get_num_nameservers (config); i++) { - tmp = nm_ip4_config_get_nameserver (config, i); + for (i = 0; i < nm_ip4_config_get_num_nameservers (self); i++) { + tmp = nm_ip4_config_get_nameserver (self, i); g_message (" ns: %s", nm_utils_inet4_ntop (tmp, NULL)); } /* routes */ - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, config, &route) + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &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++) - g_message (" domain: %s", nm_ip4_config_get_domain (config, i)); + for (i = 0; i < nm_ip4_config_get_num_domains (self); i++) + g_message (" domain: %s", nm_ip4_config_get_domain (self, i)); /* dns searches */ - for (i = 0; i < nm_ip4_config_get_num_searches (config); i++) - g_message (" search: %s", nm_ip4_config_get_search (config, i)); + for (i = 0; i < nm_ip4_config_get_num_searches (self); i++) + g_message (" search: %s", nm_ip4_config_get_search (self, i)); /* dns options */ - for (i = 0; i < nm_ip4_config_get_num_dns_options (config); i++) - g_message (" dnsopt: %s", nm_ip4_config_get_dns_option (config, i)); + for (i = 0; i < nm_ip4_config_get_num_dns_options (self); i++) + g_message (" dnsopt: %s", nm_ip4_config_get_dns_option (self, i)); - g_message (" dnspri: %d", nm_ip4_config_get_dns_priority (config)); + g_message (" dnspri: %d", nm_ip4_config_get_dns_priority (self)); - g_message (" mss: %"G_GUINT32_FORMAT, nm_ip4_config_get_mss (config)); - g_message (" mtu: %"G_GUINT32_FORMAT" (source: %d)", nm_ip4_config_get_mtu (config), (int) nm_ip4_config_get_mtu_source (config)); + g_message (" mss: %"G_GUINT32_FORMAT, nm_ip4_config_get_mss (self)); + g_message (" mtu: %"G_GUINT32_FORMAT" (source: %d)", nm_ip4_config_get_mtu (self), (int) nm_ip4_config_get_mtu_source (self)); /* NIS */ - for (i = 0; i < nm_ip4_config_get_num_nis_servers (config); i++) { - tmp = nm_ip4_config_get_nis_server (config, i); + for (i = 0; i < nm_ip4_config_get_num_nis_servers (self); i++) { + tmp = nm_ip4_config_get_nis_server (self, i); g_message (" nis: %s", nm_utils_inet4_ntop (tmp, NULL)); } - g_message (" nisdmn: %s", nm_ip4_config_get_nis_domain (config) ?: "(none)"); + g_message (" nisdmn: %s", nm_ip4_config_get_nis_domain (self) ?: "(none)"); /* WINS */ - for (i = 0; i < nm_ip4_config_get_num_wins (config); i++) { - tmp = nm_ip4_config_get_wins (config, i); + for (i = 0; i < nm_ip4_config_get_num_wins (self); i++) { + tmp = nm_ip4_config_get_wins (self, i); g_message (" wins: %s", nm_utils_inet4_ntop (tmp, NULL)); } - g_message (" n-dflt: %d", nm_ip4_config_get_never_default (config)); - g_message (" mtrd: %d", (int) nm_ip4_config_get_metered (config)); + g_message (" n-dflt: %d", nm_ip4_config_get_never_default (self)); + g_message (" mtrd: %d", (int) nm_ip4_config_get_metered (self)); } gboolean -nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 network, guint8 plen) +nm_ip4_config_destination_is_direct (const NMIP4Config *self, guint32 network, guint8 plen) { - guint naddresses = nm_ip4_config_get_num_addresses (config); - guint i; + const NMPlatformIP4Address *item; in_addr_t peer_network; + NMDedupMultiIter iter; - for (i = 0; i < naddresses; i++) { - const NMPlatformIP4Address *item = nm_ip4_config_get_address (config, i); - + nm_ip_config_iter_ip4_address_for_each (&iter, self, &item) { if (item->plen > plen) continue; @@ -1598,48 +1794,48 @@ nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 network, /*****************************************************************************/ void -nm_ip4_config_set_never_default (NMIP4Config *config, gboolean never_default) +nm_ip4_config_set_never_default (NMIP4Config *self, gboolean never_default) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); priv->never_default = never_default; } gboolean -nm_ip4_config_get_never_default (const NMIP4Config *config) +nm_ip4_config_get_never_default (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->never_default; } void -nm_ip4_config_set_gateway (NMIP4Config *config, guint32 gateway) +nm_ip4_config_set_gateway (NMIP4Config *self, guint32 gateway) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (priv->gateway != gateway || !priv->has_gateway) { priv->gateway = gateway; priv->has_gateway = TRUE; - _notify (config, PROP_GATEWAY); + _notify (self, PROP_GATEWAY); } } void -nm_ip4_config_unset_gateway (NMIP4Config *config) +nm_ip4_config_unset_gateway (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (priv->has_gateway) { priv->gateway = 0; priv->has_gateway = FALSE; - _notify (config, PROP_GATEWAY); + _notify (self, PROP_GATEWAY); } } /** * nm_ip4_config_has_gateway: - * @config: the #NMIP4Config object + * @self: the #NMIP4Config object * * NetworkManager's handling of default-routes is limited and usually a default-route * cannot have gateway 0.0.0.0. For peer-to-peer routes, we still want to @@ -1648,25 +1844,25 @@ nm_ip4_config_unset_gateway (NMIP4Config *config) * * Returns: whether the object has a gateway explicitly set. */ gboolean -nm_ip4_config_has_gateway (const NMIP4Config *config) +nm_ip4_config_has_gateway (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->has_gateway; } guint32 -nm_ip4_config_get_gateway (const NMIP4Config *config) +nm_ip4_config_get_gateway (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->gateway; } gint64 -nm_ip4_config_get_route_metric (const NMIP4Config *config) +nm_ip4_config_get_route_metric (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->route_metric; } @@ -1674,211 +1870,166 @@ nm_ip4_config_get_route_metric (const NMIP4Config *config) /*****************************************************************************/ void -nm_ip4_config_reset_addresses (NMIP4Config *config) +nm_ip4_config_reset_addresses (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); - if (priv->addresses->len != 0) { - g_array_set_size (priv->addresses, 0); - notify_addresses (config); - } + if (nm_dedup_multi_index_remove_idx (priv->multi_idx, + &priv->idx_ip4_addresses) > 0) + _notify_addresses (self); +} + +static void +_add_address (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Address *new) +{ + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + + if (_nm_ip_config_add_obj (priv->multi_idx, + &priv->idx_ip4_addresses_, + priv->ifindex, + obj_new, + (const NMPlatformObject *) new)) + _notify_addresses (self); } /** * nm_ip4_config_add_address: - * @config: the #NMIP4Config - * @new: the new address to add to @config + * @self: the #NMIP4Config + * @new: the new address to add to @self * - * Adds the new address to @config. If an address with the same basic properties - * (address, prefix) already exists in @config, it is overwritten with the + * Adds the new address to @self. If an address with the same basic properties + * (address, prefix) already exists in @self, it is overwritten with the * lifetime and preferred of @new. The source is also overwritten by the source * from @new if that source is higher priority. */ void -nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *new) +nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *new) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - NMPlatformIP4Address item_old; - int i; - - g_return_if_fail (new != NULL); - - for (i = 0; i < priv->addresses->len; i++ ) { - NMPlatformIP4Address *item = &g_array_index (priv->addresses, NMPlatformIP4Address, i); - - if (addresses_are_duplicate (item, new)) { - if (nm_platform_ip4_address_cmp (item, new) == 0) - return; - - /* remember the old values. */ - item_old = *item; - /* Copy over old item to get new lifetime, timestamp, preferred */ - *item = *new; - - /* But restore highest priority source */ - item->addr_source = MAX (item_old.addr_source, new->addr_source); - - /* for addresses that we read from the kernel, we keep the timestamps as defined - * by the previous source (item_old). The reason is, that the other source configured the lifetimes - * with "what should be" and the kernel values are "what turned out after configuring it". - * - * For other sources, the longer lifetime wins. */ - if ( (new->addr_source == NM_IP_CONFIG_SOURCE_KERNEL && new->addr_source != item_old.addr_source) - || nm_platform_ip_address_cmp_expiry ((const NMPlatformIPAddress *) &item_old, (const NMPlatformIPAddress *) new) > 0) { - item->timestamp = item_old.timestamp; - item->lifetime = item_old.lifetime; - item->preferred = item_old.preferred; - } - if (nm_platform_ip4_address_cmp (&item_old, item) == 0) - return; - goto NOTIFY; - } - } + g_return_if_fail (self); + g_return_if_fail (new); + g_return_if_fail (new->plen > 0 && new->plen <= 32); + g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (self)->ifindex > 0); - g_array_append_val (priv->addresses, *new); -NOTIFY: - notify_addresses (config); + _add_address (self, NULL, new); } void -nm_ip4_config_del_address (NMIP4Config *config, guint i) +_nmtst_nm_ip4_config_del_address (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); - - g_return_if_fail (i < priv->addresses->len); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + const NMPlatformIP4Address *a; - g_array_remove_index (priv->addresses, i); + a = _nmtst_nm_ip4_config_get_address (self, i); + g_return_if_fail (a); - notify_addresses (config); + if (nm_dedup_multi_index_remove_obj (priv->multi_idx, + &priv->idx_ip4_addresses, + NMP_OBJECT_UP_CAST (a)) != 1) + g_return_if_reached (); + _notify_addresses (self); } guint -nm_ip4_config_get_num_addresses (const NMIP4Config *config) +nm_ip4_config_get_num_addresses (const NMIP4Config *self) +{ + const NMDedupMultiHeadEntry *head_entry; + + head_entry = nm_ip4_config_lookup_addresses (self); + return head_entry ? head_entry->len : 0; +} + +const NMPlatformIP4Address * +nm_ip4_config_get_first_address (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMDedupMultiIter iter; + const NMPlatformIP4Address *a = NULL; - return priv->addresses->len; + nm_ip_config_iter_ip4_address_for_each (&iter, self, &a) + return a; + return NULL; } const NMPlatformIP4Address * -nm_ip4_config_get_address (const NMIP4Config *config, guint i) +_nmtst_nm_ip4_config_get_address (const NMIP4Config *self, guint i) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMDedupMultiIter iter; + const NMPlatformIP4Address *a = NULL; + guint j; - return &g_array_index (priv->addresses, NMPlatformIP4Address, i); + j = 0; + nm_ip_config_iter_ip4_address_for_each (&iter, self, &a) { + if (i == j) + return a; + j++; + } + g_return_val_if_reached (NULL); } gboolean -nm_ip4_config_address_exists (const NMIP4Config *config, +nm_ip4_config_address_exists (const NMIP4Config *self, const NMPlatformIP4Address *needle) { - return _addresses_get_index (config, needle) >= 0; + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + NMPObject obj_stack; + + nmp_object_stackinit_id_ip4_address (&obj_stack, + priv->ifindex, + needle->address, + needle->plen, + needle->peer_address); + return !!nm_dedup_multi_index_lookup_obj (priv->multi_idx, + &priv->idx_ip4_routes, + &obj_stack); } /*****************************************************************************/ void -nm_ip4_config_reset_routes (NMIP4Config *config) +nm_ip4_config_reset_routes (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (nm_dedup_multi_index_remove_idx (priv->multi_idx, - &priv->idx_ip4_routes) > 0) { - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); - } + &priv->idx_ip4_routes) > 0) + _notify_routes (self); } static void -_add_route (NMIP4Config *config, const NMPObject *o_new, const NMPlatformIP4Route *new) +_add_route (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Route *new) { - NMIP4ConfigPrivate *priv; - NMPObject o_new_storage; - nm_auto_nmpobj const NMPObject *obj_old = NULL; - - nm_assert (NM_IS_IP4_CONFIG (config)); - - priv = NM_IP4_CONFIG_GET_PRIVATE (config); - - nm_assert (priv->ifindex > 0); - - /* we go through extra lengths to accept a full o_new object. That one, - * can be reused by increasing the ref-count. */ - if (!o_new) { - nm_assert (new); - nm_assert (new->plen > 0 && new->plen <= 32); - nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP4_ROUTE, - (const NMPlatformObject *) new); - o_new_storage.ip4_route.ifindex = priv->ifindex; - o_new = &o_new_storage; - } else { - nm_assert (!new); - nm_assert (NMP_OBJECT_GET_TYPE (o_new) == NMP_OBJECT_TYPE_IP4_ROUTE); - nm_assert (o_new->ip4_route.plen > 0 && o_new->ip4_route.plen <= 32); - if (o_new->ip4_route.ifindex != priv->ifindex) { - nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP4_ROUTE, &o_new->object); - o_new_storage.ip4_route.ifindex = priv->ifindex; - o_new = &o_new_storage; - } - } - - if (!nm_dedup_multi_index_add (priv->multi_idx, - &priv->idx_ip4_routes, - o_new, - NM_DEDUP_MULTI_IDX_MODE_APPEND, - NULL, - &obj_old)) - return; + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); - if (obj_old) { - NMIPConfigSource old_source; - - old_source = obj_old->ip_route.rt_source; - /* we want to keep the maximum rt_source. But since we expect - * that usually we already add the maxiumum right away, we first try to - * add the new route (replacing the old one). Only if we later - * find out that rt_source is now lower, we fix it. - */ - if (o_new->ip_route.rt_source < old_source) { - if (o_new != &o_new_storage) { - nmp_object_stackinit (&o_new_storage, NMP_OBJECT_TYPE_IP4_ROUTE, - &o_new->object); - o_new = &o_new_storage; - } - o_new_storage.ip_route.rt_source = old_source; - if (!nm_dedup_multi_index_add (priv->multi_idx, - &priv->idx_ip4_routes, - o_new, - NM_DEDUP_MULTI_IDX_MODE_APPEND, - NULL, - NULL)) - nm_assert_not_reached (); - } - } + nm_assert ((!new) != (!obj_new)); + nm_assert (!new || _route_valid (new)); + nm_assert (!obj_new || _route_valid (NMP_OBJECT_CAST_IP4_ROUTE (obj_new))); - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); + if (_nm_ip_config_add_obj (priv->multi_idx, + &priv->idx_ip4_routes_, + priv->ifindex, + obj_new, + (const NMPlatformObject *) new)) + _notify_routes (self); } /** * nm_ip4_config_add_route: - * @config: the #NMIP4Config - * @new: the new route to add to @config + * @self: the #NMIP4Config + * @new: the new route to add to @self * - * Adds the new route to @config. If a route with the same basic properties - * (network, prefix) already exists in @config, it is overwritten including the + * Adds the new route to @self. If a route with the same basic properties + * (network, prefix) already exists in @self, it is overwritten including the * gateway and metric of @new. The source is also overwritten by the source * from @new if that source is higher priority. */ void -nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *new) +nm_ip4_config_add_route (NMIP4Config *self, const NMPlatformIP4Route *new) { - g_return_if_fail (config); + g_return_if_fail (self); g_return_if_fail (new); g_return_if_fail (new->plen > 0 && new->plen <= 32); - g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (config)->ifindex > 0); + g_return_if_fail (NM_IP4_CONFIG_GET_PRIVATE (self)->ifindex > 0); - _add_route (config, NULL, new); + _add_route (self, NULL, new); } void @@ -1894,8 +2045,7 @@ _nmtst_nm_ip4_config_del_route (NMIP4Config *self, guint i) &priv->idx_ip4_routes, NMP_OBJECT_UP_CAST (r)) != 1) g_return_if_reached (); - _notify (self, PROP_ROUTE_DATA); - _notify (self, PROP_ROUTES); + _notify_routes (self); } guint @@ -1903,7 +2053,7 @@ nm_ip4_config_get_num_routes (const NMIP4Config *self) { const NMDedupMultiHeadEntry *head_entry; - head_entry = _idx_ip4_routes (self); + head_entry = nm_ip4_config_lookup_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; } @@ -1911,18 +2061,15 @@ nm_ip4_config_get_num_routes (const NMIP4Config *self) const NMPlatformIP4Route * _nmtst_nm_ip4_config_get_route (const NMIP4Config *self, guint i) { - const NMDedupMultiHeadEntry *head_entry; - CList *iter; + NMDedupMultiIter iter; + const NMPlatformIP4Route *r = NULL; guint j; - head_entry = _idx_ip4_routes (self); - if (head_entry) { - j = 0; - c_list_for_each (iter, &head_entry->lst_entries_head) { - if (i == j) - return _entry_iter_get_ip4_route (iter); - j++; - } + j = 0; + nm_ip_config_iter_ip4_route_for_each (&iter, self, &r) { + if (i == j) + return r; + j++; } g_return_val_if_reached (NULL); } @@ -1936,7 +2083,7 @@ nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, guint32 host) g_return_val_if_fail (host, NULL); - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, self, &item) { + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &item) { if (item->gateway != 0) continue; @@ -1957,20 +2104,20 @@ nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, guint32 host) /*****************************************************************************/ void -nm_ip4_config_reset_nameservers (NMIP4Config *config) +nm_ip4_config_reset_nameservers (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (priv->nameservers->len != 0) { g_array_set_size (priv->nameservers, 0); - _notify (config, PROP_NAMESERVERS); + _notify (self, PROP_NAMESERVERS); } } void -nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 new) +nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 new) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); int i; g_return_if_fail (new != 0); @@ -1980,32 +2127,32 @@ nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 new) return; g_array_append_val (priv->nameservers, new); - _notify (config, PROP_NAMESERVERS); + _notify (self, PROP_NAMESERVERS); } void -nm_ip4_config_del_nameserver (NMIP4Config *config, guint i) +nm_ip4_config_del_nameserver (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->nameservers->len); g_array_remove_index (priv->nameservers, i); - _notify (config, PROP_NAMESERVERS); + _notify (self, PROP_NAMESERVERS); } guint -nm_ip4_config_get_num_nameservers (const NMIP4Config *config) +nm_ip4_config_get_num_nameservers (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->nameservers->len; } guint32 -nm_ip4_config_get_nameserver (const NMIP4Config *config, guint i) +nm_ip4_config_get_nameserver (const NMIP4Config *self, guint i) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return g_array_index (priv->nameservers, guint32, i); } @@ -2013,20 +2160,20 @@ nm_ip4_config_get_nameserver (const NMIP4Config *config, guint i) /*****************************************************************************/ void -nm_ip4_config_reset_domains (NMIP4Config *config) +nm_ip4_config_reset_domains (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (priv->domains->len != 0) { g_ptr_array_set_size (priv->domains, 0); - _notify (config, PROP_DOMAINS); + _notify (self, PROP_DOMAINS); } } void -nm_ip4_config_add_domain (NMIP4Config *config, const char *domain) +nm_ip4_config_add_domain (NMIP4Config *self, const char *domain) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); int i; g_return_if_fail (domain != NULL); @@ -2037,32 +2184,32 @@ nm_ip4_config_add_domain (NMIP4Config *config, const char *domain) return; g_ptr_array_add (priv->domains, g_strdup (domain)); - _notify (config, PROP_DOMAINS); + _notify (self, PROP_DOMAINS); } void -nm_ip4_config_del_domain (NMIP4Config *config, guint i) +nm_ip4_config_del_domain (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->domains->len); g_ptr_array_remove_index (priv->domains, i); - _notify (config, PROP_DOMAINS); + _notify (self, PROP_DOMAINS); } guint -nm_ip4_config_get_num_domains (const NMIP4Config *config) +nm_ip4_config_get_num_domains (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->domains->len; } const char * -nm_ip4_config_get_domain (const NMIP4Config *config, guint i) +nm_ip4_config_get_domain (const NMIP4Config *self, guint i) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return g_ptr_array_index (priv->domains, i); } @@ -2070,20 +2217,20 @@ nm_ip4_config_get_domain (const NMIP4Config *config, guint i) /*****************************************************************************/ void -nm_ip4_config_reset_searches (NMIP4Config *config) +nm_ip4_config_reset_searches (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (priv->searches->len != 0) { g_ptr_array_set_size (priv->searches, 0); - _notify (config, PROP_SEARCHES); + _notify (self, PROP_SEARCHES); } } void -nm_ip4_config_add_search (NMIP4Config *config, const char *new) +nm_ip4_config_add_search (NMIP4Config *self, const char *new) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); char *search; size_t len; @@ -2109,32 +2256,32 @@ nm_ip4_config_add_search (NMIP4Config *config, const char *new) } g_ptr_array_add (priv->searches, search); - _notify (config, PROP_SEARCHES); + _notify (self, PROP_SEARCHES); } void -nm_ip4_config_del_search (NMIP4Config *config, guint i) +nm_ip4_config_del_search (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->searches->len); g_ptr_array_remove_index (priv->searches, i); - _notify (config, PROP_SEARCHES); + _notify (self, PROP_SEARCHES); } guint -nm_ip4_config_get_num_searches (const NMIP4Config *config) +nm_ip4_config_get_num_searches (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->searches->len; } const char * -nm_ip4_config_get_search (const NMIP4Config *config, guint i) +nm_ip4_config_get_search (const NMIP4Config *self, guint i) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return g_ptr_array_index (priv->searches, i); } @@ -2142,20 +2289,20 @@ nm_ip4_config_get_search (const NMIP4Config *config, guint i) /*****************************************************************************/ void -nm_ip4_config_reset_dns_options (NMIP4Config *config) +nm_ip4_config_reset_dns_options (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (priv->dns_options->len != 0) { g_ptr_array_set_size (priv->dns_options, 0); - _notify (config, PROP_DNS_OPTIONS); + _notify (self, PROP_DNS_OPTIONS); } } void -nm_ip4_config_add_dns_option (NMIP4Config *config, const char *new) +nm_ip4_config_add_dns_option (NMIP4Config *self, const char *new) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); int i; g_return_if_fail (new != NULL); @@ -2166,32 +2313,32 @@ nm_ip4_config_add_dns_option (NMIP4Config *config, const char *new) return; g_ptr_array_add (priv->dns_options, g_strdup (new)); - _notify (config, PROP_DNS_OPTIONS); + _notify (self, PROP_DNS_OPTIONS); } void -nm_ip4_config_del_dns_option(NMIP4Config *config, guint i) +nm_ip4_config_del_dns_option(NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->dns_options->len); g_ptr_array_remove_index (priv->dns_options, i); - _notify (config, PROP_DNS_OPTIONS); + _notify (self, PROP_DNS_OPTIONS); } guint -nm_ip4_config_get_num_dns_options (const NMIP4Config *config) +nm_ip4_config_get_num_dns_options (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->dns_options->len; } const char * -nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i) +nm_ip4_config_get_dns_option (const NMIP4Config *self, guint i) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return g_ptr_array_index (priv->dns_options, i); } @@ -2199,20 +2346,20 @@ nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i) /*****************************************************************************/ void -nm_ip4_config_set_dns_priority (NMIP4Config *config, gint priority) +nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (priority != priv->dns_priority) { priv->dns_priority = priority; - _notify (config, PROP_DNS_PRIORITY); + _notify (self, PROP_DNS_PRIORITY); } } gint -nm_ip4_config_get_dns_priority (const NMIP4Config *config) +nm_ip4_config_get_dns_priority (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->dns_priority; } @@ -2220,17 +2367,17 @@ nm_ip4_config_get_dns_priority (const NMIP4Config *config) /*****************************************************************************/ void -nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss) +nm_ip4_config_set_mss (NMIP4Config *self, guint32 mss) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); priv->mss = mss; } guint32 -nm_ip4_config_get_mss (const NMIP4Config *config) +nm_ip4_config_get_mss (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->mss; } @@ -2238,17 +2385,17 @@ nm_ip4_config_get_mss (const NMIP4Config *config) /*****************************************************************************/ void -nm_ip4_config_reset_nis_servers (NMIP4Config *config) +nm_ip4_config_reset_nis_servers (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_array_set_size (priv->nis, 0); } void -nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis) +nm_ip4_config_add_nis_server (NMIP4Config *self, guint32 nis) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); int i; for (i = 0; i < priv->nis->len; i++) @@ -2259,9 +2406,9 @@ nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis) } void -nm_ip4_config_del_nis_server (NMIP4Config *config, guint i) +nm_ip4_config_del_nis_server (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->nis->len); @@ -2269,34 +2416,34 @@ nm_ip4_config_del_nis_server (NMIP4Config *config, guint i) } guint -nm_ip4_config_get_num_nis_servers (const NMIP4Config *config) +nm_ip4_config_get_num_nis_servers (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->nis->len; } guint32 -nm_ip4_config_get_nis_server (const NMIP4Config *config, guint i) +nm_ip4_config_get_nis_server (const NMIP4Config *self, guint i) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return g_array_index (priv->nis, guint32, i); } void -nm_ip4_config_set_nis_domain (NMIP4Config *config, const char *domain) +nm_ip4_config_set_nis_domain (NMIP4Config *self, const char *domain) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_free (priv->nis_domain); priv->nis_domain = g_strdup (domain); } const char * -nm_ip4_config_get_nis_domain (const NMIP4Config *config) +nm_ip4_config_get_nis_domain (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->nis_domain; } @@ -2304,20 +2451,20 @@ nm_ip4_config_get_nis_domain (const NMIP4Config *config) /*****************************************************************************/ void -nm_ip4_config_reset_wins (NMIP4Config *config) +nm_ip4_config_reset_wins (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (priv->wins->len != 0) { g_array_set_size (priv->wins, 0); - _notify (config, PROP_WINS_SERVERS); + _notify (self, PROP_WINS_SERVERS); } } void -nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins) +nm_ip4_config_add_wins (NMIP4Config *self, guint32 wins) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); int i; g_return_if_fail (wins != 0); @@ -2327,32 +2474,32 @@ nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins) return; g_array_append_val (priv->wins, wins); - _notify (config, PROP_WINS_SERVERS); + _notify (self, PROP_WINS_SERVERS); } void -nm_ip4_config_del_wins (NMIP4Config *config, guint i) +nm_ip4_config_del_wins (NMIP4Config *self, guint i) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->wins->len); g_array_remove_index (priv->wins, i); - _notify (config, PROP_WINS_SERVERS); + _notify (self, PROP_WINS_SERVERS); } guint -nm_ip4_config_get_num_wins (const NMIP4Config *config) +nm_ip4_config_get_num_wins (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->wins->len; } guint32 -nm_ip4_config_get_wins (const NMIP4Config *config, guint i) +nm_ip4_config_get_wins (const NMIP4Config *self, guint i) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return g_array_index (priv->wins, guint32, i); } @@ -2360,9 +2507,9 @@ nm_ip4_config_get_wins (const NMIP4Config *config, guint i) /*****************************************************************************/ void -nm_ip4_config_set_mtu (NMIP4Config *config, guint32 mtu, NMIPConfigSource source) +nm_ip4_config_set_mtu (NMIP4Config *self, guint32 mtu, NMIPConfigSource source) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); if (!mtu) source = NM_IP_CONFIG_SOURCE_UNKNOWN; @@ -2372,17 +2519,17 @@ nm_ip4_config_set_mtu (NMIP4Config *config, guint32 mtu, NMIPConfigSource source } guint32 -nm_ip4_config_get_mtu (const NMIP4Config *config) +nm_ip4_config_get_mtu (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->mtu; } NMIPConfigSource -nm_ip4_config_get_mtu_source (const NMIP4Config *config) +nm_ip4_config_get_mtu_source (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->mtu_source; } @@ -2390,17 +2537,17 @@ nm_ip4_config_get_mtu_source (const NMIP4Config *config) /*****************************************************************************/ void -nm_ip4_config_set_metered (NMIP4Config *config, gboolean metered) +nm_ip4_config_set_metered (NMIP4Config *self, gboolean metered) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); priv->metered = metered; } gboolean -nm_ip4_config_get_metered (const NMIP4Config *config) +nm_ip4_config_get_metered (const NMIP4Config *self) { - const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + const NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); return priv->metered; } @@ -2414,61 +2561,60 @@ hash_u32 (GChecksum *sum, guint32 n) } void -nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only) +nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only) { guint i; const char *s; NMDedupMultiIter ipconf_iter; + const NMPlatformIP4Address *address; const NMPlatformIP4Route *route; - g_return_if_fail (config); + g_return_if_fail (self); g_return_if_fail (sum); if (!dns_only) { - hash_u32 (sum, nm_ip4_config_has_gateway (config)); - hash_u32 (sum, nm_ip4_config_get_gateway (config)); + hash_u32 (sum, nm_ip4_config_has_gateway (self)); + hash_u32 (sum, nm_ip4_config_get_gateway (self)); - for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++) { - const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i); + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, self, &address) { hash_u32 (sum, address->address); hash_u32 (sum, address->plen); hash_u32 (sum, address->peer_address & nm_utils_ip4_prefix_to_netmask (address->plen)); } - - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, config, &route) { + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) { hash_u32 (sum, route->network); hash_u32 (sum, route->plen); hash_u32 (sum, route->gateway); hash_u32 (sum, route->metric); } - for (i = 0; i < nm_ip4_config_get_num_nis_servers (config); i++) - hash_u32 (sum, nm_ip4_config_get_nis_server (config, i)); + for (i = 0; i < nm_ip4_config_get_num_nis_servers (self); i++) + hash_u32 (sum, nm_ip4_config_get_nis_server (self, i)); - s = nm_ip4_config_get_nis_domain (config); + s = nm_ip4_config_get_nis_domain (self); if (s) g_checksum_update (sum, (const guint8 *) s, strlen (s)); } - for (i = 0; i < nm_ip4_config_get_num_nameservers (config); i++) - hash_u32 (sum, nm_ip4_config_get_nameserver (config, i)); + for (i = 0; i < nm_ip4_config_get_num_nameservers (self); i++) + hash_u32 (sum, nm_ip4_config_get_nameserver (self, i)); - for (i = 0; i < nm_ip4_config_get_num_wins (config); i++) - hash_u32 (sum, nm_ip4_config_get_wins (config, i)); + for (i = 0; i < nm_ip4_config_get_num_wins (self); i++) + hash_u32 (sum, nm_ip4_config_get_wins (self, i)); - for (i = 0; i < nm_ip4_config_get_num_domains (config); i++) { - s = nm_ip4_config_get_domain (config, i); + for (i = 0; i < nm_ip4_config_get_num_domains (self); i++) { + s = nm_ip4_config_get_domain (self, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } - for (i = 0; i < nm_ip4_config_get_num_searches (config); i++) { - s = nm_ip4_config_get_search (config, i); + for (i = 0; i < nm_ip4_config_get_num_searches (self); i++) { + s = nm_ip4_config_get_search (self, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } - for (i = 0; i < nm_ip4_config_get_num_dns_options (config); i++) { - s = nm_ip4_config_get_dns_option (config, i); + for (i = 0; i < nm_ip4_config_get_num_dns_options (self); i++) { + s = nm_ip4_config_get_dns_option (self, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } } @@ -2519,11 +2665,12 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMIP4Config *config = NM_IP4_CONFIG (object); - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4Config *self = NM_IP4_CONFIG (object); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter ipconf_iter; const NMPlatformIP4Route *route; - GVariantBuilder array_builder, addr_builder, route_builder; + GVariantBuilder builder_data, builder_legacy; switch (prop_id) { case PROP_IFINDEX: @@ -2531,24 +2678,32 @@ get_property (GObject *object, guint prop_id, break; case PROP_ADDRESS_DATA: case PROP_ADDRESSES: - { - gs_unref_array GArray *new = NULL; - guint naddr, i; + nm_assert (!!priv->address_data_variant == !!priv->addresses_variant); + + if (priv->address_data_variant) + goto out_addresses_cached; + + g_variant_builder_init (&builder_data, G_VARIANT_TYPE ("aa{sv}")); + g_variant_builder_init (&builder_legacy, G_VARIANT_TYPE ("aau")); - g_return_if_fail (!!priv->address_data_variant == !!priv->addresses_variant); + head_entry = nm_ip4_config_lookup_addresses (self); + if (head_entry) { + gs_free const NMPObject **addresses = NULL; + guint naddr, i; - if (priv->address_data_variant) - goto return_cached; + addresses = (const NMPObject **) nm_dedup_multi_objs_to_array_head (head_entry, NULL, NULL, &naddr); + nm_assert (addresses && naddr); - naddr = nm_ip4_config_get_num_addresses (config); - new = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Address), naddr); - g_array_append_vals (new, priv->addresses->data, priv->addresses->len); - g_array_sort (new, _addresses_sort_cmp); + g_qsort_with_data (addresses, + naddr, + sizeof (addresses[0]), + _addresses_sort_cmp, + NULL); /* Build address data variant */ - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); for (i = 0; i < naddr; i++) { - const NMPlatformIP4Address *address = &g_array_index (new, NMPlatformIP4Address, i); + GVariantBuilder addr_builder; + const NMPlatformIP4Address *address = NMP_OBJECT_CAST_IP4_ADDRESS (addresses[i]); g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&addr_builder, "{sv}", @@ -2569,82 +2724,88 @@ get_property (GObject *object, guint prop_id, g_variant_new_string (address->label)); } - g_variant_builder_add (&array_builder, "a{sv}", &addr_builder); - } - priv->address_data_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); + g_variant_builder_add (&builder_data, "a{sv}", &addr_builder); - /* Build addresses variant */ - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau")); - for (i = 0; i < naddr; i++) { - const NMPlatformIP4Address *address = &g_array_index (new, NMPlatformIP4Address, i); - guint32 dbus_addr[3]; - - dbus_addr[0] = address->address; - dbus_addr[1] = address->plen; - dbus_addr[2] = i == 0 ? priv->gateway : 0; + { + const guint32 dbus_addr[3] = { + address->address, + address->plen, + i == 0 ? priv->gateway : 0, + }; - g_variant_builder_add (&array_builder, "@au", - g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, - dbus_addr, 3, sizeof (guint32))); + g_variant_builder_add (&builder_legacy, "@au", + g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, + dbus_addr, 3, sizeof (guint32))); + } } - priv->addresses_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); - -return_cached: - g_value_set_variant (value, - prop_id == PROP_ADDRESS_DATA ? - priv->address_data_variant : - priv->addresses_variant); } - break; - case PROP_ROUTE_DATA: - { - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); - 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", - g_variant_new_string (nm_utils_inet4_ntop (route->network, NULL))); - g_variant_builder_add (&route_builder, "{sv}", - "prefix", - g_variant_new_uint32 (route->plen)); - if (route->gateway) { - g_variant_builder_add (&route_builder, "{sv}", - "next-hop", - g_variant_new_string (nm_utils_inet4_ntop (route->gateway, NULL))); - } - g_variant_builder_add (&route_builder, "{sv}", - "metric", - g_variant_new_uint32 (route->metric)); - g_variant_builder_add (&array_builder, "a{sv}", &route_builder); - } + priv->address_data_variant = g_variant_ref_sink (g_variant_builder_end (&builder_data)); + priv->addresses_variant = g_variant_ref_sink (g_variant_builder_end (&builder_legacy)); - g_value_take_variant (value, g_variant_builder_end (&array_builder)); - } +out_addresses_cached: + g_value_set_variant (value, + prop_id == PROP_ADDRESS_DATA ? + priv->address_data_variant : + priv->addresses_variant); break; + case PROP_ROUTE_DATA: case PROP_ROUTES: - { - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aau")); - 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 - * plen is positive. Skip the default routes not to break older clients. */ - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) - continue; + nm_assert (!!priv->route_data_variant == !!priv->routes_variant); - dbus_route[0] = route->network; - dbus_route[1] = route->plen; - dbus_route[2] = route->gateway; - dbus_route[3] = route->metric; + if (priv->route_data_variant) + goto out_routes_cached; - g_variant_builder_add (&array_builder, "@au", + g_variant_builder_init (&builder_data, G_VARIANT_TYPE ("aa{sv}")); + g_variant_builder_init (&builder_legacy, G_VARIANT_TYPE ("aau")); + + nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, self, &route) { + GVariantBuilder route_builder; + + nm_assert (_route_valid (route)); + + g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&route_builder, "{sv}", + "dest", + g_variant_new_string (nm_utils_inet4_ntop (route->network, NULL))); + g_variant_builder_add (&route_builder, "{sv}", + "prefix", + g_variant_new_uint32 (route->plen)); + if (route->gateway) { + g_variant_builder_add (&route_builder, "{sv}", + "next-hop", + g_variant_new_string (nm_utils_inet4_ntop (route->gateway, NULL))); + } + g_variant_builder_add (&route_builder, "{sv}", + "metric", + g_variant_new_uint32 (route->metric)); + + g_variant_builder_add (&builder_data, "a{sv}", &route_builder); + + /* legacy versions of nm_ip4_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)) { + const guint32 dbus_route[4] = { + route->network, + route->plen, + route->gateway, + route->metric, + }; + + g_variant_builder_add (&builder_legacy, "@au", g_variant_new_fixed_array (G_VARIANT_TYPE_UINT32, dbus_route, 4, sizeof (guint32))); } - - g_value_take_variant (value, g_variant_builder_end (&array_builder)); } + + priv->route_data_variant = g_variant_ref_sink (g_variant_builder_end (&builder_data)); + priv->routes_variant = g_variant_ref_sink (g_variant_builder_end (&builder_legacy)); + +out_routes_cached: + g_value_set_variant (value, + prop_id == PROP_ROUTE_DATA ? + priv->route_data_variant : + priv->routes_variant); break; case PROP_GATEWAY: if (priv->has_gateway) @@ -2714,14 +2875,15 @@ set_property (GObject *object, /*****************************************************************************/ static void -nm_ip4_config_init (NMIP4Config *config) +nm_ip4_config_init (NMIP4Config *self) { - NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config); + NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (self); + nm_ip_config_dedup_multi_idx_type_init ((NMIPConfigDedupMultiIdxType *) &priv->idx_ip4_addresses, + NMP_OBJECT_TYPE_IP4_ADDRESS); 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->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); @@ -2747,11 +2909,14 @@ 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_addresses); 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); + nm_clear_g_variant (&priv->route_data_variant); + nm_clear_g_variant (&priv->routes_variant); + 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 7049f9e5f3..e11043b79c 100644 --- a/src/nm-ip4-config.h +++ b/src/nm-ip4-config.h @@ -25,6 +25,7 @@ #include "nm-setting-ip4-config.h" #include "nm-utils/nm-dedup-multi.h" +#include "platform/nmp-object.h" /*****************************************************************************/ @@ -35,19 +36,64 @@ typedef struct { 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); +/*****************************************************************************/ + +void nm_ip_config_iter_ip4_address_init (NMDedupMultiIter *iter, const NMIP4Config *self); +void nm_ip_config_iter_ip4_route_init (NMDedupMultiIter *iter, const NMIP4Config *self); + +static inline gboolean +nm_ip_config_iter_ip4_address_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP4Address **out_address) +{ + gboolean has_next; + + g_return_val_if_fail (out_address, FALSE); + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (has_next) + *out_address = NMP_OBJECT_CAST_IP4_ADDRESS (ipconf_iter->current->obj); + return has_next; +} + +static inline gboolean +nm_ip_config_iter_ip4_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP4Route **out_route) +{ + gboolean has_next; -#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)); \ - ) + g_return_val_if_fail (out_route, FALSE); + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (has_next) + *out_route = NMP_OBJECT_CAST_IP4_ROUTE (ipconf_iter->current->obj); + return has_next; +} + +#define nm_ip_config_iter_ip4_address_for_each(iter, self, address) \ + for (*(address) = NULL, nm_ip_config_iter_ip4_address_init ((iter), (self)); \ + nm_ip_config_iter_ip4_address_next ((iter), (address)); \ + ) + +#define nm_ip_config_iter_ip4_route_for_each(iter, self, route) \ + for (*(route) = NULL, nm_ip_config_iter_ip4_route_init ((iter), (self)); \ + nm_ip_config_iter_ip4_route_next ((iter), (route)); \ + ) + +/*****************************************************************************/ + +gboolean nm_ip_config_obj_id_equal_ip4_address (const NMPlatformIP4Address *a, + const NMPlatformIP4Address *b); +gboolean nm_ip_config_obj_id_equal_ip6_address (const NMPlatformIP6Address *a, + const NMPlatformIP6Address *b); 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); +gboolean _nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx, + NMIPConfigDedupMultiIdxType *idx_type, + int ifindex, + const NMPObject *obj_new, + const NMPlatformObject *pl_new); + /*****************************************************************************/ #define NM_TYPE_IP4_CONFIG (nm_ip4_config_get_type ()) @@ -84,99 +130,102 @@ GType nm_ip4_config_get_type (void); NMIP4Config * nm_ip4_config_new (NMDedupMultiIndex *multi_idx, int ifindex); -int nm_ip4_config_get_ifindex (const NMIP4Config *config); +int nm_ip4_config_get_ifindex (const NMIP4Config *self); NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self); 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); +gboolean nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric); +void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric); +NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self); void nm_ip4_config_merge (NMIP4Config *dst, const NMIP4Config *src, NMIPConfigMergeFlags merge_flags); void nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src); void nm_ip4_config_intersect (NMIP4Config *dst, const NMIP4Config *src); gboolean nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relevant_changes); -gboolean nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 dest, guint8 plen); -void nm_ip4_config_dump (const NMIP4Config *config, const char *detail); - - -void nm_ip4_config_set_never_default (NMIP4Config *config, gboolean never_default); -gboolean nm_ip4_config_get_never_default (const NMIP4Config *config); -void nm_ip4_config_set_gateway (NMIP4Config *config, guint32 gateway); -void nm_ip4_config_unset_gateway (NMIP4Config *config); -gboolean nm_ip4_config_has_gateway (const NMIP4Config *config); -guint32 nm_ip4_config_get_gateway (const NMIP4Config *config); -gint64 nm_ip4_config_get_route_metric (const NMIP4Config *config); - -void nm_ip4_config_reset_addresses (NMIP4Config *config); -void nm_ip4_config_add_address (NMIP4Config *config, const NMPlatformIP4Address *address); -void nm_ip4_config_del_address (NMIP4Config *config, guint i); -guint nm_ip4_config_get_num_addresses (const NMIP4Config *config); -const NMPlatformIP4Address *nm_ip4_config_get_address (const NMIP4Config *config, guint i); -gboolean nm_ip4_config_address_exists (const NMIP4Config *config, const NMPlatformIP4Address *address); - -void nm_ip4_config_reset_routes (NMIP4Config *config); -void nm_ip4_config_add_route (NMIP4Config *config, const NMPlatformIP4Route *route); -void _nmtst_nm_ip4_config_del_route (NMIP4Config *config, guint i); -guint nm_ip4_config_get_num_routes (const NMIP4Config *config); -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); - -void nm_ip4_config_reset_nameservers (NMIP4Config *config); -void nm_ip4_config_add_nameserver (NMIP4Config *config, guint32 nameserver); -void nm_ip4_config_del_nameserver (NMIP4Config *config, guint i); -guint nm_ip4_config_get_num_nameservers (const NMIP4Config *config); -guint32 nm_ip4_config_get_nameserver (const NMIP4Config *config, guint i); - -void nm_ip4_config_reset_domains (NMIP4Config *config); -void nm_ip4_config_add_domain (NMIP4Config *config, const char *domain); -void nm_ip4_config_del_domain (NMIP4Config *config, guint i); -guint nm_ip4_config_get_num_domains (const NMIP4Config *config); -const char * nm_ip4_config_get_domain (const NMIP4Config *config, guint i); - -void nm_ip4_config_reset_searches (NMIP4Config *config); -void nm_ip4_config_add_search (NMIP4Config *config, const char *search); -void nm_ip4_config_del_search (NMIP4Config *config, guint i); -guint nm_ip4_config_get_num_searches (const NMIP4Config *config); -const char * nm_ip4_config_get_search (const NMIP4Config *config, guint i); - -void nm_ip4_config_reset_dns_options (NMIP4Config *config); -void nm_ip4_config_add_dns_option (NMIP4Config *config, const char *option); -void nm_ip4_config_del_dns_option (NMIP4Config *config, guint i); -guint nm_ip4_config_get_num_dns_options (const NMIP4Config *config); -const char * nm_ip4_config_get_dns_option (const NMIP4Config *config, guint i); - -void nm_ip4_config_set_dns_priority (NMIP4Config *config, gint priority); -gint nm_ip4_config_get_dns_priority (const NMIP4Config *config); - -void nm_ip4_config_set_mss (NMIP4Config *config, guint32 mss); -guint32 nm_ip4_config_get_mss (const NMIP4Config *config); - -void nm_ip4_config_reset_nis_servers (NMIP4Config *config); -void nm_ip4_config_add_nis_server (NMIP4Config *config, guint32 nis); -void nm_ip4_config_del_nis_server (NMIP4Config *config, guint i); -guint nm_ip4_config_get_num_nis_servers (const NMIP4Config *config); -guint32 nm_ip4_config_get_nis_server (const NMIP4Config *config, guint i); -void nm_ip4_config_set_nis_domain (NMIP4Config *config, const char *domain); -const char * nm_ip4_config_get_nis_domain (const NMIP4Config *config); - -void nm_ip4_config_reset_wins (NMIP4Config *config); -void nm_ip4_config_add_wins (NMIP4Config *config, guint32 wins); -void nm_ip4_config_del_wins (NMIP4Config *config, guint i); -guint nm_ip4_config_get_num_wins (const NMIP4Config *config); -guint32 nm_ip4_config_get_wins (const NMIP4Config *config, guint i); - -void nm_ip4_config_set_mtu (NMIP4Config *config, guint32 mtu, NMIPConfigSource source); -guint32 nm_ip4_config_get_mtu (const NMIP4Config *config); -NMIPConfigSource nm_ip4_config_get_mtu_source (const NMIP4Config *config); - -void nm_ip4_config_set_metered (NMIP4Config *config, gboolean metered); -gboolean nm_ip4_config_get_metered (const NMIP4Config *config); - -void nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only); +gboolean nm_ip4_config_destination_is_direct (const NMIP4Config *self, guint32 dest, guint8 plen); +void nm_ip4_config_dump (const NMIP4Config *self, const char *detail); + + +void nm_ip4_config_set_never_default (NMIP4Config *self, gboolean never_default); +gboolean nm_ip4_config_get_never_default (const NMIP4Config *self); +void nm_ip4_config_set_gateway (NMIP4Config *self, guint32 gateway); +void nm_ip4_config_unset_gateway (NMIP4Config *self); +gboolean nm_ip4_config_has_gateway (const NMIP4Config *self); +guint32 nm_ip4_config_get_gateway (const NMIP4Config *self); +gint64 nm_ip4_config_get_route_metric (const NMIP4Config *self); + +const NMDedupMultiHeadEntry *nm_ip4_config_lookup_addresses (const NMIP4Config *self); +void nm_ip4_config_reset_addresses (NMIP4Config *self); +void nm_ip4_config_add_address (NMIP4Config *self, const NMPlatformIP4Address *address); +void _nmtst_nm_ip4_config_del_address (NMIP4Config *self, guint i); +guint nm_ip4_config_get_num_addresses (const NMIP4Config *self); +const NMPlatformIP4Address *nm_ip4_config_get_first_address (const NMIP4Config *self); +const NMPlatformIP4Address *_nmtst_nm_ip4_config_get_address (const NMIP4Config *self, guint i); +gboolean nm_ip4_config_address_exists (const NMIP4Config *self, const NMPlatformIP4Address *address); + +const NMDedupMultiHeadEntry *nm_ip4_config_lookup_routes (const NMIP4Config *self); +void nm_ip4_config_reset_routes (NMIP4Config *self); +void nm_ip4_config_add_route (NMIP4Config *self, const NMPlatformIP4Route *route); +void _nmtst_nm_ip4_config_del_route (NMIP4Config *self, guint i); +guint nm_ip4_config_get_num_routes (const NMIP4Config *self); +const NMPlatformIP4Route *_nmtst_nm_ip4_config_get_route (const NMIP4Config *self, guint i); + +const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *self, guint32 host); + +void nm_ip4_config_reset_nameservers (NMIP4Config *self); +void nm_ip4_config_add_nameserver (NMIP4Config *self, guint32 nameserver); +void nm_ip4_config_del_nameserver (NMIP4Config *self, guint i); +guint nm_ip4_config_get_num_nameservers (const NMIP4Config *self); +guint32 nm_ip4_config_get_nameserver (const NMIP4Config *self, guint i); + +void nm_ip4_config_reset_domains (NMIP4Config *self); +void nm_ip4_config_add_domain (NMIP4Config *self, const char *domain); +void nm_ip4_config_del_domain (NMIP4Config *self, guint i); +guint nm_ip4_config_get_num_domains (const NMIP4Config *self); +const char * nm_ip4_config_get_domain (const NMIP4Config *self, guint i); + +void nm_ip4_config_reset_searches (NMIP4Config *self); +void nm_ip4_config_add_search (NMIP4Config *self, const char *search); +void nm_ip4_config_del_search (NMIP4Config *self, guint i); +guint nm_ip4_config_get_num_searches (const NMIP4Config *self); +const char * nm_ip4_config_get_search (const NMIP4Config *self, guint i); + +void nm_ip4_config_reset_dns_options (NMIP4Config *self); +void nm_ip4_config_add_dns_option (NMIP4Config *self, const char *option); +void nm_ip4_config_del_dns_option (NMIP4Config *self, guint i); +guint nm_ip4_config_get_num_dns_options (const NMIP4Config *self); +const char * nm_ip4_config_get_dns_option (const NMIP4Config *self, guint i); + +void nm_ip4_config_set_dns_priority (NMIP4Config *self, gint priority); +gint nm_ip4_config_get_dns_priority (const NMIP4Config *self); + +void nm_ip4_config_set_mss (NMIP4Config *self, guint32 mss); +guint32 nm_ip4_config_get_mss (const NMIP4Config *self); + +void nm_ip4_config_reset_nis_servers (NMIP4Config *self); +void nm_ip4_config_add_nis_server (NMIP4Config *self, guint32 nis); +void nm_ip4_config_del_nis_server (NMIP4Config *self, guint i); +guint nm_ip4_config_get_num_nis_servers (const NMIP4Config *self); +guint32 nm_ip4_config_get_nis_server (const NMIP4Config *self, guint i); +void nm_ip4_config_set_nis_domain (NMIP4Config *self, const char *domain); +const char * nm_ip4_config_get_nis_domain (const NMIP4Config *self); + +void nm_ip4_config_reset_wins (NMIP4Config *self); +void nm_ip4_config_add_wins (NMIP4Config *self, guint32 wins); +void nm_ip4_config_del_wins (NMIP4Config *self, guint i); +guint nm_ip4_config_get_num_wins (const NMIP4Config *self); +guint32 nm_ip4_config_get_wins (const NMIP4Config *self, guint i); + +void nm_ip4_config_set_mtu (NMIP4Config *self, guint32 mtu, NMIPConfigSource source); +guint32 nm_ip4_config_get_mtu (const NMIP4Config *self); +NMIPConfigSource nm_ip4_config_get_mtu_source (const NMIP4Config *self); + +void nm_ip4_config_set_metered (NMIP4Config *self, gboolean metered); +gboolean nm_ip4_config_get_metered (const NMIP4Config *self); + +void nm_ip4_config_hash (const NMIP4Config *self, GChecksum *sum, gboolean dns_only); gboolean nm_ip4_config_equal (const NMIP4Config *a, const NMIP4Config *b); /*****************************************************************************/ diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c index b376833f45..6fe19cf7e4 100644 --- a/src/nm-ip6-config.c +++ b/src/nm-ip6-config.c @@ -41,6 +41,20 @@ /*****************************************************************************/ +static gboolean +_route_valid (const NMPlatformIP6Route *r) +{ + struct in6_addr n; + + return r + && r->plen <= 128 + && (memcmp (&r->network, + nm_utils_ip6_address_clear_host_address (&n, &r->network, r->plen), + sizeof (n)) == 0); +} + +/*****************************************************************************/ + typedef struct { bool never_default:1; guint32 mss; @@ -49,15 +63,20 @@ typedef struct { NMSettingIP6ConfigPrivacy privacy; gint64 route_metric; struct in6_addr gateway; - GArray *addresses; GArray *nameservers; GPtrArray *domains; GPtrArray *searches; GPtrArray *dns_options; GVariant *address_data_variant; GVariant *addresses_variant; + GVariant *route_data_variant; + GVariant *routes_variant; NMDedupMultiIndex *multi_idx; union { + NMIPConfigDedupMultiIdxType idx_ip6_addresses_; + NMDedupMultiIdxType idx_ip6_addresses; + }; + union { NMIPConfigDedupMultiIdxType idx_ip6_routes_; NMDedupMultiIdxType idx_ip6_routes; }; @@ -93,77 +112,73 @@ NM_GOBJECT_PROPERTIES_DEFINE (NMIP6Config, /*****************************************************************************/ -static void _add_route (NMIP6Config *config, const NMPObject *o_new, const NMPlatformIP6Route *new); +static void _add_address (NMIP6Config *self, const NMPObject *obj_new, const NMPlatformIP6Address *new); +static void _add_route (NMIP6Config *self, const NMPObject *obj_new, const NMPlatformIP6Route *new); /*****************************************************************************/ int -nm_ip6_config_get_ifindex (const NMIP6Config *config) +nm_ip6_config_get_ifindex (const NMIP6Config *self) { - return NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex; + return NM_IP6_CONFIG_GET_PRIVATE (self)->ifindex; } NMDedupMultiIndex * -nm_ip6_config_get_multi_idx (const NMIP6Config *config) +nm_ip6_config_get_multi_idx (const NMIP6Config *self) { - return NM_IP6_CONFIG_GET_PRIVATE (config)->multi_idx; + return NM_IP6_CONFIG_GET_PRIVATE (self)->multi_idx; } void -nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privacy) +nm_ip6_config_set_privacy (NMIP6Config *self, NMSettingIP6ConfigPrivacy privacy) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); priv->privacy = privacy; } /*****************************************************************************/ -static const NMDedupMultiHeadEntry * -_idx_ip6_routes (const NMIP6Config *self) +const NMDedupMultiHeadEntry * +nm_ip6_config_lookup_addresses (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, + &priv->idx_ip6_addresses, 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) +nm_ip_config_iter_ip6_address_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)); + nm_dedup_multi_iter_init (ipconf_iter, nm_ip6_config_lookup_addresses (self)); } -gboolean -nm_ip6_config_iter_ip6_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Route **out_route) +/*****************************************************************************/ + +const NMDedupMultiHeadEntry * +nm_ip6_config_lookup_routes (const NMIP6Config *self) { - gboolean has_next; + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); - 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; + return nm_dedup_multi_index_lookup_head (priv->multi_idx, + &priv->idx_ip6_routes, + NULL); +} + +void +nm_ip_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, nm_ip6_config_lookup_routes (self)); } /*****************************************************************************/ static void -notify_addresses (NMIP6Config *self) +_notify_addresses (NMIP6Config *self) { NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); @@ -173,6 +188,19 @@ notify_addresses (NMIP6Config *self) _notify (self, PROP_ADDRESSES); } +static void +_notify_routes (NMIP6Config *self) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + + nm_clear_g_variant (&priv->route_data_variant); + nm_clear_g_variant (&priv->routes_variant); + _notify (self, PROP_ROUTE_DATA); + _notify (self, PROP_ROUTES); +} + +/*****************************************************************************/ + /** * nm_ip6_config_capture_resolv_conf(): * @nameservers: array of struct in6_addr @@ -239,12 +267,6 @@ nm_ip6_config_capture_resolv_conf (GArray *nameservers, return changed; } -static gboolean -addresses_are_duplicate (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b) -{ - return IN6_ARE_ADDR_EQUAL (&a->address, &b->address); -} - static gint _addresses_sort_cmp_get_prio (const struct in6_addr *addr) { @@ -263,13 +285,14 @@ _addresses_sort_cmp_get_prio (const struct in6_addr *addr) return 6; } -static gint -_addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data) +static int +_addresses_sort_cmp (const NMPlatformIP6Address *a1, + const NMPlatformIP6Address *a2, + gboolean prefer_temp) { gint p1, p2, c; gboolean perm1, perm2, tent1, tent2; gboolean ipv6_privacy1, ipv6_privacy2; - const NMPlatformIP6Address *a1 = a, *a2 = b; /* tentative addresses are always sorted back... */ /* sort tentative addresses after non-tentative. */ @@ -288,7 +311,6 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data) ipv6_privacy1 = !!(a1->n_ifa_flags & (IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY)); ipv6_privacy2 = !!(a2->n_ifa_flags & (IFA_F_MANAGETEMPADDR | IFA_F_TEMPORARY)); if (ipv6_privacy1 || ipv6_privacy2) { - gboolean prefer_temp = ((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR; gboolean public1 = TRUE, public2 = TRUE; if (ipv6_privacy1) { @@ -323,30 +345,60 @@ _addresses_sort_cmp (gconstpointer a, gconstpointer b, gpointer user_data) return c != 0 ? c : memcmp (a1, a2, sizeof (*a1)); } +static int +_addresses_sort_cmp_prop (gconstpointer a, gconstpointer b, gpointer user_data) +{ + return _addresses_sort_cmp (NMP_OBJECT_CAST_IP6_ADDRESS (*((const NMPObject **) a)), + NMP_OBJECT_CAST_IP6_ADDRESS (*((const NMPObject **) b)), + ((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR); +} + +static int +sort_captured_addresses (const CList *lst_a, const CList *lst_b, gconstpointer user_data) +{ + const NMPlatformIP6Address *addr_a = NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_a, NMDedupMultiEntry, lst_entries)->obj); + const NMPlatformIP6Address *addr_b = NMP_OBJECT_CAST_IP6_ADDRESS (c_list_entry (lst_b, NMDedupMultiEntry, lst_entries)->obj); + + return _addresses_sort_cmp (addr_a, addr_b, + ((NMSettingIP6ConfigPrivacy) GPOINTER_TO_INT (user_data)) == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR); +} + gboolean -nm_ip6_config_addresses_sort (NMIP6Config *self) +_nmtst_nm_ip6_config_addresses_sort (NMIP6Config *self) { NMIP6ConfigPrivate *priv; - size_t data_len = 0; - char *data_pre = NULL; - gboolean changed; + const NMDedupMultiHeadEntry *head_entry; g_return_val_if_fail (NM_IS_IP6_CONFIG (self), FALSE); - priv = NM_IP6_CONFIG_GET_PRIVATE (self); - if (priv->addresses->len > 1) { - data_len = priv->addresses->len * g_array_get_element_size (priv->addresses); - data_pre = g_new (char, data_len); - memcpy (data_pre, priv->addresses->data, data_len); + head_entry = nm_ip6_config_lookup_addresses (self); + if (head_entry && head_entry->len > 1) { + gboolean changed; + gs_free gconstpointer *addresses_old = NULL; + guint naddr, j; + NMDedupMultiIter iter; + + priv = NM_IP6_CONFIG_GET_PRIVATE (self); - g_array_sort_with_data (priv->addresses, _addresses_sort_cmp, - GINT_TO_POINTER (priv->privacy)); + addresses_old = nm_dedup_multi_objs_to_array_head (head_entry, NULL, NULL, &naddr); + nm_assert (addresses_old); + nm_assert (naddr > 0 && naddr == head_entry->len); - changed = memcmp (data_pre, priv->addresses->data, data_len) != 0; - g_free (data_pre); + nm_dedup_multi_head_entry_sort (head_entry, + sort_captured_addresses, + GINT_TO_POINTER (priv->privacy)); + + changed = FALSE; + j = 0; + nm_dedup_multi_iter_for_each (&iter, head_entry) { + nm_assert (j < naddr); + if (iter.current->obj != addresses_old[j++]) + changed = TRUE; + } + nm_assert (j == naddr); if (changed) { - notify_addresses (self); + _notify_addresses (self); return TRUE; } } @@ -356,38 +408,58 @@ nm_ip6_config_addresses_sort (NMIP6Config *self) NMIP6Config * nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary) { - NMIP6Config *config; + NMIP6Config *self; NMIP6ConfigPrivate *priv; guint32 lowest_metric = G_MAXUINT32; struct in6_addr old_gateway = IN6ADDR_ANY_INIT; gboolean has_gateway; - const NMDedupMultiHeadEntry *pl_head_entry; + const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter iter; const NMPObject *plobj = NULL; gboolean notify_nameservers = FALSE; + gboolean has_addresses = FALSE; + + nm_assert (ifindex > 0); /* Slaves have no IP configuration */ if (nm_platform_link_get_master (platform, ifindex) > 0) return NULL; - config = nm_ip6_config_new (multi_idx, ifindex); - priv = NM_IP6_CONFIG_GET_PRIVATE (config); - - g_array_unref (priv->addresses); + self = nm_ip6_config_new (multi_idx, ifindex); + priv = NM_IP6_CONFIG_GET_PRIVATE (self); - priv->addresses = nm_platform_ip6_address_get_all (platform, ifindex); + head_entry = nm_platform_lookup_addrroute (platform, + NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex); + if (head_entry) { + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { + if (!nm_dedup_multi_index_add (priv->multi_idx, + &priv->idx_ip6_addresses, + plobj, + NM_DEDUP_MULTI_IDX_MODE_APPEND, + NULL, + NULL)) + nm_assert_not_reached (); + has_addresses = TRUE; + } + head_entry = nm_ip6_config_lookup_addresses (self); + nm_assert (head_entry); + nm_dedup_multi_head_entry_sort (head_entry, + sort_captured_addresses, + GINT_TO_POINTER (use_temporary)); + } - pl_head_entry = nm_platform_lookup_route_visible (platform, - NMP_OBJECT_TYPE_IP6_ROUTE, - ifindex, - FALSE); + head_entry = nm_platform_lookup_route_visible (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex, + FALSE); /* Extract gateway from default route */ old_gateway = priv->gateway; lowest_metric = G_MAXUINT32; has_gateway = FALSE; - nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj); if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route) @@ -404,8 +476,7 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i * routes have their route metrics explicitly set. */ priv->route_metric = has_gateway ? (gint64) lowest_metric : (gint64) -1; - nm_dedup_multi_iter_rewind (&iter); - nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) { + nmp_cache_iter_for_each (&iter, head_entry, &plobj) { const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (plobj); if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) @@ -422,60 +493,62 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i */ continue; } - _add_route (config, plobj, NULL); + _add_route (self, plobj, NULL); } /* If the interface has the default route, and has IPv6 addresses, capture * nameservers from /etc/resolv.conf. */ - if (priv->addresses->len && has_gateway && capture_resolv_conf) + if (has_addresses && has_gateway && capture_resolv_conf) notify_nameservers = nm_ip6_config_capture_resolv_conf (priv->nameservers, priv->dns_options, NULL); - g_array_sort_with_data (priv->addresses, _addresses_sort_cmp, GINT_TO_POINTER (use_temporary)); - /* actually, nobody should be connected to the signal, just to be sure, notify */ if (notify_nameservers) - _notify (config, PROP_NAMESERVERS); - _notify (config, PROP_ADDRESS_DATA); - _notify (config, PROP_ADDRESSES); - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); + _notify (self, PROP_NAMESERVERS); + _notify_addresses (self); + _notify_routes (self); if (!IN6_ARE_ADDR_EQUAL (&priv->gateway, &old_gateway)) - _notify (config, PROP_GATEWAY); + _notify (self, PROP_GATEWAY); - return config; + return self; } gboolean -nm_ip6_config_commit (const NMIP6Config *config, +nm_ip6_config_commit (const NMIP6Config *self, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + gs_unref_ptrarray GPtrArray *addresses = NULL; + const NMDedupMultiHeadEntry *head_entry; g_return_val_if_fail (ifindex > 0, FALSE); - g_return_val_if_fail (config != NULL, FALSE); + g_return_val_if_fail (self != NULL, FALSE); /* Addresses */ - nm_platform_ip6_address_sync (platform, ifindex, priv->addresses, TRUE); + addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_ip6_config_lookup_addresses (self), + NULL, NULL); + + nm_platform_ip6_address_sync (platform, ifindex, addresses, TRUE); /* Routes */ { - const NMDedupMultiHeadEntry *head_entry; gs_unref_array GArray *routes = NULL; const CList *iter; - head_entry = _idx_ip6_routes (config); + head_entry = nm_ip6_config_lookup_routes (self); 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); + c_list_for_each (iter, &head_entry->lst_entries_head) { + g_array_append_vals (routes, + NMP_OBJECT_CAST_IP6_ROUTE (c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj), + 1); + } } if (!nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync)) @@ -537,7 +610,7 @@ merge_route_attributes (NMIPRoute *s_route, NMPlatformIP6Route *r) } void -nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, guint32 default_route_metric) +nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 default_route_metric) { NMIP6ConfigPrivate *priv; guint naddresses, nroutes, nnameservers, nsearches; @@ -549,26 +622,26 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu g_return_if_fail (NM_IS_SETTING_IP6_CONFIG (setting)); - priv = NM_IP6_CONFIG_GET_PRIVATE (config); + priv = NM_IP6_CONFIG_GET_PRIVATE (self); naddresses = nm_setting_ip_config_get_num_addresses (setting); nroutes = nm_setting_ip_config_get_num_routes (setting); nnameservers = nm_setting_ip_config_get_num_dns (setting); nsearches = nm_setting_ip_config_get_num_dns_searches (setting); - g_object_freeze_notify (G_OBJECT (config)); + g_object_freeze_notify (G_OBJECT (self)); /* Gateway */ if (nm_setting_ip_config_get_never_default (setting)) - nm_ip6_config_set_never_default (config, TRUE); + nm_ip6_config_set_never_default (self, TRUE); else if (nm_setting_ip_config_get_ignore_auto_routes (setting)) - nm_ip6_config_set_never_default (config, FALSE); + nm_ip6_config_set_never_default (self, FALSE); gateway_str = nm_setting_ip_config_get_gateway (setting); if (gateway_str) { struct in6_addr gateway; inet_pton (AF_INET6, gateway_str, &gateway); - nm_ip6_config_set_gateway (config, &gateway); + nm_ip6_config_set_gateway (self, &gateway); } if (priv->route_metric == -1) @@ -587,12 +660,12 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu address.preferred = NM_PLATFORM_LIFETIME_PERMANENT; address.addr_source = NM_IP_CONFIG_SOURCE_USER; - nm_ip6_config_add_address (config, &address); + _add_address (self, NULL, &address); } /* Routes */ if (nm_setting_ip_config_get_ignore_auto_routes (setting)) - nm_ip6_config_reset_routes (config); + nm_ip6_config_reset_routes (self); for (i = 0; i < nroutes; i++) { NMIPRoute *s_route = nm_setting_ip_config_get_route (setting, i); NMPlatformIP6Route route; @@ -612,69 +685,70 @@ nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, gu route.metric = nm_ip_route_get_metric (s_route); route.rt_source = NM_IP_CONFIG_SOURCE_USER; + nm_utils_ip6_address_clear_host_address (&route.network, &route.network, route.plen); + merge_route_attributes (s_route, &route); - _add_route (config, NULL, &route); + _add_route (self, NULL, &route); } /* DNS */ if (nm_setting_ip_config_get_ignore_auto_dns (setting)) { - nm_ip6_config_reset_nameservers (config); - nm_ip6_config_reset_domains (config); - nm_ip6_config_reset_searches (config); + nm_ip6_config_reset_nameservers (self); + nm_ip6_config_reset_domains (self); + nm_ip6_config_reset_searches (self); } for (i = 0; i < nnameservers; i++) { struct in6_addr ip; if (inet_pton (AF_INET6, nm_setting_ip_config_get_dns (setting, i), &ip) == 1) - nm_ip6_config_add_nameserver (config, &ip); + nm_ip6_config_add_nameserver (self, &ip); } for (i = 0; i < nsearches; i++) - nm_ip6_config_add_search (config, nm_setting_ip_config_get_dns_search (setting, i)); + nm_ip6_config_add_search (self, nm_setting_ip_config_get_dns_search (setting, i)); i = 0; while ((i = nm_setting_ip_config_next_valid_dns_option (setting, i)) >= 0) { - nm_ip6_config_add_dns_option (config, nm_setting_ip_config_get_dns_option (setting, i)); + nm_ip6_config_add_dns_option (self, nm_setting_ip_config_get_dns_option (setting, i)); i++; } priority = nm_setting_ip_config_get_dns_priority (setting); if (priority) - nm_ip6_config_set_dns_priority (config, priority); + nm_ip6_config_set_dns_priority (self, priority); - g_object_thaw_notify (G_OBJECT (config)); + g_object_thaw_notify (G_OBJECT (self)); } NMSetting * -nm_ip6_config_create_setting (const NMIP6Config *config) +nm_ip6_config_create_setting (const NMIP6Config *self) { NMSettingIPConfig *s_ip6; const struct in6_addr *gateway; - guint naddresses, nnameservers, nsearches, noptions; + guint nnameservers, nsearches, noptions; const char *method = NULL; int i; gint64 route_metric; NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *address; const NMPlatformIP6Route *route; s_ip6 = NM_SETTING_IP_CONFIG (nm_setting_ip6_config_new ()); - if (!config) { + if (!self) { g_object_set (s_ip6, NM_SETTING_IP_CONFIG_METHOD, NM_SETTING_IP6_CONFIG_METHOD_IGNORE, NULL); return NM_SETTING (s_ip6); } - gateway = nm_ip6_config_get_gateway (config); - naddresses = nm_ip6_config_get_num_addresses (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); - route_metric = nm_ip6_config_get_route_metric (config); + gateway = nm_ip6_config_get_gateway (self); + nnameservers = nm_ip6_config_get_num_nameservers (self); + nsearches = nm_ip6_config_get_num_searches (self); + noptions = nm_ip6_config_get_num_dns_options (self); + route_metric = nm_ip6_config_get_route_metric (self); /* Addresses */ - for (i = 0; i < naddresses; i++) { - const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) { NMIPAddress *s_addr; /* Ignore link-local address. */ @@ -717,7 +791,7 @@ nm_ip6_config_create_setting (const NMIP6Config *config) NULL); /* Routes */ - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) { + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &route) { NMIPRoute *s_route; /* Ignore link-local route. */ @@ -742,24 +816,24 @@ nm_ip6_config_create_setting (const NMIP6Config *config) /* DNS */ for (i = 0; i < nnameservers; i++) { - const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (config, i); + const struct in6_addr *nameserver = nm_ip6_config_get_nameserver (self, i); nm_setting_ip_config_add_dns (s_ip6, nm_utils_inet6_ntop (nameserver, NULL)); } for (i = 0; i < nsearches; i++) { - const char *search = nm_ip6_config_get_search (config, i); + const char *search = nm_ip6_config_get_search (self, i); nm_setting_ip_config_add_dns_search (s_ip6, search); } for (i = 0; i < noptions; i++) { - const char *option = nm_ip6_config_get_dns_option (config, i); + const char *option = nm_ip6_config_get_dns_option (self, i); nm_setting_ip_config_add_dns_option (s_ip6, option); } g_object_set (s_ip6, NM_SETTING_IP_CONFIG_DNS_PRIORITY, - nm_ip6_config_get_dns_priority (config), + nm_ip6_config_get_dns_priority (self), NULL); return NM_SETTING (s_ip6); @@ -774,6 +848,7 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl const NMIP6ConfigPrivate *src_priv; guint32 i; NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *address = NULL; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -784,8 +859,8 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++) - nm_ip6_config_add_address (dst, nm_ip6_config_get_address (src, i)); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, src, &address) + _add_address (dst, NMP_OBJECT_UP_CAST (address), NULL); /* nameservers */ if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_DNS)) { @@ -801,7 +876,7 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl if (!NM_FLAGS_HAS (merge_flags, NM_IP_CONFIG_MERGE_NO_ROUTES)) { const NMPlatformIP6Route *route; - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, src, &route) + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &route) _add_route (dst, NMP_OBJECT_UP_CAST (route), NULL); } @@ -839,17 +914,15 @@ nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFl } gboolean -nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6_addr *network, guint8 plen) +nm_ip6_config_destination_is_direct (const NMIP6Config *self, const struct in6_addr *network, guint8 plen) { - guint num = nm_ip6_config_get_num_addresses (config); - guint i; + const NMPlatformIP6Address *item; + NMDedupMultiIter iter; nm_assert (network); nm_assert (plen <= 128); - for (i = 0; i < num; i++) { - const NMPlatformIP6Address *item = nm_ip6_config_get_address (config, i); - + nm_ip_config_iter_ip6_address_for_each (&iter, self, &item) { if ( item->plen <= plen && !NM_FLAGS_HAS (item->n_ifa_flags, IFA_F_NOPREFIXROUTE) && nm_utils_ip6_address_same_prefix (&item->address, network, item->plen)) @@ -862,21 +935,6 @@ nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6 /*****************************************************************************/ static int -_addresses_get_index (const NMIP6Config *self, const NMPlatformIP6Address *addr) -{ - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); - guint i; - - for (i = 0; i < priv->addresses->len; i++) { - const NMPlatformIP6Address *a = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - - if (addresses_are_duplicate (a, addr)) - return (int) i; - } - return -1; -} - -static int _nameservers_get_index (const NMIP6Config *self, const struct in6_addr *ns) { const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); @@ -951,9 +1009,11 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) NMIP6ConfigPrivate *priv_dst; guint i; gint idx; + const NMPlatformIP6Address *a; const NMPlatformIP6Route *r; NMDedupMultiIter ipconf_iter; const struct in6_addr *dst_tmp, *src_tmp; + gboolean changed; g_return_if_fail (src != NULL); g_return_if_fail (dst != NULL); @@ -963,11 +1023,15 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - for (i = 0; i < nm_ip6_config_get_num_addresses (src); i++) { - idx = _addresses_get_index (dst, nm_ip6_config_get_address (src, i)); - if (idx >= 0) - nm_ip6_config_del_address (dst, idx); + changed = FALSE; + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, src, &a) { + if (nm_dedup_multi_index_remove_obj (priv_dst->multi_idx, + &priv_dst->idx_ip6_addresses, + NMP_OBJECT_UP_CAST (a))) + changed = TRUE; } + if (changed) + _notify_addresses (dst); /* nameservers */ for (i = 0; i < nm_ip6_config_get_num_nameservers (src); i++) { @@ -988,11 +1052,15 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src) /* ignore route_metric */ /* routes */ - 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)); + changed = FALSE; + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) { + if (nm_dedup_multi_index_remove_obj (priv_dst->multi_idx, + &priv_dst->idx_ip6_routes, + NMP_OBJECT_UP_CAST (r))) + changed = TRUE; } + if (changed) + _notify_routes (dst); /* domains */ for (i = 0; i < nm_ip6_config_get_num_domains (src); i++) { @@ -1030,11 +1098,11 @@ 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 NMPlatformIP6Address *a; const NMPlatformIP6Route *r; + gboolean changed; g_return_if_fail (src); g_return_if_fail (dst); @@ -1045,13 +1113,20 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) g_object_freeze_notify (G_OBJECT (dst)); /* addresses */ - for (i = 0; i < nm_ip6_config_get_num_addresses (dst); ) { - idx = _addresses_get_index (src, nm_ip6_config_get_address (dst, i)); - if (idx < 0) - nm_ip6_config_del_address (dst, i); - else - i++; + changed = FALSE; + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, dst, &a) { + if (nm_dedup_multi_index_lookup_obj (priv_src->multi_idx, + &priv_src->idx_ip6_addresses, + NMP_OBJECT_UP_CAST (a))) + continue; + + if (nm_dedup_multi_index_remove_entry (priv_dst->multi_idx, + ipconf_iter.current) != 1) + nm_assert_not_reached (); + changed = TRUE; } + if (changed) + _notify_addresses (dst); /* ignore route_metric */ /* ignore nameservers */ @@ -1067,7 +1142,8 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) } /* routes */ - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, dst, &r) { + changed = FALSE; + nm_ip_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))) @@ -1076,7 +1152,10 @@ nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src) if (nm_dedup_multi_index_remove_entry (priv_dst->multi_idx, ipconf_iter.current) != 1) nm_assert_not_reached (); + changed = TRUE; } + if (changed) + _notify_routes (dst); /* ignore domains */ /* ignore dns searches */ @@ -1109,8 +1188,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev guint i, num; NMIP6ConfigPrivate *dst_priv; const NMIP6ConfigPrivate *src_priv; - const NMPlatformIP6Address *dst_addr, *src_addr; NMDedupMultiIter ipconf_iter_src, ipconf_iter_dst; + const NMDedupMultiHeadEntry *head_entry_src; g_return_val_if_fail (NM_IS_IP6_CONFIG (src), FALSE); g_return_val_if_fail (NM_IS_IP6_CONFIG (dst), FALSE); @@ -1149,41 +1228,61 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev } /* addresses */ - num = nm_ip6_config_get_num_addresses (src); - are_equal = num == nm_ip6_config_get_num_addresses (dst); - if (are_equal) { - for (i = 0; i < num; i++ ) { - if (nm_platform_ip6_address_cmp (src_addr = nm_ip6_config_get_address (src, i), - dst_addr = nm_ip6_config_get_address (dst, i))) { - are_equal = FALSE; - if ( !addresses_are_duplicate (src_addr, dst_addr) - || src_addr->plen != dst_addr->plen - || !IN6_ARE_ADDR_EQUAL (nm_platform_ip6_address_get_peer (src_addr), - nm_platform_ip6_address_get_peer (dst_addr))) { - has_relevant_changes = TRUE; - break; - } + head_entry_src = nm_ip6_config_lookup_addresses (src); + nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src); + nm_ip_config_iter_ip6_address_init (&ipconf_iter_dst, dst); + are_equal = TRUE; + while (TRUE) { + gboolean has; + const NMPlatformIP6Address *r_src = NULL; + const NMPlatformIP6Address *r_dst = NULL; + + has = nm_ip_config_iter_ip6_address_next (&ipconf_iter_src, &r_src); + if (has != nm_ip_config_iter_ip6_address_next (&ipconf_iter_dst, &r_dst)) { + are_equal = FALSE; + has_relevant_changes = TRUE; + break; + } + if (!has) + break; + + if (nm_platform_ip6_address_cmp (r_src, r_dst) != 0) { + are_equal = FALSE; + if ( !nm_ip_config_obj_id_equal_ip6_address (r_src, r_dst) + || r_src->plen != r_dst->plen + || !IN6_ARE_ADDR_EQUAL (nm_platform_ip6_address_get_peer (r_src), + nm_platform_ip6_address_get_peer (r_dst))) { + has_relevant_changes = TRUE; + break; } } - } else - has_relevant_changes = TRUE; + } if (!are_equal) { - nm_ip6_config_reset_addresses (dst); - for (i = 0; i < num; i++) - nm_ip6_config_add_address (dst, nm_ip6_config_get_address (src, i)); has_minor_changes = TRUE; + nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_addresses); + nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) { + nm_dedup_multi_index_add (dst_priv->multi_idx, + &dst_priv->idx_ip6_addresses, + ipconf_iter_src.current->obj, + NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, + NULL, + NULL); + } + nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_addresses, FALSE); } /* routes */ - nm_ip6_config_iter_ip6_route_init (&ipconf_iter_src, src); - nm_ip6_config_iter_ip6_route_init (&ipconf_iter_dst, dst); + head_entry_src = nm_ip6_config_lookup_routes (src); + nm_dedup_multi_iter_init (&ipconf_iter_src, head_entry_src); + nm_ip_config_iter_ip6_route_init (&ipconf_iter_dst, dst); are_equal = TRUE; while (TRUE) { gboolean has; - const NMPlatformIP6Route *r_src, *r_dst; + const NMPlatformIP6Route *r_src = NULL; + const NMPlatformIP6Route *r_dst = NULL; - 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)) { + has = nm_ip_config_iter_ip6_route_next (&ipconf_iter_src, &r_src); + if (has != nm_ip_config_iter_ip6_route_next (&ipconf_iter_dst, &r_dst)) { are_equal = FALSE; has_relevant_changes = TRUE; break; @@ -1202,15 +1301,12 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev } } if (!are_equal) { - 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_iter_for_each (&ipconf_iter_src, head_entry_src) { nm_dedup_multi_index_add (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, - NMP_OBJECT_UP_CAST (r_src), + ipconf_iter_src.current->obj, NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE, NULL, NULL); @@ -1326,81 +1422,82 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev } void -nm_ip6_config_dump (const NMIP6Config *config, const char *detail) +nm_ip6_config_dump (const NMIP6Config *self, const char *detail) { const struct in6_addr *tmp; guint32 i; const char *str; NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *address; const NMPlatformIP6Route *route; - g_return_if_fail (config != NULL); + g_return_if_fail (self != NULL); - g_message ("--------- NMIP6Config %p (%s)", config, detail); + g_message ("--------- NMIP6Config %p (%s)", self, detail); - str = nm_exported_object_get_path (NM_EXPORTED_OBJECT (config)); + str = nm_exported_object_get_path (NM_EXPORTED_OBJECT (self)); if (str) g_message (" path: %s", str); /* addresses */ - for (i = 0; i < nm_ip6_config_get_num_addresses (config); i++) - g_message (" a: %s", nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i), NULL, 0)); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) + g_message (" a: %s", nm_platform_ip6_address_to_string (address, NULL, 0)); /* default gateway */ - tmp = nm_ip6_config_get_gateway (config); + tmp = nm_ip6_config_get_gateway (self); if (tmp) g_message (" gw: %s", nm_utils_inet6_ntop (tmp, NULL)); /* nameservers */ - for (i = 0; i < nm_ip6_config_get_num_nameservers (config); i++) { - tmp = nm_ip6_config_get_nameserver (config, i); + for (i = 0; i < nm_ip6_config_get_num_nameservers (self); i++) { + tmp = nm_ip6_config_get_nameserver (self, i); g_message (" ns: %s", nm_utils_inet6_ntop (tmp, NULL)); } /* routes */ - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &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++) - g_message (" domain: %s", nm_ip6_config_get_domain (config, i)); + for (i = 0; i < nm_ip6_config_get_num_domains (self); i++) + g_message (" domain: %s", nm_ip6_config_get_domain (self, i)); /* dns searches */ - for (i = 0; i < nm_ip6_config_get_num_searches (config); i++) - g_message (" search: %s", nm_ip6_config_get_search (config, i)); + for (i = 0; i < nm_ip6_config_get_num_searches (self); i++) + g_message (" search: %s", nm_ip6_config_get_search (self, i)); /* dns options */ - for (i = 0; i < nm_ip6_config_get_num_dns_options (config); i++) - g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (config, i)); + for (i = 0; i < nm_ip6_config_get_num_dns_options (self); i++) + g_message (" dnsopt: %s", nm_ip6_config_get_dns_option (self, i)); - g_message (" dnspri: %d", nm_ip6_config_get_dns_priority (config)); + g_message (" dnspri: %d", nm_ip6_config_get_dns_priority (self)); - g_message (" mss: %"G_GUINT32_FORMAT, nm_ip6_config_get_mss (config)); - g_message (" n-dflt: %d", nm_ip6_config_get_never_default (config)); + g_message (" mss: %"G_GUINT32_FORMAT, nm_ip6_config_get_mss (self)); + g_message (" n-dflt: %d", nm_ip6_config_get_never_default (self)); } /*****************************************************************************/ void -nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default) +nm_ip6_config_set_never_default (NMIP6Config *self, gboolean never_default) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); priv->never_default = never_default; } gboolean -nm_ip6_config_get_never_default (const NMIP6Config *config) +nm_ip6_config_get_never_default (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return priv->never_default; } void -nm_ip6_config_set_gateway (NMIP6Config *config, const struct in6_addr *gateway) +nm_ip6_config_set_gateway (NMIP6Config *self, const struct in6_addr *gateway) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); if (gateway) { if (IN6_ARE_ADDR_EQUAL (&priv->gateway, gateway)) @@ -1411,21 +1508,21 @@ nm_ip6_config_set_gateway (NMIP6Config *config, const struct in6_addr *gateway) return; memset (&priv->gateway, 0, sizeof (priv->gateway)); } - _notify (config, PROP_GATEWAY); + _notify (self, PROP_GATEWAY); } const struct in6_addr * -nm_ip6_config_get_gateway (const NMIP6Config *config) +nm_ip6_config_get_gateway (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return IN6_IS_ADDR_UNSPECIFIED (&priv->gateway) ? NULL : &priv->gateway; } gint64 -nm_ip6_config_get_route_metric (const NMIP6Config *config) +nm_ip6_config_get_route_metric (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return priv->route_metric; } @@ -1433,122 +1530,136 @@ nm_ip6_config_get_route_metric (const NMIP6Config *config) /*****************************************************************************/ void -nm_ip6_config_reset_addresses (NMIP6Config *config) +nm_ip6_config_reset_addresses (NMIP6Config *self) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); - if (priv->addresses->len != 0) { - g_array_set_size (priv->addresses, 0); - notify_addresses (config); - } + if (nm_dedup_multi_index_remove_idx (priv->multi_idx, + &priv->idx_ip6_addresses) > 0) + _notify_addresses (self); +} + +static void +_add_address (NMIP6Config *self, + const NMPObject *obj_new, + const NMPlatformIP6Address *new) +{ + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + + if (_nm_ip_config_add_obj (priv->multi_idx, + &priv->idx_ip6_addresses_, + priv->ifindex, + obj_new, + (const NMPlatformObject *) new)) + _notify_addresses (self); } /** * nm_ip6_config_add_address: - * @config: the #NMIP6Config - * @new: the new address to add to @config + * @self: the #NMIP6Config + * @new: the new address to add to @self * - * Adds the new address to @config. If an address with the same basic properties - * (address, prefix) already exists in @config, it is overwritten with the + * Adds the new address to @self. If an address with the same basic properties + * (address, prefix) already exists in @self, it is overwritten with the * lifetime and preferred of @new. The source is also overwritten by the source * from @new if that source is higher priority. */ void -nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *new) +nm_ip6_config_add_address (NMIP6Config *self, const NMPlatformIP6Address *new) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - NMPlatformIP6Address item_old; - int i; - - g_return_if_fail (new != NULL); - - for (i = 0; i < priv->addresses->len; i++ ) { - NMPlatformIP6Address *item = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - - if (addresses_are_duplicate (item, new)) { - if (nm_platform_ip6_address_cmp (item, new) == 0) - return; - - /* remember the old values. */ - item_old = *item; - /* Copy over old item to get new lifetime, timestamp, preferred */ - *item = *new; - - /* But restore highest priority source */ - item->addr_source = MAX (item_old.addr_source, new->addr_source); - - /* for addresses that we read from the kernel, we keep the timestamps as defined - * by the previous source (item_old). The reason is, that the other source configured the lifetimes - * with "what should be" and the kernel values are "what turned out after configuring it". - * - * For other sources, the longer lifetime wins. */ - if ( (new->addr_source == NM_IP_CONFIG_SOURCE_KERNEL && new->addr_source != item_old.addr_source) - || nm_platform_ip_address_cmp_expiry ((const NMPlatformIPAddress *) &item_old, (const NMPlatformIPAddress *) new) > 0) { - item->timestamp = item_old.timestamp; - item->lifetime = item_old.lifetime; - item->preferred = item_old.preferred; - } - if (nm_platform_ip6_address_cmp (&item_old, item) == 0) - return; - goto NOTIFY; - } - } + g_return_if_fail (self); + g_return_if_fail (new); + g_return_if_fail (new->plen > 0 && new->plen <= 128); + g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (self)->ifindex > 0); - g_array_append_val (priv->addresses, *new); -NOTIFY: -notify_addresses (config); + _add_address (self, NULL, new); } void -nm_ip6_config_del_address (NMIP6Config *config, guint i) +_nmtst_nm_ip6_config_del_address (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - - g_return_if_fail (i < priv->addresses->len); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + const NMPlatformIP6Address *a; - g_array_remove_index (priv->addresses, i); + a = _nmtst_nm_ip6_config_get_address (self, i); + g_return_if_fail (a); - notify_addresses (config); + if (nm_dedup_multi_index_remove_obj (priv->multi_idx, + &priv->idx_ip6_addresses, + NMP_OBJECT_UP_CAST (a)) != 1) + g_return_if_reached (); + _notify_addresses (self); } guint -nm_ip6_config_get_num_addresses (const NMIP6Config *config) +nm_ip6_config_get_num_addresses (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMDedupMultiHeadEntry *head_entry; - return priv->addresses->len; + head_entry = nm_ip6_config_lookup_addresses (self); + return head_entry ? head_entry->len : 0; } const NMPlatformIP6Address * -nm_ip6_config_get_address (const NMIP6Config *config, guint i) +nm_ip6_config_get_first_address (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMDedupMultiIter iter; + const NMPlatformIP6Address *a = NULL; - return &g_array_index (priv->addresses, NMPlatformIP6Address, i); + nm_ip_config_iter_ip6_address_for_each (&iter, self, &a) + return a; + return NULL; } -gboolean -nm_ip6_config_address_exists (const NMIP6Config *config, - const NMPlatformIP6Address *needle) +const NMPlatformIP6Address * +_nmtst_nm_ip6_config_get_address (const NMIP6Config *self, guint i) { - return _addresses_get_index (config, needle) >= 0; + NMDedupMultiIter iter; + const NMPlatformIP6Address *a = NULL; + guint j; + + j = 0; + nm_ip_config_iter_ip6_address_for_each (&iter, self, &a) { + if (i == j) + return a; + j++; + } + g_return_val_if_reached (NULL); } const NMPlatformIP6Address * -nm_ip6_config_get_address_first_nontentative (const NMIP6Config *config, gboolean linklocal) +nm_ip6_config_lookup_address (const NMIP6Config *self, + const struct in6_addr *addr) +{ + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + NMPObject obj_stack; + const NMDedupMultiEntry *entry; + + nmp_object_stackinit_id_ip6_address (&obj_stack, + priv->ifindex, + addr); + entry = nm_dedup_multi_index_lookup_obj (priv->multi_idx, + &priv->idx_ip6_routes, + &obj_stack); + return entry + ? NMP_OBJECT_CAST_IP6_ADDRESS (entry->obj) + : NULL; +} + +const NMPlatformIP6Address * +nm_ip6_config_get_address_first_nontentative (const NMIP6Config *self, gboolean linklocal) { const NMIP6ConfigPrivate *priv; - guint i; + const NMPlatformIP6Address *addr; + NMDedupMultiIter iter; - g_return_val_if_fail (NM_IS_IP6_CONFIG (config), NULL); + g_return_val_if_fail (NM_IS_IP6_CONFIG (self), NULL); - priv = NM_IP6_CONFIG_GET_PRIVATE (config); + priv = NM_IP6_CONFIG_GET_PRIVATE (self); linklocal = !!linklocal; - for (i = 0; i < priv->addresses->len; i++) { - const NMPlatformIP6Address *addr = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - + nm_ip_config_iter_ip6_address_for_each (&iter, self, &addr) { if ( ((!!IN6_IS_ADDR_LINKLOCAL (&addr->address)) == linklocal) && !(addr->n_ifa_flags & IFA_F_TENTATIVE)) return addr; @@ -1573,23 +1684,16 @@ gboolean nm_ip6_config_has_any_dad_pending (const NMIP6Config *self, const NMIP6Config *candidates) { + NMDedupMultiIter ipconf_iter; const NMPlatformIP6Address *addr, *addr_c; - guint i, j, num, num_c; - - num = nm_ip6_config_get_num_addresses (self); - for (i = 0; i < num; i++) { - addr = nm_ip6_config_get_address (self, i); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &addr) { if ( NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_TENTATIVE) && !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_DADFAILED) && !NM_FLAGS_HAS (addr->n_ifa_flags, IFA_F_OPTIMISTIC)) { - - num_c = nm_ip6_config_get_num_addresses (candidates); - - for (j = 0; j < num_c; j++) { - addr_c = nm_ip6_config_get_address (candidates, j); - if ( addresses_are_duplicate (addr, addr_c) - && addr->plen == addr_c->plen) + addr_c = nm_ip6_config_lookup_address (candidates, &addr->address); + if (addr_c) { + if (addr->plen == addr_c->plen) return TRUE; } } @@ -1601,107 +1705,51 @@ nm_ip6_config_has_any_dad_pending (const NMIP6Config *self, /*****************************************************************************/ void -nm_ip6_config_reset_routes (NMIP6Config *config) +nm_ip6_config_reset_routes (NMIP6Config *self) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); if (nm_dedup_multi_index_remove_idx (priv->multi_idx, - &priv->idx_ip6_routes) > 0) { - _notify (config, PROP_ROUTE_DATA); - _notify (config, PROP_ROUTES); - } + &priv->idx_ip6_routes) > 0) + _notify_routes (self); } static void -_add_route (NMIP6Config *config, const NMPObject *o_new, const NMPlatformIP6Route *new) +_add_route (NMIP6Config *self, const NMPObject *obj_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; - } - } + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); - 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; + nm_assert ((!new) != (!obj_new)); + nm_assert (!new || _route_valid (new)); + nm_assert (!obj_new || _route_valid (NMP_OBJECT_CAST_IP6_ROUTE (obj_new))); - 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); + if (_nm_ip_config_add_obj (priv->multi_idx, + &priv->idx_ip6_routes_, + priv->ifindex, + obj_new, + (const NMPlatformObject *) new)) + _notify_routes (self); } /** * nm_ip6_config_add_route: - * @config: the #NMIP6Config - * @new: the new route to add to @config + * @self: the #NMIP6Config + * @new: the new route to add to @self * - * Adds the new route to @config. If a route with the same basic properties - * (network, prefix) already exists in @config, it is overwritten including the + * Adds the new route to @self. If a route with the same basic properties + * (network, prefix) already exists in @self, it is overwritten including the * gateway and metric of @new. The source is also overwritten by the source * from @new if that source is higher priority. */ void -nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *new) +nm_ip6_config_add_route (NMIP6Config *self, const NMPlatformIP6Route *new) { - g_return_if_fail (config); + g_return_if_fail (self); g_return_if_fail (new); g_return_if_fail (new->plen > 0 && new->plen <= 128); - g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (config)->ifindex > 0); + g_return_if_fail (NM_IP6_CONFIG_GET_PRIVATE (self)->ifindex > 0); - _add_route (config, NULL, new); + _add_route (self, NULL, new); } void @@ -1717,8 +1765,7 @@ _nmtst_ip6_config_del_route (NMIP6Config *self, guint i) &priv->idx_ip6_routes, NMP_OBJECT_UP_CAST (r)) != 1) g_return_if_reached (); - _notify (self, PROP_ROUTE_DATA); - _notify (self, PROP_ROUTES); + _notify_routes (self); } guint @@ -1726,7 +1773,7 @@ nm_ip6_config_get_num_routes (const NMIP6Config *self) { const NMDedupMultiHeadEntry *head_entry; - head_entry = _idx_ip6_routes (self); + head_entry = nm_ip6_config_lookup_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; } @@ -1734,18 +1781,15 @@ nm_ip6_config_get_num_routes (const NMIP6Config *self) const NMPlatformIP6Route * _nmtst_ip6_config_get_route (const NMIP6Config *self, guint i) { - const NMDedupMultiHeadEntry *head_entry; - CList *iter; + NMDedupMultiIter iter; + const NMPlatformIP6Route *r = NULL; guint j; - head_entry = _idx_ip6_routes (self); - if (head_entry) { - j = 0; - c_list_for_each (iter, &head_entry->lst_entries_head) { - if (i == j) - return _entry_iter_get_ip6_route (iter); - j++; - } + j = 0; + nm_ip_config_iter_ip6_route_for_each (&iter, self, &r) { + if (i == j) + return r; + j++; } g_return_val_if_reached (NULL); } @@ -1759,7 +1803,7 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct i g_return_val_if_fail (host && !IN6_IS_ADDR_UNSPECIFIED (host), NULL); - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, self, &item) { + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &item) { if (!IN6_IS_ADDR_UNSPECIFIED (&item->gateway)) continue; @@ -1779,18 +1823,16 @@ nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct i } const NMPlatformIP6Address * -nm_ip6_config_get_subnet_for_host (const NMIP6Config *config, const struct in6_addr *host) +nm_ip6_config_get_subnet_for_host (const NMIP6Config *self, const struct in6_addr *host) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); - guint i; - NMPlatformIP6Address *subnet = NULL; + NMDedupMultiIter iter; + const NMPlatformIP6Address *item; + const NMPlatformIP6Address *subnet = NULL; struct in6_addr subnet2, host2; g_return_val_if_fail (host && !IN6_IS_ADDR_UNSPECIFIED (host), NULL); - for (i = 0; i < priv->addresses->len; i++) { - NMPlatformIP6Address *item = &g_array_index (priv->addresses, NMPlatformIP6Address, i); - + nm_ip_config_iter_ip6_address_for_each (&iter, self, &item) { if (subnet && subnet->plen >= item->plen) continue; @@ -1808,20 +1850,20 @@ nm_ip6_config_get_subnet_for_host (const NMIP6Config *config, const struct in6_a /*****************************************************************************/ void -nm_ip6_config_reset_nameservers (NMIP6Config *config) +nm_ip6_config_reset_nameservers (NMIP6Config *self) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); if (priv->nameservers->len != 0) { g_array_set_size (priv->nameservers, 0); - _notify (config, PROP_NAMESERVERS); + _notify (self, PROP_NAMESERVERS); } } void -nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *new) +nm_ip6_config_add_nameserver (NMIP6Config *self, const struct in6_addr *new) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); int i; g_return_if_fail (new != NULL); @@ -1831,32 +1873,32 @@ nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *new) return; g_array_append_val (priv->nameservers, *new); - _notify (config, PROP_NAMESERVERS); + _notify (self, PROP_NAMESERVERS); } void -nm_ip6_config_del_nameserver (NMIP6Config *config, guint i) +nm_ip6_config_del_nameserver (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->nameservers->len); g_array_remove_index (priv->nameservers, i); - _notify (config, PROP_NAMESERVERS); + _notify (self, PROP_NAMESERVERS); } guint -nm_ip6_config_get_num_nameservers (const NMIP6Config *config) +nm_ip6_config_get_num_nameservers (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return priv->nameservers->len; } const struct in6_addr * -nm_ip6_config_get_nameserver (const NMIP6Config *config, guint i) +nm_ip6_config_get_nameserver (const NMIP6Config *self, guint i) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return &g_array_index (priv->nameservers, struct in6_addr, i); } @@ -1864,20 +1906,20 @@ nm_ip6_config_get_nameserver (const NMIP6Config *config, guint i) /*****************************************************************************/ void -nm_ip6_config_reset_domains (NMIP6Config *config) +nm_ip6_config_reset_domains (NMIP6Config *self) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); if (priv->domains->len != 0) { g_ptr_array_set_size (priv->domains, 0); - _notify (config, PROP_DOMAINS); + _notify (self, PROP_DOMAINS); } } void -nm_ip6_config_add_domain (NMIP6Config *config, const char *domain) +nm_ip6_config_add_domain (NMIP6Config *self, const char *domain) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); int i; g_return_if_fail (domain != NULL); @@ -1888,32 +1930,32 @@ nm_ip6_config_add_domain (NMIP6Config *config, const char *domain) return; g_ptr_array_add (priv->domains, g_strdup (domain)); - _notify (config, PROP_DOMAINS); + _notify (self, PROP_DOMAINS); } void -nm_ip6_config_del_domain (NMIP6Config *config, guint i) +nm_ip6_config_del_domain (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->domains->len); g_ptr_array_remove_index (priv->domains, i); - _notify (config, PROP_DOMAINS); + _notify (self, PROP_DOMAINS); } guint -nm_ip6_config_get_num_domains (const NMIP6Config *config) +nm_ip6_config_get_num_domains (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return priv->domains->len; } const char * -nm_ip6_config_get_domain (const NMIP6Config *config, guint i) +nm_ip6_config_get_domain (const NMIP6Config *self, guint i) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return g_ptr_array_index (priv->domains, i); } @@ -1921,20 +1963,20 @@ nm_ip6_config_get_domain (const NMIP6Config *config, guint i) /*****************************************************************************/ void -nm_ip6_config_reset_searches (NMIP6Config *config) +nm_ip6_config_reset_searches (NMIP6Config *self) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); if (priv->searches->len != 0) { g_ptr_array_set_size (priv->searches, 0); - _notify (config, PROP_SEARCHES); + _notify (self, PROP_SEARCHES); } } void -nm_ip6_config_add_search (NMIP6Config *config, const char *new) +nm_ip6_config_add_search (NMIP6Config *self, const char *new) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); char *search; size_t len; @@ -1960,32 +2002,32 @@ nm_ip6_config_add_search (NMIP6Config *config, const char *new) } g_ptr_array_add (priv->searches, search); - _notify (config, PROP_SEARCHES); + _notify (self, PROP_SEARCHES); } void -nm_ip6_config_del_search (NMIP6Config *config, guint i) +nm_ip6_config_del_search (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->searches->len); g_ptr_array_remove_index (priv->searches, i); - _notify (config, PROP_SEARCHES); + _notify (self, PROP_SEARCHES); } guint -nm_ip6_config_get_num_searches (const NMIP6Config *config) +nm_ip6_config_get_num_searches (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return priv->searches->len; } const char * -nm_ip6_config_get_search (const NMIP6Config *config, guint i) +nm_ip6_config_get_search (const NMIP6Config *self, guint i) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return g_ptr_array_index (priv->searches, i); } @@ -1993,20 +2035,20 @@ nm_ip6_config_get_search (const NMIP6Config *config, guint i) /*****************************************************************************/ void -nm_ip6_config_reset_dns_options (NMIP6Config *config) +nm_ip6_config_reset_dns_options (NMIP6Config *self) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); if (priv->dns_options->len != 0) { g_ptr_array_set_size (priv->dns_options, 0); - _notify (config, PROP_DNS_OPTIONS); + _notify (self, PROP_DNS_OPTIONS); } } void -nm_ip6_config_add_dns_option (NMIP6Config *config, const char *new) +nm_ip6_config_add_dns_option (NMIP6Config *self, const char *new) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); int i; g_return_if_fail (new != NULL); @@ -2017,32 +2059,32 @@ nm_ip6_config_add_dns_option (NMIP6Config *config, const char *new) return; g_ptr_array_add (priv->dns_options, g_strdup (new)); - _notify (config, PROP_DNS_OPTIONS); + _notify (self, PROP_DNS_OPTIONS); } void -nm_ip6_config_del_dns_option (NMIP6Config *config, guint i) +nm_ip6_config_del_dns_option (NMIP6Config *self, guint i) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); g_return_if_fail (i < priv->dns_options->len); g_ptr_array_remove_index (priv->dns_options, i); - _notify (config, PROP_DNS_OPTIONS); + _notify (self, PROP_DNS_OPTIONS); } guint -nm_ip6_config_get_num_dns_options (const NMIP6Config *config) +nm_ip6_config_get_num_dns_options (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return priv->dns_options->len; } const char * -nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i) +nm_ip6_config_get_dns_option (const NMIP6Config *self, guint i) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return g_ptr_array_index (priv->dns_options, i); } @@ -2050,20 +2092,20 @@ nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i) /*****************************************************************************/ void -nm_ip6_config_set_dns_priority (NMIP6Config *config, gint priority) +nm_ip6_config_set_dns_priority (NMIP6Config *self, gint priority) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); if (priority != priv->dns_priority) { priv->dns_priority = priority; - _notify (config, PROP_DNS_PRIORITY); + _notify (self, PROP_DNS_PRIORITY); } } gint -nm_ip6_config_get_dns_priority (const NMIP6Config *config) +nm_ip6_config_get_dns_priority (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return priv->dns_priority; } @@ -2071,17 +2113,17 @@ nm_ip6_config_get_dns_priority (const NMIP6Config *config) /*****************************************************************************/ void -nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss) +nm_ip6_config_set_mss (NMIP6Config *self, guint32 mss) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); priv->mss = mss; } guint32 -nm_ip6_config_get_mss (const NMIP6Config *config) +nm_ip6_config_get_mss (const NMIP6Config *self) { - const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + const NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); return priv->mss; } @@ -2104,27 +2146,26 @@ hash_in6addr (GChecksum *sum, const struct in6_addr *a) } void -nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only) +nm_ip6_config_hash (const NMIP6Config *self, GChecksum *sum, gboolean dns_only) { guint32 i; const char *s; NMDedupMultiIter ipconf_iter; + const NMPlatformIP6Address *address; const NMPlatformIP6Route *route; - g_return_if_fail (config); + g_return_if_fail (self); g_return_if_fail (sum); if (dns_only == FALSE) { - hash_in6addr (sum, nm_ip6_config_get_gateway (config)); - - for (i = 0; i < nm_ip6_config_get_num_addresses (config); i++) { - const NMPlatformIP6Address *address = nm_ip6_config_get_address (config, i); + hash_in6addr (sum, nm_ip6_config_get_gateway (self)); + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, self, &address) { hash_in6addr (sum, &address->address); hash_u32 (sum, address->plen); } - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, config, &route) { + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &route) { hash_in6addr (sum, &route->network); hash_u32 (sum, route->plen); hash_in6addr (sum, &route->gateway); @@ -2132,21 +2173,21 @@ nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only } } - for (i = 0; i < nm_ip6_config_get_num_nameservers (config); i++) - hash_in6addr (sum, nm_ip6_config_get_nameserver (config, i)); + for (i = 0; i < nm_ip6_config_get_num_nameservers (self); i++) + hash_in6addr (sum, nm_ip6_config_get_nameserver (self, i)); - for (i = 0; i < nm_ip6_config_get_num_domains (config); i++) { - s = nm_ip6_config_get_domain (config, i); + for (i = 0; i < nm_ip6_config_get_num_domains (self); i++) { + s = nm_ip6_config_get_domain (self, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } - for (i = 0; i < nm_ip6_config_get_num_searches (config); i++) { - s = nm_ip6_config_get_search (config, i); + for (i = 0; i < nm_ip6_config_get_num_searches (self); i++) { + s = nm_ip6_config_get_search (self, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } - for (i = 0; i < nm_ip6_config_get_num_dns_options (config); i++) { - s = nm_ip6_config_get_dns_option (config, i); + for (i = 0; i < nm_ip6_config_get_num_dns_options (self); i++) { + s = nm_ip6_config_get_dns_option (self, i); g_checksum_update (sum, (const guint8 *) s, strlen (s)); } } @@ -2217,11 +2258,12 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - NMIP6Config *config = NM_IP6_CONFIG (object); - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6Config *self = NM_IP6_CONFIG (object); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + const NMDedupMultiHeadEntry *head_entry; NMDedupMultiIter ipconf_iter; const NMPlatformIP6Route *route; - GVariantBuilder array_builder, addr_builder, route_builder; + GVariantBuilder builder_data, builder_legacy; switch (prop_id) { case PROP_IFINDEX: @@ -2229,26 +2271,31 @@ get_property (GObject *object, guint prop_id, break; case PROP_ADDRESS_DATA: case PROP_ADDRESSES: - { - gs_unref_array GArray *new = NULL; - const struct in6_addr *gateway; - guint naddr, i; + nm_assert (!!priv->address_data_variant == !!priv->addresses_variant); + + if (priv->address_data_variant) + goto out_addresses_cached; + + g_variant_builder_init (&builder_data, G_VARIANT_TYPE ("aa{sv}")); + g_variant_builder_init (&builder_legacy, G_VARIANT_TYPE ("a(ayuay)")); - g_return_if_fail (!!priv->address_data_variant == !!priv->addresses_variant); + head_entry = nm_ip6_config_lookup_addresses (self); + if (head_entry) { + gs_free const NMPObject **addresses = NULL; + guint naddr, i; - if (priv->address_data_variant) - goto return_cached; + addresses = (const NMPObject **) nm_dedup_multi_objs_to_array_head (head_entry, NULL, NULL, &naddr); + nm_assert (addresses && naddr); - naddr = nm_ip6_config_get_num_addresses (config); - gateway = nm_ip6_config_get_gateway (config); - new = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Address), naddr); - g_array_append_vals (new, priv->addresses->data, naddr); - g_array_sort_with_data (new, _addresses_sort_cmp, - GINT_TO_POINTER (priv->privacy)); + g_qsort_with_data (addresses, + naddr, + sizeof (addresses[0]), + _addresses_sort_cmp_prop, + GINT_TO_POINTER (priv->privacy)); - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); for (i = 0; i < naddr; i++) { - const NMPlatformIP6Address *address = &g_array_index (new, NMPlatformIP6Address, i); + GVariantBuilder addr_builder; + const NMPlatformIP6Address *address = NMP_OBJECT_CAST_IP6_ADDRESS (addresses[i]); g_variant_builder_init (&addr_builder, G_VARIANT_TYPE ("a{sv}")); g_variant_builder_add (&addr_builder, "{sv}", @@ -2264,68 +2311,67 @@ get_property (GObject *object, guint prop_id, g_variant_new_string (nm_utils_inet6_ntop (&address->peer_address, NULL))); } - g_variant_builder_add (&array_builder, "a{sv}", &addr_builder); - } - priv->address_data_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); - - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuay)")); - for (i = 0; i < naddr; i++) { - const NMPlatformIP6Address *address = &g_array_index (new, NMPlatformIP6Address, i); + g_variant_builder_add (&builder_data, "a{sv}", &addr_builder); - g_variant_builder_add (&array_builder, "(@ayu@ay)", + g_variant_builder_add (&builder_legacy, "(@ayu@ay)", g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &address->address, 16, 1), address->plen, g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, - (i == 0 && gateway ? gateway : &in6addr_any), + i == 0 + ? (nm_ip6_config_get_gateway (self) ?: &in6addr_any) + : &in6addr_any, 16, 1)); } - - priv->addresses_variant = g_variant_ref_sink (g_variant_builder_end (&array_builder)); -return_cached: - g_value_set_variant (value, - prop_id == PROP_ADDRESS_DATA ? - priv->address_data_variant : - priv->addresses_variant); } + + priv->address_data_variant = g_variant_ref_sink (g_variant_builder_end (&builder_data)); + priv->addresses_variant = g_variant_ref_sink (g_variant_builder_end (&builder_legacy)); +out_addresses_cached: + g_value_set_variant (value, + prop_id == PROP_ADDRESS_DATA ? + priv->address_data_variant : + priv->addresses_variant); break; + case PROP_ROUTE_DATA: - { - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("aa{sv}")); - 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", - g_variant_new_string (nm_utils_inet6_ntop (&route->network, NULL))); - g_variant_builder_add (&route_builder, "{sv}", - "prefix", - g_variant_new_uint32 (route->plen)); - if (!IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) { - g_variant_builder_add (&route_builder, "{sv}", - "next-hop", - g_variant_new_string (nm_utils_inet6_ntop (&route->gateway, NULL))); - } + case PROP_ROUTES: + nm_assert (!!priv->route_data_variant == !!priv->routes_variant); - g_variant_builder_add (&route_builder, "{sv}", - "metric", - g_variant_new_uint32 (route->metric)); + if (priv->route_data_variant) + goto out_routes_cached; + + g_variant_builder_init (&builder_data, G_VARIANT_TYPE ("aa{sv}")); + g_variant_builder_init (&builder_legacy, G_VARIANT_TYPE ("a(ayuayu)")); - g_variant_builder_add (&array_builder, "a{sv}", &route_builder); + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, self, &route) { + GVariantBuilder route_builder; + + nm_assert (_route_valid (route)); + + g_variant_builder_init (&route_builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&route_builder, "{sv}", + "dest", + g_variant_new_string (nm_utils_inet6_ntop (&route->network, NULL))); + g_variant_builder_add (&route_builder, "{sv}", + "prefix", + g_variant_new_uint32 (route->plen)); + if (!IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) { + g_variant_builder_add (&route_builder, "{sv}", + "next-hop", + g_variant_new_string (nm_utils_inet6_ntop (&route->gateway, NULL))); } - g_value_take_variant (value, g_variant_builder_end (&array_builder)); - } - break; - case PROP_ROUTES: - { - g_variant_builder_init (&array_builder, G_VARIANT_TYPE ("a(ayuayu)")); - 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)) - continue; - - g_variant_builder_add (&array_builder, "(@ayu@ayu)", + g_variant_builder_add (&route_builder, "{sv}", + "metric", + g_variant_new_uint32 (route->metric)); + + g_variant_builder_add (&builder_data, "a{sv}", &route_builder); + + /* 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)) { + g_variant_builder_add (&builder_legacy, "(@ayu@ayu)", g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, &route->network, 16, 1), (guint32) route->plen, @@ -2333,9 +2379,14 @@ return_cached: &route->gateway, 16, 1), (guint32) route->metric); } - - g_value_take_variant (value, g_variant_builder_end (&array_builder)); } + priv->route_data_variant = g_variant_ref_sink (g_variant_builder_end (&builder_data)); + priv->routes_variant = g_variant_ref_sink (g_variant_builder_end (&builder_legacy)); +out_routes_cached: + g_value_set_variant (value, + prop_id == PROP_ROUTE_DATA ? + priv->route_data_variant : + priv->routes_variant); break; case PROP_GATEWAY: if (!IN6_IS_ADDR_UNSPECIFIED (&priv->gateway)) @@ -2370,8 +2421,8 @@ set_property (GObject *object, const GValue *value, GParamSpec *pspec) { - NMIP6Config *config = NM_IP6_CONFIG (object); - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6Config *self = NM_IP6_CONFIG (object); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); switch (prop_id) { case PROP_MULTI_IDX: @@ -2394,14 +2445,15 @@ set_property (GObject *object, /*****************************************************************************/ static void -nm_ip6_config_init (NMIP6Config *config) +nm_ip6_config_init (NMIP6Config *self) { - NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (config); + NMIP6ConfigPrivate *priv = NM_IP6_CONFIG_GET_PRIVATE (self); + nm_ip_config_dedup_multi_idx_type_init ((NMIPConfigDedupMultiIdxType *) &priv->idx_ip6_addresses, + NMP_OBJECT_TYPE_IP6_ADDRESS); 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->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); @@ -2438,15 +2490,18 @@ 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_addresses); nm_dedup_multi_index_remove_idx (priv->multi_idx, &priv->idx_ip6_routes); - g_array_unref (priv->addresses); + nm_clear_g_variant (&priv->address_data_variant); + nm_clear_g_variant (&priv->addresses_variant); + nm_clear_g_variant (&priv->route_data_variant); + nm_clear_g_variant (&priv->routes_variant); + g_array_unref (priv->nameservers); g_ptr_array_unref (priv->domains); g_ptr_array_unref (priv->searches); g_ptr_array_unref (priv->dns_options); - nm_clear_g_variant (&priv->address_data_variant); - nm_clear_g_variant (&priv->addresses_variant); G_OBJECT_CLASS (nm_ip6_config_parent_class)->finalize (object); diff --git a/src/nm-ip6-config.h b/src/nm-ip6-config.h index a390ff1c23..f296224fab 100644 --- a/src/nm-ip6-config.h +++ b/src/nm-ip6-config.h @@ -27,15 +27,47 @@ #include "nm-setting-ip6-config.h" #include "nm-utils/nm-dedup-multi.h" +#include "platform/nmp-object.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); +void nm_ip_config_iter_ip6_address_init (NMDedupMultiIter *iter, const NMIP6Config *self); +void nm_ip_config_iter_ip6_route_init (NMDedupMultiIter *iter, const NMIP6Config *self); -#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)); \ +static inline gboolean +nm_ip_config_iter_ip6_address_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Address **out_address) +{ + gboolean has_next; + + g_return_val_if_fail (out_address, FALSE); + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (has_next) + *out_address = NMP_OBJECT_CAST_IP6_ADDRESS (ipconf_iter->current->obj); + return has_next; +} + +static inline gboolean +nm_ip_config_iter_ip6_route_next (NMDedupMultiIter *ipconf_iter, const NMPlatformIP6Route **out_route) +{ + gboolean has_next; + + g_return_val_if_fail (out_route, FALSE); + + has_next = nm_dedup_multi_iter_next (ipconf_iter); + if (has_next) + *out_route = NMP_OBJECT_CAST_IP6_ROUTE (ipconf_iter->current->obj); + return has_next; +} + +#define nm_ip_config_iter_ip6_address_for_each(iter, self, address) \ + for (*(address) = NULL, nm_ip_config_iter_ip6_address_init ((iter), (self)); \ + nm_ip_config_iter_ip6_address_next ((iter), (address)); \ + ) + +#define nm_ip_config_iter_ip6_route_for_each(iter, self, route) \ + for (*(route) = NULL, nm_ip_config_iter_ip6_route_init ((iter), (self)); \ + nm_ip_config_iter_ip6_route_next ((iter), (route)); \ ) /*****************************************************************************/ @@ -73,89 +105,94 @@ GType nm_ip6_config_get_type (void); 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); +int nm_ip6_config_get_ifindex (const NMIP6Config *self); struct _NMDedupMultiIndex *nm_ip6_config_get_multi_idx (const NMIP6Config *self); 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, +gboolean nm_ip6_config_commit (const NMIP6Config *self, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync); -void nm_ip6_config_merge_setting (NMIP6Config *config, NMSettingIPConfig *setting, guint32 default_route_metric); -NMSetting *nm_ip6_config_create_setting (const NMIP6Config *config); +void nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 default_route_metric); +NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self); void nm_ip6_config_merge (NMIP6Config *dst, const NMIP6Config *src, NMIPConfigMergeFlags merge_flags); void nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src); void nm_ip6_config_intersect (NMIP6Config *dst, const NMIP6Config *src); gboolean nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relevant_changes); -int nm_ip6_config_destination_is_direct (const NMIP6Config *config, const struct in6_addr *dest, guint8 plen); -void nm_ip6_config_dump (const NMIP6Config *config, const char *detail); - - -void nm_ip6_config_set_never_default (NMIP6Config *config, gboolean never_default); -gboolean nm_ip6_config_get_never_default (const NMIP6Config *config); -void nm_ip6_config_set_gateway (NMIP6Config *config, const struct in6_addr *); -const struct in6_addr *nm_ip6_config_get_gateway (const NMIP6Config *config); -gint64 nm_ip6_config_get_route_metric (const NMIP6Config *config); - -void nm_ip6_config_reset_addresses (NMIP6Config *config); -void nm_ip6_config_add_address (NMIP6Config *config, const NMPlatformIP6Address *address); -void nm_ip6_config_del_address (NMIP6Config *config, guint i); -guint nm_ip6_config_get_num_addresses (const NMIP6Config *config); -const NMPlatformIP6Address *nm_ip6_config_get_address (const NMIP6Config *config, guint i); -const NMPlatformIP6Address *nm_ip6_config_get_address_first_nontentative (const NMIP6Config *config, gboolean linklocal); -gboolean nm_ip6_config_address_exists (const NMIP6Config *config, const NMPlatformIP6Address *address); -gboolean nm_ip6_config_addresses_sort (NMIP6Config *config); +int nm_ip6_config_destination_is_direct (const NMIP6Config *self, const struct in6_addr *dest, guint8 plen); +void nm_ip6_config_dump (const NMIP6Config *self, const char *detail); + + +void nm_ip6_config_set_never_default (NMIP6Config *self, gboolean never_default); +gboolean nm_ip6_config_get_never_default (const NMIP6Config *self); +void nm_ip6_config_set_gateway (NMIP6Config *self, const struct in6_addr *); +const struct in6_addr *nm_ip6_config_get_gateway (const NMIP6Config *self); +gint64 nm_ip6_config_get_route_metric (const NMIP6Config *self); + +const NMDedupMultiHeadEntry *nm_ip6_config_lookup_addresses (const NMIP6Config *self); +void nm_ip6_config_reset_addresses (NMIP6Config *self); +void nm_ip6_config_add_address (NMIP6Config *self, const NMPlatformIP6Address *address); +void _nmtst_nm_ip6_config_del_address (NMIP6Config *self, guint i); +guint nm_ip6_config_get_num_addresses (const NMIP6Config *self); +const NMPlatformIP6Address *nm_ip6_config_get_first_address (const NMIP6Config *self); +const NMPlatformIP6Address *_nmtst_nm_ip6_config_get_address (const NMIP6Config *self, guint i); +const NMPlatformIP6Address *nm_ip6_config_get_address_first_nontentative (const NMIP6Config *self, gboolean linklocal); +gboolean nm_ip6_config_address_exists (const NMIP6Config *self, const NMPlatformIP6Address *address); +const NMPlatformIP6Address *nm_ip6_config_lookup_address (const NMIP6Config *self, + const struct in6_addr *addr); +gboolean _nmtst_nm_ip6_config_addresses_sort (NMIP6Config *self); gboolean nm_ip6_config_has_any_dad_pending (const NMIP6Config *self, const NMIP6Config *candidates); -void nm_ip6_config_reset_routes (NMIP6Config *config); -void nm_ip6_config_add_route (NMIP6Config *config, const NMPlatformIP6Route *route); -void _nmtst_ip6_config_del_route (NMIP6Config *config, guint i); -guint nm_ip6_config_get_num_routes (const NMIP6Config *config); -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); - -void nm_ip6_config_reset_nameservers (NMIP6Config *config); -void nm_ip6_config_add_nameserver (NMIP6Config *config, const struct in6_addr *nameserver); -void nm_ip6_config_del_nameserver (NMIP6Config *config, guint i); -guint nm_ip6_config_get_num_nameservers (const NMIP6Config *config); -const struct in6_addr *nm_ip6_config_get_nameserver (const NMIP6Config *config, guint i); - -void nm_ip6_config_reset_domains (NMIP6Config *config); -void nm_ip6_config_add_domain (NMIP6Config *config, const char *domain); -void nm_ip6_config_del_domain (NMIP6Config *config, guint i); -guint nm_ip6_config_get_num_domains (const NMIP6Config *config); -const char * nm_ip6_config_get_domain (const NMIP6Config *config, guint i); - -void nm_ip6_config_reset_searches (NMIP6Config *config); -void nm_ip6_config_add_search (NMIP6Config *config, const char *search); -void nm_ip6_config_del_search (NMIP6Config *config, guint i); -guint nm_ip6_config_get_num_searches (const NMIP6Config *config); -const char * nm_ip6_config_get_search (const NMIP6Config *config, guint i); - -void nm_ip6_config_reset_dns_options (NMIP6Config *config); -void nm_ip6_config_add_dns_option (NMIP6Config *config, const char *option); -void nm_ip6_config_del_dns_option (NMIP6Config *config, guint i); -guint nm_ip6_config_get_num_dns_options (const NMIP6Config *config); -const char * nm_ip6_config_get_dns_option (const NMIP6Config *config, guint i); - -void nm_ip6_config_set_dns_priority (NMIP6Config *config, gint priority); -gint nm_ip6_config_get_dns_priority (const NMIP6Config *config); - -void nm_ip6_config_set_mss (NMIP6Config *config, guint32 mss); -guint32 nm_ip6_config_get_mss (const NMIP6Config *config); - -void nm_ip6_config_hash (const NMIP6Config *config, GChecksum *sum, gboolean dns_only); +const NMDedupMultiHeadEntry *nm_ip6_config_lookup_routes (const NMIP6Config *self); +void nm_ip6_config_reset_routes (NMIP6Config *self); +void nm_ip6_config_add_route (NMIP6Config *self, const NMPlatformIP6Route *route); +void _nmtst_ip6_config_del_route (NMIP6Config *self, guint i); +guint nm_ip6_config_get_num_routes (const NMIP6Config *self); +const NMPlatformIP6Route *_nmtst_ip6_config_get_route (const NMIP6Config *self, guint i); + +const NMPlatformIP6Route *nm_ip6_config_get_direct_route_for_host (const NMIP6Config *self, const struct in6_addr *host); +const NMPlatformIP6Address *nm_ip6_config_get_subnet_for_host (const NMIP6Config *self, const struct in6_addr *host); + +void nm_ip6_config_reset_nameservers (NMIP6Config *self); +void nm_ip6_config_add_nameserver (NMIP6Config *self, const struct in6_addr *nameserver); +void nm_ip6_config_del_nameserver (NMIP6Config *self, guint i); +guint nm_ip6_config_get_num_nameservers (const NMIP6Config *self); +const struct in6_addr *nm_ip6_config_get_nameserver (const NMIP6Config *self, guint i); + +void nm_ip6_config_reset_domains (NMIP6Config *self); +void nm_ip6_config_add_domain (NMIP6Config *self, const char *domain); +void nm_ip6_config_del_domain (NMIP6Config *self, guint i); +guint nm_ip6_config_get_num_domains (const NMIP6Config *self); +const char * nm_ip6_config_get_domain (const NMIP6Config *self, guint i); + +void nm_ip6_config_reset_searches (NMIP6Config *self); +void nm_ip6_config_add_search (NMIP6Config *self, const char *search); +void nm_ip6_config_del_search (NMIP6Config *self, guint i); +guint nm_ip6_config_get_num_searches (const NMIP6Config *self); +const char * nm_ip6_config_get_search (const NMIP6Config *self, guint i); + +void nm_ip6_config_reset_dns_options (NMIP6Config *self); +void nm_ip6_config_add_dns_option (NMIP6Config *self, const char *option); +void nm_ip6_config_del_dns_option (NMIP6Config *self, guint i); +guint nm_ip6_config_get_num_dns_options (const NMIP6Config *self); +const char * nm_ip6_config_get_dns_option (const NMIP6Config *self, guint i); + +void nm_ip6_config_set_dns_priority (NMIP6Config *self, gint priority); +gint nm_ip6_config_get_dns_priority (const NMIP6Config *self); + +void nm_ip6_config_set_mss (NMIP6Config *self, guint32 mss); +guint32 nm_ip6_config_get_mss (const NMIP6Config *self); + +void nm_ip6_config_hash (const NMIP6Config *self, GChecksum *sum, gboolean dns_only); gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b); -void nm_ip6_config_set_privacy (NMIP6Config *config, NMSettingIP6ConfigPrivacy privacy); +void nm_ip6_config_set_privacy (NMIP6Config *self, NMSettingIP6ConfigPrivacy privacy); /*****************************************************************************/ /* Testing-only functions */ diff --git a/src/nm-pacrunner-manager.c b/src/nm-pacrunner-manager.c index d9095cce5b..2558ca0f30 100644 --- a/src/nm-pacrunner-manager.c +++ b/src/nm-pacrunner-manager.c @@ -170,6 +170,7 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4) { NMDedupMultiIter ipconf_iter; char *cidr; + const NMPlatformIP4Address *address; const NMPlatformIP4Route *routes; guint i; @@ -182,16 +183,15 @@ get_ip4_domains (GPtrArray *domains, NMIP4Config *ip4) g_ptr_array_add (domains, g_strdup (nm_ip4_config_get_domain (ip4, i))); /* Add addresses and routes in CIDR form */ - for (i = 0; i < nm_ip4_config_get_num_addresses (ip4); i++) { - const NMPlatformIP4Address *address = nm_ip4_config_get_address (ip4, i); + nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, ip4, &address) { cidr = g_strdup_printf ("%s/%u", nm_utils_inet4_ntop (address->address, NULL), address->plen); g_ptr_array_add (domains, cidr); } - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, ip4, &routes) { + nm_ip_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); @@ -204,6 +204,7 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6) { NMDedupMultiIter ipconf_iter; char *cidr; + const NMPlatformIP6Address *address; const NMPlatformIP6Route *routes; guint i; @@ -216,16 +217,14 @@ get_ip6_domains (GPtrArray *domains, NMIP6Config *ip6) g_ptr_array_add (domains, g_strdup (nm_ip6_config_get_domain (ip6, i))); /* Add addresses and routes in CIDR form */ - for (i = 0; i < nm_ip6_config_get_num_addresses (ip6); i++) { - const NMPlatformIP6Address *address = nm_ip6_config_get_address (ip6, i); - + nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, ip6, &address) { cidr = g_strdup_printf ("%s/%u", nm_utils_inet6_ntop (&address->address, NULL), address->plen); g_ptr_array_add (domains, cidr); } - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) { + nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, ip6, &routes) { cidr = g_strdup_printf ("%s/%u", nm_utils_inet6_ntop (&routes->network, NULL), routes->plen); diff --git a/src/nm-policy.c b/src/nm-policy.c index 2d17bf3af0..1a97b02731 100644 --- a/src/nm-policy.c +++ b/src/nm-policy.c @@ -605,6 +605,8 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const NMIP4Config *ip4_config; NMIP6Config *ip6_config; gboolean external_hostname = FALSE; + const NMPlatformIP4Address *addr4; + const NMPlatformIP6Address *addr6; g_return_if_fail (self != NULL); @@ -746,17 +748,13 @@ update_system_hostname (NMPolicy *self, NMDevice *best4, NMDevice *best6, const ip4_config = best4 ? nm_device_get_ip4_config (best4) : NULL; ip6_config = best6 ? nm_device_get_ip6_config (best6) : NULL; - if (ip4_config && nm_ip4_config_get_num_addresses (ip4_config) > 0) { - const NMPlatformIP4Address *addr4; - - addr4 = nm_ip4_config_get_address (ip4_config, 0); + if ( ip4_config + && (addr4 = nm_ip4_config_get_first_address (ip4_config))) { g_clear_object (&priv->lookup.addr); priv->lookup.addr = g_inet_address_new_from_bytes ((guint8 *) &addr4->address, G_SOCKET_FAMILY_IPV4); - } else if (ip6_config && nm_ip6_config_get_num_addresses (ip6_config) > 0) { - const NMPlatformIP6Address *addr6; - - addr6 = nm_ip6_config_get_address (ip6_config, 0); + } else if ( ip6_config + && (addr6 = nm_ip6_config_get_first_address (ip6_config))) { g_clear_object (&priv->lookup.addr); priv->lookup.addr = g_inet_address_new_from_bytes ((guint8 *) &addr6->address, G_SOCKET_FAMILY_IPV6); diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c index 70554c4117..a54deebe47 100644 --- a/src/nm-route-manager.c +++ b/src/nm-route-manager.c @@ -33,7 +33,7 @@ * up, we delete it. */ #define IP4_DEVICE_ROUTES_WAIT_TIME_NS (NM_UTILS_NS_PER_SECOND / 2) -#define IP4_DEVICE_ROUTES_GC_INTERVAL_SEC (IP4_DEVICE_ROUTES_WAIT_TIME_NS * 2) +#define IP4_DEVICE_ROUTES_GC_INTERVAL_MSEC ((IP4_DEVICE_ROUTES_WAIT_TIME_NS / 1000000) * 3) /*****************************************************************************/ @@ -58,7 +58,8 @@ typedef struct { NMRouteManager *self; gint64 scheduled_at_ns; guint idle_id; - NMPObject *obj; + const NMPObject *obj; + const NMPObject *obj_cached; } IP4DeviceRoutePurgeEntry; /*****************************************************************************/ @@ -490,8 +491,10 @@ _get_next_plat_route (const RouteIndex *index, gboolean start_at_zero, guint *cu ++*cur_idx; /* get next route from the platform index. */ - if (*cur_idx < index->len) + if (*cur_idx < index->len) { + nm_assert (NMP_OBJECT_UP_CAST (index->entries[*cur_idx])); return index->entries[*cur_idx]; + } *cur_idx = index->len; return NULL; } @@ -649,7 +652,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const * in platform. Delete it. */ _LOGt (vtable->vt->addr_family, "%3d: platform rt-rm #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route, NULL, 0)); - vtable->vt->route_delete (priv->platform, ifindex, cur_plat_route); + nm_assert (ifindex == cur_plat_route->rx.ifindex); + nm_platform_ip_route_delete (priv->platform, NMP_OBJECT_UP_CAST (cur_plat_route)); } } } @@ -796,7 +800,7 @@ next: while (cur_plat_route) { int route_dest_cmp_result = 0; - g_assert (cur_plat_route->rx.ifindex == ifindex); + nm_assert (cur_plat_route->rx.ifindex == ifindex); _LOGt (vtable->vt->addr_family, "%3d: platform rt #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route, NULL, 0)); @@ -816,8 +820,10 @@ next: /* if @cur_ipx_route is not equal to @plat_route, the route must be deleted. */ if ( !cur_ipx_route || route_dest_cmp_result != 0 - || *p_effective_metric != cur_plat_route->rx.metric) - vtable->vt->route_delete (priv->platform, ifindex, cur_plat_route); + || *p_effective_metric != cur_plat_route->rx.metric) { + nm_assert (ifindex == cur_plat_route->rx.ifindex); + nm_platform_ip_route_delete (priv->platform, NMP_OBJECT_UP_CAST (cur_plat_route)); + } cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes); } @@ -1074,6 +1080,7 @@ _ip4_device_routes_purge_entry_create (NMRouteManager *self, const NMPlatformIP4 entry->scheduled_at_ns = now_ns; entry->idle_id = 0; entry->obj = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, (NMPlatformObject *) route); + entry->obj_cached = NULL; return entry; } @@ -1081,6 +1088,7 @@ static void _ip4_device_routes_purge_entry_free (IP4DeviceRoutePurgeEntry *entry) { nmp_object_unref (entry->obj); + nmp_object_unref (entry->obj_cached); nm_clear_g_source (&entry->idle_id); g_slice_free (IP4DeviceRoutePurgeEntry, entry); } @@ -1100,13 +1108,9 @@ _ip4_device_routes_idle_cb (IP4DeviceRoutePurgeEntry *entry) return G_SOURCE_REMOVE; } - _LOGt (vtable_v4.vt->addr_family, "device-route: delete %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + _LOGt (vtable_v4.vt->addr_family, "device-route: delete %s", nmp_object_to_string (entry->obj_cached, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - nm_platform_ip4_route_delete (priv->platform, - entry->obj->ip4_route.ifindex, - entry->obj->ip4_route.network, - entry->obj->ip4_route.plen, - entry->obj->ip4_route.metric); + nm_platform_ip_route_delete (priv->platform, entry->obj_cached); g_hash_table_remove (priv->ip4_device_routes.entries, entry->obj); _ip4_device_routes_cancel (self); @@ -1123,12 +1127,9 @@ _ip4_device_routes_ip4_route_changed (NMPlatform *platform, { const NMPlatformSignalChangeType change_type = change_type_i; NMRouteManagerPrivate *priv; - NMPObject obj_needle; + const NMPObject *obj; IP4DeviceRoutePurgeEntry *entry; - if (change_type == NM_PLATFORM_SIGNAL_REMOVED) - return; - if ( route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL || route->metric != 0) { /* we don't have an automatically created device route at hand. Bail out early. */ @@ -1137,8 +1138,9 @@ _ip4_device_routes_ip4_route_changed (NMPlatform *platform, priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - entry = g_hash_table_lookup (priv->ip4_device_routes.entries, - nmp_object_stackinit (&obj_needle, NMP_OBJECT_TYPE_IP4_ROUTE, (NMPlatformObject *) route)); + obj = NMP_OBJECT_UP_CAST (route); + + entry = g_hash_table_lookup (priv->ip4_device_routes.entries, obj); if (!entry) return; @@ -1149,6 +1151,15 @@ _ip4_device_routes_ip4_route_changed (NMPlatform *platform, return; } + entry->obj_cached = nmp_object_unref (entry->obj_cached); + + if (change_type == NM_PLATFORM_SIGNAL_REMOVED) { + if (nm_clear_g_source (&entry->idle_id)) + _LOGt (vtable_v4.vt->addr_family, "device-route: unschedule %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); + return; + } + + entry->obj_cached = nmp_object_ref (obj); if (entry->idle_id == 0) { _LOGt (vtable_v4.vt->addr_family, "device-route: schedule %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); entry->idle_id = g_idle_add ((GSourceFunc) _ip4_device_routes_idle_cb, entry); @@ -1227,7 +1238,7 @@ nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *sel } if (priv->ip4_device_routes.gc_id == 0) { g_signal_connect (priv->platform, NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED, G_CALLBACK (_ip4_device_routes_ip4_route_changed), self); - priv->ip4_device_routes.gc_id = g_timeout_add (IP4_DEVICE_ROUTES_GC_INTERVAL_SEC, (GSourceFunc) _ip4_device_routes_gc, self); + priv->ip4_device_routes.gc_id = g_timeout_add (IP4_DEVICE_ROUTES_GC_INTERVAL_MSEC, (GSourceFunc) _ip4_device_routes_gc, self); } } diff --git a/src/nm-types.h b/src/nm-types.h index 36a624de8b..2cc5769467 100644 --- a/src/nm-types.h +++ b/src/nm-types.h @@ -110,6 +110,7 @@ NM_IS_IP_CONFIG_SOURCE_RTPROT (NMIPConfigSource source) /* platform */ typedef struct _NMPlatform NMPlatform; +typedef struct _NMPlatformObject NMPlatformObject; typedef struct _NMPlatformIP4Address NMPlatformIP4Address; typedef struct _NMPlatformIP4Route NMPlatformIP4Route; typedef struct _NMPlatformIP6Address NMPlatformIP6Address; diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c index 718ee974ae..f817bfb571 100644 --- a/src/platform/nm-fake-platform.c +++ b/src/platform/nm-fake-platform.c @@ -106,9 +106,7 @@ static gboolean ipx_address_delete (NMPlatform *platform, static gboolean ipx_route_delete (NMPlatform *platform, int addr_family, int ifindex, - gconstpointer network, - const guint8 *plen, - const guint32 *metric); + const NMPObject *obj); static gboolean ip6_address_add (NMPlatform *platform, int ifindex, @@ -401,8 +399,8 @@ link_delete (NMPlatform *platform, int ifindex) /* 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); + ipx_route_delete (platform, AF_INET, ifindex, NULL); + ipx_route_delete (platform, AF_INET6, ifindex, NULL); nm_platform_cache_update_emit_signal (platform, cache_op, @@ -1115,42 +1113,54 @@ static gboolean ipx_route_delete (NMPlatform *platform, int addr_family, int ifindex, - gconstpointer network, - const guint8 *plen, - const guint32 *metric) + const NMPObject *obj) { gs_unref_ptrarray GPtrArray *objs = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref); NMDedupMultiIter iter; const NMPObject *o = NULL; guint i; - - g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + NMPObjectType obj_type; + + if (addr_family == AF_UNSPEC) { + g_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)); + g_assert (ifindex == -1); + ifindex = obj->object.ifindex; + obj_type = NMP_OBJECT_GET_TYPE (obj); + } else { + g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6)); + g_assert (!obj); + g_assert (ifindex > 0); + obj_type = addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ROUTE + : NMP_OBJECT_TYPE_IP6_ROUTE; + } 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), + obj_type, + ifindex), &o) { const NMPObject *obj_old = NULL; - if (addr_family == AF_INET) { - const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (o); + if (obj) { + if (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE) { + const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (o); + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (obj); - 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->network != r->network + || route->plen != r->plen + || route->metric != r->metric) + continue; + } else { + const NMPlatformIP6Route *route = NMP_OBJECT_CAST_IP6_ROUTE (o); + const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (obj); - if ( route->ifindex != ifindex - || (network && !IN6_ARE_ADDR_EQUAL (&route->network, network)) - || (plen && route->plen != *plen) - || (metric && route->metric != *metric)) - continue; + if ( !IN6_ARE_ADDR_EQUAL (&route->network, &r->network) + || route->plen != r->plen + || route->metric != r->metric) + continue; + } } if (nmp_cache_remove (nm_platform_get_cache (platform), @@ -1172,16 +1182,13 @@ ipx_route_delete (NMPlatform *platform, } static gboolean -ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +ip_route_delete (NMPlatform *platform, const NMPObject *obj) { - return ipx_route_delete (platform, AF_INET, ifindex, &network, &plen, &metric); -} + g_assert (NM_IS_FAKE_PLATFORM (platform)); + g_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)); -static gboolean -ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) -{ - metric = nm_utils_ip6_route_metric_normalize (metric); - return ipx_route_delete (platform, AF_INET6, ifindex, &network, &plen, &metric); + return ipx_route_delete (platform, AF_UNSPEC, -1, obj); } static gboolean @@ -1391,6 +1398,5 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass) platform_class->ip4_route_add = ip4_route_add; platform_class->ip6_route_add = ip6_route_add; - platform_class->ip4_route_delete = ip4_route_delete; - platform_class->ip6_route_delete = ip6_route_delete; + platform_class->ip_route_delete = ip_route_delete; } diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 6a4210de90..e25091aa9a 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2418,19 +2418,14 @@ nla_put_failure: static struct nl_msg * _nl_msg_new_route (int nlmsg_type, int nlmsg_flags, - int family, - int ifindex, + const NMPObject *obj, NMIPConfigSource source, unsigned char scope, - gconstpointer network, - guint8 plen, gconstpointer gateway, - guint32 metric, guint32 mss, gconstpointer pref_src, gconstpointer src, guint8 src_plen, - guint8 tos, guint32 window, guint32 cwnd, guint32 initcwnd, @@ -2439,23 +2434,24 @@ _nl_msg_new_route (int nlmsg_type, guint32 lock) { struct nl_msg *msg; + const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj); + gboolean is_v4 = klass->addr_family == AF_INET; struct rtmsg rtmsg = { - .rtm_family = family, - .rtm_tos = tos, + .rtm_family = klass->addr_family, + .rtm_tos = obj->ip_route.tos, .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */ .rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (source), .rtm_scope = scope, .rtm_type = RTN_UNICAST, .rtm_flags = 0, - .rtm_dst_len = plen, + .rtm_dst_len = obj->ip_route.plen, .rtm_src_len = src ? src_plen : 0, }; gsize addr_len; - nm_assert (NM_IN_SET (family, AF_INET, AF_INET6)); + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE)); - nm_assert (network); msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags); if (!msg) @@ -2464,14 +2460,19 @@ _nl_msg_new_route (int nlmsg_type, if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0) goto nla_put_failure; - addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr); + addr_len = is_v4 + ? sizeof (in_addr_t) + : sizeof (struct in6_addr); - NLA_PUT (msg, RTA_DST, addr_len, network); + NLA_PUT (msg, RTA_DST, addr_len, + is_v4 + ? (gconstpointer) &obj->ip4_route.network + : (gconstpointer) &obj->ip6_route.network); if (src) NLA_PUT (msg, RTA_SRC, addr_len, src); - NLA_PUT_U32 (msg, RTA_PRIORITY, metric); + NLA_PUT_U32 (msg, RTA_PRIORITY, obj->ip_route.metric); if (pref_src) NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src); @@ -2505,7 +2506,7 @@ _nl_msg_new_route (int nlmsg_type, if ( gateway && memcmp (gateway, &nm_ip_addr_zero, addr_len) != 0) NLA_PUT (msg, RTA_GATEWAY, addr_len, gateway); - NLA_PUT_U32 (msg, RTA_OIF, ifindex); + NLA_PUT_U32 (msg, RTA_OIF, obj->ip_route.ifindex); return msg; @@ -4032,7 +4033,7 @@ out: /* 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 (cache, obj_id); + return !nmp_cache_lookup_obj (cache, obj_id); } static WaitForNlResponseResult @@ -5688,86 +5689,78 @@ ip_route_get_lock_flag (NMPlatformIPRoute *route) static gboolean ip4_route_add (NMPlatform *platform, const NMPlatformIP4Route *route) { - NMPObject obj_id; + NMPObject obj; + NMPlatformIP4Route *r; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - in_addr_t network; - network = nm_utils_ip4_address_clear_host_address (route->network, route->plen); + nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP4_ROUTE, (const NMPlatformObject *) route); + r = NMP_OBJECT_CAST_IP4_ROUTE (&obj); + r->network = nm_utils_ip4_address_clear_host_address (r->network, r->plen); - /* FIXME: take the scope from route into account */ nlmsg = _nl_msg_new_route (RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE, - AF_INET, - route->ifindex, + &obj, route->rt_source, route->gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK, - &network, - route->plen, &route->gateway, - route->metric, route->mss, route->pref_src ? &route->pref_src : NULL, NULL, 0, - route->tos, route->window, route->cwnd, route->initcwnd, route->initrwnd, route->mtu, ip_route_get_lock_flag ((NMPlatformIPRoute *) route)); - - nmp_object_stackinit_id_ip4_route (&obj_id, route->ifindex, network, route->plen, route->metric); - return do_add_addrroute (platform, &obj_id, nlmsg); + return do_add_addrroute (platform, &obj, nlmsg); } static gboolean ip6_route_add (NMPlatform *platform, const NMPlatformIP6Route *route) { - NMPObject obj_id; + NMPObject obj; + NMPlatformIP6Route *r; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - struct in6_addr network; - nm_utils_ip6_address_clear_host_address (&network, &route->network, route->plen); + nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ROUTE, (const NMPlatformObject *) route); + r = NMP_OBJECT_CAST_IP6_ROUTE (&obj); + nm_utils_ip6_address_clear_host_address (&r->network, &r->network, r->plen); - /* FIXME: take the scope from route into account */ nlmsg = _nl_msg_new_route (RTM_NEWROUTE, NLM_F_CREATE | NLM_F_REPLACE, - AF_INET6, - route->ifindex, + &obj, route->rt_source, IN6_IS_ADDR_UNSPECIFIED (&route->gateway) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE, - &network, - route->plen, &route->gateway, - route->metric, route->mss, !IN6_IS_ADDR_UNSPECIFIED (&route->pref_src) ? &route->pref_src : NULL, !IN6_IS_ADDR_UNSPECIFIED (&route->src) ? &route->src : NULL, route->src_plen, - route->tos, route->window, route->cwnd, route->initcwnd, route->initrwnd, route->mtu, ip_route_get_lock_flag ((NMPlatformIPRoute *) route)); - - nmp_object_stackinit_id_ip6_route (&obj_id, route->ifindex, &network, route->plen, route->metric); - return do_add_addrroute (platform, &obj_id, nlmsg); + return do_add_addrroute (platform, &obj, nlmsg); } static gboolean -ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +ip_route_delete (NMPlatform *platform, + const NMPObject *obj) { + nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL; nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - NMPObject obj_id; - network = nm_utils_ip4_address_clear_host_address (network, plen); + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)); - nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric); + if (!NMP_OBJECT_IS_STACKINIT (obj)) + obj_keep_alive = nmp_object_ref (obj); - if (metric == 0) { + if ( NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_IP4_ROUTE + && obj->ip_route.metric == 0) { NMPCache *cache = nm_platform_get_cache (platform); /* Deleting an IPv4 route with metric 0 does not only delete an exectly matching route. @@ -5776,9 +5769,12 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p * * Instead, make sure that we have the most recent state and process all * delayed actions (including re-reading data from netlink). */ + + /* FIXME: later, we only want to pass in here @obj instances that originate + * from the cache, and where we know that the route with metric 0 exists. */ delayed_action_handle_all (platform, TRUE); - if (!nmp_cache_lookup_obj (cache, &obj_id)) { + if (!nmp_cache_lookup_obj (cache, obj)) { /* 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. @@ -5786,65 +5782,20 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 p * Be extra careful and reload the routes. We must be sure that such a * route doesn't exists, because when we add an IPv4 address, we immediately * afterwards try to delete the kernel-added device route with metric 0. - * It might be, that we didn't yet get the notification about that route. - * - * FIXME: once our ip4_address_add() is sure that upon return we have - * the latest state from in the platform cache, we might save this - * additional expensive cache-resync. */ + * It might be, that we didn't yet get the notification about that route. */ do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE); - if (!nmp_cache_lookup_obj (cache, &obj_id)) + if (!nmp_cache_lookup_obj (cache, obj)) return TRUE; } } nlmsg = _nl_msg_new_route (RTM_DELROUTE, 0, - AF_INET, - ifindex, - NM_IP_CONFIG_SOURCE_UNKNOWN, - RT_SCOPE_NOWHERE, - &network, - plen, - NULL, - metric, - 0, - NULL, - NULL, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0); - if (!nlmsg) - return FALSE; - - return do_delete_object (platform, &obj_id, nlmsg); -} - -static gboolean -ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) -{ - nm_auto_nlmsg struct nl_msg *nlmsg = NULL; - NMPObject obj_id; - - metric = nm_utils_ip6_route_metric_normalize (metric); - - nm_utils_ip6_address_clear_host_address (&network, &network, plen); - - nlmsg = _nl_msg_new_route (RTM_DELROUTE, - 0, - AF_INET6, - ifindex, + obj, NM_IP_CONFIG_SOURCE_UNKNOWN, RT_SCOPE_NOWHERE, - &network, - plen, NULL, - metric, 0, NULL, NULL, @@ -5854,14 +5805,10 @@ ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, gu 0, 0, 0, - 0, 0); if (!nlmsg) return FALSE; - - nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric); - - return do_delete_object (platform, &obj_id, nlmsg); + return do_delete_object (platform, obj, nlmsg); } /*****************************************************************************/ @@ -6593,8 +6540,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass) platform_class->ip4_route_add = ip4_route_add; platform_class->ip6_route_add = ip6_route_add; - platform_class->ip4_route_delete = ip4_route_delete; - platform_class->ip6_route_delete = ip6_route_delete; + platform_class->ip_route_delete = ip_route_delete; platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags; platform_class->check_support_user_ipv6ll = check_support_user_ipv6ll; diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 176f377bdb..c8c7663e0e 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2831,40 +2831,6 @@ 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) -{ - _CHECK_SELF (self, klass, NULL); - - g_return_val_if_fail (ifindex > 0, NULL); - - return ipx_address_get_all (self, ifindex, NMP_OBJECT_TYPE_IP4_ADDRESS); -} - -GArray * -nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex) -{ - _CHECK_SELF (self, klass, NULL); - - g_return_val_if_fail (ifindex > 0, NULL); - - return ipx_address_get_all (self, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS); -} - gboolean nm_platform_ip4_address_add (NMPlatform *self, int ifindex, @@ -3004,37 +2970,14 @@ nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr addr return NMP_OBJECT_CAST_IP6_ADDRESS (obj); } -static const NMPlatformIP4Address * -array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address, gint32 now) -{ - guint len = addresses ? addresses->len : 0; - guint i; - - for (i = 0; i < len; i++) { - const NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i); - - if ( candidate->address == address->address - && candidate->plen == address->plen - && ((candidate->peer_address ^ address->peer_address) & nm_utils_ip4_prefix_to_netmask (address->plen)) == 0) { - guint32 lifetime, preferred; - - if (nm_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred, - now, &lifetime, &preferred)) - return candidate; - } - } - - return NULL; -} - static gboolean -array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address, gint32 now) +array_contains_ip6_address (const GPtrArray *addresses, const NMPlatformIP6Address *address, gint32 now) { guint len = addresses ? addresses->len : 0; guint i; for (i = 0; i < len; i++) { - NMPlatformIP6Address *candidate = &g_array_index (addresses, NMPlatformIP6Address, i); + NMPlatformIP6Address *candidate = NMP_OBJECT_CAST_IP6_ADDRESS (addresses->pdata[i]); if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) { guint32 lifetime, preferred; @@ -3049,69 +2992,100 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address } static gboolean -_ptr_inside_ip4_addr_array (const GArray *array, gconstpointer needle) +ip4_addr_subnets_is_plain_address (const GPtrArray *addresses, gconstpointer needle) { - return needle >= (gconstpointer) &g_array_index (array, const NMPlatformIP4Address, 0) - && needle < (gconstpointer) &g_array_index (array, const NMPlatformIP4Address, array->len); + return needle >= (gconstpointer) &addresses->pdata[0] + && needle < (gconstpointer) &addresses->pdata[addresses->len]; +} + +static const NMPObject ** +ip4_addr_subnets_addr_list_get (const GPtrArray *addr_list, guint idx) +{ + nm_assert (addr_list); + nm_assert (addr_list->len > 1); + nm_assert (idx < addr_list->len); + nm_assert (addr_list->pdata[idx]); + nm_assert ( !(*((gpointer *) addr_list->pdata[idx])) + || NMP_OBJECT_CAST_IP4_ADDRESS (*((gpointer *) addr_list->pdata[idx]))); + nm_assert (idx == 0 || ip4_addr_subnets_addr_list_get (addr_list, idx - 1)); + return addr_list->pdata[idx]; } static void -ip4_addr_subnets_destroy_index (GHashTable *ht, const GArray *addresses) +ip4_addr_subnets_destroy_index (GHashTable *subnets, const GPtrArray *addresses) { GHashTableIter iter; gpointer p; - g_hash_table_iter_init (&iter, ht); + if (!subnets) + return; + g_hash_table_iter_init (&iter, subnets); while (g_hash_table_iter_next (&iter, NULL, &p)) { - if (!_ptr_inside_ip4_addr_array (addresses, p)) { + if (!ip4_addr_subnets_is_plain_address (addresses, p)) g_ptr_array_free ((GPtrArray *) p, TRUE); - } } - g_hash_table_unref (ht); + g_hash_table_unref (subnets); } static GHashTable * -ip4_addr_subnets_build_index (const GArray *addresses, gboolean consider_flags) +ip4_addr_subnets_build_index (const GPtrArray *addresses, + gboolean consider_flags, + gboolean full_index) { - const NMPlatformIP4Address *address; - gpointer p; GHashTable *subnets; - GPtrArray *ptr; - guint32 net; guint i; - gint position; - if (!addresses) - return NULL; + nm_assert (addresses && addresses->len); - subnets = g_hash_table_new_full (g_direct_hash, - g_direct_equal, - NULL, - NULL); + subnets = g_hash_table_new (NULL, NULL); /* Build a hash table of all addresses per subnet */ for (i = 0; i < addresses->len; i++) { - address = &g_array_index (addresses, const NMPlatformIP4Address, i); + const NMPlatformIP4Address *address; + gpointer p_address; + GPtrArray *addr_list; + guint32 net; + int position; + gpointer p; + + if (!addresses->pdata[i]) + continue; + + p_address = &addresses->pdata[i]; + address = NMP_OBJECT_CAST_IP4_ADDRESS (addresses->pdata[i]); + net = address->address & nm_utils_ip4_prefix_to_netmask (address->plen); if (!g_hash_table_lookup_extended (subnets, GUINT_TO_POINTER (net), NULL, &p)) { - g_hash_table_insert (subnets, GUINT_TO_POINTER (net), (gpointer) address); + g_hash_table_insert (subnets, GUINT_TO_POINTER (net), p_address); continue; } - if (_ptr_inside_ip4_addr_array (addresses, p)) { - ptr = g_ptr_array_new (); - g_hash_table_insert (subnets, GUINT_TO_POINTER (net), ptr); - g_ptr_array_add (ptr, p); - } else - ptr = p; - - if (!consider_flags || NM_FLAGS_HAS (address->n_ifa_flags, IFA_F_SECONDARY)) - position = -1; /* append */ - else - position = 0; /* prepend */ - - g_ptr_array_insert (ptr, position, (gpointer) address); + nm_assert (p); + + if (full_index) { + if (ip4_addr_subnets_is_plain_address (addresses, p)) { + addr_list = g_ptr_array_new (); + g_hash_table_insert (subnets, GUINT_TO_POINTER (net), addr_list); + g_ptr_array_add (addr_list, p); + } else + addr_list = p; + + if ( !consider_flags + || NM_FLAGS_HAS (address->n_ifa_flags, IFA_F_SECONDARY)) + position = -1; /* append */ + else + position = 0; /* prepend */ + g_ptr_array_insert (addr_list, position, p_address); + } else { + /* we only care about the primay. No need to track the secondaries + * as a GPtrArray. */ + nm_assert (ip4_addr_subnets_is_plain_address (addresses, p)); + if ( consider_flags + && !NM_FLAGS_HAS (address->n_ifa_flags, IFA_F_SECONDARY)) { + g_hash_table_insert (subnets, GUINT_TO_POINTER (net), p_address); + } + } } return subnets; @@ -3130,22 +3104,32 @@ ip4_addr_subnets_build_index (const GArray *addresses, gboolean consider_flags) * Returns: %TRUE if the address is secondary, %FALSE otherwise */ static gboolean -ip4_addr_subnets_is_secondary (const NMPlatformIP4Address *address, GHashTable *subnets, const GArray *addresses, GPtrArray **out_addr_list) -{ - GPtrArray *addr_list; - gpointer p; +ip4_addr_subnets_is_secondary (const NMPObject *address, + GHashTable *subnets, + const GPtrArray *addresses, + const GPtrArray **out_addr_list) +{ + const NMPlatformIP4Address *a; + const GPtrArray *addr_list; + gconstpointer p; guint32 net; + const NMPObject **o; - net = address->address & nm_utils_ip4_prefix_to_netmask (address->plen); + a = NMP_OBJECT_CAST_IP4_ADDRESS (address); + + net = a->address & nm_utils_ip4_prefix_to_netmask (a->plen); p = g_hash_table_lookup (subnets, GUINT_TO_POINTER (net)); nm_assert (p); - if (!_ptr_inside_ip4_addr_array (addresses, p)) { + if (!ip4_addr_subnets_is_plain_address (addresses, p)) { addr_list = p; + nm_assert (addr_list->len > 1); NM_SET_OUT (out_addr_list, addr_list); - if (addr_list->pdata[0] != address) + o = ip4_addr_subnets_addr_list_get (addr_list, 0); + nm_assert (o && *o); + if (*o != address) return TRUE; } else { - nm_assert ((gconstpointer) address == p); + nm_assert (address == *((gconstpointer *) p)); NM_SET_OUT (out_addr_list, NULL); } return FALSE; @@ -3155,11 +3139,14 @@ ip4_addr_subnets_is_secondary (const NMPlatformIP4Address *address, GHashTable * * nm_platform_ip4_address_sync: * @self: platform instance * @ifindex: Interface index - * @known_addresses: List of addresses - * @out_added_addresses: (out): (allow-none): if not %NULL, return a #GPtrArray - * with the addresses added. The pointers point into @known_addresses. - * It possibly does not contain all addresses from @known_address because - * some addresses might be expired. + * @known_addresses: List of addresses. The list will be modified and only + * addresses that were successfully added will be kept in the list. + * That means, expired addresses and addresses that could not be added + * will be dropped. + * Hence, the input argument @known_addresses is also an output argument + * telling which addresses were succesfully added. + * Addresses are removed by unrefing the instance via nmp_object_unref() + * and leaving a NULL tombstone. * * A convenience function to synchronize addresses for a specific interface * with the least possible disturbance. It simply removes addresses that are @@ -3168,102 +3155,162 @@ ip4_addr_subnets_is_secondary (const NMPlatformIP4Address *address, GHashTable * * Returns: %TRUE on success. */ gboolean -nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, GPtrArray **out_added_addresses) +nm_platform_ip4_address_sync (NMPlatform *self, + int ifindex, + GPtrArray *known_addresses) { - GArray *addresses; - NMPlatformIP4Address *address; + gs_unref_ptrarray GPtrArray *plat_addresses = NULL; const NMPlatformIP4Address *known_address; gint32 now = nm_utils_get_monotonic_timestamp_s (); - GHashTable *plat_subnets; - GHashTable *known_subnets; - GPtrArray *ptr; - int i, j; + GHashTable *plat_subnets = NULL; + GHashTable *known_subnets = NULL; + gs_unref_hashtable GHashTable *known_addresses_idx = NULL; + guint i, j, len; + NMPLookup lookup; + guint32 lifetime, preferred; _CHECK_SELF (self, klass, FALSE); - addresses = nm_platform_ip4_address_get_all (self, ifindex); - plat_subnets = ip4_addr_subnets_build_index (addresses, TRUE); - known_subnets = ip4_addr_subnets_build_index (known_addresses, FALSE); + if (known_addresses) { + /* remove all addresses that are already expired. */ + for (i = 0; i < known_addresses->len; i++) { + const NMPObject *o; + + o = known_addresses->pdata[i]; + nm_assert (o); + + known_address = NMP_OBJECT_CAST_IP4_ADDRESS (known_addresses->pdata[i]); + + if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, + now, &lifetime, &preferred)) + goto delete_and_next; + + if (G_UNLIKELY (!known_addresses_idx)) { + known_addresses_idx = g_hash_table_new ((GHashFunc) nmp_object_hash, + (GEqualFunc) nmp_object_equal); + } + if (!nm_g_hash_table_insert (known_addresses_idx, (gpointer) o, (gpointer) o)) { + /* duplicate? Keep only the first instance. */ + goto delete_and_next; + } + + continue; +delete_and_next: + nmp_object_unref (o); + known_addresses->pdata[i] = NULL; + } + + if ( !known_addresses_idx + || g_hash_table_size (known_addresses_idx) == 0) + known_addresses = NULL; + } + + plat_addresses = nm_platform_lookup_clone (self, + nmp_lookup_init_addrroute (&lookup, + NMP_OBJECT_TYPE_IP4_ADDRESS, + ifindex), + NULL, NULL); + if (plat_addresses) + plat_subnets = ip4_addr_subnets_build_index (plat_addresses, TRUE, TRUE); /* Delete unknown addresses */ - for (i = 0; i < addresses->len; i++) { - address = &g_array_index (addresses, NMPlatformIP4Address, i); + len = plat_addresses ? plat_addresses->len : 0; + for (i = 0; i < len; i++) { + const NMPObject *plat_obj; + const NMPlatformIP4Address *plat_address; + const GPtrArray *addr_list; - if (!address->ifindex) { + plat_obj = plat_addresses->pdata[i]; + if (!plat_obj) { /* Already deleted */ continue; } - known_address = array_contains_ip4_address (known_addresses, address, now); - if (known_address) { - gboolean secondary; + plat_address = NMP_OBJECT_CAST_IP4_ADDRESS (plat_obj); + + if (known_addresses) { + const NMPObject *o; + + o = g_hash_table_lookup (known_addresses_idx, plat_obj); + if (o) { + gboolean secondary; - secondary = ip4_addr_subnets_is_secondary (known_address, known_subnets, known_addresses, NULL); - /* Ignore the matching address if it has a different primary/slave - * role. */ - if (secondary != NM_FLAGS_HAS (address->n_ifa_flags, IFA_F_SECONDARY)) - known_address = NULL; + if (!known_subnets) + known_subnets = ip4_addr_subnets_build_index (known_addresses, FALSE, FALSE); + + secondary = ip4_addr_subnets_is_secondary (o, known_subnets, known_addresses, NULL); + if (secondary == NM_FLAGS_HAS (plat_address->n_ifa_flags, IFA_F_SECONDARY)) { + /* if we have an existing known-address, with matching secondary role, + * do not delete the platform-address. */ + continue; + } + } } - if (!known_address) { - nm_platform_ip4_address_delete (self, ifindex, - address->address, - address->plen, - address->peer_address); - if ( !ip4_addr_subnets_is_secondary (address, plat_subnets, addresses, &ptr) - && ptr) { - /* If we just deleted a primary addresses and there were - * secondary ones the kernel can do two things, depending on - * version and sysctl setting: delete also secondary addresses - * or promote a secondary to primary. Ensure that secondary - * addresses are deleted, so that we can start with a clean - * slate and add addresses in the right order. */ - for (j = 1; j < ptr->len; j++) { - address = ptr->pdata[j]; + nm_platform_ip4_address_delete (self, ifindex, + plat_address->address, + plat_address->plen, + plat_address->peer_address); + + if ( !ip4_addr_subnets_is_secondary (plat_obj, plat_subnets, plat_addresses, &addr_list) + && addr_list) { + /* If we just deleted a primary addresses and there were + * secondary ones the kernel can do two things, depending on + * version and sysctl setting: delete also secondary addresses + * or promote a secondary to primary. Ensure that secondary + * addresses are deleted, so that we can start with a clean + * slate and add addresses in the right order. */ + for (j = 1; j < addr_list->len; j++) { + const NMPObject **o; + + o = ip4_addr_subnets_addr_list_get (addr_list, j); + nm_assert (o); + + if (*o) { + const NMPlatformIP4Address *a; + + a = NMP_OBJECT_CAST_IP4_ADDRESS (*o); nm_platform_ip4_address_delete (self, ifindex, - address->address, - address->plen, - address->peer_address); - address->ifindex = 0; + a->address, + a->plen, + a->peer_address); + nmp_object_unref (*o); + *o = NULL; } } } } - ip4_addr_subnets_destroy_index (plat_subnets, addresses); - g_array_free (addresses, TRUE); - - if (out_added_addresses) - *out_added_addresses = NULL; + ip4_addr_subnets_destroy_index (plat_subnets, plat_addresses); + ip4_addr_subnets_destroy_index (known_subnets, known_addresses); if (!known_addresses) return TRUE; /* Add missing addresses */ for (i = 0; i < known_addresses->len; i++) { - guint32 lifetime, preferred; + const NMPObject *o; + + o = known_addresses->pdata[i]; + if (!o) + continue; - known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i); + known_address = NMP_OBJECT_CAST_IP4_ADDRESS (o); if (!nm_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred, now, &lifetime, &preferred)) - continue; + goto delete_and_next2; if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->plen, known_address->peer_address, lifetime, preferred, - 0, known_address->label)) { - ip4_addr_subnets_destroy_index (known_subnets, known_addresses); - return FALSE; - } + 0, known_address->label)) + goto delete_and_next2; - if (out_added_addresses) { - if (!*out_added_addresses) - *out_added_addresses = g_ptr_array_new (); - g_ptr_array_add (*out_added_addresses, (gpointer) known_address); - } + continue; +delete_and_next2: + nmp_object_unref (o); + known_addresses->pdata[i] = NULL; } - ip4_addr_subnets_destroy_index (known_subnets, known_addresses); - return TRUE; } @@ -3271,7 +3318,8 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known * nm_platform_ip6_address_sync: * @self: platform instance * @ifindex: Interface index - * @known_addresses: List of addresses + * @known_addresses: List of IPv6 addresses, as NMPObject. The list + * is not modified. * @keep_link_local: Don't remove link-local address * * A convenience function to synchronize addresses for a specific interface @@ -3281,33 +3329,42 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known * Returns: %TRUE on success. */ gboolean -nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, gboolean keep_link_local) +nm_platform_ip6_address_sync (NMPlatform *self, + int ifindex, + const GPtrArray *known_addresses, + gboolean keep_link_local) { - GArray *addresses; + gs_unref_ptrarray GPtrArray *plat_addresses = NULL; NMPlatformIP6Address *address; gint32 now = nm_utils_get_monotonic_timestamp_s (); - int i; + guint i; + NMPLookup lookup; /* Delete unknown addresses */ - addresses = nm_platform_ip6_address_get_all (self, ifindex); - for (i = 0; i < addresses->len; i++) { - address = &g_array_index (addresses, NMPlatformIP6Address, i); - - /* Leave link local address management to the kernel */ - if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address)) - continue; + plat_addresses = nm_platform_lookup_clone (self, + nmp_lookup_init_addrroute (&lookup, + NMP_OBJECT_TYPE_IP6_ADDRESS, + ifindex), + NULL, NULL); + if (plat_addresses) { + for (i = 0; i < plat_addresses->len; i++) { + address = NMP_OBJECT_CAST_IP6_ADDRESS (plat_addresses->pdata[i]); + + /* Leave link local address management to the kernel */ + if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address)) + continue; - if (!array_contains_ip6_address (known_addresses, address, now)) - nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen); + if (!array_contains_ip6_address (known_addresses, address, now)) + nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen); + } } - g_array_free (addresses, TRUE); if (!known_addresses) return TRUE; /* Add missing addresses */ for (i = 0; i < known_addresses->len; i++) { - const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i); + const NMPlatformIP6Address *known_address = NMP_OBJECT_CAST_IP6_ADDRESS (known_addresses->pdata[i]); guint32 lifetime, preferred; if (NM_FLAGS_HAS (known_address->n_ifa_flags, IFA_F_TEMPORARY)) { @@ -3333,7 +3390,7 @@ nm_platform_address_flush (NMPlatform *self, int ifindex) { _CHECK_SELF (self, klass, FALSE); - return nm_platform_ip4_address_sync (self, ifindex, NULL, NULL) + return nm_platform_ip4_address_sync (self, ifindex, NULL) && nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE); } @@ -3389,29 +3446,19 @@ 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) +nm_platform_ip_route_delete (NMPlatform *self, + const NMPObject *obj) { - char str_dev[TO_STRING_DEV_BUF_SIZE]; - _CHECK_SELF (self, klass, FALSE); - _LOGD ("route: deleting IPv4 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", - nm_utils_inet4_ntop (network, NULL), plen, metric, ifindex, - _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); - return klass->ip4_route_delete (self, ifindex, network, plen, metric); -} - -gboolean -nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) -{ - char str_dev[TO_STRING_DEV_BUF_SIZE]; + nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE)); - _CHECK_SELF (self, klass, FALSE); + _LOGD ("route: deleting IPv%c route %s", + NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_IP4_ROUTE ? '4' : '6', + nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - _LOGD ("route: deleting IPv6 route %s/%d, metric=%"G_GUINT32_FORMAT", ifindex %d%s", - nm_utils_inet6_ntop (&network, NULL), plen, metric, ifindex, - _to_string_dev (self, ifindex, str_dev, sizeof (str_dev))); - return klass->ip6_route_delete (self, ifindex, network, plen, metric); + return klass->ip_route_delete (self, obj); } const NMPlatformIP4Route * @@ -5103,44 +5150,12 @@ _vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *rout return nm_platform_ip6_route_add (self, &rt); } -static gboolean -_vtr_v4_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route) -{ - return nm_platform_ip4_route_delete (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->r4.network, - route->rx.plen, - route->rx.metric); -} - -static gboolean -_vtr_v6_route_delete (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route) -{ - return nm_platform_ip6_route_delete (self, - ifindex > 0 ? ifindex : route->rx.ifindex, - route->r6.network, - route->rx.plen, - route->rx.metric); -} - static guint32 _vtr_v4_metric_normalize (guint32 metric) { return metric; } -static gboolean -_vtr_v4_route_delete_default (NMPlatform *self, int ifindex, guint32 metric) -{ - return nm_platform_ip4_route_delete (self, ifindex, 0, 0, metric); -} - -static gboolean -_vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric) -{ - return nm_platform_ip6_route_delete (self, ifindex, in6addr_any, 0, metric); -} - /*****************************************************************************/ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = { @@ -5151,8 +5166,6 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = { .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_add = _vtr_v4_route_add, - .route_delete = _vtr_v4_route_delete, - .route_delete_default = _vtr_v4_route_delete_default, .metric_normalize = _vtr_v4_metric_normalize, }; @@ -5164,8 +5177,6 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = { .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_add = _vtr_v6_route_add, - .route_delete = _vtr_v6_route_delete, - .route_delete_default = _vtr_v6_route_delete_default, .metric_normalize = nm_utils_ip6_route_metric_normalize, }; diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 6e7a8b0658..956e718223 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -173,9 +173,9 @@ typedef enum { NM_PLATFORM_SIGNAL_REMOVED, } NMPlatformSignalChangeType; -typedef struct { +struct _NMPlatformObject { __NMPlatformObject_COMMON; -} NMPlatformObject; +}; #define __NMPlatformIPAddress_COMMON \ @@ -367,8 +367,6 @@ typedef struct { 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); 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); guint32 (*metric_normalize) (guint32 metric); } NMPlatformVTableRoute; @@ -644,8 +642,7 @@ typedef struct { 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); + gboolean (*ip_route_delete) (NMPlatform *, const NMPObject *obj); gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *); gboolean (*check_support_user_ipv6ll) (NMPlatform *); @@ -931,8 +928,7 @@ NMPlatformError nm_platform_link_sit_add (NMPlatform *self, const NMPlatformLink **out_link); const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address); -GArray *nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex); -GArray *nm_platform_ip6_address_get_all (NMPlatform *self, int ifindex); + gboolean nm_platform_ip4_address_add (NMPlatform *self, int ifindex, in_addr_t address, @@ -952,16 +948,15 @@ gboolean nm_platform_ip6_address_add (NMPlatform *self, guint32 flags); gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address); gboolean nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, guint8 plen); -gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, GPtrArray **out_added_addresses); -gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, gboolean keep_link_local); +gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresse); +gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GPtrArray *known_addresses, gboolean keep_link_local); 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); 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); -gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); +gboolean nm_platform_ip_route_delete (NMPlatform *self, const NMPObject *route); const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len); const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len); diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h index 9cdad2e808..b63265ee11 100644 --- a/src/platform/nmp-object.h +++ b/src/platform/nmp-object.h @@ -345,6 +345,22 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj) _obj ? &_NM_CONSTCAST (NMPObject, _obj)->link : NULL; \ }) +#define NMP_OBJECT_CAST_IP_ADDRESS(obj) \ + ({ \ + typeof (obj) _obj = (obj); \ + \ + nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); \ + _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ip_address : NULL; \ + }) + +#define NMP_OBJECT_CAST_IPX_ADDRESS(obj) \ + ({ \ + typeof (obj) _obj = (obj); \ + \ + nm_assert (!_obj || NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS)); \ + _obj ? &_NM_CONSTCAST (NMPObject, _obj)->ipx_address : NULL; \ + }) + #define NMP_OBJECT_CAST_IP4_ADDRESS(obj) \ ({ \ typeof (obj) _obj = (obj); \ @@ -419,6 +435,15 @@ NMPObject *nmp_object_new (NMPObjectType obj_type, const NMPlatformObject *plob) NMPObject *nmp_object_new_link (int ifindex); const NMPObject *nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformObject *plobj); + +static inline NMPObject * +nmp_object_stackinit_obj (NMPObject *obj, const NMPObject *src) +{ + return obj == src + ? obj + : (NMPObject *) nmp_object_stackinit (obj, NMP_OBJECT_GET_TYPE (src), &src->object); +} + const NMPObject *nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src); const NMPObject *nmp_object_stackinit_id_link (NMPObject *obj, int ifindex); const NMPObject *nmp_object_stackinit_id_ip4_address (NMPObject *obj, int ifindex, guint32 address, guint8 plen, guint32 peer_address); diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c index 2ff07b8dc4..93851ff7e8 100644 --- a/src/platform/tests/test-address.c +++ b/src/platform/tests/test-address.c @@ -102,7 +102,7 @@ test_ip4_address_general (void) accept_signals (address_changed, 0, 1); /* Test address listing */ - addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); + addresses = nmtstp_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); g_assert (addresses); g_assert_cmpint (addresses->len, ==, 1); address = &g_array_index (addresses, NMPlatformIP4Address, 0); @@ -152,7 +152,7 @@ test_ip6_address_general (void) accept_signals (address_changed, 0, 1); /* Test address listing */ - addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); + addresses = nmtstp_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); g_assert (addresses); g_assert_cmpint (addresses->len, ==, 1); address = &g_array_index (addresses, NMPlatformIP6Address, 0); @@ -329,7 +329,7 @@ test_ip4_address_peer_zero (void) nmtstp_ip4_address_add (NULL, EX, ifindex, addr, plen, r_peers[i], lifetime, preferred, 0, label); - addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); + addrs = nmtstp_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); g_assert (addrs); g_assert_cmpint (addrs->len, ==, i + 1); g_array_unref (addrs); @@ -344,7 +344,7 @@ test_ip4_address_peer_zero (void) nmtstp_ip4_address_del (NULL, EX, ifindex, addr, plen, r_peers[i]); - addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); + addrs = nmtstp_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); g_assert (addrs); g_assert_cmpint (addrs->len, ==, G_N_ELEMENTS (peers) - i - 1); g_array_unref (addrs); diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c index 690ba35a53..937cd12c7d 100644 --- a/src/platform/tests/test-cleanup.c +++ b/src/platform/tests/test-cleanup.c @@ -70,8 +70,8 @@ test_cleanup_internal (void) nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network6, plen6, gateway6, in6addr_any, metric, mss); nmtstp_ip6_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, in6addr_any, 0, gateway6, in6addr_any, metric, mss); - addresses4 = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); - addresses6 = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); + addresses4 = nmtstp_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); + addresses6 = nmtstp_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); routes4 = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); routes6 = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, ifindex); @@ -88,8 +88,8 @@ test_cleanup_internal (void) /* 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); + addresses4 = nmtstp_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex); + addresses6 = nmtstp_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex); routes4 = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex); routes6 = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, ifindex); diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c index 62c2c83fd1..51234cf17a 100644 --- a/src/platform/tests/test-common.c +++ b/src/platform/tests/test-common.c @@ -70,6 +70,90 @@ _init_platform (NMPlatform **platform, gboolean external_command) /*****************************************************************************/ +static GArray * +_ipx_address_get_all (NMPlatform *self, int ifindex, NMPObjectType obj_type) +{ + NMPLookup lookup; + + g_assert (NM_IS_PLATFORM (self)); + g_assert (ifindex > 0); + g_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 (nm_platform_lookup (self, &lookup), + obj_type, + FALSE /*addresses are always visible. */); +} + +GArray * +nmtstp_platform_ip4_address_get_all (NMPlatform *self, int ifindex) +{ + return _ipx_address_get_all (self, ifindex, NMP_OBJECT_TYPE_IP4_ADDRESS); +} + +GArray * +nmtstp_platform_ip6_address_get_all (NMPlatform *self, int ifindex) +{ + return _ipx_address_get_all (self, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS); +} + +/*****************************************************************************/ + +gboolean +nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric) +{ + NMDedupMultiIter iter; + + nm_platform_process_events (platform); + + nm_dedup_multi_iter_for_each (&iter, + nm_platform_lookup_addrroute (platform, + NMP_OBJECT_TYPE_IP4_ROUTE, + ifindex)) { + const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (iter.current->obj); + + if ( r->ifindex != ifindex + || r->network != network + || r->plen != plen + || r->metric != metric) { + continue; + } + + return nm_platform_ip_route_delete (platform, NMP_OBJECT_UP_CAST (r)); + } + + return TRUE; +} + +gboolean +nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric) +{ + NMDedupMultiIter iter; + + nm_platform_process_events (platform); + + nm_dedup_multi_iter_for_each (&iter, + nm_platform_lookup_addrroute (platform, + NMP_OBJECT_TYPE_IP6_ROUTE, + ifindex)) { + const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (iter.current->obj); + + if ( r->ifindex != ifindex + || !IN6_ARE_ADDR_EQUAL (&r->network, &network) + || r->plen != plen + || r->metric != metric) { + continue; + } + + return nm_platform_ip_route_delete (platform, NMP_OBJECT_UP_CAST (r)); + } + + return TRUE; +} + +/*****************************************************************************/ + SignalData * add_signal_full (const char *name, NMPlatformSignalChangeType change_type, GCallback callback, int ifindex, const char *ifname) { diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h index b9e879ff62..4d65a26683 100644 --- a/src/platform/tests/test-common.h +++ b/src/platform/tests/test-common.h @@ -214,6 +214,12 @@ nmtstp_ip6_route_get_all (NMPlatform *platform, /*****************************************************************************/ +GArray *nmtstp_platform_ip4_address_get_all (NMPlatform *self, int ifindex); +GArray *nmtstp_platform_ip6_address_get_all (NMPlatform *self, int ifindex); + +gboolean nmtstp_platform_ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, guint8 plen, guint32 metric); +gboolean nmtstp_platform_ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, guint8 plen, guint32 metric); + const NMPlatformLink *nmtstp_link_get_typed (NMPlatform *platform, int ifindex, const char *name, NMLinkType link_type); const NMPlatformLink *nmtstp_link_get (NMPlatform *platform, int ifindex, const char *name); diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c index 3fe0f3128a..adaf7e538a 100644 --- a/src/platform/tests/test-route.c +++ b/src/platform/tests/test-route.c @@ -136,7 +136,7 @@ test_ip4_route_metric0 (void) nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); /* Deleting route with metric 0 does nothing */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); ensure_no_signal (route_removed); nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); @@ -150,21 +150,21 @@ test_ip4_route_metric0 (void) nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); /* Delete route with metric 0 */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); accept_signal (route_removed); nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); /* Delete route with metric 0 again (we expect nothing to happen) */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, 0)); ensure_no_signal (route_removed); nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); nmtstp_assert_ip4_route_exists (NULL, TRUE, DEVICE_NAME, network, plen, metric); /* Delete the other route */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); accept_signal (route_removed); nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, 0); @@ -250,19 +250,19 @@ test_ip4_route (void) g_ptr_array_unref (routes); /* Remove route */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); nmtstp_assert_ip4_route_exists (NULL, FALSE, DEVICE_NAME, network, plen, metric); accept_signal (route_removed); /* Remove route again */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); /* Remove default route */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, 0, 0, metric)); + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, 0, 0, metric)); accept_signal (route_removed); /* Remove route to gateway */ - g_assert (nm_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, gateway, 32, metric)); + g_assert (nmtstp_platform_ip4_route_delete (NM_PLATFORM_GET, ifindex, gateway, 32, metric)); accept_signal (route_removed); free_signal (route_added); @@ -352,19 +352,19 @@ test_ip6_route (void) g_ptr_array_unref (routes); /* Remove route */ - g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); g_assert (!nm_platform_ip6_route_get (NM_PLATFORM_GET, ifindex, network, plen, metric)); accept_signal (route_removed); /* Remove route again */ - g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); + g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, network, plen, metric)); /* Remove default route */ - g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); + g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, in6addr_any, 0, metric)); accept_signal (route_removed); /* Remove route to gateway */ - g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, gateway, 128, metric)); + g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, ifindex, gateway, 128, metric)); accept_signal (route_removed); free_signal (route_added); @@ -438,10 +438,11 @@ test_ip4_route_options (void) rts[0].lock_cwnd = TRUE; g_assert_cmpint (routes->len, ==, 1); 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_assert (nm_platform_ip_route_delete (NM_PLATFORM_GET, routes->pdata[0])); + + g_ptr_array_unref (routes); } @@ -536,9 +537,9 @@ test_ip6_route_options (gconstpointer test_data) g_ptr_array_unref (routes); for (i = 0; i < rts_n; i++) { - g_assert (nm_platform_ip6_route_delete (NM_PLATFORM_GET, IFINDEX, - rts_add[i].network, rts_add[i].plen, - rts_add[i].metric)); + g_assert (nmtstp_platform_ip6_route_delete (NM_PLATFORM_GET, IFINDEX, + rts_add[i].network, rts_add[i].plen, + rts_add[i].metric)); } for (i = 0; i < addr_n; i++) { diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c index e865f5f26a..d47ff2e643 100644 --- a/src/tests/test-ip4-config.c +++ b/src/tests/test-ip4-config.c @@ -75,7 +75,7 @@ test_subtract (void) const NMPlatformIP4Route *test_route; const char *expected_addr = "192.168.1.12"; guint32 expected_addr_plen = 24; - const char *expected_route_dest = "8.7.6.5"; + const char *expected_route_dest = "8.0.0.0"; guint32 expected_route_plen = 8; const char *expected_route_next_hop = "192.168.1.1"; guint32 expected_ns1 = nmtst_inet4_from_string ("8.8.8.8"); @@ -112,7 +112,7 @@ test_subtract (void) /* ensure what's left is what we expect */ g_assert_cmpuint (nm_ip4_config_get_num_addresses (dst), ==, 1); - test_addr = nm_ip4_config_get_address (dst, 0); + test_addr = _nmtst_nm_ip4_config_get_address (dst, 0); g_assert (test_addr != NULL); g_assert_cmpuint (test_addr->address, ==, nmtst_inet4_from_string (expected_addr)); g_assert_cmpuint (test_addr->peer_address, ==, test_addr->address); @@ -196,27 +196,27 @@ test_add_address_with_source (void) addr.addr_source = NM_IP_CONFIG_SOURCE_USER; nm_ip4_config_add_address (a, &addr); - test_addr = nm_ip4_config_get_address (a, 0); + test_addr = _nmtst_nm_ip4_config_get_address (a, 0); g_assert_cmpint (test_addr->addr_source, ==, NM_IP_CONFIG_SOURCE_USER); addr.addr_source = NM_IP_CONFIG_SOURCE_VPN; nm_ip4_config_add_address (a, &addr); - test_addr = nm_ip4_config_get_address (a, 0); + test_addr = _nmtst_nm_ip4_config_get_address (a, 0); g_assert_cmpint (test_addr->addr_source, ==, NM_IP_CONFIG_SOURCE_USER); /* Test that a lower priority address source is overwritten */ - nm_ip4_config_del_address (a, 0); + _nmtst_nm_ip4_config_del_address (a, 0); addr.addr_source = NM_IP_CONFIG_SOURCE_KERNEL; nm_ip4_config_add_address (a, &addr); - test_addr = nm_ip4_config_get_address (a, 0); + test_addr = _nmtst_nm_ip4_config_get_address (a, 0); g_assert_cmpint (test_addr->addr_source, ==, NM_IP_CONFIG_SOURCE_KERNEL); addr.addr_source = NM_IP_CONFIG_SOURCE_USER; nm_ip4_config_add_address (a, &addr); - test_addr = nm_ip4_config_get_address (a, 0); + test_addr = _nmtst_nm_ip4_config_get_address (a, 0); g_assert_cmpint (test_addr->addr_source, ==, NM_IP_CONFIG_SOURCE_USER); g_object_unref (a); @@ -232,7 +232,7 @@ test_add_route_with_source (void) a = nmtst_ip4_config_new (1); /* Test that a higher priority source is not overwritten */ - route = *nmtst_platform_ip4_route ("1.2.3.4", 24, "1.2.3.1"); + route = *nmtst_platform_ip4_route ("1.2.3.0", 24, "1.2.3.1"); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip4_config_add_route (a, &route); diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c index 0887e9da98..7079009539 100644 --- a/src/tests/test-ip6-config.c +++ b/src/tests/test-ip6-config.c @@ -37,8 +37,8 @@ build_test_config (void) 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)); - nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001:abba::", 16, "2001:abba::2234", NULL)); + nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("abcd:1200::", 24, "abcd:1234:4321:cdde::2", NULL)); + nm_ip6_config_add_route (config, nmtst_platform_ip6_route ("2001::", 16, "2001:abba::2234", NULL)); nm_ip6_config_set_gateway (config, nmtst_inet6_from_string ("3001:abba::3234")); @@ -60,7 +60,7 @@ test_subtract (void) const NMPlatformIP6Route *test_route; const char *expected_addr = "1122:3344:5566::7788"; guint32 expected_addr_plen = 96; - const char *expected_route_dest = "9991:8882:7773::"; + const char *expected_route_dest = "9991:8800::"; guint32 expected_route_plen = 24; const char *expected_route_next_hop = "1119:2228:3337:4446::5555"; struct in6_addr expected_ns1; @@ -88,7 +88,7 @@ test_subtract (void) /* ensure what's left is what we expect */ g_assert_cmpuint (nm_ip6_config_get_num_addresses (dst), ==, 1); - test_addr = nm_ip6_config_get_address (dst, 0); + test_addr = _nmtst_nm_ip6_config_get_address (dst, 0); g_assert (test_addr != NULL); tmp = *nmtst_inet6_from_string (expected_addr); g_assert (memcmp (&test_addr->address, &tmp, sizeof (tmp)) == 0); @@ -139,7 +139,7 @@ test_compare_with_source (void) nm_ip6_config_add_address (b, &addr); /* Route */ - route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL); + route = *nmtst_platform_ip6_route ("abcd:1200::", 24, "abcd:1234:4321:cdde::2", NULL); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_route (a, &route); @@ -167,27 +167,27 @@ test_add_address_with_source (void) addr.addr_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_address (a, &addr); - test_addr = nm_ip6_config_get_address (a, 0); + test_addr = _nmtst_nm_ip6_config_get_address (a, 0); g_assert_cmpint (test_addr->addr_source, ==, NM_IP_CONFIG_SOURCE_USER); addr.addr_source = NM_IP_CONFIG_SOURCE_VPN; nm_ip6_config_add_address (a, &addr); - test_addr = nm_ip6_config_get_address (a, 0); + test_addr = _nmtst_nm_ip6_config_get_address (a, 0); g_assert_cmpint (test_addr->addr_source, ==, NM_IP_CONFIG_SOURCE_USER); /* Test that a lower priority address source is overwritten */ - nm_ip6_config_del_address (a, 0); + _nmtst_nm_ip6_config_del_address (a, 0); addr.addr_source = NM_IP_CONFIG_SOURCE_KERNEL; nm_ip6_config_add_address (a, &addr); - test_addr = nm_ip6_config_get_address (a, 0); + test_addr = _nmtst_nm_ip6_config_get_address (a, 0); g_assert_cmpint (test_addr->addr_source, ==, NM_IP_CONFIG_SOURCE_KERNEL); addr.addr_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_address (a, &addr); - test_addr = nm_ip6_config_get_address (a, 0); + test_addr = _nmtst_nm_ip6_config_get_address (a, 0); g_assert_cmpint (test_addr->addr_source, ==, NM_IP_CONFIG_SOURCE_USER); g_object_unref (a); @@ -203,7 +203,7 @@ test_add_route_with_source (void) a = nmtst_ip6_config_new (1); /* Test that a higher priority source is not overwritten */ - route = *nmtst_platform_ip6_route ("abcd:1234:4321::", 24, "abcd:1234:4321:cdde::2", NULL); + route = *nmtst_platform_ip6_route ("abcd:1200::", 24, "abcd:1234:4321:cdde::2", NULL); route.rt_source = NM_IP_CONFIG_SOURCE_USER; nm_ip6_config_add_route (a, &route); @@ -256,18 +256,18 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config int j = g_rand_int_range (nmtst_get_rand (), i, addr_count); NMTST_SWAP (idx[i], idx[j]); - nm_ip6_config_add_address (copy, nm_ip6_config_get_address (config, idx[i])); + nm_ip6_config_add_address (copy, _nmtst_nm_ip6_config_get_address (config, idx[i])); } /* reorder them again */ - nm_ip6_config_addresses_sort (copy); + _nmtst_nm_ip6_config_addresses_sort (copy); /* check equality using nm_ip6_config_equal() */ if (!nm_ip6_config_equal (copy, config)) { g_message ("%s", "SORTING yields unexpected output:"); for (i = 0; i < addr_count; i++) { - g_message (" >> [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i), NULL, 0)); - g_message (" << [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (copy, i), NULL, 0)); + g_message (" >> [%d] = %s", i, nm_platform_ip6_address_to_string (_nmtst_nm_ip6_config_get_address (config, i), NULL, 0)); + g_message (" << [%d] = %s", i, nm_platform_ip6_address_to_string (_nmtst_nm_ip6_config_get_address (copy, i), NULL, 0)); } g_assert_not_reached (); } diff --git a/src/vpn/nm-vpn-connection.c b/src/vpn/nm-vpn-connection.c index ab6103d497..63692cffbc 100644 --- a/src/vpn/nm-vpn-connection.c +++ b/src/vpn/nm-vpn-connection.c @@ -959,7 +959,8 @@ print_vpn_config (NMVpnConnection *self) _LOGI ("Data: IPv4 configuration:"); - address4 = nm_ip4_config_get_address (priv->ip4_config, 0); + address4 = nm_ip4_config_get_first_address (priv->ip4_config); + nm_assert (address4); if (priv->ip4_internal_gw) _LOGI ("Data: Internal Gateway: %s", nm_utils_inet4_ntop (priv->ip4_internal_gw, NULL)); @@ -968,7 +969,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)); - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) { + nm_ip_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, @@ -996,7 +997,8 @@ print_vpn_config (NMVpnConnection *self) _LOGI ("Data: IPv6 configuration:"); - address6 = nm_ip6_config_get_address (priv->ip6_config, 0); + address6 = nm_ip6_config_get_first_address (priv->ip6_config); + nm_assert (address6); if (priv->ip6_internal_gw) _LOGI ("Data: Internal Gateway: %s", nm_utils_inet6_ntop (priv->ip6_internal_gw, NULL)); @@ -1005,7 +1007,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)); - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) { + nm_ip_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, @@ -1506,7 +1508,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) NMDedupMultiIter ipconf_iter; const NMPlatformIP4Route *route; - nm_ip4_config_iter_ip4_route_for_each (&ipconf_iter, priv->ip4_config, &route) + nm_ip_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)) { @@ -1529,6 +1531,7 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict) if (plen > 32 || plen == 0) break; route.plen = plen; + route.network = nm_utils_ip4_address_clear_host_address (route.network, plen); /* Ignore host routes to the VPN gateway since NM adds one itself * below. Since NM knows more about the routing situation than @@ -1670,7 +1673,7 @@ nm_vpn_connection_ip6_config_get (NMVpnConnection *self, GVariant *dict) NMDedupMultiIter ipconf_iter; const NMPlatformIP6Route *route; - nm_ip6_config_iter_ip6_route_for_each (&ipconf_iter, priv->ip6_config, &route) + nm_ip_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)) { |