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;
if (set_mode == NM_TERNARY_DEFAULT) {
/* 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.
*
* 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. */
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

View file

@ -1675,14 +1675,14 @@ again:
NULL);
}
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),
==,
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),
==,
objs_sync->len);
@ -1713,14 +1713,14 @@ again:
break;
}
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),
==,
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 {
for (i = 0; i < objs->len;) {

View file

@ -116,7 +116,10 @@ static void
_track_data_assert(const TrackData *track_data, gboolean linked)
{
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(track_data->user_tag);
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);
nm_hash_init(&h, 269297543u);
nm_platform_routing_rule_hash_update(NMP_OBJECT_CAST_ROUTING_RULE(track_data->obj),
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID,
&h);
nmp_object_id_hash_update(track_data->obj, &h);
nm_hash_update_val(&h, track_data->user_tag);
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);
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_CAST_ROUTING_RULE(track_data_b->obj),
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID)
== 0);
&& nmp_object_id_equal(track_data_a->obj, track_data_b->obj);
}
static void
@ -199,13 +197,8 @@ static guint
_track_obj_data_hash(gconstpointer data)
{
const TrackObjData *obj_data = data;
NMHashState h;
nm_hash_init(&h, 432817559u);
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);
return nmp_object_id_hash(obj_data->obj);
}
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_b = data_b;
return (nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(obj_data_a->obj),
NMP_OBJECT_CAST_ROUTING_RULE(obj_data_b->obj),
NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID)
== 0);
return nmp_object_id_equal(obj_data_a->obj, obj_data_b->obj);
}
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);
}
/*****************************************************************************/
/**
* nmp_route_manager_track_rule:
* nmp_route_manager_track:
* @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
* negative values indicate a forced absence of the rule. Priorities
* 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.
*/
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(NMPRouteManager *self,
NMPObjectType obj_type,
gconstpointer obj,
gint32 track_priority,
gconstpointer user_tag,
gconstpointer user_tag_untrack)
{
NMPObject obj_stack;
const NMPObject *p_obj_stack;
@ -286,11 +282,18 @@ nmp_route_manager_track_rule(NMPRouteManager *self,
gboolean track_priority_present;
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);
/* 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);
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));
@ -363,12 +366,13 @@ nmp_route_manager_track_rule(NMPRouteManager *self,
_track_data_assert(track_data, TRUE);
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),
(track_data->track_priority_val == 0
? ""
: (track_data->track_priority_present ? "+" : "-")),
(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));
}
}
@ -386,8 +390,9 @@ _track_data_untrack(NMPRouteManager *self,
nm_assert(self->by_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),
NMP_OBJECT_GET_CLASS(track_data->obj)->obj_type_name,
nmp_object_to_string(track_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
#if NM_MORE_ASSERTS
@ -425,19 +430,24 @@ _track_data_untrack(NMPRouteManager *self,
}
void
nmp_route_manager_untrack_rule(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule,
gconstpointer user_tag)
nmp_route_manager_untrack(NMPRouteManager *self,
NMPObjectType obj_type,
gconstpointer obj,
gconstpointer user_tag)
{
NMPObject obj_stack;
const NMPObject *p_obj_stack;
TrackData *track_data;
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);
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));
@ -490,29 +500,41 @@ nmp_route_manager_untrack_all(NMPRouteManager *self,
g_hash_table_remove(self->by_user_tag, user_tag_data);
}
/*****************************************************************************/
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;
NMDedupMultiIter pl_iter;
const NMPObject *plobj;
gs_unref_ptrarray GPtrArray *rules_to_delete = NULL;
gs_unref_ptrarray GPtrArray *objs_to_delete = NULL;
TrackObjData *obj_data;
GHashTableIter h_iter;
guint i;
const TrackData *td_best;
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) {
nmp_cache_iter_for_each (&pl_iter, pl_head_entry, &plobj) {
obj_data = g_hash_table_lookup(self->by_obj, &plobj);
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. */
continue;
}
@ -535,28 +557,36 @@ nmp_route_manager_sync_rules(NMPRouteManager *self, gboolean keep_deleted_rules)
}
}
if (keep_deleted_rules) {
_LOGD("forget/leak rule added by us: %s",
if (keep_deleted) {
_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));
continue;
}
if (!rules_to_delete)
rules_to_delete = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
if (!objs_to_delete)
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;
}
}
if (rules_to_delete) {
for (i = 0; i < rules_to_delete->len; i++)
nm_platform_object_delete(self->platform, rules_to_delete->pdata[i]);
if (objs_to_delete) {
for (i = 0; i < objs_to_delete->len; i++)
nm_platform_object_delete(self->platform, objs_to_delete->pdata[i]);
}
g_hash_table_iter_init(&h_iter, self->by_obj);
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);
if (!td_best) {
@ -585,12 +615,18 @@ nmp_route_manager_sync_rules(NMPRouteManager *self, gboolean keep_deleted_rules)
continue;
obj_data->config_state = CONFIG_STATE_ADDED_BY_US;
nm_platform_routing_rule_add(self->platform,
NMP_NLM_FLAG_ADD,
NMP_OBJECT_CAST_ROUTING_RULE(obj_data->obj));
if (obj_type == NMP_OBJECT_TYPE_ROUTING_RULE) {
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
nmp_route_manager_track_rule_from_platform(NMPRouteManager *self,
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)
NM_AUTO_DEFINE_FCN0(NMPRouteManager *, _nmp_route_manager_unref, nmp_route_manager_unref);
void nmp_route_manager_track_rule(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule,
gint32 track_priority,
gconstpointer user_tag,
gconstpointer user_tag_untrack);
void nmp_route_manager_track(NMPRouteManager *self,
NMPObjectType obj_type,
gconstpointer obj,
gint32 track_priority,
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,
int addr_family,
@ -36,9 +52,18 @@ void nmp_route_manager_track_rule_from_platform(NMPRouteManager *self,
gint32 tracking_priority,
gconstpointer user_tag);
void nmp_route_manager_untrack_rule(NMPRouteManager *self,
const NMPlatformRoutingRule *routing_rule,
gconstpointer user_tag);
void nmp_route_manager_untrack(NMPRouteManager *self,
NMPObjectType obj_type,
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);
@ -46,7 +71,7 @@ void nmp_route_manager_untrack_all(NMPRouteManager *self,
gconstpointer user_tag,
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);
/*****************************************************************************/