core: avoid cloning platform routes but iterate the cache directly

This commit is contained in:
Thomas Haller 2017-06-29 15:19:35 +02:00
parent c9cd6d9954
commit 667c50f5d9
12 changed files with 387 additions and 155 deletions

View file

@ -42,6 +42,7 @@
#include "NetworkManagerUtils.h"
#include "nm-manager.h"
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
#include "ndisc/nm-ndisc.h"
#include "ndisc/nm-lndp-ndisc.h"
#include "dhcp/nm-dhcp-manager.h"
@ -5405,45 +5406,46 @@ ipv4ll_start (NMDevice *self)
static gboolean
_device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlatformIPRoute *out_route)
{
gboolean success = FALSE;
int ifindex = nm_device_get_ip_ifindex (self);
GArray *routes;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
const NMPlatformIPRoute *route = NULL;
guint32 route_metric = G_MAXUINT32;
if (addr_family == AF_INET)
routes = nm_platform_ip4_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
else
routes = nm_platform_ip6_route_get_all (nm_device_get_platform (self), ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
pl_head_entry = nm_platform_lookup_route_visible (nm_device_get_platform (self),
addr_family == AF_INET
? NMP_OBJECT_TYPE_IP4_ROUTE
: NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex,
TRUE,
FALSE);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
guint32 m;
const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj);
if (routes) {
guint route_metric = G_MAXUINT32, m;
const NMPlatformIPRoute *route = NULL, *r;
guint i;
if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
/* if there are several default routes, find the one with the best metric */
for (i = 0; i < routes->len; i++) {
if (addr_family == AF_INET) {
r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP4Route, i);
m = r->metric;
} else {
r = (const NMPlatformIPRoute *) &g_array_index (routes, NMPlatformIP6Route, i);
m = nm_utils_ip6_route_metric_normalize (r->metric);
}
if (!route || m < route_metric) {
route = r;
route_metric = m;
}
}
m = r->metric;
if (addr_family != AF_INET)
m = nm_utils_ip6_route_metric_normalize (r->metric);
if (route) {
if (addr_family == AF_INET)
*((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route);
else
*((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route);
success = TRUE;
if (!route || m < route_metric) {
route = NMP_OBJECT_CAST_IP_ROUTE (plobj);
route_metric = m;
}
g_array_free (routes, TRUE);
}
return success;
if (route) {
if (addr_family == AF_INET)
*((NMPlatformIP4Route *) out_route) = *((NMPlatformIP4Route *) route);
else
*((NMPlatformIP6Route *) out_route) = *((NMPlatformIP6Route *) route);
return TRUE;
}
return FALSE;
}
/*****************************************************************************/

View file

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

View file

@ -386,11 +386,12 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
{
NMIP4Config *config;
NMIP4ConfigPrivate *priv;
guint i;
guint32 lowest_metric = G_MAXUINT32;
guint32 lowest_metric;
guint32 old_gateway = 0;
gboolean old_has_gateway = FALSE;
gs_unref_array GArray *routes = NULL;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
/* Slaves have no IP configuration */
if (nm_platform_link_get_master (platform, ifindex) > 0)
@ -404,50 +405,56 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
priv->addresses = nm_platform_ip4_address_get_all (platform, ifindex);
g_array_sort (priv->addresses, sort_captured_addresses);
routes = nm_platform_ip4_route_get_all (platform, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
pl_head_entry = nm_platform_lookup_route_visible (platform,
NMP_OBJECT_TYPE_IP4_ROUTE,
ifindex,
TRUE,
TRUE);
/* Extract gateway from default route */
old_gateway = priv->gateway;
old_has_gateway = priv->has_gateway;
for (i = 0; i < routes->len; ) {
const NMPlatformIP4Route *route = &g_array_index (routes, NMPlatformIP4Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
lowest_metric = G_MAXUINT32;
priv->has_gateway = FALSE;
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj);
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)
&& route->rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL) {
if (route->metric < lowest_metric) {
priv->gateway = route->gateway;
lowest_metric = route->metric;
}
priv->has_gateway = TRUE;
/* Remove the default route from the list */
g_array_remove_index_fast (routes, i);
continue;
}
i++;
}
/* we detect the route metric based on the default route. All non-default
* routes have their route metrics explicitly set. */
priv->route_metric = priv->has_gateway ? (gint64) lowest_metric : (gint64) -1;
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
if (priv->has_gateway) {
for (i = 0; i < routes->len; i++) {
const NMPlatformIP4Route *route = &g_array_index (routes, NMPlatformIP4Route, i);
nm_dedup_multi_iter_rewind (&iter);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP4Route *route = NMP_OBJECT_CAST_IP4_ROUTE (plobj);
if ( (route->plen == 32)
&& (route->network == priv->gateway)
&& (route->gateway == 0)) {
g_array_remove_index (routes, i);
i--;
}
if (route->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
if ( priv->has_gateway
&& route->plen == 32
&& route->network == priv->gateway
&& route->gateway == 0) {
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
continue;
}
_add_route (config, plobj, NULL);
}
for (i = 0; i < routes->len; i++)
_add_route (config, NULL, &g_array_index (routes, NMPlatformIP4Route, i));
/* If the interface has the default route, and has IPv4 addresses, capture
* nameservers from /etc/resolv.conf.
*/

View file

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

View file

@ -226,6 +226,25 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP
}
}
#ifdef __NMP_OBJECT_H__
static inline void
nmtst_platform_ip4_routes_equal_aptr (const NMPObject *const*a, const NMPlatformIP4Route *b, gsize len, gboolean ignore_order)
{
gsize i;
gs_free NMPlatformIP4Route *c_a = NULL;
g_assert (len > 0);
g_assert (a);
c_a = g_new (NMPlatformIP4Route, len);
for (i = 0; i < len; i++)
c_a[i] = *NMP_OBJECT_CAST_IP4_ROUTE (a[i]);
nmtst_platform_ip4_routes_equal (c_a, b, len, ignore_order);
}
#endif
static inline int
_nmtst_platform_ip6_routes_equal_sort (gconstpointer a, gconstpointer b, gpointer user_data)
{
@ -260,6 +279,25 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP
}
}
#ifdef __NMP_OBJECT_H__
static inline void
nmtst_platform_ip6_routes_equal_aptr (const NMPObject *const*a, const NMPlatformIP6Route *b, gsize len, gboolean ignore_order)
{
gsize i;
gs_free NMPlatformIP6Route *c_a = NULL;
g_assert (len > 0);
g_assert (a);
c_a = g_new (NMPlatformIP6Route, len);
for (i = 0; i < len; i++)
c_a[i] = *NMP_OBJECT_CAST_IP6_ROUTE (a[i]);
nmtst_platform_ip6_routes_equal (c_a, b, len, ignore_order);
}
#endif
#endif

View file

@ -2659,6 +2659,64 @@ nm_platform_lookup (NMPlatform *platform,
lookup);
}
gboolean
nm_platform_lookup_predicate_routes_skip_rtprot_kernel (const NMPObject *obj,
gpointer user_data)
{
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE));
return obj->ip_route.rt_source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
}
/**
* nm_platform_lookup_clone:
* @platform:
* @lookup:
* @predicate: if given, only objects for which @predicate returns %TRUE are included
* in the result.
* @user_data: user data for @predicate
*
* Returns the result of lookup in a GPtrArray. The result array contains
* references objects from the cache, it's destroy function will unref them.
*
* The user must unref the GPtrArray, which will also unref the NMPObject
* elements.
*
* The elements in the array *must* not be modified.
*
* Returns: the result of the lookup.
*/
GPtrArray *
nm_platform_lookup_clone (NMPlatform *platform,
const NMPLookup *lookup,
gboolean (*predicate) (const NMPObject *obj, gpointer user_data),
gpointer user_data)
{
const NMDedupMultiHeadEntry *head_entry;
GPtrArray *result;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
head_entry = nm_platform_lookup (platform, lookup);
if (!head_entry)
return NULL;
result = g_ptr_array_new_full (head_entry->len,
(GDestroyNotify) nmp_object_unref);
nmp_cache_iter_for_each (&iter, head_entry, &plobj) {
if ( predicate
&& !predicate (plobj, user_data))
continue;
g_ptr_array_add (result, (gpointer) nmp_object_ref (plobj));
}
if (result->len == 0) {
g_ptr_array_unref (result);
return NULL;
}
return result;
}
void
nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, guint8 plen)
{
@ -3200,16 +3258,6 @@ ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NM
return array;
}
GArray *
nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags)
{
_CHECK_SELF (self, klass, NULL);
g_return_val_if_fail (ifindex >= 0, NULL);
return ipx_route_get_all (self, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags);
}
GArray *
nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags)
{
@ -5026,11 +5074,11 @@ _vtr_v6_route_delete_default (NMPlatform *self, int ifindex, guint32 metric)
const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
.is_ip4 = TRUE,
.obj_type = NMP_OBJECT_TYPE_IP4_ROUTE,
.addr_family = AF_INET,
.sizeof_route = sizeof (NMPlatformIP4Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip4_route_cmp_full,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
.route_get_all = nm_platform_ip4_route_get_all,
.route_add = _vtr_v4_route_add,
.route_delete = _vtr_v4_route_delete,
.route_delete_default = _vtr_v4_route_delete_default,
@ -5039,11 +5087,11 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
.is_ip4 = FALSE,
.obj_type = NMP_OBJECT_TYPE_IP6_ROUTE,
.addr_family = AF_INET6,
.sizeof_route = sizeof (NMPlatformIP6Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part)) nm_platform_ip6_route_cmp_full,
.route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string,
.route_get_all = nm_platform_ip6_route_get_all,
.route_add = _vtr_v6_route_add,
.route_delete = _vtr_v6_route_delete,
.route_delete_default = _vtr_v6_route_delete_default,

View file

@ -373,11 +373,11 @@ typedef union {
typedef struct {
gboolean is_ip4;
NMPObjectType obj_type;
int addr_family;
gsize sizeof_route;
int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, gboolean consider_host_part);
const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len);
GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric);
gboolean (*route_delete) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route);
gboolean (*route_delete_default) (NMPlatform *self, int ifindex, guint32 metric);
@ -778,6 +778,14 @@ struct _NMPLookup;
const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *platform,
const struct _NMPLookup *lookup);
gboolean nm_platform_lookup_predicate_routes_skip_rtprot_kernel (const NMPObject *obj,
gpointer user_data);
GPtrArray *nm_platform_lookup_clone (NMPlatform *platform,
const struct _NMPLookup *lookup,
gboolean (*predicate) (const NMPObject *obj, gpointer user_data),
gpointer user_data);
/* convienience methods to lookup the link and access fields of NMPlatformLink. */
int nm_platform_link_get_ifindex (NMPlatform *self, const char *name);
const char *nm_platform_link_get_name (NMPlatform *self, int ifindex);
@ -972,7 +980,6 @@ gboolean nm_platform_address_flush (NMPlatform *self, int ifindex);
const NMPlatformIP4Route *nm_platform_ip4_route_get (NMPlatform *self, int ifindex, in_addr_t network, guint8 plen, guint32 metric);
const NMPlatformIP6Route *nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr network, guint8 plen, guint32 metric);
GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
gboolean nm_platform_ip4_route_add (NMPlatform *self, const NMPlatformIP4Route *route);
gboolean nm_platform_ip6_route_add (NMPlatform *self, const NMPlatformIP6Route *route);

View file

@ -339,6 +339,24 @@ NMP_OBJECT_GET_TYPE (const NMPObject *obj)
return obj ? obj->_class->obj_type : NMP_OBJECT_TYPE_UNKNOWN;
}
#define NMP_OBJECT_CAST_IPX_ROUTE(obj) \
({ \
typeof (*(obj)) *_obj = (obj); \
_nm_unused const NMPObject *_obj_type_check = _obj; \
\
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \
&_obj->ipx_route; \
})
#define NMP_OBJECT_CAST_IP_ROUTE(obj) \
({ \
typeof (*(obj)) *_obj = (obj); \
_nm_unused const NMPObject *_obj_type_check = _obj; \
\
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (_obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)); \
&_obj->ip_route; \
})
#define NMP_OBJECT_CAST_IP4_ROUTE(obj) \
({ \
typeof (*(obj)) *_obj = (obj); \
@ -623,6 +641,21 @@ nm_platform_lookup_route_visible (NMPlatform *platform,
return nm_platform_lookup (platform, &lookup);
}
static inline GPtrArray *
nm_platform_lookup_route_visible_clone (NMPlatform *platform,
NMPObjectType obj_type,
int ifindex,
gboolean with_default,
gboolean with_non_default,
gboolean (*predicate) (const NMPObject *obj, gpointer user_data),
gpointer user_data)
{
NMPLookup lookup;
nmp_lookup_init_route_visible (&lookup, obj_type, ifindex, with_default, with_non_default);
return nm_platform_lookup_clone (platform, &lookup, predicate, user_data);
}
static inline const NMDedupMultiHeadEntry *
nm_platform_lookup_route_by_dest (NMPlatform *platform,
int addr_family,

View file

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

View file

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

View file

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

View file

@ -145,15 +145,38 @@ update_dev0_ip4 (int ifindex)
static GArray *
ip4_routes (test_fixture *fixture)
{
GArray *routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET,
fixture->ifindex0,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
GArray *routes1 = nm_platform_ip4_route_get_all (NM_PLATFORM_GET,
fixture->ifindex1,
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
GArray *routes;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
guint i;
g_array_append_vals (routes, routes1->data, routes1->len);
g_array_free (routes1, TRUE);
routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
for (i = 0; i < 2; i++) {
int ifindex;
if (i == 0)
ifindex = fixture->ifindex0;
else
ifindex = fixture->ifindex1;
pl_head_entry = nm_platform_lookup_route_visible (NM_PLATFORM_GET,
NMP_OBJECT_TYPE_IP4_ROUTE,
ifindex,
FALSE,
TRUE);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (plobj);
if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
g_assert (!NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r));
g_assert (r->ifindex == ifindex);
g_assert (nmp_object_is_visible (plobj));
g_array_append_vals (routes, r, 1);
}
}
return routes;
}