core: merge branch 'th/device-route-bgo751264'

Several fixes to route and address handling in platform.
Especially refactor managing of IPv4 device routes and
let NMRouteManager handle them.

https://bugzilla.gnome.org/show_bug.cgi?id=751264
https://bugzilla.redhat.com/show_bug.cgi?id=1211287

(cherry picked from commit 1749ad4068)
This commit is contained in:
Thomas Haller 2015-07-01 16:05:41 +02:00
commit b774bde8ed
23 changed files with 762 additions and 328 deletions

View file

@ -112,6 +112,8 @@ GPtrArray *_nm_utils_copy_object_array (const GPtrArray *array);
gssize _nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle);
gssize _nm_utils_ptrarray_find_binary_search (gpointer *list, gsize len, gpointer needle, GCompareDataFunc cmpfcn, gpointer user_data);
gboolean _nm_utils_string_in_list (const char *str,
const char **valid_strings);

View file

@ -657,6 +657,39 @@ _nm_utils_ptrarray_find_first (gpointer *list, gssize len, gconstpointer needle)
return -1;
}
gssize
_nm_utils_ptrarray_find_binary_search (gpointer *list, gsize len, gpointer needle, GCompareDataFunc cmpfcn, gpointer user_data)
{
gssize imin, imax, imid;
int cmp;
g_return_val_if_fail (list || !len, ~((gssize) 0));
g_return_val_if_fail (cmpfcn, ~((gssize) 0));
imin = 0;
if (len == 0)
return ~imin;
imax = len - 1;
while (imin <= imax) {
imid = imin + (imax - imin) / 2;
cmp = cmpfcn (list[imid], needle, user_data);
if (cmp == 0)
return imid;
if (cmp < 0)
imin = imid + 1;
else
imax = imid - 1;
}
/* return the inverse of @imin. This is a negative number, but
* also is ~imin the position where the value should be inserted. */
return ~imin;
}
GVariant *
_nm_utils_bytes_to_dbus (const GValue *prop_value)
{

View file

@ -4297,6 +4297,110 @@ test_g_ptr_array_insert (void)
/******************************************************************************/
static int
_test_find_binary_search_cmp (gconstpointer a, gconstpointer b, gpointer dummy)
{
int ia, ib;
ia = GPOINTER_TO_INT (a);
ib = GPOINTER_TO_INT (b);
if (ia == ib)
return 0;
if (ia < ib)
return -1;
return 1;
}
static void
_test_find_binary_search_do (const int *array, gsize len)
{
gsize i;
gssize idx;
gs_free gpointer *parray = g_new (gpointer, len);
const int needle = 0;
gpointer pneedle = GINT_TO_POINTER (needle);
gssize expected_result;
for (i = 0; i < len; i++)
parray[i] = GINT_TO_POINTER (array[i]);
expected_result = _nm_utils_ptrarray_find_first (parray, len, pneedle);
idx = _nm_utils_ptrarray_find_binary_search (parray, len, pneedle, _test_find_binary_search_cmp, NULL);
if (expected_result >= 0)
g_assert_cmpint (expected_result, ==, idx);
else {
gssize idx2 = ~idx;
g_assert_cmpint (idx, <, 0);
g_assert (idx2 >= 0);
g_assert (idx2 <= len);
g_assert (idx2 - 1 < 0 || _test_find_binary_search_cmp (parray[idx2 - 1], pneedle, NULL) < 0);
g_assert (idx2 >= len || _test_find_binary_search_cmp (parray[idx2], pneedle, NULL) > 0);
}
for (i = 0; i < len; i++) {
int cmp;
cmp = _test_find_binary_search_cmp (parray[i], pneedle, NULL);
if (cmp == 0) {
g_assert (pneedle == parray[i]);
g_assert (idx >= 0);
g_assert (i == idx);
} else {
g_assert (pneedle != parray[i]);
if (cmp < 0) {
if (idx < 0)
g_assert (i < ~idx);
else
g_assert (i < idx);
} else {
if (idx < 0)
g_assert (i >= ~idx);
else
g_assert (i >= idx);
}
}
}
}
#define test_find_binary_search_do(...) \
G_STMT_START { \
const int _array[] = { __VA_ARGS__ } ; \
_test_find_binary_search_do (_array, G_N_ELEMENTS (_array)); \
} G_STMT_END
static void
test_nm_utils_ptrarray_find_binary_search (void)
{
#define _NOT(idx) (~ ((gssize) (idx)))
test_find_binary_search_do ( 0);
test_find_binary_search_do ( -1, 0);
test_find_binary_search_do ( -2, -1, 0);
test_find_binary_search_do (-3, -2, -1, 0);
test_find_binary_search_do ( 0, 1);
test_find_binary_search_do ( 0, 1, 2);
test_find_binary_search_do ( -1, 0, 1, 2);
test_find_binary_search_do ( -2, -1, 0, 1, 2);
test_find_binary_search_do (-3, -2, -1, 0, 1, 2);
test_find_binary_search_do (-3, -2, -1, 0, 1, 2);
test_find_binary_search_do (-3, -2, -1, 0, 1, 2, 3);
test_find_binary_search_do (-3, -2, -1, 0, 1, 2, 3, 4);
test_find_binary_search_do ( -1);
test_find_binary_search_do ( -2, -1);
test_find_binary_search_do (-3, -2, -1);
test_find_binary_search_do ( 1);
test_find_binary_search_do ( 1, 2);
test_find_binary_search_do ( -1, 1, 2);
test_find_binary_search_do ( -2, -1, 1, 2);
test_find_binary_search_do (-3, -2, -1, 1, 2);
test_find_binary_search_do (-3, -2, -1, 1, 2);
test_find_binary_search_do (-3, -2, -1, 1, 2, 3);
test_find_binary_search_do (-3, -2, -1, 1, 2, 3, 4);
}
/******************************************************************************/
NMTST_DEFINE ();
int main (int argc, char **argv)
@ -4398,6 +4502,7 @@ int main (int argc, char **argv)
g_test_add_func ("/core/general/_nm_utils_ascii_str_to_int64", test_nm_utils_ascii_str_to_int64);
g_test_add_func ("/core/general/nm_utils_is_power_of_two", test_nm_utils_is_power_of_two);
g_test_add_func ("/core/general/_glib_compat_g_ptr_array_insert", test_g_ptr_array_insert);
g_test_add_func ("/core/general/_nm_utils_ptrarray_find_binary_search", test_nm_utils_ptrarray_find_binary_search);
return g_test_run ();
}

View file

