about summary refs log tree commit diff
path: root/src/libnm-platform
diff options
context:
space:
mode:
authorSebastien Bacher <seb128@ubuntu.com>2021-08-25 15:24:42 +0200
committerSebastien Bacher <seb128@ubuntu.com>2021-08-25 15:24:42 +0200
commitdbb91282fa488964fb20595f9494a9f0e4f36a58 (patch)
tree142bc942e5320b35514cdf03a5f9f47a9b89df0e /src/libnm-platform
parent5f2ede3a2813b0e9204befdcfc67509d34be71c6 (diff)
parentcfb80376641fa49137b9996130352697e7f8b436 (diff)
Update upstream source from tag 'upstream/1.32.10'
Update to upstream version '1.32.10'
with Debian dir fcf2778b50b013ede3e7375bc1d829e984175658
Diffstat (limited to 'src/libnm-platform')
-rw-r--r--src/libnm-platform/nm-linux-platform.c1
-rw-r--r--src/libnm-platform/nm-platform.c62
-rw-r--r--src/libnm-platform/nm-platform.h8
-rw-r--r--src/libnm-platform/nmp-netns.c10
-rw-r--r--src/libnm-platform/nmp-object.h15
5 files changed, 73 insertions, 23 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index bdeae826..bcf94200 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -3519,6 +3519,7 @@ rta_multipath_done:;
 
     obj = nmp_object_new(is_v4 ? 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);
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index 089d0d42..6c0d0015 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -4489,6 +4489,20 @@ nm_platform_ip_route_sync(NMPlatform *self,
 
             conf_o = routes->pdata[i];
 
+            if (NMP_OBJECT_CAST_IP_ROUTE(conf_o)->is_external) {
+                /* This route is added externally. We don't have our own agenda to
+                 * add it, so skip. */
+                continue;
+            }
+
+            /* User space cannot add IPv6 routes with metric 0. However, kernel can, and we might track such
+             * routes in @route as they are present external. As we already skipped external routes above,
+             * we don't expect a user's choice to add such a route (it won't work anyway). */
+            nm_assert(
+                IS_IPv4
+                || nm_platform_ip6_route_get_effective_metric(NMP_OBJECT_CAST_IP6_ROUTE(conf_o))
+                       != 0);
+
 #define VTABLE_IS_DEVICE_ROUTE(vt, o)                          \
     (vt->is_ip4 ? (NMP_OBJECT_CAST_IP4_ROUTE(o)->gateway == 0) \
                 : IN6_IS_ADDR_UNSPECIFIED(&NMP_OBJECT_CAST_IP6_ROUTE(o)->gateway))
@@ -4505,7 +4519,7 @@ nm_platform_ip_route_sync(NMPlatform *self,
                 routes_idx = g_hash_table_new((GHashFunc) nmp_object_id_hash,
                                               (GEqualFunc) nmp_object_id_equal);
             }
-            if (!g_hash_table_insert(routes_idx, (gpointer) conf_o, (gpointer) conf_o)) {
+            if (!g_hash_table_add(routes_idx, (gpointer) conf_o)) {
                 _LOG3D("route-sync: skip adding duplicate route %s",
                        nmp_object_to_string(conf_o,
                                             NMP_OBJECT_TO_STRING_PUBLIC,
@@ -4514,14 +4528,6 @@ nm_platform_ip_route_sync(NMPlatform *self,
                 continue;
             }
 
-            if (!IS_IPv4
-                && nm_platform_ip6_route_get_effective_metric(NMP_OBJECT_CAST_IP6_ROUTE(conf_o))
-                       == 0) {
-                /* User space cannot add routes with metric 0. However, kernel can, and we might track such
-                 * routes in @route as they are present external. Skip them silently. */
-                continue;
-            }
-
             plat_entry = nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, conf_o);
             if (plat_entry) {
                 const NMPObject *plat_o;
@@ -4684,6 +4690,24 @@ sync_route_add:
     }
 
     if (routes_prune) {
+        if (routes) {
+            for (i = 0; i < routes->len; i++) {
+                conf_o = routes->pdata[i];
+
+                if (NMP_OBJECT_CAST_IP_ROUTE(conf_o)->is_external) {
+                    /* this is only to catch the case where an external route is
+                     * both in @routes and @routes_prune list. In that case,
+                     * @routes should win and we should not remove the address. */
+                    if (!routes_idx) {
+                        routes_idx = g_hash_table_new((GHashFunc) nmp_object_id_hash,
+                                                      (GEqualFunc) nmp_object_id_equal);
+                    }
+                    g_hash_table_add(routes_idx, (gpointer) conf_o);
+                    continue;
+                }
+            }
+        }
+
         for (i = 0; i < routes_prune->len; i++) {
             const NMPObject *prune_o;
 
@@ -4694,7 +4718,7 @@ sync_route_add:
                       || (!NM_IS_IPv4(addr_family)
                           && NMP_OBJECT_GET_TYPE(prune_o) == NMP_OBJECT_TYPE_IP6_ROUTE));
 
-            if (routes_idx && g_hash_table_lookup(routes_idx, prune_o))
+            if (nm_g_hash_table_lookup(routes_idx, prune_o))
                 continue;
 
             if (!nm_platform_lookup_entry(self, NMP_CACHE_ID_TYPE_OBJECT_TYPE, prune_o))
@@ -6524,6 +6548,7 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
         "%s"                                   /* initcwnd */
         "%s"                                   /* initrwnd */
         "%s"                                   /* mtu */
+        "%s"                                   /* is_external */
         "",
         nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced),
                                               str_type),
@@ -6579,7 +6604,8 @@ nm_platform_ip4_route_to_string(const NMPlatformIP4Route *route, char *buf, gsiz
                                                        " mtu %s%" G_GUINT32_FORMAT,
                                                        route->lock_mtu ? "lock " : "",
                                                        route->mtu)
-                                      : "");
+                                      : "",
+        route->is_external ? " (E)" : "");
     return buf;
 }
 
