summary refs log tree commit diff
path: root/src/libnm-platform
diff options
context:
space:
mode:
Diffstat (limited to 'src/libnm-platform')
-rw-r--r--src/libnm-platform/nm-linux-platform.c56
-rw-r--r--src/libnm-platform/nm-platform.c25
-rw-r--r--src/libnm-platform/nm-platform.h15
-rw-r--r--src/libnm-platform/nmp-ethtool.c2
-rw-r--r--src/libnm-platform/nmp-object.c2
5 files changed, 86 insertions, 14 deletions
diff --git a/src/libnm-platform/nm-linux-platform.c b/src/libnm-platform/nm-linux-platform.c
index 0c1097c2..cc5b99e0 100644
--- a/src/libnm-platform/nm-linux-platform.c
+++ b/src/libnm-platform/nm-linux-platform.c
@@ -59,6 +59,7 @@ G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW == MPTCP_PM_ADDR_FLAG_SUBFLOW);
 G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_BACKUP == MPTCP_PM_ADDR_FLAG_BACKUP);
 G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_FULLMESH == MPTCP_PM_ADDR_FLAG_FULLMESH);
 G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_IMPLICIT == MPTCP_PM_ADDR_FLAG_IMPLICIT);
+G_STATIC_ASSERT(NM_MPTCP_PM_ADDR_FLAG_LAMINAR == MPTCP_PM_ADDR_FLAG_LAMINAR);
 
 /*****************************************************************************/
 
@@ -4014,6 +4015,7 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
         [RTA_PREF]      = {.type = NLA_U8},
         [RTA_FLOW]      = {.type = NLA_U32},
         [RTA_CACHEINFO] = {.minlen = nm_offsetofend(struct rta_cacheinfo, rta_tsage)},
+        [RTA_VIA]       = {.minlen = nm_offsetofend(struct rtvia, rtvia_family)},
         [RTA_METRICS]   = {.type = NLA_NESTED},
         [RTA_MULTIPATH] = {.type = NLA_NESTED},
     };
@@ -4030,9 +4032,11 @@ _new_from_nl_route(const struct nlmsghdr *nlh, gboolean id_only, ParseNlmsgIter
         guint8   weight;
         int      ifindex;
         NMIPAddr gateway;
+        gboolean is_via;
     } nh = {
         .found    = FALSE,
         .has_more = FALSE,
+        .is_via   = FALSE,
     };
     guint                           v4_n_nexthops = 0;
     NMPlatformIP4RtNextHop          v4_nh_extra_nexthops_stack[10];
@@ -4201,13 +4205,26 @@ rta_multipath_done:
         return nm_assert_unreachable_val(NULL);
     }
 
-    if (tb[RTA_OIF] || tb[RTA_GATEWAY] || tb[RTA_FLOW]) {
+    if (tb[RTA_OIF] || tb[RTA_GATEWAY] || tb[RTA_FLOW] || tb[RTA_VIA]) {
         int      ifindex = 0;
         NMIPAddr gateway = {};
 
         if (tb[RTA_OIF])
             ifindex = nla_get_u32(tb[RTA_OIF]);
-        if (_check_addr_or_return_null(tb, RTA_GATEWAY, addr_len))
+
+        if (tb[RTA_VIA]) {
+            struct rtvia *rtvia;
+
+            /* Used when the gateway family doesn't match the route family */
+            rtvia = nla_data(tb[RTA_VIA]);
+            if (rtvia->rtvia_family != AF_INET6)
+                return NULL;
+            if (nla_len(tb[RTA_VIA]) < sizeof(struct rtvia) + sizeof(struct in6_addr))
+                return NULL;
+
+            nh.is_via = TRUE;
+            memcpy(&gateway, rtvia->rtvia_addr, sizeof(struct in6_addr));
+        } else if (_check_addr_or_return_null(tb, RTA_GATEWAY, addr_len))
             memcpy(&gateway, nla_data(tb[RTA_GATEWAY]), addr_len);
 
         if (!nh.found) {
@@ -4223,6 +4240,9 @@ rta_multipath_done:
         } else {
             /* Kernel supports new style nexthop configuration,
              * verify that it is a duplicate and ignore old-style nexthop. */
+            if (nh.is_via)
+                return NULL;
+
             if (nh.ifindex != ifindex || memcmp(&nh.gateway, &gateway, addr_len) != 0) {
                 /* we have a RTA_MULTIPATH attribute that does not agree.
                  * That seems not right. Error out. */
@@ -4238,7 +4258,7 @@ rta_multipath_done:
          * 1 (lo). Of course it does!! */
         if (nh.found) {
             if (IS_IPv4) {
-                if (nh.ifindex != 0 || nh.gateway.addr4 != 0) {
+                if (nh.ifindex != 0 || nh.gateway.addr4 != 0 || nh.is_via) {
                     /* 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. */
@@ -4337,9 +4357,14 @@ rta_multipath_done:
     if (tb[RTA_PRIORITY])
         obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]);
 
-    if (IS_IPv4)
-        obj->ip4_route.gateway = nh.gateway.addr4;
-    else
+    if (IS_IPv4) {
+        if (nh.is_via) {
+            obj->ip4_route.via.addr_family = AF_INET6;
+            obj->ip4_route.via.addr        = nh.gateway;
+        } else {
+            obj->ip4_route.gateway = nh.gateway.addr4;
+        }
+    } else
         obj->ip6_route.gateway = nh.gateway.addr6;
 
     if (IS_IPv4)
@@ -5838,7 +5863,24 @@ _nl_msg_new_route(uint16_t nlmsg_type, uint16_t nlmsg_flags, const NMPObject *ob
 
     /* We currently don't have need for multi-hop routes... */
     if (IS_IPv4) {
-        NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip4_route.gateway);
+        if (obj->ip4_route.gateway == INADDR_ANY && obj->ip4_route.via.addr_family != AF_UNSPEC) {
+            struct rtvia *rtvia;
+
+            nm_assert(obj->ip4_route.via.addr_family == AF_INET6);
+
+            rtvia = nla_data(nla_reserve(
+                msg,
+                RTA_VIA,
+                sizeof(*rtvia) + nm_utils_addr_family_to_size(obj->ip4_route.via.addr_family)));
+            if (!rtvia)
+                goto nla_put_failure;
+            rtvia->rtvia_family = obj->ip4_route.via.addr_family;
+            memcpy(rtvia->rtvia_addr,
+                   obj->ip4_route.via.addr.addr_ptr,
+                   nm_utils_addr_family_to_size(obj->ip4_route.via.addr_family));
+        } else {
+            NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip4_route.gateway);
+        }
     } else {
         if (!IN6_IS_ADDR_UNSPECIFIED(&obj->ip6_route.gateway))
             NLA_PUT(msg, RTA_GATEWAY, addr_len, &obj->ip6_route.gateway);
diff --git a/src/libnm-platform/nm-platform.c b/src/libnm-platform/nm-platform.c
index 33c763c3..853157d2 100644
--- a/src/libnm-platform/nm-platform.c
+++ b/src/libnm-platform/nm-platform.c
@@ -7206,7 +7206,7 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route     *route,
 {
     char *buf0;
     char  s_network[INET_ADDRSTRLEN];
-    char  s_gateway[INET_ADDRSTRLEN];
+    char  s_gateway[INET6_ADDRSTRLEN];
     char  s_pref_src[INET_ADDRSTRLEN];
     char  str_dev[30];
     char  str_mss[32];
@@ -7235,10 +7235,13 @@ nm_platform_ip4_route_to_string_full(const NMPlatformIP4Route     *route,
 
     inet_ntop(AF_INET, &route->network, s_network, sizeof(s_network));
 
-    if (route->gateway == 0)
-        s_gateway[0] = '\0';
-    else
+    if (route->gateway != INADDR_ANY) {
         inet_ntop(AF_INET, &route->gateway, s_gateway, sizeof(s_gateway));
+    } else if (route->via.addr_family == AF_INET6) {
+        inet_ntop(AF_INET6, route->via.addr.addr_ptr, s_gateway, sizeof(s_gateway));
+    } else {
+        s_gateway[0] = '\0';
+    }
 
     nm_strbuf_append(
         &buf,
@@ -7979,7 +7982,8 @@ static NM_UTILS_FLAGS2STR_DEFINE(_mptcp_flags_to_string,
                                  NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_SIGNAL, "signal"),
                                  NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_SUBFLOW, "subflow"),
                                  NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_BACKUP, "backup"),
-                                 NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_FULLMESH, "fullmesh"));
+                                 NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_FULLMESH, "fullmesh"),
+                                 NM_UTILS_FLAGS2STR(NM_MPTCP_PM_ADDR_FLAG_LAMINAR, "laminar"));
 
 const char *
 nm_platform_mptcp_addr_to_string(const NMPlatformMptcpAddr *mptcp_addr, char *buf, gsize len)
@@ -8978,6 +8982,9 @@ nm_platform_ip4_route_hash_update(const NMPlatformIP4Route *obj,
                 nm_hash_update_vals(h,
                                     obj->ifindex,
                                     n_nexthops,
+                                    obj->via.addr_family,
+                                    obj->via.addr_family == AF_INET6 ? obj->via.addr.addr6
+                                                                     : in6addr_any,
                                     obj->gateway,
                                     _ip4_route_weight_normalize(n_nexthops, obj->weight, FALSE));
             }
@@ -9128,6 +9135,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
             if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_ID) {
                 NM_CMP_FIELD(a, b, ifindex);
                 NM_CMP_FIELD(a, b, gateway);
+                NM_CMP_FIELD(a, b, via.addr_family);
+                if (a->via.addr_family == AF_INET6) {
+                    NM_CMP_FIELD_IN6ADDR(a, b, via.addr.addr6);
+                }
                 n_nexthops = nm_platform_ip4_route_get_n_nexthops(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),
@@ -9153,6 +9164,10 @@ nm_platform_ip4_route_cmp(const NMPlatformIP4Route *a,
         NM_CMP_FIELD_UNSAFE(a, b, metric_any);
         NM_CMP_FIELD(a, b, metric);
         NM_CMP_FIELD(a, b, gateway);
+        NM_CMP_FIELD(a, b, via.addr_family);
+        if (a->via.addr_family == AF_INET6) {
+            NM_CMP_FIELD_IN6ADDR(a, b, via.addr.addr6);
+        }
         if (cmp_type == NM_PLATFORM_IP_ROUTE_CMP_TYPE_SEMANTICALLY) {
             n_nexthops = nm_platform_ip4_route_get_n_nexthops(a);
             NM_CMP_DIRECT(n_nexthops, nm_platform_ip4_route_get_n_nexthops(b));
diff --git a/src/libnm-platform/nm-platform.h b/src/libnm-platform/nm-platform.h
index a63f40c7..033dc515 100644
--- a/src/libnm-platform/nm-platform.h
+++ b/src/libnm-platform/nm-platform.h
@@ -46,6 +46,7 @@ typedef gboolean (*NMPObjectPredicateFunc)(const NMPObject *obj, gpointer user_d
 #define NM_MPTCP_PM_ADDR_FLAG_BACKUP   ((guint32) (1 << 2))
 #define NM_MPTCP_PM_ADDR_FLAG_FULLMESH ((guint32) (1 << 3))
 #define NM_MPTCP_PM_ADDR_FLAG_IMPLICIT ((guint32) (1 << 4))
+#define NM_MPTCP_PM_ADDR_FLAG_LAMINAR  ((guint32) (1 << 5))
 
 /* Redefine this in host's endianness */
 #define NM_GRE_KEY 0x2000
@@ -443,6 +444,12 @@ struct _NMPlatformIP4Route {
      * the first hop. */
     in_addr_t gateway;
 
+    /* RTA_VIA. Part of the primary key for a route. Allows a gateway for a
+     * route to exist in a different address family.
+     * Only valid if: n_nexthops == 1, gateway == 0, via.family != AF_UNSPEC
+     */
+    NMIPAddrTyped via;
+
     /* RTA_PREFSRC (called "src" by iproute2).
      *
      * pref_src is part of the ID of an IPv4 route. When deleting a route,
@@ -2406,6 +2413,14 @@ nm_platform_ip_route_get_gateway(int addr_family, const NMPlatformIPRoute *route
     return &((NMPlatformIP6Route *) route)->gateway;
 }
 
+static inline const NMIPAddrTyped *
+nm_platform_ip4_route_get_via(const NMPlatformIP4Route *route)
+{
+    nm_assert(route);
+
+    return &route->via;
+}
+
 static inline gconstpointer
 nm_platform_ip_route_get_pref_src(int addr_family, const NMPlatformIPRoute *route)
 {
diff --git a/src/libnm-platform/nmp-ethtool.c b/src/libnm-platform/nmp-ethtool.c
index ed028f6a..28d12ffb 100644
--- a/src/libnm-platform/nmp-ethtool.c
+++ b/src/libnm-platform/nmp-ethtool.c
@@ -153,7 +153,7 @@ ethtool_send_and_recv(struct nl_sock *sock,
 
 out:
     if (nle < 0 && err_msg && *err_msg == NULL)
-        *err_msg = strdup(nm_strerror(nle));
+        *err_msg = g_strdup(nm_strerror(nle));
 
     if (nle >= 0 && cb_result < 0)
         nle = cb_result;
diff --git a/src/libnm-platform/nmp-object.c b/src/libnm-platform/nmp-object.c
index e11bfb3f..56533c99 100644
--- a/src/libnm-platform/nmp-object.c
+++ b/src/libnm-platform/nmp-object.c
@@ -893,7 +893,7 @@ const NMPObject *
 nmp_object_stackinit_id_ip6_address(NMPObject *obj, int ifindex, const struct in6_addr *address)
 {
     _nmp_object_stackinit_from_type(obj, NMP_OBJECT_TYPE_IP6_ADDRESS);
-    obj->ip4_address.ifindex = ifindex;
+    obj->ip6_address.ifindex = ifindex;
     if (address)
         obj->ip6_address.address = *address;
     return obj;