platform: merge branch 'th/platform-route-pt3'

Continue with the routing rework. Get rid of NMRouteManager
and configure non-exclusive routes.

https://github.com/NetworkManager/NetworkManager/pull/25
This commit is contained in:
Thomas Haller 2017-08-24 11:55:58 +02:00
commit f4d88630b0
42 changed files with 2207 additions and 3287 deletions

View file

@ -1323,9 +1323,6 @@ src_libNetworkManagerBase_la_SOURCES = \
src/nm-ip6-config.c \
src/nm-ip6-config.h \
\
src/nm-route-manager.c \
src/nm-route-manager.h \
\
src/dhcp/nm-dhcp-client.c \
src/dhcp/nm-dhcp-client.h \
src/dhcp/nm-dhcp-client-logging.h \
@ -2961,8 +2958,6 @@ check_programs += \
src/tests/test-general-with-expect \
src/tests/test-ip4-config \
src/tests/test-ip6-config \
src/tests/test-route-manager-linux \
src/tests/test-route-manager-fake \
src/tests/test-dcb \
src/tests/test-systemd \
src/tests/test-resolvconf-capture \
@ -3010,28 +3005,6 @@ $(src_tests_test_general_with_expect_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(src_tests_test_wired_defname_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(src_tests_test_utils_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
src_tests_test_route_manager_ldflags = \
$(CODE_COVERAGE_LDFLAGS)
src_tests_test_route_manager_ldadd = \
src/libNetworkManagerTest.la \
$(GLIB_LIBS) \
$(LIBUDEV_LIBS) \
$(LIBNL_LIBS)
src_tests_test_route_manager_fake_SOURCES = src/tests/test-route-manager.c
src_tests_test_route_manager_fake_CPPFLAGS = $(src_tests_cppflags_fake)
src_tests_test_route_manager_fake_LDFLAGS = $(src_tests_test_route_manager_ldflags)
src_tests_test_route_manager_fake_LDADD = $(src_tests_test_route_manager_ldadd)
src_tests_test_route_manager_linux_SOURCES = src/tests/test-route-manager.c
src_tests_test_route_manager_linux_CPPFLAGS = $(src_tests_cppflags_linux)
src_tests_test_route_manager_linux_LDFLAGS = $(src_tests_test_route_manager_ldflags)
src_tests_test_route_manager_linux_LDADD = $(src_tests_test_route_manager_ldadd)
$(src_tests_test_route_manager_fake_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
$(src_tests_test_route_manager_linux_OBJECTS): $(libnm_core_lib_h_pub_mkenums)
src_tests_test_systemd_CPPFLAGS = $(src_libsystemd_nm_la_cppflags)
src_tests_test_systemd_LDADD = \
src/libsystemd-nm.la \

View file

@ -78,6 +78,26 @@ G_STATIC_ASSERT (sizeof (bool) <= sizeof (int));
/*****************************************************************************/
static void
test_nm_g_slice_free_fcn (void)
{
gpointer p;
p = g_slice_new (gint64);
(nm_g_slice_free_fcn (gint64)) (p);
p = g_slice_new (gint32);
(nm_g_slice_free_fcn (gint32)) (p);
p = g_slice_new (gint);
(nm_g_slice_free_fcn (gint)) (p);
p = g_slice_new (gint64);
nm_g_slice_free_fcn_gint64 (p);
}
/*****************************************************************************/
typedef struct {
int val;
int idx;
@ -6177,6 +6197,7 @@ int main (int argc, char **argv)
{
nmtst_init (&argc, &argv, TRUE);
g_test_add_func ("/core/general/test_nm_g_slice_free_fcn", test_nm_g_slice_free_fcn);
g_test_add_func ("/core/general/test_c_list_sort", test_c_list_sort);
g_test_add_func ("/core/general/test_dedup_multi", test_dedup_multi);
g_test_add_func ("/core/general/test_utils_str_utf8safe", test_utils_str_utf8safe);

View file

@ -77,7 +77,7 @@ nm_dedup_multi_idx_type_init (NMDedupMultiIdxType *idx_type,
/*****************************************************************************/
static NMDedupMultiEntry *
_entry_lookup_obj (NMDedupMultiIndex *self,
_entry_lookup_obj (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj)
{
@ -92,7 +92,7 @@ _entry_lookup_obj (NMDedupMultiIndex *self,
}
static NMDedupMultiHeadEntry *
_entry_lookup_head (NMDedupMultiIndex *self,
_entry_lookup_head (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
const NMDedupMultiObj *obj)
{
@ -253,6 +253,8 @@ _add (NMDedupMultiIndex *self,
}));
if (entry) {
gboolean changed = FALSE;
nm_dedup_multi_entry_set_dirty (entry, FALSE);
nm_assert (!head_existing || entry->head == head_existing);
@ -270,11 +272,13 @@ _add (NMDedupMultiIndex *self,
&& entry->lst_entries.next != &entry_order->lst_entries) {
c_list_unlink (&entry->lst_entries);
c_list_link_before ((CList *) &entry_order->lst_entries, &entry->lst_entries);
changed = TRUE;
}
} else {
if (entry->lst_entries.prev != &entry->head->lst_entries_head) {
c_list_unlink (&entry->lst_entries);
c_list_link_front ((CList *) &entry->head->lst_entries_head, &entry->lst_entries);
changed = TRUE;
}
}
break;
@ -284,11 +288,13 @@ _add (NMDedupMultiIndex *self,
&& entry->lst_entries.prev != &entry_order->lst_entries) {
c_list_unlink (&entry->lst_entries);
c_list_link_after ((CList *) &entry_order->lst_entries, &entry->lst_entries);
changed = TRUE;
}
} else {
if (entry->lst_entries.next != &entry->head->lst_entries_head) {
c_list_unlink (&entry->lst_entries);
c_list_link_tail ((CList *) &entry->head->lst_entries_head, &entry->lst_entries);
changed = TRUE;
}
}
break;
@ -303,7 +309,7 @@ _add (NMDedupMultiIndex *self,
entry->obj)) {
NM_SET_OUT (out_entry, entry);
NM_SET_OUT (out_obj_old, nm_dedup_multi_obj_ref (entry->obj));
return FALSE;
return changed;
}
obj_new = nm_dedup_multi_index_obj_intern (self, obj);
@ -620,13 +626,22 @@ nm_dedup_multi_index_remove_entry (NMDedupMultiIndex *self,
guint
nm_dedup_multi_index_remove_obj (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj)
/*const NMDedupMultiObj * */ gconstpointer obj,
/*const NMDedupMultiObj ** */ gconstpointer *out_obj)
{
const NMDedupMultiEntry *entry;
entry = nm_dedup_multi_index_lookup_obj (self, idx_type, obj);
if (!entry)
if (!entry) {
NM_SET_OUT (out_obj, NULL);
return 0;
}
/* since we are about to remove the object, we obviously pass
* a reference to @out_obj, the caller MUST unref the object,
* if he chooses to provide @out_obj. */
NM_SET_OUT (out_obj, nm_dedup_multi_obj_ref (entry->obj));
_remove_entry (self, (NMDedupMultiEntry *) entry, NULL);
return 1;
}
@ -667,7 +682,7 @@ nm_dedup_multi_index_remove_idx (NMDedupMultiIndex *self,
* Returns: the cache entry or %NULL if the entry wasn't found.
*/
const NMDedupMultiEntry *
nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
nm_dedup_multi_index_lookup_obj (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj)
{
@ -693,7 +708,7 @@ nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
* Returns: the cache entry or %NULL if the entry wasn't found.
*/
const NMDedupMultiHeadEntry *
nm_dedup_multi_index_lookup_head (NMDedupMultiIndex *self,
nm_dedup_multi_index_lookup_head (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj)
{

View file

@ -278,11 +278,11 @@ gboolean nm_dedup_multi_index_add (NMDedupMultiIndex *self,
const NMDedupMultiEntry **out_entry,
/* const NMDedupMultiObj ** */ gpointer out_obj_old);
const NMDedupMultiEntry *nm_dedup_multi_index_lookup_obj (NMDedupMultiIndex *self,
const NMDedupMultiEntry *nm_dedup_multi_index_lookup_obj (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
const NMDedupMultiHeadEntry *nm_dedup_multi_index_lookup_head (NMDedupMultiIndex *self,
const NMDedupMultiHeadEntry *nm_dedup_multi_index_lookup_head (const NMDedupMultiIndex *self,
const NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
@ -291,7 +291,8 @@ guint nm_dedup_multi_index_remove_entry (NMDedupMultiIndex *self,
guint nm_dedup_multi_index_remove_obj (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,
/*const NMDedupMultiObj * */ gconstpointer obj);
/*const NMDedupMultiObj * */ gconstpointer obj,
/*const NMDedupMultiObj ** */ gconstpointer *out_obj);
guint nm_dedup_multi_index_remove_head (NMDedupMultiIndex *self,
NMDedupMultiIdxType *idx_type,

View file

@ -150,6 +150,53 @@ gint _nm_utils_ascii_str_to_bool (const char *str,
/*****************************************************************************/
#define _nm_g_slice_free_fcn_define(mem_size) \
static inline void \
_nm_g_slice_free_fcn_##mem_size (gpointer mem_block) \
{ \
g_slice_free1 (mem_size, mem_block); \
}
_nm_g_slice_free_fcn_define (1)
_nm_g_slice_free_fcn_define (2)
_nm_g_slice_free_fcn_define (4)
_nm_g_slice_free_fcn_define (8)
_nm_g_slice_free_fcn_define (16)
#define _nm_g_slice_free_fcn1(mem_size) \
({ \
void (*_fcn) (gpointer); \
\
/* If mem_size is a compile time constant, the compiler
* will be able to optimize this. Hence, you don't want
* to call this with a non-constant size argument. */ \
switch (mem_size) { \
case 1: _fcn = _nm_g_slice_free_fcn_1; break; \
case 2: _fcn = _nm_g_slice_free_fcn_2; break; \
case 4: _fcn = _nm_g_slice_free_fcn_4; break; \
case 8: _fcn = _nm_g_slice_free_fcn_8; break; \
case 16: _fcn = _nm_g_slice_free_fcn_16; break; \
default: g_assert_not_reached (); _fcn = NULL; break; \
} \
_fcn; \
})
/**
* nm_g_slice_free_fcn:
* @type: type argument for sizeof() operator that you would
* pass to g_slice_new().
*
* Returns: a function pointer with GDestroyNotify signature
* for g_slice_free(type,*).
*
* Only certain types are implemented. You'll get an assertion
* using the wrong type. */
#define nm_g_slice_free_fcn(type) (_nm_g_slice_free_fcn1 (sizeof (type)))
#define nm_g_slice_free_fcn_gint64 (nm_g_slice_free_fcn (gint64))
/*****************************************************************************/
/**
* NMUtilsError:
* @NM_UTILS_ERROR_UNKNOWN: unknown or unclassified error

View file

@ -483,7 +483,7 @@ create_and_realize (NMDevice *device,
"Failed to create bond interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}
return TRUE;

View file

@ -473,7 +473,7 @@ create_and_realize (NMDevice *device,
"Failed to create bridge interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -112,7 +112,7 @@ create_and_realize (NMDevice *device,
"Failed to create dummy interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -295,7 +295,7 @@ create_and_realize (NMDevice *device,
"Failed to create InfiniBand P_Key interface '%s' for '%s': %s",
nm_device_get_iface (device),
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}
@ -324,7 +324,7 @@ unrealize (NMDevice *device, GError **error)
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to remove InfiniBand P_Key interface '%s': %s",
nm_device_get_iface (device),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -647,7 +647,7 @@ create_and_realize (NMDevice *device,
"Failed to create GRE interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}
break;
@ -670,10 +670,10 @@ create_and_realize (NMDevice *device,
plerr = nm_platform_link_sit_add (nm_device_get_platform (device), iface, &lnk_sit, out_plink);
if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create SIT interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
"Failed to create SIT interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string_a (plerr));
return FALSE;
}
break;
@ -696,10 +696,10 @@ create_and_realize (NMDevice *device,
plerr = nm_platform_link_ipip_add (nm_device_get_platform (device), iface, &lnk_ipip, out_plink);
if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
"Failed to create IPIP interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
"Failed to create IPIP interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string_a (plerr));
return FALSE;
}
break;
@ -728,7 +728,7 @@ create_and_realize (NMDevice *device,
"Failed to create IPIP interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}
break;

View file

@ -720,7 +720,7 @@ create_and_realize (NMDevice *device,
"Failed to create macsec interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -258,7 +258,7 @@ create_and_realize (NMDevice *device,
lnk.tap ? "macvtap" : "macvlan",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -244,7 +244,7 @@ create_and_realize (NMDevice *device,
"Failed to create TUN/TAP interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -266,7 +266,7 @@ create_and_realize (NMDevice *device,
"Failed to create VLAN interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -223,7 +223,7 @@ create_and_realize (NMDevice *device,
"Failed to create VXLAN interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -66,7 +66,6 @@
#include "dns/nm-dns-manager.h"
#include "nm-core-internal.h"
#include "nm-default-route-manager.h"
#include "nm-route-manager.h"
#include "systemd/nm-sd.h"
#include "nm-lldp-listener.h"
#include "nm-audit-manager.h"
@ -491,16 +490,14 @@ static void nm_device_set_proxy_config (NMDevice *self, const char *pac_url);
static gboolean nm_device_set_ip4_config (NMDevice *self,
NMIP4Config *config,
guint32 default_route_metric,
gboolean commit,
gboolean routes_full_sync);
gboolean commit);
static gboolean ip4_config_merge_and_apply (NMDevice *self,
NMIP4Config *config,
gboolean commit);
static gboolean nm_device_set_ip6_config (NMDevice *self,
NMIP6Config *config,
gboolean commit,
gboolean routes_full_sync);
gboolean commit);
static gboolean ip6_config_merge_and_apply (NMDevice *self,
gboolean commit);
@ -2767,6 +2764,101 @@ link_changed_cb (NMPlatform *platform,
}
}
/*****************************************************************************/
typedef struct {
in_addr_t network;
guint8 plen;
} IP4RPFilterData;
static guint
_v4_has_shadowed_routes_detect_hash (const IP4RPFilterData *d)
{
guint h = 0;
h = NM_HASH_COMBINE (h, d->network);
h = NM_HASH_COMBINE (h, d->plen);
return h;
}
static gboolean
_v4_has_shadowed_routes_detect_equal (const IP4RPFilterData *d1, const IP4RPFilterData *d2)
{
return d1->network == d2->network && d1->plen == d2->plen;
}
static gboolean
_v4_has_shadowed_routes_detect (NMDevice *self)
{
NMPlatform *platform;
int ifindex;
NMPLookup lookup;
const NMDedupMultiHeadEntry *head_entry;
NMDedupMultiIter iter;
const NMPObject *o;
guint data_len;
gs_unref_hashtable GHashTable *data_hash = NULL;
gs_free IP4RPFilterData *data_arr = NULL;
ifindex = nm_device_get_ip_ifindex (self);
if (ifindex <= 0)
return FALSE;
platform = nm_device_get_platform (self);
head_entry = nm_platform_lookup (platform,
nmp_lookup_init_addrroute (&lookup,
NMP_OBJECT_TYPE_IP4_ROUTE,
ifindex));
if (!head_entry)
return FALSE;
/* first, create a lookup index @data_hash for all network/plen pairs. */
data_len = 0;
data_arr = g_new (IP4RPFilterData, head_entry->len);
data_hash = g_hash_table_new ((GHashFunc) _v4_has_shadowed_routes_detect_hash,
(GEqualFunc) _v4_has_shadowed_routes_detect_equal);
nmp_cache_iter_for_each (&iter, head_entry, &o) {
const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (o);
IP4RPFilterData *d;
nm_assert (r->ifindex == ifindex);
if ( NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
|| r->table_coerced)
continue;
d = &data_arr[data_len++];
d->network = nm_utils_ip4_address_clear_host_address (r->network, r->plen);
d->plen = r->plen;
g_hash_table_add (data_hash, d);
}
/* then, search if there is any route on another interface with the same
* network/plen destination. If yes, we consider this a multihoming
* setup. */
head_entry = nm_platform_lookup (platform,
nmp_lookup_init_obj_type (&lookup,
NMP_OBJECT_TYPE_IP4_ROUTE));
nmp_cache_iter_for_each (&iter, head_entry, &o) {
const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (o);
IP4RPFilterData d;
if ( r->ifindex == ifindex
|| NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r)
|| r->table_coerced)
continue;
d.network = nm_utils_ip4_address_clear_host_address (r->network, r->plen);
d.plen = r->plen;
if (g_hash_table_contains (data_hash, &d))
return TRUE;
}
return FALSE;
}
static void
ip4_rp_filter_update (NMDevice *self)
{
@ -2792,20 +2884,6 @@ ip4_rp_filter_update (NMDevice *self)
}
}
static void
ip4_routes_changed_changed_cb (NMRouteManager *route_manager, NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int ifindex = nm_device_get_ip_ifindex (self);
if (nm_device_sys_iface_state_is_external_or_assume (self))
return;
priv->v4_has_shadowed_routes = nm_route_manager_ip4_routes_shadowed (route_manager,
ifindex);
ip4_rp_filter_update (self);
}
static void
link_changed (NMDevice *self, const NMPlatformLink *pllink)
{
@ -3846,8 +3924,8 @@ nm_device_removed (NMDevice *self, gboolean unconfigure_ip_config)
_update_default_route (self, AF_INET6, priv->default_route.v6_has, TRUE);
_update_default_route (self, AF_INET, FALSE, TRUE);
_update_default_route (self, AF_INET6, FALSE, TRUE);
nm_device_set_ip4_config (self, NULL, 0, FALSE, FALSE);
nm_device_set_ip6_config (self, NULL, FALSE, FALSE);
nm_device_set_ip4_config (self, NULL, 0, FALSE);
nm_device_set_ip6_config (self, NULL, FALSE);
}
static gboolean
@ -5461,9 +5539,9 @@ _device_get_default_route_from_platform (NMDevice *self, int addr_family, NMPlat
guint32 m;
const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj);
if (r->ifindex != ifindex)
continue;
if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
if ( r->ifindex != ifindex
|| r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL
|| r->table_coerced)
continue;
/* if there are several default routes, find the one with the best metric */
@ -5582,7 +5660,6 @@ ip4_config_merge_and_apply (NMDevice *self,
const guint32 default_route_metric = nm_device_get_ip4_route_metric (self);
guint32 gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean routes_full_sync;
gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE;
gboolean auto_method = FALSE;
@ -5749,11 +5826,7 @@ END_ADD_DEFAULT_ROUTE:
NM_DEVICE_GET_CLASS (self)->ip4_config_pre_commit (self, composite);
}
routes_full_sync = commit
&& priv->v4_commit_first_time
&& !nm_device_sys_iface_state_is_external_or_assume (self);
success = nm_device_set_ip4_config (self, composite, default_route_metric, commit, routes_full_sync);
success = nm_device_set_ip4_config (self, composite, default_route_metric, commit);
g_object_unref (composite);
if (commit)
@ -6308,7 +6381,6 @@ ip6_config_merge_and_apply (NMDevice *self,
gboolean has_direct_route;
const struct in6_addr *gateway;
gboolean connection_has_default_route, connection_is_never_default;
gboolean routes_full_sync;
gboolean ignore_auto_routes = FALSE;
gboolean ignore_auto_dns = FALSE;
gboolean auto_method = FALSE;
@ -6497,11 +6569,7 @@ END_ADD_DEFAULT_ROUTE:
}
}
routes_full_sync = commit
&& priv->v6_commit_first_time
&& !nm_device_sys_iface_state_is_external_or_assume (self);
success = nm_device_set_ip6_config (self, composite, commit, routes_full_sync);
success = nm_device_set_ip6_config (self, composite, commit);
g_object_unref (composite);
if (commit)
priv->v6_commit_first_time = FALSE;
@ -7319,26 +7387,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
{
NMNDiscConfigMap changed = changed_int;
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int i;
int system_support;
guint32 ifa_flags = 0x00;
/*
* Check, whether kernel is recent enough to help user space handling RA.
* If it's not supported, we have no ipv6-privacy and must add autoconf
* addresses as /128. The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address.
**/
system_support = nm_platform_check_support_kernel_extended_ifa_flags (nm_device_get_platform (self));
if (system_support)
ifa_flags = IFA_F_NOPREFIXROUTE;
if ( priv->ndisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|| priv->ndisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
{
/* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
ifa_flags |= IFA_F_MANAGETEMPADDR;
}
guint i;
g_return_if_fail (priv->act_request);
@ -7354,49 +7403,35 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
}
if (changed & NM_NDISC_CONFIG_ADDRESSES) {
/* Rebuild address list from neighbor discovery cache. */
nm_ip6_config_reset_addresses (priv->ac_ip6_config);
guint8 plen;
guint32 ifa_flags;
/* ndisc->addresses contains at most max_addresses entries.
* This is different from what the kernel does, which
* also counts static and temporary addresses when checking
* max_addresses.
**/
for (i = 0; i < rdata->addresses_n; i++) {
const NMNDiscAddress *discovered_address = &rdata->addresses[i];
NMPlatformIP6Address address;
/* Check, whether kernel is recent enough to help user space handling RA.
* If it's not supported, we have no ipv6-privacy and must add autoconf
* addresses as /128. The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address. */
ifa_flags = 0;
if (nm_platform_check_support_kernel_extended_ifa_flags (nm_device_get_platform (self))) {
ifa_flags |= IFA_F_NOPREFIXROUTE;
if (NM_IN_SET (priv->ndisc_use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR))
ifa_flags |= IFA_F_MANAGETEMPADDR;
plen = 64;
} else
plen = 128;
memset (&address, 0, sizeof (address));
address.address = discovered_address->address;
address.plen = system_support ? 64 : 128;
address.timestamp = discovered_address->timestamp;
address.lifetime = discovered_address->lifetime;
address.preferred = discovered_address->preferred;
if (address.preferred > address.lifetime)
address.preferred = address.lifetime;
address.addr_source = NM_IP_CONFIG_SOURCE_NDISC;
address.n_ifa_flags = ifa_flags;
nm_ip6_config_add_address (priv->ac_ip6_config, &address);
}
nm_ip6_config_reset_addresses_ndisc (priv->ac_ip6_config,
rdata->addresses,
rdata->addresses_n,
plen,
ifa_flags);
}
if (changed & NM_NDISC_CONFIG_ROUTES) {
/* Rebuild route list from neighbor discovery cache. */
nm_ip6_config_reset_routes (priv->ac_ip6_config);
for (i = 0; i < rdata->routes_n; i++) {
const NMNDiscRoute *discovered_route = &rdata->routes[i];
const NMPlatformIP6Route route = {
.network = discovered_route->network,
.plen = discovered_route->plen,
.gateway = discovered_route->gateway,
.rt_source = NM_IP_CONFIG_SOURCE_NDISC,
.metric = nm_device_get_ip6_route_metric (self),
};
nm_ip6_config_add_route (priv->ac_ip6_config, &route);
}
nm_ip6_config_reset_routes_ndisc (priv->ac_ip6_config,
rdata->routes,
rdata->routes_n,
nm_device_get_ip6_route_metric (self));
}
if (changed & NM_NDISC_CONFIG_DNS_SERVERS) {
@ -7696,7 +7731,7 @@ set_nm_ipv6ll (NMDevice *self, gboolean enable)
LOGD_IP6,
"failed to %s userspace IPv6LL address handling (%s)",
detail,
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
}
if (enable) {
@ -9853,46 +9888,35 @@ static gboolean
nm_device_set_ip4_config (NMDevice *self,
NMIP4Config *new_config,
guint32 default_route_metric,
gboolean commit,
gboolean routes_full_sync)
gboolean commit)
{
NMDevicePrivate *priv;
NMIP4Config *old_config = NULL;
gboolean has_changes = FALSE;
gboolean success = TRUE;
gboolean def_route_changed;
int ip_ifindex, config_ifindex;
int ip_ifindex = 0;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
_LOGD (LOGD_IP4, "ip4-config: update (commit=%d, routes-full-sync=%d, new-config=%p)",
commit, routes_full_sync, new_config);
_LOGD (LOGD_IP4, "ip4-config: update (commit=%d, new-config=%p)",
commit, new_config);
nm_assert ( !new_config
|| ( new_config
&& ((ip_ifindex = nm_device_get_ip_ifindex (self)) > 0)
&& ip_ifindex == nm_ip4_config_get_ifindex (new_config)));
priv = NM_DEVICE_GET_PRIVATE (self);
ip_ifindex = nm_device_get_ip_ifindex (self);
if (new_config) {
config_ifindex = nm_ip4_config_get_ifindex (new_config);
if (config_ifindex > 0)
g_return_val_if_fail (ip_ifindex == config_ifindex, FALSE);
}
old_config = priv->ip4_config;
/* Always commit to nm-platform to update lifetimes */
if (commit && new_config) {
gboolean assumed = nm_device_sys_iface_state_is_external_or_assume (self);
_commit_mtu (self, new_config);
/* 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,
nm_device_get_platform (self),
nm_netns_get_route_manager (priv->netns),
ip_ifindex,
routes_full_sync,
assumed ? (gint64) -1 : (gint64) default_route_metric);
default_route_metric);
}
if (new_config) {
@ -10031,29 +10055,26 @@ nm_device_set_wwan_ip4_config (NMDevice *self, NMIP4Config *config)
static gboolean
nm_device_set_ip6_config (NMDevice *self,
NMIP6Config *new_config,
gboolean commit,
gboolean routes_full_sync)
gboolean commit)
{
NMDevicePrivate *priv;
NMIP6Config *old_config = NULL;
gboolean has_changes = FALSE;
gboolean success = TRUE;
gboolean def_route_changed;
int ip_ifindex, config_ifindex;
int ip_ifindex = 0;
g_return_val_if_fail (NM_IS_DEVICE (self), FALSE);
_LOGD (LOGD_IP6, "ip6-config: update (commit=%d, routes-full-sync=%d, new-config=%p)",
commit, routes_full_sync, new_config);
_LOGD (LOGD_IP6, "ip6-config: update (commit=%d, new-config=%p)",
commit, new_config);
nm_assert ( !new_config
|| ( new_config
&& ((ip_ifindex = nm_device_get_ip_ifindex (self)) > 0)
&& ip_ifindex == nm_ip6_config_get_ifindex (new_config)));
priv = NM_DEVICE_GET_PRIVATE (self);
ip_ifindex = nm_device_get_ip_ifindex (self);
if (new_config) {
config_ifindex = nm_ip6_config_get_ifindex (new_config);
if (config_ifindex > 0)
g_return_val_if_fail (ip_ifindex == config_ifindex, FALSE);
}
old_config = priv->ip6_config;
@ -10061,10 +10082,7 @@ nm_device_set_ip6_config (NMDevice *self,
if (commit && new_config) {
_commit_mtu (self, priv->ip4_config);
success = nm_ip6_config_commit (new_config,
nm_device_get_platform (self),
nm_netns_get_route_manager (priv->netns),
ip_ifindex,
routes_full_sync);
nm_device_get_platform (self));
}
if (new_config) {
@ -10900,6 +10918,11 @@ queued_ip4_config_change (gpointer user_data)
set_unmanaged_external_down (self, TRUE);
if (!nm_device_sys_iface_state_is_external_or_assume (self)) {
priv->v4_has_shadowed_routes = _v4_has_shadowed_routes_detect (self);;
ip4_rp_filter_update (self);
}
return FALSE;
}
@ -12105,8 +12128,8 @@ _cleanup_generic_post (NMDevice *self, CleanupType cleanup_type)
/* Clean up IP configs; this does not actually deconfigure the
* interface; the caller must flush routes and addresses explicitly.
*/
nm_device_set_ip4_config (self, NULL, 0, TRUE, TRUE);
nm_device_set_ip6_config (self, NULL, TRUE, TRUE);
nm_device_set_ip4_config (self, NULL, 0, TRUE);
nm_device_set_ip6_config (self, NULL, TRUE);
g_clear_object (&priv->proxy_config);
g_clear_object (&priv->con_ip4_config);
g_clear_object (&priv->dev_ip4_config);
@ -12194,18 +12217,24 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
if (NM_DEVICE_GET_CLASS (self)->deactivate)
NM_DEVICE_GET_CLASS (self)->deactivate (self);
ifindex = nm_device_get_ip_ifindex (self);
if (cleanup_type == CLEANUP_TYPE_DECONFIGURE) {
/* master: release slaves */
nm_device_master_release_slaves (self);
/* Take out any entries in the routing table and any IP address the device had. */
ifindex = nm_device_get_ip_ifindex (self);
if (ifindex > 0) {
nm_route_manager_route_flush (nm_netns_get_route_manager (priv->netns), ifindex);
nm_platform_address_flush (nm_device_get_platform (self), ifindex);
NMPlatform *platform = nm_device_get_platform (self);
nm_platform_ip_route_flush (platform, AF_UNSPEC, ifindex);
nm_platform_ip_address_flush (platform, AF_UNSPEC, ifindex);
}
}
if (ifindex > 0)
nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), ifindex, NULL);
/* slave: mark no longer enslaved */
if ( priv->master
&& nm_platform_link_get_master (nm_device_get_platform (self), priv->ifindex) <= 0)
@ -13370,7 +13399,7 @@ handle_fail:
_NMLOG (plerr == NM_PLATFORM_ERROR_NOT_FOUND ? LOGL_DEBUG : LOGL_WARN,
LOGD_DEVICE, "set-hw-addr: failed to %s MAC address to %s (%s) (%s)",
operation, addr, detail,
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
}
if (was_up) {
@ -13851,9 +13880,6 @@ constructed (GObject *object)
g_signal_connect (platform, NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED, G_CALLBACK (device_ipx_changed), self);
g_signal_connect (platform, NM_PLATFORM_SIGNAL_LINK_CHANGED, G_CALLBACK (link_changed_cb), self);
g_signal_connect (nm_netns_get_route_manager (priv->netns), NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED,
G_CALLBACK (ip4_routes_changed_changed_cb), self);
priv->settings = g_object_ref (NM_SETTINGS_GET);
g_assert (priv->settings);
@ -13894,9 +13920,6 @@ dispose (GObject *object)
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ipx_changed), self);
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self);
g_signal_handlers_disconnect_by_func (nm_netns_get_route_manager (priv->netns),
G_CALLBACK (ip4_routes_changed_changed_cb), self);
g_slist_free_full (priv->arping.dad_list, (GDestroyNotify) nm_arping_manager_destroy);
priv->arping.dad_list = NULL;

View file

@ -774,7 +774,7 @@ create_and_realize (NMDevice *device,
"Failed to create team master interface '%s' for '%s': %s",
iface,
nm_connection_get_id (connection),
nm_platform_error_to_string (plerr));
nm_platform_error_to_string_a (plerr));
return FALSE;
}

View file

@ -32,7 +32,6 @@
#include "nm-setting-connection.h"
#include "NetworkManagerUtils.h"
#include "devices/nm-device-private.h"
#include "nm-route-manager.h"
#include "nm-netns.h"
#include "nm-act-request.h"
#include "nm-ip4-config.h"
@ -1066,10 +1065,11 @@ deactivate_cleanup (NMModem *self, NMDevice *device)
priv->ip6_method == NM_MODEM_IP_METHOD_AUTO) {
ifindex = nm_device_get_ip_ifindex (device);
if (ifindex > 0) {
nm_route_manager_route_flush (nm_netns_get_route_manager (nm_device_get_netns (device)),
ifindex);
nm_platform_address_flush (nm_device_get_platform (device), ifindex);
nm_platform_link_set_down (nm_device_get_platform (device), ifindex);
NMPlatform *platform = nm_device_get_platform (device);
nm_platform_ip_route_flush (platform, AF_UNSPEC, ifindex);
nm_platform_ip_address_flush (platform, AF_UNSPEC, ifindex);
nm_platform_link_set_down (platform, ifindex);
}
}
}

View file

@ -69,22 +69,24 @@ typedef struct {
NMNDiscPreference preference;
} NMNDiscGateway;
typedef struct {
struct _NMNDiscAddress {
struct in6_addr address;
guint8 dad_counter;
guint32 timestamp;
guint32 lifetime;
guint32 preferred;
} NMNDiscAddress;
};
typedef struct _NMNDiscAddress NMNDiscAddress;
typedef struct {
struct _NMNDiscRoute {
struct in6_addr network;
guint8 plen;
struct in6_addr gateway;
guint32 timestamp;
guint32 lifetime;
NMNDiscPreference preference;
} NMNDiscRoute;
};
typedef struct _NMNDiscRoute NMNDiscRoute;
typedef struct {
struct in6_addr address;

View file

@ -2146,7 +2146,7 @@ monotonic_timestamp_get (struct timespec *tp)
break;
case 2:
/* fallback, return CLOCK_MONOTONIC. Kernels prior to 2.6.39
* don't support CLOCK_BOOTTIME. */
* (released on 18 May, 2011) don't support CLOCK_BOOTTIME. */
err = clock_gettime (CLOCK_MONOTONIC, tp);
break;
}

View file

@ -304,7 +304,7 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g
rt.plen = 0;
rt.metric = entry->effective_metric;
success = nm_platform_ip4_route_add (priv->platform, NMP_NLM_FLAG_REPLACE, &rt);
success = (nm_platform_ip4_route_add (priv->platform, NMP_NLM_FLAG_REPLACE, &rt) == NM_PLATFORM_ERROR_SUCCESS);
} else {
NMPlatformIP6Route rt = entry->route.r6;
@ -312,7 +312,7 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g
rt.plen = 0;
rt.metric = entry->effective_metric;
success = nm_platform_ip6_route_add (priv->platform, NMP_NLM_FLAG_REPLACE, &rt);
success = (nm_platform_ip6_route_add (priv->platform, NMP_NLM_FLAG_REPLACE, &rt) == NM_PLATFORM_ERROR_SUCCESS);
}
if (!success) {
_LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u",
@ -334,7 +334,7 @@ _platform_route_sync_flush (const VTableIP *vtable, NMDefaultRouteManager *self,
routes = nm_platform_lookup_route_default_clone (priv->platform,
vtable->vt->obj_type,
nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
NULL);
if (!routes)
return FALSE;
@ -515,7 +515,7 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
routes = nm_platform_lookup_route_default_clone (priv->platform,
vtable->vt->obj_type,
nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
NULL);
assumed_metrics = _get_assumed_interface_metrics (vtable, self, routes);

View file

@ -42,7 +42,6 @@
#include "nm-utils.h"
#include "nm-setting-ip6-config.h"
#include "systemd/nm-sd.h"
#include "nm-route-manager.h"
#if !defined(NM_DIST_VERSION)
# define NM_DIST_VERSION VERSION
@ -98,12 +97,6 @@ static struct {
/*****************************************************************************/
NMRouteManager *route_manager_get (void);
NM_DEFINE_SINGLETON_GETTER (NMRouteManager, route_manager_get, NM_TYPE_ROUTE_MANAGER);
/*****************************************************************************/
static void
dhcp4_state_changed (NMDhcpClient *client,
NMDhcpState state,
@ -122,13 +115,17 @@ dhcp4_state_changed (NMDhcpClient *client,
switch (state) {
case NM_DHCP_STATE_BOUND:
g_assert (ip4_config);
g_assert (nm_ip4_config_get_ifindex (ip4_config) == gl.ifindex);
existing = nm_ip4_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex, FALSE);
if (last_config)
nm_ip4_config_subtract (existing, last_config);
nm_ip4_config_merge (existing, ip4_config, NM_IP_CONFIG_MERGE_DEFAULT);
if (!nm_ip4_config_commit (existing, NM_PLATFORM_GET, route_manager_get (), gl.ifindex, TRUE, global_opt.priority_v4))
if (!nm_ip4_config_commit (existing,
NM_PLATFORM_GET,
global_opt.priority_v4))
_LOGW (LOGD_DHCP4, "failed to apply DHCPv4 config");
if (last_config)
@ -157,27 +154,6 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
NMNDiscConfigMap changed = changed_int;
static NMIP6Config *ndisc_config = NULL;
NMIP6Config *existing;
int system_support;
guint32 ifa_flags = 0x00;
int i;
/*
* Check, whether kernel is recent enough, to help user space handling RA.
* If it's not supported, we have no ipv6-privacy and must add autoconf
* addresses as /128.
* The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address.
**/
system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
if (system_support)
ifa_flags = IFA_F_NOPREFIXROUTE;
if (global_opt.tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|| global_opt.tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
{
/* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
ifa_flags |= IFA_F_MANAGETEMPADDR;
}
existing = nm_ip6_config_capture (nm_platform_get_multi_idx (NM_PLATFORM_GET),
NM_PLATFORM_GET, gl.ifindex, FALSE, global_opt.tempaddr);
@ -197,49 +173,35 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
}
if (changed & NM_NDISC_CONFIG_ADDRESSES) {
/* Rebuild address list from neighbor discovery cache. */
nm_ip6_config_reset_addresses (ndisc_config);
guint8 plen;
guint32 ifa_flags;
/* ndisc->addresses contains at most max_addresses entries.
* This is different from what the kernel does, which
* also counts static and temporary addresses when checking
* max_addresses.
**/
for (i = 0; i < rdata->addresses_n; i++) {
const NMNDiscAddress *discovered_address = &rdata->addresses[i];
NMPlatformIP6Address address;
/* Check, whether kernel is recent enough to help user space handling RA.
* If it's not supported, we have no ipv6-privacy and must add autoconf
* addresses as /128. The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address. */
ifa_flags = 0;
if (nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET)) {
ifa_flags |= IFA_F_NOPREFIXROUTE;
if (NM_IN_SET (global_opt.tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR,
NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR))
ifa_flags |= IFA_F_MANAGETEMPADDR;
plen = 64;
} else
plen = 128;
memset (&address, 0, sizeof (address));
address.address = discovered_address->address;
address.plen = system_support ? 64 : 128;
address.timestamp = discovered_address->timestamp;
address.lifetime = discovered_address->lifetime;
address.preferred = discovered_address->preferred;
if (address.preferred > address.lifetime)
address.preferred = address.lifetime;
address.addr_source = NM_IP_CONFIG_SOURCE_NDISC;
address.n_ifa_flags = ifa_flags;
nm_ip6_config_add_address (ndisc_config, &address);
}
nm_ip6_config_reset_addresses_ndisc (ndisc_config,
rdata->addresses,
rdata->addresses_n,
plen,
ifa_flags);
}
if (changed & NM_NDISC_CONFIG_ROUTES) {
/* Rebuild route list from neighbor discovery cache. */
nm_ip6_config_reset_routes (ndisc_config);
for (i = 0; i < rdata->routes_n; i++) {
const NMNDiscRoute *discovered_route = &rdata->routes[i];
const NMPlatformIP6Route route = {
.network = discovered_route->network,
.plen = discovered_route->plen,
.gateway = discovered_route->gateway,
.rt_source = NM_IP_CONFIG_SOURCE_NDISC,
.metric = global_opt.priority_v6,
};
nm_ip6_config_add_route (ndisc_config, &route);
}
nm_ip6_config_reset_routes_ndisc (ndisc_config,
rdata->routes,
rdata->routes_n,
global_opt.priority_v6);
}
if (changed & NM_NDISC_CONFIG_DHCP_LEVEL) {
@ -257,7 +219,7 @@ ndisc_config_changed (NMNDisc *ndisc, const NMNDiscData *rdata, guint changed_in
}
nm_ip6_config_merge (existing, ndisc_config, NM_IP_CONFIG_MERGE_DEFAULT);
if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET, route_manager_get (), gl.ifindex, TRUE))
if (!nm_ip6_config_commit (existing, NM_PLATFORM_GET))
_LOGW (LOGD_IP6, "failed to apply IPv6 config");
}

View file

@ -33,7 +33,6 @@
#include "platform/nm-platform.h"
#include "platform/nm-platform-utils.h"
#include "NetworkManagerUtils.h"
#include "nm-route-manager.h"
#include "nm-core-internal.h"
#include "introspection/org.freedesktop.NetworkManager.IP4Config.h"
@ -164,7 +163,9 @@ _nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx,
NMIPConfigDedupMultiIdxType *idx_type,
int ifindex,
const NMPObject *obj_new,
const NMPlatformObject *pl_new)
const NMPlatformObject *pl_new,
gboolean merge,
gboolean append_force)
{
NMPObject obj_new_stackinit;
const NMDedupMultiEntry *entry_old;
@ -201,58 +202,62 @@ _nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx,
const NMPObject *obj_old = entry_old->obj;
if (nmp_object_equal (obj_new, obj_old))
return FALSE;
goto append_force_and_out;
switch (idx_type->obj_type) {
case NMP_OBJECT_TYPE_IP4_ADDRESS:
case NMP_OBJECT_TYPE_IP6_ADDRESS:
/* we want to keep the maximum addr_source. But since we expect
* that usually we already add the maxiumum right away, we first try to
* add the new address (replacing the old one). Only if we later
* find out that addr_source is now lower, we fix it.
*/
if (obj_new->ip_address.addr_source < obj_old->ip_address.addr_source) {
obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new);
obj_new_stackinit.ip_address.addr_source = obj_old->ip_address.addr_source;
modified = TRUE;
/* if @merge, we merge the new object with the existing one.
* Otherwise, we replace it entirely. */
if (merge) {
switch (idx_type->obj_type) {
case NMP_OBJECT_TYPE_IP4_ADDRESS:
case NMP_OBJECT_TYPE_IP6_ADDRESS:
/* we want to keep the maximum addr_source. But since we expect
* that usually we already add the maxiumum right away, we first try to
* add the new address (replacing the old one). Only if we later
* find out that addr_source is now lower, we fix it.
*/
if (obj_new->ip_address.addr_source < obj_old->ip_address.addr_source) {
obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new);
obj_new_stackinit.ip_address.addr_source = obj_old->ip_address.addr_source;
modified = TRUE;
}
/* for addresses that we read from the kernel, we keep the timestamps as defined
* by the previous source (item_old). The reason is, that the other source configured the lifetimes
* with "what should be" and the kernel values are "what turned out after configuring it".
*
* For other sources, the longer lifetime wins. */
if ( ( obj_new->ip_address.addr_source == NM_IP_CONFIG_SOURCE_KERNEL
&& obj_old->ip_address.addr_source != NM_IP_CONFIG_SOURCE_KERNEL)
|| nm_platform_ip_address_cmp_expiry (NMP_OBJECT_CAST_IP_ADDRESS (obj_old), NMP_OBJECT_CAST_IP_ADDRESS(obj_new)) > 0) {
obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new);
obj_new_stackinit.ip_address.timestamp = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->timestamp;
obj_new_stackinit.ip_address.lifetime = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->lifetime;
obj_new_stackinit.ip_address.preferred = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->preferred;
modified = TRUE;
}
break;
case NMP_OBJECT_TYPE_IP4_ROUTE:
case NMP_OBJECT_TYPE_IP6_ROUTE:
/* we want to keep the maximum rt_source. But since we expect
* that usually we already add the maxiumum right away, we first try to
* add the new route (replacing the old one). Only if we later
* find out that rt_source is now lower, we fix it.
*/
if (obj_new->ip_route.rt_source < obj_old->ip_route.rt_source) {
obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new);
obj_new_stackinit.ip_route.rt_source = obj_old->ip_route.rt_source;
modified = TRUE;
}
break;
default:
nm_assert_not_reached ();
break;
}
/* for addresses that we read from the kernel, we keep the timestamps as defined
* by the previous source (item_old). The reason is, that the other source configured the lifetimes
* with "what should be" and the kernel values are "what turned out after configuring it".
*
* For other sources, the longer lifetime wins. */
if ( ( obj_new->ip_address.addr_source == NM_IP_CONFIG_SOURCE_KERNEL
&& obj_old->ip_address.addr_source != NM_IP_CONFIG_SOURCE_KERNEL)
|| nm_platform_ip_address_cmp_expiry (NMP_OBJECT_CAST_IP_ADDRESS (obj_old), NMP_OBJECT_CAST_IP_ADDRESS(obj_new)) > 0) {
obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new);
obj_new_stackinit.ip_address.timestamp = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->timestamp;
obj_new_stackinit.ip_address.lifetime = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->lifetime;
obj_new_stackinit.ip_address.preferred = NMP_OBJECT_CAST_IP_ADDRESS (obj_old)->preferred;
modified = TRUE;
}
break;
case NMP_OBJECT_TYPE_IP4_ROUTE:
case NMP_OBJECT_TYPE_IP6_ROUTE:
/* we want to keep the maximum rt_source. But since we expect
* that usually we already add the maxiumum right away, we first try to
* add the new route (replacing the old one). Only if we later
* find out that rt_source is now lower, we fix it.
*/
if (obj_new->ip_route.rt_source < obj_old->ip_route.rt_source) {
obj_new = nmp_object_stackinit_obj (&obj_new_stackinit, obj_new);
obj_new_stackinit.ip_route.rt_source = obj_old->ip_route.rt_source;
modified = TRUE;
}
break;
default:
nm_assert_not_reached ();
break;
if ( modified
&& nmp_object_equal (obj_new, obj_old))
goto append_force_and_out;
}
if ( modified
&& nmp_object_equal (obj_new, obj_old))
return FALSE;
}
if (!nm_dedup_multi_index_add_full (multi_idx,
@ -269,6 +274,55 @@ _nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx,
}
return TRUE;
append_force_and_out:
if (append_force) {
if (nm_dedup_multi_entry_reorder (entry_old, NULL, TRUE))
return TRUE;
}
return FALSE;
}
/**
* _nm_ip_config_lookup_ip_route:
* @multi_idx:
* @idx_type:
* @needle:
* @cmp_type: after lookup, filter the result by comparing with @cmp_type. Only
* return the result, if it compares equal to @needle according to this @cmp_type.
* Note that the index uses %NM_PLATFORM_IP_ROUTE_CMP_TYPE_DST type, so passing
* that compare-type means not to filter any further.
*
* Returns: the found entry or %NULL.
*/
const NMDedupMultiEntry *
_nm_ip_config_lookup_ip_route (const NMDedupMultiIndex *multi_idx,
const NMIPConfigDedupMultiIdxType *idx_type,
const NMPObject *needle,
NMPlatformIPRouteCmpType cmp_type)
{
const NMDedupMultiEntry *entry;
nm_assert (multi_idx);
nm_assert (idx_type);
nm_assert (NM_IN_SET (idx_type->obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
nm_assert (NMP_OBJECT_GET_TYPE (needle) == idx_type->obj_type);
entry = nm_dedup_multi_index_lookup_obj (multi_idx,
&idx_type->parent,
needle);
if (!entry)
return NULL;
if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_DST)
nm_assert (nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (entry->obj), NMP_OBJECT_CAST_IP4_ROUTE (needle), cmp_type) == 0);
else {
if (nm_platform_ip4_route_cmp (NMP_OBJECT_CAST_IP4_ROUTE (entry->obj),
NMP_OBJECT_CAST_IP4_ROUTE (needle),
cmp_type) != 0)
return NULL;
}
return entry;
}
/*****************************************************************************/
@ -339,6 +393,9 @@ G_DEFINE_TYPE (NMIP4Config, nm_ip4_config, NM_TYPE_EXPORTED_OBJECT)
static void _add_address (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Address *new);
static void _add_route (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Route *new);
static const NMDedupMultiEntry *_lookup_route (const NMIP4Config *self,
const NMPObject *needle,
NMPlatformIPRouteCmpType cmp_type);
/*****************************************************************************/
@ -624,16 +681,6 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
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 (self, plobj, NULL);
}
@ -656,92 +703,122 @@ nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
}
gboolean
nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric)
nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform,
guint32 default_route_metric)
{
const NMIP4ConfigPrivate *priv;
gs_unref_ptrarray GPtrArray *addresses = NULL;
const NMDedupMultiHeadEntry *head_entry;
gs_unref_ptrarray GPtrArray *routes = NULL;
gs_unref_ptrarray GPtrArray *ip4_dev_route_blacklist = NULL;
int ifindex;
guint i;
gboolean success = TRUE;
g_return_val_if_fail (NM_IS_IP4_CONFIG (self), FALSE);
priv = NM_IP4_CONFIG_GET_PRIVATE (self);
ifindex = nm_ip4_config_get_ifindex (self);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (self != NULL, FALSE);
addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_addresses (self),
NULL, NULL);
nm_platform_ip4_address_sync (platform, ifindex, addresses);
routes = nm_dedup_multi_objs_to_ptr_array_head (nm_ip4_config_lookup_routes (self),
NULL, NULL);
/* Routes */
{
guint i;
gs_unref_array GArray *routes = NULL;
gs_unref_array GArray *device_route_purge_list = NULL;
const CList *iter;
if (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 (i = 0; i < addresses->len; i++) {
const NMPObject *o = addresses->pdata[i];
const NMPlatformIP4Address *addr;
nm_auto_nmpobj NMPObject *r = NULL;
NMPlatformIP4Route *route;
in_addr_t network;
head_entry = nm_ip4_config_lookup_routes (self);
if (!o)
continue;
routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP4Route), head_entry ? head_entry->len : 0);
addr = NMP_OBJECT_CAST_IP4_ADDRESS (o);
if (addr->plen == 0)
continue;
if ( default_route_metric >= 0
&& 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 < addresses->len; i++) {
const NMPObject *o = addresses->pdata[i];
const NMPlatformIP4Address *addr;
NMPlatformIP4Route route = { 0 };
nm_assert (addr->plen <= 32);
if (!o)
continue;
/* The destination network depends on the peer-address. */
network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen);
addr = NMP_OBJECT_CAST_IP4_ADDRESS (o);
if (addr->plen == 0)
continue;
if (_ipv4_is_zeronet (network)) {
/* Kernel doesn't add device-routes for destinations that
* start with 0.x.y.z. Skip them. */
continue;
}
nm_assert (addr->plen <= 32);
r = nmp_object_new (NMP_OBJECT_TYPE_IP4_ROUTE, NULL);
route = NMP_OBJECT_CAST_IP4_ROUTE (r);
route.ifindex = ifindex;
route.rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
route->ifindex = ifindex;
route->rt_source = NM_IP_CONFIG_SOURCE_KERNEL;
route->network = network;
route->plen = addr->plen;
route->pref_src = addr->address;
route->metric = default_route_metric;
route->scope_inv = nm_platform_route_scope_inv (NM_RT_SCOPE_LINK);
/* The destination network depends on the peer-address. */
route.network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen);
nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route);
if (_ipv4_is_zeronet (route.network)) {
/* Kernel doesn't add device-routes for destinations that
* start with 0.x.y.z. Skip them. */
continue;
}
if (_lookup_route (self,
r,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) {
/* we already track this route. Don't add it again. */
} else {
if (!routes)
routes = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
g_ptr_array_add (routes, (gpointer) nmp_object_ref (r));
}
route.plen = addr->plen;
route.pref_src = addr->address;
route.metric = default_route_metric;
if (default_route_metric != NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_ROUTE) {
nm_auto_nmpobj NMPObject *r_dev = NULL;
g_array_append_val (routes, route);
r_dev = nmp_object_clone (r, FALSE);
route = NMP_OBJECT_CAST_IP4_ROUTE (r_dev);
route->metric = NM_PLATFORM_ROUTE_METRIC_IP4_DEVICE_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);
nm_platform_ip_route_normalize (AF_INET, (NMPlatformIPRoute *) route);
if (_lookup_route (self,
r_dev,
NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID)) {
/* we track such a route explicitly. Don't blacklist it. */
} else {
if (!ip4_dev_route_blacklist)
ip4_dev_route_blacklist = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
g_ptr_array_add (ip4_dev_route_blacklist,
g_steal_pointer (&r_dev));
}
}
}
if (head_entry) {
c_list_for_each (iter, &head_entry->lst_entries_head) {
g_array_append_vals (routes,
NMP_OBJECT_CAST_IP4_ROUTE (c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj),
1);
}
}
nm_route_manager_ip4_route_register_device_route_purge_list (route_manager, device_route_purge_list);
if (!nm_route_manager_ip4_route_sync (route_manager, ifindex, routes,
default_route_metric < 0, routes_full_sync))
return FALSE;
}
return TRUE;
nm_platform_ip4_address_sync (platform, ifindex, addresses);
if (!nm_platform_ip_route_sync (platform,
AF_INET,
ifindex,
routes,
nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
NULL))
success = FALSE;
nm_platform_ip4_dev_route_blacklist_set (platform,
ifindex,
ip4_dev_route_blacklist);
return success;
}
static void
@ -841,6 +918,11 @@ nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guin
NMIPRoute *s_route = nm_setting_ip_config_get_route (setting, i);
NMPlatformIP4Route route;
if (nm_ip_route_get_family (s_route) != AF_INET) {
nm_assert_not_reached ();
continue;
}
memset (&route, 0, sizeof (route));
nm_ip_route_get_dest_binary (s_route, &route.network);
@ -1228,7 +1310,8 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
nm_ip_config_iter_ip4_address_for_each (&ipconf_iter, src, &a) {
if (nm_dedup_multi_index_remove_obj (priv_dst->multi_idx,
&priv_dst->idx_ip4_addresses,
NMP_OBJECT_UP_CAST (a)))
NMP_OBJECT_UP_CAST (a),
NULL))
changed = TRUE;
}
if (changed)
@ -1256,7 +1339,8 @@ nm_ip4_config_subtract (NMIP4Config *dst, const NMIP4Config *src)
nm_ip_config_iter_ip4_route_for_each (&ipconf_iter, src, &r) {
if (nm_dedup_multi_index_remove_obj (priv_dst->multi_idx,
&priv_dst->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r)))
NMP_OBJECT_UP_CAST (r),
NULL))
changed = TRUE;
}
if (changed)
@ -1885,7 +1969,9 @@ _add_address (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Ad
&priv->idx_ip4_addresses_,
priv->ifindex,
obj_new,
(const NMPlatformObject *) new))
(const NMPlatformObject *) new,
TRUE,
FALSE))
_notify_addresses (self);
}
@ -1921,7 +2007,8 @@ _nmtst_nm_ip4_config_del_address (NMIP4Config *self, guint i)
if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
&priv->idx_ip4_addresses,
NMP_OBJECT_UP_CAST (a)) != 1)
NMP_OBJECT_UP_CAST (a),
NULL) != 1)
g_return_if_reached ();
_notify_addresses (self);
}
@ -1975,12 +2062,30 @@ nm_ip4_config_address_exists (const NMIP4Config *self,
needle->plen,
needle->peer_address);
return !!nm_dedup_multi_index_lookup_obj (priv->multi_idx,
&priv->idx_ip4_routes,
&priv->idx_ip4_addresses,
&obj_stack);
}
/*****************************************************************************/
static const NMDedupMultiEntry *
_lookup_route (const NMIP4Config *self,
const NMPObject *needle,
NMPlatformIPRouteCmpType cmp_type)
{
const NMIP4ConfigPrivate *priv;
nm_assert (NM_IS_IP4_CONFIG (self));
nm_assert (NMP_OBJECT_GET_TYPE (needle) == NMP_OBJECT_TYPE_IP4_ROUTE);
priv = NM_IP4_CONFIG_GET_PRIVATE (self);
return _nm_ip_config_lookup_ip_route (priv->multi_idx,
&priv->idx_ip4_routes_,
needle,
cmp_type);
}
void
nm_ip4_config_reset_routes (NMIP4Config *self)
{
@ -2004,7 +2109,9 @@ _add_route (NMIP4Config *self, const NMPObject *obj_new, const NMPlatformIP4Rout
&priv->idx_ip4_routes_,
priv->ifindex,
obj_new,
(const NMPlatformObject *) new))
(const NMPlatformObject *) new,
TRUE,
FALSE))
_notify_routes (self);
}
@ -2040,7 +2147,8 @@ _nmtst_nm_ip4_config_del_route (NMIP4Config *self, guint i)
if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
&priv->idx_ip4_routes,
NMP_OBJECT_UP_CAST (r)) != 1)
NMP_OBJECT_UP_CAST (r),
NULL) != 1)
g_return_if_reached ();
_notify_routes (self);
}

