about summary refs log tree commit diff
path: root/src/libnm-platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-platform')
-rw-r--r--src/libnm-platform/meson.build2
-rw-r--r--src/libnm-platform/nm-linux-platform.c895
-rw-r--r--src/libnm-platform/nm-netlink.c93
-rw-r--r--src/libnm-platform/nm-netlink.h44
-rw-r--r--src/libnm-platform/nm-platform-private.h2
-rw-r--r--src/libnm-platform/nm-platform-utils.c64
-rw-r--r--src/libnm-platform/nm-platform-utils.h8
-rw-r--r--src/libnm-platform/nm-platform.c523
-rw-r--r--src/libnm-platform/nm-platform.h344
-rw-r--r--src/libnm-platform/nmp-netns.c24
-rw-r--r--src/libnm-platform/nmp-object.c183
-rw-r--r--src/libnm-platform/nmp-object.h93
-rw-r--r--src/libnm-platform/nmp-route-manager.c839
-rw-r--r--src/libnm-platform/nmp-route-manager.h79
-rw-r--r--src/libnm-platform/nmp-rules-manager.c809
-rw-r--r--src/libnm-platform/nmp-rules-manager.h53
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils-nl80211.c86
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils-private.h4
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils-wext.c14
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils.c4
-rw-r--r--src/libnm-platform/wifi/nm-wifi-utils.h4
-rw-r--r--src/libnm-platform/wpan/nm-wpan-utils.c22
22 files changed, 2203 insertions, 1986 deletions
diff --git a/src/libnm-platform/meson.build b/src/libnm-platform/meson.build
index 3e4f41a9..d0a7c6c2 100644
--- a/src/libnm-platform/meson.build
+++ b/src/libnm-platform/meson.build
@@ -9,7 +9,7 @@ libnm_platform = static_library(
     'nm-platform.c',
     'nmp-netns.c',
     'nmp-object.c',
-    'nmp-rules-manager.c',
+    'nmp-route-manager.c',
     'wifi/nm-wifi-utils-nl80211.c',
     'wifi/nm-wifi-utils.c',
     'wpan/nm-wpan-utils.c',
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index 78df53e7..93935b98 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -402,11 +402,11 @@ typedef struct {
     guint32                            seq_number;
     WaitForNlResponseResult            seq_result;
     DelayedActionWaitForNlResponseType response_type;
-    gint64                             timeout_abs_ns;
-    WaitForNlResponseResult *          out_seq_result;
-    char **                            out_errmsg;
+    gint64                             timeout_abs_nsec;
+    WaitForNlResponseResult           *out_seq_result;
+    char                             **out_errmsg;
     union {
-        int *       out_refresh_all_in_progress;
+        int        *out_refresh_all_in_progress;
         NMPObject **out_route_get;
         gpointer    out_data;
     } response;
@@ -446,11 +446,22 @@ typedef struct {
 
         GPtrArray *list_master_connected;
         GPtrArray *list_refresh_link;
-        GArray *   list_wait_for_nl_response;
+        GArray    *list_wait_for_nl_response;
 
         int is_handling;
     } delayed_action;
 
+    /* This is the receive buffer for netlink messages. This buffer should be large
+     * enough for any rtnetlink message. When too small, nl_recv() would notice the
+     * truncation and lose the message. In that case, we reallocate a larger buffer.
+     *
+     * We keep the receive buffer around for the entire lifetime of the platform instance.
+     * Usually we only have one platform instance per netns, so we don't waste too much. */
+    struct {
+        unsigned char *buf;
+        gsize          len;
+    } netlink_recv_buf;
+
 } NMLinuxPlatformPrivate;
 
 struct _NMLinuxPlatform {
@@ -493,7 +504,7 @@ NM_LINUX_PLATFORM_FROM_PRIVATE(NMLinuxPlatformPrivate *priv)
     G_STMT_START                                                                          \
     {                                                                                     \
         char              __prefix[32];                                                   \
-        const char *      __p_prefix = _NMLOG_PREFIX_NAME;                                \
+        const char       *__p_prefix = _NMLOG_PREFIX_NAME;                                \
         NMPlatform *const __self     = (self);                                            \
                                                                                           \
         if (__self && nm_platform_get_log_with_ptr(__self)) {                             \
@@ -554,7 +565,7 @@ delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpo
 static gboolean delayed_action_handle_all(NMPlatform *platform, gboolean read_netlink);
 static void do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char *name);
 static void do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action_type);
-static void cache_on_change(NMPlatform *     platform,
+static void cache_on_change(NMPlatform      *platform,
                             NMPCacheOpsType  cache_op,
                             const NMPObject *obj_old,
                             const NMPObject *obj_new);
@@ -576,8 +587,8 @@ wait_for_nl_response_to_nmerr(WaitForNlResponseResult seq_result)
 
 static const char *
 wait_for_nl_response_to_string(WaitForNlResponseResult seq_result,
-                               const char *            errmsg,
-                               char *                  buf,
+                               const char             *errmsg,
+                               char                   *buf,
                                gsize                   buf_size)
 {
     char *buf0 = buf;
@@ -993,9 +1004,9 @@ _addrtime_get_lifetimes(guint32  timestamp,
 /*****************************************************************************/
 
 static const NMPObject *
-_lookup_cached_link(const NMPCache *  cache,
+_lookup_cached_link(const NMPCache   *cache,
                     int               ifindex,
-                    gboolean *        completed_from_cache,
+                    gboolean         *completed_from_cache,
                     const NMPObject **link_cached)
 {
     const NMPObject *obj;
@@ -1019,7 +1030,7 @@ static char *
 _linktype_read_devtype(int dirfd)
 {
     gs_free char *contents = NULL;
-    char *        cont, *end;
+    char         *cont, *end;
 
     nm_assert(dirfd >= 0);
 
@@ -1046,16 +1057,16 @@ _linktype_read_devtype(int dirfd)
 }
 
 static NMLinkType
-_linktype_get_type(NMPlatform *      platform,
-                   const NMPCache *  cache,
-                   const char *      kind,
+_linktype_get_type(NMPlatform       *platform,
+                   const NMPCache   *cache,
+                   const char       *kind,
                    int               ifindex,
-                   const char *      ifname,
+                   const char       *ifname,
                    unsigned          flags,
                    unsigned          arptype,
-                   gboolean *        completed_from_cache,
+                   gboolean         *completed_from_cache,
                    const NMPObject **link_cached,
-                   const char **     out_kind)
+                   const char      **out_kind)
 {
     NMLinkType link_type;
 
@@ -1138,7 +1149,7 @@ _linktype_get_type(NMPlatform *      platform,
 
     {
         nm_auto_close int dirfd   = -1;
-        gs_free char *    devtype = NULL;
+        gs_free char     *devtype = NULL;
         char              ifname_verified[IFNAMSIZ];
 
         dirfd = nmp_utils_sysctl_open_netdir(ifindex, ifname, ifname_verified);
@@ -1242,12 +1253,12 @@ _nl_addattr_l(struct nlmsghdr *n, int maxlen, int type, const void *data, int al
 
 /* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */
 static gboolean
-_parse_af_inet6(NMPlatform *        platform,
-                struct nlattr *     attr,
+_parse_af_inet6(NMPlatform         *platform,
+                struct nlattr      *attr,
                 NMUtilsIPv6IfaceId *out_token,
-                gboolean *          out_token_valid,
-                guint8 *            out_addr_gen_mode_inv,
-                gboolean *          out_addr_gen_mode_valid)
+                gboolean           *out_token_valid,
+                guint8             *out_addr_gen_mode_inv,
+                gboolean           *out_addr_gen_mode_valid)
 {
     static const struct nla_policy policy[] = {
         [IFLA_INET6_FLAGS]      = {.type = NLA_U32},
@@ -1258,7 +1269,7 @@ _parse_af_inet6(NMPlatform *        platform,
         [IFLA_INET6_TOKEN]      = {.minlen = sizeof(struct in6_addr)},
         [IFLA_INET6_ADDR_GEN_MODE] = {.type = NLA_U8},
     };
-    struct nlattr * tb[G_N_ELEMENTS(policy)];
+    struct nlattr  *tb[G_N_ELEMENTS(policy)];
     struct in6_addr i6_token;
     gboolean        token_valid          = FALSE;
     gboolean        addr_gen_mode_valid  = FALSE;
@@ -1331,8 +1342,8 @@ _parse_lnk_bridge(const char *kind, struct nlattr *info_data)
         [IFLA_BR_MCAST_STARTUP_QUERY_INTVL]  = {.type = NLA_U64},
     };
     NMPlatformLnkBridge *props;
-    struct nlattr *      tb[G_N_ELEMENTS(policy)];
-    NMPObject *          obj;
+    struct nlattr       *tb[G_N_ELEMENTS(policy)];
+    NMPObject           *obj;
 
     if (!info_data || !nm_streq0(kind, "bridge"))
         return NULL;
@@ -1420,8 +1431,8 @@ _parse_lnk_gre(const char *kind, struct nlattr *info_data)
         [IFLA_GRE_TOS]      = {.type = NLA_U8},
         [IFLA_GRE_PMTUDISC] = {.type = NLA_U8},
     };
-    struct nlattr *   tb[G_N_ELEMENTS(policy)];
-    NMPObject *       obj;
+    struct nlattr    *tb[G_N_ELEMENTS(policy)];
+    NMPObject        *obj;
     NMPlatformLnkGre *props;
     gboolean          is_tap;
 
@@ -1480,10 +1491,10 @@ _parse_lnk_infiniband(const char *kind, struct nlattr *info_data)
         [IFLA_IPOIB_MODE]   = {.type = NLA_U16},
         [IFLA_IPOIB_UMCAST] = {.type = NLA_U16},
     };
-    struct nlattr *          tb[G_N_ELEMENTS(policy)];
+    struct nlattr           *tb[G_N_ELEMENTS(policy)];
     NMPlatformLnkInfiniband *info;
-    NMPObject *              obj;
-    const char *             mode;
+    NMPObject               *obj;
+    const char              *mode;
 
     if (!info_data || !nm_streq0(kind, "ipoib"))
         return NULL;
@@ -1529,8 +1540,8 @@ _parse_lnk_ip6tnl(const char *kind, struct nlattr *info_data)
         [IFLA_IPTUN_PROTO]       = {.type = NLA_U8},
         [IFLA_IPTUN_FLAGS]       = {.type = NLA_U32},
     };
-    struct nlattr *      tb[G_N_ELEMENTS(policy)];
-    NMPObject *          obj;
+    struct nlattr       *tb[G_N_ELEMENTS(policy)];
+    NMPObject           *obj;
     NMPlatformLnkIp6Tnl *props;
     guint32              flowinfo;
 
@@ -1582,8 +1593,8 @@ _parse_lnk_ip6gre(const char *kind, struct nlattr *info_data)
         [IFLA_GRE_FLOWINFO]    = {.type = NLA_U32},
         [IFLA_GRE_FLAGS]       = {.type = NLA_U32},
     };
-    struct nlattr *      tb[G_N_ELEMENTS(policy)];
-    NMPObject *          obj;
+    struct nlattr       *tb[G_N_ELEMENTS(policy)];
+    NMPObject           *obj;
     NMPlatformLnkIp6Tnl *props;
     guint32              flowinfo;
     gboolean             is_tap;
@@ -1648,8 +1659,8 @@ _parse_lnk_ipip(const char *kind, struct nlattr *info_data)
         [IFLA_IPTUN_TOS]      = {.type = NLA_U8},
         [IFLA_IPTUN_PMTUDISC] = {.type = NLA_U8},
     };
-    struct nlattr *    tb[G_N_ELEMENTS(policy)];
-    NMPObject *        obj;
+    struct nlattr     *tb[G_N_ELEMENTS(policy)];
+    NMPObject         *obj;
     NMPlatformLnkIpIp *props;
 
     if (!info_data || !nm_streq0(kind, "ipip"))
@@ -1681,8 +1692,8 @@ _parse_lnk_macvlan(const char *kind, struct nlattr *info_data)
         [IFLA_MACVLAN_FLAGS] = {.type = NLA_U16},
     };
     NMPlatformLnkMacvlan *props;
-    struct nlattr *       tb[G_N_ELEMENTS(policy)];
-    NMPObject *           obj;
+    struct nlattr        *tb[G_N_ELEMENTS(policy)];
+    NMPObject            *obj;
     gboolean              tap;
 
     if (!info_data || !kind)
@@ -1732,8 +1743,8 @@ _parse_lnk_macsec(const char *kind, struct nlattr *info_data)
         [IFLA_MACSEC_REPLAY_PROTECT] = {.type = NLA_U8},
         [IFLA_MACSEC_VALIDATION]     = {.type = NLA_U8},
     };
-    struct nlattr *      tb[G_N_ELEMENTS(policy)];
-    NMPObject *          obj;
+    struct nlattr       *tb[G_N_ELEMENTS(policy)];
+    NMPObject           *obj;
     NMPlatformLnkMacsec *props;
 
     if (!info_data || !nm_streq0(kind, "macsec"))
@@ -1800,8 +1811,8 @@ _parse_lnk_sit(const char *kind, struct nlattr *info_data)
         [IFLA_IPTUN_FLAGS]    = {.type = NLA_U16},
         [IFLA_IPTUN_PROTO]    = {.type = NLA_U8},
     };
-    struct nlattr *   tb[G_N_ELEMENTS(policy)];
-    NMPObject *       obj;
+    struct nlattr    *tb[G_N_ELEMENTS(policy)];
+    NMPObject        *obj;
     NMPlatformLnkSit *props;
 
     if (!info_data || !nm_streq0(kind, "sit"))
@@ -1841,8 +1852,8 @@ _parse_lnk_tun(const char *kind, struct nlattr *info_data)
         [IFLA_TUN_NUM_QUEUES]          = {.type = NLA_U32},
         [IFLA_TUN_NUM_DISABLED_QUEUES] = {.type = NLA_U32},
     };
-    struct nlattr *   tb[G_N_ELEMENTS(policy)];
-    NMPObject *       obj;
+    struct nlattr    *tb[G_N_ELEMENTS(policy)];
+    NMPObject        *obj;
     NMPlatformLnkTun *props;
 
     if (!info_data || !nm_streq0(kind, "tun"))
@@ -1878,12 +1889,12 @@ _parse_lnk_tun(const char *kind, struct nlattr *info_data)
 /*****************************************************************************/
 
 static gboolean
-_vlan_qos_mapping_from_nla(struct nlattr *          nlattr,
+_vlan_qos_mapping_from_nla(struct nlattr           *nlattr,
                            const NMVlanQosMapping **out_map,
-                           guint *                  out_n_map)
+                           guint                   *out_n_map)
 {
-    struct nlattr *   nla;
-    int               remaining;
+    struct nlattr               *nla;
+    int                          remaining;
     gs_unref_ptrarray GPtrArray *array = NULL;
 
     G_STATIC_ASSERT(sizeof(NMVlanQosMapping) == sizeof(struct ifla_vlan_qos_mapping));
@@ -1950,9 +1961,9 @@ _parse_lnk_vlan(const char *kind, struct nlattr *info_data)
         [IFLA_VLAN_EGRESS_QOS]  = {.type = NLA_NESTED},
         [IFLA_VLAN_PROTOCOL]    = {.type = NLA_U16},
     };
-    struct nlattr *tb[G_N_ELEMENTS(policy)];
+    struct nlattr            *tb[G_N_ELEMENTS(policy)];
     nm_auto_nmpobj NMPObject *obj = NULL;
-    NMPObject *               obj_result;
+    NMPObject                *obj_result;
 
     if (!info_data || !nm_streq0(kind, "vlan"))
         return NULL;
@@ -2050,8 +2061,8 @@ _parse_lnk_vxlan(const char *kind, struct nlattr *info_data)
         [IFLA_VXLAN_PORT]       = {.type = NLA_U16},
     };
     NMPlatformLnkVxlan *props;
-    struct nlattr *     tb[G_N_ELEMENTS(policy)];
-    NMPObject *         obj;
+    struct nlattr      *tb[G_N_ELEMENTS(policy)];
+    NMPObject          *obj;
 
     if (!info_data || !nm_streq0(kind, "vxlan"))
         return NULL;
@@ -2117,8 +2128,8 @@ _parse_lnk_vrf(const char *kind, struct nlattr *info_data)
         [IFLA_VRF_TABLE] = {.type = NLA_U32},
     };
     NMPlatformLnkVrf *props;
-    struct nlattr *   tb[G_N_ELEMENTS(policy)];
-    NMPObject *       obj;
+    struct nlattr    *tb[G_N_ELEMENTS(policy)];
+    NMPObject        *obj;
 
     if (!info_data || !nm_streq0(kind, "vrf"))
         return NULL;
@@ -2199,7 +2210,7 @@ _wireguard_update_from_peers_nla(CList *peers, GArray **p_allowed_ips, struct nl
         [WGPEER_A_TX_BYTES]                      = {.type = NLA_U64},
         [WGPEER_A_ALLOWEDIPS]                    = {.type = NLA_NESTED},
     };
-    struct nlattr *         tb[G_N_ELEMENTS(policy)];
+    struct nlattr          *tb[G_N_ELEMENTS(policy)];
     WireGuardPeerConstruct *peer_c;
 
     if (nla_parse_nested_arr(tb, peer_attr, policy) < 0)
@@ -2259,7 +2270,7 @@ _wireguard_update_from_peers_nla(CList *peers, GArray **p_allowed_ips, struct nl
     if (tb[WGPEER_A_ALLOWEDIPS]) {
         struct nlattr *attr;
         int            rem;
-        GArray *       allowed_ips = *p_allowed_ips;
+        GArray        *allowed_ips = *p_allowed_ips;
 
         nla_for_each_nested (attr, tb[WGPEER_A_ALLOWEDIPS], rem) {
             if (!allowed_ips) {
@@ -2290,7 +2301,7 @@ typedef struct {
     const int  ifindex;
     NMPObject *obj;
     CList      peers;
-    GArray *   allowed_ips;
+    GArray    *allowed_ips;
 } WireGuardParseData;
 
 static int
@@ -2306,7 +2317,7 @@ _wireguard_get_device_cb(struct nl_msg *msg, void *arg)
         [WGDEVICE_A_FWMARK]      = {.type = NLA_U32},
         [WGDEVICE_A_PEERS]       = {.type = NLA_NESTED},
     };
-    struct nlattr *     tb[G_N_ELEMENTS(policy)];
+    struct nlattr      *tb[G_N_ELEMENTS(policy)];
     WireGuardParseData *parse_data = arg;
 
     if (genlmsg_parse_arr(nlmsg_hdr(msg), 0, tb, policy) < 0)
@@ -2327,7 +2338,7 @@ _wireguard_get_device_cb(struct nl_msg *msg, void *arg)
         /* we already have an object instance. This means the netlink message
          * is a continuation, only providing more WGDEVICE_A_PEERS data below. */
     } else {
-        NMPObject *             obj;
+        NMPObject              *obj;
         NMPlatformLnkWireGuard *props;
 
         obj   = nmp_object_new(NMP_OBJECT_TYPE_LNK_WIREGUARD, NULL);
@@ -2370,18 +2381,18 @@ _wireguard_get_device_cb(struct nl_msg *msg, void *arg)
 }
 
 static const NMPObject *
-_wireguard_read_info(NMPlatform *    platform /* used only as logging context */,
+_wireguard_read_info(NMPlatform     *platform /* used only as logging context */,
                      struct nl_sock *genl,
                      int             wireguard_family_id,
                      int             ifindex)
 {
     nm_auto_nlmsg struct nl_msg *msg = NULL;
-    NMPObject *                  obj = NULL;
-    WireGuardPeerConstruct *     peer_c;
-    WireGuardPeerConstruct *     peer_c_safe;
-    gs_unref_array GArray *allowed_ips = NULL;
-    WireGuardParseData     parse_data  = {
-        .ifindex = ifindex,
+    NMPObject                   *obj = NULL;
+    WireGuardPeerConstruct      *peer_c;
+    WireGuardPeerConstruct      *peer_c_safe;
+    gs_unref_array GArray       *allowed_ips = NULL;
+    WireGuardParseData           parse_data  = {
+                   .ifindex = ifindex,
     };
     guint i;
 
@@ -2522,13 +2533,13 @@ _wireguard_get_family_id(NMPlatform *platform, int ifindex_try)
 static const NMPObject *
 _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifindex)
 {
-    NMLinuxPlatformPrivate *priv            = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+    NMLinuxPlatformPrivate         *priv    = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     nm_auto_nmpobj const NMPObject *obj_old = NULL;
     nm_auto_nmpobj const NMPObject *obj_new = NULL;
     nm_auto_nmpobj const NMPObject *lnk_new = NULL;
     NMPCacheOpsType                 cache_op;
-    const NMPObject *               plink = NULL;
-    nm_auto_nmpobj NMPObject *obj         = NULL;
+    const NMPObject                *plink = NULL;
+    nm_auto_nmpobj NMPObject       *obj   = NULL;
 
     nm_assert(wireguard_family_id >= 0);
     nm_assert(ifindex > 0);
@@ -2587,25 +2598,25 @@ _wireguard_refresh_link(NMPlatform *platform, int wireguard_family_id, int ifind
 }
 
 static int
-_wireguard_create_change_nlmsgs(NMPlatform *                              platform,
+_wireguard_create_change_nlmsgs(NMPlatform                               *platform,
                                 int                                       ifindex,
                                 int                                       wireguard_family_id,
-                                const NMPlatformLnkWireGuard *            lnk_wireguard,
-                                const NMPWireGuardPeer *                  peers,
+                                const NMPlatformLnkWireGuard             *lnk_wireguard,
+                                const NMPWireGuardPeer                   *peers,
                                 const NMPlatformWireGuardChangePeerFlags *peer_flags,
                                 guint                                     peers_len,
                                 NMPlatformWireGuardChangeFlags            change_flags,
-                                GPtrArray **                              out_msgs)
+                                GPtrArray                               **out_msgs)
 {
-    gs_unref_ptrarray GPtrArray *      msgs    = NULL;
-    nm_auto_nlmsg struct nl_msg *      msg     = NULL;
+    gs_unref_ptrarray GPtrArray       *msgs    = NULL;
+    nm_auto_nlmsg struct nl_msg       *msg     = NULL;
     const guint                        IDX_NIL = G_MAXUINT;
     guint                              idx_peer_curr;
     guint                              idx_allowed_ips_curr;
-    struct nlattr *                    nest_peers;
-    struct nlattr *                    nest_curr_peer;
-    struct nlattr *                    nest_allowed_ips;
-    struct nlattr *                    nest_curr_allowed_ip;
+    struct nlattr                     *nest_peers;
+    struct nlattr                     *nest_curr_peer;
+    struct nlattr                     *nest_allowed_ips;
+    struct nlattr                     *nest_curr_allowed_ip;
     NMPlatformWireGuardChangePeerFlags p_flags = NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_DEFAULT;
 
 #define _nla_nest_end(msg, nest_start)             \
@@ -2821,15 +2832,15 @@ nla_put_failure:
 }
 
 static int
-link_wireguard_change(NMPlatform *                              platform,
+link_wireguard_change(NMPlatform                               *platform,
                       int                                       ifindex,
-                      const NMPlatformLnkWireGuard *            lnk_wireguard,
-                      const NMPWireGuardPeer *                  peers,
+                      const NMPlatformLnkWireGuard             *lnk_wireguard,
+                      const NMPWireGuardPeer                   *peers,
                       const NMPlatformWireGuardChangePeerFlags *peer_flags,
                       guint                                     peers_len,
                       NMPlatformWireGuardChangeFlags            change_flags)
 {
-    NMLinuxPlatformPrivate *priv      = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+    NMLinuxPlatformPrivate      *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     gs_unref_ptrarray GPtrArray *msgs = NULL;
     int                          wireguard_family_id;
     guint                        i;
@@ -2897,8 +2908,8 @@ _nmp_link_address_set(NMPLinkAddress *dst, const struct nlattr *nla)
 
 /* Copied and heavily modified from libnl3's link_msg_parser(). */
 static NMPObject *
-_new_from_nl_link(NMPlatform *     platform,
-                  const NMPCache * cache,
+_new_from_nl_link(NMPlatform      *platform,
+                  const NMPCache  *cache,
                   struct nlmsghdr *nlh,
                   gboolean         id_only)
 {
@@ -2930,15 +2941,15 @@ _new_from_nl_link(NMPlatform *     platform,
         [IFLA_LINK_NETNSID]  = {},
         [IFLA_PERM_ADDRESS]  = {.type = NLA_UNSPEC},
     };
-    const struct ifinfomsg *ifi;
-    struct nlattr *         tb[G_N_ELEMENTS(policy)];
-    struct nlattr *         nl_info_data               = NULL;
-    const char *            nl_info_kind               = NULL;
+    const struct ifinfomsg   *ifi;
+    struct nlattr            *tb[G_N_ELEMENTS(policy)];
+    struct nlattr            *nl_info_data             = NULL;
+    const char               *nl_info_kind             = NULL;
     nm_auto_nmpobj NMPObject *obj                      = NULL;
     gboolean                  completed_from_cache_val = FALSE;
-    gboolean *                completed_from_cache     = cache ? &completed_from_cache_val : NULL;
-    const NMPObject *         link_cached              = NULL;
-    const NMPObject *         lnk_data                 = NULL;
+    gboolean                 *completed_from_cache     = cache ? &completed_from_cache_val : NULL;
+    const NMPObject          *link_cached              = NULL;
+    const NMPObject          *lnk_data                 = NULL;
     gboolean                  address_complete_from_cache      = TRUE;
     gboolean                  perm_address_complete_from_cache = TRUE;
     gboolean                  broadcast_complete_from_cache    = TRUE;
@@ -3210,7 +3221,7 @@ _new_from_nl_link(NMPlatform *     platform,
 
     if (obj->link.type == NM_LINK_TYPE_WIREGUARD) {
         const NMPObject *lnk_data_new = NULL;
-        struct nl_sock * genl         = NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl;
+        struct nl_sock  *genl         = NM_LINUX_PLATFORM_GET_PRIVATE(platform)->genl;
 
         /* The WireGuard kernel module does not yet send link update
          * notifications, so we don't actually update the cache. For
@@ -3255,9 +3266,9 @@ _new_from_nl_addr(struct nlmsghdr *nlh, gboolean id_only)
         [IFA_CACHEINFO] = {.minlen = nm_offsetofend(struct ifa_cacheinfo, tstamp)},
         [IFA_FLAGS]     = {},
     };
-    struct nlattr *         tb[G_N_ELEMENTS(policy)];
-    const struct ifaddrmsg *ifa;
-    gboolean                is_v4;
+    struct nlattr            *tb[G_N_ELEMENTS(policy)];
+    const struct ifaddrmsg   *ifa;
+    gboolean                  IS_IPv4;
     nm_auto_nmpobj NMPObject *obj = NULL;
     int                       addr_len;
     guint32                   lifetime, preferred, timestamp;
@@ -3267,29 +3278,31 @@ _new_from_nl_addr(struct nlmsghdr *nlh, gboolean id_only)
 
     ifa = nlmsg_data(nlh);
 
-    if (!NM_IN_SET(ifa->ifa_family, AF_INET, AF_INET6))
+    if (ifa->ifa_family == AF_INET)
+        IS_IPv4 = TRUE;
+    else if (ifa->ifa_family == AF_INET6)
+        IS_IPv4 = FALSE;
+    else
         return NULL;
 
-    is_v4 = ifa->ifa_family == AF_INET;
-
     if (nlmsg_parse_arr(nlh, sizeof(*ifa), tb, policy) < 0)
         return NULL;
 
-    addr_len = is_v4 ? sizeof(in_addr_t) : sizeof(struct in6_addr);
+    addr_len = IS_IPv4 ? sizeof(in_addr_t) : sizeof(struct in6_addr);
 
-    if (ifa->ifa_prefixlen > (is_v4 ? 32 : 128))
+    if (ifa->ifa_prefixlen > (IS_IPv4 ? 32 : 128))
         return NULL;
 
     /*****************************************************************/
 
-    obj = nmp_object_new(is_v4 ? NMP_OBJECT_TYPE_IP4_ADDRESS : NMP_OBJECT_TYPE_IP6_ADDRESS, NULL);
+    obj = nmp_object_new(IS_IPv4 ? NMP_OBJECT_TYPE_IP4_ADDRESS : NMP_OBJECT_TYPE_IP6_ADDRESS, NULL);
 
     obj->ip_address.ifindex = ifa->ifa_index;
     obj->ip_address.plen    = ifa->ifa_prefixlen;
 
     _check_addr_or_return_null(tb, IFA_ADDRESS, addr_len);
     _check_addr_or_return_null(tb, IFA_LOCAL, addr_len);
-    if (is_v4) {
+    if (IS_IPv4) {
         /* For IPv4, kernel omits IFA_LOCAL/IFA_ADDRESS if (and only if) they
          * are effectively 0.0.0.0 (all-zero). */
         if (tb[IFA_LOCAL])
@@ -3325,7 +3338,7 @@ _new_from_nl_addr(struct nlmsghdr *nlh, gboolean id_only)
 
     obj->ip_address.n_ifa_flags = tb[IFA_FLAGS] ? nla_get_u32(tb[IFA_FLAGS]) : ifa->ifa_flags;
 
-    if (is_v4) {
+    if (IS_IPv4) {
         if (tb[IFA_LABEL]) {
             char label[IFNAMSIZ];
 
@@ -3374,9 +3387,9 @@ _new_from_nl_route(struct nlmsghdr *nlh, gboolean id_only)
         [RTA_METRICS]   = {.type = NLA_NESTED},
         [RTA_MULTIPATH] = {.type = NLA_NESTED},
     };
-    const struct rtmsg *rtm;
-    struct nlattr *     tb[G_N_ELEMENTS(policy)];
-    gboolean            is_v4;
+    const struct rtmsg       *rtm;
+    struct nlattr            *tb[G_N_ELEMENTS(policy)];
+    gboolean                  IS_IPv4;
     nm_auto_nmpobj NMPObject *obj = NULL;
     int                       addr_len;
     struct {
@@ -3403,10 +3416,19 @@ _new_from_nl_route(struct nlmsghdr *nlh, gboolean id_only)
      * only handle ~supported~ routes.
      *****************************************************************/
 
-    if (!NM_IN_SET(rtm->rtm_family, AF_INET, AF_INET6))
+    if (rtm->rtm_family == AF_INET)
+        IS_IPv4 = TRUE;
+    else if (rtm->rtm_family == AF_INET6)
+        IS_IPv4 = FALSE;
+    else
         return NULL;
 
-    if (!NM_IN_SET(rtm->rtm_type, RTN_UNICAST, RTN_LOCAL))
+    if (!NM_IN_SET(rtm->rtm_type,
+                   RTN_UNICAST,
+                   RTN_LOCAL,
+                   RTN_BLACKHOLE,
+                   RTN_UNREACHABLE,
+                   RTN_PROHIBIT))
         return NULL;
 
     if (nlmsg_parse_arr(nlh, sizeof(struct rtmsg), tb, policy) < 0)
@@ -3414,10 +3436,9 @@ _new_from_nl_route(struct nlmsghdr *nlh, gboolean id_only)
 
     /*****************************************************************/
 
-    is_v4    = rtm->rtm_family == AF_INET;
-    addr_len = is_v4 ? sizeof(in_addr_t) : sizeof(struct in6_addr);
+    addr_len = IS_IPv4 ? sizeof(in_addr_t) : sizeof(struct in6_addr);
 
-    if (rtm->rtm_dst_len > (is_v4 ? 32 : 128))
+    if (rtm->rtm_dst_len > (IS_IPv4 ? 32 : 128))
         return NULL;
 
     /*****************************************************************
@@ -3481,16 +3502,45 @@ rta_multipath_done:;
             /* If no nexthops have been provided via RTA_MULTIPATH
              * we add it as regular nexthop to maintain backwards
              * compatibility */
-            nh.ifindex = ifindex;
-            nh.gateway = gateway;
+            nh.ifindex    = ifindex;
+            nh.gateway    = gateway;
+            nh.is_present = TRUE;
         } else {
             /* Kernel supports new style nexthop configuration,
              * verify that it is a duplicate and ignore old-style nexthop. */
             if (nh.ifindex != ifindex || memcmp(&nh.gateway, &gateway, addr_len) != 0)
                 return NULL;
         }
-    } else if (!nh.is_present)
-        return NULL;
+    }
+
+    if (nm_platform_route_type_is_nodev(rtm->rtm_type)) {
+        /* These routes are special. They don't have an device/ifindex.
+         *
+         * Well, actually, for IPv6 kernel will always say that the device is
+         * 1 (lo). Of course it does!! */
+        if (nh.is_present) {
+            if (IS_IPv4) {
+                if (nh.ifindex != 0 || nh.gateway.addr4 != 0) {
+                    /* we only accept kernel to notify about the ifindex/gateway, if it
+                     * is zero. This is only to be a bit forgiving, but we really don't
+                     * know how to handle such routes that have an ifindex. */
+                    return NULL;
+                }
+            } else {
+                if (!NM_IN_SET(nh.ifindex, 0, 1) || !IN6_IS_ADDR_UNSPECIFIED(&nh.gateway.addr6)) {
+                    /* We allow an ifindex of 1 (will be normalized to zero). Otherwise,
+                     * we don't expect a device/next hop. */
+                    return NULL;
+                }
+                nh.ifindex = 0;
+            }
+        }
+    } else {
+        if (!nh.is_present) {
+            /* a "normal" route needs a device. This is not the route we are looking for. */
+            return NULL;
+        }
+    }
 
     /*****************************************************************/
 
@@ -3528,9 +3578,8 @@ rta_multipath_done:;
 
     /*****************************************************************/
 
-    obj = nmp_object_new(is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
+    obj = nmp_object_new(IS_IPv4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
 
-    obj->ip_route.is_external   = TRUE;
     obj->ip_route.type_coerced  = nm_platform_route_type_coerce(rtm->rtm_type);
     obj->ip_route.table_coerced = nm_platform_route_table_coerce(
         tb[RTA_TABLE] ? nla_get_u32(tb[RTA_TABLE]) : (guint32) rtm->rtm_table);
@@ -3545,22 +3594,22 @@ rta_multipath_done:;
     if (tb[RTA_PRIORITY])
         obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]);
 
-    if (is_v4)
+    if (IS_IPv4)
         obj->ip4_route.gateway = nh.gateway.addr4;
     else
         obj->ip6_route.gateway = nh.gateway.addr6;
 
-    if (is_v4)
+    if (IS_IPv4)
         obj->ip4_route.scope_inv = nm_platform_route_scope_inv(rtm->rtm_scope);
 
     if (_check_addr_or_return_null(tb, RTA_PREFSRC, addr_len)) {
-        if (is_v4)
+        if (IS_IPv4)
             memcpy(&obj->ip4_route.pref_src, nla_data(tb[RTA_PREFSRC]), addr_len);
         else
             memcpy(&obj->ip6_route.pref_src, nla_data(tb[RTA_PREFSRC]), addr_len);
     }
 
-    if (is_v4)
+    if (IS_IPv4)
         obj->ip4_route.tos = rtm->rtm_tos;
     else {
         if (tb[RTA_SRC]) {
@@ -3582,7 +3631,7 @@ rta_multipath_done:;
     obj->ip_route.lock_initrwnd = NM_FLAGS_HAS(lock, 1 << RTAX_INITRWND);
     obj->ip_route.lock_mtu      = NM_FLAGS_HAS(lock, 1 << RTAX_MTU);
 
-    if (!is_v4) {
+    if (!IS_IPv4) {
         if (tb[RTA_PREF])
             obj->ip6_route.rt_pref = nla_get_u8(tb[RTA_PREF]);
     }
@@ -3682,12 +3731,12 @@ _new_from_nl_routing_rule(struct nlmsghdr *nlh, gboolean id_only)
                 .maxlen = sizeof(NMFibRulePortRange),
             },
     };
-    struct nlattr *            tb[G_N_ELEMENTS(policy)];
+    struct nlattr             *tb[G_N_ELEMENTS(policy)];
     const struct fib_rule_hdr *frh;
-    NMPlatformRoutingRule *    props;
-    nm_auto_nmpobj NMPObject *obj = NULL;
-    int                       addr_family;
-    guint8                    addr_size;
+    NMPlatformRoutingRule     *props;
+    nm_auto_nmpobj NMPObject  *obj = NULL;
+    int                        addr_family;
+    guint8                     addr_size;
 
     if (nlmsg_parse_arr(nlh, sizeof(*frh), tb, policy) < 0)
         return NULL;
@@ -3876,8 +3925,8 @@ _new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only)
         [TCA_KIND]    = {.type = NLA_STRING},
         [TCA_OPTIONS] = {.type = NLA_NESTED},
     };
-    struct nlattr *     tb[G_N_ELEMENTS(policy)];
-    const struct tcmsg *tcm;
+    struct nlattr            *tb[G_N_ELEMENTS(policy)];
+    const struct tcmsg       *tcm;
     nm_auto_nmpobj NMPObject *obj = NULL;
 
     if (!nm_platform_get_cache_tc(platform))
@@ -3926,7 +3975,7 @@ _new_from_nl_qdisc(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_only)
                 [TCA_TBF_PARMS]  = {.minlen = sizeof(struct tc_tbf_qopt)},
                 [TCA_TBF_RATE64] = {.type = NLA_U64},
             };
-            struct nlattr *    tbf_tb[G_N_ELEMENTS(tbf_policy)];
+            struct nlattr     *tbf_tb[G_N_ELEMENTS(tbf_policy)];
             struct tc_tbf_qopt opt;
 
             if (nla_parse_nested_arr(tbf_tb, tb[TCA_OPTIONS], tbf_policy) < 0)
@@ -3988,8 +4037,8 @@ _new_from_nl_tfilter(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_onl
     static const struct nla_policy policy[] = {
         [TCA_KIND] = {.type = NLA_STRING},
     };
-    struct nlattr *     tb[G_N_ELEMENTS(policy)];
-    NMPObject *         obj = NULL;
+    struct nlattr      *tb[G_N_ELEMENTS(policy)];
+    NMPObject          *obj = NULL;
     const struct tcmsg *tcm;
 
     if (!nm_platform_get_cache_tc(platform))
@@ -4028,9 +4077,9 @@ _new_from_nl_tfilter(NMPlatform *platform, struct nlmsghdr *nlh, gboolean id_onl
  * Returns: %NULL or a newly created NMPObject instance.
  **/
 static NMPObject *
-nmp_object_new_from_nl(NMPlatform *    platform,
+nmp_object_new_from_nl(NMPlatform     *platform,
                        const NMPCache *cache,
-                       struct nl_msg * msg,
+                       struct nl_msg  *msg,
                        gboolean        id_only)
 {
     struct nlmsghdr *msghdr;
@@ -4113,7 +4162,7 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo
 {
     struct nlattr *info;
     struct nlattr *data = NULL;
-    const char *   kind;
+    const char    *kind;
 
     nm_assert(msg);
 
@@ -4242,9 +4291,9 @@ _nl_msg_new_link_set_linkinfo(struct nl_msg *msg, NMLinkType link_type, gconstpo
     }
     case NM_LINK_TYPE_VETH:
     {
-        const char *           veth_peer = extra_data;
+        const char            *veth_peer = extra_data;
         const struct ifinfomsg ifi       = {};
-        struct nlattr *        info_peer;
+        struct nlattr         *info_peer;
 
         nm_assert(veth_peer);
 
@@ -4438,7 +4487,7 @@ nla_put_failure:
 }
 
 static gboolean
-_nl_msg_new_link_set_linkinfo_vlan(struct nl_msg *         msg,
+_nl_msg_new_link_set_linkinfo_vlan(struct nl_msg          *msg,
                                    int                     vlan_id,
                                    guint32                 flags_mask,
                                    guint32                 flags_set,
@@ -4559,10 +4608,10 @@ _nl_msg_new_link_full(int         nlmsg_type,
 {
     nm_auto_nlmsg struct nl_msg *msg = NULL;
     const struct ifinfomsg       ifi = {
-        .ifi_family = family,
-        .ifi_change = flags_mask,
-        .ifi_flags  = flags_set,
-        .ifi_index  = ifindex,
+              .ifi_family = family,
+              .ifi_change = flags_mask,
+              .ifi_flags  = flags_set,
+              .ifi_index  = ifindex,
     };
 
     nm_assert(NM_IN_SET(nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK, RTM_SETLINK));
@@ -4601,14 +4650,14 @@ _nl_msg_new_address(int           nlmsg_type,
                     guint32       lifetime,
                     guint32       preferred,
                     in_addr_t     ip4_broadcast_address,
-                    const char *  label)
+                    const char   *label)
 {
     nm_auto_nlmsg struct nl_msg *msg = NULL;
     struct ifaddrmsg             am  = {
-        .ifa_family    = family,
-        .ifa_index     = ifindex,
-        .ifa_prefixlen = plen,
-        .ifa_flags     = flags,
+                     .ifa_family    = family,
+                     .ifa_index     = ifindex,
+                     .ifa_prefixlen = plen,
+                     .ifa_flags     = flags,
     };
     gsize addr_len;
 
@@ -4680,27 +4729,48 @@ ip_route_get_lock_flag(const NMPlatformIPRoute *route)
            | (((guint32) route->lock_mtu) << RTAX_MTU);
 }
 
+static gboolean
+ip_route_ignored_protocol(const NMPlatformIPRoute *route)
+{
+    guint8 prot;
+
+    nm_assert(route);
+    nm_assert(route->rt_source >= NM_IP_CONFIG_SOURCE_RTPROT_UNSPEC
+              && route->rt_source <= _NM_IP_CONFIG_SOURCE_RTPROT_LAST);
+
+    prot = route->rt_source - 1;
+
+    nm_assert(nmp_utils_ip_config_source_from_rtprot(prot) == route->rt_source);
+
+    /* We ignore all routes outside a certain subest of rtm_protocol. NetworkManager
+     * itself wouldn't configure those, so they are always configured by somebody
+     * external. We thus ignore them to avoid the overhead that processing them brings.
+     * For example, the BGP daemon "bird"  might configure a huge number of RTPROT_BIRD routes. */
+
+    return prot > RTPROT_STATIC && !NM_IN_SET(prot, RTPROT_DHCP, RTPROT_RA);
+}
+
 /* Copied and modified from libnl3's build_route_msg() and rtnl_route_build_msg(). */
 static struct nl_msg *
 _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj)
 {
-    nm_auto_nlmsg struct nl_msg *msg   = NULL;
-    const NMPClass *             klass = NMP_OBJECT_GET_CLASS(obj);
-    gboolean                     is_v4 = klass->addr_family == AF_INET;
-    const guint32                lock  = ip_route_get_lock_flag(NMP_OBJECT_CAST_IP_ROUTE(obj));
+    nm_auto_nlmsg struct nl_msg *msg     = NULL;
+    const NMPClass              *klass   = NMP_OBJECT_GET_CLASS(obj);
+    const gboolean               IS_IPv4 = NM_IS_IPv4(klass->addr_family);
+    const guint32                lock    = ip_route_get_lock_flag(NMP_OBJECT_CAST_IP_ROUTE(obj));
     const guint32                table =
         nm_platform_route_table_uncoerce(NMP_OBJECT_CAST_IP_ROUTE(obj)->table_coerced, TRUE);
     const struct rtmsg rtmsg = {
         .rtm_family   = klass->addr_family,
-        .rtm_tos      = is_v4 ? obj->ip4_route.tos : 0,
+        .rtm_tos      = IS_IPv4 ? obj->ip4_route.tos : 0,
         .rtm_table    = table <= 0xFF ? table : RT_TABLE_UNSPEC,
         .rtm_protocol = nmp_utils_ip_config_source_coerce_to_rtprot(obj->ip_route.rt_source),
         .rtm_scope =
-            is_v4 ? nm_platform_route_scope_inv(obj->ip4_route.scope_inv) : RT_SCOPE_NOWHERE,
+            IS_IPv4 ? nm_platform_route_scope_inv(obj->ip4_route.scope_inv) : RT_SCOPE_NOWHERE,
         .rtm_type    = nm_platform_route_type_uncoerce(NMP_OBJECT_CAST_IP_ROUTE(obj)->type_coerced),
         .rtm_flags   = obj->ip_route.r_rtm_flags & ((unsigned) (RTNH_F_ONLINK)),
         .rtm_dst_len = obj->ip_route.plen,
-        .rtm_src_len = is_v4 ? 0 : NMP_OBJECT_CAST_IP6_ROUTE(obj)->src_plen,
+        .rtm_src_len = IS_IPv4 ? 0 : NMP_OBJECT_CAST_IP6_ROUTE(obj)->src_plen,
     };
 
     gsize addr_len;
@@ -4714,28 +4784,28 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj)
     if (nlmsg_append_struct(msg, &rtmsg) < 0)
         goto nla_put_failure;
 
-    addr_len = is_v4 ? sizeof(in_addr_t) : sizeof(struct in6_addr);
+    addr_len = IS_IPv4 ? sizeof(in_addr_t) : sizeof(struct in6_addr);
 
     NLA_PUT(msg,
             RTA_DST,
             addr_len,
-            is_v4 ? (gconstpointer) &obj->ip4_route.network
-                  : (gconstpointer) &obj->ip6_route.network);
+            IS_IPv4 ? (gconstpointer) &obj->ip4_route.network
+                    : (gconstpointer) &obj->ip6_route.network);
 
-    if (!is_v4) {
+    if (!IS_IPv4) {
         if (!IN6_IS_ADDR_UNSPECIFIED(&NMP_OBJECT_CAST_IP6_ROUTE(obj)->src))
             NLA_PUT(msg, RTA_SRC, addr_len, &obj->ip6_route.src);
     }
 
     NLA_PUT_U32(msg,
                 RTA_PRIORITY,
-                is_v4 ? nm_platform_ip4_route_get_effective_metric(&obj->ip4_route)
-                      : nm_platform_ip6_route_get_effective_metric(&obj->ip6_route));
+                IS_IPv4 ? nm_platform_ip4_route_get_effective_metric(&obj->ip4_route)
+                        : nm_platform_ip6_route_get_effective_metric(&obj->ip6_route));
 
     if (table > 0xFF)
         NLA_PUT_U32(msg, RTA_TABLE, table);
 
-    if (is_v4) {
+    if (IS_IPv4) {
         if (NMP_OBJECT_CAST_IP4_ROUTE(obj)->pref_src)
             NLA_PUT(msg, RTA_PREFSRC, addr_len, &obj->ip4_route.pref_src);
     } else {
@@ -4770,7 +4840,7 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj)
     }
 
     /* We currently don't have need for multi-hop routes... */
-    if (is_v4) {
+    if (IS_IPv4) {
         NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip4_route.gateway);
     } else {
         if (!IN6_IS_ADDR_UNSPECIFIED(&obj->ip6_route.gateway))
@@ -4778,7 +4848,7 @@ _nl_msg_new_route(int nlmsg_type, guint16 nlmsgflags, const NMPObject *obj)
     }
     NLA_PUT_U32(msg, RTA_OIF, obj->ip_route.ifindex);
 
-    if (!is_v4 && obj->ip6_route.rt_pref != NM_ICMPV6_ROUTER_PREF_MEDIUM)
+    if (!IS_IPv4 && obj->ip6_route.rt_pref != NM_ICMPV6_ROUTER_PREF_MEDIUM)
         NLA_PUT_U8(msg, RTA_PREF, obj->ip6_route.rt_pref);
 
     return g_steal_pointer(&msg);
@@ -4904,13 +4974,13 @@ static struct nl_msg *
 _nl_msg_new_qdisc(int nlmsg_type, int nlmsg_flags, const NMPlatformQdisc *qdisc)
 {
     nm_auto_nlmsg struct nl_msg *msg = NULL;
-    struct nlattr *              tc_options;
+    struct nlattr               *tc_options;
     const struct tcmsg           tcm = {
-        .tcm_family  = qdisc->addr_family,
-        .tcm_ifindex = qdisc->ifindex,
-        .tcm_handle  = qdisc->handle,
-        .tcm_parent  = qdisc->parent,
-        .tcm_info    = qdisc->info,
+                  .tcm_family  = qdisc->addr_family,
+                  .tcm_ifindex = qdisc->ifindex,
+                  .tcm_handle  = qdisc->handle,
+                  .tcm_parent  = qdisc->parent,
+                  .tcm_info    = qdisc->info,
     };
 
     msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags | NMP_NLM_FLAG_F_ECHO);
@@ -4991,14 +5061,14 @@ static struct nl_msg *
 _nl_msg_new_tfilter(int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tfilter)
 {
     nm_auto_nlmsg struct nl_msg *msg = NULL;
-    struct nlattr *              tc_options;
-    struct nlattr *              act_tab;
+    struct nlattr               *tc_options;
+    struct nlattr               *act_tab;
     const struct tcmsg           tcm = {
-        .tcm_family  = tfilter->addr_family,
-        .tcm_ifindex = tfilter->ifindex,
-        .tcm_handle  = tfilter->handle,
-        .tcm_parent  = tfilter->parent,
-        .tcm_info    = tfilter->info,
+                  .tcm_family  = tfilter->addr_family,
+                  .tcm_ifindex = tfilter->ifindex,
+                  .tcm_handle  = tfilter->handle,
+                  .tcm_parent  = tfilter->parent,
+                  .tcm_info    = tfilter->info,
     };
 
     msg = nlmsg_alloc_simple(nlmsg_type, nlmsg_flags | NMP_NLM_FLAG_F_ECHO);
@@ -5016,8 +5086,8 @@ _nl_msg_new_tfilter(int nlmsg_type, int nlmsg_flags, const NMPlatformTfilter *tf
 
     if (tfilter->action.kind) {
         const NMPlatformAction *action = &tfilter->action;
-        struct nlattr *         prio;
-        struct nlattr *         act_options;
+        struct nlattr          *prio;
+        struct nlattr          *act_options;
 
         if (!(prio = nla_nest_start(msg, 1 /* priority */)))
             goto nla_put_failure;
@@ -5121,7 +5191,7 @@ _log_dbg_sysctl_set_impl(NMPlatform *platform,
                          const char *path,
                          const char *value)
 {
-    GError *      error         = NULL;
+    GError       *error         = NULL;
     gs_free char *contents      = NULL;
     gs_free char *value_escaped = g_strescape(value, NULL);
 
@@ -5175,7 +5245,7 @@ sysctl_set_internal(NMPlatform *platform,
     int           fd, tries;
     gssize        nwrote;
     gssize        len;
-    char *        actual;
+    char         *actual;
     gs_free char *actual_free = NULL;
     int           errsv;
 
@@ -5314,12 +5384,12 @@ sysctl_set(NMPlatform *platform, const char *pathid, int dirfd, const char *path
 }
 
 typedef struct {
-    NMPlatform *            platform;
-    char *                  pathid;
+    NMPlatform             *platform;
+    char                   *pathid;
     int                     dirfd;
-    char *                  path;
-    char **                 values;
-    GCancellable *          cancellable;
+    char                   *path;
+    char                  **values;
+    GCancellable           *cancellable;
     NMPlatformAsyncCallback callback;
     gpointer                callback_data;
 } SysctlAsyncInfo;
@@ -5340,11 +5410,11 @@ sysctl_async_info_free(SysctlAsyncInfo *info)
 static void
 sysctl_async_cb(GObject *object, GAsyncResult *res, gpointer user_data)
 {
-    NMPlatform *     platform;
-    GTask *          task = G_TASK(res);
-    SysctlAsyncInfo *info;
+    NMPlatform           *platform;
+    GTask                *task = G_TASK(res);
+    SysctlAsyncInfo      *info;
     gs_free_error GError *error      = NULL;
-    gs_free char *        values_str = NULL;
+    gs_free char         *values_str = NULL;
 
     info = g_task_get_task_data(task);
 
@@ -5360,15 +5430,15 @@ sysctl_async_cb(GObject *object, GAsyncResult *res, gpointer user_data)
 }
 
 static void
-sysctl_async_thread_fn(GTask *       task,
+sysctl_async_thread_fn(GTask        *task,
                        gpointer      source_object,
                        gpointer      task_data,
                        GCancellable *cancellable)
 {
     nm_auto_pop_netns NMPNetns *netns = NULL;
-    SysctlAsyncInfo *           info  = task_data;
-    GError *                    error = NULL;
-    char **                     value;
+    SysctlAsyncInfo            *info  = task_data;
+    GError                     *error = NULL;
+    char                      **value;
 
     if (g_task_return_error_if_cancelled(task))
         return;
@@ -5403,11 +5473,11 @@ sysctl_async_thread_fn(GTask *       task,
 static void
 sysctl_set_async_return_idle(gpointer user_data, GCancellable *cancellable)
 {
-    gs_unref_object NMPlatform *platform  = NULL;
-    gs_free_error GError *cancelled_error = NULL;
-    gs_free_error GError *  error         = NULL;
-    NMPlatformAsyncCallback callback;
-    gpointer                callback_data;
+    gs_unref_object NMPlatform *platform        = NULL;
+    gs_free_error GError       *cancelled_error = NULL;
+    gs_free_error GError       *error           = NULL;
+    NMPlatformAsyncCallback     callback;
+    gpointer                    callback_data;
 
     nm_utils_user_data_unpack(user_data, &platform, &callback, &callback_data, &error);
     g_cancellable_set_error_if_cancelled(cancellable, &cancelled_error);
@@ -5415,20 +5485,20 @@ sysctl_set_async_return_idle(gpointer user_data, GCancellable *cancellable)
 }
 
 static void
-sysctl_set_async(NMPlatform *            platform,
-                 const char *            pathid,
+sysctl_set_async(NMPlatform             *platform,
+                 const char             *pathid,
                  int                     dirfd,
-                 const char *            path,
-                 const char *const *     values,
+                 const char             *path,
+                 const char *const      *values,
                  NMPlatformAsyncCallback callback,
                  gpointer                data,
-                 GCancellable *          cancellable)
+                 GCancellable           *cancellable)
 {
     SysctlAsyncInfo *info;
-    GTask *          task;
+    GTask           *task;
     int              dirfd_dup, errsv;
     gpointer         packed;
-    GError *         error = NULL;
+    GError          *error = NULL;
 
     g_return_if_fail(platform);
     g_return_if_fail(path);
@@ -5501,7 +5571,7 @@ _nm_logging_clear_platform_logging_cache(void)
 typedef struct {
     const char *path;
     CList       lst;
-    char *      value;
+    char       *value;
     char        path_data[];
 } SysctlCacheEntry;
 
@@ -5539,7 +5609,7 @@ _log_dbg_sysctl_get_impl(NMPlatform *platform, const char *pathid, const char *c
      **/
     NM_G_MUTEX_LOCKED(&sysctl_clear_cache_lock);
     NMLinuxPlatformPrivate *priv  = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
-    SysctlCacheEntry *      entry = NULL;
+    SysctlCacheEntry       *entry = NULL;
 
     if (!priv->sysctl_get_prev_values) {
         c_list_link_tail(&sysctl_clear_cache_lst_head, &priv->sysctl_clear_cache_lst);
@@ -5567,7 +5637,7 @@ _log_dbg_sysctl_get_impl(NMPlatform *platform, const char *pathid, const char *c
 
         nm_c_list_move_front(&priv->sysctl_list, &entry->lst);
     } else {
-        gs_free char *    contents_escaped = g_strescape(contents, NULL);
+        gs_free char     *contents_escaped = g_strescape(contents, NULL);
         SysctlCacheEntry *old;
         size_t            len;
 
@@ -5602,8 +5672,8 @@ static char *
 sysctl_get(NMPlatform *platform, const char *pathid, int dirfd, const char *path)
 {
     nm_auto_pop_netns NMPNetns *netns    = NULL;
-    GError *                    error    = NULL;
-    gs_free char *              contents = NULL;
+    GError                     *error    = NULL;
+    gs_free char               *contents = NULL;
 
     ASSERT_SYSCTL_ARGS(pathid, dirfd, path);
 
@@ -5813,10 +5883,10 @@ static NM_UTILS_LOOKUP_STR_DEFINE(
 static const char *
 delayed_action_to_string_full(DelayedActionType action_type,
                               gpointer          user_data,
-                              char *            buf,
+                              char             *buf,
                               gsize             buf_size)
 {
-    char *                                    buf0 = buf;
+    char                                     *buf0 = buf;
     const DelayedActionWaitForNlResponseData *data;
 
     nm_strbuf_append_str(&buf, &buf_size, delayed_action_to_string(action_type));
@@ -5831,7 +5901,7 @@ delayed_action_to_string_full(DelayedActionType action_type,
         data = user_data;
 
         if (data) {
-            gint64 timeout = data->timeout_abs_ns - nm_utils_get_monotonic_timestamp_nsec();
+            gint64 timeout = data->timeout_abs_nsec - nm_utils_get_monotonic_timestamp_nsec();
             char   b[255];
 
             nm_strbuf_append(
@@ -5889,11 +5959,11 @@ delayed_action_refresh_all_in_progress(NMPlatform *platform, DelayedActionType a
 }
 
 static void
-delayed_action_wait_for_nl_response_complete(NMPlatform *            platform,
+delayed_action_wait_for_nl_response_complete(NMPlatform             *platform,
                                              guint                   idx,
                                              WaitForNlResponseResult seq_result)
 {
-    NMLinuxPlatformPrivate *            priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+    NMLinuxPlatformPrivate             *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     DelayedActionWaitForNlResponseData *data;
 
     nm_assert(NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE));
@@ -5932,17 +6002,17 @@ delayed_action_wait_for_nl_response_complete(NMPlatform *            platform,
 }
 
 static void
-delayed_action_wait_for_nl_response_complete_check(NMPlatform *            platform,
+delayed_action_wait_for_nl_response_complete_check(NMPlatform             *platform,
                                                    WaitForNlResponseResult force_result,
-                                                   guint32 *               out_next_seq_number,
-                                                   gint64 *                out_next_timeout_abs_ns,
-                                                   gint64 *                p_now_ns)
+                                                   guint32                *out_next_seq_number,
+                                                   gint64                 *out_next_timeout_abs_ns,
+                                                   gint64                 *p_now_nsec)
 {
     NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     guint                   i;
     guint32                 next_seq_number     = 0;
     gint64                  next_timeout_abs_ns = 0;
-    gint64                  now_ns              = 0;
+    gint64                  now_nsec            = 0;
 
     for (i = 0; i < priv->delayed_action.list_wait_for_nl_response->len;) {
         const DelayedActionWaitForNlResponseData *data =
@@ -5952,10 +6022,10 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *            platf
 
         if (data->seq_result)
             delayed_action_wait_for_nl_response_complete(platform, i, data->seq_result);
-        else if (p_now_ns
-                 && ((now_ns ?: (now_ns = nm_utils_get_monotonic_timestamp_nsec()))
-                     >= data->timeout_abs_ns)) {
-            /* the caller can optionally check for timeout by providing a p_now_ns argument. */
+        else if (p_now_nsec
+                 && ((now_nsec ?: (now_nsec = nm_utils_get_monotonic_timestamp_nsec()))
+                     >= data->timeout_abs_nsec)) {
+            /* the caller can optionally check for timeout by providing a p_now_nsec argument. */
             delayed_action_wait_for_nl_response_complete(
                 platform,
                 i,
@@ -5963,9 +6033,9 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *            platf
         } else if (force_result != WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN)
             delayed_action_wait_for_nl_response_complete(platform, i, force_result);
         else {
-            if (next_seq_number == 0 || next_timeout_abs_ns > data->timeout_abs_ns) {
+            if (next_seq_number == 0 || next_timeout_abs_ns > data->timeout_abs_nsec) {
                 next_seq_number     = data->seq_number;
-                next_timeout_abs_ns = data->timeout_abs_ns;
+                next_timeout_abs_ns = data->timeout_abs_nsec;
             }
             i++;
         }
@@ -5979,11 +6049,11 @@ delayed_action_wait_for_nl_response_complete_check(NMPlatform *            platf
 
     NM_SET_OUT(out_next_seq_number, next_seq_number);
     NM_SET_OUT(out_next_timeout_abs_ns, next_timeout_abs_ns);
-    NM_SET_OUT(p_now_ns, now_ns);
+    NM_SET_OUT(p_now_nsec, now_nsec);
 }
 
 static void
-delayed_action_wait_for_nl_response_complete_all(NMPlatform *            platform,
+delayed_action_wait_for_nl_response_complete_all(NMPlatform             *platform,
                                                  WaitForNlResponseResult fallback_result)
 {
     delayed_action_wait_for_nl_response_complete_check(platform, fallback_result, NULL, NULL, NULL);
@@ -6080,8 +6150,8 @@ delayed_action_handle_one(NMPlatform *platform)
         priv->delayed_action.flags &= ~DELAYED_ACTION_TYPE_REFRESH_ALL;
 
         if (_LOGt_ENABLED()) {
-            FOR_EACH_DELAYED_ACTION(iflags, flags)
-            _LOGt_delayed_action(iflags, NULL, "handle");
+            FOR_EACH_DELAYED_ACTION (iflags, flags)
+                _LOGt_delayed_action(iflags, NULL, "handle");
         }
 
         delayed_action_handle_REFRESH_ALL(platform, flags);
@@ -6177,22 +6247,22 @@ delayed_action_schedule(NMPlatform *platform, DelayedActionType action_type, gpo
     priv->delayed_action.flags |= action_type;
 
     if (_LOGt_ENABLED()) {
-        FOR_EACH_DELAYED_ACTION(iflags, action_type)
-        _LOGt_delayed_action(iflags, user_data, "schedule");
+        FOR_EACH_DELAYED_ACTION (iflags, action_type)
+            _LOGt_delayed_action(iflags, user_data, "schedule");
     }
 }
 
 static void
-delayed_action_schedule_WAIT_FOR_NL_RESPONSE(NMPlatform *                       platform,
+delayed_action_schedule_WAIT_FOR_NL_RESPONSE(NMPlatform                        *platform,
                                              guint32                            seq_number,
-                                             WaitForNlResponseResult *          out_seq_result,
-                                             char **                            out_errmsg,
+                                             WaitForNlResponseResult           *out_seq_result,
+                                             char                             **out_errmsg,
                                              DelayedActionWaitForNlResponseType response_type,
                                              gpointer                           response_out_data)
 {
     DelayedActionWaitForNlResponseData data = {
         .seq_number = seq_number,
-        .timeout_abs_ns =
+        .timeout_abs_nsec =
             nm_utils_get_monotonic_timestamp_nsec() + (200 * (NM_UTILS_NSEC_PER_SEC / 1000)),
         .out_seq_result    = out_seq_result,
         .out_errmsg        = out_errmsg,
@@ -6211,7 +6281,7 @@ cache_prune_one_type(NMPlatform *platform, const NMPLookup *lookup)
     NMDedupMultiIter iter;
     const NMPObject *obj;
     NMPCacheOpsType  cache_op;
-    NMPCache *       cache = nm_platform_get_cache(platform);
+    NMPCache        *cache = nm_platform_get_cache(platform);
 
     nm_dedup_multi_iter_init(&iter, nmp_cache_lookup(cache, lookup));
     while (nm_dedup_multi_iter_next(&iter)) {
@@ -6260,7 +6330,7 @@ cache_prune_all(NMPlatform *platform)
 }
 
 static void
-cache_on_change(NMPlatform *     platform,
+cache_on_change(NMPlatform      *platform,
                 NMPCacheOpsType  cache_op,
                 const NMPObject *obj_old,
                 const NMPObject *obj_new)
@@ -6268,7 +6338,7 @@ cache_on_change(NMPlatform *     platform,
     const NMPClass *klass;
     char            str_buf[sizeof(_nm_utils_to_string_buffer)];
     char            str_buf2[sizeof(_nm_utils_to_string_buffer)];
-    NMPCache *      cache = nm_platform_get_cache(platform);
+    NMPCache       *cache = nm_platform_get_cache(platform);
 
     ASSERT_nmp_cache_ops(cache, cache_op, obj_old, obj_new);
     nm_assert(cache_op != NMP_CACHE_OPS_UNCHANGED);
@@ -6531,10 +6601,10 @@ _nlh_seq_next_get(NMLinuxPlatformPrivate *priv)
  * Returns: 0 on success or a negative errno.
  */
 static int
-_nl_send_nlmsghdr(NMPlatform *                       platform,
-                  struct nlmsghdr *                  nlhdr,
-                  WaitForNlResponseResult *          out_seq_result,
-                  char **                            out_errmsg,
+_nl_send_nlmsghdr(NMPlatform                        *platform,
+                  struct nlmsghdr                   *nlhdr,
+                  WaitForNlResponseResult           *out_seq_result,
+                  char                             **out_errmsg,
                   DelayedActionWaitForNlResponseType response_type,
                   gpointer                           response_out_data)
 {
@@ -6598,15 +6668,15 @@ again:
  * Returns: 0 on success, or a negative libnl3 error code (beware, it's not an errno).
  */
 static int
-_nl_send_nlmsg(NMPlatform *                       platform,
-               struct nl_msg *                    nlmsg,
-               WaitForNlResponseResult *          out_seq_result,
-               char **                            out_errmsg,
+_nl_send_nlmsg(NMPlatform                        *platform,
+               struct nl_msg                     *nlmsg,
+               WaitForNlResponseResult           *out_seq_result,
+               char                             **out_errmsg,
                DelayedActionWaitForNlResponseType response_type,
                gpointer                           response_out_data)
 {
     NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
-    struct nlmsghdr *       nlhdr;
+    struct nlmsghdr        *nlhdr;
     guint32                 seq;
     int                     nle;
 
@@ -6632,7 +6702,7 @@ _nl_send_nlmsg(NMPlatform *                       platform,
 static void
 do_request_link_no_delayed_actions(NMPlatform *platform, int ifindex, const char *name)
 {
-    NMLinuxPlatformPrivate *     priv  = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+    NMLinuxPlatformPrivate      *priv  = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
     int                          nle;
 
@@ -6680,7 +6750,7 @@ static struct nl_msg *
 _nl_msg_new_dump(NMPObjectType obj_type, int preferred_addr_family)
 {
     nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
-    const NMPClass *             klass;
+    const NMPClass              *klass;
 
     klass = nmp_class_from_type(obj_type);
 
@@ -6753,8 +6823,7 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action
         action_type_prune &= ~DELAYED_ACTION_TYPE_REFRESH_ALL_ROUTING_RULES_ALL;
     }
 
-    FOR_EACH_DELAYED_ACTION(iflags, action_type_prune)
-    {
+    FOR_EACH_DELAYED_ACTION (iflags, action_type_prune) {
         RefreshAllType refresh_all_type = delayed_action_type_to_refresh_all_type(iflags);
         NMPLookup      lookup;
 
@@ -6763,12 +6832,11 @@ do_request_all_no_delayed_actions(NMPlatform *platform, DelayedActionType action
         nmp_cache_dirty_set_all_main(nm_platform_get_cache(platform), &lookup);
     }
 
-    FOR_EACH_DELAYED_ACTION(iflags, action_type)
-    {
+    FOR_EACH_DELAYED_ACTION (iflags, action_type) {
         RefreshAllType        refresh_all_type = delayed_action_type_to_refresh_all_type(iflags);
         const RefreshAllInfo *refresh_all_info = refresh_all_type_get_info(refresh_all_type);
         nm_auto_nlmsg struct nl_msg *nlmsg     = NULL;
-        int *                        out_refresh_all_in_progress;
+        int                         *out_refresh_all_in_progress;
 
         out_refresh_all_in_progress =
             &priv->delayed_action.refresh_all_in_progress[refresh_all_type];
@@ -6826,7 +6894,7 @@ do_request_one_type_by_needle_object(NMPlatform *platform, const NMPObject *obj_
 static void
 event_seq_check_refresh_all(NMPlatform *platform, guint32 seq_number)
 {
-    NMLinuxPlatformPrivate *            priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+    NMLinuxPlatformPrivate             *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     DelayedActionWaitForNlResponseData *data;
     guint                               i;
 
@@ -6855,12 +6923,12 @@ event_seq_check_refresh_all(NMPlatform *platform, guint32 seq_number)
 }
 
 static void
-event_seq_check(NMPlatform *            platform,
+event_seq_check(NMPlatform             *platform,
                 guint32                 seq_number,
                 WaitForNlResponseResult seq_result,
-                const char *            msg)
+                const char             *msg)
 {
-    NMLinuxPlatformPrivate *            priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+    NMLinuxPlatformPrivate             *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     DelayedActionWaitForNlResponseData *data;
     guint                               i;
 
@@ -6901,14 +6969,14 @@ event_seq_check(NMPlatform *            platform,
 static void
 event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events)
 {
-    NMLinuxPlatformPrivate *priv;
+    NMLinuxPlatformPrivate   *priv;
     nm_auto_nmpobj NMPObject *obj = NULL;
     NMPCacheOpsType           cache_op;
-    struct nlmsghdr *         msghdr;
+    struct nlmsghdr          *msghdr;
     char                      buf_nlmsghdr[400];
     gboolean                  is_del  = FALSE;
     gboolean                  is_dump = FALSE;
-    NMPCache *                cache   = nm_platform_get_cache(platform);
+    NMPCache                 *cache   = nm_platform_get_cache(platform);
 
     msghdr = nlmsg_hdr(msg);
 
@@ -7010,6 +7078,17 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events
                 }
             }
 
+            if (ip_route_ignored_protocol(NMP_OBJECT_CAST_IP_ROUTE(obj))) {
+                /* We ignore certain rtm_protocol, because NetworkManager would only ever
+                 * configure certain protocols. Other routes were not added by NetworkManager
+                 * and we don't need to track them in the platform cache.
+                 *
+                 * This is to help with the performance overhead of a huge number of
+                 * routes, for example with the bird BGP software, that adds routes
+                 * with RTPROT_BIRD protocol. */
+                return;
+            }
+
             cache_op = nmp_cache_update_netlink_route(cache,
                                                       obj,
                                                       is_dump,
@@ -7085,18 +7164,18 @@ event_valid_msg(NMPlatform *platform, struct nl_msg *msg, gboolean handle_events
 /*****************************************************************************/
 
 static int
-do_add_link_with_lookup(NMPlatform *           platform,
+do_add_link_with_lookup(NMPlatform            *platform,
                         NMLinkType             link_type,
-                        const char *           name,
-                        struct nl_msg *        nlmsg,
+                        const char            *name,
+                        struct nl_msg         *nlmsg,
                         const NMPlatformLink **out_link)
 {
-    const NMPObject *       obj        = NULL;
+    const NMPObject        *obj        = NULL;
     WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
-    gs_free char *          errmsg     = NULL;
+    gs_free char           *errmsg     = NULL;
     int                     nle;
     char                    s_buf[256];
-    NMPCache *              cache = nm_platform_get_cache(platform);
+    NMPCache               *cache = nm_platform_get_cache(platform);
 
     event_handler_read_netlink(platform, FALSE);
 
@@ -7135,13 +7214,13 @@ do_add_link_with_lookup(NMPlatform *           platform,
 }
 
 static int
-do_add_addrroute(NMPlatform *     platform,
+do_add_addrroute(NMPlatform      *platform,
                  const NMPObject *obj_id,
-                 struct nl_msg *  nlmsg,
+                 struct nl_msg   *nlmsg,
                  gboolean         suppress_netlink_failure)
 {
     WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
-    gs_free char *          errmsg     = NULL;
+    gs_free char           *errmsg     = NULL;
     int                     nle;
     char                    s_buf[256];
 
@@ -7200,11 +7279,11 @@ static gboolean
 do_delete_object(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
 {
     WaitForNlResponseResult seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
-    gs_free char *          errmsg     = NULL;
+    gs_free char           *errmsg     = NULL;
     int                     nle;
     char                    s_buf[256];
     gboolean                success;
-    const char *            log_detail = "";
+    const char             *log_detail = "";
 
     event_handler_read_netlink(platform, FALSE);
 
@@ -7270,23 +7349,23 @@ do_delete_object(NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *n
 }
 
 static int
-do_change_link(NMPlatform *          platform,
+do_change_link(NMPlatform           *platform,
                ChangeLinkType        change_link_type,
                int                   ifindex,
-               struct nl_msg *       nlmsg,
+               struct nl_msg        *nlmsg,
                const ChangeLinkData *data)
 {
     nm_auto_pop_netns NMPNetns *netns = NULL;
     int                         nle;
     WaitForNlResponseResult     seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
-    gs_free char *              errmsg     = NULL;
+    gs_free char               *errmsg     = NULL;
     char                        s_buf[256];
     int                         result          = 0;
     NMLogLevel                  log_level       = LOGL_DEBUG;
-    const char *                log_result      = "failure";
-    const char *                log_detail      = "";
-    gs_free char *              log_detail_free = NULL;
-    const NMPObject *           obj_cache;
+    const char                 *log_result      = "failure";
+    const char                 *log_detail      = "";
+    gs_free char               *log_detail_free = NULL;
+    const NMPObject            *obj_cache;
 
     if (!nm_platform_netns_push(platform, &netns)) {
         log_level  = LOGL_ERR;
@@ -7368,11 +7447,11 @@ out:
 }
 
 static int
-link_add(NMPlatform *           platform,
+link_add(NMPlatform            *platform,
          NMLinkType             type,
-         const char *           name,
+         const char            *name,
          int                    parent,
-         const void *           address,
+         const void            *address,
          size_t                 address_len,
          guint32                mtu,
          gconstpointer          extra_data,
@@ -7418,7 +7497,7 @@ link_delete(NMPlatform *platform, int ifindex)
 {
     nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
     NMPObject                    obj_id;
-    const NMPObject *            obj;
+    const NMPObject             *obj;
 
     obj = nmp_cache_lookup_link(nm_platform_get_cache(platform), ifindex);
     if (!obj || !obj->_link.netlink.is_in_netlink)
@@ -7527,7 +7606,7 @@ static gboolean
 link_supports_vlans(NMPlatform *platform, int ifindex)
 {
     nm_auto_pop_netns NMPNetns *netns = NULL;
-    const NMPObject *           obj;
+    const NMPObject            *obj;
 
     obj = nm_platform_link_get_obj(platform, ifindex, TRUE);
 
@@ -7569,10 +7648,10 @@ link_set_address(NMPlatform *platform, int ifindex, gconstpointer address, size_
 {
     nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
     const ChangeLinkData         d     = {
-        .set_address =
+                    .set_address =
             {
-                .address = address,
-                .length  = length,
+                            .address = address,
+                            .length  = length,
             },
     };
 
@@ -7643,11 +7722,11 @@ nla_put_failure:
 static void
 sriov_idle_cb(gpointer user_data, GCancellable *cancellable)
 {
-    gs_unref_object NMPlatform *platform  = NULL;
-    gs_free_error GError *cancelled_error = NULL;
-    gs_free_error GError *  error         = NULL;
-    NMPlatformAsyncCallback callback;
-    gpointer                callback_data;
+    gs_unref_object NMPlatform *platform        = NULL;
+    gs_free_error GError       *cancelled_error = NULL;
+    gs_free_error GError       *error           = NULL;
+    NMPlatformAsyncCallback     callback;
+    gpointer                    callback_data;
 
     g_cancellable_set_error_if_cancelled(cancellable, &cancelled_error);
     nm_utils_user_data_unpack(user_data, &platform, &error, &callback, &callback_data);
@@ -7655,24 +7734,24 @@ sriov_idle_cb(gpointer user_data, GCancellable *cancellable)
 }
 
 static void
-link_set_sriov_params_async(NMPlatform *            platform,
+link_set_sriov_params_async(NMPlatform             *platform,
                             int                     ifindex,
                             guint                   num_vfs,
                             NMOptionBool            autoprobe,
                             NMPlatformAsyncCallback callback,
                             gpointer                data,
-                            GCancellable *          cancellable)
+                            GCancellable           *cancellable)
 {
     nm_auto_pop_netns NMPNetns *netns = NULL;
-    gs_free_error GError *error       = NULL;
-    nm_auto_close int     dirfd       = -1;
-    int                   current_autoprobe;
-    guint                 i, total;
-    gint64                current_num;
-    char                  ifname[IFNAMSIZ];
-    gpointer              packed;
-    const char *          values[3];
-    char                  buf[64];
+    gs_free_error GError       *error = NULL;
+    nm_auto_close int           dirfd = -1;
+    int                         current_autoprobe;
+    guint                       i, total;
+    gint64                      current_num;
+    char                        ifname[IFNAMSIZ];
+    gpointer                    packed;
+    const char                 *values[3];
+    char                        buf[64];
 
     g_return_if_fail(callback || !data);
     g_return_if_fail(cancellable);
@@ -7781,7 +7860,7 @@ static gboolean
 link_set_sriov_vfs(NMPlatform *platform, int ifindex, const NMPlatformVF *const *vfs)
 {
     nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
-    struct nlattr *              list, *info, *vlan_list;
+    struct nlattr               *list, *info, *vlan_list;
     guint                        i;
 
     nlmsg = _nl_msg_new_link(RTM_NEWLINK, 0, ifindex, NULL);
@@ -7868,13 +7947,13 @@ nla_put_failure:
 }
 
 static gboolean
-link_set_bridge_vlans(NMPlatform *                       platform,
+link_set_bridge_vlans(NMPlatform                        *platform,
                       int                                ifindex,
                       gboolean                           on_master,
                       const NMPlatformBridgeVlan *const *vlans)
 {
     nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
-    struct nlattr *              list;
+    struct nlattr               *list;
     struct bridge_vlan_info      vinfo = {};
     guint                        i;
 
@@ -7959,13 +8038,13 @@ link_get_dev_id(NMPlatform *platform, int ifindex)
 }
 
 static gboolean
-link_tun_add(NMPlatform *            platform,
-             const char *            name,
+link_tun_add(NMPlatform             *platform,
+             const char             *name,
              const NMPlatformLnkTun *props,
-             const NMPlatformLink ** out_link,
-             int *                   out_fd)
+             const NMPlatformLink  **out_link,
+             int                    *out_fd)
 {
-    const NMPObject * obj;
+    const NMPObject  *obj;
     struct ifreq      ifr = {};
     nm_auto_close int fd  = -1;
 
@@ -8023,8 +8102,8 @@ _vlan_change_vlan_qos_mapping_create(gboolean                is_ingress_map,
                                      guint                   current_n_map,
                                      const NMVlanQosMapping *set_map,
                                      guint                   set_n_map,
-                                     NMVlanQosMapping **     out_map,
-                                     guint *                 out_n_map)
+                                     NMVlanQosMapping      **out_map,
+                                     guint                  *out_n_map)
 {
     NMVlanQosMapping *map;
     guint             i, j, len;
@@ -8087,7 +8166,7 @@ _vlan_change_vlan_qos_mapping_create(gboolean                is_ingress_map,
 }
 
 static gboolean
-link_vlan_change(NMPlatform *            platform,
+link_vlan_change(NMPlatform             *platform,
                  int                     ifindex,
                  _NMVlanFlags            flags_mask,
                  _NMVlanFlags            flags_set,
@@ -8098,13 +8177,13 @@ link_vlan_change(NMPlatform *            platform,
                  const NMVlanQosMapping *egress_map,
                  gsize                   n_egress_map)
 {
-    const NMPObject *            obj_cache;
+    const NMPObject             *obj_cache;
     nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
-    const NMPObjectLnkVlan *     lnk;
+    const NMPObjectLnkVlan      *lnk;
     guint                        new_n_ingress_map = 0;
     guint                        new_n_egress_map  = 0;
-    gs_free NMVlanQosMapping *new_ingress_map      = NULL;
-    gs_free NMVlanQosMapping *new_egress_map       = NULL;
+    gs_free NMVlanQosMapping    *new_ingress_map   = NULL;
+    gs_free NMVlanQosMapping    *new_egress_map    = NULL;
 
     obj_cache = nmp_cache_lookup_link(nm_platform_get_cache(platform), ifindex);
     if (!obj_cache || !obj_cache->_link.netlink.is_in_netlink) {
@@ -8175,7 +8254,7 @@ link_release(NMPlatform *platform, int master, int slave)
 /*****************************************************************************/
 
 static gboolean
-_infiniband_partition_action(NMPlatform *           platform,
+_infiniband_partition_action(NMPlatform            *platform,
                              InfinibandAction       action,
                              int                    parent,
                              int                    p_key,
@@ -8183,7 +8262,7 @@ _infiniband_partition_action(NMPlatform *           platform,
 {
     nm_auto_close int dirfd = -1;
     char              ifname_parent[IFNAMSIZ];
-    const NMPObject * obj;
+    const NMPObject  *obj;
     char              id[20];
     char              name[IFNAMSIZ];
     gboolean          success;
@@ -8234,7 +8313,7 @@ _infiniband_partition_action(NMPlatform *           platform,
 }
 
 static gboolean
-infiniband_partition_add(NMPlatform *           platform,
+infiniband_partition_add(NMPlatform            *platform,
                          int                    parent,
                          int                    p_key,
                          const NMPlatformLink **out_link)
@@ -8274,7 +8353,7 @@ get_ext_data(NMPlatform *platform, int ifindex)
 
 #define WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, retval) \
     nm_auto_pop_netns NMPNetns *netns = NULL;                          \
-    NMWifiUtils *               wifi_data;                             \
+    NMWifiUtils                *wifi_data;                             \
     if (!nm_platform_netns_push(platform, &netns))                     \
         return retval;                                                 \
     wifi_data = NM_WIFI_UTILS(get_ext_data(platform, ifindex));        \
@@ -8298,11 +8377,11 @@ wifi_get_frequency(NMPlatform *platform, int ifindex)
 }
 
 static gboolean
-wifi_get_station(NMPlatform * platform,
+wifi_get_station(NMPlatform  *platform,
                  int          ifindex,
                  NMEtherAddr *out_bssid,
-                 int *        out_quality,
-                 guint32 *    out_rate)
+                 int         *out_quality,
+                 guint32     *out_rate)
 {
     WIFI_GET_WIFI_DATA_NETNS(wifi_data, platform, ifindex, FALSE);
     return nm_wifi_utils_get_station(wifi_data, out_bssid, out_quality, out_rate);
@@ -8365,7 +8444,7 @@ link_can_assume(NMPlatform *platform, int ifindex)
     NMPLookup        lookup;
     const NMPObject *link, *o;
     NMDedupMultiIter iter;
-    NMPCache *       cache = nm_platform_get_cache(platform);
+    NMPCache        *cache = nm_platform_get_cache(platform);
 
     if (ifindex <= 0)
         return FALSE;
@@ -8488,9 +8567,9 @@ link_get_wake_on_lan(NMPlatform *platform, int ifindex)
 static gboolean
 link_get_driver_info(NMPlatform *platform,
                      int         ifindex,
-                     char **     out_driver_name,
-                     char **     out_driver_version,
-                     char **     out_fw_version)
+                     char      **out_driver_name,
+                     char      **out_driver_version,
+                     char      **out_fw_version)
 {
     nm_auto_pop_netns NMPNetns *netns = NULL;
     NMPUtilsEthtoolDriverInfo   driver_info;
@@ -8543,7 +8622,7 @@ ip4_address_add(NMPlatform *platform,
 }
 
 static gboolean
-ip6_address_add(NMPlatform *    platform,
+ip6_address_add(NMPlatform     *platform,
                 int             ifindex,
                 struct in6_addr addr,
                 guint8          plen,
@@ -8632,7 +8711,7 @@ ip6_address_delete(NMPlatform *platform, int ifindex, struct in6_addr addr, guin
 /*****************************************************************************/
 
 static int
-ip_route_add(NMPlatform *             platform,
+ip_route_add(NMPlatform              *platform,
              NMPNlmFlags              flags,
              int                      addr_family,
              const NMPlatformIPRoute *route)
@@ -8659,7 +8738,7 @@ static gboolean
 object_delete(NMPlatform *platform, const NMPObject *obj)
 {
     nm_auto_nmpobj const NMPObject *obj_keep_alive = NULL;
-    nm_auto_nlmsg struct nl_msg *   nlmsg          = NULL;
+    nm_auto_nlmsg struct nl_msg    *nlmsg          = NULL;
 
     if (!NMP_OBJECT_IS_STACKINIT(obj))
         obj_keep_alive = nmp_object_ref(obj);
@@ -8690,17 +8769,17 @@ object_delete(NMPlatform *platform, const NMPObject *obj)
 /*****************************************************************************/
 
 static int
-ip_route_get(NMPlatform *  platform,
+ip_route_get(NMPlatform   *platform,
              int           addr_family,
              gconstpointer address,
              int           oif_ifindex,
-             NMPObject **  out_route)
+             NMPObject   **out_route)
 {
-    const gboolean          is_v4     = (addr_family == AF_INET);
-    const int               addr_len  = is_v4 ? 4 : 16;
-    int                     try_count = 0;
-    WaitForNlResponseResult seq_result;
-    int                     nle;
+    const gboolean            IS_IPv4   = NM_IS_IPv4(addr_family);
+    const int                 addr_len  = IS_IPv4 ? 4 : 16;
+    int                       try_count = 0;
+    WaitForNlResponseResult   seq_result;
+    int                       nle;
     nm_auto_nmpobj NMPObject *route = NULL;
 
     nm_assert(NM_IS_LINUX_PLATFORM(platform));
@@ -8718,7 +8797,7 @@ ip_route_get(NMPlatform *  platform,
             .n.nlmsg_type  = RTM_GETROUTE,
             .r.rtm_family  = addr_family,
             .r.rtm_tos     = 0,
-            .r.rtm_dst_len = is_v4 ? 32 : 128,
+            .r.rtm_dst_len = IS_IPv4 ? 32 : 128,
             .r.rtm_flags   = 0x1000 /* RTM_F_LOOKUP_TABLE */,
         };
 
@@ -8778,7 +8857,7 @@ routing_rule_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformRoutin
 {
     WaitForNlResponseResult      seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
     nm_auto_nlmsg struct nl_msg *msg        = NULL;
-    gs_free char *               errmsg     = NULL;
+    gs_free char                *errmsg     = NULL;
     char                         s_buf[256];
     int                          nle;
 
@@ -8818,7 +8897,7 @@ static int
 qdisc_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformQdisc *qdisc)
 {
     WaitForNlResponseResult      seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
-    gs_free char *               errmsg     = NULL;
+    gs_free char                *errmsg     = NULL;
     int                          nle;
     char                         s_buf[256];
     nm_auto_nlmsg struct nl_msg *msg = NULL;
@@ -8860,14 +8939,14 @@ static int
 tc_delete(NMPlatform *platform, int nlmsgtype, int ifindex, guint32 parent, gboolean log_error)
 {
     WaitForNlResponseResult      seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
-    gs_free char *               errmsg     = NULL;
+    gs_free char                *errmsg     = NULL;
     int                          nle;
     char                         s_buf[256];
-    const char *                 log_tag;
+    const char                  *log_tag;
     nm_auto_nlmsg struct nl_msg *msg = NULL;
     const struct tcmsg           tcm = {
-        .tcm_ifindex = ifindex,
-        .tcm_parent  = parent,
+                  .tcm_ifindex = ifindex,
+                  .tcm_parent  = parent,
     };
 
     switch (nlmsgtype) {
@@ -8934,7 +9013,7 @@ static int
 tfilter_add(NMPlatform *platform, NMPNlmFlags flags, const NMPlatformTfilter *tfilter)
 {
     WaitForNlResponseResult      seq_result = WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN;
-    gs_free char *               errmsg     = NULL;
+    gs_free char                *errmsg     = NULL;
     int                          nle;
     char                         s_buf[256];
     nm_auto_nlmsg struct nl_msg *msg = NULL;
@@ -8992,39 +9071,44 @@ event_handler(int fd, GIOCondition io_condition, gpointer user_data)
 static int
 event_handler_recvmsgs(NMPlatform *platform, gboolean handle_events)
 {
-    NMLinuxPlatformPrivate *    priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
-    struct nl_sock *            sk   = priv->nlh;
-    int                         n;
-    int                         err         = 0;
-    gboolean                    multipart   = 0;
-    gboolean                    interrupted = FALSE;
-    struct nlmsghdr *           hdr;
-    WaitForNlResponseResult     seq_result;
-    struct sockaddr_nl          nla = {0};
-    struct ucred                creds;
-    gboolean                    creds_has;
-    nm_auto_free unsigned char *buf = NULL;
+    NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+    struct nl_sock         *sk   = priv->nlh;
+    int                     n;
+    int                     err         = 0;
+    gboolean                multipart   = 0;
+    gboolean                interrupted = FALSE;
+    struct nlmsghdr        *hdr;
+    WaitForNlResponseResult seq_result;
+    struct sockaddr_nl      nla;
+    struct ucred            creds;
+    gboolean                creds_has;
+    unsigned char          *buf;
 
 continue_reading:
-    nm_clear_pointer(&buf, free);
-    n = nl_recv(sk, &nla, &buf, &creds, &creds_has);
+    buf = NULL;
+
+    n = nl_recv(sk,
+                priv->netlink_recv_buf.buf,
+                priv->netlink_recv_buf.len,
+                &nla,
+                &buf,
+                &creds,
+                &creds_has);
+
+    nm_assert((n <= 0 && !buf)
+              || (n > 0 && n <= priv->netlink_recv_buf.len && buf == priv->netlink_recv_buf.buf));
 
     if (n <= 0) {
         if (n == -NME_NL_MSG_TRUNC) {
-            int buf_size;
-
             /* the message receive buffer was too small. We lost one message, which
              * is unfortunate. Try to double the buffer size for the next time. */
-            buf_size = nl_socket_get_msg_buf_size(sk);
-            if (buf_size < 512 * 1024) {
-                buf_size *= 2;
-                _LOGT("netlink: recvmsg: increase message buffer size for recvmsg() to %d bytes",
-                      buf_size);
-                if (nl_socket_set_msg_buf_size(sk, buf_size) < 0)
-                    nm_assert_not_reached();
-                if (!handle_events)
-                    goto continue_reading;
-            }
+            priv->netlink_recv_buf.len *= 2;
+            priv->netlink_recv_buf.buf =
+                g_realloc(priv->netlink_recv_buf.buf, priv->netlink_recv_buf.len);
+            _LOGT("netlink: recvmsg: increase message buffer size for recvmsg() to %zu bytes",
+                  priv->netlink_recv_buf.len);
+            if (!handle_events)
+                goto continue_reading;
         }
 
         return n;
@@ -9037,7 +9121,7 @@ continue_reading:
         gboolean                     process_valid_msg = FALSE;
         guint32                      seq_number;
         char                         buf_nlmsghdr[400];
-        const char *                 extack_msg = NULL;
+        const char                  *extack_msg = NULL;
 
         msg = nlmsg_alloc_convert(hdr);
 
@@ -9195,15 +9279,15 @@ static gboolean
 event_handler_read_netlink(NMPlatform *platform, gboolean wait_for_acks)
 {
     nm_auto_pop_netns NMPNetns *netns = NULL;
-    NMLinuxPlatformPrivate *    priv  = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
+    NMLinuxPlatformPrivate     *priv  = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     int                         r;
     struct pollfd               pfd;
     gboolean                    any = FALSE;
     int                         timeout_msec;
     struct {
         guint32 seq_number;
-        gint64  timeout_abs_ns;
-        gint64  now_ns;
+        gint64  timeout_abs_nsec;
+        gint64  now_nsec;
     } next;
 
     if (!nm_platform_netns_push(platform, &netns)) {
@@ -9275,25 +9359,33 @@ after_read:
         delayed_action_wait_for_nl_response_complete_check(platform,
                                                            WAIT_FOR_NL_RESPONSE_RESULT_UNKNOWN,
                                                            &next.seq_number,
-                                                           &next.timeout_abs_ns,
-                                                           &next.now_ns);
+                                                           &next.timeout_abs_nsec,
+                                                           &next.now_nsec);
 
         if (!wait_for_acks
             || !NM_FLAGS_HAS(priv->delayed_action.flags, DELAYED_ACTION_TYPE_WAIT_FOR_NL_RESPONSE))
             return any;
 
         nm_assert(next.seq_number);
-        nm_assert(next.now_ns > 0);
-        nm_assert(next.timeout_abs_ns > next.now_ns);
+        nm_assert(next.now_nsec > 0);
+        nm_assert(next.timeout_abs_nsec > next.now_nsec);
+        nm_assert(next.timeout_abs_nsec - next.now_nsec <= 200 * (NM_UTILS_NSEC_PER_SEC / 1000));
 
-        _LOGT("netlink: read: wait for ACK for sequence number %u...", next.seq_number);
+        timeout_msec =
+            NM_CLAMP((next.timeout_abs_nsec - next.now_nsec) / (NM_UTILS_NSEC_PER_SEC / 1000),
+                     1,
+                     1000);
 
-        timeout_msec = (next.timeout_abs_ns - next.now_ns) / (NM_UTILS_NSEC_PER_SEC / 1000);
+        _LOGT("netlink: read: wait for ACK for sequence number %u... (%d msec)",
+              next.seq_number,
+              timeout_msec);
 
         memset(&pfd, 0, sizeof(pfd));
         pfd.fd     = nl_socket_get_fd(priv->nlh);
         pfd.events = POLLIN;
-        r          = poll(&pfd, 1, MAX(1, timeout_msec));
+        r          = poll(&pfd, 1, timeout_msec);
+
+        _LOGT("netlink: read: poll done (r=%d)", r);
 
         if (r == 0) {
             /* timeout and there is nothing to read. */
@@ -9412,11 +9504,11 @@ static void
 handle_udev_event(NMUdevClient *udev_client, struct udev_device *udevice, gpointer user_data)
 {
     nm_auto_pop_netns NMPNetns *netns    = NULL;
-    NMPlatform *                platform = NM_PLATFORM(user_data);
-    const char *                subsys;
-    const char *                ifindex;
+    NMPlatform                 *platform = NM_PLATFORM(user_data);
+    const char                 *subsys;
+    const char                 *ifindex;
     guint64                     seqnum;
-    const char *                action;
+    const char                 *action;
 
     action = udev_device_get_action(udevice);
     g_return_if_fail(action);
@@ -9449,6 +9541,9 @@ nm_linux_platform_init(NMLinuxPlatform *self)
 {
     NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE(self);
 
+    priv->netlink_recv_buf.len = 32 * 1024;
+    priv->netlink_recv_buf.buf = g_malloc(priv->netlink_recv_buf.len);
+
     c_list_init(&priv->sysctl_clear_cache_lst);
     c_list_init(&priv->sysctl_list);
 
@@ -9461,7 +9556,7 @@ nm_linux_platform_init(NMLinuxPlatform *self)
 static void
 constructed(GObject *_object)
 {
-    NMPlatform *            platform = NM_PLATFORM(_object);
+    NMPlatform             *platform = NM_PLATFORM(_object);
     NMLinuxPlatformPrivate *priv     = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
     int                     nle;
     int                     fd;
@@ -9517,10 +9612,10 @@ constructed(GObject *_object)
         _LOGD("could not enable extended acks on netlink socket");
 
     /* explicitly set the msg buffer size and disable MSG_PEEK.
-     * If we later encounter NME_NL_MSG_TRUNC, we will adjust the buffer size. */
+     * We use our own receive buffer priv->netlink_recv_buf.
+     * If we encounter NME_NL_MSG_TRUNC, we will increase the buffer
+     * and resync (as we would have lost the message without NL_MSG_PEEK). */
     nl_socket_disable_msg_peek(priv->nlh);
-    nle = nl_socket_set_msg_buf_size(priv->nlh, 32 * 1024);
-    g_assert(!nle);
 
     nle = nl_socket_add_memberships(priv->nlh,
                                     RTNLGRP_IPV4_IFADDR,
@@ -9571,7 +9666,7 @@ constructed(GObject *_object)
 
     /* Set up udev monitoring */
     if (priv->udev_client) {
-        struct udev_enumerate * enumerator;
+        struct udev_enumerate  *enumerator;
         struct udev_list_entry *devices, *l;
 
         /* And read initial device list */
@@ -9643,7 +9738,7 @@ nm_linux_platform_new(gboolean log_with_ptr, gboolean netns_support, gboolean ca
 static void
 dispose(GObject *object)
 {
-    NMPlatform *            platform = NM_PLATFORM(object);
+    NMPlatform             *platform = NM_PLATFORM(object);
     NMLinuxPlatformPrivate *priv     = NM_LINUX_PLATFORM_GET_PRIVATE(platform);
 
     _LOGD("dispose");
@@ -9688,12 +9783,14 @@ finalize(GObject *object)
     priv->udev_client = nm_udev_client_destroy(priv->udev_client);
 
     G_OBJECT_CLASS(nm_linux_platform_parent_class)->finalize(object);
+
+    g_free(priv->netlink_recv_buf.buf);
 }
 
 static void
 nm_linux_platform_class_init(NMLinuxPlatformClass *klass)
 {
-    GObjectClass *   object_class   = G_OBJECT_CLASS(klass);
+    GObjectClass    *object_class   = G_OBJECT_CLASS(klass);
     NMPlatformClass *platform_class = NM_PLATFORM_CLASS(klass);
 
     object_class->constructed = constructed;
diff --git a/src/libnm-platform/nm-netlink.c b/src/libnm-platform/nm-netlink.c
index 56cde50c..697ae591 100644
--- a/src/libnm-platform/nm-netlink.c
+++ b/src/libnm-platform/nm-netlink.c
@@ -32,7 +32,7 @@ struct nl_msg {
     struct sockaddr_nl nm_src;
     struct sockaddr_nl nm_dst;
     struct ucred       nm_creds;
-    struct nlmsghdr *  nm_nlh;
+    struct nlmsghdr   *nm_nlh;
     size_t             nm_size;
     bool               nm_creds_has : 1;
 };
@@ -245,7 +245,7 @@ nlmsg_hdr(struct nl_msg *n)
 void *
 nlmsg_reserve(struct nl_msg *n, size_t len, int pad)
 {
-    char * buf       = (char *) n->nm_nlh;
+    char  *buf       = (char *) n->nm_nlh;
     size_t nlmsg_len = n->nm_nlh->nlmsg_len;
     size_t tlen;
 
@@ -386,9 +386,9 @@ nlmsg_append(struct nl_msg *n, const void *data, size_t len, int pad)
 /*****************************************************************************/
 
 int
-nlmsg_parse(struct nlmsghdr *        nlh,
+nlmsg_parse(struct nlmsghdr         *nlh,
             int                      hdrlen,
-            struct nlattr *          tb[],
+            struct nlattr           *tb[],
             int                      maxtype,
             const struct nla_policy *policy)
 {
@@ -639,9 +639,9 @@ validate_nla(const struct nlattr *nla, int maxtype, const struct nla_policy *pol
 }
 
 int
-nla_parse(struct nlattr *          tb[],
+nla_parse(struct nlattr           *tb[],
           int                      maxtype,
-          struct nlattr *          head,
+          struct nlattr           *head,
           int                      len,
           const struct nla_policy *policy)
 {
@@ -718,7 +718,7 @@ genlmsg_put(struct nl_msg *msg,
             uint8_t        cmd,
             uint8_t        version)
 {
-    struct nlmsghdr * nlh;
+    struct nlmsghdr  *nlh;
     struct genlmsghdr hdr = {
         .cmd     = cmd,
         .version = version,
@@ -794,9 +794,9 @@ genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen)
 }
 
 int
-genlmsg_parse(struct nlmsghdr *        nlh,
+genlmsg_parse(struct nlmsghdr         *nlh,
               int                      hdrlen,
-              struct nlattr *          tb[],
+              struct nlattr           *tb[],
               int                      maxtype,
               const struct nla_policy *policy)
 {
@@ -825,9 +825,9 @@ _genl_parse_getfamily(struct nl_msg *msg, void *arg)
         [CTRL_ATTR_OPS]          = {.type = NLA_NESTED},
         [CTRL_ATTR_MCAST_GROUPS] = {.type = NLA_NESTED},
     };
-    struct nlattr *  tb[G_N_ELEMENTS(ctrl_policy)];
+    struct nlattr   *tb[G_N_ELEMENTS(ctrl_policy)];
     struct nlmsghdr *nlh           = nlmsg_hdr(msg);
-    gint32 *         response_data = arg;
+    gint32          *response_data = arg;
 
     if (genlmsg_parse_arr(nlh, 0, tb, ctrl_policy) < 0)
         return NL_SKIP;
@@ -845,8 +845,8 @@ genl_ctrl_resolve(struct nl_sock *sk, const char *name)
     int                          nmerr;
     gint32                       response_data = -1;
     const struct nl_cb           cb            = {
-        .valid_cb  = _genl_parse_getfamily,
-        .valid_arg = &response_data,
+                             .valid_cb  = _genl_parse_getfamily,
+                             .valid_arg = &response_data,
     };
 
     msg = nlmsg_alloc();
@@ -1170,13 +1170,13 @@ nl_recvmsgs(struct nl_sock *sk, const struct nl_cb *cb)
 {
     int                    n, nmerr = 0, multipart = 0, interrupted = 0, nrecv = 0;
     gs_free unsigned char *buf = NULL;
-    struct nlmsghdr *      hdr;
-    struct sockaddr_nl     nla = {0};
+    struct nlmsghdr       *hdr;
+    struct sockaddr_nl     nla;
     struct ucred           creds;
     gboolean               creds_has;
 
 continue_reading:
-    n = nl_recv(sk, &nla, &buf, &creds, &creds_has);
+    n = nl_recv(sk, NULL, 0, &nla, &buf, &creds, &creds_has);
     if (n <= 0)
         return n;
 
@@ -1327,12 +1327,12 @@ int
 nl_send_iovec(struct nl_sock *sk, struct nl_msg *msg, struct iovec *iov, unsigned iovlen)
 {
     struct sockaddr_nl *dst;
-    struct ucred *      creds;
+    struct ucred       *creds;
     struct msghdr       hdr = {
-        .msg_name    = (void *) &sk->s_peer,
-        .msg_namelen = sizeof(struct sockaddr_nl),
-        .msg_iov     = iov,
-        .msg_iovlen  = iovlen,
+              .msg_name    = (void *) &sk->s_peer,
+              .msg_namelen = sizeof(struct sockaddr_nl),
+              .msg_iov     = iov,
+              .msg_iovlen  = iovlen,
     };
     char buf[CMSG_SPACE(sizeof(struct ucred))];
 
@@ -1401,12 +1401,41 @@ nl_send_auto(struct nl_sock *sk, struct nl_msg *msg)
     return nl_send(sk, msg);
 }
 
+/**
+ * nl_recv():
+ * @sk: the netlink socket
+ * @buf0: NULL or a receive buffer of length @buf0_len
+ * @buf0_len: the length of the optional receive buffer.
+ * @nla: (out): the source address on success.
+ * @buf: (out): pointer to the result buffer on success. This is
+ *   either @buf0 or an allocated buffer that gets returned.
+ * @out_creds: (out) (allow-none): optional out buffer for the credentials
+ *   on success.
+ * @out_creds_has: (out) (allow-none): result indicating whether
+ *   @out_creds was filled.
+ *
+ * If @buf0_len is zero, the function will g_malloc() a new receive buffer of size
+ * nl_socket_get_msg_buf_size(). If @buf0_len is larger than zero, then @buf0
+ * is used as receive buffer. That is also the buffer returned by @buf.
+ *
+ * If NL_MSG_PEEK is not enabled and the receive buffer is too small, then
+ * the message was lost and -NME_NL_MSG_TRUNC gets returned.
+ * If NL_MSG_PEEK is enabled, then we first peek. If the buffer is too small,
+ * we g_malloc() a new buffer. In any case, we proceed to receive the buffer.
+ * NL_MSG_PEEK is great because it means no messages are lost. But it's bad,
+ * because we always need two syscalls on every receive.
+ *
+ * Returns: a negative error code or the length of the received message in
+ *   @buf.
+ */
 int
-nl_recv(struct nl_sock *    sk,
+nl_recv(struct nl_sock     *sk,
+        unsigned char      *buf0,
+        size_t              buf0_len,
         struct sockaddr_nl *nla,
-        unsigned char **    buf,
-        struct ucred *      out_creds,
-        gboolean *          out_creds_has)
+        unsigned char     **buf,
+        struct ucred       *out_creds,
+        gboolean           *out_creds_has)
 {
     /* We really expect msg_contol_buf to be large enough and MSG_CTRUNC not
      * happening. We nm_assert() against that. However, in release builds
@@ -1443,8 +1472,13 @@ nl_recv(struct nl_sock *    sk,
         || (!(sk->s_flags & NL_MSG_PEEK_EXPLICIT) && sk->s_bufsize == 0))
         flags |= MSG_PEEK | MSG_TRUNC;
 
-    iov.iov_len  = sk->s_bufsize ?: (((size_t) nm_utils_getpagesize()) * 4u);
-    iov.iov_base = g_malloc(iov.iov_len);
+    if (buf0_len > 0) {
+        iov.iov_len  = buf0_len;
+        iov.iov_base = buf0;
+    } else {
+        iov.iov_len  = sk->s_bufsize ?: (((size_t) nm_utils_getpagesize()) * 4u);
+        iov.iov_base = g_malloc(iov.iov_len);
+    }
 
     if (out_creds && (sk->s_flags & NL_SOCK_PASSCRED)) {
         msg.msg_controllen = sizeof(msg_contol_buf);
@@ -1482,7 +1516,7 @@ retry:
         /* Provided buffer is not long enough, enlarge it
          * to size of n (which should be total length of the message)
          * and try again. */
-        iov.iov_base = g_realloc(iov.iov_base, n);
+        iov.iov_base = g_realloc(iov.iov_base != buf0 ? iov.iov_base : NULL, n);
         iov.iov_len  = n;
         flags        = 0;
         goto retry;
@@ -1517,7 +1551,8 @@ retry:
 
 abort:
     if (retval <= 0) {
-        g_free(iov.iov_base);
+        if (iov.iov_base != buf0)
+            g_free(iov.iov_base);
         return retval;
     }
 
diff --git a/src/libnm-platform/nm-netlink.h b/src/libnm-platform/nm-netlink.h
index 00d817cd..bb1e41ee 100644
--- a/src/libnm-platform/nm-netlink.h
+++ b/src/libnm-platform/nm-netlink.h
@@ -328,9 +328,9 @@ void           nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr);
 struct nlattr *nla_nest_start(struct nl_msg *msg, int attrtype);
 int            nla_nest_end(struct nl_msg *msg, struct nlattr *start);
 
-int nla_parse(struct nlattr *          tb[],
+int nla_parse(struct nlattr           *tb[],
               int                      maxtype,
-              struct nlattr *          head,
+              struct nlattr           *head,
               int                      len,
               const struct nla_policy *policy);
 
@@ -342,9 +342,9 @@ int nla_parse(struct nlattr *          tb[],
     })
 
 static inline int
-nla_parse_nested(struct nlattr *          tb[],
+nla_parse_nested(struct nlattr           *tb[],
                  int                      maxtype,
-                 struct nlattr *          nla,
+                 struct nlattr           *nla,
                  const struct nla_policy *policy)
 {
     return nla_parse(tb, maxtype, nla_data(nla), nla_len(nla), policy);
@@ -468,9 +468,9 @@ nlmsg_find_attr(struct nlmsghdr *nlh, int hdrlen, int attrtype)
     return nla_find(nlmsg_attrdata(nlh, hdrlen), nlmsg_attrlen(nlh, hdrlen), attrtype);
 }
 
-int nlmsg_parse(struct nlmsghdr *        nlh,
+int nlmsg_parse(struct nlmsghdr         *nlh,
                 int                      hdrlen,
-                struct nlattr *          tb[],
+                struct nlattr           *tb[],
                 int                      maxtype,
                 const struct nla_policy *policy);
 
@@ -517,11 +517,13 @@ int nl_socket_add_memberships(struct nl_sock *sk, int group, ...);
 
 int nl_connect(struct nl_sock *sk, int protocol);
 
-int nl_recv(struct nl_sock *    sk,
+int nl_recv(struct nl_sock     *sk,
+            unsigned char      *buf0,
+            size_t              buf0_len,
             struct sockaddr_nl *nla,
-            unsigned char **    buf,
-            struct ucred *      out_creds,
-            gboolean *          out_creds_has);
+            unsigned char     **buf,
+            struct ucred       *out_creds,
+            gboolean           *out_creds_has);
 
 int nl_send(struct nl_sock *sk, struct nl_msg *msg);
 
@@ -544,16 +546,16 @@ typedef int (*nl_recvmsg_err_cb_t)(struct sockaddr_nl *nla, struct nlmsgerr *nle
 
 struct nl_cb {
     nl_recvmsg_msg_cb_t valid_cb;
-    void *              valid_arg;
+    void               *valid_arg;
 
     nl_recvmsg_msg_cb_t finish_cb;
-    void *              finish_arg;
+    void               *finish_arg;
 
     nl_recvmsg_msg_cb_t ack_cb;
-    void *              ack_arg;
+    void               *ack_arg;
 
     nl_recvmsg_err_cb_t err_cb;
-    void *              err_arg;
+    void               *err_arg;
 };
 
 int nl_sendmsg(struct nl_sock *sk, struct nl_msg *msg, struct msghdr *hdr);
@@ -570,7 +572,7 @@ int nl_socket_set_ext_ack(struct nl_sock *sk, gboolean enable);
 
 /*****************************************************************************/
 
-void *             genlmsg_put(struct nl_msg *msg,
+void              *genlmsg_put(struct nl_msg *msg,
                                uint32_t       port,
                                uint32_t       seq,
                                int            family,
@@ -578,18 +580,18 @@ void *             genlmsg_put(struct nl_msg *msg,
                                int            flags,
                                uint8_t        cmd,
                                uint8_t        version);
-void *             genlmsg_data(const struct genlmsghdr *gnlh);
-void *             genlmsg_user_hdr(const struct genlmsghdr *gnlh);
+void              *genlmsg_data(const struct genlmsghdr *gnlh);
+void              *genlmsg_user_hdr(const struct genlmsghdr *gnlh);
 struct genlmsghdr *genlmsg_hdr(struct nlmsghdr *nlh);
-void *             genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen);
-struct nlattr *    genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen);
+void              *genlmsg_user_data(const struct genlmsghdr *gnlh, const int hdrlen);
+struct nlattr     *genlmsg_attrdata(const struct genlmsghdr *gnlh, int hdrlen);
 int                genlmsg_len(const struct genlmsghdr *gnlh);
 int                genlmsg_attrlen(const struct genlmsghdr *gnlh, int hdrlen);
 int                genlmsg_valid_hdr(struct nlmsghdr *nlh, int hdrlen);
 
-int genlmsg_parse(struct nlmsghdr *        nlh,
+int genlmsg_parse(struct nlmsghdr         *nlh,
                   int                      hdrlen,
-                  struct nlattr *          tb[],
+                  struct nlattr           *tb[],
                   int                      maxtype,
                   const struct nla_policy *policy);
 
diff --git a/src/libnm-platform/nm-platform-private.h b/src/libnm-platform/nm-platform-private.h
index cf805689..7537bb0b 100644
--- a/src/libnm-platform/nm-platform-private.h
+++ b/src/libnm-platform/nm-platform-private.h
@@ -21,7 +21,7 @@ NMPCache *nm_platform_get_cache(NMPlatform *self);
     }                                                                                          \
     G_STMT_END
 
-void nm_platform_cache_update_emit_signal(NMPlatform *     platform,
+void nm_platform_cache_update_emit_signal(NMPlatform      *platform,
                                           NMPCacheOpsType  cache_op,
                                           const NMPObject *obj_old,
                                           const NMPObject *obj_new);
diff --git a/src/libnm-platform/nm-platform-utils.c b/src/libnm-platform/nm-platform-utils.c
index f0522736..9ad030df 100644
--- a/src/libnm-platform/nm-platform-utils.c
+++ b/src/libnm-platform/nm-platform-utils.c
@@ -91,16 +91,16 @@ typedef enum {
 } IoctlCallDataType;
 
 static int
-_ioctl_call(const char *      log_ioctl_type,
-            const char *      log_subtype,
+_ioctl_call(const char       *log_ioctl_type,
+            const char       *log_subtype,
             unsigned long int ioctl_request,
             int               ifindex,
-            int *             inout_fd,
-            char *            inout_ifname,
+            int              *inout_fd,
+            char             *inout_ifname,
             IoctlCallDataType edata_type,
             gpointer          edata,
             gsize             edata_size,
-            struct ifreq *    out_ifreq)
+            struct ifreq     *out_ifreq)
 {
     nm_auto_close int fd_close = -1;
     int               fd;
@@ -109,7 +109,7 @@ _ioctl_call(const char *      log_ioctl_type,
     gs_free gpointer  edata_backup_free = NULL;
     guint             try_count;
     char              known_ifnames[2][IFNAMSIZ];
-    const char *      failure_reason = NULL;
+    const char       *failure_reason = NULL;
     struct ifreq      ifr;
 
     nm_assert(ifindex > 0);
@@ -365,7 +365,7 @@ ethtool_get_stringset(SocketHandle *shandle, int stringset_id)
         .info.reserved  = 0,
         .info.sset_mask = (1ULL << stringset_id),
     };
-    const guint32 *                  pdata;
+    const guint32                   *pdata;
     gs_free struct ethtool_gstrings *gstrings = NULL;
     gsize                            gstrings_len;
     guint32                          i, len;
@@ -574,7 +574,7 @@ _ASSERT_ethtool_feature_infos(void)
 static NMEthtoolFeatureStates *
 ethtool_get_features(SocketHandle *shandle)
 {
-    gs_free NMEthtoolFeatureStates * states      = NULL;
+    gs_free NMEthtoolFeatureStates  *states      = NULL;
     gs_free struct ethtool_gstrings *ss_features = NULL;
 
     _ASSERT_ethtool_feature_infos();
@@ -584,11 +584,11 @@ ethtool_get_features(SocketHandle *shandle)
         return NULL;
 
     if (ss_features->len > 0) {
-        gs_free struct ethtool_gfeatures *  gfeatures_free = NULL;
-        struct ethtool_gfeatures *          gfeatures;
+        gs_free struct ethtool_gfeatures   *gfeatures_free = NULL;
+        struct ethtool_gfeatures           *gfeatures;
         gsize                               gfeatures_len;
         guint                               idx;
-        const NMEthtoolFeatureState *       states_list0   = NULL;
+        const NMEthtoolFeatureState        *states_list0   = NULL;
         const NMEthtoolFeatureState *const *states_plist0  = NULL;
         guint                               states_plist_n = 0;
 
@@ -606,7 +606,7 @@ ethtool_get_features(SocketHandle *shandle)
 
             for (idx_kernel_name = 0; idx_kernel_name < info->n_kernel_names; idx_kernel_name++) {
                 NMEthtoolFeatureState *kstate;
-                const char *           kernel_name = info->kernel_names[idx_kernel_name];
+                const char            *kernel_name = info->kernel_names[idx_kernel_name];
                 int                    i_feature;
                 guint                  i_block;
                 guint32                i_flag;
@@ -667,7 +667,7 @@ NMEthtoolFeatureStates *
 nmp_utils_ethtool_get_features(int ifindex)
 {
     nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
-    NMEthtoolFeatureStates *           features;
+    NMEthtoolFeatureStates            *features;
 
     g_return_val_if_fail(ifindex > 0, 0);
 
@@ -689,10 +689,10 @@ nmp_utils_ethtool_get_features(int ifindex)
 }
 
 static const char *
-_ethtool_feature_state_to_string(char *                       buf,
+_ethtool_feature_state_to_string(char                        *buf,
                                  gsize                        buf_size,
                                  const NMEthtoolFeatureState *s,
-                                 const char *                 prefix)
+                                 const char                  *prefix)
 {
     int l;
 
@@ -718,8 +718,8 @@ nmp_utils_ethtool_set_features(
     gboolean            do_set /* or reset */)
 {
     nm_auto_socket_handle SocketHandle shandle        = SOCKET_HANDLE_INIT(ifindex);
-    gs_free struct ethtool_sfeatures * sfeatures_free = NULL;
-    struct ethtool_sfeatures *         sfeatures;
+    gs_free struct ethtool_sfeatures  *sfeatures_free = NULL;
+    struct ethtool_sfeatures          *sfeatures;
     gsize                              sfeatures_len;
     int                                r;
     guint                              i, j;
@@ -1215,8 +1215,8 @@ gboolean
 nmp_utils_ethtool_supports_vlans(int ifindex)
 {
     nm_auto_socket_handle SocketHandle shandle       = SOCKET_HANDLE_INIT(ifindex);
-    gs_free struct ethtool_gfeatures * features_free = NULL;
-    struct ethtool_gfeatures *         features;
+    gs_free struct ethtool_gfeatures  *features_free = NULL;
+    struct ethtool_gfeatures          *features;
     gsize                              features_len;
     int                                idx, block, bit, size;
 
@@ -1250,8 +1250,8 @@ nmp_utils_ethtool_get_peer_ifindex(int ifindex)
 {
     nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
     gsize                              stats_len;
-    gs_free struct ethtool_stats *     stats_free = NULL;
-    struct ethtool_stats *             stats;
+    gs_free struct ethtool_stats      *stats_free = NULL;
+    struct ethtool_stats              *stats;
     int                                peer_ifindex_stat;
 
     g_return_val_if_fail(ifindex > 0, 0);
@@ -1289,8 +1289,8 @@ nmp_utils_ethtool_get_wake_on_lan(int ifindex)
 
 gboolean
 nmp_utils_ethtool_get_link_settings(int                       ifindex,
-                                    gboolean *                out_autoneg,
-                                    guint32 *                 out_speed,
+                                    gboolean                 *out_autoneg,
+                                    guint32                  *out_speed,
                                     NMPlatformLinkDuplexType *out_duplex)
 {
     struct ethtool_cmd edata = {
@@ -1474,7 +1474,7 @@ const guint32 _nmp_link_mode_all_advertised_modes[] = {
 };
 
 static NMOptionBool
-set_link_settings_new(SocketHandle *           shandle,
+set_link_settings_new(SocketHandle            *shandle,
                       gboolean                 autoneg,
                       guint32                  speed,
                       NMPlatformLinkDuplexType duplex)
@@ -1512,8 +1512,8 @@ set_link_settings_new(SocketHandle *           shandle,
 
     {
         const guint32 *v_map_supported      = &edata->link_mode_masks[0];
-        guint32 *      v_map_advertising    = &edata->link_mode_masks[nwords];
-        guint32 *      v_map_lp_advertising = &edata->link_mode_masks[2 * nwords];
+        guint32       *v_map_advertising    = &edata->link_mode_masks[nwords];
+        guint32       *v_map_lp_advertising = &edata->link_mode_masks[2 * nwords];
 
         memcpy(v_map_advertising, v_map_supported, sizeof(guint32) * nwords);
         (void) v_map_lp_advertising;
@@ -1574,7 +1574,7 @@ nmp_utils_ethtool_set_link_settings(int                      ifindex,
 {
     nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
     struct ethtool_cmd                 edata   = {
-        .cmd = ETHTOOL_GSET,
+                          .cmd = ETHTOOL_GSET,
     };
     NMOptionBool ret;
 
@@ -1651,7 +1651,7 @@ set_autoneg:
 gboolean
 nmp_utils_ethtool_set_wake_on_lan(int                      ifindex,
                                   _NMSettingWiredWakeOnLan wol,
-                                  const char *             wol_password)
+                                  const char              *wol_password)
 {
     struct ethtool_wolinfo wol_info = {
         .cmd     = ETHTOOL_SWOL,
@@ -1706,7 +1706,7 @@ nmp_utils_mii_supports_carrier_detect(int ifindex)
     nm_auto_socket_handle SocketHandle shandle = SOCKET_HANDLE_INIT(ifindex);
     int                                r;
     struct ifreq                       ifr;
-    struct mii_ioctl_data *            mii;
+    struct mii_ioctl_data             *mii;
 
     g_return_val_if_fail(ifindex > 0, FALSE);
 
@@ -1757,7 +1757,7 @@ const char *
 nmp_utils_udev_get_driver(struct udev_device *udevice)
 {
     struct udev_device *parent = NULL, *grandparent = NULL;
-    const char *        driver, *subsys;
+    const char         *driver, *subsys;
 
     driver = udev_device_get_driver(udevice);
     if (driver)
@@ -2194,10 +2194,10 @@ nmp_utils_modprobe(GError **error, gboolean suppress_error_logging, const char *
 {
     gs_unref_ptrarray GPtrArray *argv = NULL;
     int                          exit_status;
-    gs_free char *               _log_str = NULL;
+    gs_free char                *_log_str = NULL;
 #define ARGV_TO_STR(argv) \
     (_log_str ? _log_str : (_log_str = g_strjoinv(" ", (char **) argv->pdata)))
-    GError *      local = NULL;
+    GError       *local = NULL;
     va_list       ap;
     NMLogLevel    llevel  = suppress_error_logging ? LOGL_DEBUG : LOGL_ERR;
     gs_free char *std_out = NULL, *std_err = NULL;
diff --git a/src/libnm-platform/nm-platform-utils.h b/src/libnm-platform/nm-platform-utils.h
index 5511e8af..a9ccebb3 100644
--- a/src/libnm-platform/nm-platform-utils.h
+++ b/src/libnm-platform/nm-platform-utils.h
@@ -18,7 +18,7 @@ int         nmp_utils_ethtool_get_peer_ifindex(int ifindex);
 gboolean    nmp_utils_ethtool_get_wake_on_lan(int ifindex);
 gboolean    nmp_utils_ethtool_set_wake_on_lan(int                      ifindex,
                                               _NMSettingWiredWakeOnLan wol,
-                                              const char *             wol_password);
+                                              const char              *wol_password);
 
 const char *nm_platform_link_duplex_type_to_string(NMPlatformLinkDuplexType duplex);
 
@@ -26,8 +26,8 @@ extern const guint8  _nmp_link_mode_all_advertised_modes_bits[79];
 extern const guint32 _nmp_link_mode_all_advertised_modes[3];
 
 gboolean nmp_utils_ethtool_get_link_settings(int                       ifindex,
-                                             gboolean *                out_autoneg,
-                                             guint32 *                 out_speed,
+                                             gboolean                 *out_autoneg,
+                                             guint32                  *out_speed,
                                              NMPlatformLinkDuplexType *out_duplex);
 gboolean nmp_utils_ethtool_set_link_settings(int                      ifindex,
                                              gboolean                 autoneg,
@@ -77,7 +77,7 @@ int         nmp_utils_if_nametoindex(const char *ifname);
 
 int nmp_utils_sysctl_open_netdir(int ifindex, const char *ifname_guess, char *out_ifname);
 
-char *      nmp_utils_new_vlan_name(const char *parent_iface, guint32 vlan_id);
+char       *nmp_utils_new_vlan_name(const char *parent_iface, guint32 vlan_id);
 const char *nmp_utils_new_infiniband_name(char *name, const char *parent_name, int p_key);
 
 guint32
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index 5d4ec037..b95cd95e 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -115,9 +115,9 @@ nmp_link_address_get_as_bytes(const NMPLinkAddress *addr)
 
 #define NMLOG_COMMON(level, name, ...)                                                \
     char                    __prefix[32];                                             \
-    const char *            __p_prefix = _NMLOG_PREFIX_NAME;                          \
+    const char             *__p_prefix = _NMLOG_PREFIX_NAME;                          \
     const NMPlatform *const __self     = (self);                                      \
-    const char *            __name     = name;                                        \
+    const char             *__name     = name;                                        \
                                                                                       \
     if (__self && NM_PLATFORM_GET_PRIVATE(__self)->log_with_ptr) {                    \
         g_snprintf(__prefix, sizeof(__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \
@@ -187,9 +187,9 @@ typedef struct _NMPlatformPrivate {
 
     guint              ip4_dev_route_blacklist_check_id;
     guint              ip4_dev_route_blacklist_gc_timeout_id;
-    GHashTable *       ip4_dev_route_blacklist_hash;
+    GHashTable        *ip4_dev_route_blacklist_hash;
     NMDedupMultiIndex *multi_idx;
-    NMPCache *         cache;
+    NMPCache          *cache;
 } NMPlatformPrivate;
 
 G_DEFINE_TYPE(NMPlatform, nm_platform, G_TYPE_OBJECT)
@@ -255,7 +255,7 @@ _nm_platform_signal_id_get(NMPlatformSignalIdType signal_type)
 
 #define _CHECK_SELF_NETNS(self, klass, netns, err_val)       \
     nm_auto_pop_netns NMPNetns *netns = NULL;                \
-    NMPlatformClass *           klass;                       \
+    NMPlatformClass            *klass;                       \
     do {                                                     \
         g_return_val_if_fail(NM_IS_PLATFORM(self), err_val); \
         klass = NM_PLATFORM_GET_CLASS(self);                 \
@@ -531,14 +531,14 @@ nm_platform_sysctl_set(NMPlatform *self,
  * independently of how /proc/sys/kernel/sysctl_writes_strict is configured.
  */
 void
-nm_platform_sysctl_set_async(NMPlatform *            self,
-                             const char *            pathid,
+nm_platform_sysctl_set_async(NMPlatform             *self,
+                             const char             *pathid,
                              int                     dirfd,
-                             const char *            path,
-                             const char *const *     values,
+                             const char             *path,
+                             const char *const      *values,
                              NMPlatformAsyncCallback callback,
                              gpointer                data,
-                             GCancellable *          cancellable)
+                             GCancellable           *cancellable)
 {
     _CHECK_SELF_VOID(self, klass);
 
@@ -717,7 +717,7 @@ nm_platform_sysctl_get_int_checked(NMPlatform *self,
                                    gint64      max,
                                    gint64      fallback)
 {
-    char * value = NULL;
+    char  *value = NULL;
     gint32 ret;
     int    errsv;
 
@@ -821,7 +821,7 @@ int
 nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(NMPlatform *self,
                                               const char *ifname,
                                               gboolean    consider_all,
-                                              gboolean *  out_due_to_all)
+                                              gboolean   *out_due_to_all)
 {
     int val, val_all;
 
@@ -899,11 +899,11 @@ _link_get_all_presort(gconstpointer p_a, gconstpointer p_b, gpointer sort_by_nam
 GPtrArray *
 nm_platform_link_get_all(NMPlatform *self, gboolean sort_by_name)
 {
-    gs_unref_ptrarray GPtrArray *links = NULL;
-    GPtrArray *                  result;
-    guint                        i, nresult;
+    gs_unref_ptrarray GPtrArray   *links = NULL;
+    GPtrArray                     *result;
+    guint                          i, nresult;
     gs_unref_hashtable GHashTable *unseen = NULL;
-    const NMPlatformLink *         item;
+    const NMPlatformLink          *item;
     NMPLookup                      lookup;
 
     _CHECK_SELF(self, klass, NULL);
@@ -1077,7 +1077,7 @@ struct _nm_platform_link_get_by_address_data {
 };
 
 static gboolean
-_nm_platform_link_get_by_address_match_link(const NMPObject *                             obj,
+_nm_platform_link_get_by_address_match_link(const NMPObject                              *obj,
                                             struct _nm_platform_link_get_by_address_data *d)
 {
     return obj->link.l_address.len == d->len && !memcmp(obj->link.l_address.data, d->data, d->len);
@@ -1093,12 +1093,12 @@ _nm_platform_link_get_by_address_match_link(const NMPObject *
  * address.
  **/
 const NMPlatformLink *
-nm_platform_link_get_by_address(NMPlatform *  self,
+nm_platform_link_get_by_address(NMPlatform   *self,
                                 NMLinkType    link_type,
                                 gconstpointer address,
                                 size_t        length)
 {
-    const NMPObject *                            obj;
+    const NMPObject                             *obj;
     struct _nm_platform_link_get_by_address_data d = {
         .data = address,
         .len  = length,
@@ -1125,8 +1125,8 @@ nm_platform_link_get_by_address(NMPlatform *  self,
 }
 
 static int
-_link_add_check_existing(NMPlatform *           self,
-                         const char *           name,
+_link_add_check_existing(NMPlatform            *self,
+                         const char            *name,
                          NMLinkType             type,
                          const NMPlatformLink **out_link)
 {
@@ -1174,11 +1174,11 @@ _link_add_check_existing(NMPlatform *           self,
  * Returns: the negative nm-error on failure.
  */
 int
-nm_platform_link_add(NMPlatform *           self,
+nm_platform_link_add(NMPlatform            *self,
                      NMLinkType             type,
-                     const char *           name,
+                     const char            *name,
                      int                    parent,
-                     const void *           address,
+                     const void            *address,
                      size_t                 address_len,
                      guint32                mtu,
                      gconstpointer          extra_data,
@@ -1439,13 +1439,13 @@ nm_platform_link_get_type_name(NMPlatform *self, int ifindex)
 }
 
 gboolean
-nm_platform_link_get_udev_property(NMPlatform * self,
+nm_platform_link_get_udev_property(NMPlatform  *self,
                                    int          ifindex,
-                                   const char * name,
+                                   const char  *name,
                                    const char **out_value)
 {
     struct udev_device *udevice = NULL;
-    const char *        uproperty;
+    const char         *uproperty;
 
     udevice = nm_platform_link_get_udev_device(self, ifindex);
     if (!udevice)
@@ -1717,7 +1717,7 @@ nm_platform_link_get_address(NMPlatform *self, int ifindex, size_t *length)
  * address.
  */
 gboolean
-nm_platform_link_get_permanent_address_ethtool(NMPlatform *    self,
+nm_platform_link_get_permanent_address_ethtool(NMPlatform     *self,
                                                int             ifindex,
                                                NMPLinkAddress *out_address)
 {
@@ -1735,9 +1735,9 @@ nm_platform_link_get_permanent_address_ethtool(NMPlatform *    self,
 }
 
 gboolean
-nm_platform_link_get_permanent_address(NMPlatform *          self,
+nm_platform_link_get_permanent_address(NMPlatform           *self,
                                        const NMPlatformLink *plink,
-                                       NMPLinkAddress *      out_address)
+                                       NMPLinkAddress       *out_address)
 {
     _CHECK_SELF(self, klass, FALSE);
     nm_assert(out_address);
@@ -1804,13 +1804,13 @@ nm_platform_link_supports_sriov(NMPlatform *self, int ifindex)
  * always invoked, and asynchronously.
  */
 void
-nm_platform_link_set_sriov_params_async(NMPlatform *            self,
+nm_platform_link_set_sriov_params_async(NMPlatform             *self,
                                         int                     ifindex,
                                         guint                   num_vfs,
                                         NMOptionBool            autoprobe,
                                         NMPlatformAsyncCallback callback,
                                         gpointer                callback_data,
-                                        GCancellable *          cancellable)
+                                        GCancellable           *cancellable)
 {
     _CHECK_SELF_VOID(self, klass);
 
@@ -1845,7 +1845,7 @@ nm_platform_link_set_sriov_vfs(NMPlatform *self, int ifindex, const NMPlatformVF
 }
 
 gboolean
-nm_platform_link_set_bridge_vlans(NMPlatform *                       self,
+nm_platform_link_set_bridge_vlans(NMPlatform                        *self,
                                   int                                ifindex,
                                   gboolean                           on_master,
                                   const NMPlatformBridgeVlan *const *vlans)
@@ -2038,9 +2038,9 @@ nm_platform_link_get_wake_on_lan(NMPlatform *self, int ifindex)
 gboolean
 nm_platform_link_get_driver_info(NMPlatform *self,
                                  int         ifindex,
-                                 char **     out_driver_name,
-                                 char **     out_driver_version,
-                                 char **     out_fw_version)
+                                 char      **out_driver_name,
+                                 char      **out_driver_version,
+                                 char      **out_fw_version)
 {
     _CHECK_SELF(self, klass, FALSE);
 
@@ -2149,7 +2149,7 @@ nm_platform_link_can_assume(NMPlatform *self, int ifindex)
  * (but don't modify it).
  */
 const NMPObject *
-nm_platform_link_get_lnk(NMPlatform *           self,
+nm_platform_link_get_lnk(NMPlatform            *self,
                          int                    ifindex,
                          NMLinkType             link_type,
                          const NMPlatformLink **out_link)
@@ -2308,10 +2308,10 @@ static NM_UTILS_FLAGS2STR_DEFINE(
     NM_UTILS_FLAGS2STR(NM_PLATFORM_WIREGUARD_CHANGE_PEER_FLAG_REPLACE_ALLOWEDIPS, "remove-aips"), );
 
 int
-nm_platform_link_wireguard_change(NMPlatform *                              self,
+nm_platform_link_wireguard_change(NMPlatform                               *self,
                                   int                                       ifindex,
-                                  const NMPlatformLnkWireGuard *            lnk_wireguard,
-                                  const NMPWireGuardPeer *                  peers,
+                                  const NMPlatformLnkWireGuard             *lnk_wireguard,
+                                  const NMPWireGuardPeer                   *peers,
                                   const NMPlatformWireGuardChangePeerFlags *peer_flags,
                                   guint                                     peers_len,
                                   NMPlatformWireGuardChangeFlags            change_flags)
@@ -2391,11 +2391,11 @@ nm_platform_link_wireguard_change(NMPlatform *                              self
  * Create a TUN or TAP interface.
  */
 int
-nm_platform_link_tun_add(NMPlatform *            self,
-                         const char *            name,
+nm_platform_link_tun_add(NMPlatform             *self,
+                         const char             *name,
                          const NMPlatformLnkTun *props,
-                         const NMPlatformLink ** out_link,
-                         int *                   out_fd)
+                         const NMPlatformLink  **out_link,
+                         int                    *out_fd)
 {
     char b[255];
     int  r;
@@ -2466,7 +2466,7 @@ link_set_option(NMPlatform *self,
 {
     nm_auto_close int dirfd = -1;
     char              ifname_verified[IFNAMSIZ];
-    const char *      path;
+    const char       *path;
 
     if (!category || !option)
         return FALSE;
@@ -2487,7 +2487,7 @@ link_get_option(NMPlatform *self, int ifindex, const char *category, const char
 {
     nm_auto_close int dirfd = -1;
     char              ifname_verified[IFNAMSIZ];
-    const char *      path;
+    const char       *path;
 
     if (!category || !option)
         return NULL;
@@ -2588,7 +2588,7 @@ nm_platform_sysctl_slave_get_option(NMPlatform *self, int ifindex, const char *o
 /*****************************************************************************/
 
 gboolean
-nm_platform_link_vlan_change(NMPlatform *            self,
+nm_platform_link_vlan_change(NMPlatform             *self,
                              int                     ifindex,
                              _NMVlanFlags            flags_mask,
                              _NMVlanFlags            flags_set,
@@ -2680,7 +2680,7 @@ nm_platform_link_vlan_set_egress_map(NMPlatform *self, int ifindex, int from, in
 }
 
 static int
-_infiniband_add_add_or_delete(NMPlatform *           self,
+_infiniband_add_add_or_delete(NMPlatform            *self,
                               int                    ifindex,
                               int                    p_key,
                               gboolean               add,
@@ -2727,7 +2727,7 @@ _infiniband_add_add_or_delete(NMPlatform *           self,
 }
 
 int
-nm_platform_link_infiniband_add(NMPlatform *           self,
+nm_platform_link_infiniband_add(NMPlatform            *self,
                                 int                    parent,
                                 int                    p_key,
                                 const NMPlatformLink **out_link)
@@ -2742,18 +2742,18 @@ nm_platform_link_infiniband_delete(NMPlatform *self, int parent, int p_key)
 }
 
 gboolean
-nm_platform_link_infiniband_get_properties(NMPlatform * self,
+nm_platform_link_infiniband_get_properties(NMPlatform  *self,
                                            int          ifindex,
-                                           int *        out_parent,
-                                           int *        out_p_key,
+                                           int         *out_parent,
+                                           int         *out_p_key,
                                            const char **out_mode)
 {
     nm_auto_close int              dirfd = -1;
     char                           ifname_verified[IFNAMSIZ];
     const NMPlatformLnkInfiniband *plnk;
-    const NMPlatformLink *         plink;
-    char *                         contents;
-    const char *                   mode;
+    const NMPlatformLink          *plink;
+    char                          *contents;
+    const char                    *mode;
     int                            p_key = 0;
 
     _CHECK_SELF(self, klass, FALSE);
@@ -2968,11 +2968,11 @@ nm_platform_wifi_get_frequency(NMPlatform *self, int ifindex)
 }
 
 gboolean
-nm_platform_wifi_get_station(NMPlatform * self,
+nm_platform_wifi_get_station(NMPlatform  *self,
                              int          ifindex,
                              NMEtherAddr *out_bssid,
-                             int *        out_quality,
-                             guint32 *    out_rate)
+                             int         *out_quality,
+                             guint32     *out_rate)
 {
     _CHECK_SELF(self, klass, FALSE);
 
@@ -3143,11 +3143,12 @@ nm_platform_wpan_set_channel(NMPlatform *self, int ifindex, guint8 page, guint8
 static const char *
 _to_string_dev(NMPlatform *self, int ifindex, char *buf, size_t size)
 {
-    g_assert(buf && size >= TO_STRING_DEV_BUF_SIZE);
+    nm_assert(buf);
+    nm_assert(size >= TO_STRING_DEV_BUF_SIZE);
 
     if (ifindex) {
         const char *name = ifindex > 0 && self ? nm_platform_link_get_name(self, ifindex) : NULL;
-        char *      buf2;
+        char       *buf2;
 
         strcpy(buf, " dev ");
         buf2 = buf + 5;
@@ -3188,10 +3189,10 @@ _to_string_ifa_flags(guint32 ifa_flags, char *buf, gsize size)
 /*****************************************************************************/
 
 gboolean
-nm_platform_ethtool_set_wake_on_lan(NMPlatform *             self,
+nm_platform_ethtool_set_wake_on_lan(NMPlatform              *self,
                                     int                      ifindex,
                                     _NMSettingWiredWakeOnLan wol,
-                                    const char *             wol_password)
+                                    const char              *wol_password)
 {
     _CHECK_SELF_NETNS(self, klass, netns, FALSE);
 
@@ -3201,7 +3202,7 @@ nm_platform_ethtool_set_wake_on_lan(NMPlatform *             self,
 }
 
 gboolean
-nm_platform_ethtool_set_link_settings(NMPlatform *             self,
+nm_platform_ethtool_set_link_settings(NMPlatform              *self,
                                       int                      ifindex,
                                       gboolean                 autoneg,
                                       guint32                  speed,
@@ -3215,10 +3216,10 @@ nm_platform_ethtool_set_link_settings(NMPlatform *             self,
 }
 
 gboolean
-nm_platform_ethtool_get_link_settings(NMPlatform *              self,
+nm_platform_ethtool_get_link_settings(NMPlatform               *self,
                                       int                       ifindex,
-                                      gboolean *                out_autoneg,
-                                      guint32 *                 out_speed,
+                                      gboolean                 *out_autoneg,
+                                      guint32                  *out_speed,
                                       NMPlatformLinkDuplexType *out_duplex)
 {
     _CHECK_SELF_NETNS(self, klass, netns, FALSE);
@@ -3242,7 +3243,7 @@ nm_platform_ethtool_get_link_features(NMPlatform *self, int ifindex)
 
 gboolean
 nm_platform_ethtool_set_features(
-    NMPlatform *                  self,
+    NMPlatform                   *self,
     int                           ifindex,
     const NMEthtoolFeatureStates *features,
     const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
@@ -3256,7 +3257,7 @@ nm_platform_ethtool_set_features(
 }
 
 gboolean
-nm_platform_ethtool_get_link_coalesce(NMPlatform *            self,
+nm_platform_ethtool_get_link_coalesce(NMPlatform             *self,
                                       int                     ifindex,
                                       NMEthtoolCoalesceState *coalesce)
 {
@@ -3269,7 +3270,7 @@ nm_platform_ethtool_get_link_coalesce(NMPlatform *            self,
 }
 
 gboolean
-nm_platform_ethtool_set_coalesce(NMPlatform *                  self,
+nm_platform_ethtool_set_coalesce(NMPlatform                   *self,
                                  int                           ifindex,
                                  const NMEthtoolCoalesceState *coalesce)
 {
@@ -3380,8 +3381,8 @@ nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel(const NMPObject *obj
  * Returns: the result of the lookup.
  */
 GPtrArray *
-nm_platform_lookup_clone(NMPlatform *           self,
-                         const NMPLookup *      lookup,
+nm_platform_lookup_clone(NMPlatform            *self,
+                         const NMPLookup       *lookup,
                          NMPObjectPredicateFunc predicate,
                          gpointer               user_data)
 {
@@ -3511,7 +3512,7 @@ nm_platform_ip4_address_add(NMPlatform *self,
 }
 
 gboolean
-nm_platform_ip6_address_add(NMPlatform *    self,
+nm_platform_ip6_address_add(NMPlatform     *self,
                             int             ifindex,
                             struct in6_addr address,
                             guint8          plen,
@@ -3630,7 +3631,7 @@ nm_platform_ip6_address_get(NMPlatform *self, int ifindex, const struct in6_addr
 static gboolean
 _addr_array_clean_expired(int          addr_family,
                           int          ifindex,
-                          GPtrArray *  array,
+                          GPtrArray   *array,
                           guint32      now,
                           GHashTable **idx)
 {
@@ -3748,7 +3749,7 @@ ip4_addr_subnets_build_index(const GPtrArray *addresses,
     for (i = 0; i < addresses->len; i++) {
         const NMPlatformIP4Address *address;
         gpointer                    p_address;
-        GPtrArray *                 addr_list;
+        GPtrArray                  *addr_list;
         guint32                     net;
         int                         position;
         gpointer                    p;
@@ -3805,16 +3806,16 @@ ip4_addr_subnets_build_index(const GPtrArray *addresses,
  * Returns: %TRUE if the address is secondary, %FALSE otherwise
  */
 static gboolean
-ip4_addr_subnets_is_secondary(const NMPObject * address,
-                              GHashTable *      subnets,
-                              const GPtrArray * addresses,
+ip4_addr_subnets_is_secondary(const NMPObject  *address,
+                              GHashTable       *subnets,
+                              const GPtrArray  *addresses,
                               const GPtrArray **out_addr_list)
 {
     const NMPlatformIP4Address *a;
-    const GPtrArray *           addr_list;
+    const GPtrArray            *addr_list;
     gconstpointer               p;
     guint32                     net;
-    const NMPObject **          o;
+    const NMPObject           **o;
 
     a = NMP_OBJECT_CAST_IP4_ADDRESS(address);
 
@@ -3902,14 +3903,14 @@ gboolean
 nm_platform_ip_address_sync(NMPlatform *self,
                             int         addr_family,
                             int         ifindex,
-                            GPtrArray * known_addresses,
-                            GPtrArray * addresses_prune)
+                            GPtrArray  *known_addresses,
+                            GPtrArray  *addresses_prune)
 {
-    const gint32       now                             = nm_utils_get_monotonic_timestamp_sec();
-    const int          IS_IPv4                         = NM_IS_IPv4(addr_family);
+    const gint32                   now                 = nm_utils_get_monotonic_timestamp_sec();
+    const int                      IS_IPv4             = NM_IS_IPv4(addr_family);
     gs_unref_hashtable GHashTable *known_addresses_idx = NULL;
-    GPtrArray *                    plat_addresses;
-    GHashTable *                   known_subnets = NULL;
+    GPtrArray                     *plat_addresses;
+    GHashTable                    *known_subnets = NULL;
     guint                          i_plat;
     guint                          i_know;
     guint                          i;
@@ -3947,9 +3948,9 @@ nm_platform_ip_address_sync(NMPlatform *self,
             plat_subnets = ip4_addr_subnets_build_index(plat_addresses, TRUE, TRUE);
 
             for (i = 0; i < plat_addresses->len; i++) {
-                const NMPObject *           plat_obj;
+                const NMPObject            *plat_obj;
                 const NMPlatformIP4Address *plat_address;
-                const GPtrArray *           addr_list;
+                const GPtrArray            *addr_list;
 
                 plat_obj = plat_addresses->pdata[i];
                 if (!plat_obj) {
@@ -4044,8 +4045,8 @@ nm_platform_ip_address_sync(NMPlatform *self,
              *
              * Note that we mark handled addresses by setting it to %NULL in @plat_addresses array. */
             for (i_plat = 0; i_plat < plat_addresses->len; i_plat++) {
-                const NMPObject *           plat_obj = plat_addresses->pdata[i_plat];
-                const NMPObject *           know_obj;
+                const NMPObject            *plat_obj = plat_addresses->pdata[i_plat];
+                const NMPObject            *know_obj;
                 const NMPlatformIP6Address *plat_addr = NMP_OBJECT_CAST_IP6_ADDRESS(plat_obj);
 
                 if (known_addresses_idx) {
@@ -4141,7 +4142,7 @@ next_plat:;
      */
     for (i_know = 0; i_know < known_addresses->len; i_know++) {
         const NMPlatformIPXAddress *known_address;
-        const NMPObject *           o;
+        const NMPObject            *o;
         guint32                     lifetime;
         guint32                     preferred;
 
@@ -4211,7 +4212,7 @@ nm_platform_ip_address_flush(NMPlatform *self, int addr_family, int ifindex)
 static gboolean
 _err_inval_due_to_ipv6_tentative_pref_src(NMPlatform *self, const NMPObject *obj)
 {
-    const NMPlatformIP6Route *  r;
+    const NMPlatformIP6Route   *r;
     const NMPlatformIP6Address *a;
 
     nm_assert(NM_IS_PLATFORM(self));
@@ -4253,8 +4254,8 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self,
     const int                    IS_IPv4 = NM_IS_IPv4(addr_family);
     const NMDedupMultiHeadEntry *head_entry;
     NMPLookup                    lookup;
-    GPtrArray *                  result;
-    CList *                      iter;
+    GPtrArray                   *result;
+    CList                       *iter;
 
     nmp_lookup_init_object(&lookup, NMP_OBJECT_TYPE_IP_ADDRESS(NM_IS_IPv4(addr_family)), ifindex);
 
@@ -4285,20 +4286,20 @@ nm_platform_ip_address_get_prune_list(NMPlatform *self,
 }
 
 GPtrArray *
-nm_platform_ip_route_get_prune_list(NMPlatform *           self,
+nm_platform_ip_route_get_prune_list(NMPlatform            *self,
                                     int                    addr_family,
                                     int                    ifindex,
                                     NMIPRouteTableSyncMode route_table_sync)
 {
     NMPLookup                    lookup;
-    GPtrArray *                  routes_prune;
+    GPtrArray                   *routes_prune;
     const NMDedupMultiHeadEntry *head_entry;
-    CList *                      iter;
+    CList                       *iter;
     NMPlatformIP4Route           rt_local4;
     NMPlatformIP6Route           rt_local6;
     NMPlatformIP6Route           rt_mcast6;
-    const NMPlatformLink *       pllink;
-    const NMPlatformLnkVrf *     lnk_vrf;
+    const NMPlatformLink        *pllink;
+    const NMPlatformLnkVrf      *lnk_vrf;
     guint32                      local_table;
 
     nm_assert(NM_IS_PLATFORM(self));
@@ -4326,7 +4327,7 @@ nm_platform_ip_route_get_prune_list(NMPlatform *           self,
     routes_prune = g_ptr_array_new_full(head_entry->len, (GDestroyNotify) nm_dedup_multi_obj_unref);
 
     c_list_for_each (iter, &head_entry->lst_entries_head) {
-        const NMPObject *         obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
+        const NMPObject          *obj = c_list_entry(iter, NMDedupMultiEntry, lst_entries)->obj;
         const NMPlatformIPXRoute *rt  = NMP_OBJECT_CAST_IPX_ROUTE(obj);
 
         switch (route_table_sync) {
@@ -4493,15 +4494,15 @@ gboolean
 nm_platform_ip_route_sync(NMPlatform *self,
                           int         addr_family,
                           int         ifindex,
-                          GPtrArray * routes,
-                          GPtrArray * routes_prune,
+                          GPtrArray  *routes,
+                          GPtrArray  *routes_prune,
                           GPtrArray **out_temporary_not_available)
 {
-    const int                    IS_IPv4 = NM_IS_IPv4(addr_family);
-    const NMPlatformVTableRoute *vt;
+    const int                      IS_IPv4 = NM_IS_IPv4(addr_family);
+    const NMPlatformVTableRoute   *vt;
     gs_unref_hashtable GHashTable *routes_idx = NULL;
-    const NMPObject *              conf_o;
-    const NMDedupMultiEntry *      plat_entry;
+    const NMPObject               *conf_o;
+    const NMDedupMultiEntry       *plat_entry;
     guint                          i;
     int                            i_type;
     gboolean                       success = TRUE;
@@ -4520,12 +4521,6 @@ nm_platform_ip_route_sync(NMPlatform *self,
 
             conf_o = routes->pdata[i];
 
-            if (NMP_OBJECT_CAST_IP_ROUTE(conf_o)->is_external) {
-                /* This route is added externally. We don't have our own agenda to
-                 * add it, so skip. */
-                continue;
-            }
-
             /* User space cannot add IPv6 routes with metric 0. However, kernel can, and we might track such
              * routes in @route as they are present external. As we already skipped external routes above,
              * we don't expect a user's choice to add such a route (it won't work anyway). */
@@ -4721,24 +4716,6 @@ sync_route_add:
     }
 
     if (routes_prune) {
-        if (routes) {
-            for (i = 0; i < routes->len; i++) {
-                conf_o = routes->pdata[i];
-
-                if (NMP_OBJECT_CAST_IP_ROUTE(conf_o)->is_external) {
-                    /* this is only to catch the case where an external route is
-                     * both in @routes and @routes_prune list. In that case,
-                     * @routes should win and we should not remove the address. */
-                    if (!routes_idx) {
-                        routes_idx = g_hash_table_new((GHashFunc) nmp_object_id_hash,
-                                                      (GEqualFunc) nmp_object_id_equal);
-                    }
-                    g_hash_table_add(routes_idx, (gpointer) conf_o);
-                    continue;
-                }
-            }
-        }
-
         for (i = 0; i < routes_prune->len; i++) {
             const NMPObject *prune_o;
 
@@ -4958,11 +4935,11 @@ nm_platform_object_delete(NMPlatform *self, const NMPObject *obj)
 /*****************************************************************************/
 
 int
-nm_platform_ip_route_get(NMPlatform *  self,
+nm_platform_ip_route_get(NMPlatform   *self,
                          int           addr_family,
                          gconstpointer address /* in_addr_t or struct in6_addr */,
                          int           oif_ifindex,
-                         NMPObject **  out_route)
+                         NMPObject   **out_route)
 {
     nm_auto_nmpobj NMPObject *route = NULL;
     int                       result;
@@ -5027,11 +5004,11 @@ _ip4_dev_route_blacklist_timeout_ms_marked(gint64 timeout_msec)
 static gboolean
 _ip4_dev_route_blacklist_check_cb(gpointer user_data)
 {
-    NMPlatform *       self = user_data;
+    NMPlatform        *self = user_data;
     NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
     GHashTableIter     iter;
-    const NMPObject *  p_obj;
-    gint64 *           p_timeout_ms;
+    const NMPObject   *p_obj;
+    gint64            *p_timeout_ms;
     gint64             now_ms;
 
     priv->ip4_dev_route_blacklist_check_id = 0;
@@ -5081,8 +5058,8 @@ static void
 _ip4_dev_route_blacklist_notify_route(NMPlatform *self, const NMPObject *obj)
 {
     NMPlatformPrivate *priv;
-    const NMPObject *  p_obj;
-    gint64 *           p_timeout_ms;
+    const NMPObject   *p_obj;
+    gint64            *p_timeout_ms;
     gint64             now_ms;
 
     nm_assert(NM_IS_PLATFORM(self));
@@ -5120,11 +5097,11 @@ _ip4_dev_route_blacklist_notify_route(NMPlatform *self, const NMPObject *obj)
 static gboolean
 _ip4_dev_route_blacklist_gc_timeout_handle(gpointer user_data)
 {
-    NMPlatform *       self = user_data;
+    NMPlatform        *self = user_data;
     NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
     GHashTableIter     iter;
-    const NMPObject *  p_obj;
-    gint64 *           p_timeout_ms;
+    const NMPObject   *p_obj;
+    gint64            *p_timeout_ms;
     gint64             now_ms;
 
     nm_assert(priv->ip4_dev_route_blacklist_gc_timeout_id);
@@ -5193,15 +5170,15 @@ _ip4_dev_route_blacklist_schedule(NMPlatform *self)
 void
 nm_platform_ip4_dev_route_blacklist_set(NMPlatform *self,
                                         int         ifindex,
-                                        GPtrArray * ip4_dev_route_blacklist)
+                                        GPtrArray  *ip4_dev_route_blacklist)
 {
     NMPlatformPrivate *priv;
     GHashTableIter     iter;
-    const NMPObject *  p_obj;
+    const NMPObject   *p_obj;
     guint              i;
     gint64             timeout_msec;
     gint64             timeout_msec_val;
-    gint64 *           p_timeout_ms;
+    gint64            *p_timeout_ms;
     gboolean           needs_check = FALSE;
 
     nm_assert(NM_IS_PLATFORM(self));
@@ -5275,7 +5252,7 @@ nm_platform_ip4_dev_route_blacklist_set(NMPlatform *self,
 /*****************************************************************************/
 
 int
-nm_platform_routing_rule_add(NMPlatform *                 self,
+nm_platform_routing_rule_add(NMPlatform                  *self,
                              NMPNlmFlags                  flags,
                              const NMPlatformRoutingRule *routing_rule)
 {
@@ -5355,8 +5332,8 @@ nm_platform_tfilter_delete(NMPlatform *self, int ifindex, guint32 parent, gboole
 gboolean
 nm_platform_tc_sync(NMPlatform *self,
                     int         ifindex,
-                    GPtrArray * known_qdiscs,
-                    GPtrArray * known_tfilters)
+                    GPtrArray  *known_qdiscs,
+                    GPtrArray  *known_tfilters)
 {
     guint    i;
     gboolean success = TRUE;
@@ -5397,10 +5374,10 @@ nm_platform_tc_sync(NMPlatform *self,
 /*****************************************************************************/
 
 const char *
-nm_platform_vlan_qos_mapping_to_string(const char *            name,
+nm_platform_vlan_qos_mapping_to_string(const char             *name,
                                        const NMVlanQosMapping *map,
                                        gsize                   n_map,
-                                       char *                  buf,
+                                       char                   *buf,
                                        gsize                   len)
 {
     gsize i;
@@ -5448,7 +5425,7 @@ _lifetime_summary_to_string(gint32  now,
                             guint32 timestamp,
                             guint32 preferred,
                             guint32 lifetime,
-                            char *  buf,
+                            char   *buf,
                             size_t  buf_size)
 {
     g_snprintf(buf,
@@ -5478,7 +5455,7 @@ nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len)
     char        parent[20];
     char        str_flags[1 + NM_PLATFORM_LINK_FLAGS2STR_MAX_LEN + 1];
     char        str_highlighted_flags[50];
-    char *      s;
+    char       *s;
     gsize       l;
     char        str_addrmode[30];
     char        str_address[_NM_UTILS_HWADDR_LEN_MAX * 3];
@@ -6109,7 +6086,7 @@ nm_platform_lnk_vxlan_to_string(const NMPlatformLnkVxlan *lnk, char *buf, gsize
 const char *
 nm_platform_wireguard_peer_to_string(const NMPWireGuardPeer *peer, char *buf, gsize len)
 {
-    char *        buf0           = buf;
+    char         *buf0           = buf;
     gs_free char *public_key_b64 = NULL;
     char          s_sockaddr[NM_UTILS_INET_ADDRSTRLEN + 100];
     char          s_endpoint[20 + sizeof(s_sockaddr)];
@@ -6214,7 +6191,7 @@ nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf
     char        str_dev[TO_STRING_DEV_BUF_SIZE];
     char        str_label[32];
     char        str_lft[30], str_pref[30], str_time[50], s_source[50];
-    char *      str_peer = NULL;
+    char       *str_peer = NULL;
     const char *str_lft_p, *str_pref_p, *str_time_p;
     gint32      now = nm_utils_get_monotonic_timestamp_sec();
     in_addr_t   broadcast_address;
@@ -6273,9 +6250,9 @@ nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf
         "%s" /* flags */
         "%s" /* label */
         " src %s"
-        "%s" /* external */
         "%s" /* a_acd_not_ready */
         "%s" /* a_assume_config_once */
+        "%s" /* a_force_commit */
         "",
         s_address,
         address->plen,
@@ -6293,9 +6270,9 @@ nm_platform_ip4_address_to_string(const NMPlatformIP4Address *address, char *buf
         _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)),
         str_label,
         nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)),
-        address->external ? " ext" : "",
         address->a_acd_not_ready ? " ip4acd-not-ready" : "",
-        address->a_assume_config_once ? " assume-config-once" : "");
+        address->a_assume_config_once ? " assume-config-once" : "",
+        address->a_force_commit ? " force-commit" : "");
     g_free(str_peer);
     return buf;
 }
@@ -6374,7 +6351,7 @@ nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf
     char        s_peer[INET6_ADDRSTRLEN];
     char        str_lft[30], str_pref[30], str_time[50], s_source[50];
     char        str_dev[TO_STRING_DEV_BUF_SIZE];
-    char *      str_peer = NULL;
+    char       *str_peer = NULL;
     const char *str_lft_p, *str_pref_p, *str_time_p;
     gint32      now = nm_utils_get_monotonic_timestamp_sec();
 
@@ -6415,8 +6392,8 @@ nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf
         buf,
         len,
         "%s/%d lft %s pref %s%s%s%s%s src %s"
-        "%s" /* external */
         "%s" /* a_assume_config_once */
+        "%s" /* a_force_commit */
         "",
         s_address,
         address->plen,
@@ -6427,8 +6404,8 @@ nm_platform_ip6_address_to_string(const NMPlatformIP6Address *address, char *buf
         str_dev,
         _to_string_ifa_flags(address->n_ifa_flags, s_flags, sizeof(s_flags)),
         nmp_utils_ip_config_source_to_string(address->addr_source, s_source, sizeof(s_source)),
-        address->external ? " external" : "",
-        address->a_assume_config_once ? " assume-config-once" : "");
+        address->a_assume_config_once ? " assume-config-once" : "",
+        address->a_force_commit ? " force-commit" : "");
     g_free(str_peer);
     return buf;
 }
@@ -6482,12 +6459,19 @@ _rtm_flags_to_string_full(char *buf, gsize buf_size, unsigned rtm_flags)
 const char *
 nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsize len)
 {
-    char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN];
+    char s_network[INET_ADDRSTRLEN];
+    char s_gateway[INET_ADDRSTRLEN];
     char s_pref_src[INET_ADDRSTRLEN];
     char str_dev[TO_STRING_DEV_BUF_SIZE];
     char str_table[30];
-    char str_scope[30], s_source[50];
-    char str_tos[32], str_window[32], str_cwnd[32], str_initcwnd[32], str_initrwnd[32], str_mtu[32];
+    char str_scope[30];
+    char s_source[50];
+    char str_tos[32];
+    char str_window[32];
+    char str_cwnd[32];
+    char str_initcwnd[32];
+    char str_initrwnd[32];
+    char str_mtu[32];
     char str_rtm_flags[_RTM_FLAGS_TO_STRING_MAXLEN];
     char str_type[30];
     char str_metric[30];
@@ -6496,7 +6480,11 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
         return buf;
 
     inet_ntop(AF_INET, &route->network, s_network, sizeof(s_network));
-    inet_ntop(AF_INET, &route->gateway, s_gateway, sizeof(s_gateway));
+
+    if (route->gateway == 0)
+        s_gateway[0] = '\0';
+    else
+        inet_ntop(AF_INET, &route->gateway, s_gateway, sizeof(s_gateway));
 
     _to_string_dev(NULL, route->ifindex, str_dev, sizeof(str_dev));
 
@@ -6506,21 +6494,22 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
         "type %s " /* type */
         "%s"       /* table */
         "%s/%d"
-        " via %s"
+        "%s%s" /* gateway */
         "%s"
         " metric %s"
-        " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
-        "%s"                                   /* rtm_flags */
-        "%s%s"                                 /* scope */
-        "%s%s"                                 /* pref-src */
-        "%s"                                   /* tos */
-        "%s"                                   /* window */
-        "%s"                                   /* cwnd */
-        "%s"                                   /* initcwnd */
-        "%s"                                   /* initrwnd */
-        "%s"                                   /* mtu */
-        "%s"                                   /* is_external */
-        "%s"                                   /* r_assume_config_once */
+        " mss %" G_GUINT32_FORMAT /* mss */
+        " rt-src %s"              /* protocol */
+        "%s"                      /* rtm_flags */
+        "%s%s"                    /* scope */
+        "%s%s"                    /* pref-src */
+        "%s"                      /* tos */
+        "%s"                      /* window */
+        "%s"                      /* cwnd */
+        "%s"                      /* initcwnd */
+        "%s"                      /* initrwnd */
+        "%s"                      /* mtu */
+        "%s"                      /* r_assume_config_once */
+        "%s"                      /* r_force_commit */
         "",
         nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced),
                                               str_type),
@@ -6533,6 +6522,7 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
                    : ""),
         s_network,
         route->plen,
+        s_gateway[0] ? " via " : "",
         s_gateway,
         str_dev,
         route->metric_any
@@ -6577,8 +6567,8 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
                                                        route->lock_mtu ? "lock " : "",
                                                        route->mtu)
                                       : "",
-        route->is_external ? " is-external" : "",
-        route->r_assume_config_once ? " assume-config-once" : "");
+        route->r_assume_config_once ? " assume-config-once" : "",
+        route->r_force_commit ? " force-commit" : "");
     return buf;
 }
 
@@ -6620,7 +6610,11 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
         return buf;
 
     inet_ntop(AF_INET6, &route->network, s_network, sizeof(s_network));
-    inet_ntop(AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway));
+
+    if (IN6_IS_ADDR_UNSPECIFIED(&route->gateway))
+        s_gateway[0] = '\0';
+    else
+        inet_ntop(AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway));
 
     if (IN6_IS_ADDR_UNSPECIFIED(&route->pref_src))
         s_pref_src[0] = 0;
@@ -6635,21 +6629,22 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
         "type %s " /* type */
         "%s"       /* table */
         "%s/%d"
-        " via %s"
+        "%s%s" /* gateway */
         "%s"
         " metric %s"
-        " mss %" G_GUINT32_FORMAT " rt-src %s" /* protocol */
-        "%s"                                   /* source */
-        "%s"                                   /* rtm_flags */
-        "%s%s"                                 /* pref-src */
-        "%s"                                   /* window */
-        "%s"                                   /* cwnd */
-        "%s"                                   /* initcwnd */
-        "%s"                                   /* initrwnd */
-        "%s"                                   /* mtu */
-        "%s"                                   /* pref */
-        "%s"                                   /* is_external */
-        "%s"                                   /* r_assume_config_once */
+        " mss %" G_GUINT32_FORMAT /* mss */
+        " rt-src %s"              /* protocol */
+        "%s"                      /* source */
+        "%s"                      /* rtm_flags */
+        "%s%s"                    /* pref-src */
+        "%s"                      /* window */
+        "%s"                      /* cwnd */
+        "%s"                      /* initcwnd */
+        "%s"                      /* initrwnd */
+        "%s"                      /* mtu */
+        "%s"                      /* pref */
+        "%s"                      /* r_assume_config_once */
+        "%s"                      /* r_force_commit */
         "",
         nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced),
                                               str_type),
@@ -6662,6 +6657,7 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
                    : ""),
         s_network,
         route->plen,
+        s_gateway[0] ? " via " : "",
         s_gateway,
         str_dev,
         route->metric_any
@@ -6710,15 +6706,15 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
             " pref %s",
             nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
                        : "",
-        route->is_external ? " is-external" : "",
-        route->r_assume_config_once ? " assume-config-once" : "");
+        route->r_assume_config_once ? " assume-config-once" : "",
+        route->r_force_commit ? " force-commit" : "");
 
     return buf;
 }
 
 static void
-_routing_rule_addr_to_string(char **         buf,
-                             gsize *         len,
+_routing_rule_addr_to_string(char          **buf,
+                             gsize          *len,
                              int             addr_family,
                              const NMIPAddr *addr,
                              guint8          plen,
@@ -6752,10 +6748,10 @@ _routing_rule_addr_to_string(char **         buf,
 }
 
 static void
-_routing_rule_port_range_to_string(char **                   buf,
-                                   gsize *                   len,
+_routing_rule_port_range_to_string(char                    **buf,
+                                   gsize                    *len,
                                    const NMFibRulePortRange *port_range,
-                                   const char *              name)
+                                   const char               *name)
 {
     if (port_range->start == 0 && port_range->end == 0)
         nm_strbuf_append_str(buf, len, "");
@@ -7179,11 +7175,11 @@ nm_platform_tfilter_cmp(const NMPlatformTfilter *a, const NMPlatformTfilter *b)
 const char *
 nm_platform_vf_to_string(const NMPlatformVF *vf, char *buf, gsize len)
 {
-    char                 str_mac[128], mac[128];
-    char                 str_spoof_check[64];
-    char                 str_trust[64];
-    char                 str_min_tx_rate[64];
-    char                 str_max_tx_rate[64];
+    char                          str_mac[128], mac[128];
+    char                          str_spoof_check[64];
+    char                          str_trust[64];
+    char                          str_min_tx_rate[64];
+    char                          str_max_tx_rate[64];
     nm_auto_free_gstring GString *gstr_vlans = NULL;
     guint                         i;
 
@@ -7845,10 +7841,10 @@ nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHashState
                         obj->address,
                         obj->peer_address,
                         NM_HASH_COMBINE_BOOLS(guint8,
-                                              obj->external,
                                               obj->use_ip4_broadcast_address,
                                               obj->a_acd_not_ready,
-                                              obj->a_assume_config_once));
+                                              obj->a_assume_config_once,
+                                              obj->a_force_commit));
     nm_hash_update_strarr(h, obj->label);
 }
 
@@ -7869,26 +7865,27 @@ nm_platform_ip4_address_cmp(const NMPlatformIP4Address *a, const NMPlatformIP4Ad
     NM_CMP_FIELD(a, b, preferred);
     NM_CMP_FIELD(a, b, n_ifa_flags);
     NM_CMP_FIELD_STR(a, b, label);
-    NM_CMP_FIELD_UNSAFE(a, b, external);
     NM_CMP_FIELD_UNSAFE(a, b, a_acd_not_ready);
     NM_CMP_FIELD_UNSAFE(a, b, a_assume_config_once);
+    NM_CMP_FIELD_UNSAFE(a, b, a_force_commit);
     return 0;
 }
 
 void
 nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h)
 {
-    nm_hash_update_vals(h,
-                        obj->ifindex,
-                        obj->addr_source,
-                        obj->timestamp,
-                        obj->lifetime,
-                        obj->preferred,
-                        obj->n_ifa_flags,
-                        obj->plen,
-                        obj->address,
-                        obj->peer_address,
-                        NM_HASH_COMBINE_BOOLS(guint8, obj->external, obj->a_assume_config_once));
+    nm_hash_update_vals(
+        h,
+        obj->ifindex,
+        obj->addr_source,
+        obj->timestamp,
+        obj->lifetime,
+        obj->preferred,
+        obj->n_ifa_flags,
+        obj->plen,
+        obj->address,
+        obj->peer_address,
+        NM_HASH_COMBINE_BOOLS(guint8, obj->a_assume_config_once, obj->a_force_commit));
 }
 
 int
@@ -7908,15 +7905,15 @@ nm_platform_ip6_address_cmp(const NMPlatformIP6Address *a, const NMPlatformIP6Ad
     NM_CMP_FIELD(a, b, lifetime);
     NM_CMP_FIELD(a, b, preferred);
     NM_CMP_FIELD(a, b, n_ifa_flags);
-    NM_CMP_FIELD_UNSAFE(a, b, external);
     NM_CMP_FIELD_UNSAFE(a, b, a_assume_config_once);
+    NM_CMP_FIELD_UNSAFE(a, b, a_force_commit);
     return 0;
 }
 
 void
 nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
                                   NMPlatformIPRouteCmpType  cmp_type,
-                                  NMHashState *             h)
+                                  NMHashState              *h)
 {
     switch (cmp_type) {
     case NM_PLATFORM_IP_ROUTE_CMP_TYPE_WEAK_ID:
@@ -8018,8 +8015,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
                                                   obj->lock_initcwnd,
                                                   obj->lock_initrwnd,
                                                   obj->lock_mtu,
-                                                  obj->is_external,
-                                                  obj->r_assume_config_once));
+                                                  obj->r_assume_config_once,
+                                                  obj->r_force_commit));
         break;
     }
 }
@@ -8110,8 +8107,8 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
         NM_CMP_FIELD(a, b, initrwnd);
         NM_CMP_FIELD(a, b, mtu);
         if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) {
-            NM_CMP_FIELD_UNSAFE(a, b, is_external);
             NM_CMP_FIELD_UNSAFE(a, b, r_assume_config_once);
+            NM_CMP_FIELD_UNSAFE(a, b, r_force_commit);
         }
         break;
     }
@@ -8121,7 +8118,7 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
 void
 nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
                                   NMPlatformIPRouteCmpType  cmp_type,
-                                  NMHashState *             h)
+                                  NMHashState              *h)
 {
     struct in6_addr a1, a2;
 
@@ -8205,8 +8202,8 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
                                                   obj->lock_initcwnd,
                                                   obj->lock_initrwnd,
                                                   obj->lock_mtu,
-                                                  obj->is_external,
-                                                  obj->r_assume_config_once),
+                                                  obj->r_assume_config_once,
+                                                  obj->r_force_commit),
                             obj->window,
                             obj->cwnd,
                             obj->initcwnd,
@@ -8290,8 +8287,8 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
         else
             NM_CMP_FIELD(a, b, rt_pref);
         if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL) {
-            NM_CMP_FIELD_UNSAFE(a, b, is_external);
             NM_CMP_FIELD_UNSAFE(a, b, r_assume_config_once);
+            NM_CMP_FIELD_UNSAFE(a, b, r_force_commit);
         }
         break;
     }
@@ -8308,7 +8305,7 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
 void
 nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj,
                                      NMPlatformRoutingRuleCmpType cmp_type,
-                                     NMHashState *                h)
+                                     NMHashState                 *h)
 {
     gboolean cmp_full = TRUE;
     gsize    addr_size;
@@ -8551,9 +8548,9 @@ nm_platform_ip4_address_addr_to_hash(NMPlatform *self, int ifindex)
 {
     const NMDedupMultiHeadEntry *head_entry;
     NMDedupMultiIter             iter;
-    const NMPObject *            obj;
+    const NMPObject             *obj;
     NMPLookup                    lookup;
-    GHashTable *                 hash;
+    GHashTable                  *hash;
 
     g_return_val_if_fail(NM_IS_PLATFORM(self), NULL);
     g_return_val_if_fail(ifindex > 0, NULL);
@@ -8583,7 +8580,8 @@ nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr,
                                               int                         ifindex,
                                               guint32                     route_table,
                                               guint32                     route_metric,
-                                              NMPlatformIP4Route *        dst)
+                                              gboolean                    force_commit,
+                                              NMPlatformIP4Route         *dst)
 {
     in_addr_t network_4;
 
@@ -8614,14 +8612,15 @@ nm_platform_ip4_address_generate_device_route(const NMPlatformIP4Address *addr,
     }
 
     *dst = (NMPlatformIP4Route){
-        .ifindex       = ifindex,
-        .rt_source     = NM_IP_CONFIG_SOURCE_KERNEL,
-        .network       = network_4,
-        .plen          = addr->plen,
-        .pref_src      = addr->address,
-        .table_coerced = nm_platform_route_table_coerce(route_table),
-        .metric        = route_metric,
-        .scope_inv     = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK),
+        .ifindex        = ifindex,
+        .rt_source      = NM_IP_CONFIG_SOURCE_KERNEL,
+        .network        = network_4,
+        .plen           = addr->plen,
+        .pref_src       = addr->address,
+        .table_coerced  = nm_platform_route_table_coerce(route_table),
+        .metric         = route_metric,
+        .scope_inv      = nm_platform_route_scope_inv(NM_RT_SCOPE_LINK),
+        .r_force_commit = force_commit,
     };
 
     nm_platform_ip_route_normalize(AF_INET, (NMPlatformIPRoute *) dst);
@@ -8645,10 +8644,10 @@ nm_platform_signal_change_type_to_string(NMPlatformSignalChangeType change_type)
 }
 
 static void
-log_link(NMPlatform *               self,
+log_link(NMPlatform                *self,
          NMPObjectType              obj_type,
          int                        ifindex,
-         NMPlatformLink *           device,
+         NMPlatformLink            *device,
          NMPlatformSignalChangeType change_type,
          gpointer                   user_data)
 {
@@ -8658,10 +8657,10 @@ log_link(NMPlatform *               self,
 }
 
 static void
-log_ip4_address(NMPlatform *               self,
+log_ip4_address(NMPlatform                *self,
                 NMPObjectType              obj_type,
                 int                        ifindex,
-                NMPlatformIP4Address *     address,
+                NMPlatformIP4Address      *address,
                 NMPlatformSignalChangeType change_type,
                 gpointer                   user_data)
 {
@@ -8671,10 +8670,10 @@ log_ip4_address(NMPlatform *               self,
 }
 
 static void
-log_ip6_address(NMPlatform *               self,
+log_ip6_address(NMPlatform                *self,
                 NMPObjectType              obj_type,
                 int                        ifindex,
-                NMPlatformIP6Address *     address,
+                NMPlatformIP6Address      *address,
                 NMPlatformSignalChangeType change_type,
                 gpointer                   user_data)
 {
@@ -8684,10 +8683,10 @@ log_ip6_address(NMPlatform *               self,
 }
 
 static void
-log_ip4_route(NMPlatform *               self,
+log_ip4_route(NMPlatform                *self,
               NMPObjectType              obj_type,
               int                        ifindex,
-              NMPlatformIP4Route *       route,
+              NMPlatformIP4Route        *route,
               NMPlatformSignalChangeType change_type,
               gpointer                   user_data)
 {
@@ -8697,10 +8696,10 @@ log_ip4_route(NMPlatform *               self,
 }
 
 static void
-log_ip6_route(NMPlatform *               self,
+log_ip6_route(NMPlatform                *self,
               NMPObjectType              obj_type,
               int                        ifindex,
-              NMPlatformIP6Route *       route,
+              NMPlatformIP6Route        *route,
               NMPlatformSignalChangeType change_type,
               gpointer                   user_data)
 {
@@ -8710,10 +8709,10 @@ log_ip6_route(NMPlatform *               self,
 }
 
 static void
-log_routing_rule(NMPlatform *               self,
+log_routing_rule(NMPlatform                *self,
                  NMPObjectType              obj_type,
                  int                        ifindex,
-                 NMPlatformRoutingRule *    routing_rule,
+                 NMPlatformRoutingRule     *routing_rule,
                  NMPlatformSignalChangeType change_type,
                  gpointer                   user_data)
 {
@@ -8724,10 +8723,10 @@ log_routing_rule(NMPlatform *               self,
 }
 
 static void
-log_qdisc(NMPlatform *               self,
+log_qdisc(NMPlatform                *self,
           NMPObjectType              obj_type,
           int                        ifindex,
-          NMPlatformQdisc *          qdisc,
+          NMPlatformQdisc           *qdisc,
           NMPlatformSignalChangeType change_type,
           gpointer                   user_data)
 {
@@ -8737,10 +8736,10 @@ log_qdisc(NMPlatform *               self,
 }
 
 static void
-log_tfilter(NMPlatform *               self,
+log_tfilter(NMPlatform                *self,
             NMPObjectType              obj_type,
             int                        ifindex,
-            NMPlatformTfilter *        tfilter,
+            NMPlatformTfilter         *tfilter,
             NMPlatformSignalChangeType change_type,
             gpointer                   user_data)
 {
@@ -8752,7 +8751,7 @@ log_tfilter(NMPlatform *               self,
 /*****************************************************************************/
 
 void
-nm_platform_cache_update_emit_signal(NMPlatform *     self,
+nm_platform_cache_update_emit_signal(NMPlatform      *self,
                                      NMPCacheOpsType  cache_op,
                                      const NMPObject *obj_old,
                                      const NMPObject *obj_new)
@@ -8760,7 +8759,7 @@ nm_platform_cache_update_emit_signal(NMPlatform *     self,
     gboolean         visible_new;
     gboolean         visible_old;
     const NMPObject *o;
-    const NMPClass * klass;
+    const NMPClass  *klass;
     int              ifindex;
 
     nm_assert(NM_IN_SET((NMPlatformSignalChangeType) cache_op,
@@ -8875,7 +8874,7 @@ const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
                                   const NMPlatformIPXRoute *b,
                                   NMPlatformIPRouteCmpType  cmp_type)) nm_platform_ip4_route_cmp,
             .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route,
-                                                 char *                    buf,
+                                                 char                     *buf,
                                                  gsize len)) nm_platform_ip4_route_to_string,
         },
     .v6 =
@@ -8888,7 +8887,7 @@ const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
                                   const NMPlatformIPXRoute *b,
                                   NMPlatformIPRouteCmpType  cmp_type)) nm_platform_ip6_route_cmp,
             .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route,
-                                                 char *                    buf,
+                                                 char                     *buf,
                                                  gsize len)) nm_platform_ip6_route_to_string,
         },
 };
@@ -8898,7 +8897,7 @@ const _NMPlatformVTableRouteUnion nm_platform_vtable_route = {
 static void
 set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
-    NMPlatform *       self = NM_PLATFORM(object);
+    NMPlatform        *self = NM_PLATFORM(object);
     NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
 
     switch (prop_id) {
@@ -8939,8 +8938,8 @@ nm_platform_init(NMPlatform *self)
 static GObject *
 constructor(GType type, guint n_construct_params, GObjectConstructParam *construct_params)
 {
-    GObject *          object;
-    NMPlatform *       self;
+    GObject           *object;
+    NMPlatform        *self;
     NMPlatformPrivate *priv;
 
     object = G_OBJECT_CLASS(nm_platform_parent_class)
@@ -8958,7 +8957,7 @@ constructor(GType type, guint n_construct_params, GObjectConstructParam *constru
 static void
 finalize(GObject *object)
 {
-    NMPlatform *       self = NM_PLATFORM(object);
+    NMPlatform        *self = NM_PLATFORM(object);
     NMPlatformPrivate *priv = NM_PLATFORM_GET_PRIVATE(self);
 
     nm_clear_g_source(&priv->ip4_dev_route_blacklist_check_id);
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index 7101b48c..6f5cd524 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -155,7 +155,7 @@ G_STATIC_ASSERT(_nm_alignof(NMEtherAddr) == 1);
 G_STATIC_ASSERT(_nm_alignof(NMPLinkAddress) == 1);
 
 gconstpointer nmp_link_address_get(const NMPLinkAddress *addr, size_t *length);
-GBytes *      nmp_link_address_get_as_bytes(const NMPLinkAddress *addr);
+GBytes       *nmp_link_address_get_as_bytes(const NMPLinkAddress *addr);
 
 typedef enum {
 
@@ -318,16 +318,14 @@ typedef enum {
      * IFA_FLAGS attribute. */         \
     guint32 n_ifa_flags;                                                                     \
                                                                                              \
-    /* FIXME(l3cfg): the external marker won't be necessary anymore, because we only
-     * merge addresses we care about, and ignore (don't remove) external addresses. */         \
-    bool external : 1;                                                                       \
-                                                                                             \
     bool use_ip4_broadcast_address : 1;                                                      \
                                                                                              \
-    /* Whether the address is should be configured once during assume. This is a meta flag
-     * that is not honored by NMPlatform (netlink code). Instead, it can be used by the upper
-     * layers which use NMPlatformIPAddress to track addresses that should be configured. */   \
+    /* Meta flags not honored by NMPlatform (netlink code). Instead, they can be
+     * used by the upper layers which use NMPlatformIPRoute to track addresses that
+     * should be configured. */             \
+    /* Whether the address is should be configured once during assume. */                    \
     bool a_assume_config_once : 1;                                                           \
+    bool a_force_commit : 1;                                                                 \
                                                                                              \
     guint8 plen;                                                                             \
     ;
@@ -471,18 +469,13 @@ typedef union {
      * the "table_coerced" field is ignored (unlike for the metric). */            \
     bool table_any : 1;                                                                   \
                                                                                           \
-    /* This route is tracked as external route, that is not a route that NetworkManager
-     * actively wants to add, but a route that was added externally. In some cases, such
-     * a route should be ignored.
-     *
-     * Note that unlike most other fields here, this flag only exists inside NetworkManager
-     * and is not reflected on netlink. */   \
-    bool is_external : 1;                                                                 \
-                                                                                          \
-    /* Whether the route is should be configured once during assume. This is a meta flag
-     * that is not honored by NMPlatform (netlink code). Instead, it can be used by the upper
-     * layers which use NMPlatformIPRoute to track routes that should be configured. */  \
+    /* Meta flags not honored by NMPlatform (netlink code). Instead, they can be
+     * used by the upper layers which use NMPlatformIPRoute to track routes that
+     * should be configured. */          \
+    /* Whether the route is should be configured once during assume. */                   \
     bool r_assume_config_once : 1;                                                        \
+    /* Whether the route should be committed even if it was removed externally. */        \
+    bool r_force_commit : 1;                                                              \
                                                                                           \
     /* rtnh_flags
      *
@@ -1078,7 +1071,7 @@ struct _NMPlatformPrivate;
 
 struct _NMPlatform {
     GObject                    parent;
-    NMPNetns *                 _netns;
+    NMPNetns                  *_netns;
     struct _NMPlatformPrivate *_priv;
 };
 
@@ -1090,24 +1083,24 @@ typedef struct {
                            int         dirfd,
                            const char *path,
                            const char *value);
-    void (*sysctl_set_async)(NMPlatform *            self,
-                             const char *            pathid,
+    void (*sysctl_set_async)(NMPlatform             *self,
+                             const char             *pathid,
                              int                     dirfd,
-                             const char *            path,
-                             const char *const *     values,
+                             const char             *path,
+                             const char *const      *values,
                              NMPlatformAsyncCallback callback,
                              gpointer                data,
-                             GCancellable *          cancellable);
+                             GCancellable           *cancellable);
     char *(*sysctl_get)(NMPlatform *self, const char *pathid, int dirfd, const char *path);
 
     void (*refresh_all)(NMPlatform *self, NMPObjectType obj_type);
     void (*process_events)(NMPlatform *self);
 
-    int (*link_add)(NMPlatform *           self,
+    int (*link_add)(NMPlatform            *self,
                     NMLinkType             type,
-                    const char *           name,
+                    const char            *name,
                     int                    parent,
-                    const void *           address,
+                    const void            *address,
                     size_t                 address_len,
                     guint32                mtu,
                     gconstpointer          extra_data,
@@ -1123,21 +1116,21 @@ typedef struct {
     int (*link_set_inet6_addr_gen_mode)(NMPlatform *self, int ifindex, guint8 enabled);
     gboolean (*link_set_token)(NMPlatform *self, int ifindex, const NMUtilsIPv6IfaceId *iid);
 
-    gboolean (*link_get_permanent_address_ethtool)(NMPlatform *    self,
+    gboolean (*link_get_permanent_address_ethtool)(NMPlatform     *self,
                                                    int             ifindex,
                                                    NMPLinkAddress *out_address);
     int (*link_set_address)(NMPlatform *self, int ifindex, gconstpointer address, size_t length);
     int (*link_set_mtu)(NMPlatform *self, int ifindex, guint32 mtu);
     gboolean (*link_set_name)(NMPlatform *self, int ifindex, const char *name);
-    void (*link_set_sriov_params_async)(NMPlatform *            self,
+    void (*link_set_sriov_params_async)(NMPlatform             *self,
                                         int                     ifindex,
                                         guint                   num_vfs,
                                         NMOptionBool            autoprobe,
                                         NMPlatformAsyncCallback callback,
                                         gpointer                callback_data,
-                                        GCancellable *          cancellable);
+                                        GCancellable           *cancellable);
     gboolean (*link_set_sriov_vfs)(NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
-    gboolean (*link_set_bridge_vlans)(NMPlatform *                       self,
+    gboolean (*link_set_bridge_vlans)(NMPlatform                        *self,
                                       int                                ifindex,
                                       gboolean                           on_master,
                                       const NMPlatformBridgeVlan *const *vlans);
@@ -1147,9 +1140,9 @@ typedef struct {
     gboolean (*link_get_wake_on_lan)(NMPlatform *self, int ifindex);
     gboolean (*link_get_driver_info)(NMPlatform *self,
                                      int         ifindex,
-                                     char **     out_driver_name,
-                                     char **     out_driver_version,
-                                     char **     out_fw_version);
+                                     char      **out_driver_name,
+                                     char      **out_driver_version,
+                                     char      **out_fw_version);
 
     gboolean (*link_supports_carrier_detect)(NMPlatform *self, int ifindex);
     gboolean (*link_supports_vlans)(NMPlatform *self, int ifindex);
@@ -1160,15 +1153,15 @@ typedef struct {
 
     gboolean (*link_can_assume)(NMPlatform *self, int ifindex);
 
-    int (*link_wireguard_change)(NMPlatform *                              self,
+    int (*link_wireguard_change)(NMPlatform                               *self,
                                  int                                       ifindex,
-                                 const NMPlatformLnkWireGuard *            lnk_wireguard,
-                                 const struct _NMPWireGuardPeer *          peers,
+                                 const NMPlatformLnkWireGuard             *lnk_wireguard,
+                                 const struct _NMPWireGuardPeer           *peers,
                                  const NMPlatformWireGuardChangePeerFlags *peer_flags,
                                  guint                                     peers_len,
                                  NMPlatformWireGuardChangeFlags            change_flags);
 
-    gboolean (*link_vlan_change)(NMPlatform *            self,
+    gboolean (*link_vlan_change)(NMPlatform             *self,
                                  int                     ifindex,
                                  _NMVlanFlags            flags_mask,
                                  _NMVlanFlags            flags_set,
@@ -1178,26 +1171,26 @@ typedef struct {
                                  gboolean                egress_reset_all,
                                  const NMVlanQosMapping *egress_map,
                                  gsize                   n_egress_map);
-    gboolean (*link_tun_add)(NMPlatform *            self,
-                             const char *            name,
+    gboolean (*link_tun_add)(NMPlatform             *self,
+                             const char             *name,
                              const NMPlatformLnkTun *props,
-                             const NMPlatformLink ** out_link,
-                             int *                   out_fd);
+                             const NMPlatformLink  **out_link,
+                             int                    *out_fd);
 
-    gboolean (*infiniband_partition_add)(NMPlatform *           self,
+    gboolean (*infiniband_partition_add)(NMPlatform            *self,
                                          int                    parent,
                                          int                    p_key,
                                          const NMPlatformLink **out_link);
     gboolean (*infiniband_partition_delete)(NMPlatform *self, int parent, int p_key);
 
-    gboolean (*wifi_get_capabilities)(NMPlatform *               self,
+    gboolean (*wifi_get_capabilities)(NMPlatform                *self,
                                       int                        ifindex,
                                       _NMDeviceWifiCapabilities *caps);
-    gboolean (*wifi_get_station)(NMPlatform * self,
+    gboolean (*wifi_get_station)(NMPlatform  *self,
                                  int          ifindex,
                                  NMEtherAddr *out_bssid,
-                                 int *        out_quality,
-                                 guint32 *    out_rate);
+                                 int         *out_quality,
+                                 guint32     *out_rate);
     gboolean (*wifi_get_bssid)(NMPlatform *self, int ifindex, guint8 *bssid);
     guint32 (*wifi_get_frequency)(NMPlatform *self, int ifindex);
     int (*wifi_get_quality)(NMPlatform *self, int ifindex);
@@ -1208,7 +1201,7 @@ typedef struct {
     guint32 (*wifi_find_frequency)(NMPlatform *self, int ifindex, const guint32 *freqs);
     void (*wifi_indicate_addressing_running)(NMPlatform *self, int ifindex, gboolean running);
     _NMSettingWirelessWakeOnWLan (*wifi_get_wake_on_wlan)(NMPlatform *self, int ifindex);
-    gboolean (*wifi_set_wake_on_wlan)(NMPlatform *                 self,
+    gboolean (*wifi_set_wake_on_wlan)(NMPlatform                  *self,
                                       int                          ifindex,
                                       _NMSettingWirelessWakeOnWLan wowl);
 
@@ -1234,7 +1227,7 @@ typedef struct {
                                 guint32     preferred_lft,
                                 guint32     flags,
                                 const char *label);
-    gboolean (*ip6_address_add)(NMPlatform *    self,
+    gboolean (*ip6_address_add)(NMPlatform     *self,
                                 int             ifindex,
                                 struct in6_addr address,
                                 guint8          plen,
@@ -1247,22 +1240,22 @@ typedef struct {
                                    in_addr_t   address,
                                    guint8      plen,
                                    in_addr_t   peer_address);
-    gboolean (*ip6_address_delete)(NMPlatform *    self,
+    gboolean (*ip6_address_delete)(NMPlatform     *self,
                                    int             ifindex,
                                    struct in6_addr address,
                                    guint8          plen);
 
-    int (*ip_route_add)(NMPlatform *             self,
+    int (*ip_route_add)(NMPlatform              *self,
                         NMPNlmFlags              flags,
                         int                      addr_family,
                         const NMPlatformIPRoute *route);
-    int (*ip_route_get)(NMPlatform *  self,
+    int (*ip_route_get)(NMPlatform   *self,
                         int           addr_family,
                         gconstpointer address,
                         int           oif_ifindex,
-                        NMPObject **  out_route);
+                        NMPObject   **out_route);
 
-    int (*routing_rule_add)(NMPlatform *                 self,
+    int (*routing_rule_add)(NMPlatform                  *self,
                             NMPNlmFlags                  flags,
                             const NMPlatformRoutingRule *routing_rule);
 
@@ -1415,6 +1408,12 @@ _nm_platform_link_get_inet6_addr_gen_mode(const NMPlatformLink *pllink)
     return _nm_platform_uint8_inv(pllink->inet6_addr_gen_mode_inv);
 }
 
+static inline gboolean
+nm_platform_route_type_is_nodev(guint8 type)
+{
+    return NM_IN_SET(type, 6 /* RTN_BLACKHOLE */, 7 /* RTN_UNREACHABLE */, 8 /* RTN_PROHIBIT */);
+}
+
 /**
  * nm_platform_route_type_coerce:
  * @table: the route type, in its original value.
@@ -1484,15 +1483,15 @@ gboolean nm_platform_sysctl_set(NMPlatform *self,
                                 int         dirfd,
                                 const char *path,
                                 const char *value);
-void     nm_platform_sysctl_set_async(NMPlatform *            self,
-                                      const char *            pathid,
+void     nm_platform_sysctl_set_async(NMPlatform             *self,
+                                      const char             *pathid,
                                       int                     dirfd,
-                                      const char *            path,
-                                      const char *const *     values,
+                                      const char             *path,
+                                      const char *const      *values,
                                       NMPlatformAsyncCallback callback,
                                       gpointer                data,
-                                      GCancellable *          cancellable);
-char *   nm_platform_sysctl_get(NMPlatform *self, const char *pathid, int dirfd, const char *path);
+                                      GCancellable           *cancellable);
+char    *nm_platform_sysctl_get(NMPlatform *self, const char *pathid, int dirfd, const char *path);
 gint32   nm_platform_sysctl_get_int32(NMPlatform *self,
                                       const char *pathid,
                                       int         dirfd,
@@ -1544,7 +1543,7 @@ gboolean nm_platform_sysctl_ip_neigh_set_ipv6_retrans_time(NMPlatform *self,
 int      nm_platform_sysctl_ip_conf_get_rp_filter_ipv4(NMPlatform *platform,
                                                        const char *iface,
                                                        gboolean    consider_all,
-                                                       gboolean *  out_due_to_all);
+                                                       gboolean   *out_due_to_all);
 
 const char *nm_platform_if_indextoname(NMPlatform *self,
                                        int         ifindex,
@@ -1554,27 +1553,27 @@ int         nm_platform_if_nametoindex(NMPlatform *self, const char *ifname);
 const NMPObject *nm_platform_link_get_obj(NMPlatform *self, int ifindex, gboolean visible_only);
 const NMPlatformLink *nm_platform_link_get(NMPlatform *self, int ifindex);
 const NMPlatformLink *nm_platform_link_get_by_ifname(NMPlatform *self, const char *ifname);
-const NMPlatformLink *nm_platform_link_get_by_address(NMPlatform *  self,
+const NMPlatformLink *nm_platform_link_get_by_address(NMPlatform   *self,
                                                       NMLinkType    link_type,
                                                       gconstpointer address,
                                                       size_t        length);
 
 GPtrArray *nm_platform_link_get_all(NMPlatform *self, gboolean sort_by_name);
 
-int nm_platform_link_add(NMPlatform *           self,
+int nm_platform_link_add(NMPlatform            *self,
                          NMLinkType             type,
-                         const char *           name,
+                         const char            *name,
                          int                    parent,
-                         const void *           address,
+                         const void            *address,
                          size_t                 address_len,
                          guint32                mtu,
                          gconstpointer          extra_data,
                          const NMPlatformLink **out_link);
 
 static inline int
-nm_platform_link_veth_add(NMPlatform *           self,
-                          const char *           name,
-                          const char *           peer,
+nm_platform_link_veth_add(NMPlatform            *self,
+                          const char            *name,
+                          const char            *peer,
                           const NMPlatformLink **out_link)
 {
     return nm_platform_link_add(self, NM_LINK_TYPE_VETH, name, 0, NULL, 0, 0, peer, out_link);
@@ -1587,13 +1586,13 @@ nm_platform_link_dummy_add(NMPlatform *self, const char *name, const NMPlatformL
 }
 
 static inline int
-nm_platform_link_bridge_add(NMPlatform *               self,
-                            const char *               name,
-                            const void *               address,
+nm_platform_link_bridge_add(NMPlatform                *self,
+                            const char                *name,
+                            const void                *address,
                             size_t                     address_len,
                             guint32                    mtu,
                             const NMPlatformLnkBridge *props,
-                            const NMPlatformLink **    out_link)
+                            const NMPlatformLink     **out_link)
 {
     return nm_platform_link_add(self,
                                 NM_LINK_TYPE_BRIDGE,
@@ -1625,12 +1624,12 @@ nm_platform_link_wireguard_add(NMPlatform *self, const char *name, const NMPlatf
 }
 
 static inline int
-nm_platform_link_gre_add(NMPlatform *            self,
-                         const char *            name,
-                         const void *            address,
+nm_platform_link_gre_add(NMPlatform             *self,
+                         const char             *name,
+                         const void             *address,
                          size_t                  address_len,
                          const NMPlatformLnkGre *props,
-                         const NMPlatformLink ** out_link)
+                         const NMPlatformLink  **out_link)
 {
     g_return_val_if_fail(props, -NME_BUG);
 
@@ -1646,17 +1645,17 @@ nm_platform_link_gre_add(NMPlatform *            self,
 }
 
 static inline int
-nm_platform_link_sit_add(NMPlatform *            self,
-                         const char *            name,
+nm_platform_link_sit_add(NMPlatform             *self,
+                         const char             *name,
                          const NMPlatformLnkSit *props,
-                         const NMPlatformLink ** out_link)
+                         const NMPlatformLink  **out_link)
 {
     return nm_platform_link_add(self, NM_LINK_TYPE_SIT, name, 0, NULL, 0, 0, props, out_link);
 }
 
 static inline int
-nm_platform_link_vlan_add(NMPlatform *           self,
-                          const char *           name,
+nm_platform_link_vlan_add(NMPlatform            *self,
+                          const char            *name,
                           int                    parent,
                           int                    vlanid,
                           guint32                vlanflags,
@@ -1680,26 +1679,26 @@ nm_platform_link_vlan_add(NMPlatform *           self,
 }
 
 static inline int
-nm_platform_link_vrf_add(NMPlatform *            self,
-                         const char *            name,
+nm_platform_link_vrf_add(NMPlatform             *self,
+                         const char             *name,
                          const NMPlatformLnkVrf *props,
-                         const NMPlatformLink ** out_link)
+                         const NMPlatformLink  **out_link)
 {
     return nm_platform_link_add(self, NM_LINK_TYPE_VRF, name, 0, NULL, 0, 0, props, out_link);
 }
 
 static inline int
-nm_platform_link_vxlan_add(NMPlatform *              self,
-                           const char *              name,
+nm_platform_link_vxlan_add(NMPlatform               *self,
+                           const char               *name,
                            const NMPlatformLnkVxlan *props,
-                           const NMPlatformLink **   out_link)
+                           const NMPlatformLink    **out_link)
 {
     return nm_platform_link_add(self, NM_LINK_TYPE_VXLAN, name, 0, NULL, 0, 0, props, out_link);
 }
 
 static inline int
-nm_platform_link_6lowpan_add(NMPlatform *           self,
-                             const char *           name,
+nm_platform_link_6lowpan_add(NMPlatform            *self,
+                             const char            *name,
                              int                    parent,
                              const NMPlatformLink **out_link)
 {
@@ -1715,10 +1714,10 @@ nm_platform_link_6lowpan_add(NMPlatform *           self,
 }
 
 static inline int
-nm_platform_link_ip6tnl_add(NMPlatform *               self,
-                            const char *               name,
+nm_platform_link_ip6tnl_add(NMPlatform                *self,
+                            const char                *name,
                             const NMPlatformLnkIp6Tnl *props,
-                            const NMPlatformLink **    out_link)
+                            const NMPlatformLink     **out_link)
 {
     g_return_val_if_fail(props, -NME_BUG);
     g_return_val_if_fail(!props->is_gre, -NME_BUG);
@@ -1727,12 +1726,12 @@ nm_platform_link_ip6tnl_add(NMPlatform *               self,
 }
 
 static inline int
-nm_platform_link_ip6gre_add(NMPlatform *               self,
-                            const char *               name,
-                            const void *               address,
+nm_platform_link_ip6gre_add(NMPlatform                *self,
+                            const char                *name,
+                            const void                *address,
                             size_t                     address_len,
                             const NMPlatformLnkIp6Tnl *props,
-                            const NMPlatformLink **    out_link)
+                            const NMPlatformLink     **out_link)
 {
     g_return_val_if_fail(props, -NME_BUG);
     g_return_val_if_fail(props->is_gre, -NME_BUG);
@@ -1749,10 +1748,10 @@ nm_platform_link_ip6gre_add(NMPlatform *               self,
 }
 
 static inline int
-nm_platform_link_ipip_add(NMPlatform *             self,
-                          const char *             name,
+nm_platform_link_ipip_add(NMPlatform              *self,
+                          const char              *name,
                           const NMPlatformLnkIpIp *props,
-                          const NMPlatformLink **  out_link)
+                          const NMPlatformLink   **out_link)
 {
     g_return_val_if_fail(props, -NME_BUG);
 
@@ -1760,11 +1759,11 @@ nm_platform_link_ipip_add(NMPlatform *             self,
 }
 
 static inline int
-nm_platform_link_macsec_add(NMPlatform *               self,
-                            const char *               name,
+nm_platform_link_macsec_add(NMPlatform                *self,
+                            const char                *name,
                             int                        parent,
                             const NMPlatformLnkMacsec *props,
-                            const NMPlatformLink **    out_link)
+                            const NMPlatformLink     **out_link)
 {
     g_return_val_if_fail(props, -NME_BUG);
     g_return_val_if_fail(parent > 0, -NME_BUG);
@@ -1781,11 +1780,11 @@ nm_platform_link_macsec_add(NMPlatform *               self,
 }
 
 static inline int
-nm_platform_link_macvlan_add(NMPlatform *                self,
-                             const char *                name,
+nm_platform_link_macvlan_add(NMPlatform                 *self,
+                             const char                 *name,
                              int                         parent,
                              const NMPlatformLnkMacvlan *props,
-                             const NMPlatformLink **     out_link)
+                             const NMPlatformLink      **out_link)
 {
     g_return_val_if_fail(props, -NME_BUG);
     g_return_val_if_fail(parent > 0, -NME_BUG);
@@ -1807,7 +1806,7 @@ gboolean nm_platform_link_set_netns(NMPlatform *self, int ifindex, int netns_fd)
 
 struct _NMDedupMultiHeadEntry;
 struct _NMPLookup;
-const struct _NMDedupMultiHeadEntry *nm_platform_lookup(NMPlatform *             self,
+const struct _NMDedupMultiHeadEntry *nm_platform_lookup(NMPlatform              *self,
                                                         const struct _NMPLookup *lookup);
 
 #define nm_platform_iter_obj_for_each(iter, self, lookup, obj)                   \
@@ -1818,7 +1817,7 @@ gboolean nm_platform_lookup_predicate_routes_main(const NMPObject *obj, gpointer
 gboolean nm_platform_lookup_predicate_routes_main_skip_rtprot_kernel(const NMPObject *obj,
                                                                      gpointer         user_data);
 
-GPtrArray *nm_platform_lookup_clone(NMPlatform *             self,
+GPtrArray *nm_platform_lookup_clone(NMPlatform              *self,
                                     const struct _NMPLookup *lookup,
                                     NMPObjectPredicateFunc   predicate,
                                     gpointer                 user_data);
@@ -1874,9 +1873,9 @@ nm_platform_link_change_flags(NMPlatform *self, int ifindex, unsigned value, gbo
     return nm_platform_link_change_flags_full(self, ifindex, value, set ? value : 0u);
 }
 
-gboolean    nm_platform_link_get_udev_property(NMPlatform * self,
+gboolean    nm_platform_link_get_udev_property(NMPlatform  *self,
                                                int          ifindex,
-                                               const char * name,
+                                               const char  *name,
                                                const char **out_value);
 const char *nm_platform_link_get_udi(NMPlatform *self, int ifindex);
 const char *nm_platform_link_get_path(NMPlatform *self, int ifindex);
@@ -1887,39 +1886,39 @@ int nm_platform_link_set_inet6_addr_gen_mode(NMPlatform *self, int ifindex, guin
 gboolean
 nm_platform_link_set_ipv6_token(NMPlatform *self, int ifindex, const NMUtilsIPv6IfaceId *iid);
 
-gboolean nm_platform_link_get_permanent_address_ethtool(NMPlatform *    self,
+gboolean nm_platform_link_get_permanent_address_ethtool(NMPlatform     *self,
                                                         int             ifindex,
                                                         NMPLinkAddress *out_address);
-gboolean nm_platform_link_get_permanent_address(NMPlatform *          self,
+gboolean nm_platform_link_get_permanent_address(NMPlatform           *self,
                                                 const NMPlatformLink *plink,
-                                                NMPLinkAddress *      out_address);
+                                                NMPLinkAddress       *out_address);
 int nm_platform_link_set_address(NMPlatform *self, int ifindex, const void *address, size_t length);
 int nm_platform_link_set_mtu(NMPlatform *self, int ifindex, guint32 mtu);
 gboolean nm_platform_link_set_name(NMPlatform *self, int ifindex, const char *name);
 
-void nm_platform_link_set_sriov_params_async(NMPlatform *            self,
+void nm_platform_link_set_sriov_params_async(NMPlatform             *self,
                                              int                     ifindex,
                                              guint                   num_vfs,
                                              NMOptionBool            autoprobe,
                                              NMPlatformAsyncCallback callback,
                                              gpointer                callback_data,
-                                             GCancellable *          cancellable);
+                                             GCancellable           *cancellable);
 
 gboolean
 nm_platform_link_set_sriov_vfs(NMPlatform *self, int ifindex, const NMPlatformVF *const *vfs);
-gboolean nm_platform_link_set_bridge_vlans(NMPlatform *                       self,
+gboolean nm_platform_link_set_bridge_vlans(NMPlatform                        *self,
                                            int                                ifindex,
                                            gboolean                           on_master,
                                            const NMPlatformBridgeVlan *const *vlans);
 
-char *   nm_platform_link_get_physical_port_id(NMPlatform *self, int ifindex);
+char    *nm_platform_link_get_physical_port_id(NMPlatform *self, int ifindex);
 guint    nm_platform_link_get_dev_id(NMPlatform *self, int ifindex);
 gboolean nm_platform_link_get_wake_on_lan(NMPlatform *self, int ifindex);
 gboolean nm_platform_link_get_driver_info(NMPlatform *self,
                                           int         ifindex,
-                                          char **     out_driver_name,
-                                          char **     out_driver_version,
-                                          char **     out_fw_version);
+                                          char      **out_driver_name,
+                                          char      **out_driver_version,
+                                          char      **out_fw_version);
 
 gboolean nm_platform_link_supports_carrier_detect(NMPlatform *self, int ifindex);
 gboolean nm_platform_link_supports_vlans(NMPlatform *self, int ifindex);
@@ -1932,14 +1931,14 @@ gboolean nm_platform_sysctl_master_set_option(NMPlatform *self,
                                               int         ifindex,
                                               const char *option,
                                               const char *value);
-char *   nm_platform_sysctl_master_get_option(NMPlatform *self, int ifindex, const char *option);
+char    *nm_platform_sysctl_master_get_option(NMPlatform *self, int ifindex, const char *option);
 gboolean nm_platform_sysctl_slave_set_option(NMPlatform *self,
                                              int         ifindex,
                                              const char *option,
                                              const char *value);
-char *   nm_platform_sysctl_slave_get_option(NMPlatform *self, int ifindex, const char *option);
+char    *nm_platform_sysctl_slave_get_option(NMPlatform *self, int ifindex, const char *option);
 
-const NMPObject *nm_platform_link_get_lnk(NMPlatform *           self,
+const NMPObject *nm_platform_link_get_lnk(NMPlatform            *self,
                                           int                    ifindex,
                                           NMLinkType             link_type,
                                           const NMPlatformLink **out_link);
@@ -1982,7 +1981,7 @@ nm_platform_link_get_lnk_wireguard(NMPlatform *self, int ifindex, const NMPlatfo
 
 gboolean nm_platform_link_vlan_set_ingress_map(NMPlatform *self, int ifindex, int from, int to);
 gboolean nm_platform_link_vlan_set_egress_map(NMPlatform *self, int ifindex, int from, int to);
-gboolean nm_platform_link_vlan_change(NMPlatform *            self,
+gboolean nm_platform_link_vlan_change(NMPlatform             *self,
                                       int                     ifindex,
                                       _NMVlanFlags            flags_mask,
                                       _NMVlanFlags            flags_set,
@@ -1993,30 +1992,30 @@ gboolean nm_platform_link_vlan_change(NMPlatform *            self,
                                       const NMVlanQosMapping *egress_map,
                                       gsize                   n_egress_map);
 
-int      nm_platform_link_infiniband_add(NMPlatform *           self,
+int      nm_platform_link_infiniband_add(NMPlatform            *self,
                                          int                    parent,
                                          int                    p_key,
                                          const NMPlatformLink **out_link);
 int      nm_platform_link_infiniband_delete(NMPlatform *self, int parent, int p_key);
-gboolean nm_platform_link_infiniband_get_properties(NMPlatform * self,
+gboolean nm_platform_link_infiniband_get_properties(NMPlatform  *self,
                                                     int          ifindex,
-                                                    int *        parent,
-                                                    int *        p_key,
+                                                    int         *parent,
+                                                    int         *p_key,
                                                     const char **mode);
 
 gboolean nm_platform_link_veth_get_properties(NMPlatform *self, int ifindex, int *out_peer_ifindex);
-gboolean nm_platform_link_tun_get_properties(NMPlatform *      self,
+gboolean nm_platform_link_tun_get_properties(NMPlatform       *self,
                                              int               ifindex,
                                              NMPlatformLnkTun *out_properties);
 
 gboolean
 nm_platform_wifi_get_capabilities(NMPlatform *self, int ifindex, _NMDeviceWifiCapabilities *caps);
 guint32      nm_platform_wifi_get_frequency(NMPlatform *self, int ifindex);
-gboolean     nm_platform_wifi_get_station(NMPlatform * self,
+gboolean     nm_platform_wifi_get_station(NMPlatform  *self,
                                           int          ifindex,
                                           NMEtherAddr *out_bssid,
-                                          int *        out_quality,
-                                          guint32 *    out_rate);
+                                          int         *out_quality,
+                                          guint32     *out_rate);
 _NM80211Mode nm_platform_wifi_get_mode(NMPlatform *self, int ifindex);
 void         nm_platform_wifi_set_mode(NMPlatform *self, int ifindex, _NM80211Mode mode);
 void         nm_platform_wifi_set_powersave(NMPlatform *self, int ifindex, guint32 powersave);
@@ -2045,24 +2044,24 @@ const NMPlatformIP4Address *nm_platform_ip4_address_get(NMPlatform *self,
                                                         guint8      plen,
                                                         in_addr_t   peer_address);
 
-int      nm_platform_link_sit_add(NMPlatform *            self,
-                                  const char *            name,
+int      nm_platform_link_sit_add(NMPlatform             *self,
+                                  const char             *name,
                                   const NMPlatformLnkSit *props,
-                                  const NMPlatformLink ** out_link);
-int      nm_platform_link_tun_add(NMPlatform *            self,
-                                  const char *            name,
+                                  const NMPlatformLink  **out_link);
+int      nm_platform_link_tun_add(NMPlatform             *self,
+                                  const char             *name,
                                   const NMPlatformLnkTun *props,
-                                  const NMPlatformLink ** out_link,
-                                  int *                   out_fd);
+                                  const NMPlatformLink  **out_link,
+                                  int                    *out_fd);
 gboolean nm_platform_link_6lowpan_get_properties(NMPlatform *self, int ifindex, int *out_parent);
 
 int
 nm_platform_link_wireguard_add(NMPlatform *self, const char *name, const NMPlatformLink **out_link);
 
-int nm_platform_link_wireguard_change(NMPlatform *                              self,
+int nm_platform_link_wireguard_change(NMPlatform                               *self,
                                       int                                       ifindex,
-                                      const NMPlatformLnkWireGuard *            lnk_wireguard,
-                                      const struct _NMPWireGuardPeer *          peers,
+                                      const NMPlatformLnkWireGuard             *lnk_wireguard,
+                                      const struct _NMPWireGuardPeer           *peers,
                                       const NMPlatformWireGuardChangePeerFlags *peer_flags,
                                       guint                                     peers_len,
                                       NMPlatformWireGuardChangeFlags            change_flags);
@@ -2082,7 +2081,7 @@ gboolean nm_platform_ip4_address_add(NMPlatform *self,
                                      guint32     preferred_lft,
                                      guint32     flags,
                                      const char *label);
-gboolean nm_platform_ip6_address_add(NMPlatform *    self,
+gboolean nm_platform_ip6_address_add(NMPlatform     *self,
                                      int             ifindex,
                                      struct in6_addr address,
                                      guint8          plen,
@@ -2101,8 +2100,8 @@ nm_platform_ip6_address_delete(NMPlatform *self, int ifindex, struct in6_addr ad
 gboolean nm_platform_ip_address_sync(NMPlatform *self,
                                      int         addr_family,
                                      int         ifindex,
-                                     GPtrArray * known_addresses,
-                                     GPtrArray * addresses_prune);
+                                     GPtrArray  *known_addresses,
+                                     GPtrArray  *addresses_prune);
 
 GPtrArray *nm_platform_ip_address_get_prune_list(NMPlatform *self,
                                                  int         addr_family,
@@ -2113,7 +2112,7 @@ static inline gboolean
 _nm_platform_ip_address_sync(NMPlatform *self,
                              int         addr_family,
                              int         ifindex,
-                             GPtrArray * known_addresses,
+                             GPtrArray  *known_addresses,
                              gboolean    full_sync)
 {
     gs_unref_ptrarray GPtrArray *addresses_prune = NULL;
@@ -2135,7 +2134,7 @@ nm_platform_ip4_address_sync(NMPlatform *self, int ifindex, GPtrArray *known_add
 static inline gboolean
 nm_platform_ip6_address_sync(NMPlatform *self,
                              int         ifindex,
-                             GPtrArray * known_addresses,
+                             GPtrArray  *known_addresses,
                              gboolean    full_sync)
 {
     return _nm_platform_ip_address_sync(self, AF_INET6, ifindex, known_addresses, full_sync);
@@ -2188,7 +2187,9 @@ static inline gconstpointer
 nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route)
 {
     nm_assert_addr_family(addr_family);
-    nm_assert(route);
+
+    if (!route)
+        return NULL;
 
     if (NM_IS_IPv4(addr_family))
         return &((NMPlatformIP4Route *) route)->gateway;
@@ -2199,7 +2200,7 @@ int nm_platform_ip_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPObjec
 int nm_platform_ip4_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP4Route *route);
 int nm_platform_ip6_route_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatformIP6Route *route);
 
-GPtrArray *nm_platform_ip_route_get_prune_list(NMPlatform *           self,
+GPtrArray *nm_platform_ip_route_get_prune_list(NMPlatform            *self,
                                                int                    addr_family,
                                                int                    ifindex,
                                                NMIPRouteTableSyncMode route_table_sync);
@@ -2207,19 +2208,19 @@ GPtrArray *nm_platform_ip_route_get_prune_list(NMPlatform *           self,
 gboolean nm_platform_ip_route_sync(NMPlatform *self,
                                    int         addr_family,
                                    int         ifindex,
-                                   GPtrArray * routes,
-                                   GPtrArray * routes_prune,
+                                   GPtrArray  *routes,
+                                   GPtrArray  *routes_prune,
                                    GPtrArray **out_temporary_not_available);
 
 gboolean nm_platform_ip_route_flush(NMPlatform *self, int addr_family, int ifindex);
 
-int nm_platform_ip_route_get(NMPlatform *  self,
+int nm_platform_ip_route_get(NMPlatform   *self,
                              int           addr_family,
                              gconstpointer address,
                              int           oif_ifindex,
-                             NMPObject **  out_route);
+                             NMPObject   **out_route);
 
-int nm_platform_routing_rule_add(NMPlatform *                 self,
+int nm_platform_routing_rule_add(NMPlatform                  *self,
                                  NMPNlmFlags                  flags,
                                  const NMPlatformRoutingRule *routing_rule);
 
@@ -2229,8 +2230,8 @@ int nm_platform_tfilter_add(NMPlatform *self, NMPNlmFlags flags, const NMPlatfor
 int nm_platform_tfilter_delete(NMPlatform *self, int ifindex, guint32 parent, gboolean log_error);
 gboolean nm_platform_tc_sync(NMPlatform *self,
                              int         ifindex,
-                             GPtrArray * known_qdiscs,
-                             GPtrArray * known_tfilters);
+                             GPtrArray  *known_qdiscs,
+                             GPtrArray  *known_tfilters);
 
 const char *nm_platform_link_to_string(const NMPlatformLink *link, char *buf, gsize len);
 const char *nm_platform_lnk_bridge_to_string(const NMPlatformLnkBridge *lnk, char *buf, gsize len);
@@ -2263,10 +2264,10 @@ const char *nm_platform_vf_to_string(const NMPlatformVF *vf, char *buf, gsize le
 const char *
 nm_platform_bridge_vlan_to_string(const NMPlatformBridgeVlan *vlan, char *buf, gsize len);
 
-const char *nm_platform_vlan_qos_mapping_to_string(const char *            name,
+const char *nm_platform_vlan_qos_mapping_to_string(const char             *name,
                                                    const NMVlanQosMapping *map,
                                                    gsize                   n_map,
-                                                   char *                  buf,
+                                                   char                   *buf,
                                                    gsize                   len);
 
 const char *
@@ -2339,13 +2340,13 @@ void nm_platform_ip4_address_hash_update(const NMPlatformIP4Address *obj, NMHash
 void nm_platform_ip6_address_hash_update(const NMPlatformIP6Address *obj, NMHashState *h);
 void nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
                                        NMPlatformIPRouteCmpType  cmp_type,
-                                       NMHashState *             h);
+                                       NMHashState              *h);
 void nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
                                        NMPlatformIPRouteCmpType  cmp_type,
-                                       NMHashState *             h);
+                                       NMHashState              *h);
 void nm_platform_routing_rule_hash_update(const NMPlatformRoutingRule *obj,
                                           NMPlatformRoutingRuleCmpType cmp_type,
-                                          NMHashState *                h);
+                                          NMHashState                 *h);
 void nm_platform_lnk_bridge_hash_update(const NMPlatformLnkBridge *obj, NMHashState *h);
 void nm_platform_lnk_gre_hash_update(const NMPlatformLnkGre *obj, NMHashState *h);
 void nm_platform_lnk_infiniband_hash_update(const NMPlatformLnkInfiniband *obj, NMHashState *h);
@@ -2372,34 +2373,34 @@ const char *nm_platform_route_scope2str(int scope, char *buf, gsize len);
 
 int nm_platform_ip_address_cmp_expiry(const NMPlatformIPAddress *a, const NMPlatformIPAddress *b);
 
-gboolean nm_platform_ethtool_set_wake_on_lan(NMPlatform *             self,
+gboolean nm_platform_ethtool_set_wake_on_lan(NMPlatform              *self,
                                              int                      ifindex,
                                              _NMSettingWiredWakeOnLan wol,
-                                             const char *             wol_password);
-gboolean nm_platform_ethtool_set_link_settings(NMPlatform *             self,
+                                             const char              *wol_password);
+gboolean nm_platform_ethtool_set_link_settings(NMPlatform              *self,
                                                int                      ifindex,
                                                gboolean                 autoneg,
                                                guint32                  speed,
                                                NMPlatformLinkDuplexType duplex);
-gboolean nm_platform_ethtool_get_link_settings(NMPlatform *              self,
+gboolean nm_platform_ethtool_get_link_settings(NMPlatform               *self,
                                                int                       ifindex,
-                                               gboolean *                out_autoneg,
-                                               guint32 *                 out_speed,
+                                               gboolean                 *out_autoneg,
+                                               guint32                  *out_speed,
                                                NMPlatformLinkDuplexType *out_duplex);
 
 NMEthtoolFeatureStates *nm_platform_ethtool_get_link_features(NMPlatform *self, int ifindex);
 gboolean                nm_platform_ethtool_set_features(
-                   NMPlatform *                  self,
+                   NMPlatform                   *self,
                    int                           ifindex,
                    const NMEthtoolFeatureStates *features,
                    const NMOptionBool *requested /* indexed by NMEthtoolID - _NM_ETHTOOL_ID_FEATURE_FIRST */,
                    gboolean            do_set /* or reset */);
 
-gboolean nm_platform_ethtool_get_link_coalesce(NMPlatform *            self,
+gboolean nm_platform_ethtool_get_link_coalesce(NMPlatform             *self,
                                                int                     ifindex,
                                                NMEthtoolCoalesceState *coalesce);
 
-gboolean nm_platform_ethtool_set_coalesce(NMPlatform *                  self,
+gboolean nm_platform_ethtool_set_coalesce(NMPlatform                   *self,
                                           int                           ifindex,
                                           const NMEthtoolCoalesceState *coalesce);
 
@@ -2416,7 +2417,7 @@ nm_platform_ethtool_set_pause(NMPlatform *self, int ifindex, const NMEthtoolPaus
 
 void nm_platform_ip4_dev_route_blacklist_set(NMPlatform *self,
                                              int         ifindex,
-                                             GPtrArray * ip4_dev_route_blacklist);
+                                             GPtrArray  *ip4_dev_route_blacklist);
 
 struct _NMDedupMultiIndex *nm_platform_get_multi_idx(NMPlatform *self);
 
@@ -2426,6 +2427,7 @@ NMPlatformIP4Route *nm_platform_ip4_address_generate_device_route(const NMPlatfo
                                                                   int                 ifindex,
                                                                   guint32             route_table,
                                                                   guint32             route_metric,
+                                                                  gboolean            force_commit,
                                                                   NMPlatformIP4Route *dst);
 
 /*****************************************************************************/
diff --git a/src/libnm-platform/nmp-netns.c b/src/libnm-platform/nmp-netns.c
index d06c3e11..2563e8f6 100644
--- a/src/libnm-platform/nmp-netns.c
+++ b/src/libnm-platform/nmp-netns.c
@@ -147,8 +147,8 @@ static GArray *
 _netns_stack_get_impl(void)
 {
     gs_unref_object NMPNetns *netns = NULL;
-    gs_free_error GError *error     = NULL;
-    GArray *              s;
+    gs_free_error GError     *error = NULL;
+    GArray                   *s;
 
     s = g_array_new(FALSE, FALSE, sizeof(NetnsInfo));
     g_array_set_clear_func(s, _netns_stack_clear_cb);
@@ -444,7 +444,7 @@ nmp_netns_get_fd_mnt(NMPNetns *self)
 static gboolean
 _nmp_netns_push_type(NMPNetns *self, int ns_types)
 {
-    GArray *   netns_stack = _netns_stack_get();
+    GArray    *netns_stack = _netns_stack_get();
     NetnsInfo *info;
     char       sbuf[100];
 
@@ -493,10 +493,10 @@ nmp_netns_push_type(NMPNetns *self, int ns_types)
 NMPNetns *
 nmp_netns_new(void)
 {
-    GArray *      netns_stack = _netns_stack_get();
-    NMPNetns *    self;
+    GArray       *netns_stack = _netns_stack_get();
+    NMPNetns     *self;
     int           errsv;
-    GError *      error      = NULL;
+    GError       *error      = NULL;
     unsigned long mountflags = 0;
 
     if (!_stack_peek(netns_stack)) {
@@ -553,7 +553,7 @@ err_out:
 gboolean
 nmp_netns_pop(NMPNetns *self)
 {
-    GArray *   netns_stack = _netns_stack_get();
+    GArray    *netns_stack = _netns_stack_get();
     NetnsInfo *info;
     int        ns_types;
 
@@ -608,9 +608,9 @@ nmp_netns_is_initial(void)
 gboolean
 nmp_netns_bind_to_path(NMPNetns *self, const char *filename, int *out_fd)
 {
-    gs_free char *    dirname = NULL;
-    int               errsv;
-    int               fd;
+    gs_free char               *dirname = NULL;
+    int                         errsv;
+    int                         fd;
     nm_auto_pop_netns NMPNetns *netns_pop = NULL;
 
     g_return_val_if_fail(NMP_IS_NETNS(self), FALSE);
@@ -690,7 +690,7 @@ nmp_netns_bind_to_path_destroy(NMPNetns *self, const char *filename)
 static void
 set_property(GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec)
 {
-    NMPNetns *       self = NMP_NETNS(object);
+    NMPNetns        *self = NMP_NETNS(object);
     NMPNetnsPrivate *priv = NMP_NETNS_GET_PRIVATE(self);
 
     switch (prop_id) {
@@ -717,7 +717,7 @@ nmp_netns_init(NMPNetns *self)
 static void
 dispose(GObject *object)
 {
-    NMPNetns *       self = NMP_NETNS(object);
+    NMPNetns        *self = NMP_NETNS(object);
     NMPNetnsPrivate *priv = NMP_NETNS_GET_PRIVATE(self);
 
     nm_close(priv->fd_net);
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index 559fd8d6..d518e6e5 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -279,8 +279,8 @@ static const NMDedupMultiIdxTypeClass _dedup_multi_idx_type_class;
 
 static void
 _idx_obj_id_hash_update(const NMDedupMultiIdxType *idx_type,
-                        const NMDedupMultiObj *    obj,
-                        NMHashState *              h)
+                        const NMDedupMultiObj     *obj,
+                        NMHashState               *h)
 {
     const NMPObject *o = (NMPObject *) obj;
 
@@ -292,8 +292,8 @@ _idx_obj_id_hash_update(const NMDedupMultiIdxType *idx_type,
 
 static gboolean
 _idx_obj_id_equal(const NMDedupMultiIdxType *idx_type,
-                  const NMDedupMultiObj *    obj_a,
-                  const NMDedupMultiObj *    obj_b)
+                  const NMDedupMultiObj     *obj_a,
+                  const NMDedupMultiObj     *obj_b)
 {
     const NMPObject *o_a = (NMPObject *) obj_a;
     const NMPObject *o_b = (NMPObject *) obj_b;
@@ -307,9 +307,9 @@ _idx_obj_id_equal(const NMDedupMultiIdxType *idx_type,
 
 static guint
 _idx_obj_part(const DedupMultiIdxType *idx_type,
-              const NMPObject *        obj_a,
-              const NMPObject *        obj_b,
-              NMHashState *            h)
+              const NMPObject         *obj_a,
+              const NMPObject         *obj_b,
+              NMHashState             *h)
 {
     NMPObjectType obj_type;
 
@@ -386,7 +386,11 @@ _idx_obj_part(const DedupMultiIdxType *idx_type,
                 nm_hash_update_val(h, obj_a);
             return 0;
         }
-        nm_assert(NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex > 0);
+        nm_assert(NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex > 0
+                  || (NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex == 0
+                      && NM_IN_SET(NMP_OBJECT_GET_TYPE(obj_a),
+                                   NMP_OBJECT_TYPE_IP4_ROUTE,
+                                   NMP_OBJECT_TYPE_IP6_ROUTE)));
         if (obj_b) {
             return NMP_OBJECT_GET_TYPE(obj_a) == NMP_OBJECT_GET_TYPE(obj_b)
                    && NMP_OBJECT_CAST_OBJ_WITH_IFINDEX(obj_a)->ifindex
@@ -401,14 +405,14 @@ _idx_obj_part(const DedupMultiIdxType *idx_type,
     case NMP_CACHE_ID_TYPE_ROUTES_BY_WEAK_ID:
         obj_type = NMP_OBJECT_GET_TYPE(obj_a);
         if (!NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)
-            || NMP_OBJECT_CAST_IP_ROUTE(obj_a)->ifindex <= 0) {
+            || NMP_OBJECT_CAST_IP_ROUTE(obj_a)->ifindex < 0) {
             if (h)
                 nm_hash_update_val(h, obj_a);
             return 0;
         }
         if (obj_b) {
             return obj_type == NMP_OBJECT_GET_TYPE(obj_b)
-                   && NMP_OBJECT_CAST_IP_ROUTE(obj_b)->ifindex > 0
+                   && NMP_OBJECT_CAST_IP_ROUTE(obj_b)->ifindex >= 0
                    && (obj_type == NMP_OBJECT_TYPE_IP4_ROUTE
                            ? (nm_platform_ip4_route_cmp(&obj_a->ip4_route,
                                                         &obj_b->ip4_route,
@@ -466,16 +470,16 @@ _idx_obj_partitionable(const NMDedupMultiIdxType *idx_type, const NMDedupMultiOb
 
 static void
 _idx_obj_partition_hash_update(const NMDedupMultiIdxType *idx_type,
-                               const NMDedupMultiObj *    obj,
-                               NMHashState *              h)
+                               const NMDedupMultiObj     *obj,
+                               NMHashState               *h)
 {
     _idx_obj_part((DedupMultiIdxType *) idx_type, (NMPObject *) obj, NULL, h);
 }
 
 static gboolean
 _idx_obj_partition_equal(const NMDedupMultiIdxType *idx_type,
-                         const NMDedupMultiObj *    obj_a,
-                         const NMDedupMultiObj *    obj_b)
+                         const NMDedupMultiObj     *obj_a,
+                         const NMDedupMultiObj     *obj_b)
 {
     return _idx_obj_part((DedupMultiIdxType *) idx_type,
                          (NMPObject *) obj_a,
@@ -528,8 +532,8 @@ _vlan_xgress_qos_mappings_cmp(guint                   n_map,
 }
 
 static void
-_vlan_xgress_qos_mappings_cpy(guint *                 dst_n_map,
-                              NMVlanQosMapping **     dst_map,
+_vlan_xgress_qos_mappings_cpy(guint                  *dst_n_map,
+                              NMVlanQosMapping      **dst_map,
                               guint                   src_n_map,
                               const NMVlanQosMapping *src_map)
 {
@@ -655,7 +659,7 @@ _nmp_object_fixup_link_udev_fields(NMPObject **obj_new, NMPObject *obj_orig, gbo
 {
     const char *driver      = NULL;
     gboolean    initialized = FALSE;
-    NMPObject * obj;
+    NMPObject  *obj;
 
     nm_assert(obj_orig || *obj_new);
     nm_assert(obj_new);
@@ -695,8 +699,8 @@ _nmp_object_fixup_link_udev_fields(NMPObject **obj_new, NMPObject *obj_orig, gbo
 }
 
 static void
-_nmp_object_fixup_link_master_connected(NMPObject **    obj_new,
-                                        NMPObject *     obj_orig,
+_nmp_object_fixup_link_master_connected(NMPObject     **obj_new,
+                                        NMPObject      *obj_orig,
                                         const NMPCache *cache)
 {
     NMPObject *obj;
@@ -775,7 +779,7 @@ NMPObject *
 nmp_object_new(NMPObjectType obj_type, gconstpointer plobj)
 {
     const NMPClass *klass = nmp_class_from_type(obj_type);
-    NMPObject *     obj;
+    NMPObject      *obj;
 
     obj = _nmp_object_new_from_class(klass);
     if (plobj)
@@ -891,9 +895,9 @@ nmp_object_stackinit_id_ip6_address(NMPObject *obj, int ifindex, const struct in
 /*****************************************************************************/
 
 const char *
-nmp_object_to_string(const NMPObject *     obj,
+nmp_object_to_string(const NMPObject      *obj,
                      NMPObjectToStringMode to_string_mode,
-                     char *                buf,
+                     char                 *buf,
                      gsize                 buf_size)
 {
     const NMPClass *klass;
@@ -937,13 +941,13 @@ nmp_object_to_string(const NMPObject *     obj,
 }
 
 static const char *
-_vt_cmd_obj_to_string_link(const NMPObject *     obj,
+_vt_cmd_obj_to_string_link(const NMPObject      *obj,
                            NMPObjectToStringMode to_string_mode,
-                           char *                buf,
+                           char                 *buf,
                            gsize                 buf_size)
 {
     const NMPClass *klass = NMP_OBJECT_GET_CLASS(obj);
-    char *          b     = buf;
+    char           *b     = buf;
 
     switch (to_string_mode) {
     case NMP_OBJECT_TO_STRING_ID:
@@ -982,14 +986,14 @@ _vt_cmd_obj_to_string_link(const NMPObject *     obj,
 }
 
 static const char *
-_vt_cmd_obj_to_string_lnk_vlan(const NMPObject *     obj,
+_vt_cmd_obj_to_string_lnk_vlan(const NMPObject      *obj,
                                NMPObjectToStringMode to_string_mode,
-                               char *                buf,
+                               char                 *buf,
                                gsize                 buf_size)
 {
     const NMPClass *klass;
     char            buf2[sizeof(_nm_utils_to_string_buffer)];
-    char *          b;
+    char           *b;
     gsize           l;
 
     klass = NMP_OBJECT_GET_CLASS(obj);
@@ -1046,14 +1050,14 @@ _vt_cmd_obj_to_string_lnk_vlan(const NMPObject *     obj,
 }
 
 static const char *
-_vt_cmd_obj_to_string_lnk_wireguard(const NMPObject *     obj,
+_vt_cmd_obj_to_string_lnk_wireguard(const NMPObject      *obj,
                                     NMPObjectToStringMode to_string_mode,
-                                    char *                buf,
+                                    char                 *buf,
                                     gsize                 buf_size)
 {
     const NMPClass *klass;
     char            buf2[sizeof(_nm_utils_to_string_buffer)];
-    char *          b;
+    char           *b;
     guint           i;
 
     klass = NMP_OBJECT_GET_CLASS(obj);
@@ -1100,7 +1104,7 @@ _vt_cmd_obj_to_string_lnk_wireguard(const NMPObject *     obj,
 
 #define _vt_cmd_plobj_to_string_id(type, plat_type, ...)                                  \
     static const char *_vt_cmd_plobj_to_string_id_##type(const NMPlatformObject *_obj,    \
-                                                         char *                  buf,     \
+                                                         char                   *buf,     \
                                                          gsize                   buf_len) \
     {                                                                                     \
         plat_type *const obj = (plat_type *) _obj;                                        \
@@ -1740,8 +1744,7 @@ _vt_cmd_obj_is_alive_ipx_route(const NMPObject *obj)
      * Instead we create a dead object, and nmp_cache_update_netlink()
      * will remove the old version of the update.
      **/
-    return NMP_OBJECT_CAST_IP_ROUTE(obj)->ifindex > 0
-           && !NM_FLAGS_HAS(obj->ip_route.r_rtm_flags, RTM_F_CLONED);
+    return !NM_FLAGS_HAS(NMP_OBJECT_CAST_IP_ROUTE(obj)->r_rtm_flags, RTM_F_CLONED);
 }
 
 static gboolean
@@ -1825,7 +1828,7 @@ static const guint8 _supported_cache_ids_routing_rules[] = {
 static void
 _vt_dedup_obj_destroy(NMDedupMultiObj *obj)
 {
-    NMPObject *     o = (NMPObject *) obj;
+    NMPObject      *o = (NMPObject *) obj;
     const NMPClass *klass;
 
     nm_assert(o->parent._ref_count == 0);
@@ -1907,7 +1910,7 @@ nmp_cache_link_connected_for_slave(int ifindex_master, const NMPObject *slave)
  * Returns: %TRUE, if @master->link.connected should be flipped/toggled.
  **/
 gboolean
-nmp_cache_link_connected_needs_toggle(const NMPCache * cache,
+nmp_cache_link_connected_needs_toggle(const NMPCache  *cache,
                                       const NMPObject *master,
                                       const NMPObject *potential_slave,
                                       const NMPObject *ignore_slave)
@@ -1972,7 +1975,7 @@ nmp_cache_link_connected_needs_toggle(const NMPCache * cache,
  *   The connected flag of that master should be toggled.
  */
 const NMPObject *
-nmp_cache_link_connected_needs_toggle_by_ifindex(const NMPCache * cache,
+nmp_cache_link_connected_needs_toggle_by_ifindex(const NMPCache  *cache,
                                                  int              master_ifindex,
                                                  const NMPObject *potential_slave,
                                                  const NMPObject *ignore_slave)
@@ -1990,7 +1993,7 @@ nmp_cache_link_connected_needs_toggle_by_ifindex(const NMPCache * cache,
 /*****************************************************************************/
 
 static const NMDedupMultiEntry *
-_lookup_entry_with_idx_type(const NMPCache * cache,
+_lookup_entry_with_idx_type(const NMPCache  *cache,
                             NMPCacheIdType   cache_id_type,
                             const NMPObject *obj)
 {
@@ -2014,7 +2017,7 @@ _lookup_entry(const NMPCache *cache, const NMPObject *obj)
 }
 
 const NMDedupMultiEntry *
-nmp_cache_lookup_entry_with_idx_type(const NMPCache * cache,
+nmp_cache_lookup_entry_with_idx_type(const NMPCache  *cache,
                                      NMPCacheIdType   cache_id_type,
                                      const NMPObject *obj)
 {
@@ -2063,7 +2066,7 @@ nmp_cache_lookup_link(const NMPCache *cache, int ifindex)
 /*****************************************************************************/
 
 const NMDedupMultiHeadEntry *
-nmp_cache_lookup_all(const NMPCache * cache,
+nmp_cache_lookup_all(const NMPCache  *cache,
                      NMPCacheIdType   cache_id_type,
                      const NMPObject *select_obj)
 {
@@ -2143,7 +2146,15 @@ nmp_lookup_init_object(NMPLookup *lookup, NMPObjectType obj_type, int ifindex)
                         NMP_OBJECT_TYPE_QDISC,
                         NMP_OBJECT_TYPE_TFILTER));
 
-    if (ifindex <= 0) {
+    if (G_UNLIKELY(
+            (ifindex < 0)
+            || (ifindex == 0
+                && !NM_IN_SET(obj_type, NMP_OBJECT_TYPE_IP4_ROUTE, NMP_OBJECT_TYPE_IP6_ROUTE)))) {
+        /* This function used to have a fallback that meant to lookup all objects, if
+         * ifindex is non-positive. As routes can have a zero ifindex, that fallback is
+         * confusing and no longer supported. Only have this code, to catch accidental bugs
+         * after the API change. */
+        nm_assert_not_reached();
         return nmp_lookup_init_obj_type(lookup, obj_type);
     }
 
@@ -2220,7 +2231,7 @@ nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup,
 }
 
 const NMPLookup *
-nmp_lookup_init_ip6_route_by_weak_id(NMPLookup *            lookup,
+nmp_lookup_init_ip6_route_by_weak_id(NMPLookup             *lookup,
                                      const struct in6_addr *network,
                                      guint                  plen,
                                      guint32                metric,
@@ -2269,10 +2280,10 @@ nmp_cache_lookup_to_array(const NMDedupMultiHeadEntry *head_entry,
                           NMPObjectType                obj_type,
                           gboolean                     visible_only)
 {
-    const NMPClass * klass = nmp_class_from_type(obj_type);
+    const NMPClass  *klass = nmp_class_from_type(obj_type);
     NMDedupMultiIter iter;
     const NMPObject *o;
-    GArray *         array;
+    GArray          *array;
 
     g_return_val_if_fail(klass, NULL);
 
@@ -2289,19 +2300,19 @@ nmp_cache_lookup_to_array(const NMDedupMultiHeadEntry *head_entry,
 /*****************************************************************************/
 
 const NMPObject *
-nmp_cache_lookup_link_full(const NMPCache * cache,
+nmp_cache_lookup_link_full(const NMPCache  *cache,
                            int              ifindex,
-                           const char *     ifname,
+                           const char      *ifname,
                            gboolean         visible_only,
                            NMLinkType       link_type,
                            NMPObjectMatchFn match_fn,
                            gpointer         user_data)
 {
     NMPObject                    obj_needle;
-    const NMPObject *            obj;
+    const NMPObject             *obj;
     NMDedupMultiIter             iter;
     const NMDedupMultiHeadEntry *head_entry;
-    const NMPlatformLink *       link = NULL;
+    const NMPlatformLink        *link = NULL;
     NMPLookup                    lookup;
 
     if (ifindex > 0) {
@@ -2369,8 +2380,8 @@ _obj_get_add_mode(const NMPObject *obj)
 static void
 _idxcache_update_order_for_dump(NMPCache *cache, const NMDedupMultiEntry *entry)
 {
-    const NMPClass *         klass;
-    const guint8 *           i_idx_type;
+    const NMPClass          *klass;
+    const guint8            *i_idx_type;
     const NMDedupMultiEntry *entry2;
 
     nm_dedup_multi_entry_reorder(entry, NULL, TRUE);
@@ -2396,7 +2407,7 @@ _idxcache_update_order_for_dump(NMPCache *cache, const NMDedupMultiEntry *entry)
 }
 
 static void
-_idxcache_update_other_cache_ids(NMPCache *       cache,
+_idxcache_update_other_cache_ids(NMPCache        *cache,
                                  NMPCacheIdType   cache_id_type,
                                  const NMPObject *obj_old,
                                  const NMPObject *obj_new,
@@ -2405,7 +2416,7 @@ _idxcache_update_other_cache_ids(NMPCache *       cache,
     const NMDedupMultiEntry *entry_new;
     const NMDedupMultiEntry *entry_old;
     const NMDedupMultiEntry *entry_order;
-    NMDedupMultiIdxType *    idx_type;
+    NMDedupMultiIdxType     *idx_type;
 
     nm_assert(obj_new || obj_old);
     nm_assert(!obj_new || NMP_OBJECT_GET_TYPE(obj_new) != NMP_OBJECT_TYPE_UNKNOWN);
@@ -2474,15 +2485,15 @@ _idxcache_update_other_cache_ids(NMPCache *       cache,
 }
 
 static void
-_idxcache_update(NMPCache *                cache,
-                 const NMDedupMultiEntry * entry_old,
-                 NMPObject *               obj_new,
+_idxcache_update(NMPCache                 *cache,
+                 const NMDedupMultiEntry  *entry_old,
+                 NMPObject                *obj_new,
                  gboolean                  is_dump,
                  const NMDedupMultiEntry **out_entry_new)
 {
-    const NMPClass *         klass;
-    const guint8 *           i_idx_type;
-    NMDedupMultiIdxType *    idx_type_o     = _idx_type_get(cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE);
+    const NMPClass          *klass;
+    const guint8            *i_idx_type;
+    NMDedupMultiIdxType     *idx_type_o     = _idx_type_get(cache, NMP_CACHE_ID_TYPE_OBJECT_TYPE);
     const NMDedupMultiEntry *entry_new      = NULL;
     nm_auto_nmpobj const NMPObject *obj_old = NULL;
 
@@ -2559,14 +2570,14 @@ _idxcache_update(NMPCache *                cache,
 }
 
 NMPCacheOpsType
-nmp_cache_remove(NMPCache *        cache,
-                 const NMPObject * obj_needle,
+nmp_cache_remove(NMPCache         *cache,
+                 const NMPObject  *obj_needle,
                  gboolean          equals_by_ptr,
                  gboolean          only_dirty,
                  const NMPObject **out_obj_old)
 {
     const NMDedupMultiEntry *entry_old;
-    const NMPObject *        obj_old;
+    const NMPObject         *obj_old;
 
     entry_old = _lookup_entry(cache, obj_needle);
 
@@ -2593,14 +2604,14 @@ nmp_cache_remove(NMPCache *        cache,
 }
 
 NMPCacheOpsType
-nmp_cache_remove_netlink(NMPCache *        cache,
-                         const NMPObject * obj_needle,
+nmp_cache_remove_netlink(NMPCache         *cache,
+                         const NMPObject  *obj_needle,
                          const NMPObject **out_obj_old,
                          const NMPObject **out_obj_new)
 {
-    const NMDedupMultiEntry *entry_old;
-    const NMDedupMultiEntry *entry_new = NULL;
-    const NMPObject *        obj_old;
+    const NMDedupMultiEntry  *entry_old;
+    const NMDedupMultiEntry  *entry_new = NULL;
+    const NMPObject          *obj_old;
     nm_auto_nmpobj NMPObject *obj_new = NULL;
 
     entry_old = _lookup_entry(cache, obj_needle);
@@ -2679,15 +2690,15 @@ nmp_cache_remove_netlink(NMPCache *        cache,
  * and @out_obj_new will be set accordingly.
  **/
 NMPCacheOpsType
-nmp_cache_update_netlink(NMPCache *        cache,
-                         NMPObject *       obj_hand_over,
+nmp_cache_update_netlink(NMPCache         *cache,
+                         NMPObject        *obj_hand_over,
                          gboolean          is_dump,
                          const NMPObject **out_obj_old,
                          const NMPObject **out_obj_new)
 {
     const NMDedupMultiEntry *entry_old;
     const NMDedupMultiEntry *entry_new;
-    const NMPObject *        obj_old;
+    const NMPObject         *obj_old;
     gboolean                 is_alive;
 
     nm_assert(cache);
@@ -2789,20 +2800,20 @@ nmp_cache_update_netlink(NMPCache *        cache,
 }
 
 NMPCacheOpsType
-nmp_cache_update_netlink_route(NMPCache *        cache,
-                               NMPObject *       obj_hand_over,
+nmp_cache_update_netlink_route(NMPCache         *cache,
+                               NMPObject        *obj_hand_over,
                                gboolean          is_dump,
                                guint16           nlmsgflags,
                                const NMPObject **out_obj_old,
                                const NMPObject **out_obj_new,
                                const NMPObject **out_obj_replace,
-                               gboolean *        out_resync_required)
+                               gboolean         *out_resync_required)
 {
     NMDedupMultiIter             iter;
-    const NMDedupMultiEntry *    entry_old;
-    const NMDedupMultiEntry *    entry_new;
-    const NMDedupMultiEntry *    entry_cur;
-    const NMDedupMultiEntry *    entry_replace;
+    const NMDedupMultiEntry     *entry_old;
+    const NMDedupMultiEntry     *entry_new;
+    const NMDedupMultiEntry     *entry_cur;
+    const NMDedupMultiEntry     *entry_replace;
     const NMDedupMultiHeadEntry *head_entry;
     gboolean                     is_alive;
     NMPCacheOpsType              ops_type = NMP_CACHE_OPS_UNCHANGED;
@@ -2937,16 +2948,16 @@ out:
 }
 
 NMPCacheOpsType
-nmp_cache_update_link_udev(NMPCache *          cache,
+nmp_cache_update_link_udev(NMPCache           *cache,
                            int                 ifindex,
                            struct udev_device *udevice,
-                           const NMPObject **  out_obj_old,
-                           const NMPObject **  out_obj_new)
+                           const NMPObject   **out_obj_old,
+                           const NMPObject   **out_obj_new)
 {
-    const NMPObject *obj_old;
+    const NMPObject          *obj_old;
     nm_auto_nmpobj NMPObject *obj_new = NULL;
-    const NMDedupMultiEntry * entry_old;
-    const NMDedupMultiEntry * entry_new;
+    const NMDedupMultiEntry  *entry_old;
+    const NMDedupMultiEntry  *entry_new;
 
     entry_old = nmp_cache_lookup_entry_link(cache, ifindex);
 
@@ -2997,14 +3008,14 @@ nmp_cache_update_link_udev(NMPCache *          cache,
 }
 
 NMPCacheOpsType
-nmp_cache_update_link_master_connected(NMPCache *        cache,
+nmp_cache_update_link_master_connected(NMPCache         *cache,
                                        int               ifindex,
                                        const NMPObject **out_obj_old,
                                        const NMPObject **out_obj_new)
 {
-    const NMDedupMultiEntry *entry_old;
-    const NMDedupMultiEntry *entry_new = NULL;
-    const NMPObject *        obj_old;
+    const NMDedupMultiEntry  *entry_old;
+    const NMDedupMultiEntry  *entry_new = NULL;
+    const NMPObject          *obj_old;
     nm_auto_nmpobj NMPObject *obj_new = NULL;
 
     entry_old = nmp_cache_lookup_entry_link(cache, ifindex);
diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h
index bf140d78..784dcc2d 100644
--- a/src/libnm-platform/nmp-object.h
+++ b/src/libnm-platform/nmp-object.h
@@ -170,9 +170,9 @@ typedef enum {
 
 typedef struct {
     NMDedupMultiObjClass   parent;
-    const char *           obj_type_name;
-    const char *           signal_type;
-    const guint8 *         supported_cache_ids;
+    const char            *obj_type_name;
+    const char            *signal_type;
+    const guint8          *supported_cache_ids;
     int                    sizeof_data;
     int                    sizeof_public;
     int                    addr_family;
@@ -189,9 +189,9 @@ typedef struct {
     void (*cmd_obj_dispose)(NMPObject *obj);
     gboolean (*cmd_obj_is_alive)(const NMPObject *obj);
     gboolean (*cmd_obj_is_visible)(const NMPObject *obj);
-    const char *(*cmd_obj_to_string)(const NMPObject *     obj,
+    const char *(*cmd_obj_to_string)(const NMPObject      *obj,
                                      NMPObjectToStringMode to_string_mode,
-                                     char *                buf,
+                                     char                 *buf,
                                      gsize                 buf_size);
 
     /* functions that operate on NMPlatformObject */
@@ -302,7 +302,7 @@ typedef struct {
 
 typedef struct {
     NMPlatformLnkWireGuard       _public;
-    const NMPWireGuardPeer *     peers;
+    const NMPWireGuardPeer      *peers;
     const NMPWireGuardAllowedIP *_allowed_ips_buf;
     guint                        peers_len;
     guint                        _allowed_ips_buf_len;
@@ -662,7 +662,7 @@ nmp_object_ref_set_up_cast(gpointer pp, gconstpointer obj)
 {
     gboolean         _changed = FALSE;
     const NMPObject *p;
-    gconstpointer *  pp2 = pp;
+    gconstpointer   *pp2 = pp;
 
     nm_assert(!pp2 || !*pp2 || NMP_OBJECT_IS_VALID(NMP_OBJECT_UP_CAST(*pp2)));
     nm_assert(!obj || NMP_OBJECT_IS_VALID(NMP_OBJECT_UP_CAST(obj)));
@@ -699,9 +699,9 @@ const NMPObject *nmp_object_stackinit_id_ip4_address(NMPObject *obj,
 const NMPObject *
 nmp_object_stackinit_id_ip6_address(NMPObject *obj, int ifindex, const struct in6_addr *address);
 
-const char *nmp_object_to_string(const NMPObject *     obj,
+const char *nmp_object_to_string(const NMPObject      *obj,
                                  NMPObjectToStringMode to_string_mode,
-                                 char *                buf,
+                                 char                 *buf,
                                  gsize                 buf_size);
 void        nmp_object_hash_update(const NMPObject *obj, NMHashState *h);
 
@@ -758,7 +758,7 @@ _nm_auto_nmpobj_cleanup(gpointer p)
 
 typedef struct _NMPCache NMPCache;
 
-typedef void (*NMPCachePreHook)(NMPCache *       cache,
+typedef void (*NMPCachePreHook)(NMPCache        *cache,
                                 const NMPObject *old,
                                 const NMPObject *new,
                                 NMPCacheOpsType ops_type,
@@ -766,12 +766,12 @@ typedef void (*NMPCachePreHook)(NMPCache *       cache,
 typedef gboolean (*NMPObjectMatchFn)(const NMPObject *obj, gpointer user_data);
 
 const NMDedupMultiEntry *nmp_cache_lookup_entry(const NMPCache *cache, const NMPObject *obj);
-const NMDedupMultiEntry *nmp_cache_lookup_entry_with_idx_type(const NMPCache * cache,
+const NMDedupMultiEntry *nmp_cache_lookup_entry_with_idx_type(const NMPCache  *cache,
                                                               NMPCacheIdType   cache_id_type,
                                                               const NMPObject *obj);
 const NMDedupMultiEntry *nmp_cache_lookup_entry_link(const NMPCache *cache, int ifindex);
-const NMPObject *        nmp_cache_lookup_obj(const NMPCache *cache, const NMPObject *obj);
-const NMPObject *        nmp_cache_lookup_link(const NMPCache *cache, int ifindex);
+const NMPObject         *nmp_cache_lookup_obj(const NMPCache *cache, const NMPObject *obj);
+const NMPObject         *nmp_cache_lookup_link(const NMPCache *cache, int ifindex);
 
 typedef struct _NMPLookup NMPLookup;
 
@@ -780,7 +780,7 @@ struct _NMPLookup {
     NMPObject      selector_obj;
 };
 
-const NMDedupMultiHeadEntry *nmp_cache_lookup_all(const NMPCache * cache,
+const NMDedupMultiHeadEntry *nmp_cache_lookup_all(const NMPCache  *cache,
                                                   NMPCacheIdType   cache_id_type,
                                                   const NMPObject *select_obj);
 
@@ -800,7 +800,7 @@ const NMPLookup *nmp_lookup_init_ip4_route_by_weak_id(NMPLookup *lookup,
                                                       guint      plen,
                                                       guint32    metric,
                                                       guint8     tos);
-const NMPLookup *nmp_lookup_init_ip6_route_by_weak_id(NMPLookup *            lookup,
+const NMPLookup *nmp_lookup_init_ip6_route_by_weak_id(NMPLookup             *lookup,
                                                       const struct in6_addr *network,
                                                       guint                  plen,
                                                       guint32                metric,
@@ -858,20 +858,20 @@ nmp_cache_iter_next_link(NMDedupMultiIter *iter, const NMPlatformLink **out_obj)
 #define nmp_cache_iter_for_each_link(iter, head, obj) \
     for (nm_dedup_multi_iter_init((iter), (head)); nmp_cache_iter_next_link((iter), (obj));)
 
-const NMPObject *nmp_cache_lookup_link_full(const NMPCache * cache,
+const NMPObject *nmp_cache_lookup_link_full(const NMPCache  *cache,
                                             int              ifindex,
-                                            const char *     ifname,
+                                            const char      *ifname,
                                             gboolean         visible_only,
                                             NMLinkType       link_type,
                                             NMPObjectMatchFn match_fn,
                                             gpointer         user_data);
 
 gboolean         nmp_cache_link_connected_for_slave(int ifindex_master, const NMPObject *slave);
-gboolean         nmp_cache_link_connected_needs_toggle(const NMPCache * cache,
+gboolean         nmp_cache_link_connected_needs_toggle(const NMPCache  *cache,
                                                        const NMPObject *master,
                                                        const NMPObject *potential_slave,
                                                        const NMPObject *ignore_slave);
-const NMPObject *nmp_cache_link_connected_needs_toggle_by_ifindex(const NMPCache * cache,
+const NMPObject *nmp_cache_link_connected_needs_toggle_by_ifindex(const NMPCache  *cache,
                                                                   int              master_ifindex,
                                                                   const NMPObject *potential_slave,
                                                                   const NMPObject *ignore_slave);
@@ -880,42 +880,42 @@ gboolean nmp_cache_use_udev_get(const NMPCache *cache);
 
 void nmtst_assert_nmp_cache_is_consistent(const NMPCache *cache);
 
-NMPCacheOpsType nmp_cache_remove(NMPCache *        cache,
-                                 const NMPObject * obj_needle,
+NMPCacheOpsType nmp_cache_remove(NMPCache         *cache,
+                                 const NMPObject  *obj_needle,
                                  gboolean          equals_by_ptr,
                                  gboolean          only_dirty,
                                  const NMPObject **out_obj_old);
-NMPCacheOpsType nmp_cache_remove_netlink(NMPCache *        cache,
-                                         const NMPObject * obj_needle,
+NMPCacheOpsType nmp_cache_remove_netlink(NMPCache         *cache,
+                                         const NMPObject  *obj_needle,
                                          const NMPObject **out_obj_old,
                                          const NMPObject **out_obj_new);
-NMPCacheOpsType nmp_cache_update_netlink(NMPCache *        cache,
-                                         NMPObject *       obj_hand_over,
+NMPCacheOpsType nmp_cache_update_netlink(NMPCache         *cache,
+                                         NMPObject        *obj_hand_over,
                                          gboolean          is_dump,
                                          const NMPObject **out_obj_old,
                                          const NMPObject **out_obj_new);
-NMPCacheOpsType nmp_cache_update_netlink_route(NMPCache *        cache,
-                                               NMPObject *       obj_hand_over,
+NMPCacheOpsType nmp_cache_update_netlink_route(NMPCache         *cache,
+                                               NMPObject        *obj_hand_over,
                                                gboolean          is_dump,
                                                guint16           nlmsgflags,
                                                const NMPObject **out_obj_old,
                                                const NMPObject **out_obj_new,
                                                const NMPObject **out_obj_replace,
-                                               gboolean *        out_resync_required);
-NMPCacheOpsType nmp_cache_update_link_udev(NMPCache *          cache,
+                                               gboolean         *out_resync_required);
+NMPCacheOpsType nmp_cache_update_link_udev(NMPCache           *cache,
                                            int                 ifindex,
                                            struct udev_device *udevice,
-                                           const NMPObject **  out_obj_old,
-                                           const NMPObject **  out_obj_new);
-NMPCacheOpsType nmp_cache_update_link_master_connected(NMPCache *        cache,
+                                           const NMPObject   **out_obj_old,
+                                           const NMPObject   **out_obj_new);
+NMPCacheOpsType nmp_cache_update_link_master_connected(NMPCache         *cache,
                                                        int               ifindex,
                                                        const NMPObject **out_obj_old,
                                                        const NMPObject **out_obj_new);
 
 static inline const NMDedupMultiEntry *
-nmp_cache_reresolve_main_entry(NMPCache *               cache,
+nmp_cache_reresolve_main_entry(NMPCache                *cache,
                                const NMDedupMultiEntry *entry,
-                               const NMPLookup *        lookup)
+                               const NMPLookup         *lookup)
 {
     const NMDedupMultiEntry *main_entry;
 
@@ -944,7 +944,7 @@ NMPCache *nmp_cache_new(NMDedupMultiIndex *multi_idx, gboolean use_udev);
 void      nmp_cache_free(NMPCache *cache);
 
 static inline void
-ASSERT_nmp_cache_ops(const NMPCache * cache,
+ASSERT_nmp_cache_ops(const NMPCache  *cache,
                      NMPCacheOpsType  ops_type,
                      const NMPObject *obj_old,
                      const NMPObject *obj_new)
@@ -1024,7 +1024,7 @@ nm_platform_lookup_object(NMPlatform *platform, NMPObjectType obj_type, int ifin
 }
 
 static inline GPtrArray *
-nm_platform_lookup_object_clone(NMPlatform *           platform,
+nm_platform_lookup_object_clone(NMPlatform            *platform,
                                 NMPObjectType          obj_type,
                                 int                    ifindex,
                                 NMPObjectPredicateFunc predicate,
@@ -1046,7 +1046,7 @@ nm_platform_lookup_route_default(NMPlatform *platform, NMPObjectType obj_type)
 }
 
 static inline GPtrArray *
-nm_platform_lookup_route_default_clone(NMPlatform *           platform,
+nm_platform_lookup_route_default_clone(NMPlatform            *platform,
                                        NMPObjectType          obj_type,
                                        NMPObjectPredicateFunc predicate,
                                        gpointer               user_data)
@@ -1071,7 +1071,7 @@ nm_platform_lookup_ip4_route_by_weak_id(NMPlatform *platform,
 }
 
 static inline const NMDedupMultiHeadEntry *
-nm_platform_lookup_ip6_route_by_weak_id(NMPlatform *           platform,
+nm_platform_lookup_ip6_route_by_weak_id(NMPlatform            *platform,
                                         const struct in6_addr *network,
                                         guint                  plen,
                                         guint32                metric,
@@ -1085,7 +1085,7 @@ nm_platform_lookup_ip6_route_by_weak_id(NMPlatform *           platform,
 }
 
 static inline const NMDedupMultiHeadEntry *
-nm_platform_lookup_object_by_addr_family(NMPlatform *  platform,
+nm_platform_lookup_object_by_addr_family(NMPlatform   *platform,
                                          NMPObjectType obj_type,
                                          int           addr_family)
 {
@@ -1112,6 +1112,21 @@ nmp_object_get_assume_config_once(const NMPObject *obj)
     }
 }
 
+static inline gboolean
+nmp_object_get_force_commit(const NMPObject *obj)
+{
+    switch (NMP_OBJECT_GET_TYPE(obj)) {
+    case NMP_OBJECT_TYPE_IP4_ADDRESS:
+    case NMP_OBJECT_TYPE_IP6_ADDRESS:
+        return NMP_OBJECT_CAST_IP_ADDRESS(obj)->a_force_commit;
+    case NMP_OBJECT_TYPE_IP4_ROUTE:
+    case NMP_OBJECT_TYPE_IP6_ROUTE:
+        return NMP_OBJECT_CAST_IP_ROUTE(obj)->r_force_commit;
+    default:
+        return nm_assert_unreachable_val(FALSE);
+    }
+}
+
 static inline const char *
 nmp_object_link_get_ifname(const NMPObject *obj)
 {
diff --git a/src/libnm-platform/nmp-route-manager.c b/src/libnm-platform/nmp-route-manager.c
new file mode 100644
index 00000000..c31c9806
--- /dev/null
+++ b/src/libnm-platform/nmp-route-manager.c
@@ -0,0 +1,839 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#include "libnm-glib-aux/nm-default-glib-i18n-lib.h"
+
+#include "nmp-route-manager.h"
+
+#include <linux/fib_rules.h>
+#include <linux/rtnetlink.h>
+
+#include "libnm-log-core/nm-logging.h"
+#include "libnm-std-aux/c-list-util.h"
+#include "nmp-object.h"
+
+/*****************************************************************************/
+
+struct _NMPRouteManager {
+    NMPlatform *platform;
+    GHashTable *by_obj;
+    GHashTable *by_user_tag;
+    GHashTable *by_data;
+    CList       by_obj_lst_heads[3];
+    guint       ref_count;
+};
+
+/*****************************************************************************/
+
+#define _NMLOG_DOMAIN      LOGD_PLATFORM
+#define _NMLOG_PREFIX_NAME "route-manager"
+
+#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, LOGD_PLATFORM, _NMLOG_PREFIX_NAME, __VA_ARGS__)
+
+/*****************************************************************************/
+
+static gboolean
+NMP_IS_ROUTE_MANAGER(gpointer self)
+{
+    return self && ((NMPRouteManager *) self)->ref_count > 0
+           && NM_IS_PLATFORM(((NMPRouteManager *) self)->platform);
+}
+
+/*****************************************************************************/
+
+typedef struct {
+    const NMPObject *obj;
+    gconstpointer    user_tag;
+    CList            obj_lst;
+    CList            user_tag_lst;
+
+    /* track_priority_val zero is special: those are weakly tracked rules.
+     * That means: NetworkManager will restore them only if it removed them earlier.
+     * But it will not remove or add them otherwise.
+     *
+     * Otherwise, the track_priority_val goes together with track_priority_present.
+     * In case of one rule being tracked multiple times (with different priorities),
+     * the one with higher priority wins. See _track_obj_data_get_best_data().
+     * Then, the winning present state either enforces that the rule is present
+     * or absent.
+     *
+     * If a rules is not tracked at all, it is ignored by NetworkManager. Assuming
+     * that it was added externally by the user. But unlike weakly tracked rules,
+     * NM will *not* restore such rules if NetworkManager themself removed them. */
+    guint32 track_priority_val;
+    bool    track_priority_present : 1;
+
+    bool dirty : 1;
+} TrackData;
+
+typedef enum {
+    CONFIG_STATE_NONE          = 0,
+    CONFIG_STATE_ADDED_BY_US   = 1,
+    CONFIG_STATE_REMOVED_BY_US = 2,
+
+    /* ConfigState encodes whether the rule was touched by us at all (CONFIG_STATE_NONE).
+     *
+     * Maybe we would only need to track whether we touched the rule at all. But we
+     * track it more in detail what we did: did we add it (CONFIG_STATE_ADDED_BY_US)
+     * or did we remove it (CONFIG_STATE_REMOVED_BY_US)?
+     * Finally, we need CONFIG_STATE_OWNED_BY_US, which means that we didn't actively
+     * add/remove it, but whenever we are about to undo the add/remove, we need to do it.
+     * In that sense, CONFIG_STATE_OWNED_BY_US is really just a flag that we unconditionally
+     * force the state next time when necessary. */
+    CONFIG_STATE_OWNED_BY_US = 3,
+} ConfigState;
+
+typedef struct {
+    const NMPObject *obj;
+    CList            obj_lst_head;
+
+    CList by_obj_lst;
+
+    /* indicates whether we configured/removed the rule (during sync()). We need that, so
+     * if the rule gets untracked, that we know to remove/restore it.
+     *
+     * This makes NMPRouteManager stateful (beyond the configuration that indicates
+     * which rules are tracked).
+     * After a restart, NetworkManager would no longer remember which rules were added
+     * by us.
+     *
+     * That is partially fixed by NetworkManager taking over the rules that it
+     * actively configures (see %NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG). */
+    ConfigState config_state;
+} TrackObjData;
+
+typedef struct {
+    gconstpointer user_tag;
+    CList         user_tag_lst_head;
+} TrackUserTagData;
+
+/*****************************************************************************/
+
+static void _track_data_untrack(NMPRouteManager *self,
+                                TrackData       *track_data,
+                                gboolean         remove_user_tag_data,
+                                gboolean         make_owned_by_us);
+
+/*****************************************************************************/
+
+static CList *
+_by_obj_lst_head(NMPRouteManager *self, NMPObjectType obj_type)
+{
+    G_STATIC_ASSERT(G_N_ELEMENTS(self->by_obj_lst_heads) == 3);
+
+    switch (obj_type) {
+    case NMP_OBJECT_TYPE_IP4_ROUTE:
+        return &self->by_obj_lst_heads[0];
+    case NMP_OBJECT_TYPE_IP6_ROUTE:
+        return &self->by_obj_lst_heads[1];
+    case NMP_OBJECT_TYPE_ROUTING_RULE:
+        return &self->by_obj_lst_heads[2];
+    default:
+        return nm_assert_unreachable_val(NULL);
+    }
+}
+
+/*****************************************************************************/
+
+static void
+_track_data_assert(const TrackData *track_data, gboolean linked)
+{
+    nm_assert(track_data);
+    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));
+    nm_assert(!linked || !c_list_is_empty(&track_data->user_tag_lst));
+}
+
+static guint
+_track_data_hash(gconstpointer data)
+{
+    const TrackData *track_data = data;
+    NMHashState      h;
+
+    _track_data_assert(track_data, FALSE);
+
+    nm_hash_init(&h, 269297543u);
+    nmp_object_id_hash_update(track_data->obj, &h);
+    nm_hash_update_val(&h, track_data->user_tag);
+    return nm_hash_complete(&h);
+}
+
+static gboolean
+_track_data_equal(gconstpointer data_a, gconstpointer data_b)
+{
+    const TrackData *track_data_a = data_a;
+    const TrackData *track_data_b = data_b;
+
+    _track_data_assert(track_data_a, FALSE);
+    _track_data_assert(track_data_b, FALSE);
+
+    return track_data_a->user_tag == track_data_b->user_tag
+           && nmp_object_id_equal(track_data_a->obj, track_data_b->obj);
+}
+
+static void
+_track_data_destroy(gpointer data)
+{
+    TrackData *track_data = data;
+
+    _track_data_assert(track_data, FALSE);
+
+    c_list_unlink_stale(&track_data->obj_lst);
+    c_list_unlink_stale(&track_data->user_tag_lst);
+    nmp_object_unref(track_data->obj);
+    nm_g_slice_free(track_data);
+}
+
+static const TrackData *
+_track_obj_data_get_best_data(TrackObjData *obj_data)
+{
+    TrackData       *track_data;
+    const TrackData *td_best = NULL;
+
+    c_list_for_each_entry (track_data, &obj_data->obj_lst_head, obj_lst) {
+        _track_data_assert(track_data, TRUE);
+
+        if (td_best) {
+            if (td_best->track_priority_val > track_data->track_priority_val)
+                continue;
+            if (td_best->track_priority_val == track_data->track_priority_val) {
+                if (td_best->track_priority_present || !track_data->track_priority_present) {
+                    /* if the priorities are identical, then "present" wins over
+                     * "!present" (absent). */
+                    continue;
+                }
+            }
+        }
+
+        td_best = track_data;
+    }
+
+    return td_best;
+}
+
+static guint
+_track_obj_data_hash(gconstpointer data)
+{
+    const TrackObjData *obj_data = data;
+
+    return nmp_object_id_hash(obj_data->obj);
+}
+
+static gboolean
+_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 nmp_object_id_equal(obj_data_a->obj, obj_data_b->obj);
+}
+
+static void
+_track_obj_data_destroy(gpointer data)
+{
+    TrackObjData *obj_data = data;
+
+    c_list_unlink_stale(&obj_data->obj_lst_head);
+    c_list_unlink_stale(&obj_data->by_obj_lst);
+    nmp_object_unref(obj_data->obj);
+    nm_g_slice_free(obj_data);
+}
+
+static void
+_track_user_tag_data_destroy(gpointer data)
+{
+    TrackUserTagData *user_tag_data = data;
+
+    c_list_unlink_stale(&user_tag_data->user_tag_lst_head);
+    nm_g_slice_free(user_tag_data);
+}
+
+static TrackData *
+_track_data_lookup(GHashTable *by_data, const NMPObject *obj, gconstpointer user_tag)
+{
+    TrackData track_data_needle = {
+        .obj      = obj,
+        .user_tag = user_tag,
+    };
+
+    return g_hash_table_lookup(by_data, &track_data_needle);
+}
+
+/*****************************************************************************/
+
+/**
+ * nmp_route_manager_track:
+ * @self: the #NMPRouteManager instance
+ * @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
+ *   value being more important). For example, if you track the same
+ *   rule twice, once with priority -5 and +10, then the rule is
+ *   present (because the positive number is more important).
+ *   The special value 0 indicates weakly-tracked rules.
+ * @user_tag: the tag associated with tracking this rule. The same tag
+ *   must be used to untrack the rule later.
+ * @user_tag_untrack: if not %NULL, at the same time untrack this user-tag
+ *   for the same rule. Note that this is different from a plain nmp_route_manager_untrack_rule(),
+ *   because it enforces ownership of the now tracked rule. On the other hand,
+ *   a plain nmp_route_manager_untrack_rule() merely forgets about the tracking.
+ *   The purpose here is to set this to %NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG.
+ *
+ * Returns: %TRUE, if something changed.
+ */
+gboolean
+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;
+    TrackData        *track_data;
+    TrackObjData     *obj_data;
+    TrackUserTagData *user_tag_data;
+    gboolean          changed         = FALSE;
+    gboolean          changed_untrack = FALSE;
+    guint32           track_priority_val;
+    gboolean          track_priority_present;
+
+    g_return_val_if_fail(NMP_IS_ROUTE_MANAGER(self), FALSE);
+    g_return_val_if_fail(obj, FALSE);
+    g_return_val_if_fail(user_tag, FALSE);
+
+    /* The route must not be tied to an interface. We can only handle here
+     * blackhole/unreachable/prohibit route types. */
+    g_return_val_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),
+        FALSE);
+
+    nm_assert(track_priority != G_MININT32);
+
+    p_obj_stack = nmp_object_stackinit(&obj_stack, obj_type, obj);
+
+    nm_assert(nmp_object_is_visible(p_obj_stack));
+
+    if (track_priority >= 0) {
+        track_priority_val     = track_priority;
+        track_priority_present = TRUE;
+    } else {
+        track_priority_val     = -track_priority;
+        track_priority_present = FALSE;
+    }
+
+    track_data = _track_data_lookup(self->by_data, p_obj_stack, user_tag);
+
+    if (!track_data) {
+        track_data  = g_slice_new(TrackData);
+        *track_data = (TrackData){
+            .obj      = nm_dedup_multi_index_obj_intern(nm_platform_get_multi_idx(self->platform),
+                                                   p_obj_stack),
+            .user_tag = user_tag,
+            .track_priority_val     = track_priority_val,
+            .track_priority_present = track_priority_present,
+            .dirty                  = FALSE,
+        };
+        g_hash_table_add(self->by_data, track_data);
+
+        obj_data = g_hash_table_lookup(self->by_obj, &track_data->obj);
+        if (!obj_data) {
+            obj_data  = g_slice_new(TrackObjData);
+            *obj_data = (TrackObjData){
+                .obj          = nmp_object_ref(track_data->obj),
+                .obj_lst_head = C_LIST_INIT(obj_data->obj_lst_head),
+                .config_state = CONFIG_STATE_NONE,
+            };
+            g_hash_table_add(self->by_obj, obj_data);
+            c_list_link_tail(_by_obj_lst_head(self, obj_type), &obj_data->by_obj_lst);
+        }
+        c_list_link_tail(&obj_data->obj_lst_head, &track_data->obj_lst);
+
+        user_tag_data = g_hash_table_lookup(self->by_user_tag, &track_data->user_tag);
+        if (!user_tag_data) {
+            user_tag_data  = g_slice_new(TrackUserTagData);
+            *user_tag_data = (TrackUserTagData){
+                .user_tag          = user_tag,
+                .user_tag_lst_head = C_LIST_INIT(user_tag_data->user_tag_lst_head),
+            };
+            g_hash_table_add(self->by_user_tag, user_tag_data);
+        }
+        c_list_link_tail(&user_tag_data->user_tag_lst_head, &track_data->user_tag_lst);
+        changed = TRUE;
+    } else {
+        track_data->dirty = FALSE;
+        if (track_data->track_priority_val != track_priority_val
+            || track_data->track_priority_present != track_priority_present) {
+            track_data->track_priority_val     = track_priority_val;
+            track_data->track_priority_present = track_priority_present;
+            changed                            = TRUE;
+        }
+    }
+
+    if (user_tag_untrack) {
+        if (user_tag != user_tag_untrack) {
+            TrackData *track_data_untrack;
+
+            track_data_untrack = _track_data_lookup(self->by_data, p_obj_stack, user_tag_untrack);
+            if (track_data_untrack) {
+                _track_data_untrack(self, track_data_untrack, FALSE, TRUE);
+                changed_untrack = TRUE;
+            }
+        } else
+            nm_assert_not_reached();
+    }
+
+    _track_data_assert(track_data, TRUE);
+
+    if (changed) {
+        _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));
+    }
+
+    return changed || changed_untrack;
+}
+
+static void
+_track_data_untrack(NMPRouteManager *self,
+                    TrackData       *track_data,
+                    gboolean         remove_user_tag_data,
+                    gboolean         make_owned_by_us)
+{
+    TrackObjData *obj_data;
+
+    nm_assert(NMP_IS_ROUTE_MANAGER(self));
+    _track_data_assert(track_data, TRUE);
+    nm_assert(self->by_data);
+    nm_assert(g_hash_table_lookup(self->by_data, track_data) == track_data);
+
+    _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
+    {
+        TrackUserTagData *user_tag_data;
+
+        user_tag_data = g_hash_table_lookup(self->by_user_tag, &track_data->user_tag);
+        nm_assert(user_tag_data);
+        nm_assert(c_list_contains(&user_tag_data->user_tag_lst_head, &track_data->user_tag_lst));
+    }
+#endif
+
+    nm_assert(!c_list_is_empty(&track_data->user_tag_lst));
+
+    obj_data = g_hash_table_lookup(self->by_obj, &track_data->obj);
+    nm_assert(obj_data);
+    nm_assert(c_list_contains(&obj_data->obj_lst_head, &track_data->obj_lst));
+    nm_assert(obj_data == g_hash_table_lookup(self->by_obj, &track_data->obj));
+
+    if (make_owned_by_us) {
+        if (obj_data->config_state == CONFIG_STATE_NONE) {
+            /* we need to mark this entry that it requires a touch on the next
+             * sync. */
+            obj_data->config_state = CONFIG_STATE_OWNED_BY_US;
+        }
+    } else if (remove_user_tag_data && c_list_length_is(&track_data->user_tag_lst, 1))
+        g_hash_table_remove(self->by_user_tag, &track_data->user_tag);
+
+    /* if obj_data is marked to be "added_by_us" or "removed_by_us", we need to keep this entry
+     * around for the next sync -- so that we can undo what we did earlier. */
+    if (obj_data->config_state == CONFIG_STATE_NONE && c_list_length_is(&track_data->obj_lst, 1))
+        g_hash_table_remove(self->by_obj, &track_data->obj);
+
+    g_hash_table_remove(self->by_data, track_data);
+}
+
+gboolean
+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;
+    gboolean         changed = FALSE;
+
+    g_return_val_if_fail(NMP_IS_ROUTE_MANAGER(self), FALSE);
+    nm_assert(NM_IN_SET(obj_type,
+                        NMP_OBJECT_TYPE_IP4_ROUTE,
+                        NMP_OBJECT_TYPE_IP6_ROUTE,
+                        NMP_OBJECT_TYPE_ROUTING_RULE));
+    g_return_val_if_fail(obj, FALSE);
+    g_return_val_if_fail(user_tag, FALSE);
+
+    p_obj_stack = nmp_object_stackinit(&obj_stack, obj_type, obj);
+
+    nm_assert(nmp_object_is_visible(p_obj_stack));
+
+    track_data = _track_data_lookup(self->by_data, p_obj_stack, user_tag);
+    if (track_data) {
+        _track_data_untrack(self, track_data, TRUE, FALSE);
+        changed = TRUE;
+    }
+
+    return changed;
+}
+
+void
+nmp_route_manager_set_dirty(NMPRouteManager *self, gconstpointer user_tag)
+{
+    TrackData        *track_data;
+    TrackUserTagData *user_tag_data;
+
+    g_return_if_fail(NMP_IS_ROUTE_MANAGER(self));
+    g_return_if_fail(user_tag);
+
+    user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag);
+    if (!user_tag_data)
+        return;
+
+    c_list_for_each_entry (track_data, &user_tag_data->user_tag_lst_head, user_tag_lst)
+        track_data->dirty = TRUE;
+}
+
+gboolean
+nmp_route_manager_untrack_all(NMPRouteManager *self,
+                              gconstpointer    user_tag,
+                              gboolean         all /* or only dirty */,
+                              gboolean         make_survivors_dirty)
+{
+    TrackData        *track_data;
+    TrackData        *track_data_safe;
+    TrackUserTagData *user_tag_data;
+    gboolean          changed = FALSE;
+
+    g_return_val_if_fail(NMP_IS_ROUTE_MANAGER(self), FALSE);
+    g_return_val_if_fail(user_tag, FALSE);
+
+    user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag);
+    if (!user_tag_data)
+        return FALSE;
+
+    c_list_for_each_entry_safe (track_data,
+                                track_data_safe,
+                                &user_tag_data->user_tag_lst_head,
+                                user_tag_lst) {
+        if (all || track_data->dirty) {
+            _track_data_untrack(self, track_data, FALSE, FALSE);
+            changed = TRUE;
+            continue;
+        }
+        if (make_survivors_dirty)
+            track_data->dirty = TRUE;
+    }
+    if (c_list_is_empty(&user_tag_data->user_tag_lst_head))
+        g_hash_table_remove(self->by_user_tag, user_tag_data);
+
+    return changed;
+}
+
+/*****************************************************************************/
+
+void
+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 *objs_to_delete = NULL;
+    TrackObjData                *obj_data;
+    TrackObjData                *obj_data_safe;
+    CList                       *by_obj_lst_head;
+    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%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);
+
+    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 obj is not tracked. It was externally added, hence we
+                 * ignore it. */
+                continue;
+            }
+
+            td_best = _track_obj_data_get_best_data(obj_data);
+            if (td_best) {
+                if (td_best->track_priority_present) {
+                    if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US)
+                        obj_data->config_state = CONFIG_STATE_ADDED_BY_US;
+                    continue;
+                }
+                if (td_best->track_priority_val == 0) {
+                    if (!NM_IN_SET(obj_data->config_state,
+                                   CONFIG_STATE_ADDED_BY_US,
+                                   CONFIG_STATE_OWNED_BY_US)) {
+                        obj_data->config_state = CONFIG_STATE_NONE;
+                        continue;
+                    }
+                    obj_data->config_state = CONFIG_STATE_NONE;
+                }
+            }
+
+            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 (!objs_to_delete)
+                objs_to_delete = g_ptr_array_new_with_free_func((GDestroyNotify) nmp_object_unref);
+
+            g_ptr_array_add(objs_to_delete, (gpointer) nmp_object_ref(plobj));
+
+            obj_data->config_state = CONFIG_STATE_REMOVED_BY_US;
+        }
+    }
+
+    if (objs_to_delete) {
+        for (i = 0; i < objs_to_delete->len; i++)
+            nm_platform_object_delete(self->platform, objs_to_delete->pdata[i]);
+    }
+
+    by_obj_lst_head = _by_obj_lst_head(self, obj_type);
+
+    c_list_for_each_entry_safe (obj_data, obj_data_safe, by_obj_lst_head, by_obj_lst) {
+        nm_assert(NMP_OBJECT_GET_TYPE(obj_data->obj) == obj_type);
+
+        td_best = _track_obj_data_get_best_data(obj_data);
+
+        if (!td_best) {
+            g_hash_table_remove(self->by_obj, obj_data);
+            continue;
+        }
+
+        if (!td_best->track_priority_present) {
+            if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US)
+                obj_data->config_state = CONFIG_STATE_REMOVED_BY_US;
+            continue;
+        }
+        if (td_best->track_priority_val == 0) {
+            if (!NM_IN_SET(obj_data->config_state,
+                           CONFIG_STATE_REMOVED_BY_US,
+                           CONFIG_STATE_OWNED_BY_US)) {
+                obj_data->config_state = CONFIG_STATE_NONE;
+                continue;
+            }
+            obj_data->config_state = CONFIG_STATE_NONE;
+        }
+
+        plobj =
+            nm_platform_lookup_obj(self->platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj_data->obj);
+        if (plobj)
+            continue;
+
+        obj_data->config_state = CONFIG_STATE_ADDED_BY_US;
+
+        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,
+                                           int              addr_family,
+                                           gint32           tracking_priority,
+                                           gconstpointer    user_tag)
+{
+    NMPLookup                    lookup;
+    const NMDedupMultiHeadEntry *head_entry;
+    NMDedupMultiIter             iter;
+    const NMPObject             *o;
+
+    g_return_if_fail(NMP_IS_ROUTE_MANAGER(self));
+
+    if (!platform)
+        platform = self->platform;
+    else
+        g_return_if_fail(NM_IS_PLATFORM(platform));
+
+    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
+
+    nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE);
+    head_entry = nm_platform_lookup(platform, &lookup);
+    nmp_cache_iter_for_each (&iter, head_entry, &o) {
+        const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE(o);
+
+        if (addr_family != AF_UNSPEC && rr->addr_family != addr_family)
+            continue;
+
+        nmp_route_manager_track_rule(self, rr, tracking_priority, user_tag, NULL);
+    }
+}
+
+/*****************************************************************************/
+
+void
+nmp_route_manager_track_rule_default(NMPRouteManager *self,
+                                     int              addr_family,
+                                     gint32           track_priority,
+                                     gconstpointer    user_tag)
+{
+    g_return_if_fail(NMP_IS_ROUTE_MANAGER(self));
+
+    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
+
+    /* track the default rules. See also `man ip-rule`. */
+
+    if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)) {
+        nmp_route_manager_track_rule(self,
+                                     &((NMPlatformRoutingRule){
+                                         .addr_family = AF_INET,
+                                         .priority    = 0,
+                                         .table       = RT_TABLE_LOCAL,
+                                         .action      = FR_ACT_TO_TBL,
+                                         .protocol    = RTPROT_KERNEL,
+                                     }),
+                                     track_priority,
+                                     user_tag,
+                                     NULL);
+        nmp_route_manager_track_rule(self,
+                                     &((NMPlatformRoutingRule){
+                                         .addr_family = AF_INET,
+                                         .priority    = 32766,
+                                         .table       = RT_TABLE_MAIN,
+                                         .action      = FR_ACT_TO_TBL,
+                                         .protocol    = RTPROT_KERNEL,
+                                     }),
+                                     track_priority,
+                                     user_tag,
+                                     NULL);
+        nmp_route_manager_track_rule(self,
+                                     &((NMPlatformRoutingRule){
+                                         .addr_family = AF_INET,
+                                         .priority    = 32767,
+                                         .table       = RT_TABLE_DEFAULT,
+                                         .action      = FR_ACT_TO_TBL,
+                                         .protocol    = RTPROT_KERNEL,
+                                     }),
+                                     track_priority,
+                                     user_tag,
+                                     NULL);
+    }
+    if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) {
+        nmp_route_manager_track_rule(self,
+                                     &((NMPlatformRoutingRule){
+                                         .addr_family = AF_INET6,
+                                         .priority    = 0,
+                                         .table       = RT_TABLE_LOCAL,
+                                         .action      = FR_ACT_TO_TBL,
+                                         .protocol    = RTPROT_KERNEL,
+                                     }),
+                                     track_priority,
+                                     user_tag,
+                                     NULL);
+        nmp_route_manager_track_rule(self,
+                                     &((NMPlatformRoutingRule){
+                                         .addr_family = AF_INET6,
+                                         .priority    = 32766,
+                                         .table       = RT_TABLE_MAIN,
+                                         .action      = FR_ACT_TO_TBL,
+                                         .protocol    = RTPROT_KERNEL,
+                                     }),
+                                     track_priority,
+                                     user_tag,
+                                     NULL);
+    }
+}
+
+/*****************************************************************************/
+
+NMPRouteManager *
+nmp_route_manager_new(NMPlatform *platform)
+{
+    NMPRouteManager *self;
+
+    g_return_val_if_fail(NM_IS_PLATFORM(platform), NULL);
+
+    G_STATIC_ASSERT_EXPR(G_STRUCT_OFFSET(TrackUserTagData, user_tag) == 0);
+
+    self  = g_slice_new(NMPRouteManager);
+    *self = (NMPRouteManager){
+        .ref_count = 1,
+        .platform  = g_object_ref(platform),
+        .by_data =
+            g_hash_table_new_full(_track_data_hash, _track_data_equal, NULL, _track_data_destroy),
+        .by_obj              = g_hash_table_new_full(_track_obj_data_hash,
+                                        _track_obj_data_equal,
+                                        NULL,
+                                        _track_obj_data_destroy),
+        .by_user_tag         = g_hash_table_new_full(nm_pdirect_hash,
+                                             nm_pdirect_equal,
+                                             NULL,
+                                             _track_user_tag_data_destroy),
+        .by_obj_lst_heads[0] = C_LIST_INIT(self->by_obj_lst_heads[0]),
+        .by_obj_lst_heads[1] = C_LIST_INIT(self->by_obj_lst_heads[1]),
+        .by_obj_lst_heads[2] = C_LIST_INIT(self->by_obj_lst_heads[2]),
+    };
+    return self;
+}
+
+NMPRouteManager *
+nmp_route_manager_ref(NMPRouteManager *self)
+{
+    g_return_val_if_fail(NMP_IS_ROUTE_MANAGER(self), NULL);
+
+    self->ref_count++;
+    return self;
+}
+
+void
+nmp_route_manager_unref(NMPRouteManager *self)
+{
+    g_return_if_fail(NMP_IS_ROUTE_MANAGER(self));
+
+    if (--self->ref_count > 0)
+        return;
+
+    g_hash_table_destroy(self->by_user_tag);
+    g_hash_table_destroy(self->by_obj);
+    g_hash_table_destroy(self->by_data);
+    nm_assert(c_list_is_empty(&self->by_obj_lst_heads[0]));
+    nm_assert(c_list_is_empty(&self->by_obj_lst_heads[1]));
+    nm_assert(c_list_is_empty(&self->by_obj_lst_heads[2]));
+    g_object_unref(self->platform);
+    nm_g_slice_free(self);
+}
diff --git a/src/libnm-platform/nmp-route-manager.h b/src/libnm-platform/nmp-route-manager.h
new file mode 100644
index 00000000..97ec3840
--- /dev/null
+++ b/src/libnm-platform/nmp-route-manager.h
@@ -0,0 +1,79 @@
+/* SPDX-License-Identifier: LGPL-2.1-or-later */
+
+#ifndef __NMP_ROUTE_MANAGER_H__
+#define __NMP_ROUTE_MANAGER_H__
+
+#include "nm-platform.h"
+
+/*****************************************************************************/
+
+#define NMP_ROUTE_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG ((const void *) nmp_route_manager_new)
+
+typedef struct _NMPRouteManager NMPRouteManager;
+
+NMPRouteManager *nmp_route_manager_new(NMPlatform *platform);
+
+NMPRouteManager *nmp_route_manager_ref(NMPRouteManager *self);
+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);
+
+gboolean nmp_route_manager_track(NMPRouteManager *self,
+                                 NMPObjectType    obj_type,
+                                 gconstpointer    obj,
+                                 gint32           track_priority,
+                                 gconstpointer    user_tag,
+                                 gconstpointer    user_tag_untrack);
+
+static inline gboolean
+nmp_route_manager_track_rule(NMPRouteManager             *self,
+                             const NMPlatformRoutingRule *routing_rule,
+                             gint32                       track_priority,
+                             gconstpointer                user_tag,
+                             gconstpointer                user_tag_untrack)
+{
+    return 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,
+                                          gint32           track_priority,
+                                          gconstpointer    user_tag);
+
+void nmp_route_manager_track_rule_from_platform(NMPRouteManager *self,
+                                                NMPlatform      *platform,
+                                                int              addr_family,
+                                                gint32           tracking_priority,
+                                                gconstpointer    user_tag);
+
+gboolean nmp_route_manager_untrack(NMPRouteManager *self,
+                                   NMPObjectType    obj_type,
+                                   gconstpointer    obj,
+                                   gconstpointer    user_tag);
+
+static inline gboolean
+nmp_route_manager_untrack_rule(NMPRouteManager             *self,
+                               const NMPlatformRoutingRule *routing_rule,
+                               gconstpointer                user_tag)
+{
+    return 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);
+
+gboolean nmp_route_manager_untrack_all(NMPRouteManager *self,
+                                       gconstpointer    user_tag,
+                                       gboolean         all /* or only dirty */,
+                                       gboolean         make_survivors_dirty);
+
+void nmp_route_manager_sync(NMPRouteManager *self, NMPObjectType obj_type, gboolean keep_deleted);
+
+/*****************************************************************************/
+
+#endif /* __NMP_ROUTE_MANAGER_H__ */
diff --git a/src/libnm-platform/nmp-rules-manager.c b/src/libnm-platform/nmp-rules-manager.c
deleted file mode 100644
index 636c90b2..00000000
--- a/src/libnm-platform/nmp-rules-manager.c
+++ /dev/null
@@ -1,809 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#include "libnm-glib-aux/nm-default-glib-i18n-lib.h"
-
-#include "nmp-rules-manager.h"
-
-#include <linux/fib_rules.h>
-#include <linux/rtnetlink.h>
-
-#include "libnm-log-core/nm-logging.h"
-#include "libnm-std-aux/c-list-util.h"
-#include "nmp-object.h"
-
-/*****************************************************************************/
-
-struct _NMPRulesManager {
-    NMPlatform *platform;
-    GHashTable *by_obj;
-    GHashTable *by_user_tag;
-    GHashTable *by_data;
-    guint       ref_count;
-};
-
-/*****************************************************************************/
-
-static void _rules_init(NMPRulesManager *self);
-
-/*****************************************************************************/
-
-#define _NMLOG_DOMAIN      LOGD_PLATFORM
-#define _NMLOG_PREFIX_NAME "rules-manager"
-
-#define _NMLOG(level, ...)                                                 \
-    G_STMT_START                                                           \
-    {                                                                      \
-        const NMLogLevel __level = (level);                                \
-                                                                           \
-        if (nm_logging_enabled(__level, _NMLOG_DOMAIN)) {                  \
-            _nm_log(__level,                                               \
-                    _NMLOG_DOMAIN,                                         \
-                    0,                                                     \
-                    NULL,                                                  \
-                    NULL,                                                  \
-                    "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__),             \
-                    _NMLOG_PREFIX_NAME _NM_UTILS_MACRO_REST(__VA_ARGS__)); \
-        }                                                                  \
-    }                                                                      \
-    G_STMT_END
-
-/*****************************************************************************/
-
-static gboolean
-NMP_IS_RULES_MANAGER(gpointer self)
-{
-    return self && ((NMPRulesManager *) self)->ref_count > 0
-           && NM_IS_PLATFORM(((NMPRulesManager *) self)->platform);
-}
-
-#define _USER_TAG_LOG(user_tag) nm_hash_obfuscate_ptr(1240261787u, (user_tag))
-
-/*****************************************************************************/
-
-typedef struct {
-    const NMPObject *obj;
-    gconstpointer    user_tag;
-    CList            obj_lst;
-    CList            user_tag_lst;
-
-    /* track_priority_val zero is special: those are weakly tracked rules.
-     * That means: NetworkManager will restore them only if it removed them earlier.
-     * But it will not remove or add them otherwise.
-     *
-     * Otherwise, the track_priority_val goes together with track_priority_present.
-     * In case of one rule being tracked multiple times (with different priorities),
-     * the one with higher priority wins. See _rules_obj_get_best_data().
-     * Then, the winning present state either enforces that the rule is present
-     * or absent.
-     *
-     * If a rules is not tracked at all, it is ignored by NetworkManager. Assuming
-     * that it was added externally by the user. But unlike weakly tracked rules,
-     * NM will *not* restore such rules if NetworkManager themself removed them. */
-    guint32 track_priority_val;
-    bool    track_priority_present : 1;
-
-    bool dirty : 1;
-} RulesData;
-
-typedef enum {
-    CONFIG_STATE_NONE          = 0,
-    CONFIG_STATE_ADDED_BY_US   = 1,
-    CONFIG_STATE_REMOVED_BY_US = 2,
-
-    /* ConfigState encodes whether the rule was touched by us at all (CONFIG_STATE_NONE).
-     *
-     * Maybe we would only need to track whether we touched the rule at all. But we
-     * track it more in detail what we did: did we add it (CONFIG_STATE_ADDED_BY_US)
-     * or did we remove it (CONFIG_STATE_REMOVED_BY_US)?
-     * Finally, we need CONFIG_STATE_OWNED_BY_US, which means that we didn't actively
-     * add/remove it, but whenever we are about to undo the add/remove, we need to do it.
-     * In that sense, CONFIG_STATE_OWNED_BY_US is really just a flag that we unconditionally
-     * force the state next time when necessary. */
-    CONFIG_STATE_OWNED_BY_US = 3,
-} ConfigState;
-
-typedef struct {
-    const NMPObject *obj;
-    CList            obj_lst_head;
-
-    /* indicates whether we configured/removed the rule (during sync()). We need that, so
-     * if the rule gets untracked, that we know to remove/restore it.
-     *
-     * This makes NMPRulesManager stateful (beyond the configuration that indicates
-     * which rules are tracked).
-     * After a restart, NetworkManager would no longer remember which rules were added
-     * by us.
-     *
-     * That is partially fixed by NetworkManager taking over the rules that it
-     * actively configures (see %NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG). */
-    ConfigState config_state;
-} RulesObjData;
-
-typedef struct {
-    gconstpointer user_tag;
-    CList         user_tag_lst_head;
-} RulesUserTagData;
-
-/*****************************************************************************/
-
-static void _rules_data_untrack(NMPRulesManager *self,
-                                RulesData *      rules_data,
-                                gboolean         remove_user_tag_data,
-                                gboolean         make_owned_by_us);
-
-/*****************************************************************************/
-
-static void
-_rules_data_assert(const RulesData *rules_data, gboolean linked)
-{
-    nm_assert(rules_data);
-    nm_assert(NMP_OBJECT_GET_TYPE(rules_data->obj) == NMP_OBJECT_TYPE_ROUTING_RULE);
-    nm_assert(nmp_object_is_visible(rules_data->obj));
-    nm_assert(rules_data->user_tag);
-    nm_assert(!linked || !c_list_is_empty(&rules_data->obj_lst));
-    nm_assert(!linked || !c_list_is_empty(&rules_data->user_tag_lst));
-}
-
-static guint
-_rules_data_hash(gconstpointer data)
-{
-    const RulesData *rules_data = data;
-    NMHashState      h;
-
-    _rules_data_assert(rules_data, FALSE);
-
-    nm_hash_init(&h, 269297543u);
-    nm_platform_routing_rule_hash_update(NMP_OBJECT_CAST_ROUTING_RULE(rules_data->obj),
-                                         NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID,
-                                         &h);
-    nm_hash_update_val(&h, rules_data->user_tag);
-    return nm_hash_complete(&h);
-}
-
-static gboolean
-_rules_data_equal(gconstpointer data_a, gconstpointer data_b)
-{
-    const RulesData *rules_data_a = data_a;
-    const RulesData *rules_data_b = data_b;
-
-    _rules_data_assert(rules_data_a, FALSE);
-    _rules_data_assert(rules_data_b, FALSE);
-
-    return rules_data_a->user_tag == rules_data_b->user_tag
-           && (nm_platform_routing_rule_cmp(NMP_OBJECT_CAST_ROUTING_RULE(rules_data_a->obj),
-                                            NMP_OBJECT_CAST_ROUTING_RULE(rules_data_b->obj),
-                                            NM_PLATFORM_ROUTING_RULE_CMP_TYPE_ID)
-               == 0);
-}
-
-static void
-_rules_data_destroy(gpointer data)
-{
-    RulesData *rules_data = data;
-
-    _rules_data_assert(rules_data, FALSE);
-
-    c_list_unlink_stale(&rules_data->obj_lst);
-    c_list_unlink_stale(&rules_data->user_tag_lst);
-    nmp_object_unref(rules_data->obj);
-    g_slice_free(RulesData, rules_data);
-}
-
-static const RulesData *
-_rules_obj_get_best_data(RulesObjData *obj_data)
-{
-    RulesData *      rules_data;
-    const RulesData *rd_best = NULL;
-
-    c_list_for_each_entry (rules_data, &obj_data->obj_lst_head, obj_lst) {
-        _rules_data_assert(rules_data, TRUE);
-
-        if (rd_best) {
-            if (rd_best->track_priority_val > rules_data->track_priority_val)
-                continue;
-            if (rd_best->track_priority_val == rules_data->track_priority_val) {
-                if (rd_best->track_priority_present || !rules_data->track_priority_present) {
-                    /* if the priorities are identical, then "present" wins over
-                     * "!present" (absent). */
-                    continue;
-                }
-            }
-        }
-
-        rd_best = rules_data;
-    }
-
-    return rd_best;
-}
-
-static guint
-_rules_obj_hash(gconstpointer data)
-{
-    const RulesObjData *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);
-}
-
-static gboolean
-_rules_obj_equal(gconstpointer data_a, gconstpointer data_b)
-{
-    const RulesObjData *obj_data_a = data_a;
-    const RulesObjData *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);
-}
-
-static void
-_rules_obj_destroy(gpointer data)
-{
-    RulesObjData *obj_data = data;
-
-    c_list_unlink_stale(&obj_data->obj_lst_head);
-    nmp_object_unref(obj_data->obj);
-    g_slice_free(RulesObjData, obj_data);
-}
-
-static guint
-_rules_user_tag_hash(gconstpointer data)
-{
-    const RulesUserTagData *user_tag_data = data;
-
-    return nm_hash_val(644693447u, user_tag_data->user_tag);
-}
-
-static gboolean
-_rules_user_tag_equal(gconstpointer data_a, gconstpointer data_b)
-{
-    const RulesUserTagData *user_tag_data_a = data_a;
-    const RulesUserTagData *user_tag_data_b = data_b;
-
-    return user_tag_data_a->user_tag == user_tag_data_b->user_tag;
-}
-
-static void
-_rules_user_tag_destroy(gpointer data)
-{
-    RulesUserTagData *user_tag_data = data;
-
-    c_list_unlink_stale(&user_tag_data->user_tag_lst_head);
-    g_slice_free(RulesUserTagData, user_tag_data);
-}
-
-static RulesData *
-_rules_data_lookup(GHashTable *by_data, const NMPObject *obj, gconstpointer user_tag)
-{
-    RulesData rules_data_needle = {
-        .obj      = obj,
-        .user_tag = user_tag,
-    };
-
-    return g_hash_table_lookup(by_data, &rules_data_needle);
-}
-
-/**
- * nmp_rules_manager_track:
- * @self: the #NMPRulesManager instance
- * @routing_rule: the #NMPlatformRoutingRule to track or untrack
- * @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
- *   value being more important). For example, if you track the same
- *   rule twice, once with priority -5 and +10, then the rule is
- *   present (because the positive number is more important).
- *   The special value 0 indicates weakly-tracked rules.
- * @user_tag: the tag associated with tracking this rule. The same tag
- *   must be used to untrack the rule later.
- * @user_tag_untrack: if not %NULL, at the same time untrack this user-tag
- *   for the same rule. Note that this is different from a plain nmp_rules_manager_untrack(),
- *   because it enforces ownership of the now tracked rule. On the other hand,
- *   a plain nmp_rules_manager_untrack() merely forgets about the tracking.
- *   The purpose here is to set this to %NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG.
- */
-void
-nmp_rules_manager_track(NMPRulesManager *            self,
-                        const NMPlatformRoutingRule *routing_rule,
-                        gint32                       track_priority,
-                        gconstpointer                user_tag,
-                        gconstpointer                user_tag_untrack)
-{
-    NMPObject         obj_stack;
-    const NMPObject * p_obj_stack;
-    RulesData *       rules_data;
-    RulesObjData *    obj_data;
-    RulesUserTagData *user_tag_data;
-    gboolean          changed = FALSE;
-    guint32           track_priority_val;
-    gboolean          track_priority_present;
-
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-    g_return_if_fail(routing_rule);
-    g_return_if_fail(user_tag);
-    nm_assert(track_priority != G_MININT32);
-
-    _rules_init(self);
-
-    p_obj_stack = nmp_object_stackinit(&obj_stack, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule);
-
-    nm_assert(nmp_object_is_visible(p_obj_stack));
-
-    if (track_priority >= 0) {
-        track_priority_val     = track_priority;
-        track_priority_present = TRUE;
-    } else {
-        track_priority_val     = -track_priority;
-        track_priority_present = FALSE;
-    }
-
-    rules_data = _rules_data_lookup(self->by_data, p_obj_stack, user_tag);
-
-    if (!rules_data) {
-        rules_data  = g_slice_new(RulesData);
-        *rules_data = (RulesData){
-            .obj      = nm_dedup_multi_index_obj_intern(nm_platform_get_multi_idx(self->platform),
-                                                   p_obj_stack),
-            .user_tag = user_tag,
-            .track_priority_val     = track_priority_val,
-            .track_priority_present = track_priority_present,
-            .dirty                  = FALSE,
-        };
-        g_hash_table_add(self->by_data, rules_data);
-
-        obj_data = g_hash_table_lookup(self->by_obj, &rules_data->obj);
-        if (!obj_data) {
-            obj_data  = g_slice_new(RulesObjData);
-            *obj_data = (RulesObjData){
-                .obj          = nmp_object_ref(rules_data->obj),
-                .obj_lst_head = C_LIST_INIT(obj_data->obj_lst_head),
-                .config_state = CONFIG_STATE_NONE,
-            };
-            g_hash_table_add(self->by_obj, obj_data);
-        }
-        c_list_link_tail(&obj_data->obj_lst_head, &rules_data->obj_lst);
-
-        user_tag_data = g_hash_table_lookup(self->by_user_tag, &rules_data->user_tag);
-        if (!user_tag_data) {
-            user_tag_data  = g_slice_new(RulesUserTagData);
-            *user_tag_data = (RulesUserTagData){
-                .user_tag          = user_tag,
-                .user_tag_lst_head = C_LIST_INIT(user_tag_data->user_tag_lst_head),
-            };
-            g_hash_table_add(self->by_user_tag, user_tag_data);
-        }
-        c_list_link_tail(&user_tag_data->user_tag_lst_head, &rules_data->user_tag_lst);
-        changed = TRUE;
-    } else {
-        rules_data->dirty = FALSE;
-        if (rules_data->track_priority_val != track_priority_val
-            || rules_data->track_priority_present != track_priority_present) {
-            rules_data->track_priority_val     = track_priority_val;
-            rules_data->track_priority_present = track_priority_present;
-            changed                            = TRUE;
-        }
-    }
-
-    if (user_tag_untrack) {
-        if (user_tag != user_tag_untrack) {
-            RulesData *rules_data_untrack;
-
-            rules_data_untrack = _rules_data_lookup(self->by_data, p_obj_stack, user_tag_untrack);
-            if (rules_data_untrack)
-                _rules_data_untrack(self, rules_data_untrack, FALSE, TRUE);
-        } else
-            nm_assert_not_reached();
-    }
-
-    _rules_data_assert(rules_data, TRUE);
-
-    if (changed) {
-        _LOGD("routing-rule: track [" NM_HASH_OBFUSCATE_PTR_FMT ",%s%u] \"%s\")",
-              _USER_TAG_LOG(rules_data->user_tag),
-              (rules_data->track_priority_val == 0
-                   ? ""
-                   : (rules_data->track_priority_present ? "+" : "-")),
-              (guint) rules_data->track_priority_val,
-              nmp_object_to_string(rules_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
-    }
-}
-
-static void
-_rules_data_untrack(NMPRulesManager *self,
-                    RulesData *      rules_data,
-                    gboolean         remove_user_tag_data,
-                    gboolean         make_owned_by_us)
-{
-    RulesObjData *obj_data;
-
-    nm_assert(NMP_IS_RULES_MANAGER(self));
-    _rules_data_assert(rules_data, TRUE);
-    nm_assert(self->by_data);
-    nm_assert(g_hash_table_lookup(self->by_data, rules_data) == rules_data);
-
-    _LOGD("routing-rule: untrack [" NM_HASH_OBFUSCATE_PTR_FMT "] \"%s\"",
-          _USER_TAG_LOG(rules_data->user_tag),
-          nmp_object_to_string(rules_data->obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
-
-#if NM_MORE_ASSERTS
-    {
-        RulesUserTagData *user_tag_data;
-
-        user_tag_data = g_hash_table_lookup(self->by_user_tag, &rules_data->user_tag);
-        nm_assert(user_tag_data);
-        nm_assert(c_list_contains(&user_tag_data->user_tag_lst_head, &rules_data->user_tag_lst));
-    }
-#endif
-
-    nm_assert(!c_list_is_empty(&rules_data->user_tag_lst));
-
-    obj_data = g_hash_table_lookup(self->by_obj, &rules_data->obj);
-    nm_assert(obj_data);
-    nm_assert(c_list_contains(&obj_data->obj_lst_head, &rules_data->obj_lst));
-    nm_assert(obj_data == g_hash_table_lookup(self->by_obj, &rules_data->obj));
-
-    if (make_owned_by_us) {
-        if (obj_data->config_state == CONFIG_STATE_NONE) {
-            /* we need to mark this entry that it requires a touch on the next
-             * sync. */
-            obj_data->config_state = CONFIG_STATE_OWNED_BY_US;
-        }
-    } else if (remove_user_tag_data && c_list_length_is(&rules_data->user_tag_lst, 1))
-        g_hash_table_remove(self->by_user_tag, &rules_data->user_tag);
-
-    /* if obj_data is marked to be "added_by_us" or "removed_by_us", we need to keep this entry
-     * around for the next sync -- so that we can undo what we did earlier. */
-    if (obj_data->config_state == CONFIG_STATE_NONE && c_list_length_is(&rules_data->obj_lst, 1))
-        g_hash_table_remove(self->by_obj, &rules_data->obj);
-
-    g_hash_table_remove(self->by_data, rules_data);
-}
-
-void
-nmp_rules_manager_untrack(NMPRulesManager *            self,
-                          const NMPlatformRoutingRule *routing_rule,
-                          gconstpointer                user_tag)
-{
-    NMPObject        obj_stack;
-    const NMPObject *p_obj_stack;
-    RulesData *      rules_data;
-
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-    g_return_if_fail(routing_rule);
-    g_return_if_fail(user_tag);
-
-    _rules_init(self);
-
-    p_obj_stack = nmp_object_stackinit(&obj_stack, NMP_OBJECT_TYPE_ROUTING_RULE, routing_rule);
-
-    nm_assert(nmp_object_is_visible(p_obj_stack));
-
-    rules_data = _rules_data_lookup(self->by_data, p_obj_stack, user_tag);
-    if (rules_data)
-        _rules_data_untrack(self, rules_data, TRUE, FALSE);
-}
-
-void
-nmp_rules_manager_set_dirty(NMPRulesManager *self, gconstpointer user_tag)
-{
-    RulesData *       rules_data;
-    RulesUserTagData *user_tag_data;
-
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-    g_return_if_fail(user_tag);
-
-    if (!self->by_data)
-        return;
-
-    user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag);
-    if (!user_tag_data)
-        return;
-
-    c_list_for_each_entry (rules_data, &user_tag_data->user_tag_lst_head, user_tag_lst)
-        rules_data->dirty = TRUE;
-}
-
-void
-nmp_rules_manager_untrack_all(NMPRulesManager *self,
-                              gconstpointer    user_tag,
-                              gboolean         all /* or only dirty */)
-{
-    RulesData *       rules_data;
-    RulesData *       rules_data_safe;
-    RulesUserTagData *user_tag_data;
-
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-    g_return_if_fail(user_tag);
-
-    if (!self->by_data)
-        return;
-
-    user_tag_data = g_hash_table_lookup(self->by_user_tag, &user_tag);
-    if (!user_tag_data)
-        return;
-
-    c_list_for_each_entry_safe (rules_data,
-                                rules_data_safe,
-                                &user_tag_data->user_tag_lst_head,
-                                user_tag_lst) {
-        if (all || rules_data->dirty)
-            _rules_data_untrack(self, rules_data, FALSE, FALSE);
-    }
-    if (c_list_is_empty(&user_tag_data->user_tag_lst_head))
-        g_hash_table_remove(self->by_user_tag, user_tag_data);
-}
-
-void
-nmp_rules_manager_sync(NMPRulesManager *self, gboolean keep_deleted_rules)
-{
-    const NMDedupMultiHeadEntry *pl_head_entry;
-    NMDedupMultiIter             pl_iter;
-    const NMPObject *            plobj;
-    gs_unref_ptrarray GPtrArray *rules_to_delete = NULL;
-    RulesObjData *               obj_data;
-    GHashTableIter               h_iter;
-    guint                        i;
-    const RulesData *            rd_best;
-
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-
-    if (!self->by_data)
-        return;
-
-    _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) {
-        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
-                 * ignore it. */
-                continue;
-            }
-
-            rd_best = _rules_obj_get_best_data(obj_data);
-            if (rd_best) {
-                if (rd_best->track_priority_present) {
-                    if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US)
-                        obj_data->config_state = CONFIG_STATE_ADDED_BY_US;
-                    continue;
-                }
-                if (rd_best->track_priority_val == 0) {
-                    if (!NM_IN_SET(obj_data->config_state,
-                                   CONFIG_STATE_ADDED_BY_US,
-                                   CONFIG_STATE_OWNED_BY_US)) {
-                        obj_data->config_state = CONFIG_STATE_NONE;
-                        continue;
-                    }
-                    obj_data->config_state = CONFIG_STATE_NONE;
-                }
-            }
-
-            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);
-
-            g_ptr_array_add(rules_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]);
-    }
-
-    g_hash_table_iter_init(&h_iter, self->by_obj);
-    while (g_hash_table_iter_next(&h_iter, (gpointer *) &obj_data, NULL)) {
-        rd_best = _rules_obj_get_best_data(obj_data);
-
-        if (!rd_best) {
-            g_hash_table_iter_remove(&h_iter);
-            continue;
-        }
-
-        if (!rd_best->track_priority_present) {
-            if (obj_data->config_state == CONFIG_STATE_OWNED_BY_US)
-                obj_data->config_state = CONFIG_STATE_REMOVED_BY_US;
-            continue;
-        }
-        if (rd_best->track_priority_val == 0) {
-            if (!NM_IN_SET(obj_data->config_state,
-                           CONFIG_STATE_REMOVED_BY_US,
-                           CONFIG_STATE_OWNED_BY_US)) {
-                obj_data->config_state = CONFIG_STATE_NONE;
-                continue;
-            }
-            obj_data->config_state = CONFIG_STATE_NONE;
-        }
-
-        plobj =
-            nm_platform_lookup_obj(self->platform, NMP_CACHE_ID_TYPE_OBJECT_TYPE, obj_data->obj);
-        if (plobj)
-            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));
-    }
-}
-
-void
-nmp_rules_manager_track_from_platform(NMPRulesManager *self,
-                                      NMPlatform *     platform,
-                                      int              addr_family,
-                                      gint32           tracking_priority,
-                                      gconstpointer    user_tag)
-{
-    NMPLookup                    lookup;
-    const NMDedupMultiHeadEntry *head_entry;
-    NMDedupMultiIter             iter;
-    const NMPObject *            o;
-
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-
-    if (!platform)
-        platform = self->platform;
-    else
-        g_return_if_fail(NM_IS_PLATFORM(platform));
-
-    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
-
-    nmp_lookup_init_obj_type(&lookup, NMP_OBJECT_TYPE_ROUTING_RULE);
-    head_entry = nm_platform_lookup(platform, &lookup);
-    nmp_cache_iter_for_each (&iter, head_entry, &o) {
-        const NMPlatformRoutingRule *rr = NMP_OBJECT_CAST_ROUTING_RULE(o);
-
-        if (addr_family != AF_UNSPEC && rr->addr_family != addr_family)
-            continue;
-
-        nmp_rules_manager_track(self, rr, tracking_priority, user_tag, NULL);
-    }
-}
-
-/*****************************************************************************/
-
-void
-nmp_rules_manager_track_default(NMPRulesManager *self,
-                                int              addr_family,
-                                gint32           track_priority,
-                                gconstpointer    user_tag)
-{
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-
-    nm_assert(NM_IN_SET(addr_family, AF_UNSPEC, AF_INET, AF_INET6));
-
-    /* track the default rules. See also `man ip-rule`. */
-
-    if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET)) {
-        nmp_rules_manager_track(self,
-                                &((NMPlatformRoutingRule){
-                                    .addr_family = AF_INET,
-                                    .priority    = 0,
-                                    .table       = RT_TABLE_LOCAL,
-                                    .action      = FR_ACT_TO_TBL,
-                                    .protocol    = RTPROT_KERNEL,
-                                }),
-                                track_priority,
-                                user_tag,
-                                NULL);
-        nmp_rules_manager_track(self,
-                                &((NMPlatformRoutingRule){
-                                    .addr_family = AF_INET,
-                                    .priority    = 32766,
-                                    .table       = RT_TABLE_MAIN,
-                                    .action      = FR_ACT_TO_TBL,
-                                    .protocol    = RTPROT_KERNEL,
-                                }),
-                                track_priority,
-                                user_tag,
-                                NULL);
-        nmp_rules_manager_track(self,
-                                &((NMPlatformRoutingRule){
-                                    .addr_family = AF_INET,
-                                    .priority    = 32767,
-                                    .table       = RT_TABLE_DEFAULT,
-                                    .action      = FR_ACT_TO_TBL,
-                                    .protocol    = RTPROT_KERNEL,
-                                }),
-                                track_priority,
-                                user_tag,
-                                NULL);
-    }
-    if (NM_IN_SET(addr_family, AF_UNSPEC, AF_INET6)) {
-        nmp_rules_manager_track(self,
-                                &((NMPlatformRoutingRule){
-                                    .addr_family = AF_INET6,
-                                    .priority    = 0,
-                                    .table       = RT_TABLE_LOCAL,
-                                    .action      = FR_ACT_TO_TBL,
-                                    .protocol    = RTPROT_KERNEL,
-                                }),
-                                track_priority,
-                                user_tag,
-                                NULL);
-        nmp_rules_manager_track(self,
-                                &((NMPlatformRoutingRule){
-                                    .addr_family = AF_INET6,
-                                    .priority    = 32766,
-                                    .table       = RT_TABLE_MAIN,
-                                    .action      = FR_ACT_TO_TBL,
-                                    .protocol    = RTPROT_KERNEL,
-                                }),
-                                track_priority,
-                                user_tag,
-                                NULL);
-    }
-}
-
-static void
-_rules_init(NMPRulesManager *self)
-{
-    if (self->by_data)
-        return;
-
-    self->by_data =
-        g_hash_table_new_full(_rules_data_hash, _rules_data_equal, NULL, _rules_data_destroy);
-    self->by_obj =
-        g_hash_table_new_full(_rules_obj_hash, _rules_obj_equal, NULL, _rules_obj_destroy);
-    self->by_user_tag = g_hash_table_new_full(_rules_user_tag_hash,
-                                              _rules_user_tag_equal,
-                                              NULL,
-                                              _rules_user_tag_destroy);
-}
-
-/*****************************************************************************/
-
-NMPRulesManager *
-nmp_rules_manager_new(NMPlatform *platform)
-{
-    NMPRulesManager *self;
-
-    g_return_val_if_fail(NM_IS_PLATFORM(platform), NULL);
-
-    self  = g_slice_new(NMPRulesManager);
-    *self = (NMPRulesManager){
-        .ref_count = 1,
-        .platform  = g_object_ref(platform),
-    };
-    return self;
-}
-
-void
-nmp_rules_manager_ref(NMPRulesManager *self)
-{
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-
-    self->ref_count++;
-}
-
-void
-nmp_rules_manager_unref(NMPRulesManager *self)
-{
-    g_return_if_fail(NMP_IS_RULES_MANAGER(self));
-
-    if (--self->ref_count > 0)
-        return;
-
-    if (self->by_data) {
-        g_hash_table_destroy(self->by_user_tag);
-        g_hash_table_destroy(self->by_obj);
-        g_hash_table_destroy(self->by_data);
-    }
-    g_object_unref(self->platform);
-    g_slice_free(NMPRulesManager, self);
-}
diff --git a/src/libnm-platform/nmp-rules-manager.h b/src/libnm-platform/nmp-rules-manager.h
deleted file mode 100644
index 69cf9075..00000000
--- a/src/libnm-platform/nmp-rules-manager.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/* SPDX-License-Identifier: LGPL-2.1-or-later */
-
-#ifndef __NMP_RULES_MANAGER_H__
-#define __NMP_RULES_MANAGER_H__
-
-#include "nm-platform.h"
-
-/*****************************************************************************/
-
-#define NMP_RULES_MANAGER_EXTERN_WEAKLY_TRACKED_USER_TAG ((const void *) nmp_rules_manager_new)
-
-typedef struct _NMPRulesManager NMPRulesManager;
-
-NMPRulesManager *nmp_rules_manager_new(NMPlatform *platform);
-
-void nmp_rules_manager_ref(NMPRulesManager *self);
-void nmp_rules_manager_unref(NMPRulesManager *self);
-
-#define nm_auto_unref_rules_manager nm_auto(_nmp_rules_manager_unref)
-NM_AUTO_DEFINE_FCN0(NMPRulesManager *, _nmp_rules_manager_unref, nmp_rules_manager_unref);
-
-void nmp_rules_manager_track(NMPRulesManager *            self,
-                             const NMPlatformRoutingRule *routing_rule,
-                             gint32                       track_priority,
-                             gconstpointer                user_tag,
-                             gconstpointer                user_tag_untrack);
-
-void nmp_rules_manager_track_default(NMPRulesManager *self,
-                                     int              addr_family,
-                                     gint32           track_priority,
-                                     gconstpointer    user_tag);
-
-void nmp_rules_manager_track_from_platform(NMPRulesManager *self,
-                                           NMPlatform *     platform,
-                                           int              addr_family,
-                                           gint32           tracking_priority,
-                                           gconstpointer    user_tag);
-
-void nmp_rules_manager_untrack(NMPRulesManager *            self,
-                               const NMPlatformRoutingRule *routing_rule,
-                               gconstpointer                user_tag);
-
-void nmp_rules_manager_set_dirty(NMPRulesManager *self, gconstpointer user_tag);
-
-void nmp_rules_manager_untrack_all(NMPRulesManager *self,
-                                   gconstpointer    user_tag,
-                                   gboolean         all /* or only dirty */);
-
-void nmp_rules_manager_sync(NMPRulesManager *self, gboolean keep_deleted_rules);
-
-/*****************************************************************************/
-
-#endif /* __NMP_RULES_MANAGER_H__ */
diff --git a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c
index 148657ea..2fa46e38 100644
--- a/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c
+++ b/src/libnm-platform/wifi/nm-wifi-utils-nl80211.c
@@ -43,7 +43,7 @@
 typedef struct {
     NMWifiUtils     parent;
     struct nl_sock *nl_sock;
-    guint32 *       freqs;
+    guint32        *freqs;
     int             id;
     int             num_freqs;
     int             phy;
@@ -104,21 +104,21 @@ nl80211_alloc_msg(NMWifiUtilsNl80211 *self, guint32 cmd, guint32 flags)
 
 static int
 nl80211_send_and_recv(NMWifiUtilsNl80211 *self,
-                      struct nl_msg *     msg,
+                      struct nl_msg      *msg,
                       int (*valid_handler)(struct nl_msg *, void *),
                       void *valid_data)
 {
     int                err;
     int                done = 0;
     const struct nl_cb cb   = {
-        .err_cb     = error_handler,
-        .err_arg    = &done,
-        .finish_cb  = finish_handler,
-        .finish_arg = &done,
-        .ack_cb     = ack_handler,
-        .ack_arg    = &done,
-        .valid_cb   = valid_handler,
-        .valid_arg  = valid_data,
+          .err_cb     = error_handler,
+          .err_arg    = &done,
+          .finish_cb  = finish_handler,
+          .finish_arg = &done,
+          .ack_cb     = ack_handler,
+          .ack_arg    = &done,
+          .valid_cb   = valid_handler,
+          .valid_arg  = valid_data,
     };
 
     g_return_val_if_fail(msg != NULL, -ENOMEM);
@@ -169,8 +169,8 @@ static int
 nl80211_iface_info_handler(struct nl_msg *msg, void *arg)
 {
     struct nl80211_iface_info *info = arg;
-    struct genlmsghdr *        gnlh = nlmsg_data(nlmsg_hdr(msg));
-    struct nlattr *            tb[NL80211_ATTR_MAX + 1];
+    struct genlmsghdr         *gnlh = nlmsg_data(nlmsg_hdr(msg));
+    struct nlattr             *tb[NL80211_ATTR_MAX + 1];
 
     if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
         return NL_SKIP;
@@ -202,7 +202,7 @@ nl80211_iface_info_handler(struct nl_msg *msg, void *arg)
 static _NM80211Mode
 wifi_nl80211_get_mode(NMWifiUtils *data)
 {
-    NMWifiUtilsNl80211 *      self       = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211       *self       = (NMWifiUtilsNl80211 *) data;
     struct nl80211_iface_info iface_info = {
         .mode = _NM_802_11_MODE_UNKNOWN,
     };
@@ -219,7 +219,7 @@ wifi_nl80211_get_mode(NMWifiUtils *data)
 static gboolean
 wifi_nl80211_set_mode(NMWifiUtils *data, const _NM80211Mode mode)
 {
-    NMWifiUtilsNl80211 *         self = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self = (NMWifiUtilsNl80211 *) data;
     nm_auto_nlmsg struct nl_msg *msg  = NULL;
     int                          err;
 
@@ -252,7 +252,7 @@ nla_put_failure:
 static gboolean
 wifi_nl80211_set_powersave(NMWifiUtils *data, guint32 powersave)
 {
-    NMWifiUtilsNl80211 *         self = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self = (NMWifiUtilsNl80211 *) data;
     nm_auto_nlmsg struct nl_msg *msg  = NULL;
     int                          err;
 
@@ -271,9 +271,9 @@ static int
 nl80211_get_wake_on_wlan_handler(struct nl_msg *msg, void *arg)
 {
     _NMSettingWirelessWakeOnWLan *wowl = arg;
-    struct nlattr *               attrs[NL80211_ATTR_MAX + 1];
-    struct nlattr *               trig[NUM_NL80211_WOWLAN_TRIG];
-    struct genlmsghdr *           gnlh = nlmsg_data(nlmsg_hdr(msg));
+    struct nlattr                *attrs[NL80211_ATTR_MAX + 1];
+    struct nlattr                *trig[NUM_NL80211_WOWLAN_TRIG];
+    struct genlmsghdr            *gnlh = nlmsg_data(nlmsg_hdr(msg));
 
     nla_parse_arr(attrs, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL);
 
@@ -309,7 +309,7 @@ nl80211_get_wake_on_wlan_handler(struct nl_msg *msg, void *arg)
 static _NMSettingWirelessWakeOnWLan
 wifi_nl80211_get_wake_on_wlan(NMWifiUtils *data)
 {
-    NMWifiUtilsNl80211 *         self = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self = (NMWifiUtilsNl80211 *) data;
     _NMSettingWirelessWakeOnWLan wowl = _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE;
     nm_auto_nlmsg struct nl_msg *msg  = NULL;
 
@@ -323,9 +323,9 @@ wifi_nl80211_get_wake_on_wlan(NMWifiUtils *data)
 static gboolean
 wifi_nl80211_set_wake_on_wlan(NMWifiUtils *data, _NMSettingWirelessWakeOnWLan wowl)
 {
-    NMWifiUtilsNl80211 *         self = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self = (NMWifiUtilsNl80211 *) data;
     nm_auto_nlmsg struct nl_msg *msg  = NULL;
-    struct nlattr *              triggers;
+    struct nlattr               *triggers;
     int                          err;
 
     if (wowl == _NM_SETTING_WIRELESS_WAKE_ON_WLAN_IGNORE)
@@ -365,7 +365,7 @@ nla_put_failure:
 static guint32
 wifi_nl80211_get_freq(NMWifiUtils *data)
 {
-    NMWifiUtilsNl80211 *         self       = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self       = (NMWifiUtilsNl80211 *) data;
     struct nl80211_iface_info    iface_info = {};
     nm_auto_nlmsg struct nl_msg *msg        = NULL;
 
@@ -441,11 +441,11 @@ nl80211_station_dump_handler(struct nl_msg *msg, void *arg)
         [NL80211_RATE_INFO_40_MHZ_WIDTH] = {.type = NLA_FLAG},
         [NL80211_RATE_INFO_SHORT_GI]     = {.type = NLA_FLAG},
     };
-    struct nlattr *              rinfo[G_N_ELEMENTS(rate_policy)];
-    struct nlattr *              sinfo[G_N_ELEMENTS(stats_policy)];
+    struct nlattr               *rinfo[G_N_ELEMENTS(rate_policy)];
+    struct nlattr               *sinfo[G_N_ELEMENTS(stats_policy)];
     struct nl80211_station_info *info = arg;
-    struct nlattr *              tb[NL80211_ATTR_MAX + 1];
-    struct genlmsghdr *          gnlh = nlmsg_data(nlmsg_hdr(msg));
+    struct nlattr               *tb[NL80211_ATTR_MAX + 1];
+    struct genlmsghdr           *gnlh = nlmsg_data(nlmsg_hdr(msg));
 
     if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), NULL) < 0)
         return NL_SKIP;
@@ -495,10 +495,10 @@ nl80211_station_dump_handler(struct nl_msg *msg, void *arg)
 static gboolean
 wifi_nl80211_get_station(NMWifiUtils *data,
                          NMEtherAddr *out_bssid,
-                         int *        out_quality,
-                         guint32 *    out_rate)
+                         int         *out_quality,
+                         guint32     *out_rate)
 {
-    NMWifiUtilsNl80211 *         self     = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self     = (NMWifiUtilsNl80211 *) data;
     nm_auto_nlmsg struct nl_msg *msg      = NULL;
     struct nl80211_station_info  sta_info = {};
 
@@ -525,7 +525,7 @@ wifi_nl80211_get_station(NMWifiUtils *data,
 static gboolean
 wifi_nl80211_indicate_addressing_running(NMWifiUtils *data, gboolean running)
 {
-    NMWifiUtilsNl80211 *         self = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self = (NMWifiUtilsNl80211 *) data;
     nm_auto_nlmsg struct nl_msg *msg  = NULL;
     int                          err;
 
@@ -552,7 +552,7 @@ nla_put_failure:
 struct nl80211_device_info {
     NMWifiUtilsNl80211 *self;
     int                 phy;
-    guint32 *           freqs;
+    guint32            *freqs;
     int                 num_freqs;
     guint32             freq;
     guint32             caps;
@@ -587,14 +587,14 @@ nl80211_wiphy_info_handler(struct nl_msg *msg, void *arg)
         [NL80211_FREQUENCY_ATTR_RADAR]        = {.type = NLA_FLAG},
         [NL80211_FREQUENCY_ATTR_MAX_TX_POWER] = {.type = NLA_U32},
     };
-    struct nlattr *             tb[NL80211_ATTR_MAX + 1];
-    struct genlmsghdr *         gnlh = nlmsg_data(nlmsg_hdr(msg));
+    struct nlattr              *tb[NL80211_ATTR_MAX + 1];
+    struct genlmsghdr          *gnlh = nlmsg_data(nlmsg_hdr(msg));
     struct nl80211_device_info *info = arg;
-    NMWifiUtilsNl80211 *        self = info->self;
-    struct nlattr *             tb_band[NL80211_BAND_ATTR_MAX + 1];
-    struct nlattr *             tb_freq[G_N_ELEMENTS(freq_policy)];
-    struct nlattr *             nl_band;
-    struct nlattr *             nl_freq;
+    NMWifiUtilsNl80211         *self = info->self;
+    struct nlattr              *tb_band[NL80211_BAND_ATTR_MAX + 1];
+    struct nlattr              *tb_freq[G_N_ELEMENTS(freq_policy)];
+    struct nlattr              *nl_band;
+    struct nlattr              *nl_freq;
     int                         rem_freq;
     int                         rem_band;
     int                         freq_idx;
@@ -761,7 +761,7 @@ nl80211_wiphy_info_handler(struct nl_msg *msg, void *arg)
 static guint32
 wifi_nl80211_get_mesh_channel(NMWifiUtils *data)
 {
-    NMWifiUtilsNl80211 *         self        = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self        = (NMWifiUtilsNl80211 *) data;
     nm_auto_nlmsg struct nl_msg *msg         = NULL;
     struct nl80211_device_info   device_info = {.self = self};
     int                          i;
@@ -783,7 +783,7 @@ wifi_nl80211_get_mesh_channel(NMWifiUtils *data)
 static gboolean
 wifi_nl80211_set_mesh_channel(NMWifiUtils *data, guint32 channel)
 {
-    NMWifiUtilsNl80211 *         self = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self = (NMWifiUtilsNl80211 *) data;
     nm_auto_nlmsg struct nl_msg *msg  = NULL;
     int                          err;
 
@@ -802,7 +802,7 @@ nla_put_failure:
 static gboolean
 wifi_nl80211_set_mesh_ssid(NMWifiUtils *data, const guint8 *ssid, gsize len)
 {
-    NMWifiUtilsNl80211 *         self = (NMWifiUtilsNl80211 *) data;
+    NMWifiUtilsNl80211          *self = (NMWifiUtilsNl80211 *) data;
     nm_auto_nlmsg struct nl_msg *msg  = NULL;
     int                          err;
 
@@ -822,7 +822,7 @@ nm_wifi_utils_nl80211_init(NMWifiUtilsNl80211 *self)
 static void
 nm_wifi_utils_nl80211_class_init(NMWifiUtilsNl80211Class *klass)
 {
-    GObjectClass *    object_class     = G_OBJECT_CLASS(klass);
+    GObjectClass     *object_class     = G_OBJECT_CLASS(klass);
     NMWifiUtilsClass *wifi_utils_class = NM_WIFI_UTILS_CLASS(klass);
 
     object_class->dispose = dispose;
@@ -845,7 +845,7 @@ NMWifiUtils *
 nm_wifi_utils_nl80211_new(int ifindex, struct nl_sock *genl)
 {
     gs_unref_object NMWifiUtilsNl80211 *self        = NULL;
-    nm_auto_nlmsg struct nl_msg *       msg         = NULL;
+    nm_auto_nlmsg struct nl_msg        *msg         = NULL;
     struct nl80211_device_info          device_info = {};
 
     if (!genl)
diff --git a/src/libnm-platform/wifi/nm-wifi-utils-private.h b/src/libnm-platform/wifi/nm-wifi-utils-private.h
index bc1e75ec..7461b65e 100644
--- a/src/libnm-platform/wifi/nm-wifi-utils-private.h
+++ b/src/libnm-platform/wifi/nm-wifi-utils-private.h
@@ -39,8 +39,8 @@ typedef struct {
      */
     gboolean (*get_station)(NMWifiUtils *data,
                             NMEtherAddr *out_bssid,
-                            int *        out_quality,
-                            guint32 *    out_rate);
+                            int         *out_quality,
+                            guint32     *out_rate);
 
     /* OLPC Mesh-only functions */
 
diff --git a/src/libnm-platform/wifi/nm-wifi-utils-wext.c b/src/libnm-platform/wifi/nm-wifi-utils-wext.c
index 6fb37c49..2d4112bc 100644
--- a/src/libnm-platform/wifi/nm-wifi-utils-wext.c
+++ b/src/libnm-platform/wifi/nm-wifi-utils-wext.c
@@ -427,7 +427,7 @@ wext_qual_to_percent(const struct iw_quality *qual, const struct iw_quality *max
 static int
 wifi_wext_get_qual(NMWifiUtils *data)
 {
-    NMWifiUtilsWext *    wext = (NMWifiUtilsWext *) data;
+    NMWifiUtilsWext     *wext = (NMWifiUtilsWext *) data;
     struct iwreq         wrq;
     struct iw_statistics stats;
     char                 ifname[IFNAMSIZ];
@@ -455,8 +455,8 @@ wifi_wext_get_qual(NMWifiUtils *data)
 static gboolean
 wifi_wext_get_station(NMWifiUtils *data,
                       NMEtherAddr *out_bssid,
-                      int *        out_quality,
-                      guint32 *    out_rate)
+                      int         *out_quality,
+                      guint32     *out_rate)
 {
     NMEtherAddr local_addr;
 
@@ -588,9 +588,9 @@ wext_can_scan_ifname(NMWifiUtilsWext *wext, const char *ifname)
 
 static gboolean
 wext_get_range_ifname(NMWifiUtilsWext *wext,
-                      const char *     ifname,
+                      const char      *ifname,
                       struct iw_range *range,
-                      guint32 *        response_len)
+                      guint32         *response_len)
 {
     int          i       = 26;
     gboolean     success = FALSE;
@@ -698,7 +698,7 @@ nm_wifi_utils_wext_init(NMWifiUtilsWext *self)
 static void
 nm_wifi_utils_wext_class_init(NMWifiUtilsWextClass *klass)
 {
-    GObjectClass *    object_class     = G_OBJECT_CLASS(klass);
+    GObjectClass     *object_class     = G_OBJECT_CLASS(klass);
     NMWifiUtilsClass *wifi_utils_class = NM_WIFI_UTILS_CLASS(klass);
 
     object_class->dispose = dispose;
@@ -717,7 +717,7 @@ nm_wifi_utils_wext_class_init(NMWifiUtilsWextClass *klass)
 NMWifiUtils *
 nm_wifi_utils_wext_new(int ifindex, gboolean check_scan)
 {
-    NMWifiUtilsWext *               wext;
+    NMWifiUtilsWext                *wext;
     struct iw_range                 range;
     guint32                         response_len = 0;
     struct iw_range_with_scan_capa *scan_capa_range;
diff --git a/src/libnm-platform/wifi/nm-wifi-utils.c b/src/libnm-platform/wifi/nm-wifi-utils.c
index 0b5f8d71..8bdd65c2 100644
--- a/src/libnm-platform/wifi/nm-wifi-utils.c
+++ b/src/libnm-platform/wifi/nm-wifi-utils.c
@@ -132,8 +132,8 @@ nm_wifi_utils_find_freq(NMWifiUtils *data, const guint32 *freqs)
 gboolean
 nm_wifi_utils_get_station(NMWifiUtils *data,
                           NMEtherAddr *out_bssid,
-                          int *        out_quality,
-                          guint32 *    out_rate)
+                          int         *out_quality,
+                          guint32     *out_rate)
 {
     g_return_val_if_fail(data != NULL, FALSE);
 
diff --git a/src/libnm-platform/wifi/nm-wifi-utils.h b/src/libnm-platform/wifi/nm-wifi-utils.h
index 157522ee..be33b90c 100644
--- a/src/libnm-platform/wifi/nm-wifi-utils.h
+++ b/src/libnm-platform/wifi/nm-wifi-utils.h
@@ -51,8 +51,8 @@ guint32 nm_wifi_utils_find_freq(NMWifiUtils *data, const guint32 *freqs);
  */
 gboolean nm_wifi_utils_get_station(NMWifiUtils *data,
                                    NMEtherAddr *out_bssid,
-                                   int *        out_quality,
-                                   guint32 *    out_rate);
+                                   int         *out_quality,
+                                   guint32     *out_rate);
 
 /* Tells the driver DHCP or SLAAC is running */
 gboolean nm_wifi_utils_indicate_addressing_running(NMWifiUtils *data, gboolean running);
diff --git a/src/libnm-platform/wpan/nm-wpan-utils.c b/src/libnm-platform/wpan/nm-wpan-utils.c
index 082cc3e7..d9bbd0f0 100644
--- a/src/libnm-platform/wpan/nm-wpan-utils.c
+++ b/src/libnm-platform/wpan/nm-wpan-utils.c
@@ -95,7 +95,7 @@ nl802154_alloc_msg(NMWpanUtils *self, guint32 cmd, guint32 flags)
 }
 
 static int
-nl802154_send_and_recv(NMWpanUtils *  self,
+nl802154_send_and_recv(NMWpanUtils   *self,
                        struct nl_msg *msg,
                        int (*valid_handler)(struct nl_msg *, void *),
                        void *valid_data)
@@ -103,14 +103,14 @@ nl802154_send_and_recv(NMWpanUtils *  self,
     int                err;
     int                done = 0;
     const struct nl_cb cb   = {
-        .err_cb     = error_handler,
-        .err_arg    = &done,
-        .finish_cb  = finish_handler,
-        .finish_arg = &done,
-        .ack_cb     = ack_handler,
-        .ack_arg    = &done,
-        .valid_cb   = valid_handler,
-        .valid_arg  = valid_data,
+          .err_cb     = error_handler,
+          .err_arg    = &done,
+          .finish_cb  = finish_handler,
+          .finish_arg = &done,
+          .ack_cb     = ack_handler,
+          .ack_arg    = &done,
+          .valid_cb   = valid_handler,
+          .valid_arg  = valid_data,
     };
 
     g_return_val_if_fail(msg != NULL, -ENOMEM);
@@ -149,9 +149,9 @@ nl802154_get_interface_handler(struct nl_msg *msg, void *arg)
         [NL802154_ATTR_PAN_ID]     = {.type = NLA_U16},
         [NL802154_ATTR_SHORT_ADDR] = {.type = NLA_U16},
     };
-    struct nlattr *            tb[G_N_ELEMENTS(nl802154_policy)];
+    struct nlattr             *tb[G_N_ELEMENTS(nl802154_policy)];
     struct nl802154_interface *info = arg;
-    struct genlmsghdr *        gnlh = nlmsg_data(nlmsg_hdr(msg));
+    struct genlmsghdr         *gnlh = nlmsg_data(nlmsg_hdr(msg));
 
     if (nla_parse_arr(tb, genlmsg_attrdata(gnlh, 0), genlmsg_attrlen(gnlh, 0), nl802154_policy) < 0)
         return NL_SKIP;