diff options
Diffstat (limited to 'src/nm-route-manager.c')
| -rw-r--r-- | src/nm-route-manager.c | 1321 |
1 files changed, 0 insertions, 1321 deletions
diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c deleted file mode 100644 index f293f130..00000000 --- a/src/nm-route-manager.c +++ /dev/null @@ -1,1321 +0,0 @@ -/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ -/* NetworkManager -- Network link manager - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License along - * with this program; if not, write to the Free Software Foundation, Inc., - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Copyright (C) 2015 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-route-manager.h" - -#include <string.h> - -#include "platform/nm-platform.h" -#include "platform/nm-platform-utils.h" -#include "platform/nmp-object.h" -#include "nm-core-internal.h" -#include "NetworkManagerUtils.h" - -/* if within half a second after adding an IP address a matching device-route shows - * 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) - -/*****************************************************************************/ - -typedef struct { - guint len; - NMPlatformIPXRoute *entries[1]; -} RouteIndex; - -typedef struct { - GArray *entries; - RouteIndex *index; - - /* list of effective metrics. The indexes of the array correspond to @index, not @entries. */ - GArray *effective_metrics; - - /* this array contains the effective metrics but using the reversed index that corresponds - * to @entries, instead of @index. */ - GArray *effective_metrics_reverse; -} RouteEntries; - -typedef struct { - NMRouteManager *self; - gint64 scheduled_at_ns; - guint idle_id; - NMPObject *obj; -} IP4DeviceRoutePurgeEntry; - -/*****************************************************************************/ - -enum { - IP4_ROUTES_CHANGED, - LAST_SIGNAL, -}; -static guint signals[LAST_SIGNAL] = { 0 }; - -NM_GOBJECT_PROPERTIES_DEFINE_BASE ( - PROP_LOG_WITH_PTR, - PROP_PLATFORM, -); - -typedef struct { - NMPlatform *platform; - - RouteEntries ip4_routes; - RouteEntries ip6_routes; - struct { - GHashTable *entries; - guint gc_id; - } ip4_device_routes; - - bool log_with_ptr; -} NMRouteManagerPrivate; - -struct _NMRouteManager { - GObject parent; - NMRouteManagerPrivate _priv; -}; - -struct _NMRouteManagerClass { - GObjectClass parent; -}; - -G_DEFINE_TYPE (NMRouteManager, nm_route_manager, G_TYPE_OBJECT); - -#define NM_ROUTE_MANAGER_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMRouteManager, NM_IS_ROUTE_MANAGER) - -/*****************************************************************************/ - -typedef struct { - const NMPlatformVTableRoute *vt; - - /* a compare function for two routes that considers only the destination fields network/plen. - * It is a looser comparisong then @route_id_cmp(), that means that if @route_dest_cmp() - * returns non-zero, also @route_id_cmp() returns the same value. It also means, that - * sorting by @route_id_cmp() implicitly sorts by @route_dest_cmp() as well. */ - int (*route_dest_cmp) (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2); - - /* a compare function for two routes that considers only the fields network/plen,metric. */ - int (*route_id_cmp) (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2); -} VTableIP; - -static const VTableIP vtable_v4, vtable_v6; - -#define VTABLE_ROUTE_INDEX(vtable, garray, idx) ((NMPlatformIPXRoute *) &((garray)->data[(idx) * (vtable)->vt->sizeof_route])) - -#define VTABLE_IS_DEVICE_ROUTE(vtable, route) ((vtable)->vt->is_ip4 \ - ? ((route)->r4.gateway == 0) \ - : IN6_IS_ADDR_UNSPECIFIED (&(route)->r6.gateway) ) - -#define CMP_AND_RETURN_INT(a, b) \ - G_STMT_START { \ - typeof(a) _a = (a), _b = (b); \ - \ - if (_a < _b) \ - return -1; \ - if (_a > _b) \ - return 1; \ - } G_STMT_END - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "route-mgr" -#undef _NMLOG_ENABLED -#define _NMLOG_ENABLED(level, addr_family) \ - ({ \ - const int __addr_family = (addr_family); \ - const NMLogLevel __level = (level); \ - const NMLogDomain __domain = __addr_family == AF_INET ? LOGD_IP4 : (__addr_family == AF_INET6 ? LOGD_IP6 : LOGD_IP); \ - \ - nm_logging_enabled (__level, __domain); \ - }) -#define _NMLOG(level, addr_family, ...) \ - G_STMT_START { \ - const int __addr_family = (addr_family); \ - const NMLogLevel __level = (level); \ - const NMLogDomain __domain = __addr_family == AF_INET ? LOGD_IP4 : (__addr_family == AF_INET6 ? LOGD_IP6 : LOGD_IP); \ - \ - if (nm_logging_enabled (__level, __domain)) { \ - char __ch = __addr_family == AF_INET ? '4' : (__addr_family == AF_INET6 ? '6' : '-'); \ - char __prefix[30] = _NMLOG_PREFIX_NAME; \ - \ - if (NM_ROUTE_MANAGER_GET_PRIVATE (self)->log_with_ptr) \ - g_snprintf (__prefix, sizeof (__prefix), "%s%c[%p]", _NMLOG_PREFIX_NAME, __ch, (self)); \ - else \ - __prefix[NM_STRLEN (_NMLOG_PREFIX_NAME)] = __ch; \ - _nm_log ((level), (__domain), 0, NULL, NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } G_STMT_END - -/*****************************************************************************/ - -static gboolean _ip4_device_routes_cancel (NMRouteManager *self); - -/*****************************************************************************/ - -#if NM_MORE_ASSERTS && !defined (G_DISABLE_ASSERT) -static inline void -ASSERT_route_index_valid (const VTableIP *vtable, const GArray *entries, const RouteIndex *index, gboolean unique_ifindexes) -{ - guint i, j; - int c; - const NMPlatformIPXRoute *r1, *r2; - gs_unref_hashtable GHashTable *ptrs = g_hash_table_new (NULL, NULL); - const NMPlatformIPXRoute *r_first = NULL, *r_last = NULL; - - g_assert (index); - - if (entries) - g_assert_cmpint (entries->len, ==, index->len); - else - g_assert (index->len == 0); - - if (index->len > 0) { - r_first = VTABLE_ROUTE_INDEX (vtable, entries, 0); - r_last = VTABLE_ROUTE_INDEX (vtable, entries, index->len - 1); - } - - /* assert that the @index is valid for the @entries. */ - - g_assert (!index->entries[index->len]); - for (i = 0; i < index->len; i++) { - r1 = index->entries[i]; - - g_assert (r1); - g_assert (r1 >= r_first); - g_assert (r1 <= r_last); - g_assert_cmpint ((((char *) r1) - ((char *) entries->data)) % vtable->vt->sizeof_route, ==, 0); - - g_assert (!g_hash_table_contains (ptrs, (gpointer) r1)); - g_hash_table_add (ptrs, (gpointer) r1); - - for (j = i; j > 0; ) { - r2 = index->entries[--j]; - - c = vtable->route_id_cmp (r1, r2); - g_assert (c >= 0); - if (c != 0) - break; - if (unique_ifindexes) - g_assert_cmpint (r1->rx.ifindex, !=, r2->rx.ifindex); - } - } -} -#else -#define ASSERT_route_index_valid(vtable, entries, index, unique_ifindexes) G_STMT_START { (void) 0; } G_STMT_END -#endif - -/*****************************************************************************/ - -static int -_v4_route_dest_cmp (const NMPlatformIP4Route *r1, const NMPlatformIP4Route *r2) -{ - CMP_AND_RETURN_INT (r1->plen, r2->plen); - CMP_AND_RETURN_INT (nm_utils_ip4_address_clear_host_address (r1->network, r1->plen), - nm_utils_ip4_address_clear_host_address (r2->network, r2->plen)); - return 0; -} - -static int -_v6_route_dest_cmp (const NMPlatformIP6Route *r1, const NMPlatformIP6Route *r2) -{ - struct in6_addr n1, n2; - - CMP_AND_RETURN_INT (r1->plen, r2->plen); - - nm_utils_ip6_address_clear_host_address (&n1, &r1->network, r1->plen); - nm_utils_ip6_address_clear_host_address (&n2, &r2->network, r2->plen ); - return memcmp (&n1, &n2, sizeof (n1)); -} - -static int -_v4_route_id_cmp (const NMPlatformIP4Route *r1, const NMPlatformIP4Route *r2) -{ - CMP_AND_RETURN_INT (r1->plen, r2->plen); - CMP_AND_RETURN_INT (nm_utils_ip4_address_clear_host_address (r1->network, r1->plen), - nm_utils_ip4_address_clear_host_address (r2->network, r2->plen)); - CMP_AND_RETURN_INT (r1->metric, r2->metric); - return 0; -} - -static int -_v6_route_id_cmp (const NMPlatformIP6Route *r1, const NMPlatformIP6Route *r2) -{ - struct in6_addr n1, n2; - int c; - - CMP_AND_RETURN_INT (r1->plen, r2->plen); - - nm_utils_ip6_address_clear_host_address (&n1, &r1->network, r1->plen); - nm_utils_ip6_address_clear_host_address (&n2, &r2->network, r2->plen); - c = memcmp (&n1, &n2, sizeof (n1)); - if (c != 0) - return c; - - CMP_AND_RETURN_INT (nm_utils_ip6_route_metric_normalize (r1->metric), - nm_utils_ip6_route_metric_normalize (r2->metric)); - return 0; -} - -/*****************************************************************************/ - -static int -_route_index_create_sort (const NMPlatformIPXRoute **p1, const NMPlatformIPXRoute ** p2, const VTableIP *vtable) -{ - return vtable->route_id_cmp (*p1, *p2); -} - -static RouteIndex * -_route_index_create (const VTableIP *vtable, const GArray *routes) -{ - RouteIndex *index; - guint i; - guint len = routes ? routes->len : 0; - - index = g_malloc (sizeof (RouteIndex) + len * sizeof (NMPlatformIPXRoute *)); - - index->len = len; - for (i = 0; i < len; i++) - index->entries[i] = VTABLE_ROUTE_INDEX (vtable, routes, i); - index->entries[i] = NULL; - - /* this is a stable sort, which is very important at this point. */ - g_qsort_with_data (index->entries, - len, - sizeof (NMPlatformIPXRoute *), - (GCompareDataFunc) _route_index_create_sort, - (gpointer) vtable); - return index; -} - -static int -_vx_route_id_cmp_full (const NMPlatformIPXRoute *r1, const NMPlatformIPXRoute *r2, const VTableIP *vtable) -{ - return vtable->route_id_cmp (r1, r2); -} - -static gssize -_route_index_find (const VTableIP *vtable, const RouteIndex *index, const NMPlatformIPXRoute *needle) -{ - gssize idx, idx2; - - idx = _nm_utils_ptrarray_find_binary_search ((gconstpointer *) index->entries, index->len, needle, (GCompareDataFunc) _vx_route_id_cmp_full, (gpointer) vtable); - if (idx < 0) - return idx; - - /* we only know that the route at index @idx has matching destination. Also find the one with the right - * ifindex by searching the neighbours */ - - idx2 = idx; - do { - if (index->entries[idx2]->rx.ifindex == needle->rx.ifindex) - return idx2; - } while ( idx2 > 0 - && vtable->route_id_cmp (index->entries[--idx2], needle) != 0); - - for (idx++; idx < index->len; idx++ ){ - if (vtable->route_id_cmp (index->entries[idx], needle) != 0) - break; - if (index->entries[idx]->rx.ifindex == needle->rx.ifindex) - return idx; - } - - return ~idx; -} - -static guint -_route_index_reverse_idx (const VTableIP *vtable, const RouteIndex *index, guint idx_idx, const GArray *routes) -{ - const NMPlatformIPXRoute *r, *r0; - gssize offset; - - /* reverse the @idx_idx that points into @index, to the corresponding index into the unsorted @routes array. */ - - r = index->entries[idx_idx]; - r0 = VTABLE_ROUTE_INDEX (vtable, routes, 0); - - if (vtable->vt->is_ip4) - offset = &r->r4 - &r0->r4; - else - offset = &r->r6 - &r0->r6; - g_assert (offset >= 0 && offset < index->len); - g_assert (VTABLE_ROUTE_INDEX (vtable, routes, offset) == r); - return offset; -} - -/*****************************************************************************/ - -static gboolean -_route_equals_ignoring_ifindex (const VTableIP *vtable, - const NMPlatformIPXRoute *plat_rt, - const NMPlatformIPXRoute *rt, - gint64 rt_metric) -{ - NMPlatformIPXRoute rt_backup; - - memcpy (&rt_backup, rt, vtable->vt->sizeof_route); - rt_backup.rx.ifindex = plat_rt->rx.ifindex; - if (rt_metric >= 0) - rt_backup.rx.metric = (guint32) rt_metric; - rt_backup.rx.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (rt_backup.rx.rt_source); - - return vtable->vt->route_cmp (plat_rt, &rt_backup, FALSE) == 0; -} - -static NMPlatformIPXRoute * -_get_next_ipx_route (const RouteIndex *index, gboolean start_at_zero, guint *cur_idx, int ifindex) -{ - guint i; - - if (start_at_zero) - i = 0; - else - i = *cur_idx + 1; - /* Find the next route with matching @ifindex. */ - for (; i < index->len; i++) { - if (index->entries[i]->rx.ifindex == ifindex) { - *cur_idx = i; - return index->entries[i]; - } - } - *cur_idx = index->len; - return NULL; -} - -static const NMPlatformIPXRoute * -_get_next_known_route (const VTableIP *vtable, const RouteIndex *index, gboolean start_at_zero, guint *cur_idx) -{ - guint i = 0; - const NMPlatformIPXRoute *cur = NULL; - - if (!start_at_zero) { - i = *cur_idx; - cur = index->entries[i]; - i++; - } - /* For @known_routes we expect that all routes have the same @ifindex. This is not enforced however, - * the ifindex value of these routes is ignored. */ - for (; i < index->len; i++) { - const NMPlatformIPXRoute *r = index->entries[i]; - - /* skip over default routes. */ - if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)) - continue; - - /* @known_routes should not, but could contain duplicate routes. Skip over them. */ - if (cur && vtable->route_id_cmp (cur, r) == 0) - continue; - - *cur_idx = i; - return r; - } - *cur_idx = index->len; - return NULL; -} - -static const NMPlatformIPXRoute * -_get_next_plat_route (const RouteIndex *index, gboolean start_at_zero, guint *cur_idx) -{ - if (start_at_zero) - *cur_idx = 0; - else - ++*cur_idx; - - /* get next route from the platform index. */ - if (*cur_idx < index->len) - return index->entries[*cur_idx]; - *cur_idx = index->len; - return NULL; -} - -static int -_sort_indexes_cmp (guint *a, guint *b) -{ - CMP_AND_RETURN_INT (*a, *b); - g_return_val_if_reached (0); -} - -/*****************************************************************************/ - -static gboolean -_vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync) -{ - NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - GArray *plat_routes; - RouteEntries *ipx_routes; - RouteIndex *plat_routes_idx, *known_routes_idx; - gboolean success = TRUE; - guint i, i_type; - GArray *to_delete_indexes = NULL; - GPtrArray *to_add_routes = NULL; - guint i_known_routes, i_plat_routes, i_ipx_routes; - const NMPlatformIPXRoute *cur_known_route, *cur_plat_route; - NMPlatformIPXRoute *cur_ipx_route; - gint64 *p_effective_metric = NULL; - gboolean ipx_routes_changed = FALSE; - gint64 *effective_metrics = NULL; - - nm_platform_process_events (priv->platform); - - ipx_routes = vtable->vt->is_ip4 ? &priv->ip4_routes : &priv->ip6_routes; - plat_routes = vtable->vt->route_get_all (priv->platform, ifindex, - ignore_kernel_routes - ? NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT - : NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL); - plat_routes_idx = _route_index_create (vtable, plat_routes); - known_routes_idx = _route_index_create (vtable, known_routes); - - effective_metrics = &g_array_index (ipx_routes->effective_metrics, gint64, 0); - - ASSERT_route_index_valid (vtable, plat_routes, plat_routes_idx, TRUE); - ASSERT_route_index_valid (vtable, known_routes, known_routes_idx, FALSE); - - _LOGD (vtable->vt->addr_family, "%3d: sync %u IPv%c routes", ifindex, known_routes_idx->len, vtable->vt->is_ip4 ? '4' : '6'); - if (_LOGt_ENABLED (vtable->vt->addr_family)) { - for (i = 0; i < known_routes_idx->len; i++) { - _LOGt (vtable->vt->addr_family, "%3d: sync new route #%u: %s", - ifindex, i, vtable->vt->route_to_string (VTABLE_ROUTE_INDEX (vtable, known_routes, i), NULL, 0)); - } - for (i = 0; i < ipx_routes->index->len; i++) - _LOGt (vtable->vt->addr_family, "%3d: STATE: has #%u - %s (%lld)", - ifindex, i, - vtable->vt->route_to_string (ipx_routes->index->entries[i], NULL, 0), - (long long) g_array_index (ipx_routes->effective_metrics, gint64, i)); - } - - /*************************************************************************** - * Check which routes are in @known_routes, and update @ipx_routes. - * - * This first part only updates @ipx_routes to find out what routes must - * be added/deleted. - **************************************************************************/ - - /* iterate over @ipx_routes and @known_routes */ - cur_ipx_route = _get_next_ipx_route (ipx_routes->index, TRUE, &i_ipx_routes, ifindex); - cur_known_route = _get_next_known_route (vtable, known_routes_idx, TRUE, &i_known_routes); - while (cur_ipx_route || cur_known_route) { - int route_id_cmp_result = -1; - - while ( cur_ipx_route - && ( !cur_known_route - || ((route_id_cmp_result = vtable->route_id_cmp (cur_ipx_route, cur_known_route)) < 0))) { - /* we have @cur_ipx_route, which is less then @cur_known_route. Hence, - * the route does no longer exist in @known_routes */ - if (!to_delete_indexes) - to_delete_indexes = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (to_delete_indexes, i_ipx_routes); - - /* find the next @cur_ipx_route with matching ifindex. */ - cur_ipx_route = _get_next_ipx_route (ipx_routes->index, FALSE, &i_ipx_routes, ifindex); - } - if ( cur_ipx_route - && cur_known_route - && route_id_cmp_result == 0) { - if (!_route_equals_ignoring_ifindex (vtable, cur_ipx_route, cur_known_route, -1)) { - /* The routes match. Update the entry in place. As this is an exact match of primary - * fields, this only updates possibly modified fields such as @gateway or @mss. - * Modifiying @cur_ipx_route this way does not invalidate @ipx_routes->index. */ - memcpy (cur_ipx_route, cur_known_route, vtable->vt->sizeof_route); - cur_ipx_route->rx.ifindex = ifindex; - cur_ipx_route->rx.metric = vtable->vt->metric_normalize (cur_ipx_route->rx.metric); - nm_utils_ipx_address_clear_host_address (vtable->vt->addr_family, cur_ipx_route->rx.network_ptr, - cur_ipx_route->rx.network_ptr, cur_ipx_route->rx.plen); - ipx_routes_changed = TRUE; - _LOGt (vtable->vt->addr_family, "%3d: STATE: update #%u - %s", ifindex, i_ipx_routes, - vtable->vt->route_to_string (cur_ipx_route, NULL, 0)); - } - } else if (cur_known_route) { - g_assert (!cur_ipx_route || route_id_cmp_result > 0); - /* @cur_known_route is new. We cannot immediately add @cur_known_route to @ipx_routes, because - * it would invalidate @ipx_routes->index. Instead remember to add it later. */ - if (!to_add_routes) - to_add_routes = g_ptr_array_new (); - g_ptr_array_add (to_add_routes, (gpointer) cur_known_route); - } - - if (cur_ipx_route && (!cur_known_route || route_id_cmp_result == 0)) - cur_ipx_route = _get_next_ipx_route (ipx_routes->index, FALSE, &i_ipx_routes, ifindex); - if (cur_known_route) - cur_known_route = _get_next_known_route (vtable, known_routes_idx, FALSE, &i_known_routes); - } - - if (!full_sync && to_delete_indexes) { - /*************************************************************************** - * Delete routes in platform, that we are about to remove from @ipx_routes - * - * When doing a non-full_sync, we delete routes from platform that were previously - * known by route-manager, and are now deleted. - ***************************************************************************/ - - /* iterate over @to_delete_indexes and @plat_routes. - * @to_delete_indexes contains the indexes (relative to ipx_routes->index) of items - * we are about to delete. */ - cur_plat_route = _get_next_plat_route (plat_routes_idx, TRUE, &i_plat_routes); - for (i = 0; i < to_delete_indexes->len; i++) { - int route_dest_cmp_result = 0; - i_ipx_routes = g_array_index (to_delete_indexes, guint, i); - cur_ipx_route = ipx_routes->index->entries[i_ipx_routes]; - p_effective_metric = &effective_metrics[i_ipx_routes]; - - nm_assert (cur_ipx_route->rx.ifindex == ifindex); - - if (*p_effective_metric == -1) - continue; - - /* skip over @plat_routes that are ordered before our @cur_ipx_route. */ - while ( cur_plat_route - && (route_dest_cmp_result = vtable->route_dest_cmp (cur_plat_route, cur_ipx_route)) <= 0) { - if ( route_dest_cmp_result == 0 - && cur_plat_route->rx.metric >= *p_effective_metric) - break; - cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes); - } - - if (!cur_plat_route) { - /* no more platform routes. Break the loop. */ - break; - } - - if ( route_dest_cmp_result == 0 - && cur_plat_route->rx.metric == *p_effective_metric) { - /* we are about to delete cur_ipx_route and we have a matching route - * 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); - } - } - } - - /* Update @ipx_routes with the just learned changes. */ - if (to_delete_indexes || to_add_routes) { - if (to_delete_indexes) { - for (i = 0; i < to_delete_indexes->len; i++) { - guint idx = g_array_index (to_delete_indexes, guint, i); - - _LOGt (vtable->vt->addr_family, "%3d: STATE: delete #%u - %s", ifindex, idx, - vtable->vt->route_to_string (ipx_routes->index->entries[idx], NULL, 0)); - g_array_index (to_delete_indexes, guint, i) = _route_index_reverse_idx (vtable, ipx_routes->index, idx, ipx_routes->entries); - } - g_array_sort (to_delete_indexes, (GCompareFunc) _sort_indexes_cmp); - nm_utils_array_remove_at_indexes (ipx_routes->entries, &g_array_index (to_delete_indexes, guint, 0), to_delete_indexes->len); - nm_utils_array_remove_at_indexes (ipx_routes->effective_metrics_reverse, &g_array_index (to_delete_indexes, guint, 0), to_delete_indexes->len); - g_array_unref (to_delete_indexes); - } - if (to_add_routes) { - guint j = ipx_routes->effective_metrics_reverse->len; - - g_array_set_size (ipx_routes->effective_metrics_reverse, j + to_add_routes->len); - - for (i = 0; i < to_add_routes->len; i++) { - NMPlatformIPXRoute *ipx_route; - - g_array_append_vals (ipx_routes->entries, g_ptr_array_index (to_add_routes, i), 1); - - ipx_route = VTABLE_ROUTE_INDEX (vtable, ipx_routes->entries, ipx_routes->entries->len - 1); - ipx_route->rx.ifindex = ifindex; - ipx_route->rx.metric = vtable->vt->metric_normalize (ipx_route->rx.metric); - nm_utils_ipx_address_clear_host_address (vtable->vt->addr_family, ipx_route->rx.network_ptr, - ipx_route->rx.network_ptr, ipx_route->rx.plen); - - g_array_index (ipx_routes->effective_metrics_reverse, gint64, j++) = -1; - - _LOGt (vtable->vt->addr_family, "%3d: STATE: added #%u - %s", ifindex, ipx_routes->entries->len - 1, - vtable->vt->route_to_string (ipx_route, NULL, 0)); - } - g_ptr_array_unref (to_add_routes); - } - g_free (ipx_routes->index); - ipx_routes->index = _route_index_create (vtable, ipx_routes->entries); - ipx_routes_changed = TRUE; - ASSERT_route_index_valid (vtable, ipx_routes->entries, ipx_routes->index, TRUE); - } - - if (ipx_routes_changed) { - /*************************************************************************** - * Rebuild the list of effective metrics. In case of conflicting routes, - * we configure device routes with a bumped metric. We do this, because non-direct - * routes might require this direct route to reach the gateway (e.g. the default - * route). - * - * We determine the effective metrics only based on our internal list @ipx_routes - * and don't consider @plat_routes. That means, we might bump the metric of a route - * and thereby cause a conflict with an existing route on an unmanaged device (which - * causes the route on the unmanaged device to be replaced). - * Still, that is not much different then from messing with unmanaged routes when - * the effective and the intended metrics equal. The rules is: NM will leave routes - * on unmanaged devices alone, unless they conflict with what NM wants to configure. - ***************************************************************************/ - - g_array_set_size (ipx_routes->effective_metrics, ipx_routes->entries->len); - effective_metrics = &g_array_index (ipx_routes->effective_metrics, gint64, 0); - - /* Completely regenerate the list of effective metrics by walking through - * ipx_routes->index and determining the effective metric. */ - - for (i_ipx_routes = 0; i_ipx_routes < ipx_routes->index->len; i_ipx_routes++) { - gint64 *p_effective_metric_before; - gboolean is_shadowed; - guint i_ipx_routes_before; - - cur_ipx_route = ipx_routes->index->entries[i_ipx_routes]; - p_effective_metric = &effective_metrics[i_ipx_routes]; - - is_shadowed = i_ipx_routes > 0 - && vtable->route_dest_cmp (cur_ipx_route, ipx_routes->index->entries[i_ipx_routes - 1]) == 0; - - if (!is_shadowed) { - /* the route is not shadowed, the effective metric is just as specified. */ - *p_effective_metric = cur_ipx_route->rx.metric; - goto next; - } - if (!VTABLE_IS_DEVICE_ROUTE (vtable, cur_ipx_route)) { - /* The route is not a device route. We want to add redundant device routes, because - * we might need the direct routes to the gateway. For non-direct routes, there is not much - * reason to do the metric increment. */ - *p_effective_metric = -1; - goto next; - } - - /* The current route might be shadowed by several other routes. Find the one with the highest metric, - * i.e. the one with an effecive metric set and in the index before the current index. */ - i_ipx_routes_before = i_ipx_routes; - while (TRUE) { - nm_assert (i_ipx_routes_before > 0); - - i_ipx_routes_before--; - - p_effective_metric_before = &effective_metrics[i_ipx_routes_before]; - - if (*p_effective_metric_before == -1) { - /* this route is also shadowed, continue search. */ - continue; - } - - if (*p_effective_metric_before < cur_ipx_route->rx.metric) { - /* the previous route has a lower metric. There is no conflict, - * just use the original metric. */ - *p_effective_metric = cur_ipx_route->rx.metric; - } else if (*p_effective_metric_before == G_MAXUINT32) { - /* we cannot bump the metric. Don't configure this route. */ - *p_effective_metric = -1; - } else { - /* bump the metric by one. */ - *p_effective_metric = *p_effective_metric_before + 1; - } - break; - } -next: - _LOGt (vtable->vt->addr_family, "%3d: new metric #%u - %s (%lld)", - ifindex, i_ipx_routes, - vtable->vt->route_to_string (cur_ipx_route, NULL, 0), - (long long) *p_effective_metric); - } - } - - if (full_sync) { - /*************************************************************************** - * Delete all routes in platform, that no longer exist in @ipx_routes - * - * Different from the delete action above, we delete every unknown route on - * the interface. - ***************************************************************************/ - - /* iterate over @plat_routes and @ipx_routes */ - cur_plat_route = _get_next_plat_route (plat_routes_idx, TRUE, &i_plat_routes); - cur_ipx_route = _get_next_ipx_route (ipx_routes->index, TRUE, &i_ipx_routes, ifindex); - if (cur_ipx_route) - p_effective_metric = &effective_metrics[i_ipx_routes]; - while (cur_plat_route) { - int route_dest_cmp_result = 0; - - g_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)); - - /* skip over @cur_ipx_route that are ordered before @cur_plat_route */ - while ( cur_ipx_route - && ((route_dest_cmp_result = vtable->route_dest_cmp (cur_ipx_route, cur_plat_route)) <= 0)) { - if ( route_dest_cmp_result == 0 - && *p_effective_metric != -1 - && *p_effective_metric >= cur_plat_route->rx.metric) { - break; - } - cur_ipx_route = _get_next_ipx_route (ipx_routes->index, FALSE, &i_ipx_routes, ifindex); - if (cur_ipx_route) - p_effective_metric = &effective_metrics[i_ipx_routes]; - } - - /* 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); - - cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes); - } - } - - /*************************************************************************** - * Restore shadowed routes. These routes are on an other @ifindex then what - * we are syncing now. But the current changes make it necessary to add those - * routes. - * - * Only add some routes that might be necessary. We don't delete any routes - * on other ifindexes here. I.e. we don't do a full sync, but only ~add~ routes - * that were shadowed previously, but should be now present with a different - * metric. - **************************************************************************/ - - if (ipx_routes_changed) { - GArray *gateway_routes = NULL; - - /* @effective_metrics_reverse contains the list of assigned metrics from the last - * sync. Walk through it and see what changes there are (and possibly restore a - * shadowed route). - * Thereby also update @effective_metrics_reverse to be up-to-date again. */ - for (i_ipx_routes = 0; i_ipx_routes < ipx_routes->entries->len; i_ipx_routes++) { - guint i_ipx_routes_reverse; - gint64 *p_effective_metric_reversed; - - p_effective_metric = &effective_metrics[i_ipx_routes]; - - i_ipx_routes_reverse = _route_index_reverse_idx (vtable, ipx_routes->index, i_ipx_routes, ipx_routes->entries); - p_effective_metric_reversed = &g_array_index (ipx_routes->effective_metrics_reverse, gint64, i_ipx_routes_reverse); - - if (*p_effective_metric_reversed == *p_effective_metric) { - /* The entry is up to date. No change, continue with the next one. */ - continue; - } - *p_effective_metric_reversed = *p_effective_metric; - - if (*p_effective_metric == -1) { - /* the entry is shadowed. Nothing to do. */ - continue; - } - - cur_ipx_route = ipx_routes->index->entries[i_ipx_routes]; - if (cur_ipx_route->rx.ifindex == ifindex) { - /* @cur_ipx_route is on the current @ifindex. No need to special handling them - * because we are about to do a full sync of the ifindex. */ - continue; - } - - /* the effective metric from previous sync changed. While @cur_ipx_route is not on the - * ifindex we are about to sync, we still must add this route. Possibly it was shadowed - * before, and now we want to restore it. - * - * Note that we don't do a full sync on the other ifindex. Especially, we don't delete - * or add any further routes then this. That means there might be some stale routes - * (with a higher metric!). They will only be removed on the next sync of that other - * ifindex. */ - - if (!VTABLE_IS_DEVICE_ROUTE (vtable, cur_ipx_route)) { - /* the route to restore has a gateway. We can only restore the route - * when we also have a direct route to the gateway. There can be cases - * where the direct route is shadowed too, and we cannot restore the gateway - * route. - * - * Restore first the direct-routes, and gateway-routes afterwards. - * This can avoid some cases where we would fail to add the - * gateway route. */ - if (!gateway_routes) - gateway_routes = g_array_new (FALSE, FALSE, sizeof (guint)); - g_array_append_val (gateway_routes, i_ipx_routes); - } else - vtable->vt->route_add (priv->platform, 0, cur_ipx_route, *p_effective_metric); - } - - if (gateway_routes) { - for (i = 0; i < gateway_routes->len; i++) { - i_ipx_routes = g_array_index (gateway_routes, guint, i); - vtable->vt->route_add (priv->platform, 0, - ipx_routes->index->entries[i_ipx_routes], - effective_metrics[i_ipx_routes]); - } - g_array_unref (gateway_routes); - } - } - - /*************************************************************************** - * Sync @ipx_routes for @ifindex to platform - **************************************************************************/ - - for (i_type = 0; i_type < 2; i_type++) { - /* iterate (twice) over @ipx_routes and @plat_routes */ - cur_plat_route = _get_next_plat_route (plat_routes_idx, TRUE, &i_plat_routes); - cur_ipx_route = _get_next_ipx_route (ipx_routes->index, TRUE, &i_ipx_routes, ifindex); - /* Iterate here over @ipx_routes instead of @known_routes. That is done because - * we need to know whether a route is shadowed by another route, and that - * requires to look at @ipx_routes. */ - for (; cur_ipx_route; cur_ipx_route = _get_next_ipx_route (ipx_routes->index, FALSE, &i_ipx_routes, ifindex)) { - int route_dest_cmp_result = -1; - - if ( (i_type == 0 && !VTABLE_IS_DEVICE_ROUTE (vtable, cur_ipx_route)) - || (i_type == 1 && VTABLE_IS_DEVICE_ROUTE (vtable, cur_ipx_route))) { - /* Make two runs over the list of @ipx_routes. On the first, only add - * device routes, on the second the others (gateway routes). */ - continue; - } - - p_effective_metric = &effective_metrics[i_ipx_routes]; - - if (*p_effective_metric == -1) { - /* @cur_ipx_route is shadewed by another route. */ - continue; - } - - /* skip over @plat_routes that are ordered before our @cur_ipx_route. */ - while ( cur_plat_route - && (route_dest_cmp_result = vtable->route_dest_cmp (cur_plat_route, cur_ipx_route)) <= 0) { - if ( route_dest_cmp_result == 0 - && cur_plat_route->rx.metric >= *p_effective_metric) - break; - cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes); - } - - /* only add the route if we don't have an identical route in @plat_routes, - * i.e. if @cur_plat_route is different from @cur_ipx_route. */ - if ( !cur_plat_route - || route_dest_cmp_result != 0 - || !_route_equals_ignoring_ifindex (vtable, cur_plat_route, cur_ipx_route, *p_effective_metric)) { - - if (!vtable->vt->route_add (priv->platform, ifindex, cur_ipx_route, *p_effective_metric)) { - if (cur_ipx_route->rx.rt_source < NM_IP_CONFIG_SOURCE_USER) { - _LOGD (vtable->vt->addr_family, - "ignore error adding IPv%c route to kernel: %s", - vtable->vt->is_ip4 ? '4' : '6', - vtable->vt->route_to_string (cur_ipx_route, NULL, 0)); - } else { - /* Remember that there was a failure, but for now continue trying - * to sync the remaining routes. */ - success = FALSE; - } - } - } - } - } - - if (vtable->vt->is_ip4 && ipx_routes_changed) - g_signal_emit (self, signals[IP4_ROUTES_CHANGED], 0); - - g_free (known_routes_idx); - g_free (plat_routes_idx); - g_array_unref (plat_routes); - - return success; -} - -/** - * nm_route_manager_ip4_route_sync: - * @ifindex: Interface index - * @known_routes: List of routes - * @ignore_kernel_routes: if %TRUE, ignore kernel routes. - * @full_sync: whether to do a full sync and delete routes - * that are configured on the interface but not currently - * tracked by route-manager. - * - * A convenience function to synchronize routes for a specific interface - * with the least possible disturbance. It simply removes routes that are - * not listed and adds routes that are. - * Default routes are ignored (both in @known_routes and those already - * configured on the device). - * - * Returns: %TRUE on success. - */ -gboolean -nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync) -{ - return _vx_route_sync (&vtable_v4, self, ifindex, known_routes, ignore_kernel_routes, full_sync); -} - -/** - * nm_route_manager_ip6_route_sync: - * @ifindex: Interface index - * @known_routes: List of routes - * @ignore_kernel_routes: if %TRUE, ignore kernel routes. - * @full_sync: whether to do a full sync and delete routes - * that are configured on the interface but not currently - * tracked by route-manager. - * - * A convenience function to synchronize routes for a specific interface - * with the least possible disturbance. It simply removes routes that are - * not listed and adds routes that are. - * Default routes are ignored (both in @known_routes and those already - * configured on the device). - * - * Returns: %TRUE on success. - */ -gboolean -nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync) -{ - return _vx_route_sync (&vtable_v6, self, ifindex, known_routes, ignore_kernel_routes, full_sync); -} - -gboolean -nm_route_manager_route_flush (NMRouteManager *self, int ifindex) -{ - bool success = TRUE; - - success &= (bool) nm_route_manager_ip4_route_sync (self, ifindex, NULL, FALSE, TRUE); - success &= (bool) nm_route_manager_ip6_route_sync (self, ifindex, NULL, FALSE, TRUE); - return success; -} - -/** - * nm_route_manager_ip4_routes_shadowed: - * @ifindex: Interface index - * - * Returns: %TRUE if some other link has a route to the same destination - * with a lower metric. - */ -gboolean -nm_route_manager_ip4_routes_shadowed (NMRouteManager *self, int ifindex) -{ - NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - RouteIndex *index = priv->ip4_routes.index; - const NMPlatformIP4Route *route; - guint i; - - for (i = 1; i < index->len; i++) { - route = (const NMPlatformIP4Route *) index->entries[i]; - - if (route->ifindex != ifindex) - continue; - if (_v4_route_dest_cmp (route, (const NMPlatformIP4Route *) index->entries[i - 1]) == 0) - return TRUE; - } - - return FALSE; -} - -/*****************************************************************************/ - -static gboolean -_ip4_device_routes_entry_expired (const IP4DeviceRoutePurgeEntry *entry, gint64 now) -{ - return entry->scheduled_at_ns + IP4_DEVICE_ROUTES_WAIT_TIME_NS < now; -} - -static IP4DeviceRoutePurgeEntry * -_ip4_device_routes_purge_entry_create (NMRouteManager *self, const NMPlatformIP4Route *route, gint64 now_ns) -{ - IP4DeviceRoutePurgeEntry *entry; - - entry = g_slice_new (IP4DeviceRoutePurgeEntry); - - entry->self = self; - entry->scheduled_at_ns = now_ns; - entry->idle_id = 0; - entry->obj = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, (NMPlatformObject *) route); - return entry; -} - -static void -_ip4_device_routes_purge_entry_free (IP4DeviceRoutePurgeEntry *entry) -{ - nmp_object_unref (entry->obj); - nm_clear_g_source (&entry->idle_id); - g_slice_free (IP4DeviceRoutePurgeEntry, entry); -} - -static gboolean -_ip4_device_routes_idle_cb (IP4DeviceRoutePurgeEntry *entry) -{ - NMRouteManager *self; - NMRouteManagerPrivate *priv; - - nm_clear_g_source (&entry->idle_id); - - self = entry->self; - priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - if (_route_index_find (&vtable_v4, priv->ip4_routes.index, &entry->obj->ipx_route) >= 0) { - /* we have an identical route in our list. Don't delete it. */ - 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)); - - 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); - - g_hash_table_remove (priv->ip4_device_routes.entries, entry->obj); - _ip4_device_routes_cancel (self); - return G_SOURCE_REMOVE; -} - -static void -_ip4_device_routes_ip4_route_changed (NMPlatform *platform, - int obj_type_i, - int ifindex, - const NMPlatformIP4Route *route, - int change_type_i, - NMRouteManager *self) -{ - const NMPlatformSignalChangeType change_type = change_type_i; - NMRouteManagerPrivate *priv; - NMPObject obj_needle; - 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. */ - return; - } - - 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)); - if (!entry) - return; - - if (_ip4_device_routes_entry_expired (entry, nm_utils_get_monotonic_timestamp_ns ())) { - _LOGt (vtable_v4.vt->addr_family, "device-route: cleanup-ch %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - g_hash_table_remove (priv->ip4_device_routes.entries, entry->obj); - _ip4_device_routes_cancel (self); - return; - } - - 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); - } -} - -static gboolean -_ip4_device_routes_cancel (NMRouteManager *self) -{ - NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - - if (priv->ip4_device_routes.gc_id) { - if (g_hash_table_size (priv->ip4_device_routes.entries) > 0) - return G_SOURCE_CONTINUE; - _LOGt (vtable_v4.vt->addr_family, "device-route: cancel"); - if (priv->platform) - g_signal_handlers_disconnect_by_func (priv->platform, G_CALLBACK (_ip4_device_routes_ip4_route_changed), self); - nm_clear_g_source (&priv->ip4_device_routes.gc_id); - } - return G_SOURCE_REMOVE; -} - -static gboolean -_ip4_device_routes_gc (NMRouteManager *self) -{ - NMRouteManagerPrivate *priv; - GHashTableIter iter; - IP4DeviceRoutePurgeEntry *entry; - gint64 now = nm_utils_get_monotonic_timestamp_ns (); - - priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - - g_hash_table_iter_init (&iter, priv->ip4_device_routes.entries); - while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &entry)) { - if (_ip4_device_routes_entry_expired (entry, now)) { - _LOGt (vtable_v4.vt->addr_family, "device-route: cleanup-gc %s", nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - g_hash_table_iter_remove (&iter); - } - } - - return _ip4_device_routes_cancel (self); -} - -/** - * nm_route_manager_ip4_route_register_device_route_purge_list: - * - * When adding an IPv4 address, kernel will automatically add a device route with - * metric zero. We don't want that route and want to delete it. However, the route - * by kernel immediately, but some time after. That means during nm_route_manager_ip4_route_sync() - * such a route doesn't exist yet. We must remember that we expect such a route to appear later - * and to remove it. */ -void -nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *self, GArray *device_route_purge_list) -{ - NMRouteManagerPrivate *priv; - guint i; - gint64 now_ns; - - if (!device_route_purge_list || device_route_purge_list->len == 0) - return; - - priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - - now_ns = nm_utils_get_monotonic_timestamp_ns (); - for (i = 0; i < device_route_purge_list->len; i++) { - IP4DeviceRoutePurgeEntry *entry; - - entry = _ip4_device_routes_purge_entry_create (self, &g_array_index (device_route_purge_list, NMPlatformIP4Route, i), now_ns); - _LOGt (vtable_v4.vt->addr_family, "device-route: watch (%s) %s", - g_hash_table_contains (priv->ip4_device_routes.entries, entry->obj) - ? "update" : "new", - nmp_object_to_string (entry->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); - g_hash_table_replace (priv->ip4_device_routes.entries, - nmp_object_ref (entry->obj), - entry); - } - 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); - } -} - -/*****************************************************************************/ - -static const VTableIP vtable_v4 = { - .vt = &nm_platform_vtable_route_v4, - .route_dest_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v4_route_dest_cmp, - .route_id_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v4_route_id_cmp, -}; - -static const VTableIP vtable_v6 = { - .vt = &nm_platform_vtable_route_v6, - .route_dest_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v6_route_dest_cmp, - .route_id_cmp = (int (*) (const NMPlatformIPXRoute *, const NMPlatformIPXRoute *)) _v6_route_id_cmp, -}; - -/*****************************************************************************/ - -static void -set_property (GObject *object, guint prop_id, - const GValue *value, GParamSpec *pspec) -{ - NMRouteManager *self = NM_ROUTE_MANAGER (object); - NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - - switch (prop_id) { - case PROP_LOG_WITH_PTR: - /* construct-only */ - priv->log_with_ptr = g_value_get_boolean (value); - break; - case PROP_PLATFORM: - /* construct-only */ - priv->platform = g_value_get_object (value) ? : NM_PLATFORM_GET; - if (!priv->platform) - g_return_if_reached (); - g_object_ref (priv->platform); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_route_manager_init (NMRouteManager *self) -{ - NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - - priv->ip4_routes.entries = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route)); - priv->ip6_routes.entries = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route)); - priv->ip4_routes.effective_metrics = g_array_new (FALSE, FALSE, sizeof (gint64)); - priv->ip6_routes.effective_metrics = g_array_new (FALSE, FALSE, sizeof (gint64)); - priv->ip4_routes.effective_metrics_reverse = g_array_new (FALSE, FALSE, sizeof (gint64)); - priv->ip6_routes.effective_metrics_reverse = g_array_new (FALSE, FALSE, sizeof (gint64)); - priv->ip4_routes.index = _route_index_create (&vtable_v4, priv->ip4_routes.entries); - priv->ip6_routes.index = _route_index_create (&vtable_v6, priv->ip6_routes.entries); - priv->ip4_device_routes.entries = g_hash_table_new_full ((GHashFunc) nmp_object_id_hash, - (GEqualFunc) nmp_object_id_equal, - (GDestroyNotify) nmp_object_unref, - (GDestroyNotify) _ip4_device_routes_purge_entry_free); -} - -NMRouteManager * -nm_route_manager_new (gboolean log_with_ptr, NMPlatform *platform) -{ - return g_object_new (NM_TYPE_ROUTE_MANAGER, - NM_ROUTE_MANAGER_LOG_WITH_PTR, log_with_ptr, - NM_ROUTE_MANAGER_PLATFORM, platform, - NULL); -} - -static void -dispose (GObject *object) -{ - NMRouteManager *self = NM_ROUTE_MANAGER (object); - NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self); - - g_hash_table_remove_all (priv->ip4_device_routes.entries); - _ip4_device_routes_cancel (self); - - G_OBJECT_CLASS (nm_route_manager_parent_class)->dispose (object); -} - -static void -finalize (GObject *object) -{ - NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE ((NMRouteManager *) object); - - g_array_free (priv->ip4_routes.entries, TRUE); - g_array_free (priv->ip6_routes.entries, TRUE); - g_array_free (priv->ip4_routes.effective_metrics, TRUE); - g_array_free (priv->ip6_routes.effective_metrics, TRUE); - g_array_free (priv->ip4_routes.effective_metrics_reverse, TRUE); - g_array_free (priv->ip6_routes.effective_metrics_reverse, TRUE); - g_free (priv->ip4_routes.index); - g_free (priv->ip6_routes.index); - - g_hash_table_unref (priv->ip4_device_routes.entries); - - g_clear_object (&priv->platform); - - G_OBJECT_CLASS (nm_route_manager_parent_class)->finalize (object); -} - -static void -nm_route_manager_class_init (NMRouteManagerClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = set_property; - object_class->dispose = dispose; - object_class->finalize = finalize; - - obj_properties[PROP_LOG_WITH_PTR] = - g_param_spec_boolean (NM_ROUTE_MANAGER_LOG_WITH_PTR, "", "", - TRUE, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_PLATFORM] = - g_param_spec_object (NM_ROUTE_MANAGER_PLATFORM, "", "", - NM_TYPE_PLATFORM, - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_STRINGS); - g_object_class_install_properties (object_class, _PROPERTY_ENUMS_LAST, obj_properties); - - signals[IP4_ROUTES_CHANGED] = - g_signal_new (NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - 0, NULL, NULL, NULL, - G_TYPE_NONE, 0); -} |