about summary refs log tree commit diff
path: root/src/libnm-platform/nm-platform.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2026-05-14 19:21:22 +0200
committerMichael Biebl <biebl@debian.org>2026-05-14 19:21:22 +0200
commit869e9027026cdbb15d4e4a6327ff41d2697858eb (patch)
tree52edec7f935ff1bbb425c3515c6e49e6b8b0e28b /src/libnm-platform/nm-platform.c
parent067fb576988f685e83ac8b0ae690334aff547c85 (diff)
New upstream version 1.56.1 upstream/1.56.1
Diffstat (limited to 'src/libnm-platform/nm-platform.c')
-rw-r--r--src/libnm-platform/nm-platform.c109
1 files changed, 99 insertions, 10 deletions
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index 853157d2..914dcd86 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -1388,6 +1388,12 @@ nm_platform_link_add(NMPlatform            *self,
                case NM_LINK_TYPE_VETH:
                    nm_sprintf_buf(buf, ", veth-peer \"%s\"", (const char *) extra_data);
                    break;
+               case NM_LINK_TYPE_GENEVE:
+                   nm_strbuf_append_str(&buf_p, &buf_len, ", ");
+                   nm_platform_lnk_geneve_to_string((const NMPlatformLnkGeneve *) extra_data,
+                                                    buf_p,
+                                                    buf_len);
+                   break;
                case NM_LINK_TYPE_GRE:
                case NM_LINK_TYPE_GRETAP:
                    nm_strbuf_append_str(&buf_p, &buf_len, ", ");
@@ -2565,6 +2571,12 @@ nm_platform_link_get_lnk_bridge(NMPlatform *self, int ifindex, const NMPlatformL
     return _link_get_lnk(self, ifindex, NM_LINK_TYPE_BRIDGE, out_link);
 }
 
+const NMPlatformLnkGeneve *
+nm_platform_link_get_lnk_geneve(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+    return _link_get_lnk(self, ifindex, NM_LINK_TYPE_GENEVE, out_link);
+}
+
 const NMPlatformLnkGre *
 nm_platform_link_get_lnk_gre(NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
 {
@@ -6495,6 +6507,52 @@ nm_platform_lnk_bond_to_string(const NMPlatformLnkBond *lnk, char *buf, gsize le
 }
 
 const char *
+nm_platform_lnk_geneve_to_string(const NMPlatformLnkGeneve *lnk, char *buf, gsize len)
+{
+    char str_remote[NM_INET_ADDRSTRLEN];
+    char str_remote1[30 + NM_INET_ADDRSTRLEN];
+    char str_remote6[NM_INET_ADDRSTRLEN];
+    char str_remote6_1[30 + NM_INET_ADDRSTRLEN];
+    char str_ttl[30];
+    char str_tos[30];
+    char str_id[30];
+    char str_dstport[30];
+
+    if (!nm_utils_to_string_buffer_init_null(lnk, &buf, &len))
+        return buf;
+
+    g_snprintf(
+        buf,
+        len,
+        "geneve"
+        "%s" /* id */
+        "%s" /* remote */
+        "%s" /* remote6 */
+        "%s" /* dst_port */
+        "%s" /* ttl */
+        "%s" /* tos */
+        "%s" /* df */
+        "",
+        lnk->id ? nm_sprintf_buf(str_id, " id %u", lnk->id) : "",
+        lnk->remote
+            ? nm_sprintf_buf(str_remote, " remote %s", nm_inet4_ntop(lnk->remote, str_remote1))
+            : "",
+        !IN6_IS_ADDR_UNSPECIFIED(&lnk->remote6)
+            ? nm_sprintf_buf(str_remote6, " remote %s", nm_inet6_ntop(&lnk->remote6, str_remote6_1))
+            : "",
+        lnk->dst_port ? nm_sprintf_buf(str_dstport, " dstport %u", lnk->dst_port) : "",
+        lnk->ttl > 0    ? nm_sprintf_buf(str_ttl, " ttl %u", lnk->ttl & 0xff)
+        : lnk->ttl == 0 ? "ttl auto"
+                        : "ttl inherit",
+        lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf(str_tos, " tos 0x%x", lnk->tos))
+                 : "",
+        lnk->df == 1   ? " df set "
+        : lnk->df == 2 ? " df inherit "
+                       : "");
+    return buf;
+}
+
+const char *
 nm_platform_lnk_gre_to_string(const NMPlatformLnkGre *lnk, char *buf, gsize len)
 {
     char str_local[30];
@@ -7366,13 +7424,16 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route     *route,
                         "%s"         /* ifindex */
                         "%s%s"       /* gateway */
                         " weight %s" /* weight */
+                        "%s"         /* onlink */
                         "",
                         NM_PRINT_FMT_QUOTED2(nexthop->gateway != 0 || nexthop->ifindex <= 0,
                                              " via ",
                                              nm_inet4_ntop(nexthop->gateway, s_gateway),
                                              ""),
                         _to_string_dev(str_dev, nexthop->ifindex),
-                        nm_sprintf_buf(weight_str, "%u", nexthop->weight));
+                        nm_sprintf_buf(weight_str, "%u", nexthop->weight),
+                        NM_FLAGS_HAS(nexthop->rtnh_flags, (unsigned) RTNH_F_ONLINK) ? " onlink"
+                                                                                    : "");
                 }
             }
         }