@ -3076,9 +3076,9 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat
GArray *routes;
if (addr_family == AF_INET)
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
else
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
if (routes) {
guint route_metric = G_MAXUINT32, m;
@ -6332,10 +6332,11 @@ nm_device_set_ip4_config (NMDevice *self,
nm_device_set_mtu (self, nm_ip4_config_get_mtu (new_config));
/* for assumed devices we set the device_route_metric to the default which will
* stop nm_platform_ip4_address_sync() to replace the device routes. */
/* For assumed devices we must not touch the kernel-routes, such as the device-route.
* FIXME: this is wrong in case where "assumed" means "take-over-seamlessly". In this
* case, we should manage the device route, for example on new DHCP lease. */
success = nm_ip4_config_commit (new_config, ip_ifindex,
assumed ? NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE : default_route_metric);
assumed ? (gint64) -1 : (gint64) default_route_metric);
if (!success)
reason_local = NM_DEVICE_STATE_REASON_CONFIG_FAILED;
}
@ -7133,6 +7134,11 @@ update_ip4_config (NMDevice *self, gboolean initial)
capture_lease_config (self, priv->ext_ip4_config, &priv->dev_ip4_config, NULL, NULL);
}
/* FIXME: ext_ip4_config does not contain routes with source==RTPROT_KERNEL.
* Hence, we will wrongly remove device-routes with metric=0 if they were added by
* the user on purpose. This should be fixed by also tracking and exposing
* kernel routes. */
/* This function was called upon external changes. Remove the configuration
* (adresses,routes) that is no longer present externally from the interal
* config. This way, we don't readd addresses that were manually removed

View file

@ -292,7 +292,7 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self,
gboolean changed = FALSE;
/* prune all other default routes from this device. */
routes = vtable->vt->route_get_all (NM_PLATFORM_GET, 0, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
routes = vtable->vt->route_get_all (NM_PLATFORM_GET, 0, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
for (i = 0; i < routes->len; i++) {
const NMPlatformIPRoute *route;
@ -478,7 +478,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
entries = vtable->get_entries (priv);
routes = vtable->vt->route_get_all (NM_PLATFORM_GET, 0, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT);
routes = vtable->vt->route_get_all (NM_PLATFORM_GET, 0, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT);
assumed_metrics = _get_assumed_interface_metrics (vtable, self, routes);

View file

@ -34,6 +34,7 @@
#include "NetworkManagerUtils.h"
#include "nm-core-internal.h"
#include "nm-route-manager.h"
#include "gsystem-local-alloc.h"
G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, G_TYPE_OBJECT)
@ -197,11 +198,11 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
g_array_unref (priv->routes);
priv->addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
priv->routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
priv->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);
/* Extract gateway from default route */
old_gateway = priv->gateway;
for (i = 0; i < priv->routes->len; i++) {
for (i = 0; i < priv->routes->len; ) {
const NMPlatformIP4Route *route = &g_array_index (priv->routes, NMPlatformIP4Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
@ -211,9 +212,10 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
}
has_gateway = TRUE;
/* Remove the default route from the list */
g_array_remove_index (priv->routes, i);
i--;
g_array_remove_index_fast (priv->routes, i);
continue;
}
i++;
}
/* If there is a host route to the gateway, ignore that route. It is
@ -252,25 +254,59 @@ nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf)
}
gboolean
nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_route_metric)
nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gint64 default_route_metric)
{
NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
int i;
gs_unref_ptrarray GPtrArray *added_addresses = NULL;
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (config != NULL, FALSE);
/* Addresses */
nm_platform_ip4_address_sync (NM_PLATFORM_GET, ifindex, priv->addresses, default_route_metric);
nm_platform_ip4_address_sync (NM_PLATFORM_GET, ifindex, priv->addresses,
default_route_metric >= 0 ? &added_addresses : NULL);
/* Routes */
{
int count = nm_ip4_config_get_num_routes (config);
GArray *routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), count);
const NMPlatformIP4Route *route;
gboolean success;
gs_unref_array GArray *device_route_purge_list = NULL;
if ( default_route_metric >= 0
&& added_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];
NMPlatformIP4Route route = { 0 };
if (addr->plen == 0)
continue;
route.ifindex = ifindex;
route.source = NM_IP_CONFIG_SOURCE_KERNEL;
route.network = nm_utils_ip4_address_clear_host_address (addr->address, addr->plen);
route.plen = addr->plen;
route.pref_src = addr->address;
route.metric = default_route_metric;
g_array_append_val (routes, route);
if (default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
if (!device_route_purge_list)
device_route_purge_list = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
route.metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE;
g_array_append_val (device_route_purge_list, route);
}
}
}
for (i = 0; i < count; i++) {
const NMPlatformIP4Route *route;
route = nm_ip4_config_get_route (config, i);
/* Don't add the route if it's more specific than one of the subnets
@ -280,10 +316,14 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_ro
&& nm_ip4_config_destination_is_direct (config, route->network, route->plen))
continue;
/* duplicates in @routes are no problem as route-manager handles them
* gracefully (by ignoring them). */
g_array_append_vals (routes, route, 1);
}
success = nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes);
nm_route_manager_ip4_route_register_device_route_purge_list (nm_route_manager_get (), device_route_purge_list);
success = nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, default_route_metric < 0);
g_array_unref (routes);
if (!success)
return FALSE;

View file

@ -64,7 +64,7 @@ const char * nm_ip4_config_get_dbus_path (const NMIP4Config *config);
/* Integration with nm-platform and nm-setting */
NMIP4Config *nm_ip4_config_capture (int ifindex, gboolean capture_resolv_conf);
gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, guint32 default_route_metric);
gboolean nm_ip4_config_commit (const NMIP4Config *config, int ifindex, 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);

View file