View file

@ -92,7 +92,14 @@ gboolean _nm_ip_config_add_obj (NMDedupMultiIndex *multi_idx,
NMIPConfigDedupMultiIdxType *idx_type,
int ifindex,
const NMPObject *obj_new,
const NMPlatformObject *pl_new);
const NMPlatformObject *pl_new,
gboolean merge,
gboolean append_force);
const NMDedupMultiEntry *_nm_ip_config_lookup_ip_route (const NMDedupMultiIndex *multi_idx,
const NMIPConfigDedupMultiIdxType *idx_type,
const NMPObject *needle,
NMPlatformIPRouteCmpType cmp_type);
/*****************************************************************************/
@ -135,7 +142,9 @@ int nm_ip4_config_get_ifindex (const NMIP4Config *self);
NMDedupMultiIndex *nm_ip4_config_get_multi_idx (const NMIP4Config *self);
NMIP4Config *nm_ip4_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex, gboolean capture_resolv_conf);
gboolean nm_ip4_config_commit (const NMIP4Config *self, NMPlatform *platform, NMRouteManager *route_manager, int ifindex, gboolean routes_full_sync, gint64 default_route_metric);
gboolean nm_ip4_config_commit (const NMIP4Config *self,
NMPlatform *platform,
guint32 default_route_metric);
void nm_ip4_config_merge_setting (NMIP4Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip4_config_create_setting (const NMIP4Config *self);

View file

@ -32,10 +32,10 @@
#include "platform/nmp-object.h"
#include "platform/nm-platform.h"
#include "platform/nm-platform-utils.h"
#include "nm-route-manager.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
#include "nm-ip4-config.h"
#include "ndisc/nm-ndisc.h"
#include "introspection/org.freedesktop.NetworkManager.IP6Config.h"
@ -483,15 +483,6 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (route))
continue;
if ( has_gateway
&& route->plen == 128
&& IN6_ARE_ADDR_EQUAL (&route->network, &priv->gateway)
&& IN6_IS_ADDR_UNSPECIFIED (&route->gateway)) {
/* If there is a host route to the gateway, ignore that route. It is
* automatically added by NetworkManager when needed.
*/
continue;
}
_add_route (self, plobj, NULL);
}
@ -516,45 +507,33 @@ nm_ip6_config_capture (NMDedupMultiIndex *multi_idx, NMPlatform *platform, int i
gboolean
nm_ip6_config_commit (const NMIP6Config *self,
NMPlatform *platform,
NMRouteManager *route_manager,
int ifindex,
gboolean routes_full_sync)
NMPlatform *platform)
{
gs_unref_ptrarray GPtrArray *addresses = NULL;
const NMDedupMultiHeadEntry *head_entry;
gs_unref_ptrarray GPtrArray *routes = NULL;
int ifindex;
gboolean success = TRUE;
g_return_val_if_fail (NM_IS_IP6_CONFIG (self), FALSE);
ifindex = nm_ip6_config_get_ifindex (self);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (self != NULL, FALSE);
/* Addresses */
addresses = nm_dedup_multi_objs_to_ptr_array_head (nm_ip6_config_lookup_addresses (self),
NULL, NULL);
routes = nm_dedup_multi_objs_to_ptr_array_head (nm_ip6_config_lookup_routes (self),
NULL, NULL);
nm_platform_ip6_address_sync (platform, ifindex, addresses, TRUE);
/* Routes */
{
gs_unref_array GArray *routes = NULL;
const CList *iter;
if (!nm_platform_ip_route_sync (platform,
AF_INET6,
ifindex,
routes,
nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
NULL))
success = FALSE;
head_entry = nm_ip6_config_lookup_routes (self);
routes = g_array_sized_new (FALSE, FALSE, sizeof (NMPlatformIP6Route), head_entry ? head_entry->len : 0);
if (head_entry) {
c_list_for_each (iter, &head_entry->lst_entries_head) {
g_array_append_vals (routes,
NMP_OBJECT_CAST_IP6_ROUTE (c_list_entry (iter, NMDedupMultiEntry, lst_entries)->obj),
1);
}
}
if (!nm_route_manager_ip6_route_sync (route_manager, ifindex, routes, TRUE, routes_full_sync))
return FALSE;
}
return TRUE;
return success;
}
static void
@ -668,6 +647,11 @@ nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guin
NMIPRoute *s_route = nm_setting_ip_config_get_route (setting, i);
NMPlatformIP6Route route;
if (nm_ip_route_get_family (s_route) != AF_INET6) {
nm_assert_not_reached ();
continue;
}
memset (&route, 0, sizeof (route));
nm_ip_route_get_dest_binary (s_route, &route.network);
@ -1025,7 +1009,8 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
nm_ip_config_iter_ip6_address_for_each (&ipconf_iter, src, &a) {
if (nm_dedup_multi_index_remove_obj (priv_dst->multi_idx,
&priv_dst->idx_ip6_addresses,
NMP_OBJECT_UP_CAST (a)))
NMP_OBJECT_UP_CAST (a),
NULL))
changed = TRUE;
}
if (changed)
@ -1054,7 +1039,8 @@ nm_ip6_config_subtract (NMIP6Config *dst, const NMIP6Config *src)
nm_ip_config_iter_ip6_route_for_each (&ipconf_iter, src, &r) {
if (nm_dedup_multi_index_remove_obj (priv_dst->multi_idx,
&priv_dst->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r)))
NMP_OBJECT_UP_CAST (r),
NULL))
changed = TRUE;
}
if (changed)
@ -1200,6 +1186,8 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
dst_priv = NM_IP6_CONFIG_GET_PRIVATE (dst);
src_priv = NM_IP6_CONFIG_GET_PRIVATE (src);
g_return_val_if_fail (src_priv->ifindex > 0, FALSE);
g_object_freeze_notify (G_OBJECT (dst));
/* ifindex */
@ -1259,12 +1247,13 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
has_minor_changes = TRUE;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_addresses);
nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) {
nm_dedup_multi_index_add (dst_priv->multi_idx,
&dst_priv->idx_ip6_addresses,
ipconf_iter_src.current->obj,
NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE,
NULL,
NULL);
_nm_ip_config_add_obj (dst_priv->multi_idx,
&dst_priv->idx_ip6_addresses_,
dst_priv->ifindex,
ipconf_iter_src.current->obj,
NULL,
FALSE,
TRUE);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_addresses, FALSE);
_notify_addresses (dst);
@ -1303,12 +1292,13 @@ nm_ip6_config_replace (NMIP6Config *dst, const NMIP6Config *src, gboolean *relev
has_minor_changes = TRUE;
nm_dedup_multi_index_dirty_set_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes);
nm_dedup_multi_iter_for_each (&ipconf_iter_src, head_entry_src) {
nm_dedup_multi_index_add (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes,
ipconf_iter_src.current->obj,
NM_DEDUP_MULTI_IDX_MODE_APPEND_FORCE,
NULL,
NULL);
_nm_ip_config_add_obj (dst_priv->multi_idx,
&dst_priv->idx_ip6_routes_,
dst_priv->ifindex,
ipconf_iter_src.current->obj,
NULL,
FALSE,
TRUE);
}
nm_dedup_multi_index_dirty_remove_idx (dst_priv->multi_idx, &dst_priv->idx_ip6_routes, FALSE);
_notify_routes (dst);
@ -1529,6 +1519,58 @@ nm_ip6_config_get_route_metric (const NMIP6Config *self)
/*****************************************************************************/
void
nm_ip6_config_reset_addresses_ndisc (NMIP6Config *self,
const NMNDiscAddress *addresses,
guint addresses_n,
guint8 plen,
guint32 ifa_flags)
{
NMIP6ConfigPrivate *priv;
guint i;
gboolean changed = FALSE;
g_return_if_fail (NM_IS_IP6_CONFIG (self));
priv = NM_IP6_CONFIG_GET_PRIVATE (self);
g_return_if_fail (priv->ifindex > 0);
nm_dedup_multi_index_dirty_set_idx (priv->multi_idx, &priv->idx_ip6_addresses);
for (i = 0; i < addresses_n; i++) {
const NMNDiscAddress *ndisc_addr = &addresses[i];
NMPObject obj;
NMPlatformIP6Address *a;
nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ADDRESS, NULL);
a = NMP_OBJECT_CAST_IP6_ADDRESS (&obj);
a->ifindex = priv->ifindex;
a->address = ndisc_addr->address;
a->plen = plen;
a->timestamp = ndisc_addr->timestamp;
a->lifetime = ndisc_addr->lifetime;
a->preferred = MIN (ndisc_addr->lifetime, ndisc_addr->preferred);
a->addr_source = NM_IP_CONFIG_SOURCE_NDISC;
a->n_ifa_flags = ifa_flags;
if (_nm_ip_config_add_obj (priv->multi_idx,
&priv->idx_ip6_addresses_,
priv->ifindex,
&obj,
NULL,
FALSE,
TRUE))
changed = TRUE;
}
if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_addresses, FALSE) > 0)
changed = TRUE;
if (changed)
_notify_addresses (self);
}
void
nm_ip6_config_reset_addresses (NMIP6Config *self)
{
@ -1550,7 +1592,9 @@ _add_address (NMIP6Config *self,
&priv->idx_ip6_addresses_,
priv->ifindex,
obj_new,
(const NMPlatformObject *) new))
(const NMPlatformObject *) new,
TRUE,
FALSE))
_notify_addresses (self);
}
@ -1586,7 +1630,8 @@ _nmtst_nm_ip6_config_del_address (NMIP6Config *self, guint i)
if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
&priv->idx_ip6_addresses,
NMP_OBJECT_UP_CAST (a)) != 1)
NMP_OBJECT_UP_CAST (a),
NULL) != 1)
g_return_if_reached ();
_notify_addresses (self);
}
@ -1704,6 +1749,55 @@ nm_ip6_config_has_any_dad_pending (const NMIP6Config *self,
/*****************************************************************************/
void
nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
const NMNDiscRoute *routes,
guint routes_n,
guint32 metric)
{
NMIP6ConfigPrivate *priv;
guint i;
gboolean changed = FALSE;
g_return_if_fail (NM_IS_IP6_CONFIG (self));
priv = NM_IP6_CONFIG_GET_PRIVATE (self);
g_return_if_fail (priv->ifindex > 0);
nm_dedup_multi_index_dirty_set_idx (priv->multi_idx, &priv->idx_ip6_routes);
for (i = 0; i < routes_n; i++) {
const NMNDiscRoute *ndisc_route = &routes[i];
NMPObject obj;
NMPlatformIP6Route *r;
nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
r = NMP_OBJECT_CAST_IP6_ROUTE (&obj);
r->ifindex = priv->ifindex;
r->network = ndisc_route->network;
r->plen = ndisc_route->plen;
r->gateway = ndisc_route->gateway;
r->rt_source = NM_IP_CONFIG_SOURCE_NDISC;
r->metric = metric;
if (_nm_ip_config_add_obj (priv->multi_idx,
&priv->idx_ip6_routes_,
priv->ifindex,
&obj,
NULL,
FALSE,
TRUE))
changed = TRUE;
}
if (nm_dedup_multi_index_dirty_remove_idx (priv->multi_idx, &priv->idx_ip6_routes, FALSE) > 0)
changed = TRUE;
if (changed)
_notify_routes (self);
}
void
nm_ip6_config_reset_routes (NMIP6Config *self)
{
@ -1727,7 +1821,9 @@ _add_route (NMIP6Config *self, const NMPObject *obj_new, const NMPlatformIP6Rout
&priv->idx_ip6_routes_,
priv->ifindex,
obj_new,
(const NMPlatformObject *) new))
(const NMPlatformObject *) new,
TRUE,
FALSE))
_notify_routes (self);
}
@ -1763,7 +1859,8 @@ _nmtst_ip6_config_del_route (NMIP6Config *self, guint i)
if (nm_dedup_multi_index_remove_obj (priv->multi_idx,
&priv->idx_ip6_routes,
NMP_OBJECT_UP_CAST (r)) != 1)
NMP_OBJECT_UP_CAST (r),
NULL) != 1)
g_return_if_reached ();
_notify_routes (self);
}

