diff options
| author | Jeremy Bicha <jeremy.bicha@canonical.com> | 2022-02-22 16:51:45 -0500 |
|---|---|---|
| committer | Jeremy Bicha <jeremy.bicha@canonical.com> | 2022-02-22 16:51:45 -0500 |
| commit | 9d53567404b8f256e36619ee9345cef6dfb59f76 (patch) | |
| tree | 8c760223d10c83710d45d5c2819f39f121e3d9f0 /src/core | |
| parent | da4d2b990df5b0119d1dffd76ff68141517d6136 (diff) | |
| parent | 2f94dba7385fd0e0ef19a06eb4a2fcf6c43d7946 (diff) | |
Merge tag 'upstream/1.35.91' into ubuntu/master
Upstream version 1.35.91
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/NetworkManagerUtils.c | 13 | ||||
| -rw-r--r-- | src/core/devices/nm-device-wireguard.c | 2 | ||||
| -rw-r--r-- | src/core/devices/nm-device.c | 40 | ||||
| -rw-r--r-- | src/core/nm-l3-config-data.c | 34 | ||||
| -rw-r--r-- | src/core/nm-l3cfg.c | 263 | ||||
| -rw-r--r-- | src/core/nm-l3cfg.h | 14 | ||||
| -rw-r--r-- | src/core/nm-netns.c | 34 | ||||
| -rw-r--r-- | src/core/nm-netns.h | 2 | ||||
| -rw-r--r-- | src/core/platform/nm-fake-platform.c | 11 | ||||
| -rw-r--r-- | src/core/platform/tests/test-common.c | 6 | ||||
| -rw-r--r-- | src/core/platform/tests/test-platform-general.c | 26 | ||||
| -rw-r--r-- | src/core/platform/tests/test-route.c | 128 |
12 files changed, 440 insertions, 133 deletions
diff --git a/src/core/NetworkManagerUtils.c b/src/core/NetworkManagerUtils.c index 0d08efbb..c50dbada 100644 --- a/src/core/NetworkManagerUtils.c +++ b/src/core/NetworkManagerUtils.c @@ -1316,6 +1316,7 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, NMPlatformIPRoute *r, gint64 route_table) { + const int IS_IPv4 = NM_IS_IPv4(addr_family); GVariant *variant; guint32 table; NMIPAddr addr; @@ -1324,7 +1325,7 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, gboolean onlink; nm_assert(s_route); - nm_assert_addr_family(addr_family); + nm_assert(addr_family == nm_ip_route_get_family(s_route)); nm_assert(r); nm_assert(route_table >= -1); nm_assert(route_table <= (gint64) G_MAXUINT32); @@ -1346,7 +1347,8 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, int type; type = nm_net_aux_rtnl_rtntype_a2n(g_variant_get_string(variant, NULL)); - nm_assert(NM_IN_SET(type, RTN_UNICAST, RTN_LOCAL)); + nm_assert( + NM_IN_SET(type, RTN_UNICAST, RTN_LOCAL, RTN_BLACKHOLE, RTN_UNREACHABLE, RTN_PROHIBIT)); r->type_coerced = nm_platform_route_type_coerce(type); } else @@ -1365,7 +1367,7 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, else r->table_any = TRUE; - if (NM_IS_IPv4(addr_family)) { + if (IS_IPv4) { guint8 scope; GET_ATTR(NM_IP_ROUTE_ATTRIBUTE_TOS, r4->tos, BYTE, byte, 0); @@ -1391,15 +1393,14 @@ nm_utils_ip_route_attribute_to_platform(int addr_family, if ((variant = nm_ip_route_get_attribute(s_route, NM_IP_ROUTE_ATTRIBUTE_SRC)) && g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { if (inet_pton(addr_family, g_variant_get_string(variant, NULL), &addr) == 1) { - if (NM_IS_IPv4(addr_family)) + if (IS_IPv4) r4->pref_src = addr.addr4; else r6->pref_src = addr.addr6; } } - if (!NM_IS_IPv4(addr_family) - && (variant = nm_ip_route_get_attribute(s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) + if (!IS_IPv4 && (variant = nm_ip_route_get_attribute(s_route, NM_IP_ROUTE_ATTRIBUTE_FROM)) && g_variant_is_of_type(variant, G_VARIANT_TYPE_STRING)) { int prefix; diff --git a/src/core/devices/nm-device-wireguard.c b/src/core/devices/nm-device-wireguard.c index 4399e834..bdb96cb2 100644 --- a/src/core/devices/nm-device-wireguard.c +++ b/src/core/devices/nm-device-wireguard.c @@ -18,7 +18,7 @@ #include "nm-device-private.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-object.h" -#include "libnm-platform/nmp-rules-manager.h" +#include "libnm-platform/nmp-route-manager.h" #include "nm-device-factory.h" #include "nm-active-connection.h" #include "nm-act-request.h" diff --git a/src/core/devices/nm-device.c b/src/core/devices/nm-device.c index 6dda5431..696c0df8 100644 --- a/src/core/devices/nm-device.c +++ b/src/core/devices/nm-device.c @@ -41,7 +41,7 @@ #include "libnm-platform/nm-platform.h" #include "libnm-platform/nm-platform-utils.h" #include "libnm-platform/nmp-object.h" -#include "libnm-platform/nmp-rules-manager.h" +#include "libnm-platform/nmp-route-manager.h" #include "ndisc/nm-ndisc.h" #include "ndisc/nm-lndp-ndisc.h" @@ -2943,7 +2943,7 @@ _dev_ip_state_req_timeout_cb_x(NMDevice *self, int addr_family) _LOGD_ip(addr_family, "required-timeout: expired"); nm_clear_g_source_inst(&priv->ip_data_x[NM_IS_IPv4(addr_family)].req_timeout_source); - _dev_ip_state_check(self, addr_family); + _dev_ip_state_check(self, nm_utils_addr_family_other(addr_family)); return G_SOURCE_CONTINUE; } @@ -9280,7 +9280,7 @@ 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)); + NMPRouteManager *route_manager = nm_netns_get_route_manager(nm_device_get_netns(self)); NMDeviceClass *klass = NM_DEVICE_GET_CLASS(self); gboolean untrack_only_dirty = FALSE; gboolean keep_deleted_rules; @@ -9298,9 +9298,6 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) int is_ipv4; untrack_only_dirty = TRUE; - nmp_rules_manager_set_dirty(rules_manager, user_tag_1); - if (klass->get_extra_rules) - nmp_rules_manager_set_dirty(rules_manager, user_tag_2); applied_connection = nm_device_get_applied_connection(self); @@ -9320,13 +9317,13 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) nm_ip_routing_rule_to_platform(rule, &plrule); /* We track this rule, but we also make it explicitly not weakly-tracked - * (meaning to untrack NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG at + * (meaning to untrack NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG at * the same time). */ - nmp_rules_manager_track(rules_manager, - &plrule, - 10, - user_tag_1, - NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + nmp_route_manager_track_rule(route_manager, + &plrule, + 10, + user_tag_1, + NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); } } @@ -9336,24 +9333,25 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) extra_rules = klass->get_extra_rules(self); if (extra_rules) { for (i = 0; i < extra_rules->len; i++) { - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(extra_rules->pdata[i]), - 10, - user_tag_2, - NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + nmp_route_manager_track_rule( + route_manager, + NMP_OBJECT_CAST_ROUTING_RULE(extra_rules->pdata[i]), + 10, + user_tag_2, + NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); } } } } - nmp_rules_manager_untrack_all(rules_manager, user_tag_1, !untrack_only_dirty); + nmp_route_manager_untrack_all(route_manager, user_tag_1, !untrack_only_dirty, TRUE); if (klass->get_extra_rules) - nmp_rules_manager_untrack_all(rules_manager, user_tag_2, !untrack_only_dirty); + nmp_route_manager_untrack_all(route_manager, user_tag_2, !untrack_only_dirty, TRUE); 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, + * 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 @@ -9367,7 +9365,7 @@ _routing_rules_sync(NMDevice *self, NMTernary set_mode) * file and track them after restart again. */ keep_deleted_rules = TRUE; } - nmp_rules_manager_sync(rules_manager, keep_deleted_rules); + nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, keep_deleted_rules); } static gboolean diff --git a/src/core/nm-l3-config-data.c b/src/core/nm-l3-config-data.c index 226ccd00..03593ea2 100644 --- a/src/core/nm-l3-config-data.c +++ b/src/core/nm-l3-config-data.c @@ -1094,8 +1094,22 @@ _l3_config_data_add_obj(NMDedupMultiIndex *multi_idx, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ADDRESS, NMP_OBJECT_TYPE_IP6_ROUTE)); + nm_assert((!!obj_new) != (!!pl_new)); + + if (NM_IN_SET(idx_type->obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)) { + const NMPlatformIPRoute *r; + + r = obj_new ? NMP_OBJECT_CAST_IP_ROUTE(obj_new) : (NMPlatformIPRoute *) pl_new; + + if (nm_platform_route_type_is_nodev(nm_platform_route_type_uncoerce(r->type_coerced))) { + /* such routes don't have a device/next-hop. We track them without ifindex. */ + ifindex = 0; + } + } + /* we go through extra lengths to accept a full obj_new object. That one, - * can be reused by increasing the ref-count. */ + * can be reused by increasing the ref-count. We thus accept any ifindex, and + * set it here. */ if (!obj_new) { nm_assert(pl_new); obj_new = nmp_object_stackinit(&obj_new_stackinit, idx_type->obj_type, pl_new); @@ -2995,12 +3009,12 @@ nm_l3_config_data_merge(NML3ConfigData *self, NML3ConfigMergeHookAddObj hook_add_obj, gpointer hook_user_data) { - static const guint32 x_default_route_table_x[2] = {RT_TABLE_MAIN, RT_TABLE_MAIN}; static const guint32 x_default_route_metric_x[2] = {NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP6, NM_PLATFORM_ROUTE_METRIC_DEFAULT_IP4}; static const guint32 x_default_route_penalty_x[2] = {0, 0}; static const int x_default_dns_priority_x[2] = {NM_DNS_PRIORITY_DEFAULT_NORMAL, NM_DNS_PRIORITY_DEFAULT_NORMAL}; + guint32 default_route_table_coerced_x[2]; NMDedupMultiIter iter; const NMPObject *obj; int IS_IPv4; @@ -3008,8 +3022,16 @@ nm_l3_config_data_merge(NML3ConfigData *self, nm_assert(_NM_IS_L3_CONFIG_DATA(self, FALSE)); nm_assert(_NM_IS_L3_CONFIG_DATA(src, TRUE)); - if (!default_route_table_x) - default_route_table_x = x_default_route_table_x; + if (default_route_table_x) { + default_route_table_coerced_x[0] = nm_platform_route_table_coerce(default_route_table_x[0]); + default_route_table_coerced_x[1] = nm_platform_route_table_coerce(default_route_table_x[1]); + } else { + default_route_table_coerced_x[0] = nm_platform_route_table_coerce(RT_TABLE_MAIN); + default_route_table_coerced_x[1] = nm_platform_route_table_coerce(RT_TABLE_MAIN); + } + nm_assert(nm_platform_route_table_uncoerce(default_route_table_coerced_x[0], FALSE) != 0); + nm_assert(nm_platform_route_table_uncoerce(default_route_table_coerced_x[1], FALSE) != 0); + if (!default_route_metric_x) default_route_metric_x = x_default_route_metric_x; if (!default_route_penalty_x) @@ -3017,8 +3039,6 @@ nm_l3_config_data_merge(NML3ConfigData *self, if (!default_dns_priority_x) default_dns_priority_x = x_default_dns_priority_x; - nm_assert(default_route_table_x[0] != 0); - nm_assert(default_route_table_x[1] != 0); nm_assert(default_route_metric_x[0] != 0); /* IPv6 route metric cannot be zero. */ nm_assert(!NM_FLAGS_HAS(merge_flags, NM_L3_CONFIG_MERGE_FLAGS_CLONE) @@ -3145,7 +3165,7 @@ nm_l3_config_data_merge(NML3ConfigData *self, if (r_src->table_any) { _ensure_r(); r.rx.table_any = FALSE; - r.rx.table_coerced = default_route_table_x[IS_IPv4]; + r.rx.table_coerced = default_route_table_coerced_x[IS_IPv4]; } if (r_src->metric_any) { diff --git a/src/core/nm-l3cfg.c b/src/core/nm-l3cfg.c index aed4cf05..bcbe140c 100644 --- a/src/core/nm-l3cfg.c +++ b/src/core/nm-l3cfg.c @@ -12,6 +12,7 @@ #include "libnm-glib-aux/nm-time-utils.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-object.h" +#include "libnm-platform/nmp-route-manager.h" #include "nm-netns.h" #include "n-acd/src/n-acd.h" #include "nm-l3-ipv4ll.h" @@ -410,6 +411,92 @@ static NM_UTILS_LOOKUP_DEFINE(_l3_acd_addr_state_to_string, "external-removed"), NM_UTILS_LOOKUP_ITEM(NM_L3_ACD_ADDR_STATE_USED, "used"), ); +static gboolean +_obj_is_route_nodev(const NMPObject *obj) +{ + gboolean has_ifindex; + + nm_assert(obj); + + has_ifindex = (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj)->ifindex > 0); + + nm_assert(has_ifindex + == !(NM_IN_SET(NMP_OBJECT_GET_TYPE(obj), + NMP_OBJECT_TYPE_IP4_ROUTE, + NMP_OBJECT_TYPE_IP6_ROUTE) + && nm_platform_route_type_is_nodev(nm_platform_route_type_uncoerce( + NMP_OBJECT_CAST_IP_ROUTE(obj)->type_coerced)))); + + return !has_ifindex; +} + +/*****************************************************************************/ + +NMIPConfig * +nm_l3cfg_ipconfig_get(NML3Cfg *self, int addr_family) +{ + g_return_val_if_fail(NM_IS_L3CFG(self), NULL); + nm_assert_addr_family(addr_family); + + return self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)]; +} + +static void +_ipconfig_toggle_notify(gpointer data, GObject *object, gboolean is_last_ref) +{ + NML3Cfg *self = NM_L3CFG(data); + NMIPConfig *ipconfig = NM_IP_CONFIG(object); + + if (!is_last_ref) { + /* This happens while we take another ref below. Ignore the signal. */ + nm_assert(!NM_IN_SET(ipconfig, self->priv.p->ipconfig_4, self->priv.p->ipconfig_6)); + return; + } + + if (ipconfig == self->priv.p->ipconfig_4) + self->priv.p->ipconfig_4 = NULL; + else { + nm_assert(ipconfig == self->priv.p->ipconfig_6); + self->priv.p->ipconfig_6 = NULL; + } + + /* We take a second reference to keep the instance alive, while also removing the + * toggle ref. This will notify the function again, but we will ignore that. */ + g_object_ref(ipconfig); + + g_object_remove_toggle_ref(G_OBJECT(ipconfig), _ipconfig_toggle_notify, self); + + /* pass on the reference, and unexport on idle. */ + nm_ip_config_take_and_unexport_on_idle(g_steal_pointer(&ipconfig)); +} + +NMIPConfig * +nm_l3cfg_ipconfig_acquire(NML3Cfg *self, int addr_family) +{ + NMIPConfig *ipconfig; + + g_return_val_if_fail(NM_IS_L3CFG(self), NULL); + nm_assert_addr_family(addr_family); + + ipconfig = self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)]; + + if (ipconfig) + return g_object_ref(ipconfig); + + ipconfig = nm_ip_config_new(addr_family, self); + + self->priv.p->ipconfig_x[NM_IS_IPv4(addr_family)] = ipconfig; + + /* The ipconfig keeps self alive. We use a toggle reference + * to avoid a cycle. But we anyway wouldn't want a strong reference, + * because the user releases the instance by unrefing it, and we + * notice that via the weak reference. */ + g_object_add_toggle_ref(G_OBJECT(ipconfig), _ipconfig_toggle_notify, self); + + /* We keep the toggle reference, and return the other reference to the caller. */ + return g_steal_pointer(&ipconfig); +} + /*****************************************************************************/ NMIPConfig * @@ -952,6 +1039,11 @@ _obj_states_update_all(NML3Cfg *self) self->priv.p->combined_l3cd_commited, &obj, obj_type) { + if (_obj_is_route_nodev(obj)) { + /* this is a nodev route. We don't track an obj-state for this. */ + continue; + } + obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj); if (!obj_state) { obj_state = @@ -1008,18 +1100,11 @@ typedef struct { } ObjStatesSyncFilterData; static gboolean -_obj_states_sync_filter(/* const NMDedupMultiObj * */ gconstpointer o, gpointer user_data) +_obj_states_sync_filter(NML3Cfg *self, const NMPObject *obj, NML3CfgCommitType commit_type) { - char sbuf[sizeof(_nm_utils_to_string_buffer)]; - const NMPObject *obj = o; - const ObjStatesSyncFilterData *sync_filter_data = user_data; - NMPObjectType obj_type; - ObjStateData *obj_state; - NML3Cfg *self; - - nm_assert(sync_filter_data); - nm_assert(NM_IS_L3CFG(sync_filter_data->self)); - self = sync_filter_data->self; + char sbuf[sizeof(_nm_utils_to_string_buffer)]; + NMPObjectType obj_type; + ObjStateData *obj_state; obj_type = NMP_OBJECT_GET_TYPE(obj); @@ -1027,14 +1112,14 @@ _obj_states_sync_filter(/* const NMDedupMultiObj * */ gconstpointer o, gpointer && NMP_OBJECT_CAST_IP4_ADDRESS(obj)->a_acd_not_ready) return FALSE; - obj_state = g_hash_table_lookup(sync_filter_data->self->priv.p->obj_state_hash, &obj); + obj_state = g_hash_table_lookup(self->priv.p->obj_state_hash, &obj); - nm_assert_obj_state(sync_filter_data->self, obj_state); + nm_assert_obj_state(self, obj_state); nm_assert(obj_state->obj == obj); nm_assert(c_list_is_empty(&obj_state->os_zombie_lst)); if (!obj_state->os_nm_configured) { - if (sync_filter_data->commit_type == NM_L3_CFG_COMMIT_TYPE_ASSUME + if (commit_type == NM_L3_CFG_COMMIT_TYPE_ASSUME && !_obj_state_data_get_assume_config_once(obj_state)) return FALSE; @@ -1051,13 +1136,78 @@ _obj_states_sync_filter(/* const NMDedupMultiObj * */ gconstpointer o, gpointer return TRUE; } - if (!obj_state->os_plobj && sync_filter_data->commit_type != NM_L3_CFG_COMMIT_TYPE_REAPPLY + if (!obj_state->os_plobj && commit_type != NM_L3_CFG_COMMIT_TYPE_REAPPLY && !nmp_object_get_force_commit(obj)) return FALSE; return TRUE; } +static gboolean +_obj_states_sync_filter_predicate(gconstpointer o, gpointer user_data) +{ + const NMPObject *obj = o; + const ObjStatesSyncFilterData *sync_filter_data = user_data; + + return _obj_states_sync_filter(sync_filter_data->self, obj, sync_filter_data->commit_type); +} + +static GPtrArray * +_commit_collect_addresses(NML3Cfg *self, int addr_family, NML3CfgCommitType commit_type) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMDedupMultiHeadEntry *head_entry; + const ObjStatesSyncFilterData sync_filter_data = { + .self = self, + .commit_type = commit_type, + }; + + head_entry = nm_l3_config_data_lookup_objs(self->priv.p->combined_l3cd_commited, + NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)); + return nm_dedup_multi_objs_to_ptr_array_head(head_entry, + _obj_states_sync_filter_predicate, + (gpointer) &sync_filter_data); +} + +static void +_commit_collect_routes(NML3Cfg *self, + int addr_family, + NML3CfgCommitType commit_type, + GPtrArray **routes, + GPtrArray **routes_nodev) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMDedupMultiHeadEntry *head_entry; + const NMDedupMultiEntry *entry; + + nm_assert(routes && !*routes); + nm_assert(routes_nodev && !*routes_nodev); + + head_entry = nm_l3_config_data_lookup_objs(self->priv.p->combined_l3cd_commited, + NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)); + + if (!head_entry) + return; + + c_list_for_each_entry (entry, &head_entry->lst_entries_head, lst_entries) { + const NMPObject *obj = entry->obj; + GPtrArray **r; + + if (_obj_is_route_nodev(obj)) + r = routes_nodev; + else { + if (!_obj_states_sync_filter(self, obj, commit_type)) + continue; + r = routes; + } + + if (!*r) + *r = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref); + + g_ptr_array_add(*r, (gpointer) nmp_object_ref(obj)); + } +} + static void _obj_state_zombie_lst_get_prune_lists(NML3Cfg *self, int addr_family, @@ -2386,9 +2536,9 @@ handle_init: nm_utils_get_monotonic_timestamp_msec_cached(p_now_msec); if (acd_data->info.state == NM_L3_ACD_ADDR_STATE_PROBING) { - if (acd_data->probing_timestamp_msec + ACD_WAIT_PROBING_EXTRA_TIME_MSEC - + ACD_WAIT_PROBING_EXTRA_TIME2_MSEC - >= (*p_now_msec)) { + if ((*p_now_msec) > acd_data->probing_timestamp_msec + + ACD_WAIT_PROBING_EXTRA_TIME_MSEC + + ACD_WAIT_PROBING_EXTRA_TIME2_MSEC) { /* hm. We failed to create a new probe too long. Something is really wrong * internally, but let's ignore the issue and assume the address is good. What * else would we do? Assume the address is USED? */ @@ -3351,6 +3501,53 @@ nm_l3cfg_remove_config_all_dirty(NML3Cfg *self, gconstpointer tag) /*****************************************************************************/ +#define _NODEV_ROUTES_TAG(self, IS_IPv4) ((gconstpointer) (&(&(self)->priv.route_manager)[IS_IPv4])) + +static gboolean +_nodev_routes_untrack(NML3Cfg *self, int addr_family) +{ + return nmp_route_manager_untrack_all(self->priv.route_manager, + _NODEV_ROUTES_TAG(self, NM_IS_IPv4(addr_family)), + FALSE, + TRUE); +} + +static void +_nodev_routes_sync(NML3Cfg *self, + int addr_family, + NML3CfgCommitType commit_type, + GPtrArray *routes_nodev) +{ + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMPObjectType obj_type = NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4); + guint i; + gboolean changed = FALSE; + + if (!routes_nodev) + goto out_clear; + + for (i = 0; i < routes_nodev->len; i++) { + const NMPObject *obj = routes_nodev->pdata[i]; + + if (nmp_route_manager_track(self->priv.route_manager, + obj_type, + NMP_OBJECT_CAST_IP_ROUTE(obj), + 1, + _NODEV_ROUTES_TAG(self, IS_IPv4), + NULL)) + changed = TRUE; + } + +out_clear: + if (_nodev_routes_untrack(self, addr_family)) + changed = TRUE; + + if (changed || commit_type >= NM_L3_CFG_COMMIT_TYPE_REAPPLY) + nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), FALSE); +} + +/*****************************************************************************/ + typedef struct { NML3Cfg *self; gconstpointer tag; @@ -3789,6 +3986,7 @@ out_prune: } /*****************************************************************************/ + static const char * ip6_privacy_to_str(NMSettingIP6ConfigPrivacy ip6_privacy) { @@ -4049,6 +4247,7 @@ _l3_commit_one(NML3Cfg *self, const int IS_IPv4 = NM_IS_IPv4(addr_family); gs_unref_ptrarray GPtrArray *addresses = NULL; gs_unref_ptrarray GPtrArray *routes = NULL; + gs_unref_ptrarray GPtrArray *routes_nodev = NULL; gs_unref_ptrarray GPtrArray *addresses_prune = NULL; gs_unref_ptrarray GPtrArray *routes_prune = NULL; gs_unref_ptrarray GPtrArray *routes_temporary_not_available_arr = NULL; @@ -4070,23 +4269,9 @@ _l3_commit_one(NML3Cfg *self, _l3_cfg_commit_type_to_string(commit_type, sbuf_commit_type, sizeof(sbuf_commit_type))); if (self->priv.p->combined_l3cd_commited) { - const NMDedupMultiHeadEntry *head_entry; - const ObjStatesSyncFilterData sync_filter_data = { - .self = self, - .commit_type = commit_type, - }; + addresses = _commit_collect_addresses(self, addr_family, commit_type); - head_entry = nm_l3_config_data_lookup_objs(self->priv.p->combined_l3cd_commited, - NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)); - addresses = nm_dedup_multi_objs_to_ptr_array_head(head_entry, - _obj_states_sync_filter, - (gpointer) &sync_filter_data); - - head_entry = nm_l3_config_data_lookup_objs(self->priv.p->combined_l3cd_commited, - NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4)); - routes = nm_dedup_multi_objs_to_ptr_array_head(head_entry, - _obj_states_sync_filter, - (gpointer) &sync_filter_data); + _commit_collect_routes(self, addr_family, commit_type, &routes, &routes_nodev); route_table_sync = nm_l3_config_data_get_route_table_sync(self->priv.p->combined_l3cd_commited, @@ -4124,6 +4309,8 @@ _l3_commit_one(NML3Cfg *self, addresses, addresses_prune); + _nodev_routes_sync(self, addr_family, commit_type, routes_nodev); + if (!nm_platform_ip_route_sync(self->priv.platform, addr_family, self->priv.ifindex, @@ -4558,6 +4745,8 @@ constructed(GObject *object) self->priv.platform = g_object_ref(nm_netns_get_platform(self->priv.netns)); nm_assert(NM_IS_PLATFORM(self->priv.platform)); + self->priv.route_manager = nmp_route_manager_ref(nm_netns_get_route_manager(self->priv.netns)); + _LOGT("created (netns=" NM_HASH_OBFUSCATE_PTR_FMT ")", NM_HASH_OBFUSCATE_PTR(self->priv.netns)); G_OBJECT_CLASS(nm_l3cfg_parent_class)->constructed(object); @@ -4608,8 +4797,14 @@ finalize(GObject *object) nm_assert(c_list_is_empty(&self->priv.p->obj_state_temporary_not_available_lst_head)); nm_assert(c_list_is_empty(&self->priv.p->obj_state_zombie_lst_head)); + if (_nodev_routes_untrack(self, AF_INET)) + nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP4_ROUTE, FALSE); + if (_nodev_routes_untrack(self, AF_INET6)) + nmp_route_manager_sync(self->priv.route_manager, NMP_OBJECT_TYPE_IP6_ROUTE, FALSE); + g_clear_object(&self->priv.netns); g_clear_object(&self->priv.platform); + nm_clear_pointer(&self->priv.route_manager, nmp_route_manager_unref); nm_clear_l3cd(&self->priv.p->combined_l3cd_merged); nm_clear_l3cd(&self->priv.p->combined_l3cd_commited); diff --git a/src/core/nm-l3cfg.h b/src/core/nm-l3cfg.h index 6fd8f9de..7dc9facc 100644 --- a/src/core/nm-l3cfg.h +++ b/src/core/nm-l3cfg.h @@ -195,16 +195,18 @@ typedef struct { } NML3ConfigNotifyData; struct _NML3CfgPrivate; +struct _NMPRouteManager; struct _NML3Cfg { GObject parent; struct { - struct _NML3CfgPrivate *p; - NMNetns *netns; - NMPlatform *platform; - const NMPObject *plobj; - const NMPObject *plobj_next; - int ifindex; + struct _NML3CfgPrivate *p; + NMNetns *netns; + NMPlatform *platform; + struct _NMPRouteManager *route_manager; + const NMPObject *plobj; + const NMPObject *plobj_next; + int ifindex; } priv; }; diff --git a/src/core/nm-netns.c b/src/core/nm-netns.c index 4d3c3172..f120e43d 100644 --- a/src/core/nm-netns.c +++ b/src/core/nm-netns.c @@ -15,7 +15,7 @@ #include "nm-l3cfg.h" #include "libnm-platform/nm-platform.h" #include "libnm-platform/nmp-netns.h" -#include "libnm-platform/nmp-rules-manager.h" +#include "libnm-platform/nmp-route-manager.h" /*****************************************************************************/ @@ -25,7 +25,7 @@ typedef struct { NMNetns *_self_signal_user_data; NMPlatform *platform; NMPNetns *platform_netns; - NMPRulesManager *rules_manager; + NMPRouteManager *route_manager; GHashTable *l3cfgs; GHashTable *shared_ips; CList l3cfg_signal_pending_lst_head; @@ -79,10 +79,10 @@ nm_netns_get_platform(NMNetns *self) return NM_NETNS_GET_PRIVATE(self)->platform; } -NMPRulesManager * -nm_netns_get_rules_manager(NMNetns *self) +NMPRouteManager * +nm_netns_get_route_manager(NMNetns *self) { - return NM_NETNS_GET_PRIVATE(self)->rules_manager; + return NM_NETNS_GET_PRIVATE(self)->route_manager; } NMDedupMultiIndex * @@ -397,14 +397,14 @@ constructed(GObject *object) priv->platform_netns = nm_platform_netns_get(priv->platform); - priv->rules_manager = nmp_rules_manager_new(priv->platform); + priv->route_manager = nmp_route_manager_new(priv->platform); /* Weakly track the default rules with a dummy user-tag. These * rules are always weekly tracked... */ - nmp_rules_manager_track_default(priv->rules_manager, - AF_UNSPEC, - 0, - nm_netns_parent_class /* static dummy user-tag */); + nmp_route_manager_track_rule_default(priv->route_manager, + AF_UNSPEC, + 0, + nm_netns_parent_class /* static dummy user-tag */); /* Also weakly track all existing rules. These were added before NetworkManager * starts, so they are probably none of NetworkManager's business. @@ -414,12 +414,12 @@ constructed(GObject *object) * of NetworkManager, we just don't know. * * For that reason, whenever we will touch such rules later one, we make them - * fully owned and no longer weekly tracked. See %NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG. */ - nmp_rules_manager_track_from_platform(priv->rules_manager, - NULL, - AF_UNSPEC, - 0, - NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); + * fully owned and no longer weekly tracked. See %NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG. */ + nmp_route_manager_track_rule_from_platform(priv->route_manager, + NULL, + AF_UNSPEC, + 0, + NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG); G_OBJECT_CLASS(nm_netns_parent_class)->constructed(object); @@ -469,7 +469,7 @@ dispose(GObject *object) g_clear_object(&priv->platform); nm_clear_pointer(&priv->l3cfgs, g_hash_table_unref); - nm_clear_pointer(&priv->rules_manager, nmp_rules_manager_unref); + nm_clear_pointer(&priv->route_manager, nmp_route_manager_unref); G_OBJECT_CLASS(nm_netns_parent_class)->dispose(object); } diff --git a/src/core/nm-netns.h b/src/core/nm-netns.h index 0cb56375..deb1d1f0 100644 --- a/src/core/nm-netns.h +++ b/src/core/nm-netns.h @@ -29,7 +29,7 @@ NMNetns *nm_netns_new(struct _NMPlatform *platform); struct _NMPlatform *nm_netns_get_platform(NMNetns *self); NMPNetns *nm_netns_get_platform_netns(NMNetns *self); -struct _NMPRulesManager *nm_netns_get_rules_manager(NMNetns *self); +struct _NMPRouteManager *nm_netns_get_route_manager(NMNetns *self); struct _NMDedupMultiIndex *nm_netns_get_multi_idx(NMNetns *self); diff --git a/src/core/platform/nm-fake-platform.c b/src/core/platform/nm-fake-platform.c index ebb6a795..7d8986d7 100644 --- a/src/core/platform/nm-fake-platform.c +++ b/src/core/platform/nm-fake-platform.c @@ -957,11 +957,10 @@ ipx_address_delete(NMPlatform *platform, peer_addr_i = peer_addr ? *((guint32 *) peer_addr) : 0; nmp_cache_iter_for_each (&iter, - nm_platform_lookup_object(platform, - addr_family == AF_INET - ? NMP_OBJECT_TYPE_IP4_ADDRESS - : NMP_OBJECT_TYPE_IP6_ADDRESS, - 0), + nm_platform_lookup_obj_type(platform, + addr_family == AF_INET + ? NMP_OBJECT_TYPE_IP4_ADDRESS + : NMP_OBJECT_TYPE_IP6_ADDRESS), &o) { const NMPObject *obj_old = NULL; @@ -1139,7 +1138,7 @@ ip_route_add(NMPlatform *platform, gboolean has_route_to_gw = FALSE; nmp_cache_iter_for_each (&iter, - nm_platform_lookup_object(platform, NMP_OBJECT_GET_TYPE(obj), 0), + nm_platform_lookup_obj_type(platform, NMP_OBJECT_GET_TYPE(obj)), &o) { if (addr_family == AF_INET) { const NMPlatformIP4Route *item = NMP_OBJECT_CAST_IP4_ROUTE(o); diff --git a/src/core/platform/tests/test-common.c b/src/core/platform/tests/test-common.c index 24426a54..9053d351 100644 --- a/src/core/platform/tests/test-common.c +++ b/src/core/platform/tests/test-common.c @@ -102,7 +102,11 @@ nmtstp_platform_ip_address_find(NMPlatform *self, int ifindex, int addr_family, nm_assert_addr_family(addr_family); nm_assert(addr); - nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex); + if (ifindex > 0) + nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4), ifindex); + else + nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(IS_IPv4)); + nm_platform_iter_obj_for_each (&iter, self, &lookup, &obj) { const NMPlatformIPAddress *a = NMP_OBJECT_CAST_IP_ADDRESS(obj); diff --git a/src/core/platform/tests/test-platform-general.c b/src/core/platform/tests/test-platform-general.c index 7597f4f1..9629326a 100644 --- a/src/core/platform/tests/test-platform-general.c +++ b/src/core/platform/tests/test-platform-general.c @@ -748,6 +748,31 @@ test_platform_ip_address_pretty_sort_cmp(gconstpointer test_data) /*****************************************************************************/ +static void +test_route_type_is_nodev(void) +{ + int i; + + for (i = -1; i <= 257; i++) { + gboolean is_nodev; + + switch ((guint8) i) { + case RTN_BLACKHOLE: + case RTN_UNREACHABLE: + case RTN_PROHIBIT: + is_nodev = TRUE; + break; + default: + is_nodev = FALSE; + break; + } + + g_assert_cmpint(is_nodev, ==, nm_platform_route_type_is_nodev(i)); + } +} + +/*****************************************************************************/ + NMTST_DEFINE(); int @@ -767,6 +792,7 @@ main(int argc, char **argv) g_test_add_data_func("/general/platform_ip_address_pretty_sort_cmp/6/2", GINT_TO_POINTER(2), test_platform_ip_address_pretty_sort_cmp); + g_test_add_func("/general/test_route_type_is_nodev", test_route_type_is_nodev); return g_test_run(); } diff --git a/src/core/platform/tests/test-route.c b/src/core/platform/tests/test-route.c index 37909d55..cf0236e0 100644 --- a/src/core/platform/tests/test-route.c +++ b/src/core/platform/tests/test-route.c @@ -10,7 +10,7 @@ #include "nm-core-utils.h" #include "libnm-platform/nm-platform-utils.h" -#include "libnm-platform/nmp-rules-manager.h" +#include "libnm-platform/nmp-route-manager.h" #include "test-common.h" @@ -1637,8 +1637,8 @@ again: if (TEST_SYNC) { gs_unref_hashtable GHashTable *unique_priorities = g_hash_table_new(NULL, NULL); - nm_auto_unref_rules_manager NMPRulesManager *rules_manager = - nmp_rules_manager_new(platform); + nm_auto_unref_route_manager NMPRouteManager *route_manager = + nmp_route_manager_new(platform); gs_unref_ptrarray GPtrArray *objs_sync = NULL; gconstpointer USER_TAG_1 = &platform; gconstpointer USER_TAG_2 = &unique_priorities; @@ -1660,29 +1660,29 @@ again: } for (i = 0; i < objs_sync->len; i++) { - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - 1, - USER_TAG_1, - NULL); + nmp_route_manager_track_rule(route_manager, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + 1, + USER_TAG_1, + NULL); if (nmtst_get_rand_bool()) { /* this has no effect, because a negative priority (of same absolute value) * has lower priority than the positive priority above. */ - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -1, - USER_TAG_2, - NULL); + nmp_route_manager_track_rule(route_manager, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + -1, + USER_TAG_2, + NULL); } if (nmtst_get_rand_uint32() % objs_sync->len == 0) { - nmp_rules_manager_sync(rules_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_rules_manager_sync(rules_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); @@ -1690,37 +1690,37 @@ again: for (i = 0; i < objs_sync->len; i++) { switch (nmtst_get_rand_uint32() % 3) { case 0: - nmp_rules_manager_untrack(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - USER_TAG_1); - nmp_rules_manager_untrack(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - USER_TAG_1); + nmp_route_manager_untrack_rule(route_manager, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + USER_TAG_1); + nmp_route_manager_untrack_rule(route_manager, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + USER_TAG_1); break; case 1: - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -1, - USER_TAG_1, - NULL); + nmp_route_manager_track_rule(route_manager, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + -1, + USER_TAG_1, + NULL); break; case 2: - nmp_rules_manager_track(rules_manager, - NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), - -2, - USER_TAG_2, - NULL); + nmp_route_manager_track_rule(route_manager, + NMP_OBJECT_CAST_ROUTING_RULE(objs_sync->pdata[i]), + -2, + USER_TAG_2, + NULL); break; } if (nmtst_get_rand_uint32() % objs_sync->len == 0) { - nmp_rules_manager_sync(rules_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_rules_manager_sync(rules_manager, FALSE); + nmp_route_manager_sync(route_manager, NMP_OBJECT_TYPE_ROUTING_RULE, FALSE); } else { for (i = 0; i < objs->len;) { @@ -1886,6 +1886,64 @@ again: /*****************************************************************************/ +static void +test_blackhole(gconstpointer test_data) +{ + int TEST_IDX = GPOINTER_TO_INT(test_data); + const int addr_family = (TEST_IDX == 1) ? AF_INET : AF_INET6; + const int IS_IPv4 = NM_IS_IPv4(addr_family); + const NMDedupMultiHeadEntry *head_entry; + NMDedupMultiIter iter; + const NMPObject *obj; + NMPObject obj_stack; + NMPlatformIPXRoute rr = {}; + int r = -1; + int i; + + if (IS_IPv4) { + rr.r4 = (const NMPlatformIP4Route){ + .type_coerced = nmtst_rand_select(RTN_BLACKHOLE, RTN_UNREACHABLE, RTN_PROHIBIT), + }; + } else { + rr.r6 = (const NMPlatformIP6Route){ + .type_coerced = nmtst_rand_select(RTN_BLACKHOLE, RTN_UNREACHABLE, RTN_PROHIBIT), + .metric = 1000, + }; + } + + nm_platform_ip_route_normalize(addr_family, &rr.rx); + + if (IS_IPv4) + r = nm_platform_ip4_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r4); + else + r = nm_platform_ip6_route_add(NM_PLATFORM_GET, NMP_NLM_FLAG_APPEND, &rr.r6); + + g_assert_cmpint(r, ==, 0); + + nmp_object_stackinit(&obj_stack, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), &rr); + + obj = nm_platform_lookup_obj(NM_PLATFORM_GET, NMP_CACHE_ID_TYPE_OBJECT_TYPE, &obj_stack); + + _LOGT(">>> adding %s", + nmp_object_to_string(&obj_stack, NMP_OBJECT_TO_STRING_ALL, g_alloca(1000), 1000)); + _LOGT(">>> found %s", + nmp_object_to_string(obj, NMP_OBJECT_TO_STRING_ALL, g_alloca(1000), 1000)); + + g_assert(obj); + + head_entry = nm_platform_lookup_object(NM_PLATFORM_GET, NMP_OBJECT_TYPE_IP_ROUTE(IS_IPv4), 0); + g_assert(head_entry); + g_assert_cmpint(head_entry->len, ==, 1); + i = 0; + nm_dedup_multi_iter_for_each (&iter, head_entry) { + i++; + g_assert(iter.current->obj == obj); + } + g_assert_cmpint(i, ==, 1); +} + +/*****************************************************************************/ + NMTstpSetupFunc const _nmtstp_setup_platform_func = SETUP; void @@ -1923,4 +1981,8 @@ _nmtstp_setup_tests(void) add_test_func_data("/route/rule/3", test_rule, GINT_TO_POINTER(3)); add_test_func_data("/route/rule/4", test_rule, GINT_TO_POINTER(4)); } + if (nmtstp_is_root_test()) { + add_test_func_data("/route/blackhole/1", test_blackhole, GINT_TO_POINTER(1)); + add_test_func_data("/route/blackhole/2", test_blackhole, GINT_TO_POINTER(2)); + } } |