Commit b8398b9e authored by Thomas Haller's avatar Thomas Haller

platform: add NMPRulesManager for syncing routing rules

Routing rules are unlike addresses or routes not tied to an interface.
NetworkManager thinks in terms of connection profiles. That works well
for addresses and routes, as one profile configures addresses and routes
for one device. For example, when activating a profile on a device, the
configuration does not interfere with the addresses/routes of other
devices. That is not the case for routing rules, which are global, netns-wide
entities.

When one connection profile specifies rules, then this per-device configuration
must be merged with the global configuration. And when a device disconnects later,
the rules must be removed.

Add a new NMPRulesManager API to track/untrack routing rules. Devices can
register/add there the routing rules they require. And the sync method will
apply the configuration. This is be implemented on top of NMPlatform's
caching API.
parent 5ae2431b
Pipeline #23761 passed with stage
in 65 minutes and 20 seconds
......@@ -1795,6 +1795,8 @@ src_libNetworkManagerBase_la_SOURCES = \
src/platform/nm-platform-private.h \
src/platform/nm-linux-platform.c \
src/platform/nm-linux-platform.h \
src/platform/nmp-rules-manager.c \
src/platform/nmp-rules-manager.h \
src/platform/wifi/nm-wifi-utils-nl80211.c \
src/platform/wifi/nm-wifi-utils-nl80211.h \
src/platform/wifi/nm-wifi-utils-private.h \
......
......@@ -35,6 +35,7 @@ sources = files(
'platform/nm-platform-utils.c',
'platform/nmp-netns.c',
'platform/nmp-object.c',
'platform/nmp-rules-manager.c',
'main-utils.c',
'NetworkManagerUtils.c',
'nm-core-utils.c',
......
......@@ -24,10 +24,11 @@
#include "nm-utils/nm-dedup-multi.h"
#include "NetworkManagerUtils.h"
#include "nm-core-internal.h"
#include "platform/nm-platform.h"
#include "platform/nmp-netns.h"
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
#include "platform/nmp-rules-manager.h"
/*****************************************************************************/
......@@ -38,6 +39,7 @@ NM_GOBJECT_PROPERTIES_DEFINE_BASE (
typedef struct {
NMPlatform *platform;
NMPNetns *platform_netns;
NMPRulesManager *rules_manager;
} NMNetnsPrivate;
struct _NMNetns {
......@@ -71,6 +73,12 @@ nm_netns_get_platform (NMNetns *self)
return NM_NETNS_GET_PRIVATE (self)->platform;
}
NMPRulesManager *
nm_netns_get_rules_manager (NMNetns *self)
{
return NM_NETNS_GET_PRIVATE (self)->rules_manager;
}
NMDedupMultiIndex *
nm_netns_get_multi_idx (NMNetns *self)
{
......@@ -118,6 +126,8 @@ constructed (GObject *object)
priv->platform_netns = nm_platform_netns_get (priv->platform);
priv->rules_manager = nmp_rules_manager_new (priv->platform, TRUE);
G_OBJECT_CLASS (nm_netns_parent_class)->constructed (object);
}
......@@ -137,6 +147,8 @@ dispose (GObject *object)
g_clear_object (&priv->platform);
nm_clear_pointer (&priv->rules_manager, nmp_rules_manager_unref);
G_OBJECT_CLASS (nm_netns_parent_class)->dispose (object);
}
......
......@@ -40,6 +40,8 @@ NMNetns *nm_netns_new (NMPlatform *platform);
NMPlatform *nm_netns_get_platform (NMNetns *self);
NMPNetns *nm_netns_get_platform_netns (NMNetns *self);
struct _NMPRulesManager *nm_netns_get_rules_manager (NMNetns *self);
struct _NMDedupMultiIndex *nm_netns_get_multi_idx (NMNetns *self);
#define NM_NETNS_GET (nm_netns_get ())
......
......@@ -7787,8 +7787,9 @@ constructor (GType type,
priv->multi_idx = nm_dedup_multi_index_new ();
priv->cache = nmp_cache_new (nm_platform_get_multi_idx (self),
priv->cache = nmp_cache_new (priv->multi_idx,
priv->use_udev);
return object;
}
......
This diff is collapsed.
/*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the
* Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301 USA.
*/
#ifndef __NMP_RULES_MANAGER_H__
#define __NMP_RULES_MANAGER_H__
#include "nm-platform.h"
/*****************************************************************************/
typedef struct _NMPRulesManager NMPRulesManager;
NMPRulesManager *nmp_rules_manager_new (NMPlatform *platform,
gboolean track_default);
void nmp_rules_manager_ref (NMPRulesManager *self);
void nmp_rules_manager_unref (NMPRulesManager *self);
#define nm_auto_unref_rules_manager nm_auto (_nmp_rules_manager_unref)
NM_AUTO_DEFINE_FCN0 (NMPRulesManager *, _nmp_rules_manager_unref, nmp_rules_manager_unref)
void nmp_rules_manager_track (NMPRulesManager *self,
const NMPlatformRoutingRule *routing_rule,
gint32 priority,
gconstpointer user_tag);
void nmp_rules_manager_track_default (NMPRulesManager *self,
int addr_family,
int priority,
gconstpointer user_tag);
void nmp_rules_manager_untrack (NMPRulesManager *self,
const NMPlatformRoutingRule *routing_rule,
gconstpointer user_tag);
void nmp_rules_manager_set_dirty (NMPRulesManager *self,
gconstpointer user_tag);
void nmp_rules_manager_untrack_all (NMPRulesManager *self,
gconstpointer user_tag,
gboolean all /* or only dirty */);
void nmp_rules_manager_sync (NMPRulesManager *self);
/*****************************************************************************/
#endif /* __NMP_RULES_MANAGER_H__ */
......@@ -24,6 +24,7 @@
#include "nm-core-utils.h"
#include "platform/nm-platform-utils.h"
#include "platform/nmp-rules-manager.h"
#include "test-common.h"
......@@ -1362,6 +1363,7 @@ static void
test_rule (gconstpointer test_data)
{
const int TEST_IDX = GPOINTER_TO_INT (test_data);
const gboolean TEST_SYNC = (TEST_IDX == 4);
gs_unref_ptrarray GPtrArray *objs = NULL;
gs_unref_ptrarray GPtrArray *objs_initial = NULL;
NMPlatform *platform = NM_PLATFORM_GET;
......@@ -1493,6 +1495,83 @@ again:
if (TEST_IDX != 1)
nmtst_rand_perm (NULL, objs->pdata, NULL, sizeof (gpointer), objs->len);
if (TEST_SYNC) {
gs_unref_hashtable GHashTable *unique_priorities = g_hash_table_new (NULL, NULL);
nm_auto_unref_rules_manager NMPRulesManager *rules_manager = nmp_rules_manager_new (platform, FALSE);
gs_unref_ptrarray GPtrArray *objs_sync = NULL;
gconstpointer USER_TAG_1 = &platform;
gconstpointer USER_TAG_2 = &unique_priorities;
objs_sync = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
/* ensure that priorities are unique. Otherwise it confuses the test, because
* kernel may wrongly be unable to add/delete routes based on a wrong match
* (rh#1685816, rh#1685816). */
for (i = 0; i < objs->len; i++) {
const NMPObject *obj = objs->pdata[i];
guint32 prio = NMP_OBJECT_CAST_ROUTING_RULE (obj)->priority;
if ( !NM_IN_SET (prio, 0, 32766, 32767)
&& !g_hash_table_contains (unique_priorities, GUINT_TO_POINTER (prio))) {
g_hash_table_add (unique_priorities, GUINT_TO_POINTER (prio));
g_ptr_array_add (objs_sync, (gpointer) nmp_object_ref (obj));
}
}
for (i = 0; i < objs_sync->len; i++) {
nmp_rules_manager_track (rules_manager,
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
1,
USER_TAG_1);
if (nmtst_get_rand_bool ()) {
/* this has no effect, because a negative priority (of same absolute value)
* has lower priority than the positive priority above. */
nmp_rules_manager_track (rules_manager,
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
-1,
USER_TAG_2);
}
if (nmtst_get_rand_int () % objs_sync->len == 0) {
nmp_rules_manager_sync (rules_manager);
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, i + 1);
}
}
nmp_rules_manager_sync (rules_manager);
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs_sync->len);
for (i = 0; i < objs_sync->len; i++) {
switch (nmtst_get_rand_int () % 3) {
case 0:
nmp_rules_manager_untrack (rules_manager,
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
USER_TAG_1);
nmp_rules_manager_untrack (rules_manager,
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
USER_TAG_1);
break;
case 1:
nmp_rules_manager_track (rules_manager,
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
-1,
USER_TAG_1);
break;
case 2:
nmp_rules_manager_track (rules_manager,
NMP_OBJECT_CAST_ROUTING_RULE (objs_sync->pdata[i]),
-2,
USER_TAG_2);
break;
}
if (nmtst_get_rand_int () % objs_sync->len == 0) {
nmp_rules_manager_sync (rules_manager);
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs_sync->len - i - 1);
}
}
nmp_rules_manager_sync (rules_manager);
} else {
for (i = 0; i < objs->len;) {
const NMPObject *obj = objs->pdata[i];
......@@ -1592,6 +1671,7 @@ again:
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs->len -i - 1);
}
}
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, 0);
......@@ -1645,5 +1725,6 @@ _nmtstp_setup_tests (void)
add_test_func_data ("/route/rule/1", test_rule, GINT_TO_POINTER (1));
add_test_func_data ("/route/rule/2", test_rule, GINT_TO_POINTER (2));
add_test_func_data ("/route/rule/3", test_rule, GINT_TO_POINTER (3));
add_test_func_data ("/route/rule/4", test_rule, GINT_TO_POINTER (4));
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment