platform: extend NMPRouteManager to work for routes

(cherry picked from commit 7c27c63bec)
This commit is contained in:
Thomas Haller 2022-02-02 17:39:14 +01:00
parent 506590ff66
commit dab70027e6
No known key found for this signature in database
GPG key ID: 29C2366E4DFC5728
4 changed files with 126 additions and 65 deletions

View file

@ -9354,7 +9354,7 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode)
keep_deleted_rules = FALSE; keep_deleted_rules = FALSE;
if (set_mode == NM_TERNARY_DEFAULT) { if (set_mode == NM_TERNARY_DEFAULT) {
/* when exiting NM, we leave the device up and the rules configured. /* when exiting NM, we leave the device up and the rules configured.
* We just all nmp_route_manager_sync_rules() to forget about the synced rules, * We just call nmp_route_manager_sync() to forget about the synced rules,
* but we don't actually delete them. * but we don't actually delete them.
* *
* FIXME: that is a problem after restart of NetworkManager, because these * FIXME: that is a problem after restart of NetworkManager, because these
@ -9368,7 +9368,7 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode)
* file and track them after restart again. */ * file and track them after restart again. */
keep_deleted_rules = TRUE; keep_deleted_rules = TRUE;
} }
nmp_route_manager_sync_rules(route_manager, keep_deleted_rules); nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, keep_deleted_rules);
} }
static gboolean static gboolean

View file

@ -1675,14 +1675,14 @@ again:
NULL); NULL);
} }
if (nmtst_get_rand_uint32() % objs_sync->len == 0) { if (nmtst_get_rand_uint32() % objs_sync->len == 0) {
nmp_route_manager_sync_rules(route_manager, FALSE); nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE);
g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC),
==, ==,
i + 1); i + 1);
} }
} }
nmp_route_manager_sync_rules(route_manager, FALSE); nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE);
g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC),
==, ==,
objs_sync->len); objs_sync->len);
@ -1713,14 +1713,14 @@ again:
break; break;
} }
if (nmtst_get_rand_uint32() % objs_sync->len == 0) { if (nmtst_get_rand_uint32() % objs_sync->len == 0) {
nmp_route_manager_sync_rules(route_manager, FALSE); nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE);
g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC), g_assert_cmpint(nmtstp_platform_routing_rules_get_count(platform, AF_UNSPEC),
==, ==,
objs_sync->len - i - 1); objs_sync->len - i - 1);
} }
} }
nmp_route_manager_sync_rules(route_manager, FALSE); nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE);
} else { } else {
for (i = 0; i < objs->len;) { for (i = 0; i < objs->len;) {

View file

@ -116,7 +116,10 @@ static void
_track_data_assert(const TrackData *track_data, gboolean linked) _track_data_assert(const TrackData *track_data, gboolean linked)
{ {
nm_assert(track_data); nm_assert(track_data);
nm_assert(NMP_OBJECT_GET_TYPE(track_data->obj) == NMP_OBJECT_TYPE_ROUTING_RULE); nm_assert(NM_IN_SET(NMP_OBJECT_GET_TYPE(track_data->obj),
NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE,
NMP_OBJECT_TYPE_ROUTING_RULE));
nm_assert(nmp_object_is_visible(track_data->obj)); nm_assert(nmp_object_is_visible(track_data->obj));
nm_assert(track_data->user_tag); nm_assert(track_data->user_tag);
nm_assert(!linked || !c_list_is_empty(&track_data->obj_lst)); nm_assert(!linked || !c_list_is_empty(&track_data->obj_lst));
@ -132,9 +135,7 @@ _track_data_hash(gconstpointer data)
_track_data_assert(track_data, FALSE); _track_data_assert(track_data, FALSE);
nm_hash_init(&h, 269297543u); nm_hash_init(&h, 269297543u);
nm_platform_routing_rule_hash_update(NMP_OBJECT_CAST_ROUTING_RULE(track_data->obj), nmp_object_id_hash_update(track_data->obj, &h);
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID,
&h);
nm_hash_update_val(&h, track_data->user_tag); nm_hash_update_val(&h, track_data->user_tag);
return nm_hash_complete(&h); return nm_hash_complete(&h);
} }
@ -149,10 +150,7 @@ _track_data_equal(gconstpointer data_a, gconstpointer data_b)
_track_data_assert(track_data_b, FALSE); _track_data_assert(track_data_b, FALSE);
return track_data_a->user_tag == track_data_b->user_tag return track_data_a->user_tag == track_data_b->user_tag
&& (nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(track_data_a->obj), && nmp_object_id_equal(track_data_a->obj, track_data_b->obj);
NMP_OBJECT_CAST_ROUTING_RULE(track_data_b->obj),
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID)
== 0);
} }
static void static void
@ -199,13 +197,8 @@ static guint
_track_obj_data_hash(gconstpointer data) _track_obj_data_hash(gconstpointer data)
{ {
const TrackObjData *obj_data = data; const TrackObjData *obj_data = data;
NMHashState h;
nm_hash_init(&h, 432817559u); return nmp_object_id_hash(obj_data->obj);
nm_platform_routing_rule_hash_update(NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj),
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID,
&h);
return nm_hash_complete(&h);
} }
static gboolean static gboolean
@ -214,10 +207,7 @@ _track_obj_data_equal(gconstpointer data_a, gconstpointer data_b)
const TrackObjData *obj_data_a = data_a; const TrackObjData *obj_data_a = data_a;
const TrackObjData *obj_data_b = data_b; const TrackObjData *obj_data_b = data_b;
return (nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(obj_data_a->obj), return nmp_object_id_equal(obj_data_a->obj, obj_data_b->obj);
NMP_OBJECT_CAST_ROUTING_RULE(obj_data_b->obj),
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID)
== 0);
} }
static void static void
@ -250,10 +240,15 @@ _track_data_lookup(GHashTable *by_data, const NMPObject *obj, gconstpointer user
return g_hash_table_lookup(by_data, &track_data_needle); return g_hash_table_lookup(by_data, &track_data_needle);
} }
/*****************************************************************************/
/** /**
* nmp_route_manager_track_rule: * nmp_route_manager_track:
* @self: the #NMPRouteManager instance * @self: the #NMPRouteManager instance
* @routing_rule: the #NMPlatformRoutingRule to track or untrack * @obj_type: the NMPObjectType of @obj that we are tracking.
* @obj: the NMPlatformObject (of type NMPObjectType) to track. Usually
* a #NMPlatformRoutingRule, #NMPlatformIP4Route or #NMPlatformIP6Route
* pointer.
* @track_priority: the priority for tracking the rule. Note that * @track_priority: the priority for tracking the rule. Note that
* negative values indicate a forced absence of the rule. Priorities * negative values indicate a forced absence of the rule. Priorities
* are compared with their absolute values (with higher absolute * are compared with their absolute values (with higher absolute
@ -270,11 +265,12 @@ _track_data_lookup(GHashTable *by_data, const NMPObject *obj, gconstpointer user
* The purpose here is to set this to %NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG. * The purpose here is to set this to %NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG.
*/ */
void void
nmp_route_manager_track_rule(NMPRouteManager *self, nmp_route_manager_track(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule, NMPObjectType obj_type,
gint32 track_priority, gconstpointer obj,
gconstpointer user_tag, gint32 track_priority,
gconstpointer user_tag_untrack) gconstpointer user_tag,
gconstpointer user_tag_untrack)
{ {
NMPObject obj_stack; NMPObject obj_stack;
const NMPObject *p_obj_stack; const NMPObject *p_obj_stack;
@ -286,11 +282,18 @@ nmp_route_manager_track_rule(NMPRouteManager *self,
gboolean track_priority_present; gboolean track_priority_present;
g_return_if_fail(NMP_IS_ROUTE_MANAGER(self)); g_return_if_fail(NMP_IS_ROUTE_MANAGER(self));
g_return_if_fail(routing_rule); g_return_if_fail(obj);
g_return_if_fail(user_tag); g_return_if_fail(user_tag);
/* The route must not be tied to an interface. We can only handle here
* blackhole/unreachable/prohibit route types. */
g_return_if_fail(obj_type == NMP_OBJECT_TYPE_ROUTING_RULE
|| (NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)
&& ((const NMPlatformIPRoute *) obj)->ifindex == 0));
nm_assert(track_priority != G_MININT32); nm_assert(track_priority != G_MININT32);
p_obj_stack = nmp_object_stackinit(&obj_stack, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule); p_obj_stack = nmp_object_stackinit(&obj_stack, obj_type, obj);
nm_assert(nmp_object_is_visible(p_obj_stack)); nm_assert(nmp_object_is_visible(p_obj_stack));
@ -363,12 +366,13 @@ nmp_route_manager_track_rule(NMPRouteManager *self,
_track_data_assert(track_data, TRUE); _track_data_assert(track_data, TRUE);
if (changed) { if (changed) {
_LOGD("routing-rule: track [" NM_HASH_OBFUSCATE_PTR_FMT ",%s%u] \"%s\")", _LOGD("track [" NM_HASH_OBFUSCATE_PTR_FMT ",%s%u] %s \"%s\"",
NM_HASH_OBFUSCATE_PTR(track_data->user_tag), NM_HASH_OBFUSCATE_PTR(track_data->user_tag),
(track_data->track_priority_val == 0 (track_data->track_priority_val == 0
? "" ? ""
: (track_data->track_priority_present ? "+" : "-")), : (track_data->track_priority_present ? "+" : "-")),
(guint) track_data->track_priority_val, (guint) track_data->track_priority_val,
NMP_OBJECT_GET_CLASS(track_data->obj)->obj_type_name,
nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
} }
} }
@ -386,8 +390,9 @@ _track_data_untrack(NMPRouteManager *self,
nm_assert(self->by_data); nm_assert(self->by_data);
nm_assert(g_hash_table_lookup(self->by_data, track_data) == track_data); nm_assert(g_hash_table_lookup(self->by_data, track_data) == track_data);
_LOGD("routing-rule: untrack [" NM_HASH_OBFUSCATE_PTR_FMT "] \"%s\"", _LOGD("untrack [" NM_HASH_OBFUSCATE_PTR_FMT "] %s \"%s\"",
NM_HASH_OBFUSCATE_PTR(track_data->user_tag), NM_HASH_OBFUSCATE_PTR(track_data->user_tag),
NMP_OBJECT_GET_CLASS(track_data->obj)->obj_type_name,
nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
#if NM_MORE_ASSERTS #if NM_MORE_ASSERTS
@ -425,19 +430,24 @@ _track_data_untrack(NMPRouteManager *self,
} }
void void
nmp_route_manager_untrack_rule(NMPRouteManager *self, nmp_route_manager_untrack(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule, NMPObjectType obj_type,
gconstpointer user_tag) gconstpointer obj,
gconstpointer user_tag)
{ {
NMPObject obj_stack; NMPObject obj_stack;
const NMPObject *p_obj_stack; const NMPObject *p_obj_stack;
TrackData *track_data; TrackData *track_data;
g_return_if_fail(NMP_IS_ROUTE_MANAGER(self)); g_return_if_fail(NMP_IS_ROUTE_MANAGER(self));
g_return_if_fail(routing_rule); nm_assert(NM_IN_SET(obj_type,
NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE,
NMP_OBJECT_TYPE_ROUTING_RULE));
g_return_if_fail(obj);
g_return_if_fail(user_tag); g_return_if_fail(user_tag);
p_obj_stack = nmp_object_stackinit(&obj_stack, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule); p_obj_stack = nmp_object_stackinit(&obj_stack, obj_type, obj);
nm_assert(nmp_object_is_visible(p_obj_stack)); nm_assert(nmp_object_is_visible(p_obj_stack));
@ -490,29 +500,41 @@ nmp_route_manager_untrack_all(NMPRouteManager *self,
g_hash_table_remove(self->by_user_tag, user_tag_data); g_hash_table_remove(self->by_user_tag, user_tag_data);
} }
/*****************************************************************************/
void void
nmp_route_manager_sync_rules(NMPRouteManager *self, gboolean keep_deleted_rules) nmp_route_manager_sync(NMPRouteManager *self, NMPObjectType obj_type, gboolean keep_deleted)
{ {
const NMDedupMultiHeadEntry *pl_head_entry; const NMDedupMultiHeadEntry *pl_head_entry;
NMDedupMultiIter pl_iter; NMDedupMultiIter pl_iter;
const NMPObject *plobj; const NMPObject *plobj;
gs_unref_ptrarray GPtrArray *rules_to_delete = NULL; gs_unref_ptrarray GPtrArray *objs_to_delete = NULL;
TrackObjData *obj_data; TrackObjData *obj_data;
GHashTableIter h_iter; GHashTableIter h_iter;
guint i; guint i;
const TrackData *td_best; const TrackData *td_best;
g_return_if_fail(NMP_IS_ROUTE_MANAGER(self)); g_return_if_fail(NMP_IS_ROUTE_MANAGER(self));
g_return_if_fail(NM_IN_SET(obj_type,
NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE,
NMP_OBJECT_TYPE_ROUTING_RULE));
_LOGD("sync%s", keep_deleted_rules ? " (don't remove any rules)" : ""); _LOGD("sync %s%s",
nmp_class_from_type(obj_type)->obj_type_name,
keep_deleted ? " (don't remove any)" : "");
if (obj_type == NMP_OBJECT_TYPE_ROUTING_RULE)
pl_head_entry = nm_platform_lookup_obj_type(self->platform, obj_type);
else
pl_head_entry = nm_platform_lookup_object(self->platform, obj_type, 0);
pl_head_entry = nm_platform_lookup_obj_type(self->platform, NMP_OBJECT_TYPE_ROUTING_RULE);
if (pl_head_entry) { if (pl_head_entry) {
nmp_cache_iter_for_each (&pl_iter, pl_head_entry, &plobj) { nmp_cache_iter_for_each (&pl_iter, pl_head_entry, &plobj) {
obj_data = g_hash_table_lookup(self->by_obj, &plobj); obj_data = g_hash_table_lookup(self->by_obj, &plobj);
if (!obj_data) { if (!obj_data) {
/* this rule is not tracked. It was externally added, hence we /* this obj is not tracked. It was externally added, hence we
* ignore it. */ * ignore it. */
continue; continue;
} }
@ -535,28 +557,36 @@ nmp_route_manager_sync_rules(NMPRouteManager *self, gboolean keep_deleted_rules)
} }
} }
if (keep_deleted_rules) { if (keep_deleted) {
_LOGD("forget/leak rule added by us: %s", _LOGD("forget/leak object added by us: %s \"%s\"",
NMP_OBJECT_GET_CLASS(plobj)->obj_type_name,
nmp_object_to_string(plobj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0)); nmp_object_to_string(plobj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
continue; continue;
} }
if (!rules_to_delete) if (!objs_to_delete)
rules_to_delete = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref); objs_to_delete = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
g_ptr_array_add(rules_to_delete, (gpointer) nmp_object_ref(plobj)); g_ptr_array_add(objs_to_delete, (gpointer) nmp_object_ref(plobj));
obj_data->config_state = CONFIG_STATE_REMOVED_BY_US; obj_data->config_state = CONFIG_STATE_REMOVED_BY_US;
} }
} }
if (rules_to_delete) { if (objs_to_delete) {
for (i = 0; i < rules_to_delete->len; i++) for (i = 0; i < objs_to_delete->len; i++)
nm_platform_object_delete(self->platform, rules_to_delete->pdata[i]); nm_platform_object_delete(self->platform, objs_to_delete->pdata[i]);
} }
g_hash_table_iter_init(&h_iter, self->by_obj); g_hash_table_iter_init(&h_iter, self->by_obj);
while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_data, NULL)) { while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_data, NULL)) {
if (NMP_OBJECT_GET_TYPE(obj_data->obj) != obj_type) {
/* Here we need to iterate over all objects (rules and ip4/ip6 routes)
* and skip over the non-interesting ones. It might be better to
* track 3 separate CList by object type. */
continue;
}
td_best = _track_obj_data_get_best_data(obj_data); td_best = _track_obj_data_get_best_data(obj_data);
if (!td_best) { if (!td_best) {
@ -585,12 +615,18 @@ nmp_route_manager_sync_rules(NMPRouteManager *self, gboolean keep_deleted_rules)
continue; continue;
obj_data->config_state = CONFIG_STATE_ADDED_BY_US; obj_data->config_state = CONFIG_STATE_ADDED_BY_US;
nm_platform_routing_rule_add(self->platform,
NMP_NLM_FLAG_ADD, if (obj_type == NMP_OBJECT_TYPE_ROUTING_RULE) {
NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj)); nm_platform_routing_rule_add(self->platform,
NMP_NLM_FLAG_ADD,
NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj));
} else
nm_platform_ip_route_add(self->platform, NMP_NLM_FLAG_APPEND, obj_data->obj);
} }
} }
/*****************************************************************************/
void void
nmp_route_manager_track_rule_from_platform(NMPRouteManager *self, nmp_route_manager_track_rule_from_platform(NMPRouteManager *self,
NMPlatform *platform, NMPlatform *platform,

View file

@ -19,11 +19,27 @@ void nmp_route_manager_unref(NMPRouteManager *self);
#define nm_auto_unref_route_manager nm_auto(_nmp_route_manager_unref) #define nm_auto_unref_route_manager nm_auto(_nmp_route_manager_unref)
NM_AUTO_DEFINE_FCN0(NMPRouteManager *, _nmp_route_manager_unref, nmp_route_manager_unref); NM_AUTO_DEFINE_FCN0(NMPRouteManager *, _nmp_route_manager_unref, nmp_route_manager_unref);
void nmp_route_manager_track_rule(NMPRouteManager *self, void nmp_route_manager_track(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule, NMPObjectType obj_type,
gint32 track_priority, gconstpointer obj,
gconstpointer user_tag, gint32 track_priority,
gconstpointer user_tag_untrack); gconstpointer user_tag,
gconstpointer user_tag_untrack);
static inline void
nmp_route_manager_track_rule(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule,
gint32 track_priority,
gconstpointer user_tag,
gconstpointer user_tag_untrack)
{
nmp_route_manager_track(self,
NMP_OBJECT_TYPE_ROUTING_RULE,
routing_rule,
track_priority,
user_tag,
user_tag_untrack);
}
void nmp_route_manager_track_rule_default(NMPRouteManager *self, void nmp_route_manager_track_rule_default(NMPRouteManager *self,
int addr_family, int addr_family,
@ -36,9 +52,18 @@ void nmp_route_manager_track_rule_from_platform(NMPRouteManager *self,
gint32 tracking_priority, gint32 tracking_priority,
gconstpointer user_tag); gconstpointer user_tag);
void nmp_route_manager_untrack_rule(NMPRouteManager *self, void nmp_route_manager_untrack(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule, NMPObjectType obj_type,
gconstpointer user_tag); gconstpointer obj,
gconstpointer user_tag);
static inline void
nmp_route_manager_untrack_rule(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule,
gconstpointer user_tag)
{
nmp_route_manager_untrack(self, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule, user_tag);
}
void nmp_route_manager_set_dirty(NMPRouteManager *self, gconstpointer user_tag); void nmp_route_manager_set_dirty(NMPRouteManager *self, gconstpointer user_tag);
@ -46,7 +71,7 @@ void nmp_route_manager_untrack_all(NMPRouteManager *self,
gconstpointer user_tag, gconstpointer user_tag,
gboolean all /* or only dirty */); gboolean all /* or only dirty */);
void nmp_route_manager_sync_rules(NMPRouteManager *self, gboolean keep_deleted_rules); void nmp_route_manager_sync(NMPRouteManager *self, NMPObjectType obj_type, gboolean keep_deleted);
/*****************************************************************************/ /*****************************************************************************/