@ -309,11 +309,11 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co
g_array_unref (priv->routes);
priv->addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, ifindex);
priv->routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
priv->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);
/* Extract gateway from default route */
old_gateway = priv->gateway;
for (i = 0; i < priv->routes->len; i++) {
for (i = 0; i < priv->routes->len; ) {
const NMPlatformIP6Route *route = &g_array_index (priv->routes, NMPlatformIP6Route, i);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
@ -323,9 +323,10 @@ nm_ip6_config_capture (int ifindex, gboolean capture_resolv_conf, NMSettingIP6Co
}
has_gateway = TRUE;
/* Remove the default route from the list */
g_array_remove_index (priv->routes, i);
i--;
g_array_remove_index_fast (priv->routes, i);
continue;
}
i++;
}
/* If there is a host route to the gateway, ignore that route. It is
@ -397,7 +398,7 @@ nm_ip6_config_commit (const NMIP6Config *config, int ifindex)
g_array_append_vals (routes, route, 1);
}
success = nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes);
success = nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE);
g_array_unref (routes);
}

View file

@ -24,10 +24,18 @@
#include "nm-route-manager.h"
#include "nm-platform.h"
#include "nmp-object.h"
#include "nm-core-internal.h"
#include "nm-logging.h"
#include "gsystem-local-alloc.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];
@ -39,8 +47,21 @@ typedef struct {
} RouteEntries;
typedef struct {
NMRouteManager *self;
gint64 scheduled_at_ns;
guint idle_id;
NMPObject *obj;
} IP4DeviceRoutePurgeEntry;
typedef struct {
NMPlatform *platform;
RouteEntries ip4_routes;
RouteEntries ip6_routes;
struct {
GHashTable *entries;
guint gc_id;
} ip4_device_routes;
} NMRouteManagerPrivate;
#define NM_ROUTE_MANAGER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_ROUTE_MANAGER, NMRouteManagerPrivate))
@ -123,6 +144,10 @@ static const VTableIP vtable_v4, vtable_v6;
/*********************************************************************************************/
static gboolean _ip4_device_routes_cancel (NMRouteManager *self);
/*********************************************************************************************/
#if defined (NM_MORE_ASSERTS) && !defined (G_DISABLE_ASSERT)
inline static void
ASSERT_route_index_valid (const VTableIP *vtable, const GArray *entries, const RouteIndex *index, gboolean unique_ifindexes)
@ -232,6 +257,41 @@ _route_index_create (const VTableIP *vtable, const GArray *routes)
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 ((gpointer *) index->entries, index->len, (gpointer) 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)
{
@ -343,7 +403,7 @@ _sort_indexes_cmp (guint *a, guint *b)
/*********************************************************************************************/
static gboolean
_vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const GArray *known_routes)
_vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes)
{
NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
GArray *plat_routes;
@ -357,8 +417,13 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
const NMPlatformIPXRoute *cur_known_route, *cur_plat_route;
NMPlatformIPXRoute *cur_ipx_route;
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 (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
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);
@ -494,7 +559,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
/* if @cur_ipx_route is not equal to @plat_route, the route must be deleted. */
if (!(cur_ipx_route && route_id_cmp_result == 0))
vtable->vt->route_delete (NM_PLATFORM_GET, ifindex, cur_plat_route);
vtable->vt->route_delete (priv->platform, ifindex, cur_plat_route);
cur_plat_route = _get_next_plat_route (plat_routes_idx, FALSE, &i_plat_routes);
}
@ -515,7 +580,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
* device routes, on the second the others (gateway routes). */
continue;
}
vtable->vt->route_add (NM_PLATFORM_GET, 0, rest_route, 0);
vtable->vt->route_add (priv->platform, 0, rest_route);
}
}
g_array_unref (to_restore_routes);
@ -559,7 +624,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
|| route_id_cmp_result != 0
|| !_route_equals_ignoring_ifindex (vtable, cur_plat_route, cur_ipx_route)) {
if (!vtable->vt->route_add (NM_PLATFORM_GET, ifindex, cur_ipx_route, 0)) {
if (!vtable->vt->route_add (priv->platform, ifindex, cur_ipx_route)) {
if (cur_ipx_route->rx.source < NM_IP_CONFIG_SOURCE_USER) {
_LOGD (vtable->vt->addr_family,
"ignore error adding IPv%c route to kernel: %s",
@ -586,6 +651,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
* nm_route_manager_ip4_route_sync:
* @ifindex: Interface index
* @known_routes: List of routes
* @ignore_kernel_routes: if %TRUE, ignore kernel routes.
*
* A convenience function to synchronize routes for a specific interface
* with the least possible disturbance. It simply removes routes that are
@ -596,15 +662,16 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
* Returns: %TRUE on success.
*/
gboolean
nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes)
nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes)
{
return _vx_route_sync (&vtable_v4, self, ifindex, known_routes);
return _vx_route_sync (&vtable_v4, self, ifindex, known_routes, ignore_kernel_routes);
}
/**
* nm_route_manager_ip6_route_sync:
* @ifindex: Interface index
* @known_routes: List of routes
* @ignore_kernel_routes: if %TRUE, ignore kernel routes.
*
* A convenience function to synchronize routes for a specific interface
* with the least possible disturbance. It simply removes routes that are
@ -615,16 +682,192 @@ nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray
* Returns: %TRUE on success.
*/
gboolean
nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes)
nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes)
{
return _vx_route_sync (&vtable_v6, self, ifindex, known_routes);
return _vx_route_sync (&vtable_v6, self, ifindex, known_routes, ignore_kernel_routes);
}
gboolean
nm_route_manager_route_flush (NMRouteManager *self, int ifindex)
{
return nm_route_manager_ip4_route_sync (self, ifindex, NULL)
&& nm_route_manager_ip6_route_sync (self, ifindex, NULL);
return nm_route_manager_ip4_route_sync (self, ifindex, NULL, FALSE)
&& nm_route_manager_ip6_route_sync (self, ifindex, NULL, 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,
NMPObjectType obj_type,
int ifindex,
const NMPlatformIP4Route *route,
NMPlatformSignalChangeType change_type,
NMPlatformReason reason,
NMRouteManager *self)
{
NMRouteManagerPrivate *priv;
NMPObject obj_needle;
IP4DeviceRoutePurgeEntry *entry;
if (change_type == NM_PLATFORM_SIGNAL_REMOVED)
return;
if ( route->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);
}
}
/*********************************************************************************************/
@ -646,10 +889,30 @@ nm_route_manager_init (NMRouteManager *self)
{
NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (self);
priv->platform = g_object_ref (NM_PLATFORM_GET);
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.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);
}
static void
dispose (GObject *object)
{
NMRouteManager *self = NM_ROUTE_MANAGER (object);
NMRouteManagerPrivate *priv = NM_ROUTE_MANAGER_GET_PRIVATE (object);
g_hash_table_remove_all (priv->ip4_device_routes.entries);
_ip4_device_routes_cancel (self);
g_clear_object (&priv->platform);
G_OBJECT_CLASS (nm_route_manager_parent_class)->dispose (object);
}
static void
@ -662,6 +925,8 @@ finalize (GObject *object)
g_free (priv->ip4_routes.index);
g_free (priv->ip6_routes.index);
g_hash_table_unref (priv->ip4_device_routes.entries);
G_OBJECT_CLASS (nm_route_manager_parent_class)->finalize (object);
}
@ -673,5 +938,6 @@ nm_route_manager_class_init (NMRouteManagerClass *klass)
g_type_class_add_private (klass, sizeof (NMRouteManagerPrivate));
/* virtual methods */
object_class->dispose = dispose;
object_class->finalize = finalize;
}

View file

@ -42,10 +42,12 @@ typedef struct {
GType nm_route_manager_get_type (void);
gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes);
gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes);
gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes);
gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes);
gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex);
void nm_route_manager_ip4_route_register_device_route_purge_list (NMRouteManager *self, GArray *device_route_purge_list);
NMRouteManager *nm_route_manager_get (void);
#endif /* NM_ROUTE_MANAGER_H */

View file

