summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2019-03-23 15:09:29 +0100
committerThomas Haller <thaller@redhat.com>2019-03-27 16:23:30 +0100
commit3f9347745b30e6182c3b3c768f78295d72c47a93 (patch)
tree4830a6eb9bcfe6317b2d395a3ffb3d54ac474b37
parentba59c7c3c01b77bc596ba10cede128b8926dd735 (diff)
downloadNetworkManager-3f9347745b30e6182c3b3c768f78295d72c47a93.tar.gz
core: add handling of IP routing rules to NMDevice
-rw-r--r--src/NetworkManagerUtils.c44
-rw-r--r--src/NetworkManagerUtils.h8
-rw-r--r--src/devices/nm-device.c86
-rw-r--r--src/platform/nmp-rules-manager.c10
-rw-r--r--src/platform/nmp-rules-manager.h3
-rw-r--r--src/platform/tests/test-route.c8
6 files changed, 152 insertions, 7 deletions
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 71bfbf7c10..0f63239129 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -23,6 +23,8 @@
#include "NetworkManagerUtils.h"
+#include <linux/fib_rules.h>
+
#include "nm-utils/nm-c-list.h"
#include "nm-common-macros.h"
@@ -908,6 +910,48 @@ nm_match_spec_device_by_pllink (const NMPlatformLink *pllink,
/*****************************************************************************/
+NMPlatformRoutingRule *
+nm_ip_routing_rule_to_platform (const NMIPRoutingRule *rule,
+ NMPlatformRoutingRule *out_pl)
+{
+ nm_assert (rule);
+ nm_assert (nm_ip_routing_rule_validate (rule, NULL));
+ nm_assert (out_pl);
+
+ *out_pl = (NMPlatformRoutingRule) {
+ .addr_family = nm_ip_routing_rule_get_addr_family (rule),
+ .flags = ( nm_ip_routing_rule_get_invert (rule)
+ ? FIB_RULE_INVERT
+ : 0),
+ .priority = nm_ip_routing_rule_get_priority (rule),
+ .tos = nm_ip_routing_rule_get_tos (rule),
+ .ip_proto = nm_ip_routing_rule_get_ipproto (rule),
+ .fwmark = nm_ip_routing_rule_get_fwmark (rule),
+ .fwmask = nm_ip_routing_rule_get_fwmask (rule),
+ .sport_range = {
+ .start = nm_ip_routing_rule_get_source_port_start (rule),
+ .end = nm_ip_routing_rule_get_source_port_end (rule),
+ },
+ .dport_range = {
+ .start = nm_ip_routing_rule_get_destination_port_start (rule),
+ .end = nm_ip_routing_rule_get_destination_port_end (rule),
+ },
+ .src = *(nm_ip_routing_rule_get_from_bin (rule) ?: &nm_ip_addr_zero),
+ .dst = *(nm_ip_routing_rule_get_to_bin (rule) ?: &nm_ip_addr_zero),
+ .src_len = nm_ip_routing_rule_get_from_len (rule),
+ .dst_len = nm_ip_routing_rule_get_to_len (rule),
+ .action = nm_ip_routing_rule_get_action (rule),
+ .table = nm_ip_routing_rule_get_table (rule),
+ };
+
+ nm_ip_routing_rule_get_xifname_bin (rule, TRUE, out_pl->iifname);
+ nm_ip_routing_rule_get_xifname_bin (rule, FALSE, out_pl->oifname);
+
+ return out_pl;
+}
+
+/*****************************************************************************/
+
struct _NMShutdownWaitObjHandle {
CList lst;
GObject *watched_obj;
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index 5e7012241a..2b1f5ed891 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -24,6 +24,9 @@
#include "nm-core-utils.h"
+#include "nm-setting-ip-config.h"
+#include "platform/nm-platform.h"
+
/*****************************************************************************/
const char *nm_utils_get_ip_config_method (NMConnection *connection,
@@ -60,6 +63,11 @@ int nm_match_spec_device_by_pllink (const NMPlatformLink *pllink,
/*****************************************************************************/
+NMPlatformRoutingRule *nm_ip_routing_rule_to_platform (const NMIPRoutingRule *rule,
+ NMPlatformRoutingRule *out_pl);
+
+/*****************************************************************************/
+
/* during shutdown, there are two relevant timeouts. One is
* NM_SHUTDOWN_TIMEOUT_MS which is plenty of time, that we give for all
* actions to complete. Of course, during shutdown components should hurry
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index f87ebf9096..3959bd7d2d 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -47,6 +47,7 @@
#include "nm-manager.h"
#include "platform/nm-platform.h"
#include "platform/nmp-object.h"
+#include "platform/nmp-rules-manager.h"
#include "ndisc/nm-ndisc.h"
#include "ndisc/nm-lndp-ndisc.h"
#include "dhcp/nm-dhcp-manager.h"
@@ -6408,6 +6409,84 @@ lldp_init (NMDevice *self, gboolean restart)
}
}
+/* set-mode can be:
+ * - TRUE: sync with new rules.
+ * - FALSE: sync, but remove all rules (== flush)
+ * - DEFAULT: forget about all the rules that we previously tracked,
+ * but don't actually remove them. This is when quitting NM
+ * we want to keep the rules.
+ * The problem is, after restart of NM, the rule manager will
+ * no longer remember that NM added these rules and treat them
+ * as externally added ones. Don't restart NetworkManager if
+ * you care about that.
+ */
+static void
+_routing_rules_sync (NMDevice *self,
+ NMTernary set_mode)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+ NMPRulesManager *rules_manager = nm_netns_get_rules_manager (nm_device_get_netns (self));
+ gboolean untrack_only_dirty = FALSE;
+ gboolean keep_deleted_rules;
+ gpointer user_tag;
+
+ user_tag = priv;
+
+ if (set_mode == NM_TERNARY_TRUE) {
+ NMConnection *applied_connection;
+ NMSettingIPConfig *s_ip;
+ guint i, num;
+ int is_ipv4;
+
+ untrack_only_dirty = TRUE;
+ nmp_rules_manager_set_dirty (rules_manager, user_tag);
+
+ applied_connection = nm_device_get_applied_connection (self);
+
+ for (is_ipv4 = 0; applied_connection && is_ipv4 < 2; is_ipv4++) {
+ int addr_family = is_ipv4 ? AF_INET : AF_INET6;
+
+ s_ip = nm_connection_get_setting_ip_config (applied_connection, addr_family);
+ if (!s_ip)
+ continue;
+
+ num = nm_setting_ip_config_get_num_routing_rules (s_ip);
+ for (i = 0; i < num; i++) {
+ NMPlatformRoutingRule plrule;
+ NMIPRoutingRule *rule;
+
+ rule = nm_setting_ip_config_get_routing_rule (s_ip, i);
+ nm_ip_routing_rule_to_platform (rule, &plrule);
+ nmp_rules_manager_track (rules_manager,
+ &plrule,
+ 10,
+ user_tag);
+ }
+ }
+ }
+
+ nmp_rules_manager_untrack_all (rules_manager, user_tag, !untrack_only_dirty);
+
+ keep_deleted_rules = FALSE;
+ if (set_mode == NM_TERNARY_DEFAULT) {
+ /* when exiting NM, we leave the device up and the rules configured.
+ * We just all nmp_rules_manager_sync() to forget about the synced rules,
+ * but we don't actually delete them.
+ *
+ * FIXME: that is a problem after restart of NetworkManager, because these
+ * rules will look like externally added, and NM will no longer remove
+ * them.
+ * To fix that, we could during "assume" mark the rules of the profile
+ * as owned (and "added" by the device). The problem with that is that it
+ * wouldn't cover rules that devices add by internal decision (not because
+ * of a setting in the profile, e.g. WireGuard could setup policy routing).
+ * Maybe it would be better to remember these orphaned rules at exit in a
+ * file and track them after restart again. */
+ keep_deleted_rules = TRUE;
+ }
+ nmp_rules_manager_sync (rules_manager, keep_deleted_rules);
+}
+
static gboolean
tc_commit (NMDevice *self)
{
@@ -6519,6 +6598,8 @@ activate_stage2_device_config (NMDevice *self)
}
}
+ _routing_rules_sync (self, NM_TERNARY_TRUE);
+
if (!nm_device_sys_iface_state_is_external_or_assume (self)) {
if (!nm_device_bring_up (self, FALSE, &no_firmware)) {
if (no_firmware)
@@ -14350,6 +14431,11 @@ nm_device_cleanup (NMDevice *self, NMDeviceStateReason reason, CleanupType clean
}
}
+ _routing_rules_sync (self,
+ cleanup_type == CLEANUP_TYPE_KEEP
+ ? NM_TERNARY_DEFAULT
+ : NM_TERNARY_FALSE);
+
if (ifindex > 0)
nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), ifindex, NULL);
diff --git a/src/platform/nmp-rules-manager.c b/src/platform/nmp-rules-manager.c
index ae19b33dfc..9e3435507b 100644
--- a/src/platform/nmp-rules-manager.c
+++ b/src/platform/nmp-rules-manager.c
@@ -471,7 +471,8 @@ nmp_rules_manager_untrack_all (NMPRulesManager *self,
}
void
-nmp_rules_manager_sync (NMPRulesManager *self)
+nmp_rules_manager_sync (NMPRulesManager *self,
+ gboolean keep_deleted_rules)
{
const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter pl_iter;
@@ -486,7 +487,7 @@ nmp_rules_manager_sync (NMPRulesManager *self)
if (!self->by_data)
return;
- _LOGD ("sync");
+ _LOGD ("sync%s", keep_deleted_rules ? " (don't remove any rules)" : "");
pl_head_entry = nm_platform_lookup_obj_type (self->platform, NMP_OBJECT_TYPE_ROUTING_RULE);
if (pl_head_entry) {
@@ -508,6 +509,11 @@ nmp_rules_manager_sync (NMPRulesManager *self)
obj_data->added_by_us = FALSE;
}
+ if (keep_deleted_rules) {
+ _LOGD ("forget/leak rule added by us: %s", nmp_object_to_string (plobj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
+ continue;
+ }
+
if (!rules_to_delete)
rules_to_delete = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
diff --git a/src/platform/nmp-rules-manager.h b/src/platform/nmp-rules-manager.h
index 491df31d4a..a1e5543548 100644
--- a/src/platform/nmp-rules-manager.h
+++ b/src/platform/nmp-rules-manager.h
@@ -54,7 +54,8 @@ void nmp_rules_manager_untrack_all (NMPRulesManager *self,
gconstpointer user_tag,
gboolean all /* or only dirty */);
-void nmp_rules_manager_sync (NMPRulesManager *self);
+void nmp_rules_manager_sync (NMPRulesManager *self,
+ gboolean keep_deleted_rules);
/*****************************************************************************/
diff --git a/src/platform/tests/test-route.c b/src/platform/tests/test-route.c
index 60bd4e0170..ae3367779c 100644
--- a/src/platform/tests/test-route.c
+++ b/src/platform/tests/test-route.c
@@ -1546,12 +1546,12 @@ again:
USER_TAG_2);
}
if (nmtst_get_rand_int () % objs_sync->len == 0) {
- nmp_rules_manager_sync (rules_manager);
+ nmp_rules_manager_sync (rules_manager, FALSE);
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, i + 1);
}
}
- nmp_rules_manager_sync (rules_manager);
+ nmp_rules_manager_sync (rules_manager, FALSE);
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs_sync->len);
for (i = 0; i < objs_sync->len; i++) {
@@ -1578,12 +1578,12 @@ again:
break;
}
if (nmtst_get_rand_int () % objs_sync->len == 0) {
- nmp_rules_manager_sync (rules_manager);
+ nmp_rules_manager_sync (rules_manager, FALSE);
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs_sync->len - i - 1);
}
}
- nmp_rules_manager_sync (rules_manager);
+ nmp_rules_manager_sync (rules_manager, FALSE);
} else {
for (i = 0; i < objs->len;) {