@@ -8492,6 +8553,27 @@ nm_platform_lnk_gre_cmp(const NMPlatformLnkGre *a, const NMPlatformLnkGre *b)
 }
 
 void
+nm_platform_lnk_geneve_hash_update(const NMPlatformLnkGeneve *obj, NMHashState *h)
+{
+    nm_hash_update_vals(h, obj->id, obj->remote, obj->dst_port, obj->ttl, obj->tos, obj->df);
+    nm_hash_update_mem(h, &obj->remote6, sizeof(obj->remote6));
+}
+
+int
+nm_platform_lnk_geneve_cmp(const NMPlatformLnkGeneve *a, const NMPlatformLnkGeneve *b)
+{
+    NM_CMP_SELF(a, b);
+    NM_CMP_FIELD(a, b, id);
+    NM_CMP_FIELD(a, b, remote);
+    NM_CMP_FIELD_MEMCMP(a, b, remote6);
+    NM_CMP_FIELD(a, b, ttl);
+    NM_CMP_FIELD(a, b, tos);
+    NM_CMP_FIELD(a, b, dst_port);
+    NM_CMP_FIELD(a, b, df);
+    return 0;
+}
+
+void
 nm_platform_lnk_hsr_hash_update(const NMPlatformLnkHsr *obj, NMHashState *h)
 {
     nm_hash_update_vals(h,
@@ -8931,7 +9013,11 @@ nm_platform_ip4_rt_nexthop_hash_update(const NMPlatformIP4RtNextHop *obj,
     nm_assert(obj);
 
     w = for_id ? NM_MAX(obj->weight, 1u) : obj->weight;
-    nm_hash_update_vals(h, obj->ifindex, obj->gateway, w);
+    nm_hash_update_vals(h,
+                        obj->ifindex,
+                        obj->gateway,
+                        w,
+                        for_id ? (obj->rtnh_flags & RTNH_F_ONLINK) : obj->rtnh_flags);
 }
 
 void
@@ -8968,7 +9054,6 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
                                 obj->initrwnd,
                                 obj->mtu,
                                 obj->rto_min,
-                                obj->r_rtm_flags & RTNH_F_ONLINK,
                                 NM_HASH_COMBINE_BOOLS(guint16,
                                                       obj->quickack,
                                                       obj->lock_window,
@@ -8986,7 +9071,8 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
                                     obj->via.addr_family == AF_INET6 ? obj->via.addr.addr6
                                                                      : in6addr_any,
                                     obj->gateway,
-                                    _ip4_route_weight_normalize(n_nexthops, obj->weight, FALSE));
+                                    _ip4_route_weight_normalize(n_nexthops, obj->weight, FALSE),
+                                    obj->r_rtm_flags & RTNH_F_ONLINK);
             }
         }
         break;
@@ -9079,6 +9165,11 @@ nm_platform_ip4_rt_nexthop_cmp(const NMPlatformIP4RtNextHop *a,
     w_b = for_id ? NM_MAX(b->weight, 1u) : b->weight;
     NM_CMP_DIRECT(w_a, w_b);
 
+    if (for_id)
+        NM_CMP_DIRECT(a->rtnh_flags & RTNH_F_ONLINK, b->rtnh_flags & RTNH_F_ONLINK);
+    else
+        NM_CMP_FIELD(a, b, rtnh_flags);
+
     return 0;
 }
 
@@ -9119,12 +9210,6 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
             NM_CMP_FIELD(a, b, mtu);
             NM_CMP_FIELD(a, b, rto_min);
 
-            /* Note that for NetworkManager, the onlink flag is only part of the entire route.
-             * For kernel, each next hop has it's own onlink flag (rtnh_flags). This means,
-             * we can only merge ECMP routes, if they agree with their onlink flag, and then
-             * all next hops are onlink (or not). */
-            NM_CMP_DIRECT(a->r_rtm_flags & RTNH_F_ONLINK, b->r_rtm_flags & RTNH_F_ONLINK);
-
             NM_CMP_FIELD_UNSAFE(a, b, quickack);
             NM_CMP_FIELD_UNSAFE(a, b, lock_window);
             NM_CMP_FIELD_UNSAFE(a, b, lock_cwnd);
@@ -9143,6 +9228,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
                 NM_CMP_DIRECT(n_nexthops, nm_platform_ip4_route_get_n_nexthops(b));
                 NM_CMP_DIRECT(_ip4_route_weight_normalize(n_nexthops, a->weight, FALSE),
                               _ip4_route_weight_normalize(n_nexthops, b->weight, FALSE));
+                /* The onlink flag is per-nexthop. For the first nexthop it is in
+                 * r_rtm_flags. For extra nexthops, it's compared via
+                 * nm_platform_ip4_rt_nexthop_cmp(). */
+                NM_CMP_DIRECT(a->r_rtm_flags & RTNH_F_ONLINK, b->r_rtm_flags & RTNH_F_ONLINK);
             }
         }
         break;