@ -51,8 +51,8 @@ typedef enum {
/* platform internal flag used to mark routes with RTM_F_CLONED. */
_NM_IP_CONFIG_SOURCE_RTM_F_CLONED,
/* platform internal flag used to mark routes with protocol RTPROT_KERNEL. */
_NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
/* routes from platform with protocol RTPROT_KERNEL. */
NM_IP_CONFIG_SOURCE_RTPROT_KERNEL,
NM_IP_CONFIG_SOURCE_KERNEL,
NM_IP_CONFIG_SOURCE_SHARED,

View file

@ -1025,35 +1025,30 @@ ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int
return FALSE;
}
static gboolean
ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric)
{
return FALSE;
}
/******************************************************************/
static GArray *
ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode)
ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
GArray *routes;
NMPlatformIP4Route *route;
guint i;
g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL);
routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP4Route));
if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT;
/* Fill routes */
for (i = 0; i < priv->ip4_routes->len; i++) {
route = &g_array_index (priv->ip4_routes, NMPlatformIP4Route, i);
if (route && (!ifindex || route->ifindex == ifindex)) {
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
if (mode != NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT)
if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT))
g_array_append_val (routes, *route);
} else {
if (mode != NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT)
if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
g_array_append_val (routes, *route);
}
}
@ -1063,26 +1058,27 @@ ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mod
}
static GArray *
ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode)
ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
GArray *routes;
NMPlatformIP6Route *route;
guint i;
g_return_val_if_fail (NM_IN_SET (mode, NM_PLATFORM_GET_ROUTE_MODE_ALL, NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT, NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT), NULL);
routes = g_array_new (TRUE, TRUE, sizeof (NMPlatformIP6Route));
if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT;
/* Fill routes */
for (i = 0; i < priv->ip6_routes->len; i++) {
route = &g_array_index (priv->ip6_routes, NMPlatformIP6Route, i);
if (route && (!ifindex || route->ifindex == ifindex)) {
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route)) {
if (mode != NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT)
if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT))
g_array_append_val (routes, *route);
} else {
if (mode != NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT)
if (NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
g_array_append_val (routes, *route);
}
}
@ -1466,8 +1462,6 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->ip4_address_exists = ip4_address_exists;
platform_class->ip6_address_exists = ip6_address_exists;
platform_class->ip4_check_reinstall_device_route = ip4_check_reinstall_device_route;
platform_class->ip4_route_get_all = ip4_route_get_all;
platform_class->ip6_route_get_all = ip6_route_get_all;
platform_class->ip4_route_add = ip4_route_add;

View file

@ -597,7 +597,7 @@ _nm_ip_config_source_to_rtprot (NMIPConfigSource source)
case NM_IP_CONFIG_SOURCE_UNKNOWN:
return RTPROT_UNSPEC;
case NM_IP_CONFIG_SOURCE_KERNEL:
case _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
return RTPROT_KERNEL;
case NM_IP_CONFIG_SOURCE_DHCP:
return RTPROT_DHCP;
@ -616,7 +616,7 @@ _nm_ip_config_source_from_rtprot (guint rtprot)
case RTPROT_UNSPEC:
return NM_IP_CONFIG_SOURCE_UNKNOWN;
case RTPROT_KERNEL:
return _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
return NM_IP_CONFIG_SOURCE_RTPROT_KERNEL;
case RTPROT_REDIRECT:
return NM_IP_CONFIG_SOURCE_KERNEL;
case RTPROT_RA:
@ -1289,6 +1289,7 @@ _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject
struct rtnl_route *nlo = (struct rtnl_route *) _nlo;
struct nl_addr *dst, *gw;
struct rtnl_nexthop *nexthop;
struct nl_addr *pref_src;
if (rtnl_route_get_type (nlo) != RTN_UNICAST ||
rtnl_route_get_table (nlo) != RT_TABLE_MAIN ||
@ -1334,6 +1335,14 @@ _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject
} else
obj->source = _nm_ip_config_source_from_rtprot (rtnl_route_get_protocol (nlo));
pref_src = rtnl_route_get_pref_src (nlo);
if (pref_src) {
if (nl_addr_get_len (pref_src) != sizeof (obj->pref_src))
g_warn_if_reached ();
else
memcpy (&obj->pref_src, nl_addr_get_binary_addr (pref_src), sizeof (obj->pref_src));
}
return TRUE;
}
@ -4023,13 +4032,9 @@ build_rtnl_addr (NMPlatform *platform,
}
_nl_rtnl_addr_set_prefixlen (rtnladdr, plen);
if (lifetime) {
/* note that here we set the relative timestamps (ticking from *now*).
* Contrary to the rtnl_addr objects from our cache, which have absolute
* timestamps (see _rtnl_addr_hack_lifetimes_rel_to_abs()).
*
* This is correct, because we only use build_rtnl_addr() for
* add_object(), delete_object() and cache search (ip_address_exists). */
if ( lifetime != 0 || lifetime != NM_PLATFORM_LIFETIME_PERMANENT
|| preferred != 0 || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
/* note that here we set the relative timestamps (ticking from *now*). */
rtnl_addr_set_valid_lifetime (rtnladdr, lifetime);
rtnl_addr_set_preferred_lifetime (rtnladdr, preferred);
}
@ -4058,6 +4063,10 @@ struct nl_object *
_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
{
const NMPlatformIP4Address *obj = (const NMPlatformIP4Address *) _obj;
guint32 lifetime, preferred;
nmp_utils_lifetime_get (obj->timestamp, obj->lifetime, obj->preferred,
0, 0, &lifetime, &preferred);
return build_rtnl_addr (platform,
AF_INET,
@ -4065,8 +4074,8 @@ _nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObjec
&obj->address,
obj->peer_address ? &obj->peer_address : NULL,
obj->plen,
obj->lifetime,
obj->preferred,
lifetime,
preferred,
0,
obj->label[0] ? obj->label : NULL);
}
@ -4075,6 +4084,10 @@ struct nl_object *
_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
{
const NMPlatformIP6Address *obj = (const NMPlatformIP6Address *) _obj;
guint32 lifetime, preferred;
nmp_utils_lifetime_get (obj->timestamp, obj->lifetime, obj->preferred,
0, 0, &lifetime, &preferred);
return build_rtnl_addr (platform,
AF_INET6,
@ -4082,8 +4095,8 @@ _nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObjec
&obj->address,
!IN6_IS_ADDR_UNSPECIFIED (&obj->peer_address) ? &obj->peer_address : NULL,
obj->plen,
obj->lifetime,
obj->preferred,
lifetime,
preferred,
0,
NULL);
}
@ -4169,103 +4182,57 @@ ip6_address_exists (NMPlatform *platform, int ifindex, struct in6_addr addr, int
return nmp_object_is_visible (nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle));
}
static gboolean
ip4_check_reinstall_device_route (NMPlatform *platform, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
guint32 device_network;
NMPObject obj_needle;
const NMPlatformIP4Address *const *addresses;
const NMPlatformIP4Route *const *routes;
device_network = nm_utils_ip4_address_clear_host_address (address->address, address->plen);
/* in many cases we expect the route to already exist. So first do an exact lookup
* to save the O(n) access below. */
nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, device_network, address->plen, device_route_metric);
if (nmp_cache_lookup_obj (priv->cache, &obj_needle)) {
/* There is already a route with metric 0 or the metric we want to install
* for the same subnet. */
return FALSE;
}
if (obj_needle.ip4_route.metric != 0) {
obj_needle.ip4_route.metric = 0;
if (nmp_cache_lookup_obj (priv->cache, &obj_needle))
return FALSE;
}
/* also check whether we already have the same address configured on *any* device. */
addresses = cache_lookup_all_objects (NMPlatformIP4Address, platform, NMP_OBJECT_TYPE_IP4_ADDRESS, FALSE);
if (addresses) {
for (; *addresses; addresses++) {
const NMPlatformIP4Address *addr_candidate = *addresses;
if ( addr_candidate->plen == address->plen
&& addr_candidate->address == device_network) {
/* If we already have the same address installed on any interface,
* we back off. */
return FALSE;
}
}
}
routes = cache_lookup_all_objects (NMPlatformIP4Route, platform, NMP_OBJECT_TYPE_IP4_ROUTE, FALSE);
if (routes) {
for (; *routes; routes++) {
const NMPlatformIP4Route *route_candidate = *routes;
if ( route_candidate->network == device_network
&& route_candidate->plen == address->plen
&& (route_candidate->metric == 0 || route_candidate->metric == device_route_metric)) {
/* If we already have the same address installed on any interface,
* we back off. */
return FALSE;
}
}
}
return TRUE;
}
/******************************************************************/
static GArray *
ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteMode mode)
ipx_route_get_all (NMPlatform *platform, int ifindex, NMPObjectType obj_type, NMPlatformGetRouteFlags flags)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
gboolean with_default = FALSE, with_non_default = FALSE;
NMPCacheId cache_id;
const NMPlatformIPRoute *const* routes;
GArray *array;
const NMPClass *klass;
gboolean with_rtprot_kernel;
guint i, len;
nm_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
if (mode == NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT)
with_non_default = TRUE;
else if (mode == NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT)
with_default = TRUE;
else if (mode == NM_PLATFORM_GET_ROUTE_MODE_ALL) {
with_non_default = TRUE;
with_default = TRUE;
} else
g_return_val_if_reached (NULL);
if (!NM_FLAGS_ANY (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT))
flags |= NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT;
return nmp_cache_lookup_multi_to_array (priv->cache,
obj_type,
nmp_cache_id_init_routes_visible (NMP_CACHE_ID_STATIC,
obj_type,
with_default,
with_non_default,
ifindex));
klass = nmp_class_from_type (obj_type);
nmp_cache_id_init_routes_visible (&cache_id,
obj_type,
NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT),
NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT),
ifindex);
routes = (const NMPlatformIPRoute *const*) nmp_cache_lookup_multi (priv->cache, &cache_id, &len);
array = g_array_sized_new (FALSE, FALSE, klass->sizeof_public, len);
with_rtprot_kernel = NM_FLAGS_HAS (flags, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL);
for (i = 0; i < len; i++) {
nm_assert (NMP_OBJECT_GET_CLASS (NMP_OBJECT_UP_CAST (routes[i])) == klass);
if ( with_rtprot_kernel
|| routes[i]->source != NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
g_array_append_vals (array, routes[i], 1);
}
return array;
}
static GArray *
ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode)
ip4_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
{
return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, mode);
return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP4_ROUTE, flags);
}
static GArray *
ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteMode mode)
ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags flags)
{
return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, mode);
return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags);
}
static void
@ -4342,7 +4309,7 @@ _nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject
&obj->network,
obj->plen,
&obj->gateway,
NULL,
obj->pref_src ? &obj->pref_src : NULL,
obj->metric,
obj->mss);
}
@ -5028,8 +4995,6 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->ip4_address_exists = ip4_address_exists;
platform_class->ip6_address_exists = ip6_address_exists;
platform_class->ip4_check_reinstall_device_route = ip4_check_reinstall_device_route;
platform_class->ip4_route_get_all = ip4_route_get_all;
platform_class->ip6_route_get_all = ip6_route_get_all;
platform_class->ip4_route_add = ip4_route_add;

View file

@ -347,4 +347,92 @@ out:
return g_intern_string (driver);
}
/******************************************************************
* utils
******************************************************************/
/**
* Takes a pair @timestamp and @duration, and returns the remaining duration based
* on the new timestamp @now.
*/
guint32
nmp_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp,
guint32 duration,
guint32 now,
guint32 padding)
{
gint64 t;
if (duration == NM_PLATFORM_LIFETIME_PERMANENT)
return NM_PLATFORM_LIFETIME_PERMANENT;
if (timestamp == 0) {
/* if the @timestamp is zero, assume it was just left unset and that the relative
* @duration starts counting from @now. This is convenient to construct an address
* and print it in nm_platform_ip4_address_to_string().
*
* In general it does not make sense to set the @duration without anchoring at
* @timestamp because you don't know the absolute expiration time when looking
* at the address at a later moment. */
timestamp = now;
}
/* For timestamp > now, just accept it and calculate the expected(?) result. */
t = (gint64) timestamp + (gint64) duration - (gint64) now;
/* Optional padding to avoid potential races. */
t += (gint64) padding;
if (t <= 0)
return 0;
if (t >= NM_PLATFORM_LIFETIME_PERMANENT)
return NM_PLATFORM_LIFETIME_PERMANENT - 1;
return t;
}
gboolean
nmp_utils_lifetime_get (guint32 timestamp,
guint32 lifetime,
guint32 preferred,
guint32 now,
guint32 padding,
guint32 *out_lifetime,
guint32 *out_preferred)
{
guint32 t_lifetime, t_preferred;
if (lifetime == 0) {
*out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
*out_preferred = NM_PLATFORM_LIFETIME_PERMANENT;
/* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses
* (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT).
* In that case we also expect that the other fields (timestamp and preferred) are left unset. */
g_return_val_if_fail (timestamp == 0 && preferred == 0, TRUE);
} else {
if (!now)
now = nm_utils_get_monotonic_timestamp_s ();
t_lifetime = nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, padding);
if (!t_lifetime) {
*out_lifetime = 0;
*out_preferred = 0;
return FALSE;
}
t_preferred = nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, preferred, now, padding);
*out_lifetime = t_lifetime;
*out_preferred = MIN (t_preferred, t_lifetime);
/* Assert that non-permanent addresses have a (positive) @timestamp. nmp_utils_lifetime_rebase_relative_time_on_now()
* treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always
* should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew.
*/
g_return_val_if_fail ( timestamp != 0
|| ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT
&& preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE);
g_return_val_if_fail (t_preferred <= t_lifetime, TRUE);
}
return TRUE;
}

View file

@ -50,5 +50,17 @@ gboolean nmp_utils_mii_supports_carrier_detect (const char *ifname);
const char *nmp_utils_udev_get_driver (GUdevDevice *device);
guint32 nmp_utils_lifetime_rebase_relative_time_on_now (guint32 timestamp,
guint32 duration,
guint32 now,
guint32 padding);
gboolean nmp_utils_lifetime_get (guint32 timestamp,
guint32 lifetime,
guint32 preferred,
guint32 now,
guint32 padding,
guint32 *out_lifetime,
guint32 *out_preferred);
#endif /* __NM_PLATFORM_UTILS_H__ */

View file

