diff options
author | Thomas Haller <thaller@redhat.com> | 2019-03-23 15:09:29 +0100 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-03-27 16:23:30 +0100 |
commit | 3f9347745b30e6182c3b3c768f78295d72c47a93 (patch) | |
tree | 4830a6eb9bcfe6317b2d395a3ffb3d54ac474b37 | |
parent | ba59c7c3c01b77bc596ba10cede128b8926dd735 (diff) | |
download | NetworkManager-3f9347745b30e6182c3b3c768f78295d72c47a93.tar.gz |
core: add handling of IP routing rules to NMDevice
-rw-r--r-- | src/NetworkManagerUtils.c | 44 | ||||
-rw-r--r-- | src/NetworkManagerUtils.h | 8 | ||||
-rw-r--r-- | src/devices/nm-device.c | 86 | ||||
-rw-r--r-- | src/platform/nmp-rules-manager.c | 10 | ||||
-rw-r--r-- | src/platform/nmp-rules-manager.h | 3 | ||||
-rw-r--r-- | src/platform/tests/test-route.c | 8 |
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;) { |