View file

@ -112,10 +112,7 @@ struct _NMDedupMultiIndex *nm_ip6_config_get_multi_idx (const NMIP6Config *self)
NMIP6Config *nm_ip6_config_capture (struct _NMDedupMultiIndex *multi_idx, NMPlatform *platform, int ifindex,
gboolean capture_resolv_conf, NMSettingIP6ConfigPrivacy use_temporary);
gboolean nm_ip6_config_commit (const NMIP6Config *self,
NMPlatform *platform,
NMRouteManager *route_manager,
int ifindex,
gboolean routes_full_sync);
NMPlatform *platform);
void nm_ip6_config_merge_setting (NMIP6Config *self, NMSettingIPConfig *setting, guint32 default_route_metric);
NMSetting *nm_ip6_config_create_setting (const NMIP6Config *self);
@ -194,6 +191,18 @@ gboolean nm_ip6_config_equal (const NMIP6Config *a, const NMIP6Config *b);
void nm_ip6_config_set_privacy (NMIP6Config *self, NMSettingIP6ConfigPrivacy privacy);
struct _NMNDiscAddress;
void nm_ip6_config_reset_addresses_ndisc (NMIP6Config *self,
const struct _NMNDiscAddress *addresses,
guint addresses_n,
guint8 plen,
guint32 ifa_flags);
struct _NMNDiscRoute;
void nm_ip6_config_reset_routes_ndisc (NMIP6Config *self,
const struct _NMNDiscRoute *routes,
guint routes_n,
guint32 metric);
/*****************************************************************************/
/* Testing-only functions */

