summary refs log tree commit diff
path: root/src/libnm-platform/nm-linux-platform.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-platform/nm-linux-platform.c')
-rw-r--r--src/libnm-platform/nm-linux-platform.c895
1 files changed, 496 insertions, 399 deletions
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;