@@ -6649,6 +6675,7 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
         "%s"                                   /* initrwnd */
         "%s"                                   /* mtu */
         "%s"                                   /* pref */
+        "%s"                                   /* is_external */
         "",
         nm_net_aux_rtnl_rtntype_n2a_maybe_buf(nm_platform_route_type_uncoerce(route->type_coerced),
                                               str_type),
@@ -6708,7 +6735,8 @@ nm_platform_ip6_route_to_string(const NMPlatformIP6Route *route, char *buf, gsiz
             str_pref,
             " pref %s",
             nm_icmpv6_router_pref_to_string(route->rt_pref, str_pref2, sizeof(str_pref2)))
-                       : "");
+                       : "",
+        route->is_external ? " (E)" : "");
 
     return buf;
 }
@@ -8005,7 +8033,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
                                                   obj->lock_cwnd,
                                                   obj->lock_initcwnd,
                                                   obj->lock_initrwnd,
-                                                  obj->lock_mtu));
+                                                  obj->lock_mtu,
+                                                  obj->is_external));
         break;
     }
 }
@@ -8095,6 +8124,8 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
         NM_CMP_FIELD(a, b, initcwnd);
         NM_CMP_FIELD(a, b, initrwnd);
         NM_CMP_FIELD(a, b, mtu);
+        if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL)
+            NM_CMP_FIELD_UNSAFE(a, b, is_external);
         break;
     }
     return 0;
@@ -8186,7 +8217,8 @@ nm_platform_ip6_route_hash_update(const NMPlatformIP6Route *obj,
                                                   obj->lock_cwnd,
                                                   obj->lock_initcwnd,
                                                   obj->lock_initrwnd,
-                                                  obj->lock_mtu),
+                                                  obj->lock_mtu,
+                                                  obj->is_external),
                             obj->window,
                             obj->cwnd,
                             obj->initcwnd,