View file

@ -26,7 +26,6 @@
#include "platform/nm-platform.h"
#include "platform/nmp-netns.h"
#include "nm-route-manager.h"
#include "nm-default-route-manager.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
@ -40,7 +39,6 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE (
typedef struct {
NMPlatform *platform;
NMPNetns *platform_netns;
NMRouteManager *route_manager;
NMDefaultRouteManager *default_route_manager;
bool log_with_ptr;
} NMNetnsPrivate;
@ -88,12 +86,6 @@ nm_netns_get_default_route_manager (NMNetns *self)
return NM_NETNS_GET_PRIVATE (self)->default_route_manager;
}
NMRouteManager *
nm_netns_get_route_manager (NMNetns *self)
{
return NM_NETNS_GET_PRIVATE (self)->route_manager;
}
/*****************************************************************************/
static void
@ -137,7 +129,6 @@ constructed (GObject *object)
log_with_ptr = nm_platform_get_log_with_ptr (priv->platform);
priv->platform_netns = nm_platform_netns_get (priv->platform);
priv->route_manager = nm_route_manager_new (log_with_ptr, priv->platform);
priv->default_route_manager = nm_default_route_manager_new (log_with_ptr, priv->platform);
G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object);
@ -157,7 +148,6 @@ dispose (GObject *object)
NMNetns *self = NM_NETNS (object);
NMNetnsPrivate *priv = NM_NETNS_GET_PRIVATE (self);
g_clear_object (&priv->route_manager);
g_clear_object (&priv->default_route_manager);
g_clear_object (&priv->platform);

View file

@ -39,7 +39,6 @@ NMNetns *nm_netns_new (NMPlatform *platform);
NMPlatform *nm_netns_get_platform (NMNetns *self);
NMPNetns *nm_netns_get_platform_netns (NMNetns *self);
NMRouteManager *nm_netns_get_route_manager (NMNetns *self);
NMDefaultRouteManager *nm_netns_get_default_route_manager (NMNetns *self);
struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self);

File diff suppressed because it is too large Load diff

View file

@ -1,49 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/* NetworkManager -- Network link manager
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2015 Red Hat, Inc.
*/
#ifndef __NM_ROUTE_MANAGER_H__
#define __NM_ROUTE_MANAGER_H__
#define NM_TYPE_ROUTE_MANAGER (nm_route_manager_get_type ())
#define NM_ROUTE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_ROUTE_MANAGER, NMRouteManager))
#define NM_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), NM_TYPE_ROUTE_MANAGER, NMRouteManagerClass))
#define NM_IS_ROUTE_MANAGER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), NM_TYPE_ROUTE_MANAGER))
#define NM_IS_ROUTE_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_ROUTE_MANAGER))
#define NM_ROUTE_MANAGER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_ROUTE_MANAGER, NMRouteManagerClass))
#define NM_ROUTE_MANAGER_LOG_WITH_PTR "log-with-ptr"
#define NM_ROUTE_MANAGER_PLATFORM "platform"
#define NM_ROUTE_MANAGER_IP4_ROUTES_CHANGED "ip4-routes-changed"
typedef struct _NMRouteManagerClass NMRouteManagerClass;
GType nm_route_manager_get_type (void);
gboolean nm_route_manager_ip4_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync);
gboolean nm_route_manager_ip6_route_sync (NMRouteManager *self, int ifindex, const GArray *known_routes, gboolean ignore_kernel_routes, gboolean full_sync);
gboolean nm_route_manager_route_flush (NMRouteManager *self, int ifindex);
gboolean nm_route_manager_ip4_routes_shadowed (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_new (gboolean log_with_ptr, NMPlatform *platform);
#endif /* __NM_ROUTE_MANAGER_H__ */

View file

@ -50,7 +50,6 @@ typedef struct _NMNetns NMNetns;
typedef struct _NMPolicy NMPolicy;
typedef struct _NMRfkillManager NMRfkillManager;
typedef struct _NMPacrunnerManager NMPacrunnerManager;
typedef struct _NMRouteManager NMRouteManager;
typedef struct _NMSessionMonitor NMSessionMonitor;
typedef struct _NMSleepMonitor NMSleepMonitor;
typedef struct _NMLldpListener NMLldpListener;

View file

@ -1199,7 +1199,7 @@ ip_route_delete (NMPlatform *platform, const NMPObject *obj)
return ipx_route_delete (platform, AF_UNSPEC, -1, obj);
}
static gboolean
static NMPlatformError
ip_route_add (NMPlatform *platform,
NMPNlmFlags flags,
int addr_family,
@ -1223,6 +1223,8 @@ ip_route_add (NMPlatform *platform,
g_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
flags = NM_FLAGS_UNSET (flags, NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE);
/* currently, only replace is implemented. */
g_assert (flags == NMP_NLM_FLAG_REPLACE);
@ -1230,24 +1232,17 @@ ip_route_add (NMPlatform *platform,
? NMP_OBJECT_TYPE_IP4_ROUTE
: NMP_OBJECT_TYPE_IP6_ROUTE,
(const NMPlatformObject *) route);
r = &obj->ip_route;
r = NMP_OBJECT_CAST_IP_ROUTE (obj);
nm_platform_ip_route_normalize (addr_family, r);
switch (addr_family) {
case AF_INET:
r4 = NMP_OBJECT_CAST_IP4_ROUTE (obj);
r4->network = nm_utils_ip4_address_clear_host_address (r4->network, r4->plen);
r4->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r4->rt_source),
r4->scope_inv = nm_platform_route_scope_inv (!r4->gateway
? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
if (r4->gateway)
has_gateway = TRUE;
break;
case AF_INET6:
r6 = NMP_OBJECT_CAST_IP6_ROUTE (obj);
nm_utils_ip6_address_clear_host_address (&r6->network, &r6->network, r6->plen);
r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r6->rt_source),
r6->metric = nm_utils_ip6_route_metric_normalize (r6->metric);
nm_utils_ip6_address_clear_host_address (&r6->src, &r6->src, r6->src_plen);
if (!IN6_IS_ADDR_UNSPECIFIED (&r6->gateway))
has_gateway = TRUE;
break;
@ -1291,7 +1286,7 @@ ip_route_add (NMPlatform *platform,
nm_log_warn (LOGD_PLATFORM, "Fake platform: failure adding ip6-route '%d: %s/%d %d': Network Unreachable",
r->ifindex, nm_utils_inet6_ntop (&r6->network, NULL), r->plen, r->metric);
}
return FALSE;
return NM_PLATFORM_ERROR_UNSPECIFIED;
}
}
@ -1353,7 +1348,7 @@ ip_route_add (NMPlatform *platform,
}
}
return TRUE;
return NM_PLATFORM_ERROR_SUCCESS;
}
/*****************************************************************************/

View file