@ -33,11 +33,14 @@
#include "NetworkManagerUtils.h"
#include "nm-utils.h"
#include "nm-platform.h"
#include "nm-platform-utils.h"
#include "NetworkManagerUtils.h"
#include "nm-logging.h"
#include "nm-enum-types.h"
#include "nm-core-internal.h"
#define ADDRESS_LIFETIME_PADDING 5
G_STATIC_ASSERT (sizeof ( ((NMPlatformLink *) NULL)->addr.data ) == NM_UTILS_HWADDR_LEN_MAX);
#define debug(...) nm_log_dbg (LOGD_PLATFORM, __VA_ARGS__)
@ -1947,7 +1950,7 @@ nm_platform_ip6_address_exists (NMPlatform *self, int ifindex, struct in6_addr a
}
static gboolean
array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address)
array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address *address, gint64 now, guint32 padding)
{
guint len = addresses ? addresses->len : 0;
guint i;
@ -1955,15 +1958,20 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address
for (i = 0; i < len; i++) {
NMPlatformIP4Address *candidate = &g_array_index (addresses, NMPlatformIP4Address, i);
if (candidate->address == address->address && candidate->plen == address->plen)
return TRUE;
if (candidate->address == address->address && candidate->plen == address->plen) {
guint32 lifetime, preferred;
if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred,
now, padding, &lifetime, &preferred))
return TRUE;
}
}
return FALSE;
}
static gboolean
array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address)
array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address *address, gint64 now, guint32 padding)
{
guint len = addresses ? addresses->len : 0;
guint i;
@ -1971,109 +1979,27 @@ array_contains_ip6_address (const GArray *addresses, const NMPlatformIP6Address
for (i = 0; i < len; i++) {
NMPlatformIP6Address *candidate = &g_array_index (addresses, NMPlatformIP6Address, i);
if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen)
return TRUE;
if (IN6_ARE_ADDR_EQUAL (&candidate->address, &address->address) && candidate->plen == address->plen) {
guint32 lifetime, preferred;
if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred,
now, padding, &lifetime, &preferred))
return TRUE;
}
}
return FALSE;
}
/**
* Takes a pair @timestamp and @duration, and returns the remaining duration based
* on the new timestamp @now.
*/
static guint32
_rebase_relative_time_on_now (guint32 timestamp, guint32 duration, guint32 now, guint32 padding)
{
gint64 t;
if (duration == NM_PLATFORM_LIFETIME_PERMANENT)
return NM_PLATFORM_LIFETIME_PERMANENT;
if (timestamp == 0) {
/* if the @timestamp is zero, assume it was just left unset and that the relative
* @duration starts counting from @now. This is convenient to construct an address
* and print it in nm_platform_ip4_address_to_string().
*
* In general it does not make sense to set the @duration without anchoring at
* @timestamp because you don't know the absolute expiration time when looking
* at the address at a later moment. */
timestamp = now;
}
/* For timestamp > now, just accept it and calculate the expected(?) result. */
t = (gint64) timestamp + (gint64) duration - (gint64) now;
/* Optional padding to avoid potential races. */
t += (gint64) padding;
if (t <= 0)
return 0;
if (t >= NM_PLATFORM_LIFETIME_PERMANENT)
return NM_PLATFORM_LIFETIME_PERMANENT - 1;
return t;
}
static gboolean
_address_get_lifetime (const NMPlatformIPAddress *address, guint32 now, guint32 padding, guint32 *out_lifetime, guint32 *out_preferred)
{
guint32 lifetime, preferred;
if (address->lifetime == 0) {
*out_lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
*out_preferred = NM_PLATFORM_LIFETIME_PERMANENT;
/* We treat lifetime==0 as permanent addresses to allow easy creation of such addresses
* (without requiring to set the lifetime fields to NM_PLATFORM_LIFETIME_PERMANENT).
* In that case we also expect that the other fields (timestamp and preferred) are left unset. */
g_return_val_if_fail (address->timestamp == 0 && address->preferred == 0, TRUE);
} else {
lifetime = _rebase_relative_time_on_now (address->timestamp, address->lifetime, now, padding);
if (!lifetime)
return FALSE;
preferred = _rebase_relative_time_on_now (address->timestamp, address->preferred, now, padding);
*out_lifetime = lifetime;
*out_preferred = MIN (preferred, lifetime);
/* Assert that non-permanent addresses have a (positive) @timestamp. _rebase_relative_time_on_now()
* treats addresses with timestamp 0 as *now*. Addresses passed to _address_get_lifetime() always
* should have a valid @timestamp, otherwise on every re-sync, their lifetime will be extended anew.
*/
g_return_val_if_fail ( address->timestamp != 0
|| ( address->lifetime == NM_PLATFORM_LIFETIME_PERMANENT
&& address->preferred == NM_PLATFORM_LIFETIME_PERMANENT), TRUE);
g_return_val_if_fail (preferred <= lifetime, TRUE);
}
return TRUE;
}
gboolean
nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric)
{
_CHECK_SELF (self, klass, FALSE);
if ( ifindex <= 0
|| address->plen <= 0
|| address->plen >= 32)
return FALSE;
if (device_route_metric == NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
/* The automatically added route would be already our desired priority.
* Nothing to do. */
return FALSE;
}
return klass->ip4_check_reinstall_device_route (self, ifindex, address, device_route_metric);
}
/**
* nm_platform_ip4_address_sync:
* @self: platform instance
* @ifindex: Interface index
* @known_addresses: List of addresses
* @device_route_metric: the route metric for adding subnet routes (replaces
* the kernel added routes).
* @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.
*
* A convenience function to synchronize addresses for a specific interface
* with the least possible disturbance. It simply removes addresses that are
@ -2082,7 +2008,7 @@ nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, con
* Returns: %TRUE on success.
*/
gboolean
nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, guint32 device_route_metric)
nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, GPtrArray **out_added_addresses)
{
GArray *addresses;
NMPlatformIP4Address *address;
@ -2096,11 +2022,14 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known
for (i = 0; i < addresses->len; i++) {
address = &g_array_index (addresses, NMPlatformIP4Address, i);
if (!array_contains_ip4_address (known_addresses, address))
if (!array_contains_ip4_address (known_addresses, address, now, ADDRESS_LIFETIME_PADDING))
nm_platform_ip4_address_delete (self, ifindex, address->address, address->plen, address->peer_address);
}
g_array_free (addresses, TRUE);
if (out_added_addresses)
*out_added_addresses = NULL;
if (!known_addresses)
return TRUE;
@ -2108,33 +2037,18 @@ nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known
for (i = 0; i < known_addresses->len; i++) {
const NMPlatformIP4Address *known_address = &g_array_index (known_addresses, NMPlatformIP4Address, i);
guint32 lifetime, preferred;
guint32 network;
gboolean reinstall_device_route = FALSE;
/* add a padding of 5 seconds to avoid potential races. */
if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred))
if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred))
continue;
if (nm_platform_ip4_check_reinstall_device_route (self, ifindex, known_address, device_route_metric))
reinstall_device_route = TRUE;
if (!nm_platform_ip4_address_add (self, ifindex, known_address->address, known_address->peer_address, known_address->plen, lifetime, preferred, known_address->label))
return FALSE;
if (reinstall_device_route) {
/* Kernel automatically adds a device route for us with metric 0. That is not what we want.
* Remove it, and re-add it.
*
* In face of having the same subnets on two different interfaces with the same metric,
* this is a problem. Surprisingly, kernel is able to add two routes for the same subnet/prefix,metric
* to different interfaces. We cannot. Adding one, would replace the other. This is avoided
* by the above nm_platform_ip4_check_reinstall_device_route() check.
*/
network = nm_utils_ip4_address_clear_host_address (known_address->address, known_address->plen);
(void) nm_platform_ip4_route_add (self, ifindex, NM_IP_CONFIG_SOURCE_KERNEL, network, known_address->plen,
0, known_address->address, device_route_metric, 0);
(void) nm_platform_ip4_route_delete (self, ifindex, network, known_address->plen,
NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE);
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);
}
}
@ -2171,7 +2085,7 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known
if (keep_link_local && IN6_IS_ADDR_LINKLOCAL (&address->address))
continue;
if (!array_contains_ip6_address (known_addresses, address))
if (!array_contains_ip6_address (known_addresses, address, now, ADDRESS_LIFETIME_PADDING))
nm_platform_ip6_address_delete (self, ifindex, address->address, address->plen);
}
g_array_free (addresses, TRUE);
@ -2184,8 +2098,8 @@ nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GArray *known
const NMPlatformIP6Address *known_address = &g_array_index (known_addresses, NMPlatformIP6Address, i);
guint32 lifetime, preferred;
/* add a padding of 5 seconds to avoid potential races. */
if (!_address_get_lifetime ((NMPlatformIPAddress *) known_address, now, 5, &lifetime, &preferred))
if (!nmp_utils_lifetime_get (known_address->timestamp, known_address->lifetime, known_address->preferred,
now, ADDRESS_LIFETIME_PADDING, &lifetime, &preferred))
continue;
if (!nm_platform_ip6_address_add (self, ifindex, known_address->address,
@ -2202,32 +2116,30 @@ nm_platform_address_flush (NMPlatform *self, int ifindex)
{
_CHECK_SELF (self, klass, FALSE);
return nm_platform_ip4_address_sync (self, ifindex, NULL, 0)
&& nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE);
return nm_platform_ip4_address_sync (self, ifindex, NULL, NULL)
&& nm_platform_ip6_address_sync (self, ifindex, NULL, FALSE);
}
/******************************************************************/
GArray *
nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode)
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);
g_return_val_if_fail (klass->ip4_route_get_all, NULL);
return klass->ip4_route_get_all (self, ifindex, mode);
return klass->ip4_route_get_all (self, ifindex, flags);
}
GArray *
nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode)
nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags)
{
_CHECK_SELF (self, klass, NULL);
g_return_val_if_fail (ifindex >= 0, NULL);
g_return_val_if_fail (klass->ip6_route_get_all, NULL);
return klass->ip6_route_get_all (self, ifindex, mode);
return klass->ip6_route_get_all (self, ifindex, flags);
}
gboolean
@ -2244,7 +2156,6 @@ nm_platform_ip4_route_add (NMPlatform *self,
if (nm_logging_enabled (LOGL_DEBUG, LOGD_PLATFORM)) {
NMPlatformIP4Route route = { 0 };
char pref_src_buf[NM_UTILS_INET_ADDRSTRLEN];
route.ifindex = ifindex;
route.source = source;
@ -2253,11 +2164,9 @@ nm_platform_ip4_route_add (NMPlatform *self,
route.gateway = gateway;
route.metric = metric;
route.mss = mss;
route.pref_src = pref_src;
debug ("route: adding or updating IPv4 route: %s%s%s%s", nm_platform_ip4_route_to_string (&route),
pref_src ? " (src: " : "",
pref_src ? nm_utils_inet4_ntop (pref_src, pref_src_buf) : "",
pref_src ? ")" : "");
debug ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route));
}
return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss);
}
@ -2345,7 +2254,7 @@ static const char *
source_to_string (NMIPConfigSource source)
{
switch (source) {
case _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
case NM_IP_CONFIG_SOURCE_RTPROT_KERNEL:
return "rtprot-kernel";
case _NM_IP_CONFIG_SOURCE_RTM_F_CLONED:
return "rtm-f-cloned";
@ -2380,7 +2289,7 @@ _lifetime_to_string (guint32 timestamp, guint32 lifetime, gint32 now, char *buf,
return "forever";
g_snprintf (buf, buf_size, "%usec",
_rebase_relative_time_on_now (timestamp, lifetime, now, 0));
nmp_utils_lifetime_rebase_relative_time_on_now (timestamp, lifetime, now, 0));
return buf;
}
@ -2662,6 +2571,7 @@ const char *
nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route)
{
char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN];
char s_pref_src[INET_ADDRSTRLEN];
char str_dev[TO_STRING_DEV_BUF_SIZE];
char str_scope[30];
@ -2680,6 +2590,7 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route)
" mss %"G_GUINT32_FORMAT
" src %s" /* source */
"%s%s" /* scope */
"%s%s" /* pref-src */
"",
s_network, route->plen,
s_gateway,
@ -2688,7 +2599,9 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route)
route->mss,
source_to_string (route->source),
route->scope_inv ? " scope " : "",
route->scope_inv ? (rtnl_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "");
route->scope_inv ? (rtnl_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "",
route->pref_src ? " pref-src " : "",
route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "");
return _nm_platform_to_string_buffer;
}
@ -2867,6 +2780,7 @@ nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route
_CMP_FIELD (a, b, metric);
_CMP_FIELD (a, b, mss);
_CMP_FIELD (a, b, scope_inv);
_CMP_FIELD (a, b, pref_src);
return 0;
}
@ -2989,7 +2903,7 @@ log_ip6_route (NMPlatform *p, NMPObjectType obj_type, int ifindex, NMPlatformIP6
/******************************************************************/
static gboolean
_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src)
_vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route)
{
return nm_platform_ip4_route_add (self,
ifindex > 0 ? ifindex : route->rx.ifindex,
@ -2997,13 +2911,13 @@ _vtr_v4_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *rout
route->r4.network,
route->rx.plen,
route->r4.gateway,
v4_pref_src,
route->r4.pref_src,
route->rx.metric,
route->rx.mss);
}
static gboolean
_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src)
_vtr_v6_route_add (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route)
{
return nm_platform_ip6_route_add (self,
ifindex > 0 ? ifindex : route->rx.ifindex,

View file

@ -151,10 +151,16 @@ typedef enum {
#define NM_PLATFORM_LIFETIME_PERMANENT G_MAXUINT32
typedef enum {
NM_PLATFORM_GET_ROUTE_MODE_ALL,
NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT,
NM_PLATFORM_GET_ROUTE_MODE_ONLY_DEFAULT,
} NMPlatformGetRouteMode;
NM_PLATFORM_GET_ROUTE_FLAGS_NONE = 0,
/* Whether to include default-routes/non-default-routes. Omitting
* both WITH_DEFAULT and WITH_NON_DEFAULT, is equal to specifying
* both of them. */
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT = (1LL << 0),
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT = (1LL << 1),
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_RTPROT_KERNEL = (1LL << 2),
} NMPlatformGetRouteFlags;
typedef struct {
__NMPlatformObject_COMMON;
@ -276,6 +282,10 @@ struct _NMPlatformIP4Route {
/* The bitwise inverse of the route scope. It is inverted so that the
* default value (RT_SCOPE_NOWHERE) is nul. */
guint8 scope_inv;
/* RTA_PREFSRC/rtnl_route_get_pref_src(). A value of zero means that
* no pref-src is set. */
guint32 pref_src;
};
G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OFFSET (NMPlatformIP4Route, network));
@ -304,8 +314,8 @@ typedef struct {
gsize sizeof_route;
int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b);
const char *(*route_to_string) (const NMPlatformIPXRoute *route);
GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode);
gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, guint32 v4_pref_src);
GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route);
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);
@ -510,10 +520,8 @@ typedef struct {
gboolean (*ip4_address_exists) (NMPlatform *, int ifindex, in_addr_t address, int plen);
gboolean (*ip6_address_exists) (NMPlatform *, int ifindex, struct in6_addr address, int plen);
gboolean (*ip4_check_reinstall_device_route) (NMPlatform *, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric);
GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteMode mode);
GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteMode mode);
GArray * (*ip4_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags);
GArray * (*ip6_route_get_all) (NMPlatform *, int ifindex, NMPlatformGetRouteFlags flags);
gboolean (*ip4_route_add) (NMPlatform *, int ifindex, NMIPConfigSource source,
in_addr_t network, int plen, in_addr_t gateway,
guint32 pref_src, guint32 metric, guint32 mss);
@ -696,14 +704,12 @@ gboolean nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_
gboolean nm_platform_ip6_address_delete (NMPlatform *self, int ifindex, struct in6_addr address, int plen);
gboolean nm_platform_ip4_address_exists (NMPlatform *self, int ifindex, in_addr_t address, int plen);
gboolean nm_platform_ip6_address_exists (NMPlatform *self, int ifindex, struct in6_addr address, int plen);
gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, const GArray *known_addresses, guint32 device_route_metric);
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_address_flush (NMPlatform *self, int ifindex);
gboolean nm_platform_ip4_check_reinstall_device_route (NMPlatform *self, int ifindex, const NMPlatformIP4Address *address, guint32 device_route_metric);
GArray *nm_platform_ip4_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode);
GArray *nm_platform_ip6_route_get_all (NMPlatform *self, int ifindex, NMPlatformGetRouteMode mode);
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, int ifindex, NMIPConfigSource source,
in_addr_t network, int plen, in_addr_t gateway,
guint32 pref_src, guint32 metric, guint32 mss);

View file

@ -786,7 +786,7 @@ _vt_cmd_obj_is_visible_ipx_route (const NMPObject *obj)
{
NMIPConfigSource source = obj->ip_route.source;
return obj->object.ifindex > 0 && (source != _NM_IP_CONFIG_SOURCE_RTPROT_KERNEL && source != _NM_IP_CONFIG_SOURCE_RTM_F_CLONED);
return obj->object.ifindex > 0 && source != _NM_IP_CONFIG_SOURCE_RTM_F_CLONED;
}
/******************************************************************/

View file

@ -86,8 +86,8 @@ dump_interface (NMPlatformLink *link)
g_array_unref (ip4_addresses);
g_array_unref (ip6_addresses);
ip4_routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
ip6_routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
ip4_routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
ip6_routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
g_assert (ip4_routes);
g_assert (ip6_routes);

View file

@ -640,7 +640,7 @@ do_ip4_route_get_all (char **argv)
int i;
if (ifindex) {
routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
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);
for (i = 0; i < routes->len; i++) {
route = &g_array_index (routes, NMPlatformIP4Route, i);
inet_ntop (AF_INET, &route->network, networkstr, sizeof (networkstr));
@ -664,7 +664,7 @@ do_ip6_route_get_all (char **argv)
int i;
if (ifindex) {
routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
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);
for (i = 0; i < routes->len; i++) {
route = &g_array_index (routes, NMPlatformIP6Route, i);
inet_ntop (AF_INET6, &route->network, networkstr, sizeof (networkstr));

View file

@ -54,8 +54,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_MODE_ALL);
routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
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);
g_assert_cmpint (addresses4->len, ==, 1);
g_assert_cmpint (addresses6->len, ==, 2); /* also has a IPv6 LL address. */
@ -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_MODE_ALL);
routes6 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, ifindex, NM_PLATFORM_GET_ROUTE_MODE_ALL);
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);
g_assert_cmpint (addresses4->len, ==, 0);
g_assert_cmpint (addresses6->len, ==, 0);