@@ -8269,6 +8301,8 @@ nm_platform_ip6_route_cmp(const NMPlatformIP6Route *a,
             NM_CMP_DIRECT(_route_pref_normalize(a->rt_pref), _route_pref_normalize(b->rt_pref));
         else
             NM_CMP_FIELD(a, b, rt_pref);
+        if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_FULL)
+            NM_CMP_FIELD_UNSAFE(a, b, is_external);
         break;
     }
     return 0;
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index e6279176..9d40cbbe 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -462,6 +462,14 @@ typedef union {
      * the "table_coerced" field is ignored (unlike for the metric). */            \
     bool table_any : 1;                                                                   \
                                                                                           \
+    /* This route is tracked as external route, that is not a route that NetworkManager
+     * actively wants to add, but a route that was added externally. In some cases, such
+     * a route should be ignored.
+     *
+     * Note that unlike most other fields here, this flag only exists inside NetworkManager
+     * and is not reflected on netlink. */   \
+    bool is_external : 1;                                                                 \
+                                                                                          \
     /* rtnh_flags
      *
      * Routes with rtm_flags RTM_F_CLONED are hidden by platform and
diff --git a/src/libnm-platform/nmp-netns.c b/src/libnm-platform/nmp-netns.c
index aea5b3b6..2b28a4cd 100644
--- a/src/libnm-platform/nmp-netns.c
+++ b/src/libnm-platform/nmp-netns.c
@@ -11,7 +11,6 @@
 #include <sys/mount.h>
 #include <sys/stat.h>
 #include <sys/types.h>
-#include <pthread.h>
 
 #include "libnm-log-core/nm-logging.h"
 
@@ -151,20 +150,13 @@ _netns_stack_get_impl(void)
 {
     gs_unref_object NMPNetns *netns = NULL;
     gs_free_error GError *error     = NULL;
-    pthread_key_t         key;
     GArray *              s;
 
     s = g_array_new(FALSE, FALSE, sizeof(NetnsInfo));
     g_array_set_clear_func(s, _netns_stack_clear_cb);
     _netns_stack = s;
 
-    /* register a destructor function to cleanup the array. If we fail
-     * to do so, we will leak NMPNetns instances (and their file descriptor) when the
-     * thread exits. */
-    if (pthread_key_create(&key, (void (*)(void *)) g_array_unref) != 0)
-        _LOGE(NULL, "failure to initialize thread-local storage");
-    else if (pthread_setspecific(key, s) != 0)
-        _LOGE(NULL, "failure to set thread-local storage");
+    nm_utils_thread_local_register_destroy(s, (GDestroyNotify) g_array_unref);
 
     /* at the bottom of the stack we must try to create a netns instance
      * that we never pop. It's the base to which we need to return. */
diff --git a/src/libnm-platform/nmp-object.h b/src/libnm-platform/nmp-object.h
index e3e101ee..021829db 100644
--- a/src/libnm-platform/nmp-object.h
+++ b/src/libnm-platform/nmp-object.h
@@ -778,6 +778,18 @@ nmp_cache_iter_next(NMDedupMultiIter *iter, const NMPObject **out_obj)
 }
 
 static inline gboolean
+nmp_cache_iter_prev(NMDedupMultiIter *iter, const NMPObject **out_obj)
+{
+    gboolean has_prev;
+
+    has_prev = nm_dedup_multi_iter_prev(iter);
+    nm_assert(!has_prev || NMP_OBJECT_IS_VALID(iter->current->obj));
+    if (out_obj)
+        *out_obj = has_prev ? iter->current->obj : NULL;
+    return has_prev;
+}
+
+static inline gboolean
 nmp_cache_iter_next_link(NMDedupMultiIter *iter, const NMPlatformLink **out_obj)
 {
     gboolean has_next;
@@ -792,6 +804,9 @@ nmp_cache_iter_next_link(NMDedupMultiIter *iter, const NMPlatformLink **out_obj)
 #define nmp_cache_iter_for_each(iter, head, obj) \
     for (nm_dedup_multi_iter_init((iter), (head)); nmp_cache_iter_next((iter), (obj));)
 
+#define nmp_cache_iter_for_each_reverse(iter, head, obj) \
+    for (nm_dedup_multi_iter_init_reverse((iter), (head)); nmp_cache_iter_prev((iter), (obj));)
+
 #define nmp_cache_iter_for_each_link(iter, head, obj) \
     for (nm_dedup_multi_iter_init((iter), (head)); nmp_cache_iter_next_link((iter), (obj));)