@ -265,6 +265,16 @@ static gboolean event_handler_read_netlink (NMPlatform *platform, gboolean wait_
/*****************************************************************************/
static NMPlatformError
wait_for_nl_response_to_plerr (WaitForNlResponseResult seq_result)
{
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
return NM_PLATFORM_ERROR_SUCCESS;
if (seq_result < 0)
return (NMPlatformError) seq_result;
return NM_PLATFORM_ERROR_NETLINK;
}
static const char *
wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, char *buf, gsize buf_size)
{
@ -290,35 +300,83 @@ wait_for_nl_response_to_string (WaitForNlResponseResult seq_result, char *buf, g
return buf0;
}
/******************************************************************
/*****************************************************************************
* Support IFLA_INET6_ADDR_GEN_MODE
******************************************************************/
*****************************************************************************/
static int _support_user_ipv6ll = 0;
#define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0))
static void
_support_user_ipv6ll_detect (struct nlattr **tb)
{
gboolean supported;
nm_assert (_support_user_ipv6ll_still_undecided ());
/* IFLA_INET6_ADDR_GEN_MODE was added in kernel 3.17, dated 5 October, 2014. */
supported = !!tb[IFLA_INET6_ADDR_GEN_MODE];
_support_user_ipv6ll = supported ? 1 : -1;
_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s",
supported ? "detected" : "not detected");
}
static gboolean
_support_user_ipv6ll_get (void)
{
if (_support_user_ipv6ll_still_undecided ()) {
_support_user_ipv6ll = -1;
_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", "failed to detect; assume no support");
return FALSE;
_support_user_ipv6ll = 1;
_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s", "failed to detect; assume support");
}
return _support_user_ipv6ll > 0;
return _support_user_ipv6ll >= 0;
}
static void
_support_user_ipv6ll_detect (struct nlattr **tb)
{
if (_support_user_ipv6ll_still_undecided ()) {
gboolean supported = !!tb[IFLA_INET6_ADDR_GEN_MODE];
/*****************************************************************************
* extended IFA_FLAGS support
*****************************************************************************/
_support_user_ipv6ll = supported ? 1 : -1;
_LOG2D ("kernel-support: IFLA_INET6_ADDR_GEN_MODE: %s",
supported ? "detected" : "not detected");
static int _support_kernel_extended_ifa_flags = 0;
#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == 0))
static void
_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
{
struct nlmsghdr *msg_hdr;
gboolean support;
nm_assert (_support_kernel_extended_ifa_flags_still_undecided ());
nm_assert (msg);
msg_hdr = nlmsg_hdr (msg);
nm_assert (msg_hdr && msg_hdr->nlmsg_type == RTM_NEWADDR);
/* IFA_FLAGS is set for IPv4 and IPv6 addresses. It was added first to IPv6,
* but if we encounter an IPv4 address with IFA_FLAGS, we surely have support. */
if (NM_IN_SET (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family, AF_INET, AF_INET6))
return;
/* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
* we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
* and IFA_F_NOPREFIXROUTE for IPv6. They were added together in kernel 3.14,
* dated 30 March, 2014.
*
* For IPv4, IFA_F_NOPREFIXROUTE was added later, but there is no easy
* way to detect kernel support. */
support = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), IFA_FLAGS);
_support_kernel_extended_ifa_flags = support ? 1 : -1;
_LOG2D ("kernel-support: extended-ifa-flags: %s", support ? "detected" : "not detected");
}
static gboolean
_support_kernel_extended_ifa_flags_get (void)
{
if (_support_kernel_extended_ifa_flags_still_undecided ()) {
_LOG2D ("kernel-support: extended-ifa-flags: %s", "unable to detect kernel support for handling IPv6 temporary addresses. Assume support");
_support_kernel_extended_ifa_flags = 1;
}
return _support_kernel_extended_ifa_flags >= 0;
}
/******************************************************************
@ -778,6 +836,31 @@ _linktype_get_type (NMPlatform *platform,
* libnl unility functions and wrappers
******************************************************************/
#define NLMSG_TAIL(nmsg) \
((struct rtattr *) (((char *) (nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
/* copied from iproute2's addattr_l(). */
static gboolean
_nl_addattr_l (struct nlmsghdr *n,
int maxlen,
int type,
const void *data,
int alen)
{
int len = RTA_LENGTH (alen);
struct rtattr *rta;
if (NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len) > maxlen)
return FALSE;
rta = NLMSG_TAIL (n);
rta->rta_type = type;
rta->rta_len = len;
memcpy (RTA_DATA (rta), data, alen);
n->nlmsg_len = NLMSG_ALIGN (n->nlmsg_len) + RTA_ALIGN (len);
return TRUE;
}
#define nm_auto_nlmsg __attribute__((cleanup(_nm_auto_nl_msg_cleanup)))
static void
_nm_auto_nl_msg_cleanup (void *ptr)
@ -936,7 +1019,8 @@ _parse_af_inet6 (NMPlatform *platform,
/* Hack to detect support addrgenmode of the kernel. We only parse
* netlink messages that we receive from kernel, hence this check
* is valid. */
_support_user_ipv6ll_detect (tb);
if (_support_user_ipv6ll_still_undecided ())
_support_user_ipv6ll_detect (tb);
if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]));
@ -1946,8 +2030,6 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
table = tb[RTA_TABLE]
? nla_get_u32 (tb[RTA_TABLE])
: (guint32) rtm->rtm_table;
if (table != RT_TABLE_MAIN)
goto errout;
/*****************************************************************/
@ -2064,6 +2146,7 @@ _new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
obj->ip_route.table_coerced = nm_platform_route_table_coerce (table);
obj->ip_route.ifindex = nh.ifindex;
if (_check_addr_or_errout (tb, RTA_DST, addr_len))
@ -2501,19 +2584,20 @@ ip_route_get_lock_flag (const NMPlatformIPRoute *route)
/* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */
static struct nl_msg *
_nl_msg_new_route (int nlmsg_type,
NMPNlmFlags nlmsgflags,
guint16 nlmsgflags,
const NMPObject *obj)
{
struct nl_msg *msg;
const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj);
gboolean is_v4 = klass->addr_family == AF_INET;
const guint32 lock = ip_route_get_lock_flag (NMP_OBJECT_CAST_IP_ROUTE (obj));
const guint32 table = nm_platform_route_table_coerce (NMP_OBJECT_CAST_IP_ROUTE (obj)->table_coerced);
struct rtmsg rtmsg = {
.rtm_family = klass->addr_family,
.rtm_tos = is_v4
? obj->ip4_route.tos
: 0,
.rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */
.rtm_table = table <= 0xFF ? table : RT_TABLE_UNSPEC,
.rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot (obj->ip_route.rt_source),
.rtm_scope = is_v4
? nm_platform_route_scope_inv (obj->ip4_route.scope_inv)
@ -2531,7 +2615,6 @@ _nl_msg_new_route (int nlmsg_type,
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj), NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE));
nm_assert (((NMPNlmFlags) ((int) nlmsgflags)) == nlmsgflags);
msg = nlmsg_alloc_simple (nlmsg_type, (int) nlmsgflags);
if (!msg)
g_return_val_if_reached (NULL);
@ -2555,6 +2638,9 @@ _nl_msg_new_route (int nlmsg_type,
NLA_PUT_U32 (msg, RTA_PRIORITY, obj->ip_route.metric);
if (table > 0xFF)
NLA_PUT_U32 (msg, RTA_TABLE, table);
if (is_v4) {
if (NMP_OBJECT_CAST_IP4_ROUTE (obj)->pref_src)
NLA_PUT (msg, RTA_PREFSRC, addr_len, &obj->ip4_route.pref_src);
@ -2610,56 +2696,27 @@ nla_put_failure:
g_return_val_if_reached (NULL);
}
/*****************************************************************************/
static int _support_kernel_extended_ifa_flags = -1;
#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == -1))
static void
_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
{
struct nlmsghdr *msg_hdr;
if (!_support_kernel_extended_ifa_flags_still_undecided ())
return;
msg_hdr = nlmsg_hdr (msg);
if (msg_hdr->nlmsg_type != RTM_NEWADDR)
return;
/* the extended address flags are only set for AF_INET6 */
if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6)
return;
/* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
* we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
* and IFA_F_NOPREFIXROUTE (they were added together).
**/
_support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), IFA_FLAGS);
_LOG2D ("kernel-support: extended-ifa-flags: %s", _support_kernel_extended_ifa_flags ? "detected" : "not detected");
}
static gboolean
_support_kernel_extended_ifa_flags_get (void)
{
if (_support_kernel_extended_ifa_flags_still_undecided ()) {
_LOG2D ("kernel-support: extended-ifa-flags: %s", "unable to detect kernel support for handling IPv6 temporary addresses. Assume support");
_support_kernel_extended_ifa_flags = 1;
}
return _support_kernel_extended_ifa_flags;
}
/******************************************************************
* NMPlatform types and functions
******************************************************************/
typedef enum {
DELAYED_ACTION_RESPONSE_TYPE_VOID = 0,
DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS = 1,
DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET = 2,
} DelayedActionWaitForNlResponseType;
typedef struct {
guint32 seq_number;
WaitForNlResponseResult seq_result;
DelayedActionWaitForNlResponseType response_type;
gint64 timeout_abs_ns;
WaitForNlResponseResult *out_seq_result;
gint *out_refresh_all_in_progess;
union {
gint *out_refresh_all_in_progess;
NMPObject **out_route_get;
gpointer out_data;
} response;
} DelayedActionWaitForNlResponseData;
typedef struct {
@ -2990,7 +3047,7 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat
static gboolean
check_support_kernel_extended_ifa_flags (NMPlatform *platform)
{
g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
nm_assert (NM_IS_LINUX_PLATFORM (platform));
return _support_kernel_extended_ifa_flags_get ();
}
@ -2998,7 +3055,7 @@ check_support_kernel_extended_ifa_flags (NMPlatform *platform)
static gboolean
check_support_user_ipv6ll (NMPlatform *platform)
{
g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
nm_assert (NM_IS_LINUX_PLATFORM (platform));
return _support_user_ipv6ll_get ();
}
@ -3078,11 +3135,12 @@ delayed_action_to_string_full (DelayedActionType action_type, gpointer user_data
gint64 timeout = data->timeout_abs_ns - nm_utils_get_monotonic_timestamp_ns ();
char b[255];
nm_utils_strbuf_append (&buf, &buf_size, " (seq %u, timeout in %s%"G_GINT64_FORMAT".%09"G_GINT64_FORMAT"%s%s)",
nm_utils_strbuf_append (&buf, &buf_size, " (seq %u, timeout in %s%"G_GINT64_FORMAT".%09"G_GINT64_FORMAT", response-type %d%s%s)",
data->seq_number,
timeout < 0 ? "-" : "",
(timeout < 0 ? -timeout : timeout) / NM_UTILS_NS_PER_SECOND,
(timeout < 0 ? -timeout : timeout) % NM_UTILS_NS_PER_SECOND,
(int) data->response_type,
data->seq_result ? ", " : "",
data->seq_result ? wait_for_nl_response_to_string (data->seq_result, b, sizeof (b)) : "");
} else
@ -3144,9 +3202,22 @@ delayed_action_wait_for_nl_response_complete (NMPlatform *platform,
priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE;
if (data->out_seq_result)
*data->out_seq_result = seq_result;
if (data->out_refresh_all_in_progess) {
nm_assert (*data->out_refresh_all_in_progess > 0);
*data->out_refresh_all_in_progess -= 1;
switch (data->response_type) {
case DELAYED_ACTION_RESPONSE_TYPE_VOID:
break;
case DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS:
if (data->response.out_refresh_all_in_progess) {
nm_assert (*data->response.out_refresh_all_in_progess > 0);
*data->response.out_refresh_all_in_progess -= 1;
data->response.out_refresh_all_in_progess = NULL;
}
break;
case DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET:
if (data->response.out_route_get) {
nm_assert (!*data->response.out_route_get);
data->response.out_route_get = NULL;
}
break;
}
g_array_remove_index_fast (priv->delayed_action.list_wait_for_nl_response, idx);
@ -3356,13 +3427,15 @@ static void
delayed_action_schedule_WAIT_FOR_NL_RESPONSE (NMPlatform *platform,
guint32 seq_number,
WaitForNlResponseResult *out_seq_result,
gint *out_refresh_all_in_progess)
DelayedActionWaitForNlResponseType response_type,
gpointer response_out_data)
{
DelayedActionWaitForNlResponseData data = {
.seq_number = seq_number,
.timeout_abs_ns = nm_utils_get_monotonic_timestamp_ns () + (200 * (NM_UTILS_NS_PER_SECOND / 1000)),
.out_seq_result = out_seq_result,
.out_refresh_all_in_progess = out_refresh_all_in_progess,
.response_type = response_type,
.response.out_data = response_out_data,
};
delayed_action_schedule (platform,
@ -3647,30 +3720,111 @@ cache_on_change (NMPlatform *platform,
/*****************************************************************************/
static guint32
_nlh_seq_next_get (NMLinuxPlatformPrivate *priv)
{
/* generate a new sequence number, but skip zero. */
return priv->nlh_seq_next++ ?: priv->nlh_seq_next++;
}
/**
* _nl_send_nlmsghdr:
* @platform:
* @nlhdr:
* @out_seq_result:
* @response_type:
* @response_out_data:
*
* Returns: 0 on success or a negative errno. Beware, it's an errno, not nlerror.
*/
static int
_nl_send_auto_with_seq (NMPlatform *platform,
struct nl_msg *nlmsg,
WaitForNlResponseResult *out_seq_result,
gint *out_refresh_all_in_progess)
_nl_send_nlmsghdr (NMPlatform *platform,
struct nlmsghdr *nlhdr,
WaitForNlResponseResult *out_seq_result,
DelayedActionWaitForNlResponseType response_type,
gpointer response_out_data)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
guint32 seq;
int nle;
/* complete the message with a sequence number (ensuring it's not zero). */
seq = priv->nlh_seq_next++ ?: priv->nlh_seq_next++;
nm_assert (nlhdr);
nlmsg_hdr (nlmsg)->nlmsg_seq = seq;
seq = _nlh_seq_next_get (priv);
nlhdr->nlmsg_seq = seq;
{
struct sockaddr_nl nladdr = {
.nl_family = AF_NETLINK,
};
struct iovec iov = {
.iov_base = nlhdr,
.iov_len = nlhdr->nlmsg_len
};
struct msghdr msg = {
.msg_name = &nladdr,
.msg_namelen = sizeof(nladdr),
.msg_iov = &iov,
.msg_iovlen = 1,
};
int try_count;
if (!nlhdr->nlmsg_pid)
nlhdr->nlmsg_pid = nl_socket_get_local_port (priv->nlh);
nlhdr->nlmsg_flags |= (NLM_F_REQUEST | NLM_F_ACK);
try_count = 0;
again:
nle = sendmsg (nl_socket_get_fd (priv->nlh), &msg, 0);
if (nle < 0) {
nle = errno;
if (nle == EINTR && try_count++ < 100)
goto again;
_LOGD ("netlink: nl-send-nlmsghdr: failed sending message: %s (%d)", g_strerror (nle), nle);
return -nle;
}
}
delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result,
response_type, response_out_data);
return 0;
}
/**
* _nl_send_nlmsg:
* @platform:
* @nlmsg:
* @out_seq_result:
* @response_type:
* @response_out_data:
*
* Returns: 0 on success, or a negative libnl3 error code (beware, it's not an errno).
*/
static int
_nl_send_nlmsg (NMPlatform *platform,
struct nl_msg *nlmsg,
WaitForNlResponseResult *out_seq_result,
DelayedActionWaitForNlResponseType response_type,
gpointer response_out_data)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
struct nlmsghdr *nlhdr;
guint32 seq;
int nle;
nlhdr = nlmsg_hdr (nlmsg);
seq = _nlh_seq_next_get (priv);
nlhdr->nlmsg_seq = seq;
nle = nl_send_auto (priv->nlh, nlmsg);
if (nle < 0) {
_LOGD ("netlink: nl-send-nlmsg: failed sending message: %s (%d)", nl_geterror (nle), nle);
return nle;
}
if (nle >= 0) {
nle = 0;
delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result, out_refresh_all_in_progess);
} else
_LOGD ("netlink: send: failed sending message: %s (%d)", nl_geterror (nle), nle);
return nle;
delayed_action_schedule_WAIT_FOR_NL_RESPONSE (platform, seq, out_seq_result,
response_type, response_out_data);
return 0;
}
static void
@ -3705,7 +3859,7 @@ do_request_link_no_delayed_actions (NMPlatform *platform, int ifindex, const cha
0,
0);
if (nlmsg)
_nl_send_auto_with_seq (platform, nlmsg, NULL, NULL);
_nl_send_nlmsg (platform, nlmsg, NULL, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL);
}
static void
@ -3767,7 +3921,7 @@ do_request_all_no_delayed_actions (NMPlatform *platform, DelayedActionType actio
if (nle < 0)
continue;
if (_nl_send_auto_with_seq (platform, nlmsg, NULL, out_refresh_all_in_progess) < 0) {
if (_nl_send_nlmsg (platform, nlmsg, NULL, DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS, out_refresh_all_in_progess) < 0) {
nm_assert (*out_refresh_all_in_progess > 0);
*out_refresh_all_in_progess -= 1;
}
@ -3797,13 +3951,12 @@ event_seq_check_refresh_all (NMPlatform *platform, guint32 seq_number)
for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) {
data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
if (data->seq_number == priv->nlh_seq_last_seen) {
if (data->out_refresh_all_in_progess) {
nm_assert (*data->out_refresh_all_in_progess > 0);
*data->out_refresh_all_in_progess -= 1;
data->out_refresh_all_in_progess = NULL;
break;
}
if ( data->response_type == DELAYED_ACTION_RESPONSE_TYPE_REFRESH_ALL_IN_PROGRESS
&& data->response.out_refresh_all_in_progess
&& data->seq_number == priv->nlh_seq_last_seen) {
*data->response.out_refresh_all_in_progess -= 1;
data->response.out_refresh_all_in_progess = NULL;
break;
}
}
}
@ -3851,6 +4004,7 @@ event_seq_check (NMPlatform *platform, guint32 seq_number, WaitForNlResponseResu
static void
event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_events)
{
NMLinuxPlatformPrivate *priv;
nm_auto_nmpobj NMPObject *obj = NULL;
NMPCacheOpsType cache_op;
struct nlmsghdr *msghdr;
@ -3861,7 +4015,8 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
msghdr = nlmsg_hdr (msg);
if (_support_kernel_extended_ifa_flags_still_undecided () && msghdr->nlmsg_type == RTM_NEWADDR)
if ( _support_kernel_extended_ifa_flags_still_undecided ()
&& msghdr->nlmsg_type == RTM_NEWADDR)
_support_kernel_extended_ifa_flags_detect (msg);
if (!handle_events)
@ -3919,6 +4074,30 @@ event_valid_msg (NMPlatform *platform, struct nl_msg *msg, gboolean handle_event
gboolean resync_required = FALSE;
gboolean only_dirty = FALSE;
if (obj->ip_route.rt_cloned) {
/* a cloned route might be a response for RTM_GETROUTE. Check, whether it is. */
nm_assert (!nmp_object_is_alive (obj));
priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
if (NM_FLAGS_HAS (priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE)) {
guint i;
nm_assert (priv->delayed_action.list_wait_for_nl_response->len > 0);
for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len; i++) {
DelayedActionWaitForNlResponseData *data = &g_array_index (priv->delayed_action.list_wait_for_nl_response, DelayedActionWaitForNlResponseData, i);
if ( data->response_type == DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET
&& data->response.out_route_get) {
nm_assert (!*data->response.out_route_get);
if (data->seq_number == nlmsg_hdr (msg)->nlmsg_seq) {
*data->response.out_route_get = nmp_object_clone (obj, FALSE);
data->response.out_route_get = NULL;
break;
}
}
}
}
}
cache_op = nmp_cache_update_netlink_route (cache,
obj,
is_dump,
@ -4006,26 +4185,13 @@ do_add_link_with_lookup (NMPlatform *platform,
event_handler_read_netlink (platform, FALSE);
if (nmp_cache_lookup_link_full (cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) {
/* hm, a link with such a name already exists. Try reloading first. */
do_request_link (platform, 0, name);
obj = nmp_cache_lookup_link_full (cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL);
if (obj) {
_LOGE ("do-add-link[%s/%s]: link already exists: %s",
name,
nm_link_type_to_string (link_type),
nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
return FALSE;
}
}
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL);
if (nle < 0) {
_LOGE ("do-add-link[%s/%s]: failed sending netlink request \"%s\" (%d)",
name,
nm_link_type_to_string (link_type),
nl_geterror (nle), -nle);
NM_SET_OUT (out_link, NULL);
return FALSE;
}
@ -4035,35 +4201,29 @@ do_add_link_with_lookup (NMPlatform *platform,
_NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
? LOGL_DEBUG
: LOGL_ERR,
: LOGL_WARN,
"do-add-link[%s/%s]: %s",
name,
nm_link_type_to_string (link_type),
wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)));
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK)
obj = nmp_cache_lookup_link_full (cache, 0, name, FALSE, link_type, NULL, NULL);
if (!obj) {
/* either kernel signaled failure, or it signaled success and the link object
* is not (yet) in the cache. Try to reload it... */
do_request_link (platform, 0, name);
if (out_link) {
obj = nmp_cache_lookup_link_full (cache, 0, name, FALSE, link_type, NULL, NULL);
*out_link = NMP_OBJECT_CAST_LINK (obj);
}
if (out_link)
*out_link = obj ? &obj->link : NULL;
return !!obj;
return seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
}
static gboolean
do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
static NMPlatformError
do_add_addrroute (NMPlatform *platform,
const NMPObject *obj_id,
struct nl_msg *nlmsg,
gboolean suppress_netlink_failure)
{
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
int nle;
char s_buf[256];
const NMPObject *obj;
NMPCache *cache = nm_platform_get_cache (platform);
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id),
NMP_OBJECT_TYPE_IP4_ADDRESS, NMP_OBJECT_TYPE_IP6_ADDRESS,
@ -4071,45 +4231,43 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
event_handler_read_netlink (platform, FALSE);
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL);
if (nle < 0) {
_LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)",
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
nl_geterror (nle), -nle);
return FALSE;
return NM_PLATFORM_ERROR_NETLINK;
}
delayed_action_handle_all (platform, FALSE);
nm_assert (seq_result);
_NMLOG (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
_NMLOG (( seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK
|| ( suppress_netlink_failure
&& seq_result < 0))
? LOGL_DEBUG
: LOGL_ERR,
: LOGL_WARN,
"do-add-%s[%s]: %s",
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)));
/* In rare cases, the object is not yet ready as we received the ACK from
* kernel. Need to refetch.
*
* We want to safe the expensive refetch, thus we look first into the cache
* whether the object exists.
*
* FIXME: if the object already existed previously, we might not notice a
* missing update. It's not clear how to fix that reliably without refechting
* all the time. */
obj = nmp_cache_lookup_obj (cache, obj_id);
if (!obj) {
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
obj = nmp_cache_lookup_obj (cache, obj_id);
if (NMP_OBJECT_GET_TYPE (obj_id) == NMP_OBJECT_TYPE_IP6_ADDRESS) {
/* In rare cases, the object is not yet ready as we received the ACK from
* kernel. Need to refetch.
*
* We want to safe the expensive refetch, thus we look first into the cache
* whether the object exists.
*
* rh#1484434 */
if (!nmp_cache_lookup_obj (nm_platform_get_cache (platform),
obj_id))
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
}
/* Adding is only successful, if kernel reported success *and* we have the
* expected object in cache afterwards. */
return obj && seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK;
return wait_for_nl_response_to_plerr (seq_result);
}
static gboolean
@ -4118,25 +4276,25 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
int nle;
char s_buf[256];
gboolean success = TRUE;
gboolean success;
const char *log_detail = "";
NMPCache *cache = nm_platform_get_cache (platform);
event_handler_read_netlink (platform, FALSE);
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL);
if (nle < 0) {
_LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)",
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
nl_geterror (nle), -nle);
goto out;
return FALSE;
}
delayed_action_handle_all (platform, FALSE);
nm_assert (seq_result);
success = TRUE;
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) {
/* ok */
} else if (NM_IN_SET (-((int) seq_result), ESRCH, ENOENT))
@ -4151,21 +4309,14 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *
else
success = FALSE;
_NMLOG (success ? LOGL_DEBUG : LOGL_ERR,
_NMLOG (success ? LOGL_DEBUG : LOGL_WARN,
"do-delete-%s[%s]: %s%s",
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
wait_for_nl_response_to_string (seq_result, s_buf, sizeof (s_buf)),
log_detail);
out:
if (!nmp_cache_lookup_obj (cache, obj_id))
return TRUE;
/* such an object still exists in the cache. To be sure, refetch it (and
* hope it's gone) */
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id));
return !nmp_cache_lookup_obj (cache, obj_id);
return success;
}
static WaitForNlResponseResult
@ -4181,7 +4332,7 @@ do_change_link_request (NMPlatform *platform,
return WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
retry:
nle = _nl_send_auto_with_seq (platform, nlmsg, &seq_result, NULL);
nle = _nl_send_nlmsg (platform, nlmsg, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_VOID, NULL);
if (nle < 0) {
_LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)",
ifindex,
@ -4226,7 +4377,7 @@ do_change_link_result (NMPlatform *platform,
log_level = LOGL_DEBUG;
result = NM_PLATFORM_ERROR_NOT_FOUND;
} else {
log_level = LOGL_ERR;
log_level = LOGL_WARN;
result = NM_PLATFORM_ERROR_UNSPECIFIED;
}
_NMLOG (log_level,
@ -4421,15 +4572,15 @@ link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enable
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64;
_LOGD ("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s",
ifindex,
nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0));
if (!_support_user_ipv6ll_get ()) {
_LOGD ("link: change %d: user-ipv6ll: not supported", ifindex);
return NM_PLATFORM_ERROR_OPNOTSUPP;
}
_LOGD ("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s",
ifindex,
nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0));
nlmsg = _nl_msg_new_link (RTM_NEWLINK,
0,
ifindex,
@ -5743,7 +5894,7 @@ ip4_address_add (NMPlatform *platform,
label);
nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_addr);
return do_add_addrroute (platform, &obj_id, nlmsg);
return do_add_addrroute (platform, &obj_id, nlmsg, FALSE) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
@ -5773,7 +5924,7 @@ ip6_address_add (NMPlatform *platform,
NULL);
nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr);
return do_add_addrroute (platform, &obj_id, nlmsg);
return do_add_addrroute (platform, &obj_id, nlmsg, FALSE) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
@ -5828,7 +5979,7 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, gui
/*****************************************************************************/
static gboolean
static NMPlatformError
ip_route_add (NMPlatform *platform,
NMPNlmFlags flags,
int addr_family,
@ -5836,34 +5987,27 @@ ip_route_add (NMPlatform *platform,
{
nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
NMPObject obj;
NMPlatformIP4Route *r4;
NMPlatformIP6Route *r6;
switch (addr_family) {
case AF_INET:
nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP4_ROUTE, (const NMPlatformObject *) route);
r4 = NMP_OBJECT_CAST_IP4_ROUTE (&obj);
r4->network = nm_utils_ip4_address_clear_host_address (r4->network, r4->plen);
r4->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r4->rt_source),
r4->scope_inv = nm_platform_route_scope_inv (!r4->gateway
? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE);
break;
case AF_INET6:
nmp_object_stackinit (&obj, NMP_OBJECT_TYPE_IP6_ROUTE, (const NMPlatformObject *) route);
r6 = NMP_OBJECT_CAST_IP6_ROUTE (&obj);
nm_utils_ip6_address_clear_host_address (&r6->network, &r6->network, r6->plen);
r6->rt_source = nmp_utils_ip_config_source_round_trip_rtprot (r6->rt_source),
r6->metric = nm_utils_ip6_route_metric_normalize (r6->metric);
nm_utils_ip6_address_clear_host_address (&r6->src, &r6->src, r6->src_plen);
break;
default:
nm_assert_not_reached ();
}
nlmsg = _nl_msg_new_route (RTM_NEWROUTE, flags, &obj);
nm_platform_ip_route_normalize (addr_family, NMP_OBJECT_CAST_IP_ROUTE (&obj));
nlmsg = _nl_msg_new_route (RTM_NEWROUTE, flags & NMP_NLM_FLAG_FMASK, &obj);
if (!nlmsg)
g_return_val_if_reached (FALSE);
return do_add_addrroute (platform, &obj, nlmsg);
g_return_val_if_reached (NM_PLATFORM_ERROR_BUG);
return do_add_addrroute (platform,
&obj,
nlmsg,
NM_FLAGS_HAS (flags, NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE));
}
static gboolean
@ -5887,6 +6031,77 @@ ip_route_delete (NMPlatform *platform,
/*****************************************************************************/
static NMPlatformError
ip_route_get (NMPlatform *platform,
int addr_family,
gconstpointer address,
NMPObject **out_route)
{
const gboolean is_v4 = (addr_family == AF_INET);
const int addr_len = is_v4 ? 4 : 16;
int try_count = 0;
WaitForNlResponseResult seq_result;
int nle;
nm_auto_nlmsg NMPObject *route = NULL;
nm_assert (NM_IS_LINUX_PLATFORM (platform));
nm_assert (NM_IN_SET (addr_family, AF_INET, AF_INET6));
nm_assert (address);
do {
struct {
struct nlmsghdr n;
struct rtmsg r;
char buf[64];
} req = {
.n.nlmsg_len = NLMSG_LENGTH (sizeof (struct rtmsg)),
.n.nlmsg_flags = NLM_F_REQUEST,
.n.nlmsg_type = RTM_GETROUTE,
.r.rtm_family = addr_family,
.r.rtm_tos = 0,
.r.rtm_dst_len = is_v4 ? 32 : 128,
.r.rtm_flags = 0x1000 /* RTM_F_LOOKUP_TABLE */,
};
g_clear_pointer (&route, nmp_object_unref);
if (!_nl_addattr_l (&req.n, sizeof (req), RTA_DST, address, addr_len))
nm_assert_not_reached ();
seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
nle = _nl_send_nlmsghdr (platform, &req.n, &seq_result, DELAYED_ACTION_RESPONSE_TYPE_ROUTE_GET, &route);
if (nle < 0) {
_LOGE ("get-route: failure sending netlink request \"%s\" (%d)",
g_strerror (-nle), -nle);
return NM_PLATFORM_ERROR_UNSPECIFIED;
}
delayed_action_handle_all (platform, FALSE);
/* Retry, if we failed due to a cache resync. That can happen when the netlink
* socket fills up and we lost the response. */
} while ( seq_result == WAIT_FOR_NL_RESPONSE_RESULT_FAILED_RESYNC
&& ++try_count < 10);
if (seq_result < 0) {
/* negative seq_result is an errno from kernel. Map it to negative
* NMPlatformError (which are also errno). */
return (NMPlatformError) seq_result;
}
if (seq_result == WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_OK) {
if (route) {
NM_SET_OUT (out_route, g_steal_pointer (&route));
return NM_PLATFORM_ERROR_SUCCESS;
}
seq_result = WAIT_FOR_NL_RESPONSE_RESULT_RESPONSE_UNKNOWN;
}
return NM_PLATFORM_ERROR_UNSPECIFIED;
}
/*****************************************************************************/
#define EVENT_CONDITIONS ((GIOCondition) (G_IO_IN | G_IO_PRI))
#define ERROR_CONDITIONS ((GIOCondition) (G_IO_ERR | G_IO_NVAL))
#define DISCONNECT_CONDITIONS ((GIOCondition) (G_IO_HUP))
@ -6616,6 +6831,7 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->ip_route_add = ip_route_add;
platform_class->ip_route_delete = ip_route_delete;
platform_class->ip_route_get = ip_route_get;
platform_class->check_support_kernel_extended_ifa_flags = check_support_kernel_extended_ifa_flags;
platform_class->check_support_user_ipv6ll = check_support_user_ipv6ll;

File diff suppressed because it is too large Load diff

View file

@ -52,6 +52,9 @@
struct udev_device;
typedef gboolean (*NMPObjectPredicateFunc) (const NMPObject *obj,
gpointer user_data);
/* workaround for older libnl version, that does not define these flags. */
#ifndef IFA_F_MANAGETEMPADDR
#define IFA_F_MANAGETEMPADDR 0x100
@ -60,6 +63,8 @@ struct udev_device;
#define IFA_F_NOPREFIXROUTE 0x200
#endif
#define NM_RT_SCOPE_LINK 253 /* RT_SCOPE_LINK */
/* Define of the IN6_ADDR_GEN_MODE_* values to workaround old kernel headers
* that don't define it. */
#define NM_IN6_ADDR_GEN_MODE_UNKNOWN 255 /* no corresponding value. */
@ -81,6 +86,15 @@ typedef enum {
NMP_NLM_FLAG_F_CREATE = 0x400, /* NLM_F_CREATE, Create, if it does not exist */
NMP_NLM_FLAG_F_APPEND = 0x800, /* NLM_F_APPEND, Add to end of list */
NMP_NLM_FLAG_FMASK = 0xFFFF, /* a mask for all NMP_NLM_FLAG_F_* flags */
/* instructs NM to suppress logging an error message for any failures
* received from kernel.
*
* It will still log with debug-level, and it will still log
* other failures aside the kernel response. */
NMP_NLM_FLAG_SUPPRESS_NETLINK_FAILURE = 0x10000,
/* the following aliases correspond to iproute2's `ip route CMD` for
* RTM_NEWROUTE, with CMD being one of add, change, replace, prepend,
* append and test. */
@ -153,6 +167,7 @@ typedef enum { /*< skip >*/
NM_PLATFORM_ERROR_NOT_SLAVE,
NM_PLATFORM_ERROR_NO_FIRMWARE,
NM_PLATFORM_ERROR_OPNOTSUPP,
NM_PLATFORM_ERROR_NETLINK,
} NMPlatformError;
#define NM_PLATFORM_LINK_OTHER_NETNS (-1)
@ -409,6 +424,13 @@ typedef union {
/* RTA_PRIORITY (iproute2: metric) */ \
guint32 metric; \
\
/* rtm_table, RTA_TABLE.
*
* This is not the original table ID. Instead, 254 (RT_TABLE_MAIN) and
* zero (RT_TABLE_UNSPEC) are swapped, so that the default is the main
* table. Use nm_platform_route_table_coerce(). */ \
guint32 table_coerced; \
\
/*end*/
@ -420,8 +442,23 @@ typedef struct {
};
} NMPlatformIPRoute;
#if _NM_CC_SUPPORT_GENERIC
#define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \
(_Generic ((route), \
const NMPlatformIPRoute *: ((const NMPlatformIPRoute *) (route))->plen, \
NMPlatformIPRoute *: ((const NMPlatformIPRoute *) (route))->plen, \
const NMPlatformIPXRoute *: ((const NMPlatformIPRoute *) (route))->plen, \
NMPlatformIPXRoute *: ((const NMPlatformIPRoute *) (route))->plen, \
const NMPlatformIP4Route *: ((const NMPlatformIPRoute *) (route))->plen, \
NMPlatformIP4Route *: ((const NMPlatformIPRoute *) (route))->plen, \
const NMPlatformIP6Route *: ((const NMPlatformIPRoute *) (route))->plen, \
NMPlatformIP6Route *: ((const NMPlatformIPRoute *) (route))->plen, \
const void *: ((const NMPlatformIPRoute *) (route))->plen, \
void *: ((const NMPlatformIPRoute *) (route))->plen) == 0)
#else
#define NM_PLATFORM_IP_ROUTE_IS_DEFAULT(route) \
( ((const NMPlatformIPRoute *) (route))->plen <= 0 )
#endif
struct _NMPlatformIP4Route {
__NMPlatformIPRoute_COMMON;
@ -503,11 +540,6 @@ typedef struct {
gsize sizeof_route;
int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b, NMPlatformIPRouteCmpType cmp_type);
const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len);
gboolean (*route_add) (NMPlatform *self,
NMPNlmFlags flags,
const NMPlatformIPXRoute *route,
int ifindex,
gint64 metric);
guint32 (*metric_normalize) (guint32 metric);
} NMPlatformVTableRoute;
@ -782,12 +814,17 @@ typedef struct {
gboolean (*ip4_address_delete) (NMPlatform *, int ifindex, in_addr_t address, guint8 plen, in_addr_t peer_address);
gboolean (*ip6_address_delete) (NMPlatform *, int ifindex, struct in6_addr address, guint8 plen);
gboolean (*ip_route_add) (NMPlatform *,
NMPNlmFlags flags,
int addr_family,
const NMPlatformIPRoute *route);
NMPlatformError (*ip_route_add) (NMPlatform *,
NMPNlmFlags flags,
int addr_family,
const NMPlatformIPRoute *route);
gboolean (*ip_route_delete) (NMPlatform *, const NMPObject *obj);
NMPlatformError (*ip_route_get) (NMPlatform *self,
int addr_family,
gconstpointer address,
NMPObject **out_route);
gboolean (*check_support_kernel_extended_ifa_flags) (NMPlatform *);
gboolean (*check_support_user_ipv6ll) (NMPlatform *);
} NMPlatformClass;
@ -822,6 +859,27 @@ NMPlatform *nm_platform_get (void);
/*****************************************************************************/
/**
* nm_platform_route_table_coerce:
* @table: the route table, either its original value, or its coerced.
*
* Returns: returns the coerced table id. If the table id is like
* RTA_TABLE, it returns a value for NMPlatformIPRoute.table_coerced
* and vice versa.
*/
static inline guint32
nm_platform_route_table_coerce (guint32 table)
{
switch (table) {
case 0 /* RT_TABLE_UNSPEC */:
return 254;
case 254 /* RT_TABLE_MAIN */:
return 0;
default:
return table;
}
}
/**
* nm_platform_route_scope_inv:
* @scope: the route scope, either its original value, or its inverse.
@ -847,8 +905,11 @@ gboolean nm_platform_netns_push (NMPlatform *platform, NMPNetns **netns);
const char *nm_link_type_to_string (NMLinkType link_type);
const char *_nm_platform_error_to_string (NMPlatformError error);
#define nm_platform_error_to_string(error) NM_UTILS_LOOKUP_STR (_nm_platform_error_to_string, error)
const char *nm_platform_error_to_string (NMPlatformError error,
char *buf,
gsize buf_len);
#define nm_platform_error_to_string_a(error) \
(nm_platform_error_to_string ((error), g_alloca (30), 30))
#define NMP_SYSCTL_PATHID_ABSOLUTE(path) \
((const char *) NULL), -1, (path)
@ -897,12 +958,14 @@ struct _NMPLookup;
const struct _NMDedupMultiHeadEntry *nm_platform_lookup (NMPlatform *platform,
const struct _NMPLookup *lookup);
gboolean nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel (const NMPObject *obj,
gpointer user_data);
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),
NMPObjectPredicateFunc predicate,
gpointer user_data);
/* convienience methods to lookup the link and access fields of NMPlatformLink. */
@ -1095,13 +1158,36 @@ 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, guint8 plen);
gboolean nm_platform_ip4_address_sync (NMPlatform *self, int ifindex, GPtrArray *known_addresse);
gboolean nm_platform_ip6_address_sync (NMPlatform *self, int ifindex, const GPtrArray *known_addresses, gboolean keep_link_local);
gboolean nm_platform_address_flush (NMPlatform *self, int ifindex);
gboolean nm_platform_ip_address_flush (NMPlatform *self,
int addr_family,
int ifindex);
gboolean nm_platform_ip4_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route);
gboolean nm_platform_ip6_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route);
void nm_platform_ip_route_normalize (int addr_family,
NMPlatformIPRoute *route);
NMPlatformError nm_platform_ip_route_add (NMPlatform *self,
NMPNlmFlags flags,
const NMPObject *route);
NMPlatformError nm_platform_ip4_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route);
NMPlatformError nm_platform_ip6_route_add (NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route);
gboolean nm_platform_ip_route_delete (NMPlatform *self, const NMPObject *route);
gboolean nm_platform_ip_route_sync (NMPlatform *self,
int addr_family,
int ifindex,
GPtrArray *routes,
NMPObjectPredicateFunc kernel_delete_predicate,
gpointer kernel_delete_userdata);
gboolean nm_platform_ip_route_flush (NMPlatform *self,
int addr_family,
int ifindex);
NMPlatformError nm_platform_ip_route_get (NMPlatform *self,
int addr_family,
gconstpointer address,
NMPObject **out_route);
const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len);
const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len);
const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len);
@ -1192,6 +1278,10 @@ gboolean nm_platform_ethtool_set_wake_on_lan (NMPlatform *self, int ifindex, NMS
gboolean nm_platform_ethtool_set_link_settings (NMPlatform *self, int ifindex, gboolean autoneg, guint32 speed, NMPlatformLinkDuplexType duplex);
gboolean nm_platform_ethtool_get_link_settings (NMPlatform *self, int ifindex, gboolean *out_autoneg, guint32 *out_speed, NMPlatformLinkDuplexType *out_duplex);
void nm_platform_ip4_dev_route_blacklist_set (NMPlatform *self,
int ifindex,
GPtrArray *ip4_dev_route_blacklist);
struct _NMDedupMultiIndex *nm_platform_get_multi_idx (NMPlatform *self);
#endif /* __NETWORKMANAGER_PLATFORM_H__ */

View file

@ -676,11 +676,11 @@ ASSERT_nmp_cache_ops (const NMPCache *cache,
const NMDedupMultiHeadEntry *nm_platform_lookup_all (NMPlatform *platform,
NMPCacheIdType cache_id_type,
NMPObject *obj);
const NMPObject *obj);
const NMDedupMultiEntry *nm_platform_lookup_entry (NMPlatform *platform,
NMPCacheIdType cache_id_type,
NMPObject *obj);
const NMPObject *obj);
static inline const NMDedupMultiHeadEntry *
nm_platform_lookup_obj_type (NMPlatform *platform,
@ -717,7 +717,7 @@ static inline GPtrArray *
nm_platform_lookup_addrroute_clone (NMPlatform *platform,
NMPObjectType obj_type,
int ifindex,
gboolean (*predicate) (const NMPObject *obj, gpointer user_data),
NMPObjectPredicateFunc predicate,
gpointer user_data)
{
NMPLookup lookup;
@ -739,7 +739,7 @@ nm_platform_lookup_route_default (NMPlatform *platform,
static inline GPtrArray *
nm_platform_lookup_route_default_clone (NMPlatform *platform,
NMPObjectType obj_type,
gboolean (*predicate) (const NMPObject *obj, gpointer user_data),
NMPObjectPredicateFunc predicate,
gpointer user_data)
{
NMPLookup lookup;

View file

@ -1009,7 +1009,7 @@ void nmtstp_ip4_route_add (NMPlatform *platform,
route.metric = metric;
route.mss = mss;
g_assert (nm_platform_ip4_route_add (platform, NMP_NLM_FLAG_REPLACE, &route));
g_assert_cmpint (nm_platform_ip4_route_add (platform, NMP_NLM_FLAG_REPLACE, &route), ==, NM_PLATFORM_ERROR_SUCCESS);
}
void nmtstp_ip6_route_add (NMPlatform *platform,
@ -1033,7 +1033,7 @@ void nmtstp_ip6_route_add (NMPlatform *platform,
route.metric = metric;
route.mss = mss;
g_assert (nm_platform_ip6_route_add (platform, NMP_NLM_FLAG_REPLACE, &route));
g_assert_cmpint (nm_platform_ip6_route_add (platform, NMP_NLM_FLAG_REPLACE, &route), ==, NM_PLATFORM_ERROR_SUCCESS);
}
/*****************************************************************************/

View file

@ -230,7 +230,7 @@ nmtstp_ip4_route_get_all (NMPlatform *platform,
return nm_platform_lookup_addrroute_clone (platform,
NMP_OBJECT_TYPE_IP4_ROUTE,
ifindex,
nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
NULL);
}
@ -241,7 +241,7 @@ nmtstp_ip6_route_get_all (NMPlatform *platform,
return nm_platform_lookup_addrroute_clone (platform,
NMP_OBJECT_TYPE_IP6_ROUTE,
ifindex,
nm_platform_lookup_predicate_routes_skip_rtprot_kernel,
nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel,
NULL);
}

View file

@ -791,7 +791,7 @@ test_software_detect (gconstpointer user_data)
* namespaced, the creation can fail if a macvtap in another namespace
* has the same index. Try to detect this situation and skip already
* used indexes.
* http://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=17af2bce88d31e65ed73d638bb752d2e13c66ced
* The fix (17af2bce) is included kernel 4.7, dated 24 July, 2016.
*/
for (i = ifindex_parent + 1; i < ifindex_parent + 100; i++) {
snprintf (buf, sizeof (buf), "/sys/class/macvtap/tap%d", i);
@ -1728,8 +1728,8 @@ test_nl_bugs_veth (void)
pllink_veth0 = nm_platform_link_get (NM_PLATFORM_GET, ifindex_veth0);
g_assert (pllink_veth0);
if (pllink_veth0->parent == 0) {
/* pre-4.1 kernels don't support exposing the veth peer as IFA_LINK. skip the remainder
* of the test. */
/* Kernels prior to 4.1 dated 21 June, 2015 don't support exposing the veth peer
* as IFA_LINK. skip the remainder of the test. */
goto out;
}
g_assert_cmpint (pllink_veth0->parent, ==, ifindex_veth1);
@ -2023,8 +2023,8 @@ test_netns_general (gpointer fixture, gconstpointer test_data)
_sysctl_assert_eq (platform_1, "/proc/sys/net/ipv6/conf/dummy2b/disable_ipv6", NULL);
_sysctl_assert_eq (platform_2, "/proc/sys/net/ipv6/conf/dummy2a/disable_ipv6", NULL);
/* older kernels (Ubuntu 12.04) don't support ethtool -i for dummy devices. Work around that and
* skip asserts that are known to fail. */
/* Kernels prior to 3.19 dated 8 February, 2015 don't support ethtool -i for dummy devices.
* Work around that and skip asserts that are known to fail. */
ethtool_support = nmtstp_run_command ("ethtool -i dummy1_ > /dev/null") == 0;
if (ethtool_support) {
g_assert (nmp_utils_ethtool_get_driver_info (nmtstp_link_get_typed (platform_1, 0, "dummy1_", NM_LINK_TYPE_DUMMY)->ifindex, &driver_info));

View file

@ -388,6 +388,43 @@ test_ip6_route (void)
/*****************************************************************************/
static void
test_ip_route_get (void)
{
int ifindex = nm_platform_link_get_ifindex (NM_PLATFORM_GET, DEVICE_NAME);
in_addr_t a;
NMPlatformError result;
nm_auto_nmpobj NMPObject *route = NULL;
const NMPlatformIP4Route *r;
nmtstp_run_command_check ("ip route add 1.2.3.0/24 dev %s", DEVICE_NAME);
NMTST_WAIT_ASSERT (100, {
nmtstp_wait_for_signal (NM_PLATFORM_GET, 10);
if (nmtstp_ip4_route_get (NM_PLATFORM_GET, ifindex, nmtst_inet4_from_string ("1.2.3.0"), 24, 0, 0))
break;
});
a = nmtst_inet4_from_string ("1.2.3.1");
result = nm_platform_ip_route_get (NM_PLATFORM_GET,
AF_INET,
&a,
&route);
g_assert (result == NM_PLATFORM_ERROR_SUCCESS);
g_assert (NMP_OBJECT_GET_TYPE (route) == NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert (!NMP_OBJECT_IS_STACKINIT (route));
g_assert (route->parent._ref_count == 1);
r = NMP_OBJECT_CAST_IP4_ROUTE (route);
g_assert (r->rt_cloned);
g_assert (r->network == a);
g_assert (r->plen == 32);
nmtstp_run_command_check ("ip route flush dev %s", DEVICE_NAME);
nmtstp_wait_for_signal (NM_PLATFORM_GET, 50);
}
static void
test_ip4_zero_gateway (void)
{
@ -432,7 +469,7 @@ test_ip4_route_options (void)
route.mtu = 1350;
route.lock_cwnd = TRUE;
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &route));
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &route) == NM_PLATFORM_ERROR_SUCCESS);
/* Test route listing */
routes = nmtstp_ip4_route_get_all (NM_PLATFORM_GET, ifindex);
@ -560,7 +597,7 @@ test_ip6_route_options (gconstpointer test_data)
_wait_for_ipv6_addr_non_tentative (NM_PLATFORM_GET, 400, IFINDEX, addr_n, addr_in6);
for (i = 0; i < rts_n; i++)
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]));
g_assert (nm_platform_ip6_route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, &rts_add[i]) == NM_PLATFORM_ERROR_SUCCESS);
routes = nmtstp_ip6_route_get_all (NM_PLATFORM_GET, IFINDEX);
switch (TEST_IDX) {
@ -666,7 +703,7 @@ again_find_idx:
order_idx[order_len++] = idx;
r->ifindex = iface_data[idx].ifindex;
g_assert (nm_platform_ip4_route_add (platform, NMP_NLM_FLAG_APPEND, r));
g_assert (nm_platform_ip4_route_add (platform, NMP_NLM_FLAG_APPEND, r) == NM_PLATFORM_ERROR_SUCCESS);
} else {
i = nmtst_get_rand_int () % order_len;
idx = order_idx[i];
@ -739,6 +776,7 @@ _nmtstp_setup_tests (void)
if (nmtstp_is_root_test ()) {
add_test_func_data ("/route/ip/1", test_ip, GINT_TO_POINTER (1));
add_test_func ("/route/ip_route_get", test_ip_route_get);
add_test_func ("/route/ip4_zero_gateway", test_ip4_zero_gateway);
}
}

View file

@ -1,974 +0,0 @@
/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Copyright (C) 2015 Red Hat, Inc.
*
*/
#include "nm-default.h"
#include <arpa/inet.h>
#include <linux/rtnetlink.h>
#include "platform/nm-platform.h"
#include "platform/nm-platform-utils.h"
#include "nm-route-manager.h"
#include "platform/tests/test-common.h"
typedef struct {
int ifindex0, ifindex1;
} test_fixture;
NMRouteManager *route_manager_get (void);
NM_DEFINE_SINGLETON_GETTER (NMRouteManager, route_manager_get, NM_TYPE_ROUTE_MANAGER);
/*****************************************************************************/
static void
setup_dev0_ip4 (int ifindex, guint mss_of_first_route, guint32 metric_of_second_route)
{
GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
NMPlatformIP4Route route = { 0 };
route.ifindex = ifindex;
route.mss = 0;
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
inet_pton (AF_INET, "6.6.6.0", &route.network);
route.plen = 24;
route.gateway = INADDR_ANY;
route.metric = 20;
route.mss = mss_of_first_route;
g_array_append_val (routes, route);
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
inet_pton (AF_INET, "7.0.0.0", &route.network);
route.plen = 8;
inet_pton (AF_INET, "6.6.6.1", &route.gateway);
route.metric = metric_of_second_route;
route.mss = 0;
g_array_append_val (routes, route);
nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
g_array_free (routes, TRUE);
}
static void
setup_dev1_ip4 (int ifindex)
{
GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
NMPlatformIP4Route route = { 0 };
route.ifindex = ifindex;
route.mss = 0;
/* Add some route outside of route manager. The route manager
* should get rid of it upon sync. */
nmtstp_ip4_route_add (NM_PLATFORM_GET,
route.ifindex,
NM_IP_CONFIG_SOURCE_USER,
nmtst_inet4_from_string ("9.0.0.0"),
8,
INADDR_ANY,
0,
10,
route.mss);
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
inet_pton (AF_INET, "6.6.6.0", &route.network);
route.plen = 24;
route.gateway = INADDR_ANY;
route.metric = 20;
g_array_append_val (routes, route);
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
inet_pton (AF_INET, "7.0.0.0", &route.network);
route.plen = 8;
route.gateway = INADDR_ANY;
route.metric = 22;
g_array_append_val (routes, route);
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
inet_pton (AF_INET, "8.0.0.0", &route.network);
route.plen = 8;
inet_pton (AF_INET, "6.6.6.2", &route.gateway);
route.metric = 22;
g_array_append_val (routes, route);
nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
g_array_free (routes, TRUE);
}
static void
update_dev0_ip4 (int ifindex)
{
GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
NMPlatformIP4Route route = { 0 };
route.ifindex = ifindex;
route.mss = 0;
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
inet_pton (AF_INET, "6.6.6.0", &route.network);
route.plen = 24;
route.gateway = INADDR_ANY;
route.metric = 20;
g_array_append_val (routes, route);
route.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER);
inet_pton (AF_INET, "7.0.0.0", &route.network);
route.plen = 8;
route.gateway = INADDR_ANY;
route.metric = 21;
g_array_append_val (routes, route);
nm_route_manager_ip4_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
g_array_free (routes, TRUE);
}
static GArray *
ip_routes (test_fixture *fixture, NMPObjectType obj_type)
{
const NMPClass *klass;
GArray *routes;
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter iter;
const NMPObject *plobj = NULL;
guint i;
g_assert (NM_IN_SET (obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE));
klass = nmp_class_from_type (obj_type);
routes = g_array_new (FALSE, FALSE, klass->sizeof_public);
for (i = 0; i < 2; i++) {
int ifindex;
if (i == 0)
ifindex = fixture->ifindex0;
else
ifindex = fixture->ifindex1;
pl_head_entry = nm_platform_lookup_addrroute (NM_PLATFORM_GET,
obj_type,
ifindex);
nmp_cache_iter_for_each (&iter, pl_head_entry, &plobj) {
const NMPlatformIPRoute *r = NMP_OBJECT_CAST_IP_ROUTE (plobj);
if (NM_PLATFORM_IP_ROUTE_IS_DEFAULT (r))
continue;
if (r->rt_source == NM_IP_CONFIG_SOURCE_RTPROT_KERNEL)
continue;
g_assert (r->ifindex == ifindex);
g_assert (nmp_object_is_visible (plobj));
g_array_append_vals (routes, r, 1);
}
}
return routes;
}
static void
test_ip4 (test_fixture *fixture, gconstpointer user_data)
{
GArray *routes;
NMPlatformIP4Route state1[] = {
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("6.6.6.0"),
.plen = 24,
.ifindex = fixture->ifindex0,
.gateway = INADDR_ANY,
.metric = 20,
.mss = 1000,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("7.0.0.0"),
.plen = 8,
.ifindex = fixture->ifindex0,
.gateway = nmtst_inet4_from_string ("6.6.6.1"),
.metric = 21021,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("7.0.0.0"),
.plen = 8,
.ifindex = fixture->ifindex1,
.gateway = INADDR_ANY,
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("6.6.6.0"),
.plen = 24,
.ifindex = fixture->ifindex1,
.gateway = INADDR_ANY,
.metric = 21,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("8.0.0.0"),
.plen = 8,
.ifindex = fixture->ifindex1,
.gateway = nmtst_inet4_from_string ("6.6.6.2"),
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
},
};
NMPlatformIP4Route state2[] = {
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("6.6.6.0"),
.plen = 24,
.ifindex = fixture->ifindex0,
.gateway = INADDR_ANY,
.metric = 20,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("7.0.0.0"),
.plen = 8,
.ifindex = fixture->ifindex0,
.gateway = INADDR_ANY,
.metric = 21,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("7.0.0.0"),
.plen = 8,
.ifindex = fixture->ifindex1,
.gateway = INADDR_ANY,
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("6.6.6.0"),
.plen = 24,
.ifindex = fixture->ifindex1,
.gateway = INADDR_ANY,
.metric = 21,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("8.0.0.0"),
.plen = 8,
.ifindex = fixture->ifindex1,
.gateway = nmtst_inet4_from_string ("6.6.6.2"),
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
},
};
NMPlatformIP4Route state3[] = {
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("7.0.0.0"),
.plen = 8,
.ifindex = fixture->ifindex1,
.gateway = INADDR_ANY,
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("6.6.6.0"),
.plen = 24,
.ifindex = fixture->ifindex1,
.gateway = INADDR_ANY,
.metric = 20,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("8.0.0.0"),
.plen = 8,
.ifindex = fixture->ifindex1,
.gateway = nmtst_inet4_from_string ("6.6.6.2"),
.metric = 22,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_UNIVERSE),
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = nmtst_inet4_from_string ("6.6.6.0"),
.plen = 24,
.ifindex = fixture->ifindex1,
.gateway = INADDR_ANY,
/* this is a ghost entry because we synced ifindex0 and restore the route
* with metric 20 (above). But we don't remove the metric 21. */
.metric = 21,
.mss = 0,
.scope_inv = nm_platform_route_scope_inv (RT_SCOPE_LINK),
},
};
setup_dev0_ip4 (fixture->ifindex0, 1000, 21021);
setup_dev1_ip4 (fixture->ifindex1);
g_test_assert_expected_messages ();
/* - 6.6.6.0/24 on dev0 won over 6.6.6.0/24 on dev1
* - 6.6.6.0/24 on dev1 has metric bumped.
* - 7.0.0.0/8 route, metric 21021 added
* - 7.0.0.0/8 route, metric 22 added
* - 8.0.0.0/8 could be added. */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state1, routes->len, TRUE);
g_array_free (routes, TRUE);
setup_dev1_ip4 (fixture->ifindex1);
g_test_assert_expected_messages ();
setup_dev0_ip4 (fixture->ifindex0, 0, 21);
/* Ensure nothing changed. */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
state1[0].mss = 0;
state1[1].metric = 21;
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state1, routes->len, TRUE);
g_array_free (routes, TRUE);
update_dev0_ip4 (fixture->ifindex0);
/* minor changes in the routes. Quite similar to state1. */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state2));
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state2, routes->len, TRUE);
g_array_free (routes, TRUE);
nm_route_manager_route_flush (route_manager_get (), fixture->ifindex0);
/* 6.6.6.0/24 is now on dev1
* 6.6.6.0/24 is also still on dev1 with bumped metric 21.
* 7.0.0.0/8 gone from dev0, still present on dev1
* 8.0.0.0/8 is present on dev1
* No dev0 routes left. */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state3));
nmtst_platform_ip4_routes_equal ((NMPlatformIP4Route *) routes->data, state3, routes->len, TRUE);
g_array_free (routes, TRUE);
nm_route_manager_route_flush (route_manager_get (), fixture->ifindex1);
/* No routes left. */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP4_ROUTE);
g_assert_cmpint (routes->len, ==, 0);
g_array_free (routes, TRUE);
}
static void
setup_dev0_ip6 (int ifindex)
{
GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route));
NMPlatformIP6Route *route;
/* Add an address so that a route to the gateway below gets added. */
nm_platform_ip6_address_add (NM_PLATFORM_GET,
ifindex,
*nmtst_inet6_from_string ("2001:db8:8086::666"),
64,
in6addr_any,
3600,
3600,
0);
route = nmtst_platform_ip6_route_full ("2001:db8:8086::",
48,
NULL,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
20,
0);
g_array_append_val (routes, *route);
route = nmtst_platform_ip6_route_full ("2001:db8:1337::",
48,
NULL,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
0,
0);
g_array_append_val (routes, *route);
route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::",
64,
"2001:db8:8086::1",
ifindex,
NM_IP_CONFIG_SOURCE_USER,
21,
0);
g_array_append_val (routes, *route);
nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
g_array_free (routes, TRUE);
}
static void
setup_dev1_ip6 (int ifindex)
{
GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route));
NMPlatformIP6Route *route;
/* Add some route outside of route manager. The route manager
* should get rid of it upon sync. */
nmtstp_ip6_route_add (NM_PLATFORM_GET,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
*nmtst_inet6_from_string ("2001:db8:8088::"),
48,
in6addr_any,
in6addr_any,
10,
0);
route = nmtst_platform_ip6_route_full ("2001:db8:8086::",
48,
NULL,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
20,
0);
g_array_append_val (routes, *route);
route = nmtst_platform_ip6_route_full ("2001:db8:1337::",
48,
NULL,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
1024,
0);
g_array_append_val (routes, *route);
route = nmtst_platform_ip6_route_full ("2001:db8:d34d::",
64,
"2001:db8:8086::2",
ifindex,
NM_IP_CONFIG_SOURCE_USER,
20,
0);
g_array_append_val (routes, *route);
route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::",
64,
NULL,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
22,
0);
g_array_append_val (routes, *route);
nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
g_array_free (routes, TRUE);
}
static void
update_dev0_ip6 (int ifindex)
{
GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP6Route));
NMPlatformIP6Route *route;
/* Add an address so that a route to the gateway below gets added. */
nm_platform_ip6_address_add (NM_PLATFORM_GET,
ifindex,
*nmtst_inet6_from_string ("2001:db8:8086::2"),
64,
in6addr_any,
3600,
3600,
0);
route = nmtst_platform_ip6_route_full ("2001:db8:8086::",
48,
NULL,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
20,
0);
g_array_append_val (routes, *route);
route = nmtst_platform_ip6_route_full ("2001:db8:1337::",
48,
NULL,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
0,
0);
g_array_append_val (routes, *route);
route = nmtst_platform_ip6_route_full ("2001:db8:abad:c0de::",
64,
NULL,
ifindex,
NM_IP_CONFIG_SOURCE_USER,
21,
0);
g_array_append_val (routes, *route);
nm_route_manager_ip6_route_sync (route_manager_get (), ifindex, routes, TRUE, TRUE);
g_array_free (routes, TRUE);
}
static void
test_ip6 (test_fixture *fixture, gconstpointer user_data)
{
GArray *routes;
int i;
NMPlatformIP6Route state1[] = {
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:8086::"),
.plen = 48,
.ifindex = fixture->ifindex0,
.gateway = in6addr_any,
.metric = 20,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:1337::"),
.plen = 48,
.ifindex = fixture->ifindex0,
.gateway = in6addr_any,
.metric = 1024,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
.plen = 64,
.ifindex = fixture->ifindex0,
.gateway = *nmtst_inet6_from_string ("2001:db8:8086::1"),
.metric = 21,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
.plen = 64,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 22,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:1337::"),
.plen = 48,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 1025,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:8086::"),
.plen = 48,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 21,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:d34d::"),
.plen = 64,
.ifindex = fixture->ifindex1,
.gateway = *nmtst_inet6_from_string ("2001:db8:8086::2"),
.metric = 20,
.mss = 0,
},
};
NMPlatformIP6Route state2[] = {
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:8086::"),
.plen = 48,
.ifindex = fixture->ifindex0,
.gateway = in6addr_any,
.metric = 20,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:1337::"),
.plen = 48,
.ifindex = fixture->ifindex0,
.gateway = in6addr_any,
.metric = 1024,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
.plen = 64,
.ifindex = fixture->ifindex0,
.gateway = in6addr_any,
.metric = 21,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
.plen = 64,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 22,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:1337::"),
.plen = 48,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 1025,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:8086::"),
.plen = 48,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 21,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:d34d::"),
.plen = 64,
.ifindex = fixture->ifindex1,
.gateway = *nmtst_inet6_from_string ("2001:db8:8086::2"),
.metric = 20,
.mss = 0,
},
};
NMPlatformIP6Route state3[] = {
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
.plen = 64,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 22,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:8086::"),
.plen = 48,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 20,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:1337::"),
.plen = 48,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 1024,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:1337::"),
.plen = 48,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 1025,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:8086::"),
.plen = 48,
.ifindex = fixture->ifindex1,
.gateway = in6addr_any,
.metric = 21,
.mss = 0,
},
{
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:d34d::"),
.plen = 64,
.ifindex = fixture->ifindex1,
.gateway = *nmtst_inet6_from_string ("2001:db8:8086::2"),
.metric = 20,
.mss = 0,
},
};
setup_dev0_ip6 (fixture->ifindex0);
setup_dev1_ip6 (fixture->ifindex1);
g_test_assert_expected_messages ();
/* 2001:db8:8086::/48 on dev0 won over 2001:db8:8086::/48 on dev1
* 2001:db8:d34d::/64 on dev1 could not be added
* 2001:db8:1337::/48 on dev0 won over 2001:db8:1337::/48 on dev1 and has metric 1024
* 2001:db8:abad:c0de::/64 routes did not clash */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state1, routes->len, TRUE);
g_array_free (routes, TRUE);
setup_dev1_ip6 (fixture->ifindex1);
g_test_assert_expected_messages ();
setup_dev0_ip6 (fixture->ifindex0);
/* Ensure nothing changed. */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state1));
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state1, routes->len, TRUE);
g_array_free (routes, TRUE);
update_dev0_ip6 (fixture->ifindex0);
/* 2001:db8:abad:c0de::/64 on dev0 was updated for gateway removal*/
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
if (routes->len != G_N_ELEMENTS (state2)) {
NMPlatformIP6Route rr;
/* hm, seems kernel may wrongly treat IPv6 gateway for `ip route replace`.
* See rh#1480427.
*
* We would expect that `ip route replace` replaces an existing route.
* However, kernel may not do so, and instead prepend it.
*
* Work around that, by checking if such a route exists and accept
* it. */
g_assert (nmtstp_is_root_test ());
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state2) + 1);
rr = ((NMPlatformIP6Route) {
.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (NM_IP_CONFIG_SOURCE_USER),
.network = *nmtst_inet6_from_string ("2001:db8:abad:c0de::"),
.plen = 64,
.ifindex = fixture->ifindex0,
.gateway = *nmtst_inet6_from_string ("2001:db8:8086::1"),
.metric = 21,
.mss = 0,
});
for (i = 0; i < routes->len; i++) {
if (nm_platform_ip6_route_cmp (&rr,
&g_array_index (routes, NMPlatformIP6Route, i),
NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0)
continue;
g_array_remove_index (routes, i);
break;
}
}
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state2, routes->len, TRUE);
g_array_free (routes, TRUE);
nm_route_manager_route_flush (route_manager_get (), fixture->ifindex0);
/* 2001:db8:abad:c0de::/64 on dev1 is still there, went away from dev0
* 2001:db8:8086::/48 is now on dev1
* 2001:db8:1337::/48 is now on dev1, metric of 1024 still applies
* 2001:db8:d34d::/64 is present now that 2001:db8:8086::/48 is on dev1
* No dev0 routes left. */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, G_N_ELEMENTS (state3));
nmtst_platform_ip6_routes_equal ((NMPlatformIP6Route *) routes->data, state3, routes->len, TRUE);
g_array_free (routes, TRUE);
nm_route_manager_route_flush (route_manager_get (), fixture->ifindex1);
/* No routes left. */
routes = ip_routes (fixture, NMP_OBJECT_TYPE_IP6_ROUTE);
g_assert_cmpint (routes->len, ==, 0);
g_array_free (routes, TRUE);
}
/*****************************************************************************/
static void
_assert_route_check (const NMPlatformVTableRoute *vtable, gboolean has, const NMPlatformIPXRoute *route)
{
const NMPlatformIPXRoute *r;
NMPlatformIPXRoute c;
g_assert (route);
if (vtable->is_ip4)
r = (const NMPlatformIPXRoute *) nmtstp_ip4_route_get (NM_PLATFORM_GET, route->rx.ifindex, route->r4.network, route->rx.plen, route->rx.metric, route->r4.tos);
else
r = (const NMPlatformIPXRoute *) nmtstp_ip6_route_get (NM_PLATFORM_GET, route->rx.ifindex, &route->r6.network, route->rx.plen, route->rx.metric, &route->r6.src, route->r6.src_plen);
if (!has) {
g_assert (!r);
} else {
char buf[sizeof (_nm_utils_to_string_buffer)];
if (r) {
if (vtable->is_ip4)
c.r4 = route->r4;
else
c.r6 = route->r6;
c.rx.rt_source = nmp_utils_ip_config_source_round_trip_rtprot (c.rx.rt_source);
}
if (!r || vtable->route_cmp (r, &c, NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) != 0) {
g_error ("Invalid route. Expect %s, has %s",
vtable->route_to_string (&c, NULL, 0),
vtable->route_to_string (r, buf, sizeof (buf)));
}
}
}
static void
test_ip4_full_sync (test_fixture *fixture, gconstpointer user_data)
{
const NMPlatformVTableRoute *vtable = &nm_platform_vtable_route_v4;
gs_unref_array GArray *routes = g_array_new (FALSE, FALSE, sizeof (NMPlatformIP4Route));
NMPlatformIP4Route r01, r02, r03;
nm_log_dbg (LOGD_CORE, "TEST start test_ip4_full_sync(): start");
r01 = *nmtst_platform_ip4_route_full ("12.3.4.0", 24, NULL,
fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER,
100, 0, RT_SCOPE_LINK, NULL);
r02 = *nmtst_platform_ip4_route_full ("13.4.5.6", 32, "12.3.4.1",
fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER,
100, 0, RT_SCOPE_UNIVERSE, NULL);
r03 = *nmtst_platform_ip4_route_full ("14.5.6.7", 32, "12.3.4.1",
fixture->ifindex0, NM_IP_CONFIG_SOURCE_USER,
110, 0, RT_SCOPE_UNIVERSE, NULL);
g_array_set_size (routes, 2);
g_array_index (routes, NMPlatformIP4Route, 0) = r01;
g_array_index (routes, NMPlatformIP4Route, 1) = r02;
nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, TRUE);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02);
_assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r03);
vtable->route_add (NM_PLATFORM_GET, NMP_NLM_FLAG_REPLACE, (const NMPlatformIPXRoute *) &r03, 0, -1);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r03);
nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, FALSE);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r02);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r03);
g_array_set_size (routes, 1);
nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, FALSE);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
_assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r02);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r03);
nm_route_manager_ip4_route_sync (route_manager_get (), fixture->ifindex0, routes, TRUE, TRUE);
_assert_route_check (vtable, TRUE, (const NMPlatformIPXRoute *) &r01);
_assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r02);
_assert_route_check (vtable, FALSE, (const NMPlatformIPXRoute *) &r03);
nm_log_dbg (LOGD_CORE, "TEST test_ip4_full_sync(): done");
}
/*****************************************************************************/
static void
fixture_setup (test_fixture *fixture, gconstpointer user_data)
{
SignalData *link_added;
link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED,
NM_PLATFORM_SIGNAL_ADDED,
link_callback,
"nm-test-device0");
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0"));
g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "nm-test-device0"));
g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, "nm-test-device0", NULL) == NM_PLATFORM_ERROR_SUCCESS);
accept_signal (link_added);
free_signal (link_added);
fixture->ifindex0 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device0");
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex0, NULL));
link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED,
NM_PLATFORM_SIGNAL_ADDED,
link_callback,
"nm-test-device1");
nm_platform_link_delete (NM_PLATFORM_GET, nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1"));
g_assert (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "nm-test-device1"));
g_assert (nm_platform_link_dummy_add (NM_PLATFORM_GET, "nm-test-device1", NULL) == NM_PLATFORM_ERROR_SUCCESS);
accept_signal (link_added);
free_signal (link_added);
fixture->ifindex1 = nm_platform_link_get_ifindex (NM_PLATFORM_GET, "nm-test-device1");
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, fixture->ifindex1, NULL));
}
static void
fixture_teardown (test_fixture *fixture, gconstpointer user_data)
{
nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex0);
nm_platform_link_delete (NM_PLATFORM_GET, fixture->ifindex1);
}
/*****************************************************************************/
NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP;
void
_nmtstp_init_tests (int *argc, char ***argv)
{
nmtst_init_assert_logging (argc, argv, "WARN", "ALL");
}
void
_nmtstp_setup_tests (void)
{
g_test_add ("/route-manager/ip4", test_fixture, NULL, fixture_setup, test_ip4, fixture_teardown);
g_test_add ("/route-manager/ip6", test_fixture, NULL, fixture_setup, test_ip6, fixture_teardown);
g_test_add ("/route-manager/ip4-full-sync", test_fixture, NULL, fixture_setup, test_ip4_full_sync, fixture_teardown);
}

