core: add handling of IP routing rules to NMDevice
This commit is contained in:
@@ -23,6 +23,8 @@
|
|||||||
|
|
||||||
#include "NetworkManagerUtils.h"
|
#include "NetworkManagerUtils.h"
|
||||||
|
|
||||||
|
#include <linux/fib_rules.h>
|
||||||
|
|
||||||
#include "nm-utils/nm-c-list.h"
|
#include "nm-utils/nm-c-list.h"
|
||||||
|
|
||||||
#include "nm-common-macros.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 {
|
struct _NMShutdownWaitObjHandle {
|
||||||
CList lst;
|
CList lst;
|
||||||
GObject *watched_obj;
|
GObject *watched_obj;
|
||||||
|
@@ -24,6 +24,9 @@
|
|||||||
|
|
||||||
#include "nm-core-utils.h"
|
#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,
|
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
|
/* during shutdown, there are two relevant timeouts. One is
|
||||||
* NM_SHUTDOWN_TIMEOUT_MS which is plenty of time, that we give for all
|
* NM_SHUTDOWN_TIMEOUT_MS which is plenty of time, that we give for all
|
||||||
* actions to complete. Of course, during shutdown components should hurry
|
* actions to complete. Of course, during shutdown components should hurry
|
||||||
|
@@ -47,6 +47,7 @@
|
|||||||
#include "nm-manager.h"
|
#include "nm-manager.h"
|
||||||
#include "platform/nm-platform.h"
|
#include "platform/nm-platform.h"
|
||||||
#include "platform/nmp-object.h"
|
#include "platform/nmp-object.h"
|
||||||
|
#include "platform/nmp-rules-manager.h"
|
||||||
#include "ndisc/nm-ndisc.h"
|
#include "ndisc/nm-ndisc.h"
|
||||||
#include "ndisc/nm-lndp-ndisc.h"
|
#include "ndisc/nm-lndp-ndisc.h"
|
||||||
#include "dhcp/nm-dhcp-manager.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
|
static gboolean
|
||||||
tc_commit (NMDevice *self)
|
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_sys_iface_state_is_external_or_assume (self)) {
|
||||||
if (!nm_device_bring_up (self, FALSE, &no_firmware)) {
|
if (!nm_device_bring_up (self, FALSE, &no_firmware)) {
|
||||||
if (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)
|
if (ifindex > 0)
|
||||||
nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), ifindex, NULL);
|
nm_platform_ip4_dev_route_blacklist_set (nm_device_get_platform (self), ifindex, NULL);
|
||||||
|
|
||||||
|
@@ -471,7 +471,8 @@ nmp_rules_manager_untrack_all (NMPRulesManager *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
nmp_rules_manager_sync (NMPRulesManager *self)
|
nmp_rules_manager_sync (NMPRulesManager *self,
|
||||||
|
gboolean keep_deleted_rules)
|
||||||
{
|
{
|
||||||
const NMDedupMultiHeadEntry *pl_head_entry;
|
const NMDedupMultiHeadEntry *pl_head_entry;
|
||||||
NMDedupMultiIter pl_iter;
|
NMDedupMultiIter pl_iter;
|
||||||
@@ -486,7 +487,7 @@ nmp_rules_manager_sync (NMPRulesManager *self)
|
|||||||
if (!self->by_data)
|
if (!self->by_data)
|
||||||
return;
|
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);
|
pl_head_entry = nm_platform_lookup_obj_type (self->platform, NMP_OBJECT_TYPE_ROUTING_RULE);
|
||||||
if (pl_head_entry) {
|
if (pl_head_entry) {
|
||||||
@@ -508,6 +509,11 @@ nmp_rules_manager_sync (NMPRulesManager *self)
|
|||||||
obj_data->added_by_us = FALSE;
|
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)
|
if (!rules_to_delete)
|
||||||
rules_to_delete = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
|
rules_to_delete = g_ptr_array_new_with_free_func ((GDestroyNotify) nmp_object_unref);
|
||||||
|
|
||||||
|
@@ -54,7 +54,8 @@ void nmp_rules_manager_untrack_all (NMPRulesManager *self,
|
|||||||
gconstpointer user_tag,
|
gconstpointer user_tag,
|
||||||
gboolean all /* or only dirty */);
|
gboolean all /* or only dirty */);
|
||||||
|
|
||||||
void nmp_rules_manager_sync (NMPRulesManager *self);
|
void nmp_rules_manager_sync (NMPRulesManager *self,
|
||||||
|
gboolean keep_deleted_rules);
|
||||||
|
|
||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
@@ -1546,12 +1546,12 @@ again:
|
|||||||
USER_TAG_2);
|
USER_TAG_2);
|
||||||
}
|
}
|
||||||
if (nmtst_get_rand_int () % objs_sync->len == 0) {
|
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);
|
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);
|
g_assert_cmpint (nmtstp_platform_routing_rules_get_count (platform, AF_UNSPEC), ==, objs_sync->len);
|
||||||
|
|
||||||
for (i = 0; i < objs_sync->len; i++) {
|
for (i = 0; i < objs_sync->len; i++) {
|
||||||
@@ -1578,12 +1578,12 @@ again:
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (nmtst_get_rand_int () % objs_sync->len == 0) {
|
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);
|
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 {
|
} else {
|
||||||
for (i = 0; i < objs->len;) {
|
for (i = 0; i < objs->len;) {
|
||||||
|
Reference in New Issue
Block a user