View file

@ -155,7 +155,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_MODE_ALL);
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);
memset (rts, 0, sizeof (rts));
rts[0].source = NM_IP_CONFIG_SOURCE_USER;
rts[0].network = gateway;
@ -242,7 +242,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_MODE_ALL);
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);
memset (rts, 0, sizeof (rts));
rts[0].source = NM_IP_CONFIG_SOURCE_USER;
rts[0].network = gateway;

View file

@ -61,7 +61,7 @@ setup_dev0_ip4 (int ifindex, guint mss_of_first_route, guint32 metric_of_second_
route.mss = 0;
g_array_append_val (routes, route);
nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes);
nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE);
g_array_free (routes, TRUE);
}
@ -107,7 +107,7 @@ setup_dev1_ip4 (int ifindex)
route.metric = 22;
g_array_append_val (routes, route);
nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes);
nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE);
g_array_free (routes, TRUE);
}
@ -134,7 +134,7 @@ update_dev0_ip4 (int ifindex)
route.metric = 21;
g_array_append_val (routes, route);
nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes);
nm_route_manager_ip4_route_sync (nm_route_manager_get (), ifindex, routes, TRUE);
g_array_free (routes, TRUE);
}
@ -144,10 +144,10 @@ ip4_routes (test_fixture *fixture)
{
GArray *routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET,
fixture->ifindex0,
NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
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_MODE_NO_DEFAULT);
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
g_array_append_vals (routes, routes1->data, routes1->len);
g_array_free (routes1, TRUE);
@ -346,7 +346,7 @@ setup_dev0_ip6 (int ifindex)
0);
g_array_append_val (routes, *route);
nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes);
nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE);
g_array_free (routes, TRUE);
}
@ -403,7 +403,7 @@ setup_dev1_ip6 (int ifindex)
0);
g_array_append_val (routes, *route);
nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes);
nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE);
g_array_free (routes, TRUE);
}
@ -450,7 +450,7 @@ update_dev0_ip6 (int ifindex)
0);
g_array_append_val (routes, *route);
nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes);
nm_route_manager_ip6_route_sync (nm_route_manager_get (), ifindex, routes, TRUE);
g_array_free (routes, TRUE);
}
@ -459,10 +459,10 @@ ip6_routes (test_fixture *fixture)
{
GArray *routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET,
fixture->ifindex0,
NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
GArray *routes1 = nm_platform_ip6_route_get_all (NM_PLATFORM_GET,
fixture->ifindex1,
NM_PLATFORM_GET_ROUTE_MODE_NO_DEFAULT);
NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
g_array_append_vals (routes, routes1->data, routes1->len);
g_array_free (routes1, TRUE);