View file

@ -45,7 +45,6 @@
#include "nm-core-internal.h"
#include "nm-pacrunner-manager.h"
#include "nm-default-route-manager.h"
#include "nm-route-manager.h"
#include "nm-firewall-manager.h"
#include "nm-config.h"
#include "nm-vpn-plugin-info.h"
@ -394,9 +393,11 @@ vpn_cleanup (NMVpnConnection *self, NMDevice *parent_dev)
NMVpnConnectionPrivate *priv = NM_VPN_CONNECTION_GET_PRIVATE (self);
if (priv->ip_ifindex) {
nm_platform_link_set_down (nm_netns_get_platform (priv->netns), priv->ip_ifindex);
nm_route_manager_route_flush (nm_netns_get_route_manager (priv->netns), priv->ip_ifindex);
nm_platform_address_flush (nm_netns_get_platform (priv->netns), priv->ip_ifindex);
NMPlatform *platform = nm_netns_get_platform (priv->netns);
nm_platform_link_set_down (platform, priv->ip_ifindex);
nm_platform_ip_route_flush (platform, AF_UNSPEC, priv->ip_ifindex);
nm_platform_ip_address_flush (platform, AF_UNSPEC, priv->ip_ifindex);
}
remove_parent_device_config (self, parent_dev);
@ -704,41 +705,55 @@ device_state_changed (NMActiveConnection *active,
}
static void
add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32 vpn_gw)
add_ip4_vpn_gateway_route (NMIP4Config *config,
NMDevice *parent_device,
in_addr_t vpn_gw,
NMPlatform *platform)
{
NMIP4Config *parent_config;
guint32 parent_gw;
NMPlatformIP4Route route;
guint32 route_metric;
nm_auto_nmpobj const NMPObject *route_resolved = NULL;
g_return_if_fail (NM_IS_IP4_CONFIG (config));
g_return_if_fail (NM_IS_DEVICE (parent_device));
g_return_if_fail (vpn_gw != 0);
nm_assert (nm_ip4_config_get_ifindex (config) > 0);
/* Set up a route to the VPN gateway's public IP address through the default
* network device if the VPN gateway is on a different subnet.
*/
parent_config = nm_device_get_ip4_config (parent_device);
g_return_if_fail (parent_config != NULL);
parent_gw = nm_ip4_config_get_gateway (parent_config);
/* If the VPN gateway is in the same subnet as one of the parent device's
* IP addresses, don't add the host route to it, but a route through the
* parent device.
*/
if (nm_ip4_config_destination_is_direct (parent_config, vpn_gw, 32))
parent_gw = 0;
/* actually, let's ask kernel how to reach @vpn_gw. If (and only if)
* the destination is on @parent_device, then we take that @parent_gw. */
if (nm_platform_ip_route_get (platform,
AF_INET,
&vpn_gw,
(NMPObject **) &route_resolved) == NM_PLATFORM_ERROR_SUCCESS) {
const NMPlatformIP4Route *r = NMP_OBJECT_CAST_IP4_ROUTE (route_resolved);
if (r->ifindex == nm_ip4_config_get_ifindex (config))
parent_gw = r->gateway;
}
route_metric = nm_device_get_ip4_route_metric (parent_device);
memset (&route, 0, sizeof (route));
route.network = vpn_gw;
route.plen = 32;
route.gateway = parent_gw;
/* Set up a device route if the parent device has no gateway */
if (!parent_gw)
route.ifindex = nm_device_get_ip_ifindex (parent_device);
/* If the VPN gateway is in the same subnet as one of the parent device's
* IP addresses, don't add the host route to it, but a route through the
* parent device.
*/
if (nm_ip4_config_destination_is_direct (parent_config, vpn_gw, 32))
route.gateway = 0;
route.rt_source = NM_IP_CONFIG_SOURCE_VPN;
route.metric = route_metric;
nm_ip4_config_add_route (config, &route);
@ -754,7 +769,6 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32
route.plen = 32;
route.rt_source = NM_IP_CONFIG_SOURCE_VPN;
route.metric = route_metric;
nm_ip4_config_add_route (config, &route);
}
}
@ -762,37 +776,54 @@ add_ip4_vpn_gateway_route (NMIP4Config *config, NMDevice *parent_device, guint32
static void
add_ip6_vpn_gateway_route (NMIP6Config *config,
NMDevice *parent_device,
const struct in6_addr *vpn_gw)
const struct in6_addr *vpn_gw,
NMPlatform *platform)
{
NMIP6Config *parent_config;
const struct in6_addr *parent_gw;
NMPlatformIP6Route route;
guint32 route_metric;
nm_auto_nmpobj const NMPObject *route_resolved = NULL;
g_return_if_fail (NM_IS_IP6_CONFIG (config));
g_return_if_fail (NM_IS_DEVICE (parent_device));
g_return_if_fail (vpn_gw != NULL);
nm_assert (nm_ip6_config_get_ifindex (config) > 0);
parent_config = nm_device_get_ip6_config (parent_device);
g_return_if_fail (parent_config != NULL);
/* we add a direct route to the VPN gateway, but we only do that
* on the @parent_device. That is probably not correct in every case... */
parent_gw = nm_ip6_config_get_gateway (parent_config);
if (!parent_gw)
return;
/* If the VPN gateway is in the same subnet as one of the parent device's
* IP addresses, don't add the host route to it, but a route through the
* parent device.
*/
if (nm_ip6_config_destination_is_direct (parent_config, vpn_gw, 128))
parent_gw = &in6addr_any;
/* actually, let's ask kernel how to reach @vpn_gw. If (and only if)
* the destination is on @parent_device, then we take that @parent_gw. */
if (nm_platform_ip_route_get (platform,
AF_INET6,
vpn_gw,
(NMPObject **) &route_resolved) == NM_PLATFORM_ERROR_SUCCESS) {
const NMPlatformIP6Route *r = NMP_OBJECT_CAST_IP6_ROUTE (route_resolved);
if (r->ifindex == nm_ip6_config_get_ifindex (config))
parent_gw = &r->gateway;
}
route_metric = nm_device_get_ip6_route_metric (parent_device);
memset (&route, 0, sizeof (route));
route.network = *vpn_gw;
route.plen = 128;
route.gateway = *parent_gw;
/* If the VPN gateway is in the same subnet as one of the parent device's
* IP addresses, don't add the host route to it, but a route through the
* parent device.
*/
if (nm_ip6_config_destination_is_direct (parent_config, vpn_gw, 128))
route.gateway = in6addr_any;
route.rt_source = NM_IP_CONFIG_SOURCE_VPN;
route.metric = route_metric;
nm_ip6_config_add_route (config, &route);
@ -802,13 +833,14 @@ add_ip6_vpn_gateway_route (NMIP6Config *config,
* routes include a subnet that matches the parent device's subnet,
* the parent device's gateway would get routed through the VPN and fail.
*/
memset (&route, 0, sizeof (route));
route.network = *parent_gw;
route.plen = 128;
route.rt_source = NM_IP_CONFIG_SOURCE_VPN;
route.metric = route_metric;
nm_ip6_config_add_route (config, &route);
if (!IN6_IS_ADDR_UNSPECIFIED (parent_gw)) {
memset (&route, 0, sizeof (route));
route.network = *parent_gw;
route.plen = 128;
route.rt_source = NM_IP_CONFIG_SOURCE_VPN;
route.metric = route_metric;
nm_ip6_config_add_route (config, &route);
}
}
NMVpnConnection *
@ -1067,24 +1099,36 @@ apply_parent_device_config (NMVpnConnection *self)
* vpn-config. Instead we tell NMDefaultRouteManager directly about the
* default route. */
ifindex = nm_device_get_ip_ifindex (parent_dev);
if (priv->ip4_config) {
vpn4_parent_config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns),
ifindex);
nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_NO_DNS);
}
if (priv->ip6_config) {
vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns),
ifindex);
nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS);
nm_ip6_config_set_gateway (vpn6_parent_config, NULL);
if (ifindex > 0) {
if (priv->ip4_config) {
vpn4_parent_config = nm_ip4_config_new (nm_netns_get_multi_idx (priv->netns),
ifindex);
nm_ip4_config_merge (vpn4_parent_config, priv->ip4_config, NM_IP_CONFIG_MERGE_NO_DNS);
}
if (priv->ip6_config) {
vpn6_parent_config = nm_ip6_config_new (nm_netns_get_multi_idx (priv->netns),
ifindex);
nm_ip6_config_merge (vpn6_parent_config, priv->ip6_config, NM_IP_CONFIG_MERGE_NO_DNS);
nm_ip6_config_set_gateway (vpn6_parent_config, NULL);
}
}
}
/* Add any explicit route to the VPN gateway through the parent device */
if (vpn4_parent_config && priv->ip4_external_gw)
add_ip4_vpn_gateway_route (vpn4_parent_config, parent_dev, priv->ip4_external_gw);
if (vpn6_parent_config && priv->ip6_external_gw)
add_ip6_vpn_gateway_route (vpn6_parent_config, parent_dev, priv->ip6_external_gw);
if ( vpn4_parent_config
&& priv->ip4_external_gw) {
add_ip4_vpn_gateway_route (vpn4_parent_config,
parent_dev,
priv->ip4_external_gw,
nm_netns_get_platform (priv->netns));
}
if ( vpn6_parent_config
&& priv->ip6_external_gw) {
add_ip6_vpn_gateway_route (vpn6_parent_config,
parent_dev,
priv->ip6_external_gw,
nm_netns_get_platform (priv->netns));
}
nm_device_replace_vpn4_config (parent_dev, priv->last_device_ip4_config, vpn4_parent_config);
g_clear_object (&priv->last_device_ip4_config);
@ -1104,21 +1148,17 @@ nm_vpn_connection_apply_config (NMVpnConnection *self)
nm_platform_link_set_up (nm_netns_get_platform (priv->netns), priv->ip_ifindex, NULL);
if (priv->ip4_config) {
nm_assert (priv->ip_ifindex == nm_ip4_config_get_ifindex (priv->ip4_config));
if (!nm_ip4_config_commit (priv->ip4_config,
nm_netns_get_platform (priv->netns),
nm_netns_get_route_manager (priv->netns),
priv->ip_ifindex,
TRUE,
nm_vpn_connection_get_ip4_route_metric (self)))
return FALSE;
}
if (priv->ip6_config) {
nm_assert (priv->ip_ifindex == nm_ip6_config_get_ifindex (priv->ip6_config));
if (!nm_ip6_config_commit (priv->ip6_config,
nm_netns_get_platform (priv->netns),
nm_netns_get_route_manager (priv->netns),
priv->ip_ifindex,
TRUE))
nm_netns_get_platform (priv->netns)))
return FALSE;
}