summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2015-11-02 13:58:45 +0100
committerThomas Haller <thaller@redhat.com>2015-11-02 13:58:45 +0100
commit07c0a4952eb017e941e55fe601669818d73d021a (patch)
tree8ef49f079d9ea31383e6f5646cfdf2aa77514b22
parent1a6f4d08ba41f6f5a9d2bbd38c5155c7791642c1 (diff)
parent5feda42813ddf5d51adf51c4e95cea51748a48fd (diff)
downloadNetworkManager-07c0a4952eb017e941e55fe601669818d73d021a.tar.gz
platform: merge branch 'th/platform-parse-nl-bgo754570'
https://bugzilla.gnome.org/show_bug.cgi?id=754570
-rw-r--r--configure.ac32
-rw-r--r--docs/libnm/Makefile.am1
-rw-r--r--include/nm-macros-internal.h24
-rw-r--r--include/nm-test-utils.h86
-rw-r--r--libnm-core/Makefile.libnm-core1
-rw-r--r--libnm-core/nm-core-internal.h18
-rw-r--r--libnm-core/nm-core-types-internal.h30
-rw-r--r--libnm-core/nm-setting-vlan.c157
-rw-r--r--libnm/nm-manager.c5
-rw-r--r--libnm/nm-remote-settings.c5
-rw-r--r--src/NetworkManagerUtils.c141
-rw-r--r--src/NetworkManagerUtils.h22
-rw-r--r--src/devices/nm-device-gre.c29
-rw-r--r--src/devices/nm-device-infiniband.c2
-rw-r--r--src/devices/nm-device-macvlan.c24
-rw-r--r--src/devices/nm-device-veth.c7
-rw-r--r--src/devices/nm-device-vlan.c91
-rw-r--r--src/devices/nm-device-vxlan.c47
-rw-r--r--src/devices/nm-device.c89
-rw-r--r--src/devices/wwan/nm-modem-broadband.c1
-rw-r--r--src/dhcp-manager/nm-dhcp-dhclient-utils.c1
-rw-r--r--src/dhcp-manager/nm-dhcp-systemd.c1
-rw-r--r--src/dhcp-manager/nm-dhcp-utils.c14
-rw-r--r--src/dhcp-manager/tests/test-dhcp-dhclient.c2
-rw-r--r--src/dhcp-manager/tests/test-dhcp-utils.c2
-rw-r--r--src/dnsmasq-manager/tests/test-dnsmasq-utils.c35
-rw-r--r--src/nm-default-route-manager.c14
-rw-r--r--src/nm-iface-helper.c11
-rw-r--r--src/nm-ip4-config.c71
-rw-r--r--src/nm-ip4-config.h1
-rw-r--r--src/nm-ip6-config.c4
-rw-r--r--src/nm-route-manager.c22
-rw-r--r--src/nm-types.h9
-rw-r--r--src/platform/nm-fake-platform.c205
-rw-r--r--src/platform/nm-linux-platform.c4653
-rw-r--r--src/platform/nm-platform.c985
-rw-r--r--src/platform/nm-platform.h185
-rw-r--r--src/platform/nmp-object.c496
-rw-r--r--src/platform/nmp-object.h71
-rw-r--r--src/platform/tests/Makefile.am4
-rw-r--r--src/platform/tests/dump.c137
-rw-r--r--src/platform/tests/monitor.c22
-rw-r--r--src/platform/tests/platform.c132
-rw-r--r--src/platform/tests/test-address.c81
-rw-r--r--src/platform/tests/test-cleanup.c2
-rw-r--r--src/platform/tests/test-common.c153
-rw-r--r--src/platform/tests/test-common.h8
-rw-r--r--src/platform/tests/test-general.c32
-rw-r--r--src/platform/tests/test-link.c806
-rw-r--r--src/platform/wifi/wifi-utils-nl80211.c246
-rw-r--r--src/ppp-manager/nm-ppp-manager.c9
-rw-r--r--src/tests/test-general.c112
-rw-r--r--src/tests/test-ip4-config.c4
-rw-r--r--src/tests/test-ip6-config.c4
-rw-r--r--src/tests/test-route-manager.c6
-rw-r--r--src/vpn-manager/nm-vpn-connection.c2
56 files changed, 5947 insertions, 3407 deletions
diff --git a/configure.ac b/configure.ac
index 57d3210018..c8e7913a48 100644
--- a/configure.ac
+++ b/configure.ac
@@ -526,37 +526,7 @@ fi
AC_SUBST(NM_CONFIG_DEFAULT_LOGGING_AUDIT_TEXT)
# libnl support for the linux platform
-PKG_CHECK_MODULES(LIBNL, libnl-3.0 >= 3.2.8 libnl-route-3.0 libnl-genl-3.0)
-
-AC_CHECK_LIB([nl-route-3], [rtnl_link_inet6_get_addr_gen_mode],
- ac_have_addr_gen_mode="1",
- ac_have_addr_gen_mode="0")
-AC_DEFINE_UNQUOTED(HAVE_LIBNL_INET6_ADDR_GEN_MODE,
- $ac_have_addr_gen_mode, [Define if libnl has rtnl_link_inet6_get_addr_gen_mode()])
-
-AC_MSG_CHECKING([Linux kernel IN6_ADDR_GEN_MODE enum])
-AC_COMPILE_IFELSE(
- [AC_LANG_PROGRAM(
- [[#ifndef __user
- #define __user
- #endif
- #include <linux/if_link.h>]],
- [[int a = IN6_ADDR_GEN_MODE_EUI64; a++;]])],
- [ac_have_kernel_gen_mode=yes],
- [ac_have_kernel_gen_mode=no])
-AC_MSG_RESULT($ac_have_kernel_gen_mode)
-if test "$ac_have_kernel_gen_mode" = yes; then
- AC_DEFINE(HAVE_KERNEL_INET6_ADDR_GEN_MODE, 1, [Define if the kernel has IN6_ADDR_GEN_MODE_*])
-else
- AC_DEFINE(HAVE_KERNEL_INET6_ADDR_GEN_MODE, 0, [Define if the kernel has IN6_ADDR_GEN_MODE_*])
-fi
-
-# IPv6 tokenized identifiers support in libnl
-AC_CHECK_LIB([nl-route-3], [rtnl_link_inet6_get_token],
- ac_have_ipv6_token="1",
- ac_have_ipv6_token="0")
-AC_DEFINE_UNQUOTED(HAVE_LIBNL_INET6_TOKEN,
- $ac_have_ipv6_token, [Define if libnl has rtnl_link_inet6_get_token()])
+PKG_CHECK_MODULES(LIBNL, libnl-3.0 >= 3.2.8)
# uuid library
PKG_CHECK_MODULES(UUID, uuid)
diff --git a/docs/libnm/Makefile.am b/docs/libnm/Makefile.am
index 23631ddc24..5b96d5aaa2 100644
--- a/docs/libnm/Makefile.am
+++ b/docs/libnm/Makefile.am
@@ -39,6 +39,7 @@ IGNORE_HFILES= \
nm-dbus-helpers.h \
nm-core-internal.h \
nm-core-types.h \
+ nm-core-types-internal.h \
nm-device-private.h \
nm-dhcp4-config.h \
nm-dhcp6-config.h \
diff --git a/include/nm-macros-internal.h b/include/nm-macros-internal.h
index 5c1d61dbaf..95d6bbaa71 100644
--- a/include/nm-macros-internal.h
+++ b/include/nm-macros-internal.h
@@ -229,6 +229,18 @@ nm_clear_g_variant (GVariant **variant)
return FALSE;
}
+static inline gboolean
+nm_clear_g_cancellable (GCancellable **cancellable)
+{
+ if (cancellable && *cancellable) {
+ g_cancellable_cancel (*cancellable);
+ g_object_unref (*cancellable);
+ *cancellable = NULL;
+ return TRUE;
+ }
+ return FALSE;
+}
+
/*****************************************************************************/
/* Determine whether @x is a power of two (@x being an integer type).
@@ -316,6 +328,18 @@ nm_decode_version (guint version, guint *major, guint *minor, guint *micro) {
*minor = (version & 0x0000FF00u) >> 8;
*micro = (version & 0x000000FFu);
}
+/*****************************************************************************/
+
+#define nm_sprintf_buf(buf, format, ...) ({ \
+ char * _buf = (buf); \
+ \
+ /* some static assert trying to ensure that the buffer is statically allocated.
+ * It disallows a buffer size of sizeof(gpointer) to catch that. */ \
+ G_STATIC_ASSERT (G_N_ELEMENTS (buf) == sizeof (buf) && sizeof (buf) != sizeof (char *)); \
+ g_snprintf (_buf, sizeof (buf), \
+ ""format"", __VA_ARGS__); \
+ _buf; \
+ })
/*****************************************************************************/
diff --git a/include/nm-test-utils.h b/include/nm-test-utils.h
index fa795b5a99..9f40be9c12 100644
--- a/include/nm-test-utils.h
+++ b/include/nm-test-utils.h
@@ -400,6 +400,8 @@ __nmtst_init (int *argc, char ***argv, gboolean assert_logging, const char *log_
*out_set_logging = TRUE;
#endif
g_assert (success);
+ if (__nmtst_internal.no_expect_message)
+ g_log_set_always_fatal (G_LOG_FATAL_MASK);
} else if (__nmtst_internal.no_expect_message) {
/* We have a test that would be assert_logging, but the user specified no_expect_message.
* This transforms g_test_expect_message() into a NOP, but we also have to relax
@@ -583,6 +585,47 @@ nmtst_get_rand_int (void)
return g_rand_int (nmtst_get_rand ());
}
+inline static void *
+nmtst_rand_perm (GRand *rand, void *dst, const void *src, gsize elmt_size, gsize n_elmt)
+{
+ gsize i, j;
+ char *p_, *pj;
+ char *bu;
+
+ g_assert (dst);
+ g_assert (elmt_size > 0);
+ g_assert (n_elmt < G_MAXINT32);
+
+ if (n_elmt == 0)
+ return dst;
+
+ if (src && dst != src)
+ memcpy (dst, src, elmt_size * n_elmt);
+
+ if (!rand)
+ rand = nmtst_get_rand ();
+
+ bu = g_slice_alloc (elmt_size);
+
+ p_ = dst;
+ for (i = n_elmt; i > 1; i--) {
+ j = g_rand_int_range (rand, 0, i);
+
+ if (j != 0) {
+ pj = &p_[j * elmt_size];
+
+ /* swap */
+ memcpy (bu, p_, elmt_size);
+ memcpy (p_, pj, elmt_size);
+ memcpy (pj, bu, elmt_size);
+ }
+ p_ += elmt_size;
+ }
+
+ g_slice_free1 (elmt_size, bu);
+ return dst;
+}
+
inline static const char *
nmtst_get_sudo_cmd (void)
{
@@ -689,6 +732,37 @@ nmtst_inet6_from_string (const char *str)
}
inline static void
+_nmtst_assert_ip4_address (const char *file, int line, in_addr_t addr, const char *str_expected)
+{
+ if (nmtst_inet4_from_string (str_expected) != addr) {
+ char buf[100];
+
+ g_error ("%s:%d: Unexpected IPv4 address: expected %s, got %s",
+ file, line, str_expected ? str_expected : "0.0.0.0",
+ inet_ntop (AF_INET, &addr, buf, sizeof (buf)));
+ }
+}
+#define nmtst_assert_ip4_address(addr, str_expected) _nmtst_assert_ip4_address (__FILE__, __LINE__, addr, str_expected)
+
+inline static void
+_nmtst_assert_ip6_address (const char *file, int line, const struct in6_addr *addr, const char *str_expected)
+{
+ struct in6_addr any = in6addr_any;
+
+ if (!addr)
+ addr = &any;
+
+ if (memcmp (nmtst_inet6_from_string (str_expected), addr, sizeof (*addr)) != 0) {
+ char buf[100];
+
+ g_error ("%s:%d: Unexpected IPv6 address: expected %s, got %s",
+ file, line, str_expected ? str_expected : "::",
+ inet_ntop (AF_INET6, &addr, buf, sizeof (buf)));
+ }
+}
+#define nmtst_assert_ip6_address(addr, str_expected) _nmtst_assert_ip6_address (__FILE__, __LINE__, addr, str_expected)
+
+inline static void
FAIL(const char *test_name, const char *fmt, ...)
{
va_list args;
@@ -909,9 +983,11 @@ nmtst_platform_ip4_routes_equal (const NMPlatformIP4Route *a, const NMPlatformIP
for (i = 0; i < len; i++) {
if (nm_platform_ip4_route_cmp (&a[i], &b[i]) != 0) {
+ char buf[sizeof (_nm_utils_to_string_buffer)];
+
g_error ("Error comparing IPv4 route[%lu]: %s vs %s", (long unsigned) i,
- nmtst_static_1024_01 (nm_platform_ip4_route_to_string (&a[i])),
- nmtst_static_1024_02 (nm_platform_ip4_route_to_string (&b[i])));
+ nm_platform_ip4_route_to_string (&a[i], NULL, 0),
+ nm_platform_ip4_route_to_string (&b[i], buf, sizeof (buf)));
g_assert_not_reached ();
}
}
@@ -941,9 +1017,11 @@ nmtst_platform_ip6_routes_equal (const NMPlatformIP6Route *a, const NMPlatformIP
for (i = 0; i < len; i++) {
if (nm_platform_ip6_route_cmp (&a[i], &b[i]) != 0) {
+ char buf[sizeof (_nm_utils_to_string_buffer)];
+
g_error ("Error comparing IPv6 route[%lu]: %s vs %s", (long unsigned) i,
- nmtst_static_1024_01 (nm_platform_ip6_route_to_string (&a[i])),
- nmtst_static_1024_02 (nm_platform_ip6_route_to_string (&b[i])));
+ nm_platform_ip6_route_to_string (&a[i], NULL, 0),
+ nm_platform_ip6_route_to_string (&b[i], buf, sizeof (buf)));
g_assert_not_reached ();
}
}
diff --git a/libnm-core/Makefile.libnm-core b/libnm-core/Makefile.libnm-core
index b5e205acef..fb201bdbad 100644
--- a/libnm-core/Makefile.libnm-core
+++ b/libnm-core/Makefile.libnm-core
@@ -51,6 +51,7 @@ libnm_core_private_headers = \
$(core)/crypto.h \
$(core)/nm-connection-private.h \
$(core)/nm-core-internal.h \
+ $(core)/nm-core-types-internal.h \
$(core)/nm-keyfile-internal.h \
$(core)/nm-keyfile-utils.h \
$(core)/nm-property-compare.h \
diff --git a/libnm-core/nm-core-internal.h b/libnm-core/nm-core-internal.h
index 26c30b8a87..4c95d0d0a7 100644
--- a/libnm-core/nm-core-internal.h
+++ b/libnm-core/nm-core-internal.h
@@ -67,12 +67,7 @@
#include "nm-simple-connection.h"
#include "nm-utils.h"
#include "nm-vpn-dbus-interface.h"
-
-#define NM_UTILS_CLEAR_CANCELLABLE(c) \
- if (c) { \
- g_cancellable_cancel (c); \
- g_clear_object (&c); \
- }
+#include "nm-core-types-internal.h"
/* NM_SETTING_COMPARE_FLAG_INFERRABLE: check whether a device-generated
* connection can be replaced by a already-defined connection. This flag only
@@ -256,4 +251,15 @@ NMUtilsStrStrDictKey *_nm_utils_strstrdictkey_create (const char *v1, const char
/***********************************************************/
+gboolean _nm_setting_vlan_set_priorities (NMSettingVlan *setting,
+ NMVlanPriorityMap map,
+ const NMVlanQosMapping *qos_map,
+ guint n_qos_map);
+void _nm_setting_vlan_get_priorities (NMSettingVlan *setting,
+ NMVlanPriorityMap map,
+ NMVlanQosMapping **out_qos_map,
+ guint *out_n_qos_map);
+
+/***********************************************************/
+
#endif
diff --git a/libnm-core/nm-core-types-internal.h b/libnm-core/nm-core-types-internal.h
new file mode 100644
index 0000000000..442a10a30f
--- /dev/null
+++ b/libnm-core/nm-core-types-internal.h
@@ -0,0 +1,30 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+
+/*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301 USA.
+ *
+ * (C) Copyright 2015 Red Hat, Inc.
+ */
+
+#ifndef NM_CORE_TYPES_INTERNAL_H
+#define NM_CORE_TYPES_INTERNAL_H
+
+typedef struct {
+ guint32 from;
+ guint32 to;
+} NMVlanQosMapping;
+
+#endif /* NM_CORE_TYPES_INTERNAL_H */
diff --git a/libnm-core/nm-setting-vlan.c b/libnm-core/nm-setting-vlan.c
index 66661ec613..8428a36904 100644
--- a/libnm-core/nm-setting-vlan.c
+++ b/libnm-core/nm-setting-vlan.c
@@ -25,7 +25,10 @@
#include <string.h>
#include "nm-setting-vlan.h"
+#include "nm-default.h"
+#include "nm-macros-internal.h"
#include "nm-utils.h"
+#include "nm-core-types-internal.h"
#include "nm-setting-connection.h"
#include "nm-setting-private.h"
#include "nm-setting-wired.h"
@@ -66,11 +69,6 @@ enum {
#define MAX_SKB_PRIO G_MAXUINT32
#define MAX_8021P_PRIO 7 /* Max 802.1p priority */
-typedef struct {
- guint32 from;
- guint32 to;
-} PriorityMap;
-
/**
* nm_setting_vlan_new:
*
@@ -133,10 +131,10 @@ get_max_prio (NMVlanPriorityMap map, gboolean from)
g_assert_not_reached ();
}
-static PriorityMap *
+static NMVlanQosMapping *
priority_map_new_from_str (NMVlanPriorityMap map, const char *str)
{
- PriorityMap *p = NULL;
+ NMVlanQosMapping *p = NULL;
gchar **t = NULL;
guint32 len;
guint64 from, to;
@@ -150,7 +148,7 @@ priority_map_new_from_str (NMVlanPriorityMap map, const char *str)
to = g_ascii_strtoull (t[1], NULL, 10);
if ((from <= get_max_prio (map, TRUE)) && (to <= get_max_prio (map, FALSE))) {
- p = g_malloc0 (sizeof (PriorityMap));
+ p = g_malloc0 (sizeof (NMVlanQosMapping));
p->from = from;
p->to = to;
}
@@ -164,7 +162,7 @@ priority_map_new_from_str (NMVlanPriorityMap map, const char *str)
}
static void
-priority_map_free (PriorityMap *map)
+priority_map_free (NMVlanQosMapping *map)
{
g_return_if_fail (map != NULL);
g_free (map);
@@ -182,8 +180,11 @@ get_map (NMSettingVlan *self, NMVlanPriorityMap map)
}
static gint
-prio_map_compare (PriorityMap *a, PriorityMap *b)
+prio_map_compare (gconstpointer p_a, gconstpointer p_b)
{
+ const NMVlanQosMapping *a = p_a;
+ const NMVlanQosMapping *b = p_b;
+
return a->from < b->from
? -1
: (a->from > b->from
@@ -194,11 +195,27 @@ prio_map_compare (PriorityMap *a, PriorityMap *b)
static void
set_map (NMSettingVlan *self, NMVlanPriorityMap map, GSList *list)
{
- /* Sort the list.
- * First, it looks better. Second, it assures that comparing lists works
- * as expected.
- */
- list = g_slist_sort (list, (GCompareFunc) prio_map_compare);
+ /* Assert that the list is sorted */
+#if NM_MORE_ASSERTS >= 2
+ {
+ GSList *iter, *last;
+
+ last = list;
+ iter = list ? list->next : NULL;
+ while (iter) {
+ const NMVlanQosMapping *l = last->data;
+ const NMVlanQosMapping *m = iter->data;
+
+ nm_assert (prio_map_compare (last->data, iter->data) < 0);
+
+ /* Also reject duplicates (based on "from") */
+ nm_assert (l->from < m->from);
+
+ last = iter;
+ iter = iter->next;
+ }
+ }
+#endif
if (map == NM_VLAN_INGRESS_MAP) {
NM_SETTING_VLAN_GET_PRIVATE (self)->ingress_priority_map = list;
@@ -214,7 +231,7 @@ static gboolean
check_replace_duplicate_priority (GSList *list, guint32 from, guint32 to)
{
GSList *iter;
- PriorityMap *p;
+ NMVlanQosMapping *p;
for (iter = list; iter; iter = g_slist_next (iter)) {
p = iter->data;
@@ -245,7 +262,7 @@ nm_setting_vlan_add_priority_str (NMSettingVlan *setting,
const char *str)
{
GSList *list = NULL;
- PriorityMap *item = NULL;
+ NMVlanQosMapping *item = NULL;
g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE);
g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE);
@@ -267,7 +284,7 @@ nm_setting_vlan_add_priority_str (NMSettingVlan *setting,
return TRUE;
}
- set_map (setting, map, g_slist_append (list, item));
+ set_map (setting, map, g_slist_insert_sorted (list, item, prio_map_compare));
return TRUE;
}
@@ -312,7 +329,7 @@ nm_setting_vlan_get_priority (NMSettingVlan *setting,
guint32 *out_to)
{
GSList *list = NULL;
- PriorityMap *item = NULL;
+ NMVlanQosMapping *item = NULL;
g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE);
g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE);
@@ -357,7 +374,7 @@ nm_setting_vlan_add_priority (NMSettingVlan *setting,
guint32 to)
{
GSList *list = NULL;
- PriorityMap *item;
+ NMVlanQosMapping *item;
g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE);
g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE);
@@ -371,14 +388,96 @@ nm_setting_vlan_add_priority (NMSettingVlan *setting,
return TRUE;
}
- item = g_malloc0 (sizeof (PriorityMap));
+ item = g_malloc0 (sizeof (NMVlanQosMapping));
item->from = from;
item->to = to;
- set_map (setting, map, g_slist_append (list, item));
+ set_map (setting, map, g_slist_insert_sorted (list, item, prio_map_compare));
return TRUE;
}
+gboolean
+_nm_setting_vlan_set_priorities (NMSettingVlan *setting,
+ NMVlanPriorityMap map,
+ const NMVlanQosMapping *qos_map,
+ guint n_qos_map)
+{
+ gboolean has_changes = FALSE;
+ GSList *map_prev, *map_new;
+ guint i;
+ gint64 from_last;
+
+ map_prev = get_map (setting, map);
+
+ if (n_qos_map != g_slist_length (map_prev))
+ has_changes = TRUE;
+ else {
+ const GSList *iter;
+
+ iter = map_prev;
+ for (i = 0; i < n_qos_map; i++, iter = iter->next) {
+ const NMVlanQosMapping *m = iter->data;
+
+ if ( m->from != qos_map[i].from
+ || m->to != qos_map[i].to) {
+ has_changes = TRUE;
+ break;
+ }
+ }
+ }
+
+ if (!has_changes)
+ return FALSE;
+
+ map_new = NULL;
+ from_last = G_MAXINT64;
+ for (i = n_qos_map; i > 0;) {
+ const NMVlanQosMapping *m = &qos_map[--i];
+ NMVlanQosMapping *item;
+
+ /* We require the array to be presorted. */
+ if (m->from >= from_last)
+ g_return_val_if_reached (FALSE);
+ from_last = m->from;
+
+ item = g_malloc0 (sizeof (NMVlanQosMapping));
+ item->from = m->from;
+ item->to = m->to;
+ map_new = g_slist_prepend (map_new, item);
+ }
+
+ g_slist_free_full (map_prev, g_free);
+ set_map (setting, map, map_new);
+
+ return TRUE;
+}
+
+void
+_nm_setting_vlan_get_priorities (NMSettingVlan *setting,
+ NMVlanPriorityMap map,
+ NMVlanQosMapping **out_qos_map,
+ guint *out_n_qos_map)
+{
+ GSList *list;
+ NMVlanQosMapping *qos_map = NULL;
+ guint n_qos_map, i;
+
+ list = get_map (setting, map);
+
+ n_qos_map = g_slist_length (list);
+
+ if (n_qos_map > 0) {
+ qos_map = g_new (NMVlanQosMapping, n_qos_map);
+
+ for (i = 0; list; i++, list = list->next) {
+ nm_assert (i < n_qos_map);
+ qos_map[i] = *((const NMVlanQosMapping *) list->data);
+ }
+ }
+ *out_qos_map = qos_map;
+ *out_n_qos_map = n_qos_map;
+}
+
/**
* nm_setting_vlan_remove_priority:
* @setting: the #NMSettingVlan
@@ -403,7 +502,7 @@ nm_setting_vlan_remove_priority (NMSettingVlan *setting,
g_return_if_fail (idx < g_slist_length (list));
item = g_slist_nth (list, idx);
- priority_map_free ((PriorityMap *) (item->data));
+ priority_map_free ((NMVlanQosMapping *) (item->data));
set_map (setting, map, g_slist_delete_link (list, item));
}
@@ -427,7 +526,7 @@ nm_setting_vlan_remove_priority_by_value (NMSettingVlan *setting,
guint32 to)
{
GSList *list = NULL, *iter = NULL;
- PriorityMap *item;
+ NMVlanQosMapping *item;
g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE);
g_return_val_if_fail (map == NM_VLAN_INGRESS_MAP || map == NM_VLAN_EGRESS_MAP, FALSE);
@@ -436,7 +535,7 @@ nm_setting_vlan_remove_priority_by_value (NMSettingVlan *setting,
for (iter = list; iter; iter = g_slist_next (iter)) {
item = iter->data;
if (item->from == from && item->to == to) {
- priority_map_free ((PriorityMap *) (iter->data));
+ priority_map_free ((NMVlanQosMapping *) (iter->data));
set_map (setting, map, g_slist_delete_link (list, iter));
return TRUE;
}
@@ -461,7 +560,7 @@ nm_setting_vlan_remove_priority_str_by_value (NMSettingVlan *setting,
NMVlanPriorityMap map,
const char *str)
{
- PriorityMap *item;
+ NMVlanQosMapping *item;
gboolean found;
g_return_val_if_fail (NM_IS_SETTING_VLAN (setting), FALSE);
@@ -604,7 +703,7 @@ priority_strv_to_maplist (NMVlanPriorityMap map, char **strv)
int i;
for (i = 0; strv && strv[i]; i++) {
- PriorityMap *item;
+ NMVlanQosMapping *item;
item = priority_map_new_from_str (map, strv[i]);
if (item) {
@@ -612,7 +711,7 @@ priority_strv_to_maplist (NMVlanPriorityMap map, char **strv)
list = g_slist_prepend (list, item);
}
}
- return g_slist_sort (list, (GCompareFunc) prio_map_compare);
+ return g_slist_sort (list, prio_map_compare);
}
static void
@@ -658,7 +757,7 @@ priority_maplist_to_strv (GSList *list)
strv = g_ptr_array_new ();
for (iter = list; iter; iter = g_slist_next (iter)) {
- PriorityMap *item = iter->data;
+ NMVlanQosMapping *item = iter->data;
g_ptr_array_add (strv, g_strdup_printf ("%d:%d", item->from, item->to));
}
diff --git a/libnm/nm-manager.c b/libnm/nm-manager.c
index c0d026291a..7ed50e3ced 100644
--- a/libnm/nm-manager.c
+++ b/libnm/nm-manager.c
@@ -35,6 +35,7 @@
#include "nm-vpn-connection.h"
#include "nm-object-cache.h"
#include "nm-dbus-helpers.h"
+#include "nm-macros-internal.h"
#include "nmdbus-manager.h"
@@ -1255,7 +1256,7 @@ nm_running_changed_cb (GObject *object,
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
if (!nm_manager_get_nm_running (manager)) {
- NM_UTILS_CLEAR_CANCELLABLE (priv->props_cancellable);
+ nm_clear_g_cancellable (&priv->props_cancellable);
priv->state = NM_STATE_UNKNOWN;
priv->startup = FALSE;
@@ -1281,7 +1282,7 @@ nm_running_changed_cb (GObject *object,
} else {
_nm_object_suppress_property_updates (NM_OBJECT (manager), FALSE);
- NM_UTILS_CLEAR_CANCELLABLE (priv->props_cancellable);
+ nm_clear_g_cancellable (&priv->props_cancellable);
priv->props_cancellable = g_cancellable_new ();
_nm_object_reload_properties_async (NM_OBJECT (manager), priv->props_cancellable, updated_properties, manager);
diff --git a/libnm/nm-remote-settings.c b/libnm/nm-remote-settings.c
index 4d240e3b38..480d7c19f5 100644
--- a/libnm/nm-remote-settings.c
+++ b/libnm/nm-remote-settings.c
@@ -34,6 +34,7 @@
#include "nm-dbus-helpers.h"
#include "nm-object-private.h"
#include "nm-core-internal.h"
+#include "nm-macros-internal.h"
#include "nmdbus-settings.h"
@@ -626,7 +627,7 @@ nm_running_changed (GObject *object,
GPtrArray *connections;
int i;
- NM_UTILS_CLEAR_CANCELLABLE (priv->props_cancellable);
+ nm_clear_g_cancellable (&priv->props_cancellable);
/* Clear connections */
connections = priv->all_connections;
@@ -651,7 +652,7 @@ nm_running_changed (GObject *object,
} else {
_nm_object_suppress_property_updates (NM_OBJECT (self), FALSE);
- NM_UTILS_CLEAR_CANCELLABLE (priv->props_cancellable);
+ nm_clear_g_cancellable (&priv->props_cancellable);
priv->props_cancellable = g_cancellable_new ();
_nm_object_reload_properties_async (NM_OBJECT (self), priv->props_cancellable, updated_properties, self);
}
diff --git a/src/NetworkManagerUtils.c b/src/NetworkManagerUtils.c
index 726ceb9b4a..deab2a5869 100644
--- a/src/NetworkManagerUtils.c
+++ b/src/NetworkManagerUtils.c
@@ -1725,6 +1725,147 @@ nm_match_spec_join (GSList *specs)
return g_string_free (str, FALSE);
}
+/*****************************************************************************/
+
+char _nm_utils_to_string_buffer[];
+
+void
+nm_utils_to_string_buffer_init (char **buf, gsize *len)
+{
+ if (!*buf) {
+ *buf = _nm_utils_to_string_buffer;
+ *len = sizeof (_nm_utils_to_string_buffer);
+ }
+}
+
+gboolean
+nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len)
+{
+ nm_utils_to_string_buffer_init (buf, len);
+ if (!obj) {
+ g_strlcpy (*buf, "(null)", *len);
+ return FALSE;
+ }
+ return TRUE;
+}
+
+void
+nm_utils_strbuf_append_c (char **buf, gsize *len, char c)
+{
+ switch (*len) {
+ case 0:
+ return;
+ case 1:
+ (*buf)[0] = '\0';
+ *len = 0;
+ (*buf)++;
+ return;
+ default:
+ (*buf)[0] = c;
+ (*buf)[1] = '\0';
+ (*len)--;
+ (*buf)++;
+ return;
+ }
+}
+
+void
+nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str)
+{
+ gsize src_len;
+
+ switch (*len) {
+ case 0:
+ return;
+ case 1:
+ if (!str || !*str) {
+ (*buf)[0] = '\0';
+ return;
+ }
+ (*buf)[0] = '\0';
+ *len = 0;
+ (*buf)++;
+ return;
+ default:
+ if (!str || !*str) {
+ (*buf)[0] = '\0';
+ return;
+ }
+ src_len = g_strlcpy (*buf, str, *len);
+ if (src_len >= *len) {
+ *buf = &(*buf)[*len];
+ *len = 0;
+ } else {
+ *buf = &(*buf)[src_len];
+ *len -= src_len;
+ }
+ return;
+ }
+}
+
+void
+nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...)
+{
+ char *p = *buf;
+ va_list args;
+ gint retval;
+
+ if (*len == 0)
+ return;
+
+ va_start (args, format);
+ retval = g_vsnprintf (p, *len, format, args);
+ va_end (args);
+
+ if (retval >= *len) {
+ *buf = &p[*len];
+ *len = 0;
+ } else {
+ *buf = &p[retval];
+ *len -= retval;
+ }
+}
+
+const char *
+nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs,
+ gsize n_descs,
+ unsigned flags,
+ char *buf,
+ gsize len)
+{
+ gsize i;
+ char *p;
+
+ nm_utils_to_string_buffer_init (&buf, &len);
+
+ if (!len)
+ return buf;
+
+ buf[0] = '\0';
+ if (!flags) {
+ return buf;
+ }
+
+ p = buf;
+ for (i = 0; flags && i < n_descs; i++) {
+ if (NM_FLAGS_HAS (flags, descs[i].flag)) {
+ flags &= ~descs[i].flag;
+
+ if (buf[0] != '\0')
+ nm_utils_strbuf_append_c (&p, &len, ',');
+ nm_utils_strbuf_append_str (&p, &len, descs[i].name);
+ }
+ }
+ if (flags) {
+ if (buf[0] != '\0')
+ nm_utils_strbuf_append_c (&p, &len, ',');
+ nm_utils_strbuf_append (&p, &len, "0x%x", flags);
+ }
+ return buf;
+};
+
+/*****************************************************************************/
+
/**
* nm_utils_get_shared_wifi_permission:
* @connection: the NMConnection to lookup the permission.
diff --git a/src/NetworkManagerUtils.h b/src/NetworkManagerUtils.h
index bf90e741cd..3da2235559 100644
--- a/src/NetworkManagerUtils.h
+++ b/src/NetworkManagerUtils.h
@@ -191,6 +191,28 @@ NMMatchSpecMatchType nm_match_spec_match_config (const GSList *specs, guint nm_v
GSList *nm_match_spec_split (const char *value);
char *nm_match_spec_join (GSList *specs);
+extern char _nm_utils_to_string_buffer[2096];
+
+void nm_utils_to_string_buffer_init (char **buf, gsize *len);
+gboolean nm_utils_to_string_buffer_init_null (gconstpointer obj, char **buf, gsize *len);
+
+typedef struct {
+ unsigned flag;
+ const char *name;
+} NMUtilsFlags2StrDesc;
+
+#define NM_UTILS_FLAGS2STR(f, n) { .flag = f, .name = ""n, }
+
+const char *nm_utils_flags2str (const NMUtilsFlags2StrDesc *descs,
+ gsize n_descs,
+ unsigned flags,
+ char *buf,
+ gsize len);
+
+void nm_utils_strbuf_append (char **buf, gsize *len, const char *format, ...) __attribute__((__format__ (__printf__, 3, 4)));
+void nm_utils_strbuf_append_c (char **buf, gsize *len, char c);
+void nm_utils_strbuf_append_str (char **buf, gsize *len, const char *str);
+
const char *nm_utils_get_shared_wifi_permission (NMConnection *connection);
const char *nm_utils_get_ip_config_method (NMConnection *connection,
diff --git a/src/devices/nm-device-gre.c b/src/devices/nm-device-gre.c
index ddd913b586..9b9ffc9be1 100644
--- a/src/devices/nm-device-gre.c
+++ b/src/devices/nm-device-gre.c
@@ -41,7 +41,7 @@ G_DEFINE_TYPE (NMDeviceGre, nm_device_gre, NM_TYPE_DEVICE_GENERIC)
#define NM_DEVICE_GRE_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_GRE, NMDeviceGrePrivate))
typedef struct {
- NMPlatformGreProperties props;
+ NMPlatformLnkGre props;
} NMDeviceGrePrivate;
enum {
@@ -68,37 +68,38 @@ update_properties (NMDevice *device)
NMDeviceGre *self = NM_DEVICE_GRE (device);
NMDeviceGrePrivate *priv = NM_DEVICE_GRE_GET_PRIVATE (self);
GObject *object = G_OBJECT (device);
- NMPlatformGreProperties props;
+ const NMPlatformLnkGre *props;
- if (!nm_platform_gre_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
+ props = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
+ if (!props) {
_LOGW (LOGD_HW, "could not read gre properties");
return;
}
g_object_freeze_notify (object);
- if (priv->props.parent_ifindex != props.parent_ifindex)
+ if (priv->props.parent_ifindex != props->parent_ifindex)
g_object_notify (object, NM_DEVICE_GRE_PARENT);
- if (priv->props.input_flags != props.input_flags)
+ if (priv->props.input_flags != props->input_flags)
g_object_notify (object, NM_DEVICE_GRE_INPUT_FLAGS);
- if (priv->props.output_flags != props.output_flags)
+ if (priv->props.output_flags != props->output_flags)
g_object_notify (object, NM_DEVICE_GRE_OUTPUT_FLAGS);
- if (priv->props.input_key != props.input_key)
+ if (priv->props.input_key != props->input_key)
g_object_notify (object, NM_DEVICE_GRE_INPUT_KEY);
- if (priv->props.output_key != props.output_key)
+ if (priv->props.output_key != props->output_key)
g_object_notify (object, NM_DEVICE_GRE_OUTPUT_KEY);
- if (priv->props.local != props.local)
+ if (priv->props.local != props->local)
g_object_notify (object, NM_DEVICE_GRE_LOCAL);
- if (priv->props.remote != props.remote)
+ if (priv->props.remote != props->remote)
g_object_notify (object, NM_DEVICE_GRE_REMOTE);
- if (priv->props.ttl != props.ttl)
+ if (priv->props.ttl != props->ttl)
g_object_notify (object, NM_DEVICE_GRE_TTL);
- if (priv->props.tos != props.tos)
+ if (priv->props.tos != props->tos)
g_object_notify (object, NM_DEVICE_GRE_TOS);
- if (priv->props.path_mtu_discovery != props.path_mtu_discovery)
+ if (priv->props.path_mtu_discovery != props->path_mtu_discovery)
g_object_notify (object, NM_DEVICE_GRE_PATH_MTU_DISCOVERY);
- memcpy (&priv->props, &props, sizeof (NMPlatformGreProperties));
+ priv->props = *props;
g_object_thaw_notify (object);
}
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c
index 05bf0323af..a647245f63 100644
--- a/src/devices/nm-device-infiniband.c
+++ b/src/devices/nm-device-infiniband.c
@@ -226,7 +226,7 @@ update_connection (NMDevice *device, NMConnection *connection)
ifindex = nm_device_get_ifindex (device);
if (ifindex > 0) {
- if (!nm_platform_infiniband_get_info (NM_PLATFORM_GET, ifindex, NULL, NULL, &transport_mode))
+ if (!nm_platform_infiniband_get_properties (NM_PLATFORM_GET, ifindex, NULL, NULL, &transport_mode))
transport_mode = "datagram";
}
g_object_set (G_OBJECT (s_infiniband), NM_SETTING_INFINIBAND_TRANSPORT_MODE, transport_mode, NULL);
diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c
index 26ea0be9b7..e2dd891c1a 100644
--- a/src/devices/nm-device-macvlan.c
+++ b/src/devices/nm-device-macvlan.c
@@ -39,7 +39,8 @@ G_DEFINE_TYPE (NMDeviceMacvlan, nm_device_macvlan, NM_TYPE_DEVICE_GENERIC)
#define NM_DEVICE_MACVLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_MACVLAN, NMDeviceMacvlanPrivate))
typedef struct {
- NMPlatformMacvlanProperties props;
+ int parent_ifindex;
+ NMPlatformLnkMacvlan props;
} NMDeviceMacvlanPrivate;
enum {
@@ -61,23 +62,26 @@ update_properties (NMDevice *device)
NMDeviceMacvlan *self = NM_DEVICE_MACVLAN (device);
NMDeviceMacvlanPrivate *priv = NM_DEVICE_MACVLAN_GET_PRIVATE (device);
GObject *object = G_OBJECT (device);
- NMPlatformMacvlanProperties props;
+ const NMPlatformLnkMacvlan *props;
+ const NMPlatformLink *plink;
- if (!nm_platform_macvlan_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
- _LOGW (LOGD_HW, "could not read macvlan properties");
+ props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
+ if (!props) {
+ _LOGW (LOGD_HW, "could not get macvlan properties");
return;
}
g_object_freeze_notify (object);
- if (priv->props.parent_ifindex != props.parent_ifindex)
+ if (priv->parent_ifindex != plink->parent)
g_object_notify (object, NM_DEVICE_MACVLAN_PARENT);
- if (g_strcmp0 (priv->props.mode, props.mode) != 0)
+ if (g_strcmp0 (priv->props.mode, props->mode) != 0)
g_object_notify (object, NM_DEVICE_MACVLAN_MODE);
- if (priv->props.no_promisc != props.no_promisc)
+ if (priv->props.no_promisc != props->no_promisc)
g_object_notify (object, NM_DEVICE_MACVLAN_NO_PROMISC);
- memcpy (&priv->props, &props, sizeof (NMPlatformMacvlanProperties));
+ priv->parent_ifindex = plink->parent;
+ priv->props = *props;
g_object_thaw_notify (object);
}
@@ -113,8 +117,8 @@ get_property (GObject *object, guint prop_id,
switch (prop_id) {
case PROP_PARENT:
- if (priv->props.parent_ifindex > 0)
- parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex);
+ if (priv->parent_ifindex > 0)
+ parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->parent_ifindex);
else
parent = NULL;
nm_utils_g_value_set_object_path (value, parent);
diff --git a/src/devices/nm-device-veth.c b/src/devices/nm-device-veth.c
index d80624857e..9c22ad1e5c 100644
--- a/src/devices/nm-device-veth.c
+++ b/src/devices/nm-device-veth.c
@@ -76,17 +76,18 @@ get_peer (NMDeviceVeth *self)
{
NMDeviceVethPrivate *priv = NM_DEVICE_VETH_GET_PRIVATE (self);
NMDevice *device = NM_DEVICE (self), *peer = NULL;
- NMPlatformVethProperties props;
+ int peer_ifindex;
if (priv->ever_had_peer)
return priv->peer;
- if (!nm_platform_veth_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
+ if (!nm_platform_veth_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &peer_ifindex)) {
_LOGW (LOGD_HW, "could not read veth properties");
return NULL;
}
- peer = nm_manager_get_device_by_ifindex (nm_manager_get (), props.peer);
+ if (peer_ifindex > 0)
+ peer = nm_manager_get_device_by_ifindex (nm_manager_get (), peer_ifindex);
if (peer && NM_IS_DEVICE_VETH (peer)) {
set_peer (self, peer);
set_peer (NM_DEVICE_VETH (peer), device);
diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c
index d30ce5f4ea..55790a9273 100644
--- a/src/devices/nm-device-vlan.c
+++ b/src/devices/nm-device-vlan.c
@@ -36,6 +36,7 @@
#include "nm-device-factory.h"
#include "nm-manager.h"
#include "nm-core-internal.h"
+#include "nmp-object.h"
#include "nmdbus-device-vlan.h"
@@ -164,27 +165,28 @@ realize (NMDevice *device,
GError **error)
{
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
- int parent_ifindex = -1, vlan_id = -1;
NMDevice *parent;
+ const NMPlatformLnkVlan *plnk;
g_return_val_if_fail (plink, FALSE);
g_assert (plink->type == NM_LINK_TYPE_VLAN);
- if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, plink->ifindex, &parent_ifindex, &vlan_id)) {
+ plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, plink->ifindex, NULL);
+ if (!plnk) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
- "(%s): failed to read VLAN properties", plink->name);
+ "(%s): failed to get VLAN properties", plink->name);
return FALSE;
}
- if (vlan_id < 0) {
+ if (plnk->id < 0) {
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
"(%s): VLAN ID invalid", plink->name);
return FALSE;
}
- if (parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS) {
- parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
+ if (plink->parent != NM_PLATFORM_LINK_OTHER_NETNS) {
+ parent = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->parent);
if (!parent) {
nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", plink->name);
g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_FAILED,
@@ -196,7 +198,7 @@ realize (NMDevice *device,
g_warn_if_fail (priv->parent == NULL);
nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);
- priv->vlan_id = vlan_id;
+ priv->vlan_id = plnk->id;
return TRUE;
}
@@ -294,7 +296,8 @@ component_added (NMDevice *device, GObject *component)
NMDeviceVlan *self = NM_DEVICE_VLAN (device);
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self);
NMDevice *added_device;
- int parent_ifindex = -1;
+ const NMPlatformLink *plink;
+ const NMPlatformLnkVlan *plnk;
if (priv->parent)
return FALSE;
@@ -303,13 +306,14 @@ component_added (NMDevice *device, GObject *component)
return FALSE;
added_device = NM_DEVICE (component);
- if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, nm_device_get_ifindex (device), &parent_ifindex, NULL)) {
+ plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), &plink);
+ if (!plnk) {
_LOGW (LOGD_VLAN, "failed to get VLAN interface info while checking added component.");
return FALSE;
}
- if ( parent_ifindex <= 0
- || nm_device_get_ifindex (added_device) != parent_ifindex)
+ if ( plink->parent <= 0
+ || nm_device_get_ifindex (added_device) != plink->parent)
return FALSE;
nm_device_vlan_set_parent (self, added_device);
@@ -462,30 +466,34 @@ update_connection (NMDevice *device, NMConnection *connection)
NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (device);
NMSettingVlan *s_vlan = nm_connection_get_setting_vlan (connection);
int ifindex = nm_device_get_ifindex (device);
- int parent_ifindex = -1, vlan_id = -1;
NMDevice *parent;
const char *setting_parent, *new_parent;
+ const NMPlatformLink *plink;
+ const NMPObject *polnk;
+ nm_auto_nmpobj NMPObject *polnk_ref = NULL;
if (!s_vlan) {
s_vlan = (NMSettingVlan *) nm_setting_vlan_new ();
nm_connection_add_setting (connection, (NMSetting *) s_vlan);
}
- if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent_ifindex, &vlan_id)) {
+ polnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, NM_LINK_TYPE_VLAN, &plink);
+ if (!polnk) {
_LOGW (LOGD_VLAN, "failed to get VLAN interface info while updating connection.");
return;
}
+ polnk_ref = nmp_object_ref ((NMPObject *) polnk);
- if (priv->vlan_id != vlan_id) {
- priv->vlan_id = vlan_id;
+ if (priv->vlan_id != polnk->lnk_vlan.id) {
+ priv->vlan_id = polnk->lnk_vlan.id;
g_object_notify (G_OBJECT (device), NM_DEVICE_VLAN_ID);
}
- if (vlan_id != nm_setting_vlan_get_id (s_vlan))
+ if (polnk->lnk_vlan.id != nm_setting_vlan_get_id (s_vlan))
g_object_set (s_vlan, NM_SETTING_VLAN_ID, priv->vlan_id, NULL);
- if (parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS)
- parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
+ if (plink->parent != NM_PLATFORM_LINK_OTHER_NETNS)
+ parent = nm_manager_get_device_by_ifindex (nm_manager_get (), plink->parent);
else
parent = NULL;
nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);
@@ -506,6 +514,16 @@ update_connection (NMDevice *device, NMConnection *connection)
g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL);
} else
g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, NULL, NULL);
+
+ if (polnk->lnk_vlan.flags != nm_setting_vlan_get_flags (s_vlan))
+ g_object_set (s_vlan, NM_SETTING_VLAN_FLAGS, (NMVlanFlags) polnk->lnk_vlan.flags, NULL);
+
+ _nm_setting_vlan_set_priorities (s_vlan, NM_VLAN_INGRESS_MAP,
+ polnk->_lnk_vlan.ingress_qos_map,
+ polnk->_lnk_vlan.n_ingress_qos_map);
+ _nm_setting_vlan_set_priorities (s_vlan, NM_VLAN_EGRESS_MAP,
+ polnk->_lnk_vlan.egress_qos_map,
+ polnk->_lnk_vlan.n_egress_qos_map);
}
static NMActStageReturn
@@ -540,20 +558,29 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
s_vlan = nm_connection_get_setting_vlan (connection);
if (s_vlan) {
- int ifindex = nm_device_get_ifindex (dev);
- int num, i;
- guint32 from, to;
-
- num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_INGRESS_MAP);
- for (i = 0; i < num; i++) {
- if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_INGRESS_MAP, i, &from, &to))
- nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, from, to);
- }
- num = nm_setting_vlan_get_num_priorities (s_vlan, NM_VLAN_EGRESS_MAP);
- for (i = 0; i < num; i++) {
- if (nm_setting_vlan_get_priority (s_vlan, NM_VLAN_EGRESS_MAP, i, &from, &to))
- nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, from, to);
- }
+ gs_free NMVlanQosMapping *ingress_map = NULL;
+ gs_free NMVlanQosMapping *egress_map = NULL;
+ guint n_ingress_map = 0, n_egress_map = 0;
+
+ _nm_setting_vlan_get_priorities (s_vlan,
+ NM_VLAN_INGRESS_MAP,
+ &ingress_map,
+ &n_ingress_map);
+ _nm_setting_vlan_get_priorities (s_vlan,
+ NM_VLAN_EGRESS_MAP,
+ &egress_map,
+ &n_egress_map);
+
+ nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ nm_device_get_ifindex (dev),
+ NM_VLAN_FLAGS_ALL,
+ nm_setting_vlan_get_flags (s_vlan),
+ TRUE,
+ ingress_map,
+ n_ingress_map,
+ TRUE,
+ egress_map,
+ n_egress_map);
}
return ret;
diff --git a/src/devices/nm-device-vxlan.c b/src/devices/nm-device-vxlan.c
index b66f2368fb..7fb55f2086 100644
--- a/src/devices/nm-device-vxlan.c
+++ b/src/devices/nm-device-vxlan.c
@@ -40,7 +40,7 @@ G_DEFINE_TYPE (NMDeviceVxlan, nm_device_vxlan, NM_TYPE_DEVICE_GENERIC)
#define NM_DEVICE_VXLAN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DEVICE_VXLAN, NMDeviceVxlanPrivate))
typedef struct {
- NMPlatformVxlanProperties props;
+ NMPlatformLnkVxlan props;
} NMDeviceVxlanPrivate;
enum {
@@ -73,53 +73,54 @@ update_properties (NMDevice *device)
NMDeviceVxlan *self = NM_DEVICE_VXLAN (device);
NMDeviceVxlanPrivate *priv = NM_DEVICE_VXLAN_GET_PRIVATE (device);
GObject *object = G_OBJECT (device);
- NMPlatformVxlanProperties props;
+ const NMPlatformLnkVxlan *props;
- if (!nm_platform_vxlan_get_properties (NM_PLATFORM_GET, nm_device_get_ifindex (device), &props)) {
- _LOGW (LOGD_HW, "could not read vxlan properties");
+ props = nm_platform_link_get_lnk_vxlan (NM_PLATFORM_GET, nm_device_get_ifindex (device), NULL);
+ if (!props) {
+ _LOGW (LOGD_HW, "could not get vxlan properties");
return;
}
g_object_freeze_notify (object);
- if (priv->props.parent_ifindex != props.parent_ifindex)
+ if (priv->props.parent_ifindex != props->parent_ifindex)
g_object_notify (object, NM_DEVICE_VXLAN_PARENT);
- if (priv->props.id != props.id)
+ if (priv->props.id != props->id)
g_object_notify (object, NM_DEVICE_VXLAN_ID);
- if (priv->props.group != props.group)
+ if (priv->props.group != props->group)
g_object_notify (object, NM_DEVICE_VXLAN_GROUP);
- if (priv->props.local != props.local)
+ if (priv->props.local != props->local)
g_object_notify (object, NM_DEVICE_VXLAN_LOCAL);
- if (memcmp (&priv->props.group6, &props.group6, sizeof (props.group6)) != 0)
+ if (memcmp (&priv->props.group6, &props->group6, sizeof (props->group6)) != 0)
g_object_notify (object, NM_DEVICE_VXLAN_GROUP);
- if (memcmp (&priv->props.local6, &props.local6, sizeof (props.local6)) != 0)
+ if (memcmp (&priv->props.local6, &props->local6, sizeof (props->local6)) != 0)
g_object_notify (object, NM_DEVICE_VXLAN_LOCAL);
- if (priv->props.tos != props.tos)
+ if (priv->props.tos != props->tos)
g_object_notify (object, NM_DEVICE_VXLAN_TOS);
- if (priv->props.ttl != props.ttl)
+ if (priv->props.ttl != props->ttl)
g_object_notify (object, NM_DEVICE_VXLAN_TTL);
- if (priv->props.learning != props.learning)
+ if (priv->props.learning != props->learning)
g_object_notify (object, NM_DEVICE_VXLAN_LEARNING);
- if (priv->props.ageing != props.ageing)
+ if (priv->props.ageing != props->ageing)
g_object_notify (object, NM_DEVICE_VXLAN_AGEING);
- if (priv->props.limit != props.limit)
+ if (priv->props.limit != props->limit)
g_object_notify (object, NM_DEVICE_VXLAN_LIMIT);
- if (priv->props.dst_port != props.dst_port)
+ if (priv->props.dst_port != props->dst_port)
g_object_notify (object, NM_DEVICE_VXLAN_DST_PORT);
- if (priv->props.src_port_min != props.src_port_min)
+ if (priv->props.src_port_min != props->src_port_min)
g_object_notify (object, NM_DEVICE_VXLAN_SRC_PORT_MIN);
- if (priv->props.src_port_max != props.src_port_max)
+ if (priv->props.src_port_max != props->src_port_max)
g_object_notify (object, NM_DEVICE_VXLAN_SRC_PORT_MAX);
- if (priv->props.proxy != props.proxy)
+ if (priv->props.proxy != props->proxy)
g_object_notify (object, NM_DEVICE_VXLAN_PROXY);
- if (priv->props.rsc != props.rsc)
+ if (priv->props.rsc != props->rsc)
g_object_notify (object, NM_DEVICE_VXLAN_RSC);
- if (priv->props.l2miss != props.l2miss)
+ if (priv->props.l2miss != props->l2miss)
g_object_notify (object, NM_DEVICE_VXLAN_L2MISS);
- if (priv->props.l3miss != props.l3miss)
+ if (priv->props.l3miss != props->l3miss)
g_object_notify (object, NM_DEVICE_VXLAN_L3MISS);
- memcpy (&priv->props, &props, sizeof (NMPlatformVxlanProperties));
+ priv->props = *props;
g_object_thaw_notify (object);
}
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 7338ff5ffb..f1df6ef0a5 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -3274,8 +3274,7 @@ ipv4ll_get_ip4_config (NMDevice *self, guint32 lla)
g_assert (config);
memset (&address, 0, sizeof (address));
- address.address = lla;
- address.plen = 16;
+ nm_platform_ip4_address_set_addr (&address, lla, 16);
address.source = NM_IP_CONFIG_SOURCE_IP4LL;
nm_ip4_config_add_address (config, &address);
@@ -3711,7 +3710,7 @@ ip4_config_merge_and_apply (NMDevice *self,
goto END_ADD_DEFAULT_ROUTE;
has_direct_route = ( gateway == 0
- || nm_ip4_config_get_subnet_for_host (composite, gateway)
+ || nm_ip4_config_destination_is_direct (composite, gateway, 32)
|| nm_ip4_config_get_direct_route_for_host (composite, gateway));
priv->default_route.v4_has = TRUE;
@@ -4016,10 +4015,11 @@ reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Addres
if (s_ip4 && nm_setting_ip_config_get_num_addresses (s_ip4)) {
/* Use the first user-supplied address */
NMIPAddress *user = nm_setting_ip_config_get_address (s_ip4, 0);
+ in_addr_t a;
g_assert (user);
- nm_ip_address_get_address_binary (user, &address->address);
- address->plen = nm_ip_address_get_prefix (user);
+ nm_ip_address_get_address_binary (user, &a);
+ nm_platform_ip4_address_set_addr (address, a, nm_ip_address_get_prefix (user));
} else {
/* Find an unused address in the 10.42.x.x range */
guint32 start = (guint32) ntohl (0x0a2a0001); /* 10.42.0.1 */
@@ -4032,8 +4032,7 @@ reserve_shared_ip (NMDevice *self, NMSettingIPConfig *s_ip4, NMPlatformIP4Addres
return FALSE;
}
}
- address->address = start + count;
- address->plen = 24;
+ nm_platform_ip4_address_set_addr (address, start + count, 24);
g_hash_table_insert (shared_ips,
GUINT_TO_POINTER (address->address),
@@ -4902,53 +4901,6 @@ linklocal6_start (NMDevice *self)
/******************************************/
-static void
-print_support_extended_ifa_flags (NMSettingIP6ConfigPrivacy use_tempaddr)
-{
- static gint8 warn = 0;
- static gint8 s_libnl = -1, s_kernel;
-
- if (warn >= 2)
- return;
-
- if (s_libnl == -1) {
- s_libnl = !!nm_platform_check_support_libnl_extended_ifa_flags ();
- s_kernel = !!nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
-
- if (s_libnl && s_kernel) {
- nm_log_dbg (LOGD_IP6, "kernel and libnl support extended IFA_FLAGS (needed by NM for IPv6 private addresses)");
- warn = 2;
- return;
- }
- }
-
- if ( use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
- && use_tempaddr != NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR) {
- if (warn == 0) {
- nm_log_dbg (LOGD_IP6, "%s%s%s %s not support extended IFA_FLAGS (needed by NM for IPv6 private addresses)",
- !s_kernel ? "kernel" : "",
- !s_kernel && !s_libnl ? " and " : "",
- !s_libnl ? "libnl" : "",
- !s_kernel && !s_libnl ? "do" : "does");
- warn = 1;
- }
- return;
- }
-
- if (!s_libnl && !s_kernel) {
- nm_log_warn (LOGD_IP6, "libnl and the kernel do not support extended IFA_FLAGS needed by NM for "
- "IPv6 private addresses. This feature is not available");
- } else if (!s_libnl) {
- nm_log_warn (LOGD_IP6, "libnl does not support extended IFA_FLAGS needed by NM for "
- "IPv6 private addresses. This feature is not available");
- } else if (!s_kernel) {
- nm_log_warn (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for "
- "IPv6 private addresses. This feature is not available");
- }
-
- warn = 2;
-}
-
static void nm_device_ipv6_set_mtu (NMDevice *self, guint32 mtu);
static void
@@ -5006,24 +4958,20 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
int i;
- static int system_support = -1;
+ int system_support;
guint ifa_flags = 0x00;
- if (system_support == -1) {
- /*
- * Check, if both libnl and the kernel are recent enough,
- * to help user space handling RA. If it's not supported,
- * we have no ipv6-privacy and must add autoconf addresses
- * as /128. The reason for the /128 is to prevent the kernel
- * from adding a prefix route for this address.
- **/
- system_support = nm_platform_check_support_libnl_extended_ifa_flags () &&
- nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
- }
+ /*
+ * Check, whether kernel is recent enough to help user space handling RA.
+ * If it's not supported, we have no ipv6-privacy and must add autoconf
+ * addresses as /128. The reason for the /128 is to prevent the kernel
+ * from adding a prefix route for this address.
+ **/
+ system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
if (system_support)
ifa_flags = IFA_F_NOPREFIXROUTE;
- if (priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
+ if ( priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR
|| priv->rdisc_use_tempaddr == NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
{
/* without system_support, this flag will be ignored. Still set it, doesn't seem to do any harm. */
@@ -5233,7 +5181,12 @@ addrconf6_start (NMDevice *self, NMSettingIP6ConfigPrivacy use_tempaddr)
}
priv->rdisc_use_tempaddr = use_tempaddr;
- print_support_extended_ifa_flags (use_tempaddr);
+
+ if ( NM_IN_SET (use_tempaddr, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_TEMP_ADDR, NM_SETTING_IP6_CONFIG_PRIVACY_PREFER_PUBLIC_ADDR)
+ && !nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET)) {
+ _LOGW (LOGD_IP6, "The kernel does not support extended IFA_FLAGS needed by NM for "
+ "IPv6 private addresses. This feature is not available");
+ }
if (!nm_setting_ip_config_get_may_fail (nm_connection_get_setting_ip6_config (connection)))
nm_device_add_pending_action (self, PENDING_ACTION_AUTOCONF6, TRUE);
diff --git a/src/devices/wwan/nm-modem-broadband.c b/src/devices/wwan/nm-modem-broadband.c
index 7ec90c33ef..2236559477 100644
--- a/src/devices/wwan/nm-modem-broadband.c
+++ b/src/devices/wwan/nm-modem-broadband.c
@@ -750,6 +750,7 @@ static_stage3_ip4_done (NMModemBroadband *self)
memset (&address, 0, sizeof (address));
address.address = address_network;
+ address.peer_address = address_network;
address.plen = mm_bearer_ip_config_get_prefix (self->priv->ipv4_config);
address.source = NM_IP_CONFIG_SOURCE_WWAN;
nm_ip4_config_add_address (config, &address);
diff --git a/src/dhcp-manager/nm-dhcp-dhclient-utils.c b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
index a86596c077..726d26c8d0 100644
--- a/src/dhcp-manager/nm-dhcp-dhclient-utils.c
+++ b/src/dhcp-manager/nm-dhcp-dhclient-utils.c
@@ -675,6 +675,7 @@ nm_dhcp_dhclient_read_lease_ip_configs (const char *iface,
continue;
if (!inet_pton (AF_INET, value, &address.address))
continue;
+ address.peer_address = address.address;
/* Gateway */
value = g_hash_table_lookup (hash, "option routers");
diff --git a/src/dhcp-manager/nm-dhcp-systemd.c b/src/dhcp-manager/nm-dhcp-systemd.c
index 4459fd583f..e508ea13bb 100644
--- a/src/dhcp-manager/nm-dhcp-systemd.c
+++ b/src/dhcp-manager/nm-dhcp-systemd.c
@@ -232,6 +232,7 @@ lease_to_ip4_config (const char *iface,
sd_dhcp_lease_get_address (lease, &tmp_addr);
memset (&address, 0, sizeof (address));
address.address = tmp_addr.s_addr;
+ address.peer_address = tmp_addr.s_addr;
str = nm_utils_inet4_ntop (tmp_addr.s_addr, NULL);
LOG_LEASE (LOGD_DHCP4, " address %s", str);
add_option (options, dhcp4_requests, DHCP_OPTION_IP_ADDRESS, str);
diff --git a/src/dhcp-manager/nm-dhcp-utils.c b/src/dhcp-manager/nm-dhcp-utils.c
index cdf26fcae9..e6bc18072c 100644
--- a/src/dhcp-manager/nm-dhcp-utils.c
+++ b/src/dhcp-manager/nm-dhcp-utils.c
@@ -320,7 +320,7 @@ process_classful_routes (GHashTable *options, guint32 priority, NMIP4Config *ip4
nm_ip4_config_add_route (ip4_config, &route);
nm_log_info (LOGD_DHCP, " static route %s",
- nm_platform_ip4_route_to_string (&route));
+ nm_platform_ip4_route_to_string (&route, NULL, 0));
}
out:
@@ -380,6 +380,7 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
{
NMIP4Config *ip4_config = NULL;
guint32 tmp_addr;
+ in_addr_t addr;
NMPlatformIP4Address address;
char *str = NULL;
guint32 gwaddr = 0, plen = 0;
@@ -391,10 +392,9 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
address.timestamp = nm_utils_get_monotonic_timestamp_s ();
str = g_hash_table_lookup (options, "ip_address");
- if (str && (inet_pton (AF_INET, str, &tmp_addr) > 0)) {
- address.address = tmp_addr;
+ if (str && (inet_pton (AF_INET, str, &addr) > 0))
nm_log_info (LOGD_DHCP4, " address %s", str);
- } else
+ else
goto error;
str = g_hash_table_lookup (options, "subnet_mask");
@@ -403,10 +403,10 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
nm_log_info (LOGD_DHCP4, " plen %d (%s)", plen, str);
} else {
/* Get default netmask for the IP according to appropriate class. */
- plen = nm_utils_ip4_get_default_prefix (address.address);
+ plen = nm_utils_ip4_get_default_prefix (addr);
nm_log_info (LOGD_DHCP4, " plen %d (default)", plen);
}
- address.plen = plen;
+ nm_platform_ip4_address_set_addr (&address, addr, plen);
/* Routes: if the server returns classless static routes, we MUST ignore
* the 'static_routes' option.
@@ -469,7 +469,7 @@ nm_dhcp_utils_ip4_config_from_options (int ifindex,
route.metric = priority;
nm_ip4_config_add_route (ip4_config, &route);
nm_log_dbg (LOGD_IP, "adding route for server identifier: %s",
- nm_platform_ip4_route_to_string (&route));
+ nm_platform_ip4_route_to_string (&route, NULL, 0));
}
}
else
diff --git a/src/dhcp-manager/tests/test-dhcp-dhclient.c b/src/dhcp-manager/tests/test-dhcp-dhclient.c
index 15817addb4..ce3697a552 100644
--- a/src/dhcp-manager/tests/test-dhcp-dhclient.c
+++ b/src/dhcp-manager/tests/test-dhcp-dhclient.c
@@ -666,6 +666,7 @@ test_read_lease_ip4_config_basic (void)
g_assert (inet_aton ("192.168.1.180", (struct in_addr *) &expected_addr));
addr = nm_ip4_config_get_address (config, 0);
g_assert_cmpint (addr->address, ==, expected_addr);
+ g_assert_cmpint (addr->peer_address, ==, expected_addr);
g_assert_cmpint (addr->plen, ==, 24);
/* Gateway */
@@ -688,6 +689,7 @@ test_read_lease_ip4_config_basic (void)
g_assert (inet_aton ("10.77.52.141", (struct in_addr *) &expected_addr));
addr = nm_ip4_config_get_address (config, 0);
g_assert_cmpint (addr->address, ==, expected_addr);
+ g_assert_cmpint (addr->peer_address, ==, expected_addr);
g_assert_cmpint (addr->plen, ==, 8);
/* Gateway */
diff --git a/src/dhcp-manager/tests/test-dhcp-utils.c b/src/dhcp-manager/tests/test-dhcp-utils.c
index 65a396092a..49987c40ca 100644
--- a/src/dhcp-manager/tests/test-dhcp-utils.c
+++ b/src/dhcp-manager/tests/test-dhcp-utils.c
@@ -95,7 +95,7 @@ test_generic_options (void)
address = nm_ip4_config_get_address (ip4_config, 0);
g_assert (inet_pton (AF_INET, expected_addr, &tmp) > 0);
g_assert (address->address == tmp);
- g_assert (address->peer_address == 0);
+ g_assert (address->peer_address == tmp);
g_assert_cmpint (address->plen, ==, 24);
/* Gateway */
diff --git a/src/dnsmasq-manager/tests/test-dnsmasq-utils.c b/src/dnsmasq-manager/tests/test-dnsmasq-utils.c
index 8cc5fa9751..04bf1b4d74 100644
--- a/src/dnsmasq-manager/tests/test-dnsmasq-utils.c
+++ b/src/dnsmasq-manager/tests/test-dnsmasq-utils.c
@@ -27,13 +27,12 @@
#include "nm-test-utils.h"
-static guint32
-addr_to_num (const char *addr)
+static NMPlatformIP4Address *
+_set_addr (NMPlatformIP4Address *addr, const char *address, int plen)
{
- guint n;
-
- g_assert (inet_pton (AF_INET, addr, (void *) &n) == 1);
- return n;
+ memset (addr, 0, sizeof (*addr));
+ nm_platform_ip4_address_set_addr (addr, nmtst_inet4_from_string (address), plen);
+ return addr;
}
static void
@@ -44,58 +43,50 @@ test_address_ranges (void)
char last[INET_ADDRSTRLEN];
char *error_desc = NULL;
- addr.address = addr_to_num ("192.168.0.1");
- addr.plen = 24;
+ _set_addr (&addr, "192.168.0.1", 24);
g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc));
g_assert (error_desc == NULL);
g_assert_cmpstr (first, ==, "192.168.0.10");
g_assert_cmpstr (last, ==, "192.168.0.254");
- addr.address = addr_to_num ("192.168.0.99");
- addr.plen = 24;
+ _set_addr (&addr, "192.168.0.99", 24);
g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc));
g_assert (error_desc == NULL);
g_assert_cmpstr (first, ==, "192.168.0.108");
g_assert_cmpstr (last, ==, "192.168.0.254");
- addr.address = addr_to_num ("192.168.0.254");
- addr.plen = 24;
+ _set_addr (&addr, "192.168.0.254", 24);
g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc));
g_assert (error_desc == NULL);
g_assert_cmpstr (first, ==, "192.168.0.1");
g_assert_cmpstr (last, ==, "192.168.0.245");
/* Smaller networks */
- addr.address = addr_to_num ("1.2.3.1");
- addr.plen = 30;
+ _set_addr (&addr, "1.2.3.1", 30);
g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc));
g_assert (error_desc == NULL);
g_assert_cmpstr (first, ==, "1.2.3.2");
g_assert_cmpstr (last, ==, "1.2.3.2");
- addr.address = addr_to_num ("1.2.3.1");
- addr.plen = 29;
+ _set_addr (&addr, "1.2.3.1", 29);
g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc));
g_assert (error_desc == NULL);
g_assert_cmpstr (first, ==, "1.2.3.2");
g_assert_cmpstr (last, ==, "1.2.3.6");
- addr.address = addr_to_num ("1.2.3.1");
- addr.plen = 28;
+ _set_addr (&addr, "1.2.3.1", 28);
g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc));
g_assert (error_desc == NULL);
g_assert_cmpstr (first, ==, "1.2.3.3");
g_assert_cmpstr (last, ==, "1.2.3.14");
- addr.address = addr_to_num ("1.2.3.1");
- addr.plen = 26;
+ _set_addr (&addr, "1.2.3.1", 26);
g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc));
g_assert (error_desc == NULL);
g_assert_cmpstr (first, ==, "1.2.3.8");
g_assert_cmpstr (last, ==, "1.2.3.62");
- addr.address = addr_to_num ("1.2.3.1");
- addr.plen = 31;
+ _set_addr (&addr, "1.2.3.1", 31);
g_assert (nm_dnsmasq_utils_get_range (&addr, first, last, &error_desc) == FALSE);
g_assert (error_desc);
g_free (error_desc);
diff --git a/src/nm-default-route-manager.c b/src/nm-default-route-manager.c
index 26baf1778b..91785566cc 100644
--- a/src/nm-default-route-manager.c
+++ b/src/nm-default-route-manager.c
@@ -281,7 +281,7 @@ _platform_route_sync_add (const VTableIP *vtable, NMDefaultRouteManager *self, g
}
if (!success) {
_LOGW (vtable->vt->addr_family, "failed to add default route %s with effective metric %u",
- vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric);
+ vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric);
}
return TRUE;
}
@@ -553,23 +553,23 @@ _resync_all (const VTableIP *vtable, NMDefaultRouteManager *self, const Entry *c
g_array_append_val (changed_metrics, expected_metric);
if (old_entry) {
_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": sync:update %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
- vtable->vt->route_to_string (&entry->route), (guint) old_entry->effective_metric,
+ vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) old_entry->effective_metric,
(guint) expected_metric);
} else {
_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": sync:add %s (%u)", LOG_ENTRY_ARGS (i, entry),
- vtable->vt->route_to_string (&entry->route), (guint) expected_metric);
+ vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) expected_metric);
}
} else if (entry->effective_metric != expected_metric) {
g_array_append_val (changed_metrics, entry->effective_metric);
g_array_append_val (changed_metrics, expected_metric);
_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": sync:metric %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
- vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric,
+ vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric,
(guint) expected_metric);
} else {
if (!_vt_routes_has_entry (vtable, routes, entry)) {
g_array_append_val (changed_metrics, entry->effective_metric);
_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": sync:re-add %s (%u -> %u)", LOG_ENTRY_ARGS (i, entry),
- vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric,
+ vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric,
(guint) entry->effective_metric);
}
}
@@ -636,7 +636,7 @@ _entry_at_idx_update (const VTableIP *vtable, NMDefaultRouteManager *self, guint
_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": %s %s (%"G_GUINT32_FORMAT")",
LOG_ENTRY_ARGS (entry_idx, entry),
old_entry ? "record:update" : "record:add ",
- vtable->vt->route_to_string (&entry->route),
+ vtable->vt->route_to_string (&entry->route, NULL, 0),
entry->effective_metric);
g_ptr_array_sort_with_data (entries, _sort_entries_cmp, NULL);
@@ -658,7 +658,7 @@ _entry_at_idx_remove (const VTableIP *vtable, NMDefaultRouteManager *self, guint
entry = g_ptr_array_index (entries, entry_idx);
_LOGD (vtable->vt->addr_family, LOG_ENTRY_FMT": record:remove %s (%u)", LOG_ENTRY_ARGS (entry_idx, entry),
- vtable->vt->route_to_string (&entry->route), (guint) entry->effective_metric);
+ vtable->vt->route_to_string (&entry->route, NULL, 0), (guint) entry->effective_metric);
/* Remove the entry from the list (but don't free it yet) */
g_ptr_array_index (entries, entry_idx) = NULL;
diff --git a/src/nm-iface-helper.c b/src/nm-iface-helper.c
index 6ae19c5c7a..ecb67ea7bb 100644
--- a/src/nm-iface-helper.c
+++ b/src/nm-iface-helper.c
@@ -137,14 +137,13 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, gpointer user_da
if (system_support == -1) {
/*
- * Check, if both libnl and the kernel are recent enough,
- * to help user space handling RA. If it's not supported,
- * we have no ipv6-privacy and must add autoconf addresses
- * as /128. The reason for the /128 is to prevent the kernel
+ * Check, whether kernel is recent enough, to help user space handling RA.
+ * If it's not supported, we have no ipv6-privacy and must add autoconf
+ * addresses as /128.
+ * The reason for the /128 is to prevent the kernel
* from adding a prefix route for this address.
**/
- system_support = nm_platform_check_support_libnl_extended_ifa_flags () &&
- nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
+ system_support = nm_platform_check_support_kernel_extended_ifa_flags (NM_PLATFORM_GET);
}
if (system_support)
diff --git a/src/nm-ip4-config.c b/src/nm-ip4-config.c
index 2f14a3aa6c..7e74379ec0 100644
--- a/src/nm-ip4-config.c
+++ b/src/nm-ip4-config.c
@@ -100,13 +100,13 @@ nm_ip4_config_get_ifindex (const NMIP4Config *config)
return NM_IP4_CONFIG_GET_PRIVATE (config)->ifindex;
}
+/******************************************************************/
+
static gboolean
-same_prefix (guint32 address1, guint32 address2, int plen)
+_ipv4_is_zeronet (in_addr_t network)
{
- guint32 masked1 = ntohl (address1) >> (32 - plen);
- guint32 masked2 = ntohl (address2) >> (32 - plen);
-
- return masked1 == masked2;
+ /* Same as ipv4_is_zeronet() from kernel's include/linux/in.h. */
+ return (network & htonl(0xff000000)) == htonl(0x00000000);
}
/******************************************************************/
@@ -180,7 +180,7 @@ addresses_are_duplicate (const NMPlatformIP4Address *a, const NMPlatformIP4Addre
{
return a->address == b->address
&& a->plen == b->plen
- && nm_platform_ip4_address_equal_peer_net (a, b);
+ && ((a->peer_address ^ b->peer_address) & nm_utils_ip4_prefix_to_netmask (a->plen)) == 0;
}
static gboolean
@@ -307,7 +307,16 @@ nm_ip4_config_commit (const NMIP4Config *config, int ifindex, gboolean routes_fu
route.ifindex = ifindex;
route.source = NM_IP_CONFIG_SOURCE_KERNEL;
- route.network = nm_utils_ip4_address_clear_host_address (addr->address, addr->plen);
+
+ /* The destination network depends on the peer-address. */
+ route.network = nm_utils_ip4_address_clear_host_address (addr->peer_address, addr->plen);
+
+ if (_ipv4_is_zeronet (route.network)) {
+ /* Kernel doesn't add device-routes for destinations that
+ * start with 0.x.y.z. Skip them. */
+ continue;
+ }
+
route.plen = addr->plen;
route.pref_src = addr->address;
route.metric = default_route_metric;
@@ -395,6 +404,7 @@ nm_ip4_config_merge_setting (NMIP4Config *config, NMSettingIPConfig *setting, gu
memset (&address, 0, sizeof (address));
nm_ip_address_get_address_binary (s_addr, &address.address);
+ address.peer_address = address.address;
address.plen = nm_ip_address_get_prefix (s_addr);
address.lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
address.preferred = NM_PLATFORM_LIFETIME_PERMANENT;
@@ -996,7 +1006,7 @@ nm_ip4_config_replace (NMIP4Config *dst, const NMIP4Config *src, gboolean *relev
dst_addr = nm_ip4_config_get_address (dst, i))) {
are_equal = FALSE;
if ( !addresses_are_duplicate (src_addr, dst_addr)
- || (nm_platform_ip4_address_get_peer (src_addr) != nm_platform_ip4_address_get_peer (dst_addr))) {
+ || src_addr->peer_address != dst_addr->peer_address) {
has_relevant_changes = TRUE;
break;
}
@@ -1199,7 +1209,7 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail)
/* addresses */
for (i = 0; i < nm_ip4_config_get_num_addresses (config); i++)
- g_message (" a: %s", nm_platform_ip4_address_to_string (nm_ip4_config_get_address (config, i)));
+ g_message (" a: %s", nm_platform_ip4_address_to_string (nm_ip4_config_get_address (config, i), NULL, 0));
/* default gateway */
if (nm_ip4_config_has_gateway (config)) {
@@ -1215,7 +1225,7 @@ nm_ip4_config_dump (const NMIP4Config *config, const char *detail)
/* routes */
for (i = 0; i < nm_ip4_config_get_num_routes (config); i++)
- g_message (" rt: %s", nm_platform_ip4_route_to_string (nm_ip4_config_get_route (config, i)));
+ g_message (" rt: %s", nm_platform_ip4_route_to_string (nm_ip4_config_get_route (config, i), NULL, 0));
/* domains */
for (i = 0; i < nm_ip4_config_get_num_domains (config); i++)
@@ -1256,12 +1266,22 @@ nm_ip4_config_destination_is_direct (const NMIP4Config *config, guint32 network,
{
guint naddresses = nm_ip4_config_get_num_addresses (config);
int i;
+ in_addr_t peer_network;
for (i = 0; i < naddresses; i++) {
const NMPlatformIP4Address *item = nm_ip4_config_get_address (config, i);
- if (item->plen <= plen && same_prefix (item->address, network, item->plen))
- return TRUE;
+ if (item->plen > plen)
+ continue;
+
+ peer_network = nm_utils_ip4_address_clear_host_address (item->peer_address, item->plen);
+ if (_ipv4_is_zeronet (peer_network))
+ continue;
+
+ if (peer_network != nm_utils_ip4_address_clear_host_address (network, item->plen))
+ continue;
+
+ return TRUE;
}
return FALSE;
@@ -1554,28 +1574,6 @@ nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host
return best_route;
}
-const NMPlatformIP4Address *
-nm_ip4_config_get_subnet_for_host (const NMIP4Config *config, guint32 host)
-{
- NMIP4ConfigPrivate *priv = NM_IP4_CONFIG_GET_PRIVATE (config);
- guint i;
- NMPlatformIP4Address *subnet = NULL;
-
- g_return_val_if_fail (host, NULL);
-
- for (i = 0; i < priv->addresses->len; i++) {
- NMPlatformIP4Address *item = &g_array_index (priv->addresses, NMPlatformIP4Address, i);
-
- if (subnet && subnet->plen >= item->plen)
- continue;
- if (nm_utils_ip4_address_clear_host_address (host, item->plen) != nm_utils_ip4_address_clear_host_address (item->address, item->plen))
- continue;
- subnet = item;
- }
-
- return subnet;
-}
-
/******************************************************************/
void
@@ -2016,7 +2014,7 @@ nm_ip4_config_hash (const NMIP4Config *config, GChecksum *sum, gboolean dns_only
const NMPlatformIP4Address *address = nm_ip4_config_get_address (config, i);
hash_u32 (sum, address->address);
hash_u32 (sum, address->plen);
- hash_u32 (sum, nm_platform_ip4_address_get_peer_net (address));
+ hash_u32 (sum, address->peer_address & nm_utils_ip4_prefix_to_netmask (address->plen));
}
for (i = 0; i < nm_ip4_config_get_num_routes (config); i++) {
@@ -2163,8 +2161,7 @@ get_property (GObject *object, guint prop_id,
g_variant_builder_add (&addr_builder, "{sv}",
"prefix",
g_variant_new_uint32 (address->plen));
- if ( address->peer_address
- && address->peer_address != address->address) {
+ if (address->peer_address != address->address) {
g_variant_builder_add (&addr_builder, "{sv}",
"peer",
g_variant_new_string (nm_utils_inet4_ntop (address->peer_address, NULL)));
diff --git a/src/nm-ip4-config.h b/src/nm-ip4-config.h
index 1c76b97e99..160f2246bf 100644
--- a/src/nm-ip4-config.h
+++ b/src/nm-ip4-config.h
@@ -102,7 +102,6 @@ guint32 nm_ip4_config_get_num_routes (const NMIP4Config *config);
const NMPlatformIP4Route *nm_ip4_config_get_route (const NMIP4Config *config, guint32 i);
const NMPlatformIP4Route *nm_ip4_config_get_direct_route_for_host (const NMIP4Config *config, guint32 host);
-const NMPlatformIP4Address *nm_ip4_config_get_subnet_for_host (const NMIP4Config *config, guint32 host);
/* Nameservers */
void nm_ip4_config_reset_nameservers (NMIP4Config *config);
diff --git a/src/nm-ip6-config.c b/src/nm-ip6-config.c
index c484bf52ab..51e8e121a7 100644
--- a/src/nm-ip6-config.c
+++ b/src/nm-ip6-config.c
@@ -1166,7 +1166,7 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail)
/* addresses */
for (i = 0; i < nm_ip6_config_get_num_addresses (config); i++)
- g_message (" a: %s", nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i)));
+ g_message (" a: %s", nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i), NULL, 0));
/* default gateway */
tmp = nm_ip6_config_get_gateway (config);
@@ -1181,7 +1181,7 @@ nm_ip6_config_dump (const NMIP6Config *config, const char *detail)
/* routes */
for (i = 0; i < nm_ip6_config_get_num_routes (config); i++)
- g_message (" rt: %s", nm_platform_ip6_route_to_string (nm_ip6_config_get_route (config, i)));
+ g_message (" rt: %s", nm_platform_ip6_route_to_string (nm_ip6_config_get_route (config, i), NULL, 0));
/* domains */
for (i = 0; i < nm_ip6_config_get_num_domains (config); i++)
diff --git a/src/nm-route-manager.c b/src/nm-route-manager.c
index 2c08c9eee7..1a89af7433 100644
--- a/src/nm-route-manager.c
+++ b/src/nm-route-manager.c
@@ -467,12 +467,12 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
if (_LOGT_ENABLED (vtable->vt->addr_family)) {
for (i = 0; i < known_routes_idx->len; i++) {
_LOGT (vtable->vt->addr_family, "%3d: sync new route #%u: %s",
- ifindex, i, vtable->vt->route_to_string (VTABLE_ROUTE_INDEX (vtable, known_routes, i)));
+ ifindex, i, vtable->vt->route_to_string (VTABLE_ROUTE_INDEX (vtable, known_routes, i), NULL, 0));
}
for (i = 0; i < ipx_routes->index->len; i++)
_LOGT (vtable->vt->addr_family, "%3d: STATE: has #%u - %s (%lld)",
ifindex, i,
- vtable->vt->route_to_string (ipx_routes->index->entries[i]),
+ vtable->vt->route_to_string (ipx_routes->index->entries[i], NULL, 0),
(long long) g_array_index (ipx_routes->effective_metrics, gint64, i));
}
@@ -512,7 +512,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
cur_ipx_route->rx.ifindex = ifindex;
cur_ipx_route->rx.metric = vtable->vt->metric_normalize (cur_ipx_route->rx.metric);
ipx_routes_changed = TRUE;
- _LOGT (vtable->vt->addr_family, "%3d: STATE: update #%u - %s", ifindex, i_ipx_routes, vtable->vt->route_to_string (cur_ipx_route));
+ _LOGT (vtable->vt->addr_family, "%3d: STATE: update #%u - %s", ifindex, i_ipx_routes,
+ vtable->vt->route_to_string (cur_ipx_route, NULL, 0));
}
} else if (cur_known_route) {
g_assert (!cur_ipx_route || route_id_cmp_result > 0);
@@ -570,7 +571,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
&& cur_plat_route->rx.metric == *p_effective_metric) {
/* we are about to delete cur_ipx_route and we have a matching route
* in platform. Delete it. */
- _LOGT (vtable->vt->addr_family, "%3d: platform rt-rm #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route));
+ _LOGT (vtable->vt->addr_family, "%3d: platform rt-rm #%u - %s", ifindex, i_plat_routes,
+ vtable->vt->route_to_string (cur_plat_route, NULL, 0));
vtable->vt->route_delete (priv->platform, ifindex, cur_plat_route);
}
}
@@ -582,7 +584,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
for (i = 0; i < to_delete_indexes->len; i++) {
guint idx = g_array_index (to_delete_indexes, guint, i);
- _LOGT (vtable->vt->addr_family, "%3d: STATE: delete #%u - %s", ifindex, idx, vtable->vt->route_to_string (ipx_routes->index->entries[idx]));
+ _LOGT (vtable->vt->addr_family, "%3d: STATE: delete #%u - %s", ifindex, idx,
+ vtable->vt->route_to_string (ipx_routes->index->entries[idx], NULL, 0));
g_array_index (to_delete_indexes, guint, i) = _route_index_reverse_idx (vtable, ipx_routes->index, idx, ipx_routes->entries);
}
g_array_sort (to_delete_indexes, (GCompareFunc) _sort_indexes_cmp);
@@ -606,7 +609,8 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
g_array_index (ipx_routes->effective_metrics_reverse, gint64, j++) = -1;
- _LOGT (vtable->vt->addr_family, "%3d: STATE: added #%u - %s", ifindex, ipx_routes->entries->len - 1, vtable->vt->route_to_string (ipx_route));
+ _LOGT (vtable->vt->addr_family, "%3d: STATE: added #%u - %s", ifindex, ipx_routes->entries->len - 1,
+ vtable->vt->route_to_string (ipx_route, NULL, 0));
}
g_ptr_array_unref (to_add_routes);
}
@@ -693,7 +697,7 @@ _vx_route_sync (const VTableIP *vtable, NMRouteManager *self, int ifindex, const
next:
_LOGT (vtable->vt->addr_family, "%3d: new metric #%u - %s (%lld)",
ifindex, i_ipx_routes,
- vtable->vt->route_to_string (cur_ipx_route),
+ vtable->vt->route_to_string (cur_ipx_route, NULL, 0),
(long long) *p_effective_metric);
}
}
@@ -716,7 +720,7 @@ next:
g_assert (cur_plat_route->rx.ifindex == ifindex);
- _LOGT (vtable->vt->addr_family, "%3d: platform rt #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route));
+ _LOGT (vtable->vt->addr_family, "%3d: platform rt #%u - %s", ifindex, i_plat_routes, vtable->vt->route_to_string (cur_plat_route, NULL, 0));
/* skip over @cur_ipx_route that are ordered before @cur_plat_route */
while ( cur_ipx_route
@@ -870,7 +874,7 @@ next:
_LOGD (vtable->vt->addr_family,
"ignore error adding IPv%c route to kernel: %s",
vtable->vt->is_ip4 ? '4' : '6',
- vtable->vt->route_to_string (cur_ipx_route));
+ vtable->vt->route_to_string (cur_ipx_route, NULL, 0));
} else {
/* Remember that there was a failure, but for now continue trying
* to sync the remaining routes. */
diff --git a/src/nm-types.h b/src/nm-types.h
index 2554d47e98..6dbd3b3b45 100644
--- a/src/nm-types.h
+++ b/src/nm-types.h
@@ -79,6 +79,8 @@ typedef struct _NMPlatformIP6Address NMPlatformIP6Address;
typedef struct _NMPlatformIP6Route NMPlatformIP6Route;
typedef struct _NMPlatformLink NMPlatformLink;
+typedef struct _NMPObject NMPObject;
+
typedef enum {
/* Please don't interpret type numbers outside nm-platform and use functions
* like nm_platform_link_is_software() and nm_platform_supports_slaves().
@@ -130,6 +132,13 @@ typedef enum {
NMP_OBJECT_TYPE_IP6_ADDRESS,
NMP_OBJECT_TYPE_IP4_ROUTE,
NMP_OBJECT_TYPE_IP6_ROUTE,
+
+ NMP_OBJECT_TYPE_LNK_GRE,
+ NMP_OBJECT_TYPE_LNK_INFINIBAND,
+ NMP_OBJECT_TYPE_LNK_MACVLAN,
+ NMP_OBJECT_TYPE_LNK_VLAN,
+ NMP_OBJECT_TYPE_LNK_VXLAN,
+
__NMP_OBJECT_TYPE_LAST,
NMP_OBJECT_TYPE_MAX = __NMP_OBJECT_TYPE_LAST - 1,
} NMPObjectType;
diff --git a/src/platform/nm-fake-platform.c b/src/platform/nm-fake-platform.c
index cbb9775714..a7c6b000ff 100644
--- a/src/platform/nm-fake-platform.c
+++ b/src/platform/nm-fake-platform.c
@@ -27,6 +27,7 @@
#include <linux/rtnetlink.h>
#include "nm-utils.h"
+#include "nmp-object.h"
#include "NetworkManagerUtils.h"
#include "nm-fake-platform.h"
#include "nm-default.h"
@@ -74,8 +75,7 @@ typedef struct {
NMPlatformLink link;
char *udi;
- int vlan_id;
- int ib_p_key;
+ NMPObject *lnk;
struct in6_addr ip6_lladdr;
} NMFakePlatformLink;
@@ -100,6 +100,14 @@ static gboolean ip6_address_delete (NMPlatform *platform, int ifindex, struct in
/******************************************************************/
static gboolean
+_ip4_address_equal_peer_net (in_addr_t peer1, in_addr_t peer2, int plen)
+{
+ return ((peer1 ^ peer2) & nm_utils_ip4_prefix_to_netmask (plen)) == 0;
+}
+
+/******************************************************************/
+
+static gboolean
sysctl_set (NMPlatform *platform, const char *path, const char *value)
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
@@ -252,6 +260,32 @@ _nm_platform_link_get_by_address (NMPlatform *platform,
return NULL;
}
+static const NMPObject *
+link_get_lnk (NMPlatform *platform,
+ int ifindex,
+ NMLinkType link_type,
+ const NMPlatformLink **out_link)
+{
+ NMFakePlatformLink *device = link_get (platform, ifindex);
+
+ if (!device)
+ return NULL;
+
+ NM_SET_OUT (out_link, &device->link);
+
+ if (!device->lnk)
+ return NULL;
+
+ if (link_type == NM_LINK_TYPE_NONE)
+ return device->lnk;
+
+ if ( link_type != device->link.type
+ || link_type != NMP_OBJECT_GET_CLASS (device->lnk)->lnk_link_type)
+ return NULL;
+
+ return device->lnk;
+}
+
static gboolean
link_add (NMPlatform *platform,
const char *name,
@@ -265,6 +299,12 @@ link_add (NMPlatform *platform,
link_init (&device, priv->links->len, type, name);
+ if (address) {
+ g_return_val_if_fail (address_len > 0 && address_len <= sizeof (device.link.addr.data), FALSE);
+ memcpy (device.link.addr.data, address, address_len);
+ device.link.addr.len = address_len;
+ }
+
g_array_append_val (priv->links, device);
if (device.link.ifindex) {
@@ -291,6 +331,8 @@ link_delete (NMPlatform *platform, int ifindex)
memcpy (&deleted_device, &device->link, sizeof (deleted_device));
memset (&device->link, 0, sizeof (device->link));
+ g_clear_pointer (&device->lnk, nmp_object_unref);
+ g_clear_pointer (&device->udi, g_free);
/* Remove addresses and routes which belong to the deleted interface */
for (i = 0; i < priv->ip4_addresses->len; i++) {
@@ -631,8 +673,10 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint
device = link_get (platform, nm_platform_link_get_ifindex (platform, name));
g_return_val_if_fail (device, FALSE);
+ g_return_val_if_fail (!device->lnk, FALSE);
- device->vlan_id = vlan_id;
+ device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
+ device->lnk->lnk_vlan.id = vlan_id;
device->link.parent = parent;
if (out_link)
@@ -641,30 +685,18 @@ vlan_add (NMPlatform *platform, const char *name, int parent, int vlan_id, guint
}
static gboolean
-vlan_get_info (NMPlatform *platform, int ifindex, int *parent, int *vlan_id)
+link_vlan_change (NMPlatform *platform,
+ int ifindex,
+ NMVlanFlags flags_mask,
+ NMVlanFlags flags_set,
+ gboolean ingress_reset_all,
+ const NMVlanQosMapping *ingress_map,
+ gsize n_ingress_map,
+ gboolean egress_reset_all,
+ const NMVlanQosMapping *egress_map,
+ gsize n_egress_map)
{
- NMFakePlatformLink *device = link_get (platform, ifindex);
-
- g_return_val_if_fail (device, FALSE);
-
- if (parent)
- *parent = device->link.parent;
- if (vlan_id)
- *vlan_id = device->vlan_id;
-
- return TRUE;
-}
-
-static gboolean
-vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to)
-{
- return !!link_get (platform, ifindex);
-}
-
-static gboolean
-vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to)
-{
- return !!link_get (platform, ifindex);
+ return FALSE;
}
static gboolean
@@ -682,63 +714,17 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatfor
device = link_get (platform, nm_platform_link_get_ifindex (platform, name));
g_return_val_if_fail (device, FALSE);
+ g_return_val_if_fail (!device->lnk, FALSE);
- device->ib_p_key = p_key;
+ device->lnk = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
+ device->lnk->lnk_infiniband.p_key = p_key;
+ device->lnk->lnk_infiniband.mode = "datagram";
device->link.parent = parent;
return TRUE;
}
static gboolean
-infiniband_get_info (NMPlatform *platform, int ifindex, int *parent, int *p_key, const char **mode)
-{
- NMFakePlatformLink *device;
-
- device = link_get (platform, ifindex);
- g_return_val_if_fail (device, FALSE);
- g_return_val_if_fail (device->link.type == NM_LINK_TYPE_INFINIBAND, FALSE);
-
- if (parent)
- *parent = device->link.parent;
- if (p_key)
- *p_key = device->ib_p_key;
- if (mode)
- *mode = "datagram";
-
- return TRUE;
-}
-
-static gboolean
-veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props)
-{
- return FALSE;
-}
-
-static gboolean
-tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *props)
-{
- return FALSE;
-}
-
-static gboolean
-macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProperties *props)
-{
- return FALSE;
-}
-
-static gboolean
-vxlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformVxlanProperties *props)
-{
- return FALSE;
-}
-
-static gboolean
-gre_get_properties (NMPlatform *platform, int ifindex, NMPlatformGreProperties *props)
-{
- return FALSE;
-}
-
-static gboolean
wifi_get_capabilities (NMPlatform *platform, int ifindex, NMDeviceWifiCapabilities *caps)
{
NMFakePlatformLink *device = link_get (platform, ifindex);
@@ -908,7 +894,7 @@ ip4_address_add (NMPlatform *platform,
address.source = NM_IP_CONFIG_SOURCE_KERNEL;
address.ifindex = ifindex;
address.address = addr;
- address.peer_address = peer_addr && peer_addr != addr ? peer_addr : 0;
+ address.peer_address = peer_addr;
address.plen = plen;
address.timestamp = nm_utils_get_monotonic_timestamp_s ();
address.lifetime = lifetime;
@@ -918,18 +904,19 @@ ip4_address_add (NMPlatform *platform,
for (i = 0; i < priv->ip4_addresses->len; i++) {
NMPlatformIP4Address *item = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
+ gboolean changed;
- if (item->ifindex != address.ifindex)
- continue;
- if (item->address != address.address)
- continue;
- if (item->plen != address.plen)
- continue;
- if (!nm_platform_ip4_address_equal_peer_net (item, &address))
+ if ( item->ifindex != address.ifindex
+ || item->address != address.address
+ || item->plen != address.plen
+ || !_ip4_address_equal_peer_net (item->peer_address, address.peer_address, address.plen))
continue;
+ changed = !nm_platform_ip4_address_cmp (item, &address);
+
memcpy (item, &address, sizeof (address));
- g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
+ if (changed)
+ g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP4_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
return TRUE;
}
@@ -965,18 +952,17 @@ ip6_address_add (NMPlatform *platform,
for (i = 0; i < priv->ip6_addresses->len; i++) {
NMPlatformIP6Address *item = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
+ gboolean changed;
- if (item->ifindex != address.ifindex)
- continue;
- if (!IN6_ARE_ADDR_EQUAL (&item->address, &address.address))
- continue;
- if (item->plen != address.plen)
+ if ( item->ifindex != address.ifindex
+ || !IN6_ARE_ADDR_EQUAL (&item->address, &address.address))
continue;
- if (nm_platform_ip6_address_cmp (item, &address) != 0) {
- memcpy (item, &address, sizeof (address));
+ changed = !nm_platform_ip6_address_cmp (item, &address);
+
+ memcpy (item, &address, sizeof (address));
+ if (changed)
g_signal_emit_by_name (platform, NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED, NMP_OBJECT_TYPE_IP6_ADDRESS, ifindex, &address, NM_PLATFORM_SIGNAL_CHANGED, NM_PLATFORM_REASON_INTERNAL);
- }
return TRUE;
}
@@ -995,8 +981,10 @@ ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen,
for (i = 0; i < priv->ip4_addresses->len; i++) {
NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
- if (address->ifindex == ifindex && address->plen == plen && address->address == addr &&
- (!peer_address || address->peer_address == peer_address)) {
+ if ( address->ifindex == ifindex
+ && address->plen == plen
+ && address->address == addr
+ && ((peer_address ^ address->peer_address) & nm_utils_ip4_prefix_to_netmask (plen)) == 0) {
NMPlatformIP4Address deleted_address;
memcpy (&deleted_address, address, sizeof (deleted_address));
@@ -1018,8 +1006,9 @@ ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int
for (i = 0; i < priv->ip6_addresses->len; i++) {
NMPlatformIP6Address *address = &g_array_index (priv->ip6_addresses, NMPlatformIP6Address, i);
- if (address->ifindex == ifindex && address->plen == plen
- && IN6_ARE_ADDR_EQUAL (&address->address, &addr)) {
+ if ( address->ifindex == ifindex
+ && address->plen == plen
+ && IN6_ARE_ADDR_EQUAL (&address->address, &addr)) {
NMPlatformIP6Address deleted_address;
memcpy (&deleted_address, address, sizeof (deleted_address));
@@ -1037,12 +1026,6 @@ ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in
{
NMFakePlatformPrivate *priv = NM_FAKE_PLATFORM_GET_PRIVATE (platform);
int i;
- NMPlatformIP4Address a = {
- .ifindex = ifindex,
- .address = addr,
- .plen = plen,
- .peer_address = peer_address,
- };
for (i = 0; i < priv->ip4_addresses->len; i++) {
NMPlatformIP4Address *address = &g_array_index (priv->ip4_addresses, NMPlatformIP4Address, i);
@@ -1050,7 +1033,7 @@ ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in
if ( address->ifindex == ifindex
&& address->plen == plen
&& address->address == addr
- && nm_platform_ip4_address_equal_peer_net (address, &a))
+ && _ip4_address_equal_peer_net (address->peer_address, peer_address, plen))
return address;
}
@@ -1407,6 +1390,7 @@ nm_fake_platform_finalize (GObject *object)
NMFakePlatformLink *device = &g_array_index (priv->links, NMFakePlatformLink, i);
g_free (device->udi);
+ g_clear_pointer (&device->lnk, nmp_object_unref);
}
g_array_unref (priv->links);
g_array_unref (priv->ip4_addresses);
@@ -1439,6 +1423,8 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->link_delete = link_delete;
platform_class->link_get_type_name = link_get_type_name;
+ platform_class->link_get_lnk = link_get_lnk;
+
platform_class->link_get_udi = link_get_udi;
platform_class->link_set_up = link_set_up;
@@ -1462,18 +1448,9 @@ nm_fake_platform_class_init (NMFakePlatformClass *klass)
platform_class->slave_get_option = slave_get_option;
platform_class->vlan_add = vlan_add;
- platform_class->vlan_get_info = vlan_get_info;
- platform_class->vlan_set_ingress_map = vlan_set_ingress_map;
- platform_class->vlan_set_egress_map = vlan_set_egress_map;
+ platform_class->link_vlan_change = link_vlan_change;
platform_class->infiniband_partition_add = infiniband_partition_add;
- platform_class->infiniband_get_info = infiniband_get_info;
-
- platform_class->veth_get_properties = veth_get_properties;
- platform_class->tun_get_properties = tun_get_properties;
- platform_class->macvlan_get_properties = macvlan_get_properties;
- platform_class->vxlan_get_properties = vxlan_get_properties;
- platform_class->gre_get_properties = gre_get_properties;
platform_class->wifi_get_capabilities = wifi_get_capabilities;
platform_class->wifi_get_bssid = wifi_get_bssid;
diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c
index ed8918be61..b07afc1d45 100644
--- a/src/platform/nm-linux-platform.c
+++ b/src/platform/nm-linux-platform.c
@@ -40,16 +40,6 @@
#include <netlink/route/route.h>
#include <gudev/gudev.h>
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE || HAVE_LIBNL_INET6_TOKEN
-#include <netlink/route/link/inet6.h>
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE && HAVE_KERNEL_INET6_ADDR_GEN_MODE
-#include <linux/if_link.h>
-#else
-#define IN6_ADDR_GEN_MODE_EUI64 0
-#define IN6_ADDR_GEN_MODE_NONE 1
-#endif
-#endif
-
#include "nm-core-internal.h"
#include "NetworkManagerUtils.h"
#include "nm-linux-platform.h"
@@ -68,6 +58,39 @@
/*********************************************************************************************/
+#define IFQDISCSIZ 32
+
+/*********************************************************************************************/
+
+#ifndef IFLA_PROMISCUITY
+#define IFLA_PROMISCUITY 30
+#endif
+#define IFLA_NUM_TX_QUEUES 31
+#define IFLA_NUM_RX_QUEUES 32
+#define IFLA_CARRIER 33
+#define IFLA_PHYS_PORT_ID 34
+#define IFLA_LINK_NETNSID 37
+#define __IFLA_MAX 39
+
+#define IFLA_INET6_TOKEN 7
+#define IFLA_INET6_ADDR_GEN_MODE 8
+#define __IFLA_INET6_MAX 9
+
+#define IFLA_VLAN_PROTOCOL 5
+#define __IFLA_VLAN_MAX 6
+
+#define IFA_FLAGS 8
+#define __IFA_MAX 9
+
+#define IFLA_MACVLAN_FLAGS 2
+#define __IFLA_MACVLAN_MAX 3
+
+#ifndef MACVLAN_FLAG_NOPROMISC
+#define MACVLAN_FLAG_NOPROMISC 1
+#endif
+
+/*********************************************************************************************/
+
#define _NMLOG_PREFIX_NAME "platform-linux"
#define _NMLOG_DOMAIN LOGD_PLATFORM
#define _NMLOG2_DOMAIN LOGD_PLATFORM
@@ -119,433 +142,38 @@ typedef enum {
DELAYED_ACTION_TYPE_MAX = __DELAYED_ACTION_TYPE_MAX -1,
} DelayedActionType;
-static gboolean tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props);
static void delayed_action_schedule (NMPlatform *platform, DelayedActionType action_type, gpointer user_data);
static gboolean delayed_action_handle_all (NMPlatform *platform, gboolean read_netlink);
static void do_request_link (NMPlatform *platform, int ifindex, const char *name, gboolean handle_delayed_action);
static void do_request_all (NMPlatform *platform, DelayedActionType action_type, gboolean handle_delayed_action);
static void cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMPCacheOpsType ops_type, gpointer user_data);
static gboolean event_handler_read_netlink_all (NMPlatform *platform, gboolean wait_for_acks);
-static NMPCacheOpsType cache_remove_netlink (NMPlatform *platform, const NMPObject *obj_needle, NMPObject **out_obj_cache, gboolean *out_was_visible, NMPlatformReason reason);
+static NMPCacheOpsType cache_remove_netlink (NMPlatform *platform, const NMPObject *obj_id, NMPObject **out_obj_cache, gboolean *out_was_visible, NMPlatformReason reason);
/******************************************************************
- * libnl unility functions and wrappers
+ * Support IFLA_INET6_ADDR_GEN_MODE
******************************************************************/
-struct libnl_vtable
-{
- void *handle;
- void *handle_route;
-
- int (*f_nl_has_capability) (int capability);
- int (*f_rtnl_link_get_link_netnsid) (const struct rtnl_link *link, gint32 *out_link_netnsid);
-};
-
-static int
-_nl_f_nl_has_capability (int capability)
-{
- return FALSE;
-}
-
-static const struct libnl_vtable *
-_nl_get_vtable (void)
-{
- static struct libnl_vtable vtable;
-
- if (G_UNLIKELY (!vtable.f_nl_has_capability)) {
- vtable.handle = dlopen ("libnl-3.so.200", RTLD_LAZY | RTLD_NOLOAD);
- if (vtable.handle) {
- vtable.f_nl_has_capability = dlsym (vtable.handle, "nl_has_capability");
- }
- vtable.handle_route = dlopen ("libnl-route-3.so.200", RTLD_LAZY | RTLD_NOLOAD);
- if (vtable.handle_route) {
- vtable.f_rtnl_link_get_link_netnsid = dlsym (vtable.handle_route, "rtnl_link_get_link_netnsid");
- }
-
- if (!vtable.f_nl_has_capability)
- vtable.f_nl_has_capability = &_nl_f_nl_has_capability;
-
- _LOG2t ("libnl: rtnl_link_get_link_netnsid() %s", vtable.f_rtnl_link_get_link_netnsid ? "supported" : "not supported");
-
- g_return_val_if_fail (vtable.handle, &vtable);
- g_return_val_if_fail (vtable.handle_route, &vtable);
- }
-
- return &vtable;
-}
-
-static gboolean
-_nl_has_capability (int capability)
-{
- return (_nl_get_vtable ()->f_nl_has_capability) (capability);
-}
-
-static int
-_rtnl_link_get_link_netnsid (const struct rtnl_link *link, gint32 *out_link_netnsid)
-{
- const struct libnl_vtable *vtable;
-
- g_return_val_if_fail (link, -NLE_INVAL);
- g_return_val_if_fail (out_link_netnsid, -NLE_INVAL);
-
- vtable = _nl_get_vtable ();
- return vtable->f_rtnl_link_get_link_netnsid
- ? vtable->f_rtnl_link_get_link_netnsid (link, out_link_netnsid)
- : -NLE_OPNOTSUPP;
-}
-
-gboolean
-nm_platform_check_support_libnl_link_netnsid (void)
-{
- return !!(_nl_get_vtable ()->f_rtnl_link_get_link_netnsid);
-}
-
-/* Automatic deallocation of local variables */
-#define auto_nl_object __attribute__((cleanup(_nl_auto_nl_object)))
-static void
-_nl_auto_nl_object (void *ptr)
-{
- struct nl_object **object = ptr;
-
- if (object && *object) {
- nl_object_put (*object);
- *object = NULL;
- }
-}
-
-#define auto_nl_addr __attribute__((cleanup(_nl_auto_nl_addr)))
-static void
-_nl_auto_nl_addr (void *ptr)
-{
- struct nl_addr **object = ptr;
-
- if (object && *object) {
- nl_addr_put (*object);
- *object = NULL;
- }
-}
-
-/* wrap the libnl alloc functions and abort on out-of-memory*/
-
-static struct nl_addr *
-_nl_addr_build (int family, const void *buf, size_t size)
-{
- struct nl_addr *addr;
-
- addr = nl_addr_build (family, (void *) buf, size);
- if (!addr)
- g_error ("nl_addr_build() failed with out of memory");
-
- return addr;
-}
-
-static struct rtnl_link *
-_nl_rtnl_link_alloc (int ifindex, const char*name)
-{
- struct rtnl_link *rtnllink;
-
- rtnllink = rtnl_link_alloc ();
- if (!rtnllink)
- g_error ("rtnl_link_alloc() failed with out of memory");
-
- if (ifindex > 0)
- rtnl_link_set_ifindex (rtnllink, ifindex);
- if (name)
- rtnl_link_set_name (rtnllink, name);
- return rtnllink;
-}
-
-static struct rtnl_addr *
-_nl_rtnl_addr_alloc (int ifindex)
-{
- struct rtnl_addr *rtnladdr;
-
- rtnladdr = rtnl_addr_alloc ();
- if (!rtnladdr)
- g_error ("rtnl_addr_alloc() failed with out of memory");
- if (ifindex > 0)
- rtnl_addr_set_ifindex (rtnladdr, ifindex);
- return rtnladdr;
-}
-
-static struct rtnl_route *
-_nl_rtnl_route_alloc (void)
-{
- struct rtnl_route *rtnlroute = rtnl_route_alloc ();
-
- if (!rtnlroute)
- g_error ("rtnl_route_alloc() failed with out of memory");
- return rtnlroute;
-}
-
-static struct rtnl_nexthop *
-_nl_rtnl_route_nh_alloc (void)
-{
- struct rtnl_nexthop *nexthop;
-
- nexthop = rtnl_route_nh_alloc ();
- if (!nexthop)
- g_error ("rtnl_route_nh_alloc () failed with out of memory");
- return nexthop;
-}
-
-/* rtnl_addr_set_prefixlen fails to update the nl_addr prefixlen */
-static void
-_nl_rtnl_addr_set_prefixlen (struct rtnl_addr *rtnladdr, int plen)
-{
- struct nl_addr *nladdr;
-
- rtnl_addr_set_prefixlen (rtnladdr, plen);
-
- nladdr = rtnl_addr_get_local (rtnladdr);
- if (nladdr)
- nl_addr_set_prefixlen (nladdr, plen);
-}
-
-static const char *
-_nl_nlmsg_type_to_str (guint16 type, char *buf, gsize len)
-{
- const char *str_type = NULL;
-
- switch (type) {
- case RTM_NEWLINK: str_type = "NEWLINK"; break;
- case RTM_DELLINK: str_type = "DELLINK"; break;
- case RTM_NEWADDR: str_type = "NEWADDR"; break;
- case RTM_DELADDR: str_type = "DELADDR"; break;
- case RTM_NEWROUTE: str_type = "NEWROUTE"; break;
- case RTM_DELROUTE: str_type = "DELROUTE"; break;
- }
- if (str_type)
- g_strlcpy (buf, str_type, len);
- else
- g_snprintf (buf, len, "(%d)", type);
- return buf;
-}
-
-/******************************************************************/
-
-/* _nl_link_parse_info_data(): Re-fetches a link from the kernel
- * and parses its IFLA_INFO_DATA using a caller-provided parser.
- *
- * Code is stolen from rtnl_link_get_kernel(), nl_pickup(), and link_msg_parser().
- */
-
-typedef int (*NMNLInfoDataParser) (struct nlattr *info_data, gpointer parser_data);
-
-typedef struct {
- NMNLInfoDataParser parser;
- gpointer parser_data;
-} NMNLInfoDataClosure;
-
-static struct nla_policy info_data_link_policy[IFLA_MAX + 1] = {
- [IFLA_LINKINFO] = { .type = NLA_NESTED },
-};
-
-static struct nla_policy info_data_link_info_policy[IFLA_INFO_MAX + 1] = {
- [IFLA_INFO_DATA] = { .type = NLA_NESTED },
-};
-
-static int
-_nl_link_parse_info_data_cb (struct nl_msg *msg, void *arg)
-{
- NMNLInfoDataClosure *closure = arg;
- struct nlmsghdr *n = nlmsg_hdr (msg);
- struct nlattr *tb[IFLA_MAX + 1];
- struct nlattr *li[IFLA_INFO_MAX + 1];
- int err;
-
- if (!nlmsg_valid_hdr (n, sizeof (struct ifinfomsg)))
- return -NLE_MSG_TOOSHORT;
-
- err = nlmsg_parse (n, sizeof (struct ifinfomsg), tb, IFLA_MAX, info_data_link_policy);
- if (err < 0)
- return err;
-
- if (!tb[IFLA_LINKINFO])
- return -NLE_MISSING_ATTR;
-
- err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], info_data_link_info_policy);
- if (err < 0)
- return err;
-
- if (!li[IFLA_INFO_DATA])
- return -NLE_MISSING_ATTR;
-
- return closure->parser (li[IFLA_INFO_DATA], closure->parser_data);
-}
-
-static int
-_nl_link_parse_info_data (struct nl_sock *sk, int ifindex,
- NMNLInfoDataParser parser, gpointer parser_data)
-{
- NMNLInfoDataClosure data = { .parser = parser, .parser_data = parser_data };
- struct nl_msg *msg = NULL;
- struct nl_cb *cb;
- int err;
-
- err = rtnl_link_build_get_request (ifindex, NULL, &msg);
- if (err < 0)
- return err;
-
- err = nl_send_auto (sk, msg);
- nlmsg_free (msg);
- if (err < 0)
- return err;
-
- cb = nl_cb_clone (nl_socket_get_cb (sk));
- if (cb == NULL)
- return -NLE_NOMEM;
- nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, _nl_link_parse_info_data_cb, &data);
-
- err = nl_recvmsgs (sk, cb);
- nl_cb_put (cb);
- if (err < 0)
- return err;
-
- nl_wait_for_ack (sk);
- return 0;
-}
-
-/******************************************************************/
-
-static int
-_nl_sock_flush_data (struct nl_sock *sk)
-{
- int nle;
- struct nl_cb *cb;
-
- cb = nl_cb_clone (nl_socket_get_cb (sk));
- if (cb == NULL)
- return -NLE_NOMEM;
-
- nl_cb_set (cb, NL_CB_VALID, NL_CB_DEFAULT, NULL, NULL);
- nl_cb_set (cb, NL_CB_SEQ_CHECK, NL_CB_DEFAULT, NULL, NULL);
- nl_cb_err (cb, NL_CB_DEFAULT, NULL, NULL);
- do {
- errno = 0;
-
- nle = nl_recvmsgs (sk, cb);
-
- /* Work around a libnl bug fixed in 3.2.22 (375a6294) */
- if (nle == 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
- nle = -NLE_AGAIN;
- } while (nle != -NLE_AGAIN);
-
- nl_cb_put (cb);
- return nle;
-}
-
-static void
-_nl_msg_set_seq (struct nl_sock *sk, struct nl_msg *msg, guint32 *out_seq)
-{
- guint32 seq;
-
- /* choose our own sequence number, because libnl does not ensure that
- * it isn't zero -- which would confuse our checking for outstanding
- * messages. */
- seq = nl_socket_use_seq (sk);
- if (seq == 0)
- seq = nl_socket_use_seq (sk);
-
- nlmsg_hdr (msg)->nlmsg_seq = seq;
- if (out_seq)
- *out_seq = seq;
-}
-
-static int
-_nl_sock_request_link (NMPlatform *platform, struct nl_sock *sk, int ifindex, const char *name, guint32 *out_seq)
-{
- struct nl_msg *msg = NULL;
- int err;
-
- if (name && !name[0])
- name = NULL;
-
- g_return_val_if_fail (ifindex > 0 || name, -NLE_INVAL);
-
- _LOGT ("sock: request-link %d%s%s%s", ifindex, name ? ", \"" : "", name ? name : "", name ? "\"" : "");
-
- if ((err = rtnl_link_build_get_request (ifindex, name, &msg)) < 0)
- return err;
-
- _nl_msg_set_seq (sk, msg, out_seq);
-
- err = nl_send_auto (sk, msg);
- nlmsg_free(msg);
- if (err < 0)
- return err;
-
- return 0;
-}
-
-static int
-_nl_sock_request_all (NMPlatform *platform, struct nl_sock *sk, NMPObjectType obj_type, guint32 *out_seq)
-{
- const NMPClass *klass;
- struct rtgenmsg gmsg = { 0 };
- struct nl_msg *msg;
- int err;
-
- klass = nmp_class_from_type (obj_type);
-
- _LOGT ("sock: request-all-%s", klass->obj_type_name);
-
- /* reimplement
- * nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP);
- * because we need the sequence number.
- */
- msg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP);
- if (!msg)
- return -NLE_NOMEM;
-
- gmsg.rtgen_family = klass->addr_family;
- err = nlmsg_append (msg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO);
- if (err < 0)
- goto errout;
-
- _nl_msg_set_seq (sk, msg, out_seq);
-
- err = nl_send_auto (sk, msg);
-errout:
- nlmsg_free(msg);
-
- return err >= 0 ? 0 : err;
-}
-
-/******************************************************************/
-
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
static int _support_user_ipv6ll = 0;
#define _support_user_ipv6ll_still_undecided() (G_UNLIKELY (_support_user_ipv6ll == 0))
-#else
-#define _support_user_ipv6ll_still_undecided() (FALSE)
-#endif
static gboolean
_support_user_ipv6ll_get (void)
{
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
if (_support_user_ipv6ll_still_undecided ()) {
_support_user_ipv6ll = -1;
_LOG2W ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "failed to detect; assume no support");
- } else
- return _support_user_ipv6ll > 0;
-#endif
+ return FALSE;
+ }
+ return _support_user_ipv6ll > 0;
- return FALSE;
}
static void
-_support_user_ipv6ll_detect (const struct rtnl_link *rtnl_link)
+_support_user_ipv6ll_detect (struct nlattr **tb)
{
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
- /* If we ever see a link with valid IPv6 link-local address
- * generation modes, the kernel supports it.
- */
if (_support_user_ipv6ll_still_undecided ()) {
- uint8_t mode;
-
- if (rtnl_link_inet6_get_addr_gen_mode ((struct rtnl_link *) rtnl_link, &mode) == 0) {
+ if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
_support_user_ipv6ll = 1;
_LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "detected");
} else {
@@ -553,54 +181,23 @@ _support_user_ipv6ll_detect (const struct rtnl_link *rtnl_link)
_LOG2D ("kernel support for IFLA_INET6_ADDR_GEN_MODE %s", "not detected");
}
}
-#endif
}
-/******************************************************************/
-
-static int _support_kernel_extended_ifa_flags = 0;
-
-#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == 0))
-
-static void
-_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
-{
- struct nlmsghdr *msg_hdr;
-
- if (!_support_kernel_extended_ifa_flags_still_undecided ())
- return;
-
- msg_hdr = nlmsg_hdr (msg);
- if (msg_hdr->nlmsg_type != RTM_NEWADDR)
- return;
+/******************************************************************
+ * Various utilities
+ ******************************************************************/
- /* the extended address flags are only set for AF_INET6 */
- if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6)
- return;
+const NMIPAddr nm_ip_addr_zero = NMIPAddrInit;
- /* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
- * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
- * and IFA_F_NOPREFIXROUTE (they were added together).
- **/
- _support_kernel_extended_ifa_flags =
- nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */)
- ? 1 : -1;
-}
+#define IPV4LL_NETWORK (htonl (0xA9FE0000L))
+#define IPV4LL_NETMASK (htonl (0xFFFF0000L))
static gboolean
-_support_kernel_extended_ifa_flags_get (void)
+ip4_address_is_link_local (in_addr_t addr)
{
- if (_support_kernel_extended_ifa_flags_still_undecided ()) {
- _LOG2W ("Unable to detect kernel support for extended IFA_FLAGS. Assume no kernel support.");
- _support_kernel_extended_ifa_flags = -1;
- }
- return _support_kernel_extended_ifa_flags > 0;
+ return (addr & IPV4LL_NETMASK) == IPV4LL_NETWORK;
}
-/******************************************************************
- * Object type specific utilities
- ******************************************************************/
-
static guint
_nm_ip_config_source_to_rtprot (NMIPConfigSource source)
{
@@ -640,7 +237,46 @@ _nm_ip_config_source_from_rtprot (guint rtprot)
}
}
-/******************************************************************/
+static void
+clear_host_address (int family, const void *network, int plen, void *dst)
+{
+ g_return_if_fail (plen == (guint8)plen);
+ g_return_if_fail (network);
+
+ switch (family) {
+ case AF_INET:
+ *((in_addr_t *) dst) = nm_utils_ip4_address_clear_host_address (*((in_addr_t *) network), plen);
+ break;
+ case AF_INET6:
+ nm_utils_ip6_address_clear_host_address ((struct in6_addr *) dst, (const struct in6_addr *) network, plen);
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static int
+_vlan_qos_mapping_cmp_from (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ const NMVlanQosMapping *map_a = a;
+ const NMVlanQosMapping *map_b = b;
+
+ if (map_a->from != map_b->from)
+ return map_a->from < map_b->from ? -1 : 1;
+ return 0;
+}
+
+static int
+_vlan_qos_mapping_cmp_from_ptr (gconstpointer a, gconstpointer b, gpointer user_data)
+{
+ return _vlan_qos_mapping_cmp_from (*((const NMVlanQosMapping **) a),
+ *((const NMVlanQosMapping **) b),
+ NULL);
+}
+
+/******************************************************************
+ * NMLinkType functions
+ ******************************************************************/
typedef struct {
const NMLinkType nm_type;
@@ -719,129 +355,172 @@ nm_link_type_to_string (NMLinkType type)
}
/******************************************************************
- * NMPlatform types and functions
+ * Utilities
******************************************************************/
-typedef struct _NMLinuxPlatformPrivate NMLinuxPlatformPrivate;
+/* _timestamp_nl_to_ms:
+ * @timestamp_nl: a timestamp from ifa_cacheinfo.
+ * @monotonic_ms: *now* in CLOCK_MONOTONIC. Needed to estimate the current
+ * uptime and how often timestamp_nl wrapped.
+ *
+ * Convert the timestamp from ifa_cacheinfo to CLOCK_MONOTONIC milliseconds.
+ * The ifa_cacheinfo fields tstamp and cstamp contains timestamps that counts
+ * with in 1/100th of a second of clock_gettime(CLOCK_MONOTONIC). However,
+ * the uint32 counter wraps every 497 days of uptime, so we have to compensate
+ * for that. */
+static gint64
+_timestamp_nl_to_ms (guint32 timestamp_nl, gint64 monotonic_ms)
+{
+ const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100);
+ gint64 timestamp_nl_ms;
-struct _NMLinuxPlatformPrivate {
- struct nl_sock *nlh;
- struct nl_sock *nlh_event;
- guint32 nlh_seq_expect;
- guint32 nlh_seq_last;
- NMPCache *cache;
- GIOChannel *event_channel;
- guint event_id;
+ /* convert timestamp from 1/100th of a second to msec. */
+ timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100);
- gboolean sysctl_get_warned;
- GHashTable *sysctl_get_prev_values;
+ /* timestamp wraps every 497 days. Try to compensate for that.*/
+ if (timestamp_nl_ms > monotonic_ms) {
+ /* timestamp_nl_ms is in the future. Truncate it to *now* */
+ timestamp_nl_ms = monotonic_ms;
+ } else if (monotonic_ms >= WRAP_INTERVAL) {
+ timestamp_nl_ms += (monotonic_ms / WRAP_INTERVAL) * WRAP_INTERVAL;
+ if (timestamp_nl_ms > monotonic_ms)
+ timestamp_nl_ms -= WRAP_INTERVAL;
+ }
- GUdevClient *udev_client;
+ return timestamp_nl_ms;
+}
- struct {
- DelayedActionType flags;
- GPtrArray *list_master_connected;
- GPtrArray *list_refresh_link;
- gint is_handling;
- guint idle_id;
- } delayed_action;
+static guint32
+_addrtime_timestamp_to_nm (guint32 timestamp, gint32 *out_now_nm)
+{
+ struct timespec tp;
+ gint64 now_nl, now_nm, result;
+ int err;
- GHashTable *prune_candidates;
- GHashTable *delayed_deletion;
+ /* timestamp is unset. Default to 1. */
+ if (!timestamp) {
+ if (out_now_nm)
+ *out_now_nm = 0;
+ return 1;
+ }
- GHashTable *wifi_data;
-};
+ /* do all the calculations in milliseconds scale */
-static inline NMLinuxPlatformPrivate *
-NM_LINUX_PLATFORM_GET_PRIVATE (const void *self)
-{
- nm_assert (NM_IS_LINUX_PLATFORM (self));
+ err = clock_gettime (CLOCK_MONOTONIC, &tp);
+ g_assert (err == 0);
+ now_nm = nm_utils_get_monotonic_timestamp_ms ();
+ now_nl = (((gint64) tp.tv_sec) * ((gint64) 1000)) +
+ (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000));
- return ((NMLinuxPlatform *) self)->priv;
-}
+ result = now_nm - (now_nl - _timestamp_nl_to_ms (timestamp, now_nl));
-G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
+ if (out_now_nm)
+ *out_now_nm = now_nm / 1000;
-void
-nm_linux_platform_setup (void)
-{
- g_object_new (NM_TYPE_LINUX_PLATFORM,
- NM_PLATFORM_REGISTER_SINGLETON, TRUE,
- NULL);
-}
+ /* converting the timestamp into nm_utils_get_monotonic_timestamp_ms() scale is
+ * a good guess but fails in the following situations:
+ *
+ * - If the address existed before start of the process, the timestamp in nm scale would
+ * be negative or zero. In this case we default to 1.
+ * - during hibernation, the CLOCK_MONOTONIC/timestamp drifts from
+ * nm_utils_get_monotonic_timestamp_ms() scale.
+ */
+ if (result <= 1000)
+ return 1;
-/******************************************************************/
+ if (result > now_nm)
+ return now_nm / 1000;
+
+ return result / 1000;
+}
-NMPObjectType
-_nlo_get_object_type (const struct nl_object *object)
+static guint32
+_addrtime_extend_lifetime (guint32 lifetime, guint32 seconds)
{
- const char *type_str;
+ guint64 v;
- if (!object || !(type_str = nl_object_get_type (object)))
- return NMP_OBJECT_TYPE_UNKNOWN;
+ if ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT
+ || seconds == 0)
+ return lifetime;
- if (!strcmp (type_str, "route/link"))
- return NMP_OBJECT_TYPE_LINK;
- else if (!strcmp (type_str, "route/addr")) {
- switch (rtnl_addr_get_family ((struct rtnl_addr *) object)) {
- case AF_INET:
- return NMP_OBJECT_TYPE_IP4_ADDRESS;
- case AF_INET6:
- return NMP_OBJECT_TYPE_IP6_ADDRESS;
- default:
- return NMP_OBJECT_TYPE_UNKNOWN;
- }
- } else if (!strcmp (type_str, "route/route")) {
- switch (rtnl_route_get_family ((struct rtnl_route *) object)) {
- case AF_INET:
- return NMP_OBJECT_TYPE_IP4_ROUTE;
- case AF_INET6:
- return NMP_OBJECT_TYPE_IP6_ROUTE;
- default:
- return NMP_OBJECT_TYPE_UNKNOWN;
- }
- } else
- return NMP_OBJECT_TYPE_UNKNOWN;
+ v = (guint64) lifetime + (guint64) seconds;
+ return MIN (v, NM_PLATFORM_LIFETIME_PERMANENT - 1);
}
-/******************************************************************/
-
-static gboolean
-check_support_kernel_extended_ifa_flags (NMPlatform *platform)
+/* The rtnl_addr object contains relative lifetimes @valid and @preferred
+ * that count in seconds, starting from the moment when the kernel constructed
+ * the netlink message.
+ *
+ * There is also a field rtnl_addr_last_update_time(), which is the absolute
+ * time in 1/100th of a second of clock_gettime (CLOCK_MONOTONIC) when the address
+ * was modified (wrapping every 497 days).
+ * Immediately at the time when the address was last modified, #NOW and @last_update_time
+ * are the same, so (only) in that case @valid and @preferred are anchored at @last_update_time.
+ * However, this is not true in general. As time goes by, whenever kernel sends a new address
+ * via netlink, the lifetimes keep counting down.
+ **/
+static void
+_addrtime_get_lifetimes (guint32 timestamp,
+ guint32 lifetime,
+ guint32 preferred,
+ guint32 *out_timestamp,
+ guint32 *out_lifetime,
+ guint32 *out_preferred)
{
- g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
+ gint32 now;
- return _support_kernel_extended_ifa_flags_get ();
-}
+ if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT
+ || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
+ if (preferred > lifetime)
+ preferred = lifetime;
+ timestamp = _addrtime_timestamp_to_nm (timestamp, &now);
-static gboolean
-check_support_user_ipv6ll (NMPlatform *platform)
-{
- g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
+ if (now == 0) {
+ /* strange. failed to detect the last-update time and assumed that timestamp is 1. */
+ nm_assert (timestamp == 1);
+ now = nm_utils_get_monotonic_timestamp_s ();
+ }
+ if (timestamp < now) {
+ guint32 diff = now - timestamp;
- return _support_user_ipv6ll_get ();
+ lifetime = _addrtime_extend_lifetime (lifetime, diff);
+ preferred = _addrtime_extend_lifetime (preferred, diff);
+ } else
+ nm_assert (timestamp == now);
+ } else
+ timestamp = 0;
+ *out_timestamp = timestamp;
+ *out_lifetime = lifetime;
+ *out_preferred = preferred;
}
-static void
-process_events (NMPlatform *platform)
+/******************************************************************/
+
+static const NMPObject *
+_lookup_cached_link (const NMPCache *cache, int ifindex, gboolean *completed_from_cache, const NMPObject **link_cached)
{
- delayed_action_handle_all (platform, TRUE);
-}
+ const NMPObject *obj;
-/******************************************************************/
+ nm_assert (completed_from_cache && link_cached);
-#define cache_lookup_all_objects(type, platform, obj_type, visible_only) \
- ((const type *const*) nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE ((platform))->cache, \
- nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, (obj_type), (visible_only)), \
- NULL))
+ if (!*completed_from_cache) {
+ obj = ifindex > 0 && cache ? nmp_cache_lookup_link (cache, ifindex) : NULL;
+ if (obj && !obj->_link.netlink.is_in_netlink)
+ *link_cached = obj;
+ else
+ *link_cached = NULL;
+ *completed_from_cache = TRUE;
+ }
+ return *link_cached;
+}
/******************************************************************/
#define DEVTYPE_PREFIX "DEVTYPE="
static char *
-read_devtype (const char *sysfs_path)
+_linktype_read_devtype (const char *sysfs_path)
{
gs_free char *uevent = g_strdup_printf ("%s/uevent", sysfs_path);
char *contents = NULL;
@@ -863,69 +542,63 @@ read_devtype (const char *sysfs_path)
return NULL;
}
-static const NMPObject *
-_lookup_link_cached (NMPlatform *platform, int ifindex, gboolean *completed_from_cache, const NMPObject **link_cached)
-{
- const NMPObject *obj;
-
- nm_assert (completed_from_cache && link_cached);
-
- if (!*completed_from_cache) {
- obj = ifindex > 0 ? nmp_cache_lookup_link (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, ifindex) : NULL;
-
- if (obj && !obj->_link.netlink.is_in_netlink)
- *link_cached = obj;
- else
- *link_cached = NULL;
- *completed_from_cache = TRUE;
- }
- return *link_cached;
-}
-
static NMLinkType
-link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, gboolean *completed_from_cache, const NMPObject **link_cached, const char **out_kind)
+_linktype_get_type (NMPlatform *platform,
+ const NMPCache *cache,
+ const char *kind,
+ int ifindex,
+ const char *ifname,
+ unsigned flags,
+ unsigned arptype,
+ gboolean *completed_from_cache,
+ const NMPObject **link_cached,
+ const char **out_kind)
{
- const char *rtnl_type, *ifname;
- int i, arptype;
-
- if (!rtnllink) {
- if (out_kind)
- *out_kind = NULL;
- return NM_LINK_TYPE_NONE;
- }
+ guint i;
- rtnl_type = rtnl_link_get_type (rtnllink);
- if (!rtnl_type && completed_from_cache) {
+ if (completed_from_cache) {
const NMPObject *obj;
- obj = _lookup_link_cached (platform, rtnl_link_get_ifindex (rtnllink), completed_from_cache, link_cached);
- if (obj && obj->link.kind) {
- rtnl_type = obj->link.kind;
- _LOGT ("link_extract_type(): complete kind from cache: ifindex=%d, kind=%s", rtnl_link_get_ifindex (rtnllink), rtnl_type);
+ obj = _lookup_cached_link (cache, ifindex, completed_from_cache, link_cached);
+
+ /* If we detected the link type before, we stick to that
+ * decision unless the "kind" changed.
+ *
+ * This way, we save edditional ethtool/sysctl lookups, but moreover,
+ * we keep the linktype stable and don't change it as long as the link
+ * exists.
+ *
+ * Note that kernel *can* reuse the ifindex (on integer overflow, and
+ * when moving interfce to other netns). Thus here there is a tiny potential
+ * of messing stuff up. */
+ if ( obj
+ && !NM_IN_SET (obj->link.type, NM_LINK_TYPE_UNKNOWN, NM_LINK_TYPE_NONE)
+ && ( !kind
+ || !g_strcmp0 (kind, obj->link.kind))) {
+ nm_assert (obj->link.kind == g_intern_string (obj->link.kind));
+ *out_kind = obj->link.kind;
+ return obj->link.type;
}
}
- if (out_kind)
- *out_kind = rtnl_type;
- if (rtnl_type) {
+
+ *out_kind = g_intern_string (kind);
+
+ if (kind) {
for (i = 0; i < G_N_ELEMENTS (linktypes); i++) {
- if (g_strcmp0 (rtnl_type, linktypes[i].rtnl_type) == 0)
+ if (g_strcmp0 (kind, linktypes[i].rtnl_type) == 0)
return linktypes[i].nm_type;
}
- if (!strcmp (rtnl_type, "tun")) {
+ if (!strcmp (kind, "tun")) {
NMPlatformTunProperties props;
- guint flags;
- if (tun_get_properties_ifname (platform, rtnl_link_get_name (rtnllink), &props)) {
+ if ( platform
+ && nm_platform_tun_get_properties_ifname (platform, ifname, &props)) {
if (!g_strcmp0 (props.mode, "tap"))
return NM_LINK_TYPE_TAP;
if (!g_strcmp0 (props.mode, "tun"))
return NM_LINK_TYPE_TUN;
}
- flags = rtnl_link_get_flags (rtnllink);
-
- _LOGD ("Failed to read tun properties for interface %d (link flags: %X)",
- rtnl_link_get_ifindex (rtnllink), flags);
/* try guessing the type using the link flags instead... */
if (flags & IFF_POINTOPOINT)
@@ -934,13 +607,11 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, gboolean *c
}
}
- arptype = rtnl_link_get_arptype (rtnllink);
if (arptype == ARPHRD_LOOPBACK)
return NM_LINK_TYPE_LOOPBACK;
else if (arptype == ARPHRD_INFINIBAND)
return NM_LINK_TYPE_INFINIBAND;
- ifname = rtnl_link_get_name (rtnllink);
if (ifname) {
gs_free char *driver = NULL;
gs_free char *sysfs_path = NULL;
@@ -966,7 +637,7 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, gboolean *c
if (g_file_test (anycast_mask, G_FILE_TEST_EXISTS))
return NM_LINK_TYPE_OLPC_MESH;
- devtype = read_devtype (sysfs_path);
+ devtype = _linktype_read_devtype (sysfs_path);
for (i = 0; devtype && i < G_N_ELEMENTS (linktypes); i++) {
if (g_strcmp0 (devtype, linktypes[i].devtype) == 0) {
if (linktypes[i].nm_type == NM_LINK_TYPE_BNEP) {
@@ -989,366 +660,1004 @@ link_extract_type (NMPlatform *platform, struct rtnl_link *rtnllink, gboolean *c
* prevent future virtual network drivers from being treated as Ethernet
* when they should be Generic instead.
*/
- if (arptype == ARPHRD_ETHER && !rtnl_type && !devtype)
+ if (arptype == ARPHRD_ETHER && !kind && !devtype)
return NM_LINK_TYPE_ETHERNET;
}
return NM_LINK_TYPE_UNKNOWN;
}
-gboolean
-_nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
+/******************************************************************
+ * libnl unility functions and wrappers
+ ******************************************************************/
+
+#define nm_auto_nlmsg __attribute__((cleanup(_nm_auto_nl_msg_cleanup)))
+static void
+_nm_auto_nl_msg_cleanup (void *ptr)
{
- NMPlatformLink *obj = (NMPlatformLink *) _obj;
- NMPObjectLink *obj_priv = (NMPObjectLink *) _obj;
- struct rtnl_link *nlo = (struct rtnl_link *) _nlo;
- const char *name;
- struct nl_addr *nladdr;
- const char *kind;
- gboolean completed_from_cache_val = FALSE;
- gboolean *completed_from_cache = complete_from_cache ? &completed_from_cache_val : NULL;
- const NMPObject *link_cached = NULL;
- int parent;
+ nlmsg_free (*((struct nl_msg **) ptr));
+}
- nm_assert (memcmp (obj, ((char [sizeof (NMPObjectLink)]) { 0 }), sizeof (NMPObjectLink)) == 0);
+static const char *
+_nl_nlmsg_type_to_str (guint16 type, char *buf, gsize len)
+{
+ const char *str_type = NULL;
- if (_LOGT_ENABLED () && !NM_IN_SET (rtnl_link_get_family (nlo), AF_UNSPEC, AF_BRIDGE))
- _LOGT ("netlink object for ifindex %d has unusual family %d", rtnl_link_get_ifindex (nlo), rtnl_link_get_family (nlo));
+ switch (type) {
+ case RTM_NEWLINK: str_type = "NEWLINK"; break;
+ case RTM_DELLINK: str_type = "DELLINK"; break;
+ case RTM_NEWADDR: str_type = "NEWADDR"; break;
+ case RTM_DELADDR: str_type = "DELADDR"; break;
+ case RTM_NEWROUTE: str_type = "NEWROUTE"; break;
+ case RTM_DELROUTE: str_type = "DELROUTE"; break;
+ }
+ if (str_type)
+ g_strlcpy (buf, str_type, len);
+ else
+ g_snprintf (buf, len, "(%d)", type);
+ return buf;
+}
- obj->ifindex = rtnl_link_get_ifindex (nlo);
+/******************************************************************
+ * NMPObject/netlink functions
+ ******************************************************************/
- if (id_only)
- return TRUE;
+#define _check_addr_or_errout(tb, attr, addr_len) \
+ ({ \
+ const struct nlattr *__t = (tb)[(attr)]; \
+ \
+ if (__t) { \
+ if (nla_len (__t) != (addr_len)) { \
+ goto errout; \
+ } \
+ } \
+ !!__t; \
+ })
- name = rtnl_link_get_name (nlo);
- if (name)
- g_strlcpy (obj->name, name, sizeof (obj->name));
- obj->type = link_extract_type (platform, nlo, completed_from_cache, &link_cached, &kind);
- obj->kind = g_intern_string (kind);
- obj->flags = rtnl_link_get_flags (nlo);
- obj->connected = NM_FLAGS_HAS (obj->flags, IFF_LOWER_UP);
- obj->master = rtnl_link_get_master (nlo);
- parent = rtnl_link_get_link (nlo);
- if (parent > 0) {
- gint32 link_netnsid;
-
- if (_rtnl_link_get_link_netnsid (nlo, &link_netnsid) == 0)
- obj->parent = NM_PLATFORM_LINK_OTHER_NETNS;
- else
- obj->parent = parent;
- }
- obj->mtu = rtnl_link_get_mtu (nlo);
- obj->arptype = rtnl_link_get_arptype (nlo);
-
- if (obj->type == NM_LINK_TYPE_VLAN) {
- if (!g_strcmp0 (rtnl_link_get_type (nlo), "vlan"))
- obj->vlan_id = rtnl_link_vlan_get_id (nlo);
- else if (completed_from_cache) {
- _lookup_link_cached (platform, obj->ifindex, completed_from_cache, &link_cached);
- if (link_cached)
- obj->vlan_id = link_cached->link.vlan_id;
- }
- }
+/*****************************************************************************/
- if ((nladdr = rtnl_link_get_addr (nlo))) {
- unsigned int l = 0;
+/* Copied and heavily modified from libnl3's inet6_parse_protinfo(). */
+static gboolean
+_parse_af_inet6 (NMPlatform *platform,
+ struct nlattr *attr,
+ NMUtilsIPv6IfaceId *out_iid,
+ guint8 *out_iid_is_valid,
+ guint8 *out_addr_gen_mode_inv)
+{
+ static struct nla_policy policy[IFLA_INET6_MAX+1] = {
+ [IFLA_INET6_FLAGS] = { .type = NLA_U32 },
+ [IFLA_INET6_CACHEINFO] = { .minlen = sizeof(struct ifla_cacheinfo) },
+ [IFLA_INET6_CONF] = { .minlen = 4 },
+ [IFLA_INET6_STATS] = { .minlen = 8 },
+ [IFLA_INET6_ICMP6STATS] = { .minlen = 8 },
+ [IFLA_INET6_TOKEN] = { .minlen = sizeof(struct in6_addr) },
+ [IFLA_INET6_ADDR_GEN_MODE] = { .type = NLA_U8 },
+ };
+ struct nlattr *tb[IFLA_INET6_MAX+1];
+ int err;
+ struct in6_addr i6_token;
+ gboolean iid_is_valid = FALSE;
+ guint8 i6_addr_gen_mode_inv = 0;
+ gboolean success = FALSE;
- l = nl_addr_get_len (nladdr);
- if (l > 0 && l <= NM_UTILS_HWADDR_LEN_MAX) {
- G_STATIC_ASSERT (NM_UTILS_HWADDR_LEN_MAX == sizeof (obj->addr.data));
- memcpy (obj->addr.data, nl_addr_get_binary_addr (nladdr), l);
- obj->addr.len = l;
- }
- }
+ err = nla_parse_nested (tb, IFLA_INET6_MAX, attr, policy);
+ if (err < 0)
+ goto errout;
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
- if (_support_user_ipv6ll_get ()) {
- guint8 mode = 0;
+ if (tb[IFLA_INET6_CONF] && nla_len(tb[IFLA_INET6_CONF]) % 4)
+ goto errout;
+ if (tb[IFLA_INET6_STATS] && nla_len(tb[IFLA_INET6_STATS]) % 8)
+ goto errout;
+ if (tb[IFLA_INET6_ICMP6STATS] && nla_len(tb[IFLA_INET6_ICMP6STATS]) % 8)
+ goto errout;
- if (rtnl_link_inet6_get_addr_gen_mode (nlo, &mode) == 0)
- obj->inet6_addr_gen_mode_inv = _nm_platform_uint8_inv (mode);
+ if (_check_addr_or_errout (tb, IFLA_INET6_TOKEN, sizeof (struct in6_addr))) {
+ nla_memcpy (&i6_token, tb[IFLA_INET6_TOKEN], sizeof (struct in6_addr));
+ if (!IN6_IS_ADDR_UNSPECIFIED (&i6_token))
+ iid_is_valid = TRUE;
}
-#endif
-#if HAVE_LIBNL_INET6_TOKEN
- if ((rtnl_link_inet6_get_token (nlo, &nladdr)) == 0) {
- if ( nl_addr_get_family (nladdr) == AF_INET6
- && nl_addr_get_len (nladdr) == sizeof (struct in6_addr)) {
- struct in6_addr *addr;
- NMUtilsIPv6IfaceId *iid = &obj->inet6_token.iid;
-
- addr = nl_addr_get_binary_addr (nladdr);
- iid->id_u8[7] = addr->s6_addr[15];
- iid->id_u8[6] = addr->s6_addr[14];
- iid->id_u8[5] = addr->s6_addr[13];
- iid->id_u8[4] = addr->s6_addr[12];
- iid->id_u8[3] = addr->s6_addr[11];
- iid->id_u8[2] = addr->s6_addr[10];
- iid->id_u8[1] = addr->s6_addr[9];
- iid->id_u8[0] = addr->s6_addr[8];
- obj->inet6_token.is_valid = TRUE;
+ /* Hack to detect support addrgenmode of the kernel. We only parse
+ * netlink messages that we receive from kernel, hence this check
+ * is valid. */
+ _support_user_ipv6ll_detect (tb);
+
+ if (tb[IFLA_INET6_ADDR_GEN_MODE]) {
+ i6_addr_gen_mode_inv = _nm_platform_uint8_inv (nla_get_u8 (tb[IFLA_INET6_ADDR_GEN_MODE]));
+ if (i6_addr_gen_mode_inv == 0) {
+ /* an inverse addrgenmode of zero is unexpected. We need to reserve zero
+ * to signal "unset". */
+ goto errout;
}
- nl_addr_put (nladdr);
}
-#endif
-
- obj_priv->netlink.is_in_netlink = TRUE;
- return TRUE;
+ success = TRUE;
+ if (iid_is_valid) {
+ out_iid->id_u8[7] = i6_token.s6_addr[15];
+ out_iid->id_u8[6] = i6_token.s6_addr[14];
+ out_iid->id_u8[5] = i6_token.s6_addr[13];
+ out_iid->id_u8[4] = i6_token.s6_addr[12];
+ out_iid->id_u8[3] = i6_token.s6_addr[11];
+ out_iid->id_u8[2] = i6_token.s6_addr[10];
+ out_iid->id_u8[1] = i6_token.s6_addr[9];
+ out_iid->id_u8[0] = i6_token.s6_addr[8];
+ *out_iid_is_valid = TRUE;
+ }
+ *out_addr_gen_mode_inv = i6_addr_gen_mode_inv;
+errout:
+ return success;
}
-/* _timestamp_nl_to_ms:
- * @timestamp_nl: a timestamp from ifa_cacheinfo.
- * @monotonic_ms: *now* in CLOCK_MONOTONIC. Needed to estimate the current
- * uptime and how often timestamp_nl wrapped.
- *
- * Convert the timestamp from ifa_cacheinfo to CLOCK_MONOTONIC milliseconds.
- * The ifa_cacheinfo fields tstamp and cstamp contains timestamps that counts
- * with in 1/100th of a second of clock_gettime(CLOCK_MONOTONIC). However,
- * the uint32 counter wraps every 497 days of uptime, so we have to compensate
- * for that. */
-static gint64
-_timestamp_nl_to_ms (guint32 timestamp_nl, gint64 monotonic_ms)
+/*****************************************************************************/
+
+static NMPObject *
+_parse_lnk_gre (const char *kind, struct nlattr *info_data)
{
- const gint64 WRAP_INTERVAL = (((gint64) G_MAXUINT32) + 1) * (1000 / 100);
- gint64 timestamp_nl_ms;
+ static struct nla_policy policy[IFLA_GRE_MAX + 1] = {
+ [IFLA_GRE_LINK] = { .type = NLA_U32 },
+ [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
+ [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
+ [IFLA_GRE_IKEY] = { .type = NLA_U32 },
+ [IFLA_GRE_OKEY] = { .type = NLA_U32 },
+ [IFLA_GRE_LOCAL] = { .type = NLA_U32 },
+ [IFLA_GRE_REMOTE] = { .type = NLA_U32 },
+ [IFLA_GRE_TTL] = { .type = NLA_U8 },
+ [IFLA_GRE_TOS] = { .type = NLA_U8 },
+ [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
+ };
+ struct nlattr *tb[IFLA_GRE_MAX + 1];
+ int err;
+ NMPObject *obj;
+ NMPlatformLnkGre *props;
- /* convert timestamp from 1/100th of a second to msec. */
- timestamp_nl_ms = ((gint64) timestamp_nl) * (1000 / 100);
+ if (!info_data || g_strcmp0 (kind, "gre"))
+ return NULL;
- /* timestamp wraps every 497 days. Try to compensate for that.*/
- if (timestamp_nl_ms > monotonic_ms) {
- /* timestamp_nl_ms is in the future. Truncate it to *now* */
- timestamp_nl_ms = monotonic_ms;
- } else if (monotonic_ms >= WRAP_INTERVAL) {
- timestamp_nl_ms += (monotonic_ms / WRAP_INTERVAL) * WRAP_INTERVAL;
- if (timestamp_nl_ms > monotonic_ms)
- timestamp_nl_ms -= WRAP_INTERVAL;
- }
+ err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data, policy);
+ if (err < 0)
+ return NULL;
- return timestamp_nl_ms;
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_GRE, NULL);
+ props = &obj->lnk_gre;
+
+ props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0;
+ props->input_flags = tb[IFLA_GRE_IFLAGS] ? nla_get_u16 (tb[IFLA_GRE_IFLAGS]) : 0;
+ props->output_flags = tb[IFLA_GRE_OFLAGS] ? nla_get_u16 (tb[IFLA_GRE_OFLAGS]) : 0;
+ props->input_key = (props->input_flags & GRE_KEY) && tb[IFLA_GRE_IKEY] ? nla_get_u32 (tb[IFLA_GRE_IKEY]) : 0;
+ props->output_key = (props->output_flags & GRE_KEY) && tb[IFLA_GRE_OKEY] ? nla_get_u32 (tb[IFLA_GRE_OKEY]) : 0;
+ props->local = tb[IFLA_GRE_LOCAL] ? nla_get_u32 (tb[IFLA_GRE_LOCAL]) : 0;
+ props->remote = tb[IFLA_GRE_REMOTE] ? nla_get_u32 (tb[IFLA_GRE_REMOTE]) : 0;
+ props->tos = tb[IFLA_GRE_TOS] ? nla_get_u8 (tb[IFLA_GRE_TOS]) : 0;
+ props->ttl = tb[IFLA_GRE_TTL] ? nla_get_u8 (tb[IFLA_GRE_TTL]) : 0;
+ props->path_mtu_discovery = !tb[IFLA_GRE_PMTUDISC] || !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]);
+
+ return obj;
}
-static guint32
-_rtnl_addr_last_update_time_to_nm (const struct rtnl_addr *rtnladdr, gint32 *out_now_nm)
+/*****************************************************************************/
+
+/* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers
+ * we're building against might not have those properties even though the
+ * running kernel might.
+ */
+#define IFLA_IPOIB_UNSPEC 0
+#define IFLA_IPOIB_PKEY 1
+#define IFLA_IPOIB_MODE 2
+#define IFLA_IPOIB_UMCAST 3
+#undef IFLA_IPOIB_MAX
+#define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST
+
+#define IPOIB_MODE_DATAGRAM 0 /* using unreliable datagram QPs */
+#define IPOIB_MODE_CONNECTED 1 /* using connected QPs */
+
+static NMPObject *
+_parse_lnk_infiniband (const char *kind, struct nlattr *info_data)
{
- guint32 last_update_time = rtnl_addr_get_last_update_time ((struct rtnl_addr *) rtnladdr);
- struct timespec tp;
- gint64 now_nl, now_nm, result;
+ static struct nla_policy policy[IFLA_IPOIB_MAX + 1] = {
+ [IFLA_IPOIB_PKEY] = { .type = NLA_U16 },
+ [IFLA_IPOIB_MODE] = { .type = NLA_U16 },
+ [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 },
+ };
+ struct nlattr *tb[IFLA_IPOIB_MAX + 1];
+ NMPlatformLnkInfiniband *info;
+ NMPObject *obj;
int err;
+ const char *mode;
- /* timestamp is unset. Default to 1. */
- if (!last_update_time) {
- if (out_now_nm)
- *out_now_nm = 0;
- return 1;
- }
-
- /* do all the calculations in milliseconds scale */
+ if (!info_data || g_strcmp0 (kind, "ipoib"))
+ return NULL;
- err = clock_gettime (CLOCK_MONOTONIC, &tp);
- g_assert (err == 0);
- now_nm = nm_utils_get_monotonic_timestamp_ms ();
- now_nl = (((gint64) tp.tv_sec) * ((gint64) 1000)) +
- (tp.tv_nsec / (NM_UTILS_NS_PER_SECOND/1000));
+ err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data, policy);
+ if (err < 0)
+ return NULL;
- result = now_nm - (now_nl - _timestamp_nl_to_ms (last_update_time, now_nl));
+ if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE])
+ return NULL;
- if (out_now_nm)
- *out_now_nm = now_nm / 1000;
+ switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) {
+ case IPOIB_MODE_DATAGRAM:
+ mode = "datagram";
+ break;
+ case IPOIB_MODE_CONNECTED:
+ mode = "connected";
+ break;
+ default:
+ return NULL;
+ }
- /* converting the last_update_time into nm_utils_get_monotonic_timestamp_ms() scale is
- * a good guess but fails in the following situations:
- *
- * - If the address existed before start of the process, the timestamp in nm scale would
- * be negative or zero. In this case we default to 1.
- * - during hibernation, the CLOCK_MONOTONIC/last_update_time drifts from
- * nm_utils_get_monotonic_timestamp_ms() scale.
- */
- if (result <= 1000)
- return 1;
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_INFINIBAND, NULL);
+ info = &obj->lnk_infiniband;
- if (result > now_nm)
- return now_nm / 1000;
+ info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]);
+ info->mode = mode;
- return result / 1000;
+ return obj;
}
-static guint32
-_extend_lifetime (guint32 lifetime, guint32 seconds)
+/*****************************************************************************/
+
+static NMPObject *
+_parse_lnk_macvlan (const char *kind, struct nlattr *info_data)
{
- guint64 v;
+ static struct nla_policy policy[IFLA_MACVLAN_MAX + 1] = {
+ [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
+ [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
+ };
+ NMPlatformLnkMacvlan *props;
+ struct nlattr *tb[IFLA_MACVLAN_MAX + 1];
+ int err;
+ NMPObject *obj;
+ const char *mode;
- if ( lifetime == NM_PLATFORM_LIFETIME_PERMANENT
- || seconds == 0)
- return lifetime;
+ if (!info_data || g_strcmp0 (kind, "macvlan"))
+ return NULL;
- v = (guint64) lifetime + (guint64) seconds;
- return MIN (v, NM_PLATFORM_LIFETIME_PERMANENT - 1);
+ err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data, policy);
+ if (err < 0)
+ return NULL;
+
+ if (!tb[IFLA_MACVLAN_MODE])
+ return NULL;
+
+ switch (nla_get_u32 (tb[IFLA_MACVLAN_MODE])) {
+ case MACVLAN_MODE_PRIVATE:
+ mode = "private";
+ break;
+ case MACVLAN_MODE_VEPA:
+ mode = "vepa";
+ break;
+ case MACVLAN_MODE_BRIDGE:
+ mode = "bridge";
+ break;
+ case MACVLAN_MODE_PASSTHRU:
+ mode = "passthru";
+ break;
+ default:
+ return NULL;
+ }
+
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_MACVLAN, NULL);
+ props = &obj->lnk_macvlan;
+ props->mode = mode;
+
+ if (tb[IFLA_MACVLAN_FLAGS])
+ props->no_promisc = NM_FLAGS_HAS (nla_get_u16 (tb[IFLA_MACVLAN_FLAGS]), MACVLAN_FLAG_NOPROMISC);
+
+ return obj;
}
-/* The rtnl_addr object contains relative lifetimes @valid and @preferred
- * that count in seconds, starting from the moment when the kernel constructed
- * the netlink message.
- *
- * There is also a field rtnl_addr_last_update_time(), which is the absolute
- * time in 1/100th of a second of clock_gettime (CLOCK_MONOTONIC) when the address
- * was modified (wrapping every 497 days).
- * Immediately at the time when the address was last modified, #NOW and @last_update_time
- * are the same, so (only) in that case @valid and @preferred are anchored at @last_update_time.
- * However, this is not true in general. As time goes by, whenever kernel sends a new address
- * via netlink, the lifetimes keep counting down.
- **/
-static void
-_nlo_rtnl_addr_get_lifetimes (const struct rtnl_addr *rtnladdr,
- guint32 *out_timestamp,
- guint32 *out_lifetime,
- guint32 *out_preferred)
+/*****************************************************************************/
+
+static gboolean
+_vlan_qos_mapping_from_nla (struct nlattr *nlattr,
+ const NMVlanQosMapping **out_map,
+ guint *out_n_map)
{
- guint32 timestamp = 0;
- gint32 now;
- guint32 lifetime = rtnl_addr_get_valid_lifetime ((struct rtnl_addr *) rtnladdr);
- guint32 preferred = rtnl_addr_get_preferred_lifetime ((struct rtnl_addr *) rtnladdr);
+ struct nlattr *nla;
+ int remaining;
+ gs_unref_ptrarray GPtrArray *array = NULL;
- if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT
- || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
- if (preferred > lifetime)
- preferred = lifetime;
- timestamp = _rtnl_addr_last_update_time_to_nm (rtnladdr, &now);
+ G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (struct ifla_vlan_qos_mapping));
+ G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->to) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->to));
+ G_STATIC_ASSERT (sizeof (((NMVlanQosMapping *) 0)->from) == sizeof (((struct ifla_vlan_qos_mapping *) 0)->from));
+ G_STATIC_ASSERT (sizeof (NMVlanQosMapping) == sizeof (((NMVlanQosMapping *) 0)->from) + sizeof (((NMVlanQosMapping *) 0)->to));
- if (now == 0) {
- /* strange. failed to detect the last-update time and assumed that timestamp is 1. */
- nm_assert (timestamp == 1);
- now = nm_utils_get_monotonic_timestamp_s ();
+ nm_assert (out_map && !*out_map);
+ nm_assert (out_n_map && !*out_n_map);
+
+ if (!nlattr)
+ return TRUE;
+
+ array = g_ptr_array_new ();
+ nla_for_each_nested (nla, nlattr, remaining) {
+ if (nla_len (nla) < sizeof(NMVlanQosMapping))
+ return FALSE;
+ g_ptr_array_add (array, nla_data (nla));
+ }
+
+ if (array->len > 0) {
+ NMVlanQosMapping *list;
+ guint i, j;
+
+ /* The sorting is necessary, because for egress mapping, kernel
+ * doesn't sent the items strictly sorted by the from field. */
+ g_ptr_array_sort_with_data (array, _vlan_qos_mapping_cmp_from_ptr, NULL);
+
+ list = g_new (NMVlanQosMapping, array->len);
+
+ for (i = 0, j = 0; i < array->len; i++) {
+ NMVlanQosMapping *map;
+
+ map = array->pdata[i];
+
+ /* kernel doesn't really send us duplicates. Just be extra cautious
+ * because we want strong guarantees about the sort order and uniqueness
+ * of our mapping list (for simpler equality comparison). */
+ if ( j > 0
+ && list[j - 1].from == map->from)
+ list[j - 1] = *map;
+ else
+ list[j++] = *map;
}
- if (timestamp < now) {
- guint32 diff = now - timestamp;
- lifetime = _extend_lifetime (lifetime, diff);
- preferred = _extend_lifetime (preferred, diff);
- } else
- nm_assert (timestamp == now);
+ *out_n_map = j;
+ *out_map = list;
}
- *out_timestamp = timestamp;
- *out_lifetime = lifetime;
- *out_preferred = preferred;
+
+ return TRUE;
}
-gboolean
-_nmp_vt_cmd_plobj_init_from_nl_ip4_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
+/* Copied and heavily modified from libnl3's vlan_parse() */
+static NMPObject *
+_parse_lnk_vlan (const char *kind, struct nlattr *info_data)
{
- NMPlatformIP4Address *obj = (NMPlatformIP4Address *) _obj;
- struct rtnl_addr *nlo = (struct rtnl_addr *) _nlo;
- struct nl_addr *nladdr = rtnl_addr_get_local (nlo);
- struct nl_addr *nlpeer = rtnl_addr_get_peer (nlo);
- const char *label;
+ static struct nla_policy policy[IFLA_VLAN_MAX+1] = {
+ [IFLA_VLAN_ID] = { .type = NLA_U16 },
+ [IFLA_VLAN_FLAGS] = { .minlen = sizeof(struct ifla_vlan_flags) },
+ [IFLA_VLAN_INGRESS_QOS] = { .type = NLA_NESTED },
+ [IFLA_VLAN_EGRESS_QOS] = { .type = NLA_NESTED },
+ [IFLA_VLAN_PROTOCOL] = { .type = NLA_U16 },
+ };
+ struct nlattr *tb[IFLA_VLAN_MAX+1];
+ int err;
+ nm_auto_nmpobj NMPObject *obj = NULL;
+ NMPObject *obj_result;
- if (!nladdr || nl_addr_get_len (nladdr) != sizeof (obj->address))
- g_return_val_if_reached (FALSE);
+ if (!info_data || g_strcmp0 (kind, "vlan"))
+ return NULL;
+
+ if ((err = nla_parse_nested (tb, IFLA_VLAN_MAX, info_data, policy)) < 0)
+ return NULL;
+
+ if (!tb[IFLA_VLAN_ID])
+ return NULL;
+
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VLAN, NULL);
+ obj->lnk_vlan.id = nla_get_u16 (tb[IFLA_VLAN_ID]);
+
+ if (tb[IFLA_VLAN_FLAGS]) {
+ struct ifla_vlan_flags flags;
+
+ nla_memcpy (&flags, tb[IFLA_VLAN_FLAGS], sizeof(flags));
+
+ obj->lnk_vlan.flags = flags.flags;
+ }
+
+ if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_INGRESS_QOS],
+ &obj->_lnk_vlan.ingress_qos_map,
+ &obj->_lnk_vlan.n_ingress_qos_map))
+ return NULL;
+
+ if (!_vlan_qos_mapping_from_nla (tb[IFLA_VLAN_EGRESS_QOS],
+ &obj->_lnk_vlan.egress_qos_map,
+ &obj->_lnk_vlan.n_egress_qos_map))
+ return NULL;
+
+
+ obj_result = obj;
+ obj = NULL;
+ return obj_result;
+}
+
+/*****************************************************************************/
+
+/* The installed kernel headers might not have VXLAN stuff at all, or
+ * they might have the original properties, but not PORT, GROUP6, or LOCAL6.
+ * So until we depend on kernel >= 3.11, we just ignore the actual enum
+ * in if_link.h and define the values ourselves.
+ */
+#define IFLA_VXLAN_UNSPEC 0
+#define IFLA_VXLAN_ID 1
+#define IFLA_VXLAN_GROUP 2
+#define IFLA_VXLAN_LINK 3
+#define IFLA_VXLAN_LOCAL 4
+#define IFLA_VXLAN_TTL 5
+#define IFLA_VXLAN_TOS 6
+#define IFLA_VXLAN_LEARNING 7
+#define IFLA_VXLAN_AGEING 8
+#define IFLA_VXLAN_LIMIT 9
+#define IFLA_VXLAN_PORT_RANGE 10
+#define IFLA_VXLAN_PROXY 11
+#define IFLA_VXLAN_RSC 12
+#define IFLA_VXLAN_L2MISS 13
+#define IFLA_VXLAN_L3MISS 14
+#define IFLA_VXLAN_PORT 15
+#define IFLA_VXLAN_GROUP6 16
+#define IFLA_VXLAN_LOCAL6 17
+#undef IFLA_VXLAN_MAX
+#define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6
- obj->ifindex = rtnl_addr_get_ifindex (nlo);
- obj->plen = rtnl_addr_get_prefixlen (nlo);
- memcpy (&obj->address, nl_addr_get_binary_addr (nladdr), sizeof (obj->address));
+/* older kernel header might not contain 'struct ifla_vxlan_port_range'.
+ * Redefine it. */
+struct nm_ifla_vxlan_port_range {
+ guint16 low;
+ guint16 high;
+};
+
+static NMPObject *
+_parse_lnk_vxlan (const char *kind, struct nlattr *info_data)
+{
+ static struct nla_policy policy[IFLA_VXLAN_MAX + 1] = {
+ [IFLA_VXLAN_ID] = { .type = NLA_U32 },
+ [IFLA_VXLAN_GROUP] = { .type = NLA_U32 },
+ [IFLA_VXLAN_GROUP6] = { .type = NLA_UNSPEC,
+ .minlen = sizeof (struct in6_addr) },
+ [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
+ [IFLA_VXLAN_LOCAL] = { .type = NLA_U32 },
+ [IFLA_VXLAN_LOCAL6] = { .type = NLA_UNSPEC,
+ .minlen = sizeof (struct in6_addr) },
+ [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
+ [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
+ [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
+ [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
+ [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
+ [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_UNSPEC,
+ .minlen = sizeof (struct nm_ifla_vxlan_port_range) },
+ [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
+ [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
+ [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
+ [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
+ [IFLA_VXLAN_PORT] = { .type = NLA_U16 },
+ };
+ NMPlatformLnkVxlan *props;
+ struct nlattr *tb[IFLA_VXLAN_MAX + 1];
+ struct nm_ifla_vxlan_port_range *range;
+ int err;
+ NMPObject *obj;
+
+ if (!info_data || g_strcmp0 (kind, "vxlan"))
+ return NULL;
+
+ err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data, policy);
+ if (err < 0)
+ return NULL;
+
+ obj = nmp_object_new (NMP_OBJECT_TYPE_LNK_VXLAN, NULL);
+
+ props = &obj->lnk_vxlan;
+
+ if (tb[IFLA_VXLAN_LINK])
+ props->parent_ifindex = nla_get_u32 (tb[IFLA_VXLAN_LINK]);
+ if (tb[IFLA_VXLAN_ID])
+ props->id = nla_get_u32 (tb[IFLA_VXLAN_ID]);
+ if (tb[IFLA_VXLAN_GROUP])
+ props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]);
+ if (tb[IFLA_VXLAN_LOCAL])
+ props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]);
+ if (tb[IFLA_VXLAN_GROUP6])
+ memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6));
+ if (tb[IFLA_VXLAN_LOCAL6])
+ memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6));
+
+ if (tb[IFLA_VXLAN_AGEING])
+ props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]);
+ if (tb[IFLA_VXLAN_LIMIT])
+ props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]);
+ if (tb[IFLA_VXLAN_TOS])
+ props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]);
+ if (tb[IFLA_VXLAN_TTL])
+ props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]);
+
+ if (tb[IFLA_VXLAN_PORT])
+ props->dst_port = ntohs (nla_get_u16 (tb[IFLA_VXLAN_PORT]));
+
+ if (tb[IFLA_VXLAN_PORT_RANGE]) {
+ range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]);
+ props->src_port_min = ntohs (range->low);
+ props->src_port_max = ntohs (range->high);
+ }
+
+ if (tb[IFLA_VXLAN_LEARNING])
+ props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]);
+ if (tb[IFLA_VXLAN_PROXY])
+ props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]);
+ if (tb[IFLA_VXLAN_RSC])
+ props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]);
+ if (tb[IFLA_VXLAN_L2MISS])
+ props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]);
+ if (tb[IFLA_VXLAN_L3MISS])
+ props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]);
+
+ return obj;
+}
+
+/*****************************************************************************/
+
+/* Copied and heavily modified from libnl3's link_msg_parser(). */
+static NMPObject *
+_new_from_nl_link (NMPlatform *platform, const NMPCache *cache, struct nlmsghdr *nlh, gboolean id_only)
+{
+ static struct nla_policy policy[IFLA_MAX+1] = {
+ [IFLA_IFNAME] = { .type = NLA_STRING,
+ .maxlen = IFNAMSIZ },
+ [IFLA_MTU] = { .type = NLA_U32 },
+ [IFLA_TXQLEN] = { .type = NLA_U32 },
+ [IFLA_LINK] = { .type = NLA_U32 },
+ [IFLA_WEIGHT] = { .type = NLA_U32 },
+ [IFLA_MASTER] = { .type = NLA_U32 },
+ [IFLA_OPERSTATE] = { .type = NLA_U8 },
+ [IFLA_LINKMODE] = { .type = NLA_U8 },
+ [IFLA_LINKINFO] = { .type = NLA_NESTED },
+ [IFLA_QDISC] = { .type = NLA_STRING,
+ .maxlen = IFQDISCSIZ },
+ [IFLA_STATS] = { .minlen = sizeof(struct rtnl_link_stats) },
+ [IFLA_STATS64] = { .minlen = sizeof(struct rtnl_link_stats64)},
+ [IFLA_MAP] = { .minlen = sizeof(struct rtnl_link_ifmap) },
+ [IFLA_IFALIAS] = { .type = NLA_STRING, .maxlen = IFALIASZ },
+ [IFLA_NUM_VF] = { .type = NLA_U32 },
+ [IFLA_AF_SPEC] = { .type = NLA_NESTED },
+ [IFLA_PROMISCUITY] = { .type = NLA_U32 },
+ [IFLA_NUM_TX_QUEUES] = { .type = NLA_U32 },
+ [IFLA_NUM_RX_QUEUES] = { .type = NLA_U32 },
+ [IFLA_GROUP] = { .type = NLA_U32 },
+ [IFLA_CARRIER] = { .type = NLA_U8 },
+ [IFLA_PHYS_PORT_ID] = { .type = NLA_UNSPEC },
+ [IFLA_NET_NS_PID] = { .type = NLA_U32 },
+ [IFLA_NET_NS_FD] = { .type = NLA_U32 },
+ };
+ static struct nla_policy policy_link_info[IFLA_INFO_MAX+1] = {
+ [IFLA_INFO_KIND] = { .type = NLA_STRING },
+ [IFLA_INFO_DATA] = { .type = NLA_NESTED },
+ [IFLA_INFO_XSTATS] = { .type = NLA_NESTED },
+ };
+ const struct ifinfomsg *ifi;
+ struct nlattr *tb[IFLA_MAX+1];
+ struct nlattr *li[IFLA_INFO_MAX+1];
+ struct nlattr *nl_info_data = NULL;
+ const char *nl_info_kind = NULL;
+ int err;
+ nm_auto_nmpobj NMPObject *obj = NULL;
+ NMPObject *obj_result = NULL;
+ gboolean completed_from_cache_val = FALSE;
+ gboolean *completed_from_cache = cache ? &completed_from_cache_val : NULL;
+ const NMPObject *link_cached = NULL;
+ nm_auto_nmpobj NMPObject *lnk_data = NULL;
+
+ if (!nlmsg_valid_hdr (nlh, sizeof (*ifi)))
+ return NULL;
+ ifi = nlmsg_data(nlh);
+
+ obj = nmp_object_new_link (ifi->ifi_index);
if (id_only)
- return TRUE;
+ goto done;
- obj->source = NM_IP_CONFIG_SOURCE_KERNEL;
- _nlo_rtnl_addr_get_lifetimes (nlo,
- &obj->timestamp,
- &obj->lifetime,
- &obj->preferred);
- if (nlpeer) {
- if (nl_addr_get_len (nlpeer) != sizeof (obj->peer_address))
- g_warn_if_reached ();
+ err = nlmsg_parse (nlh, sizeof (*ifi), tb, IFLA_MAX, policy);
+ if (err < 0)
+ goto errout;
+
+ if (!tb[IFLA_IFNAME])
+ goto errout;
+ nla_strlcpy(obj->link.name, tb[IFLA_IFNAME], IFNAMSIZ);
+ if (!obj->link.name[0])
+ goto errout;
+
+ if (tb[IFLA_LINKINFO]) {
+ err = nla_parse_nested (li, IFLA_INFO_MAX, tb[IFLA_LINKINFO], policy_link_info);
+ if (err < 0)
+ goto errout;
+
+ if (li[IFLA_INFO_KIND])
+ nl_info_kind = nla_get_string (li[IFLA_INFO_KIND]);
+
+ nl_info_data = li[IFLA_INFO_DATA];
+ }
+
+ obj->link.flags = ifi->ifi_flags;
+ obj->link.connected = NM_FLAGS_HAS (obj->link.flags, IFF_LOWER_UP);
+ obj->link.arptype = ifi->ifi_type;
+
+ obj->link.type = _linktype_get_type (platform,
+ cache,
+ nl_info_kind,
+ obj->link.ifindex,
+ obj->link.name,
+ obj->link.flags,
+ obj->link.arptype,
+ completed_from_cache,
+ &link_cached,
+ &obj->link.kind);
+
+ if (tb[IFLA_MASTER])
+ obj->link.master = nla_get_u32 (tb[IFLA_MASTER]);
+
+ if (tb[IFLA_LINK]) {
+ if (!tb[IFLA_LINK_NETNSID])
+ obj->link.parent = nla_get_u32 (tb[IFLA_LINK]);
else
- memcpy (&obj->peer_address, nl_addr_get_binary_addr (nlpeer), sizeof (obj->peer_address));
+ obj->link.parent = NM_PLATFORM_LINK_OTHER_NETNS;
}
- label = rtnl_addr_get_label (nlo);
- /* Check for ':'; we're only interested in labels used as interface aliases */
- if (label && strchr (label, ':'))
- g_strlcpy (obj->label, label, sizeof (obj->label));
- return TRUE;
+ if (tb[IFLA_ADDRESS]) {
+ int l = nla_len (tb[IFLA_ADDRESS]);
+
+ if (l > 0 && l <= NM_UTILS_HWADDR_LEN_MAX) {
+ G_STATIC_ASSERT (NM_UTILS_HWADDR_LEN_MAX == sizeof (obj->link.addr.data));
+ memcpy (obj->link.addr.data, nla_data (tb[IFLA_ADDRESS]), l);
+ obj->link.addr.len = l;
+ }
+ }
+
+ if (tb[IFLA_AF_SPEC]) {
+ struct nlattr *af_attr;
+ int remaining;
+
+ nla_for_each_nested (af_attr, tb[IFLA_AF_SPEC], remaining) {
+ switch (nla_type (af_attr)) {
+ case AF_INET6:
+ _parse_af_inet6 (platform,
+ af_attr,
+ &obj->link.inet6_token.iid,
+ &obj->link.inet6_token.is_valid,
+ &obj->link.inet6_addr_gen_mode_inv);
+ break;
+ }
+ }
+ }
+
+ if (tb[IFLA_MTU])
+ obj->link.mtu = nla_get_u32 (tb[IFLA_MTU]);
+
+ switch (obj->link.type) {
+ case NM_LINK_TYPE_GRE:
+ lnk_data = _parse_lnk_gre (nl_info_kind, nl_info_data);
+ break;
+ case NM_LINK_TYPE_INFINIBAND:
+ lnk_data = _parse_lnk_infiniband (nl_info_kind, nl_info_data);
+ break;
+ case NM_LINK_TYPE_MACVLAN:
+ lnk_data = _parse_lnk_macvlan (nl_info_kind, nl_info_data);
+ break;
+ case NM_LINK_TYPE_VLAN:
+ lnk_data = _parse_lnk_vlan (nl_info_kind, nl_info_data);
+ break;
+ case NM_LINK_TYPE_VXLAN:
+ lnk_data = _parse_lnk_vxlan (nl_info_kind, nl_info_data);
+ break;
+ default:
+ goto no_lnk_data;
+ }
+
+ /* We always try to look into the cache and reuse the object there.
+ * We do that, because we consider the lnk object as immutable and don't
+ * modify it after creating. Hence we can share it and reuse. */
+ if (completed_from_cache) {
+ _lookup_cached_link (cache, obj->link.ifindex, completed_from_cache, &link_cached);
+ if ( link_cached
+ && link_cached->link.type == obj->link.type
+ && ( !lnk_data
+ || nmp_object_equal (lnk_data, link_cached->_link.netlink.lnk))) {
+ nmp_object_unref (lnk_data);
+ lnk_data = nmp_object_ref (link_cached->_link.netlink.lnk);
+ }
+ }
+
+no_lnk_data:
+
+ obj->_link.netlink.is_in_netlink = TRUE;
+
+ obj->_link.netlink.lnk = lnk_data;
+ lnk_data = NULL;
+
+done:
+ obj_result = obj;
+ obj = NULL;
+errout:
+ return obj_result;
}
-gboolean
-_nmp_vt_cmd_plobj_init_from_nl_ip6_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
+/* Copied and heavily modified from libnl3's addr_msg_parser(). */
+static NMPObject *
+_new_from_nl_addr (struct nlmsghdr *nlh, gboolean id_only)
{
- NMPlatformIP6Address *obj = (NMPlatformIP6Address *) _obj;
- struct rtnl_addr *nlo = (struct rtnl_addr *) _nlo;
- struct nl_addr *nladdr = rtnl_addr_get_local (nlo);
- struct nl_addr *nlpeer = rtnl_addr_get_peer (nlo);
+ static struct nla_policy policy[IFA_MAX+1] = {
+ [IFA_LABEL] = { .type = NLA_STRING,
+ .maxlen = IFNAMSIZ },
+ [IFA_CACHEINFO] = { .minlen = sizeof(struct ifa_cacheinfo) },
+ };
+ const struct ifaddrmsg *ifa;
+ struct nlattr *tb[IFA_MAX+1];
+ int err;
+ gboolean is_v4;
+ nm_auto_nmpobj NMPObject *obj = NULL;
+ NMPObject *obj_result = NULL;
+ int addr_len;
+ guint32 lifetime, preferred, timestamp;
- if (!nladdr || nl_addr_get_len (nladdr) != sizeof (obj->address))
- g_return_val_if_reached (FALSE);
+ if (!nlmsg_valid_hdr (nlh, sizeof (*ifa)))
+ return NULL;
+ ifa = nlmsg_data(nlh);
- obj->ifindex = rtnl_addr_get_ifindex (nlo);
- obj->plen = rtnl_addr_get_prefixlen (nlo);
- memcpy (&obj->address, nl_addr_get_binary_addr (nladdr), sizeof (obj->address));
+ if (!NM_IN_SET (ifa->ifa_family, AF_INET, AF_INET6))
+ goto errout;
+ is_v4 = ifa->ifa_family == AF_INET;
- if (id_only)
- return TRUE;
+ err = nlmsg_parse(nlh, sizeof(*ifa), tb, IFA_MAX, policy);
+ if (err < 0)
+ goto errout;
- obj->source = NM_IP_CONFIG_SOURCE_KERNEL;
- _nlo_rtnl_addr_get_lifetimes (nlo,
- &obj->timestamp,
- &obj->lifetime,
- &obj->preferred);
- obj->flags = rtnl_addr_get_flags (nlo);
+ addr_len = is_v4
+ ? sizeof (in_addr_t)
+ : sizeof (struct in6_addr);
- if (nlpeer) {
- if (nl_addr_get_len (nlpeer) != sizeof (obj->peer_address))
- g_warn_if_reached ();
- else
- memcpy (&obj->peer_address, nl_addr_get_binary_addr (nlpeer), sizeof (obj->peer_address));
+ /*****************************************************************/
+
+ obj = nmp_object_new (is_v4 ? 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_errout (tb, IFA_ADDRESS, addr_len);
+ _check_addr_or_errout (tb, IFA_LOCAL, addr_len);
+ if (is_v4) {
+ /* 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])
+ memcpy (&obj->ip4_address.address, nla_data (tb[IFA_LOCAL]), addr_len);
+ if (tb[IFA_ADDRESS])
+ memcpy (&obj->ip4_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len);
+ } else {
+ /* For IPv6, IFA_ADDRESS is always present.
+ *
+ * If IFA_LOCAL is missing, IFA_ADDRESS is @address and @peer_address
+ * is :: (all-zero).
+ *
+ * If unexpectely IFA_ADDRESS is missing, make the best of it -- but it _should_
+ * actually be there. */
+ if (tb[IFA_ADDRESS] || tb[IFA_LOCAL]) {
+ if (tb[IFA_LOCAL]) {
+ memcpy (&obj->ip6_address.address, nla_data (tb[IFA_LOCAL]), addr_len);
+ if (tb[IFA_ADDRESS])
+ memcpy (&obj->ip6_address.peer_address, nla_data (tb[IFA_ADDRESS]), addr_len);
+ else
+ obj->ip6_address.peer_address = obj->ip6_address.address;
+ } else
+ memcpy (&obj->ip6_address.address, nla_data (tb[IFA_ADDRESS]), addr_len);
+ }
}
- return TRUE;
+ obj->ip_address.source = NM_IP_CONFIG_SOURCE_KERNEL;
+
+ if (!is_v4) {
+ obj->ip6_address.flags = tb[IFA_FLAGS]
+ ? nla_get_u32 (tb[IFA_FLAGS])
+ : ifa->ifa_flags;
+ }
+
+ if (is_v4) {
+ if (tb[IFA_LABEL]) {
+ char label[IFNAMSIZ];
+
+ nla_strlcpy (label, tb[IFA_LABEL], IFNAMSIZ);
+
+ /* Check for ':'; we're only interested in labels used as interface aliases */
+ if (strchr (label, ':'))
+ g_strlcpy (obj->ip4_address.label, label, sizeof (obj->ip4_address.label));
+ }
+ }
+
+ lifetime = NM_PLATFORM_LIFETIME_PERMANENT;
+ preferred = NM_PLATFORM_LIFETIME_PERMANENT;
+ timestamp = 0;
+ /* IPv6 only */
+ if (tb[IFA_CACHEINFO]) {
+ const struct ifa_cacheinfo *ca = nla_data(tb[IFA_CACHEINFO]);
+
+ lifetime = ca->ifa_valid;
+ preferred = ca->ifa_prefered;
+ timestamp = ca->tstamp;
+ }
+ _addrtime_get_lifetimes (timestamp,
+ lifetime,
+ preferred,
+ &obj->ip_address.timestamp,
+ &obj->ip_address.lifetime,
+ &obj->ip_address.preferred);
+
+ obj_result = obj;
+ obj = NULL;
+errout:
+ return obj_result;
}
-gboolean
-_nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
+/* Copied and heavily modified from libnl3's rtnl_route_parse() and parse_multipath(). */
+static NMPObject *
+_new_from_nl_route (struct nlmsghdr *nlh, gboolean id_only)
{
- NMPlatformIP4Route *obj = (NMPlatformIP4Route *) _obj;
- struct rtnl_route *nlo = (struct rtnl_route *) _nlo;
- struct nl_addr *dst, *gw;
- struct rtnl_nexthop *nexthop;
- struct nl_addr *pref_src;
+ static struct nla_policy policy[RTA_MAX+1] = {
+ [RTA_IIF] = { .type = NLA_U32 },
+ [RTA_OIF] = { .type = NLA_U32 },
+ [RTA_PRIORITY] = { .type = NLA_U32 },
+ [RTA_FLOW] = { .type = NLA_U32 },
+ [RTA_CACHEINFO] = { .minlen = sizeof(struct rta_cacheinfo) },
+ [RTA_METRICS] = { .type = NLA_NESTED },
+ [RTA_MULTIPATH] = { .type = NLA_NESTED },
+ };
+ const struct rtmsg *rtm;
+ struct nlattr *tb[RTA_MAX + 1];
+ int err;
+ gboolean is_v4;
+ nm_auto_nmpobj NMPObject *obj = NULL;
+ NMPObject *obj_result = NULL;
+ int addr_len;
+ struct {
+ gboolean is_present;
+ int ifindex;
+ NMIPAddr gateway;
+ } nh;
+ guint32 mss;
+ guint32 table;
+
+ if (!nlmsg_valid_hdr (nlh, sizeof (*rtm)))
+ return NULL;
+ rtm = nlmsg_data(nlh);
- if (rtnl_route_get_type (nlo) != RTN_UNICAST ||
- rtnl_route_get_table (nlo) != RT_TABLE_MAIN ||
- rtnl_route_get_tos (nlo) != 0 ||
- rtnl_route_get_nnexthops (nlo) != 1)
- return FALSE;
+ /*****************************************************************
+ * only handle ~normal~ routes.
+ *****************************************************************/
- nexthop = rtnl_route_nexthop_n (nlo, 0);
- if (!nexthop)
- g_return_val_if_reached (FALSE);
+ if (!NM_IN_SET (rtm->rtm_family, AF_INET, AF_INET6))
+ goto errout;
- dst = rtnl_route_get_dst (nlo);
- if (!dst)
- g_return_val_if_reached (FALSE);
+ if ( rtm->rtm_type != RTN_UNICAST
+ || rtm->rtm_tos != 0)
+ goto errout;
+
+ err = nlmsg_parse (nlh, sizeof (struct rtmsg), tb, RTA_MAX, policy);
+ if (err < 0)
+ goto errout;
+
+ table = tb[RTA_TABLE]
+ ? nla_get_u32 (tb[RTA_TABLE])
+ : (guint32) rtm->rtm_table;
+ if (table != RT_TABLE_MAIN)
+ goto errout;
+
+ /*****************************************************************/
+
+ is_v4 = rtm->rtm_family == AF_INET;
+ addr_len = is_v4
+ ? sizeof (in_addr_t)
+ : sizeof (struct in6_addr);
+
+ /*****************************************************************
+ * parse nexthops. Only handle routes with one nh.
+ *****************************************************************/
+
+ memset (&nh, 0, sizeof (nh));
+
+ if (tb[RTA_MULTIPATH]) {
+ struct rtnexthop *rtnh = nla_data (tb[RTA_MULTIPATH]);
+ size_t tlen = nla_len(tb[RTA_MULTIPATH]);
+
+ while (tlen >= sizeof(*rtnh) && tlen >= rtnh->rtnh_len) {
+
+ if (nh.is_present) {
+ /* we don't support multipath routes. */
+ goto errout;
+ }
+ nh.is_present = TRUE;
+
+ nh.ifindex = rtnh->rtnh_ifindex;
+
+ if (rtnh->rtnh_len > sizeof(*rtnh)) {
+ struct nlattr *ntb[RTA_MAX + 1];
+
+ err = nla_parse (ntb, RTA_MAX, (struct nlattr *)
+ RTNH_DATA(rtnh),
+ rtnh->rtnh_len - sizeof (*rtnh),
+ policy);
+ if (err < 0)
+ goto errout;
- if (nl_addr_get_len (dst)) {
- if (nl_addr_get_len (dst) != sizeof (obj->network))
- g_return_val_if_reached (FALSE);
- memcpy (&obj->network, nl_addr_get_binary_addr (dst), sizeof (obj->network));
+ if (_check_addr_or_errout (ntb, RTA_GATEWAY, addr_len))
+ memcpy (&nh.gateway, nla_data (ntb[RTA_GATEWAY]), addr_len);
+ }
+
+ tlen -= RTNH_ALIGN(rtnh->rtnh_len);
+ rtnh = RTNH_NEXT(rtnh);
+ }
}
- obj->ifindex = rtnl_route_nh_get_ifindex (nexthop);
- obj->plen = nl_addr_get_prefixlen (dst);
- obj->metric = rtnl_route_get_priority (nlo);
- obj->scope_inv = nm_platform_route_scope_inv (rtnl_route_get_scope (nlo));
-
- gw = rtnl_route_nh_get_gateway (nexthop);
- if (gw) {
- if (nl_addr_get_len (gw) != sizeof (obj->gateway))
- g_warn_if_reached ();
- else
- memcpy (&obj->gateway, nl_addr_get_binary_addr (gw), sizeof (obj->gateway));
+
+ if ( tb[RTA_OIF]
+ || tb[RTA_GATEWAY]
+ || tb[RTA_FLOW]) {
+ int ifindex = 0;
+ NMIPAddr gateway = NMIPAddrInit;
+
+ if (tb[RTA_OIF])
+ ifindex = nla_get_u32 (tb[RTA_OIF]);
+ if (_check_addr_or_errout (tb, RTA_GATEWAY, addr_len))
+ memcpy (&gateway, nla_data (tb[RTA_GATEWAY]), addr_len);
+
+ if (!nh.is_present) {
+ /* 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;
+ } 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)
+ goto errout;
+ }
+ } else if (!nh.is_present)
+ goto errout;
+
+ /*****************************************************************/
+
+ mss = 0;
+ if (tb[RTA_METRICS]) {
+ struct nlattr *mtb[RTAX_MAX + 1];
+ int i;
+
+ err = nla_parse_nested(mtb, RTAX_MAX, tb[RTA_METRICS], NULL);
+ if (err < 0)
+ goto errout;
+
+ for (i = 1; i <= RTAX_MAX; i++) {
+ if (mtb[i]) {
+ if (i == RTAX_ADVMSS) {
+ if (nla_len (mtb[i]) >= sizeof (uint32_t))
+ mss = nla_get_u32(mtb[i]);
+ break;
+ }
+ }
+ }
}
- rtnl_route_get_metric (nlo, RTAX_ADVMSS, &obj->mss);
- if (rtnl_route_get_flags (nlo) & RTM_F_CLONED) {
+
+ /*****************************************************************/
+
+ obj = nmp_object_new (is_v4 ? NMP_OBJECT_TYPE_IP4_ROUTE : NMP_OBJECT_TYPE_IP6_ROUTE, NULL);
+
+ obj->ip_route.ifindex = nh.ifindex;
+
+ if (_check_addr_or_errout (tb, RTA_DST, addr_len))
+ memcpy (obj->ip_route.network_ptr, nla_data (tb[RTA_DST]), addr_len);
+
+ obj->ip_route.plen = rtm->rtm_dst_len;
+
+ if (tb[RTA_PRIORITY])
+ obj->ip_route.metric = nla_get_u32(tb[RTA_PRIORITY]);
+
+ if (is_v4)
+ obj->ip4_route.gateway = nh.gateway.addr4;
+ else
+ obj->ip6_route.gateway = nh.gateway.addr6;
+
+ if (is_v4)
+ obj->ip4_route.scope_inv = nm_platform_route_scope_inv (rtm->rtm_scope);
+
+ if (is_v4) {
+ if (_check_addr_or_errout (tb, RTA_PREFSRC, addr_len))
+ memcpy (&obj->ip4_route.network, nla_data (tb[RTA_PREFSRC]), addr_len);
+ }
+
+ obj->ip_route.mss = mss;
+
+ if (NM_FLAGS_HAS (rtm->rtm_flags, RTM_F_CLONED)) {
/* we must not straight way reject cloned routes, because we might have cached
* a non-cloned route. If we now receive an update of the route with the route
* being cloned, we must still return the object, so that we can remove the old
@@ -1356,69 +1665,609 @@ _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject
*
* This happens, because this route is not nmp_object_is_alive().
* */
- obj->source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED;
+ obj->ip_route.source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED;
} else
- obj->source = _nm_ip_config_source_from_rtprot (rtnl_route_get_protocol (nlo));
+ obj->ip_route.source = _nm_ip_config_source_from_rtprot (rtm->rtm_protocol);
- pref_src = rtnl_route_get_pref_src (nlo);
- if (pref_src) {
- if (nl_addr_get_len (pref_src) != sizeof (obj->pref_src))
- g_warn_if_reached ();
- else
- memcpy (&obj->pref_src, nl_addr_get_binary_addr (pref_src), sizeof (obj->pref_src));
+ obj_result = obj;
+ obj = NULL;
+errout:
+ return obj_result;
+}
+
+/**
+ * nmp_object_new_from_nl:
+ * @platform: (allow-none): for creating certain objects, the constructor wants to check
+ * sysfs. For this the platform instance is needed. If missing, the object might not
+ * be correctly detected.
+ * @cache: (allow-none): for certain objects, the netlink message doesn't contain all the information.
+ * If a cache is given, the object is completed with information from the cache.
+ * @nlh: the netlink message header
+ * @id_only: whether only to create an empty object with only the ID fields set.
+ *
+ * Returns: %NULL or a newly created NMPObject instance.
+ **/
+static NMPObject *
+nmp_object_new_from_nl (NMPlatform *platform, const NMPCache *cache, struct nl_msg *msg, gboolean id_only)
+{
+ struct nlmsghdr *msghdr;
+
+ if (nlmsg_get_proto (msg) != NETLINK_ROUTE)
+ return NULL;
+
+ msghdr = nlmsg_hdr (msg);
+
+ switch (msghdr->nlmsg_type) {
+ case RTM_NEWLINK:
+ case RTM_DELLINK:
+ case RTM_GETLINK:
+ case RTM_SETLINK:
+ return _new_from_nl_link (platform, cache, msghdr, id_only);
+ case RTM_NEWADDR:
+ case RTM_DELADDR:
+ case RTM_GETADDR:
+ return _new_from_nl_addr (msghdr, id_only);
+ case RTM_NEWROUTE:
+ case RTM_DELROUTE:
+ case RTM_GETROUTE:
+ return _new_from_nl_route (msghdr, id_only);
+ default:
+ return NULL;
}
+}
+
+/******************************************************************/
+
+static gboolean
+_nl_msg_new_link_set_afspec (struct nl_msg *msg,
+ int addr_gen_mode)
+{
+ struct nlattr *af_spec;
+ struct nlattr *af_attr;
+
+ nm_assert (msg);
+
+ if (!(af_spec = nla_nest_start (msg, IFLA_AF_SPEC)))
+ goto nla_put_failure;
+
+ if (addr_gen_mode >= 0) {
+ if (!(af_attr = nla_nest_start (msg, AF_INET6)))
+ goto nla_put_failure;
+
+ NLA_PUT_U8 (msg, IFLA_INET6_ADDR_GEN_MODE, addr_gen_mode);
+
+ nla_nest_end (msg, af_attr);
+ }
+
+ nla_nest_end (msg, af_spec);
return TRUE;
+nla_put_failure:
+ return FALSE;
}
-gboolean
-_nmp_vt_cmd_plobj_init_from_nl_ip6_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache)
+static gboolean
+_nl_msg_new_link_set_linkinfo (struct nl_msg *msg,
+ NMLinkType link_type)
{
- NMPlatformIP6Route *obj = (NMPlatformIP6Route *) _obj;
- struct rtnl_route *nlo = (struct rtnl_route *) _nlo;
- struct nl_addr *dst, *gw;
- struct rtnl_nexthop *nexthop;
+ struct nlattr *info;
+ const char *kind;
- if (rtnl_route_get_type (nlo) != RTN_UNICAST ||
- rtnl_route_get_table (nlo) != RT_TABLE_MAIN ||
- rtnl_route_get_tos (nlo) != 0 ||
- rtnl_route_get_nnexthops (nlo) != 1)
- return FALSE;
+ nm_assert (msg);
- nexthop = rtnl_route_nexthop_n (nlo, 0);
- if (!nexthop)
- g_return_val_if_reached (FALSE);
+ kind = nm_link_type_to_rtnl_type_string (link_type);
+ if (!kind)
+ goto nla_put_failure;
- dst = rtnl_route_get_dst (nlo);
- if (!dst)
- g_return_val_if_reached (FALSE);
+ if (!(info = nla_nest_start (msg, IFLA_LINKINFO)))
+ goto nla_put_failure;
- if (nl_addr_get_len (dst)) {
- if (nl_addr_get_len (dst) != sizeof (obj->network))
- g_return_val_if_reached (FALSE);
- memcpy (&obj->network, nl_addr_get_binary_addr (dst), sizeof (obj->network));
- }
- obj->ifindex = rtnl_route_nh_get_ifindex (nexthop);
- obj->plen = nl_addr_get_prefixlen (dst);
- obj->metric = rtnl_route_get_priority (nlo);
+ NLA_PUT_STRING (msg, IFLA_INFO_KIND, kind);
- if (id_only)
+ nla_nest_end (msg, info);
+
+ return TRUE;
+nla_put_failure:
+ return FALSE;
+}
+
+static gboolean
+_nl_msg_new_link_set_linkinfo_vlan (struct nl_msg *msg,
+ int vlan_id,
+ guint32 flags_mask,
+ guint32 flags_set,
+ const NMVlanQosMapping *ingress_qos,
+ int ingress_qos_len,
+ const NMVlanQosMapping *egress_qos,
+ int egress_qos_len)
+{
+ struct nlattr *info;
+ struct nlattr *data;
+ guint i;
+ gboolean has_any_vlan_properties = FALSE;
+
+#define VLAN_XGRESS_PRIO_VALID(from) (((from) & ~(guint32) 0x07) == 0)
+
+ nm_assert (msg);
+
+ /* We must not create an empty IFLA_LINKINFO section. Otherwise, kernel
+ * rejects the request as invalid. */
+ if ( flags_mask != 0
+ || vlan_id >= 0)
+ has_any_vlan_properties = TRUE;
+ if ( !has_any_vlan_properties
+ && ingress_qos && ingress_qos_len > 0) {
+ for (i = 0; i < ingress_qos_len; i++) {
+ if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) {
+ has_any_vlan_properties = TRUE;
+ break;
+ }
+ }
+ }
+ if ( !has_any_vlan_properties
+ && egress_qos && egress_qos_len > 0) {
+ for (i = 0; i < egress_qos_len; i++) {
+ if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) {
+ has_any_vlan_properties = TRUE;
+ break;
+ }
+ }
+ }
+ if (!has_any_vlan_properties)
return TRUE;
- gw = rtnl_route_nh_get_gateway (nexthop);
- if (gw) {
- if (nl_addr_get_len (gw) != sizeof (obj->gateway))
- g_warn_if_reached ();
- else
- memcpy (&obj->gateway, nl_addr_get_binary_addr (gw), sizeof (obj->gateway));
+ if (!(info = nla_nest_start (msg, IFLA_LINKINFO)))
+ goto nla_put_failure;
+
+ NLA_PUT_STRING (msg, IFLA_INFO_KIND, "vlan");
+
+ if (!(data = nla_nest_start (msg, IFLA_INFO_DATA)))
+ goto nla_put_failure;
+
+ if (vlan_id >= 0)
+ NLA_PUT_U16 (msg, IFLA_VLAN_ID, vlan_id);
+
+ if (flags_mask != 0) {
+ struct ifla_vlan_flags flags = {
+ .flags = flags_mask & flags_set,
+ .mask = flags_mask,
+ };
+
+ NLA_PUT (msg, IFLA_VLAN_FLAGS, sizeof (flags), &flags);
}
- rtnl_route_get_metric (nlo, RTAX_ADVMSS, &obj->mss);
- if (rtnl_route_get_flags (nlo) & RTM_F_CLONED)
- obj->source = _NM_IP_CONFIG_SOURCE_RTM_F_CLONED;
- else
- obj->source = _nm_ip_config_source_from_rtprot (rtnl_route_get_protocol (nlo));
+
+ if (ingress_qos && ingress_qos_len > 0) {
+ struct nlattr *qos = NULL;
+
+ for (i = 0; i < ingress_qos_len; i++) {
+ /* Silently ignore invalid mappings. Kernel would truncate
+ * them and modify the wrong mapping. */
+ if (VLAN_XGRESS_PRIO_VALID (ingress_qos[i].from)) {
+ if (!qos) {
+ if (!(qos = nla_nest_start (msg, IFLA_VLAN_INGRESS_QOS)))
+ goto nla_put_failure;
+ }
+ NLA_PUT (msg, i, sizeof (ingress_qos[i]), &ingress_qos[i]);
+ }
+ }
+
+ if (qos)
+ nla_nest_end (msg, qos);
+ }
+
+ if (egress_qos && egress_qos_len > 0) {
+ struct nlattr *qos = NULL;
+
+ for (i = 0; i < egress_qos_len; i++) {
+ if (VLAN_XGRESS_PRIO_VALID (egress_qos[i].to)) {
+ if (!qos) {
+ if (!(qos = nla_nest_start(msg, IFLA_VLAN_EGRESS_QOS)))
+ goto nla_put_failure;
+ }
+ NLA_PUT (msg, i, sizeof (egress_qos[i]), &egress_qos[i]);
+ }
+ }
+
+ if (qos)
+ nla_nest_end(msg, qos);
+ }
+
+ nla_nest_end (msg, data);
+ nla_nest_end (msg, info);
return TRUE;
+nla_put_failure:
+ return FALSE;
+}
+
+static struct nl_msg *
+_nl_msg_new_link (int nlmsg_type,
+ int nlmsg_flags,
+ int ifindex,
+ const char *ifname,
+ unsigned flags)
+{
+ struct nl_msg *msg;
+ struct ifinfomsg ifi = {
+ .ifi_flags = flags,
+ .ifi_index = ifindex,
+ };
+
+ nm_assert (NM_IN_SET (nlmsg_type, RTM_DELLINK, RTM_NEWLINK, RTM_GETLINK));
+
+ if (!(msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags)))
+ g_return_val_if_reached (NULL);
+
+ if (nlmsg_append (msg, &ifi, sizeof (ifi), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (ifname)
+ NLA_PUT_STRING (msg, IFLA_IFNAME, ifname);
+
+ return msg;
+nla_put_failure:
+ nlmsg_free (msg);
+ g_return_val_if_reached (NULL);
+}
+
+/* Copied and modified from libnl3's build_addr_msg(). */
+static struct nl_msg *
+_nl_msg_new_address (int nlmsg_type,
+ int nlmsg_flags,
+ int family,
+ int ifindex,
+ gconstpointer address,
+ int plen,
+ gconstpointer peer_address,
+ guint32 flags,
+ int scope,
+ guint32 lifetime,
+ guint32 preferred,
+ const char *label)
+{
+ struct nl_msg *msg;
+ struct ifaddrmsg am = {
+ .ifa_family = family,
+ .ifa_index = ifindex,
+ .ifa_prefixlen = plen,
+ .ifa_flags = flags,
+ };
+ gsize addr_len;
+
+ nm_assert (NM_IN_SET (family, AF_INET, AF_INET6));
+ nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWADDR, RTM_DELADDR));
+
+ msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
+ if (!msg)
+ g_return_val_if_reached (NULL);
+
+ if (scope == -1) {
+ /* Allow having scope unset, and detect the scope (including IPv4 compatibility hack). */
+ if ( family == AF_INET
+ && address
+ && *((char *) address) == 127)
+ scope = RT_SCOPE_HOST;
+ else
+ scope = RT_SCOPE_UNIVERSE;
+ }
+ am.ifa_scope = scope,
+
+ addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
+
+ if (nlmsg_append (msg, &am, sizeof (am), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ if (address)
+ NLA_PUT (msg, IFA_LOCAL, addr_len, address);
+
+ if (peer_address)
+ NLA_PUT (msg, IFA_ADDRESS, addr_len, peer_address);
+ else if (address)
+ NLA_PUT (msg, IFA_ADDRESS, addr_len, address);
+
+ if (label && label[0])
+ NLA_PUT_STRING (msg, IFA_LABEL, label);
+
+ if ( family == AF_INET
+ && nlmsg_type != RTM_DELADDR
+ && address
+ && *((in_addr_t *) address) != 0) {
+ in_addr_t broadcast;
+
+ broadcast = *((in_addr_t *) address) | ~nm_utils_ip4_prefix_to_netmask (plen);
+ NLA_PUT (msg, IFA_BROADCAST, addr_len, &broadcast);
+ }
+
+ if ( lifetime != NM_PLATFORM_LIFETIME_PERMANENT
+ || preferred != NM_PLATFORM_LIFETIME_PERMANENT) {
+ struct ifa_cacheinfo ca = {
+ .ifa_valid = lifetime,
+ .ifa_prefered = preferred,
+ };
+
+ NLA_PUT (msg, IFA_CACHEINFO, sizeof(ca), &ca);
+ }
+
+ if (flags & ~0xFF) {
+ /* only set the IFA_FLAGS attribute, if they actually contain additional
+ * flags that are not already set to am.ifa_flags.
+ *
+ * Older kernels refuse RTM_NEWADDR and RTM_NEWROUTE messages with EINVAL
+ * if they contain unknown netlink attributes. See net/core/rtnetlink.c, which
+ * was fixed by kernel commit 661d2967b3f1b34eeaa7e212e7b9bbe8ee072b59. */
+ NLA_PUT_U32 (msg, IFA_FLAGS, flags);
+ }
+
+ return msg;
+
+nla_put_failure:
+ nlmsg_free (msg);
+ g_return_val_if_reached (NULL);
+}
+
+/* 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,
+ int nlmsg_flags,
+ int family,
+ int ifindex,
+ NMIPConfigSource source,
+ unsigned char scope,
+ gconstpointer network,
+ int plen,
+ gconstpointer gateway,
+ guint32 metric,
+ guint32 mss,
+ gconstpointer pref_src)
+{
+ struct nl_msg *msg;
+ struct rtmsg rtmsg = {
+ .rtm_family = family,
+ .rtm_tos = 0,
+ .rtm_table = RT_TABLE_MAIN, /* omit setting RTA_TABLE attribute */
+ .rtm_protocol = _nm_ip_config_source_to_rtprot (source),
+ .rtm_scope = scope,
+ .rtm_type = RTN_UNICAST,
+ .rtm_flags = 0,
+ .rtm_dst_len = plen,
+ .rtm_src_len = 0,
+ };
+ NMIPAddr network_clean;
+
+ gsize addr_len;
+
+ nm_assert (NM_IN_SET (family, AF_INET, AF_INET6));
+ nm_assert (NM_IN_SET (nlmsg_type, RTM_NEWROUTE, RTM_DELROUTE));
+ nm_assert (network);
+
+ msg = nlmsg_alloc_simple (nlmsg_type, nlmsg_flags);
+ if (!msg)
+ g_return_val_if_reached (NULL);
+
+ if (nlmsg_append (msg, &rtmsg, sizeof (rtmsg), NLMSG_ALIGNTO) < 0)
+ goto nla_put_failure;
+
+ addr_len = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
+
+ clear_host_address (family, network, plen, &network_clean);
+ NLA_PUT (msg, RTA_DST, addr_len, &network_clean);
+
+ NLA_PUT_U32 (msg, RTA_PRIORITY, metric);
+
+ if (pref_src)
+ NLA_PUT (msg, RTA_PREFSRC, addr_len, pref_src);
+
+ if (mss > 0) {
+ struct nlattr *metrics;
+
+ metrics = nla_nest_start (msg, RTA_METRICS);
+ if (!metrics)
+ goto nla_put_failure;
+
+ NLA_PUT_U32 (msg, RTAX_ADVMSS, mss);
+
+ nla_nest_end(msg, metrics);
+ }
+
+ /* We currently don't have need for multi-hop routes... */
+ if ( gateway
+ && memcmp (gateway, &nm_ip_addr_zero, addr_len) != 0)
+ NLA_PUT (msg, RTA_GATEWAY, addr_len, gateway);
+ NLA_PUT_U32 (msg, RTA_OIF, ifindex);
+
+ return msg;
+
+nla_put_failure:
+ nlmsg_free (msg);
+ g_return_val_if_reached (NULL);
+}
+
+/******************************************************************/
+
+static int
+_nl_sock_flush_data (struct nl_sock *sk)
+{
+ int nle;
+ struct nl_cb *cb;
+
+ cb = nl_cb_clone (nl_socket_get_cb (sk));
+ if (cb == NULL)
+ return -NLE_NOMEM;
+
+ nl_cb_set (cb, NL_CB_VALID, NL_CB_DEFAULT, NULL, NULL);
+ nl_cb_set (cb, NL_CB_SEQ_CHECK, NL_CB_DEFAULT, NULL, NULL);
+ nl_cb_err (cb, NL_CB_DEFAULT, NULL, NULL);
+ do {
+ errno = 0;
+
+ nle = nl_recvmsgs (sk, cb);
+
+ /* Work around a libnl bug fixed in 3.2.22 (375a6294) */
+ if (nle == 0 && (errno == EAGAIN || errno == EWOULDBLOCK))
+ nle = -NLE_AGAIN;
+ } while (nle != -NLE_AGAIN);
+
+ nl_cb_put (cb);
+ return nle;
+}
+
+static void
+_nl_msg_set_seq (struct nl_sock *sk, struct nl_msg *msg, guint32 *out_seq)
+{
+ guint32 seq;
+
+ /* choose our own sequence number, because libnl does not ensure that
+ * it isn't zero -- which would confuse our checking for outstanding
+ * messages. */
+ seq = nl_socket_use_seq (sk);
+ if (seq == 0)
+ seq = nl_socket_use_seq (sk);
+
+ nlmsg_hdr (msg)->nlmsg_seq = seq;
+ if (out_seq)
+ *out_seq = seq;
+}
+
+/******************************************************************/
+
+static int _support_kernel_extended_ifa_flags = -1;
+
+#define _support_kernel_extended_ifa_flags_still_undecided() (G_UNLIKELY (_support_kernel_extended_ifa_flags == -1))
+
+static void
+_support_kernel_extended_ifa_flags_detect (struct nl_msg *msg)
+{
+ struct nlmsghdr *msg_hdr;
+
+ if (!_support_kernel_extended_ifa_flags_still_undecided ())
+ return;
+
+ msg_hdr = nlmsg_hdr (msg);
+ if (msg_hdr->nlmsg_type != RTM_NEWADDR)
+ return;
+
+ /* the extended address flags are only set for AF_INET6 */
+ if (((struct ifaddrmsg *) nlmsg_data (msg_hdr))->ifa_family != AF_INET6)
+ return;
+
+ /* see if the nl_msg contains the IFA_FLAGS attribute. If it does,
+ * we assume, that the kernel supports extended flags, IFA_F_MANAGETEMPADDR
+ * and IFA_F_NOPREFIXROUTE (they were added together).
+ **/
+ _support_kernel_extended_ifa_flags = !!nlmsg_find_attr (msg_hdr, sizeof (struct ifaddrmsg), 8 /* IFA_FLAGS */);
+ _LOG2D ("support: kernel-extended-ifa-flags: %ssupported", _support_kernel_extended_ifa_flags ? "" : "not ");
+}
+
+static gboolean
+_support_kernel_extended_ifa_flags_get (void)
+{
+ if (_support_kernel_extended_ifa_flags_still_undecided ()) {
+ _LOG2W ("support: kernel-extended-ifa-flags: unable to detect kernel support for handling IPv6 temporary addresses. Assume none");
+ _support_kernel_extended_ifa_flags = 0;
+ }
+ return _support_kernel_extended_ifa_flags;
+}
+
+/******************************************************************
+ * NMPlatform types and functions
+ ******************************************************************/
+
+typedef struct _NMLinuxPlatformPrivate NMLinuxPlatformPrivate;
+
+struct _NMLinuxPlatformPrivate {
+ struct nl_sock *nlh;
+ struct nl_sock *nlh_event;
+ guint32 nlh_seq_expect;
+ guint32 nlh_seq_last;
+ NMPCache *cache;
+ GIOChannel *event_channel;
+ guint event_id;
+
+ gboolean sysctl_get_warned;
+ GHashTable *sysctl_get_prev_values;
+
+ GUdevClient *udev_client;
+
+ struct {
+ DelayedActionType flags;
+ GPtrArray *list_master_connected;
+ GPtrArray *list_refresh_link;
+ gint is_handling;
+ guint idle_id;
+ } delayed_action;
+
+ GHashTable *prune_candidates;
+ GHashTable *delayed_deletion;
+
+ GHashTable *wifi_data;
+};
+
+static inline NMLinuxPlatformPrivate *
+NM_LINUX_PLATFORM_GET_PRIVATE (const void *self)
+{
+ nm_assert (NM_IS_LINUX_PLATFORM (self));
+
+ return ((NMLinuxPlatform *) self)->priv;
+}
+
+G_DEFINE_TYPE (NMLinuxPlatform, nm_linux_platform, NM_TYPE_PLATFORM)
+
+void
+nm_linux_platform_setup (void)
+{
+ g_object_new (NM_TYPE_LINUX_PLATFORM,
+ NM_PLATFORM_REGISTER_SINGLETON, TRUE,
+ NULL);
+}
+
+/******************************************************************/
+
+static gboolean
+check_support_kernel_extended_ifa_flags (NMPlatform *platform)
+{
+ g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
+
+ return _support_kernel_extended_ifa_flags_get ();
+}
+
+static gboolean
+check_support_user_ipv6ll (NMPlatform *platform)
+{
+ g_return_val_if_fail (NM_IS_LINUX_PLATFORM (platform), FALSE);
+
+ return _support_user_ipv6ll_get ();
+}
+
+static void
+process_events (NMPlatform *platform)
+{
+ delayed_action_handle_all (platform, TRUE);
+}
+
+/******************************************************************/
+
+#define cache_lookup_all_objects(type, platform, obj_type, visible_only) \
+ ((const type *const*) nmp_cache_lookup_multi (NM_LINUX_PLATFORM_GET_PRIVATE ((platform))->cache, \
+ nmp_cache_id_init_object_type (NMP_CACHE_ID_STATIC, (obj_type), (visible_only)), \
+ NULL))
+
+static gboolean
+_lookup_cached_link_data (NMPlatform *platform,
+ int ifindex,
+ const char *logging_tag,
+ unsigned *out_flags)
+{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+ const NMPObject *obj_cache;
+
+ obj_cache = nmp_cache_lookup_link (priv->cache, ifindex);
+ if ( obj_cache
+ && obj_cache->_link.netlink.is_in_netlink) {
+ *out_flags = obj_cache->link.flags;
+ return TRUE;
+ }
+ _LOGD ("link: change %d: %s: link does not exist", ifindex, logging_tag);
+ return FALSE;
}
/******************************************************************/
@@ -1831,8 +2680,8 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
NMPlatform *platform = NM_PLATFORM (user_data);
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
const NMPClass *klass;
- char str_buf[sizeof (_nm_platform_to_string_buffer)];
- char str_buf2[sizeof (_nm_platform_to_string_buffer)];
+ char str_buf[sizeof (_nm_utils_to_string_buffer)];
+ char str_buf2[sizeof (_nm_utils_to_string_buffer)];
nm_assert (old || new);
nm_assert (NM_IN_SET (ops_type, NMP_CACHE_OPS_ADDED, NMP_CACHE_OPS_REMOVED, NMP_CACHE_OPS_UPDATED));
@@ -1986,14 +2835,14 @@ cache_pre_hook (NMPCache *cache, const NMPObject *old, const NMPObject *new, NMP
}
static NMPCacheOpsType
-cache_remove_netlink (NMPlatform *platform, const NMPObject *obj_needle, NMPObject **out_obj_cache, gboolean *out_was_visible, NMPlatformReason reason)
+cache_remove_netlink (NMPlatform *platform, const NMPObject *obj_id, NMPObject **out_obj_cache, gboolean *out_was_visible, NMPlatformReason reason)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
NMPObject *obj_cache;
gboolean was_visible;
NMPCacheOpsType cache_op;
- cache_op = nmp_cache_remove_netlink (priv->cache, obj_needle, &obj_cache, &was_visible, cache_pre_hook, platform);
+ cache_op = nmp_cache_remove_netlink (priv->cache, obj_id, &obj_cache, &was_visible, cache_pre_hook, platform);
do_emit_signal (platform, obj_cache, cache_op, was_visible, NM_PLATFORM_REASON_INTERNAL);
if (out_obj_cache)
@@ -2046,9 +2895,16 @@ static void
do_request_link (NMPlatform *platform, int ifindex, const char *name, gboolean handle_delayed_action)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ int nle;
guint32 seq;
- _LOGT ("do_request_link (%d,%s)", ifindex, name ? name : "");
+ if (name && !name[0])
+ name = NULL;
+
+ g_return_if_fail (ifindex > 0 || name);
+
+ _LOGD ("do-request-link: %d %s", ifindex, name ? name : "");
if (ifindex > 0) {
NMPObject *obj;
@@ -2062,8 +2918,18 @@ do_request_link (NMPlatform *platform, int ifindex, const char *name, gboolean h
event_handler_read_netlink_all (platform, FALSE);
- if (_nl_sock_request_link (platform, priv->nlh_event, ifindex, name, &seq) == 0)
- _new_sequence_number (platform, seq);
+ nlmsg = _nl_msg_new_link (RTM_GETLINK,
+ 0,
+ ifindex,
+ name,
+ 0);
+ if (nlmsg) {
+ _nl_msg_set_seq (priv->nlh_event, nlmsg, &seq);
+
+ nle = nl_send_auto (priv->nlh_event, nlmsg);
+ if (nle >= 0)
+ _new_sequence_number (platform, seq);
+ }
event_handler_read_netlink_all (platform, TRUE);
@@ -2098,6 +2964,12 @@ do_request_all (NMPlatform *platform, DelayedActionType action_type, gboolean ha
for (iflags = (DelayedActionType) 0x1LL; iflags <= DELAYED_ACTION_TYPE_MAX; iflags <<= 1) {
if (NM_FLAGS_HAS (action_type, iflags)) {
NMPObjectType obj_type = delayed_action_refresh_to_object_type (iflags);
+ const NMPClass *klass = nmp_class_from_type (obj_type);
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ struct rtgenmsg gmsg = {
+ .rtgen_family = klass->addr_family,
+ };
+ int nle;
/* clear any delayed action that request a refresh of this object type. */
priv->delayed_action.flags &= ~iflags;
@@ -2110,9 +2982,26 @@ do_request_all (NMPlatform *platform, DelayedActionType action_type, gboolean ha
event_handler_read_netlink_all (platform, FALSE);
- if (_nl_sock_request_all (platform, priv->nlh_event, obj_type, &seq) == 0)
+ /* reimplement
+ * nl_rtgen_request (sk, klass->rtm_gettype, klass->addr_family, NLM_F_DUMP);
+ * because we need the sequence number.
+ */
+ nlmsg = nlmsg_alloc_simple (klass->rtm_gettype, NLM_F_DUMP);
+ if (!nlmsg)
+ goto next;
+
+ nle = nlmsg_append (nlmsg, &gmsg, sizeof (gmsg), NLMSG_ALIGNTO);
+ if (nle < 0)
+ goto next;
+
+ _nl_msg_set_seq (priv->nlh_event, nlmsg, &seq);
+
+ nle = nl_send_auto (priv->nlh_event, nlmsg);
+ if (nle >= 0)
_new_sequence_number (platform, seq);
}
+next:
+ ;
}
event_handler_read_netlink_all (platform, TRUE);
@@ -2122,211 +3011,6 @@ do_request_all (NMPlatform *platform, DelayedActionType action_type, gboolean ha
delayed_action_handle_all (platform, FALSE);
}
-static gboolean
-kernel_add_object (NMPlatform *platform, NMPObjectType obj_type, const struct nl_object *nlo)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- int nle;
-
- g_return_val_if_fail (nlo, FALSE);
-
- switch (obj_type) {
- case NMP_OBJECT_TYPE_LINK:
- nle = rtnl_link_add (priv->nlh, (struct rtnl_link *) nlo, NLM_F_CREATE);
- break;
- case NMP_OBJECT_TYPE_IP4_ADDRESS:
- case NMP_OBJECT_TYPE_IP6_ADDRESS:
- nle = rtnl_addr_add (priv->nlh, (struct rtnl_addr *) nlo, NLM_F_CREATE | NLM_F_REPLACE);
- break;
- case NMP_OBJECT_TYPE_IP4_ROUTE:
- case NMP_OBJECT_TYPE_IP6_ROUTE:
- nle = rtnl_route_add (priv->nlh, (struct rtnl_route *) nlo, NLM_F_CREATE | NLM_F_REPLACE);
- break;
- default:
- g_return_val_if_reached (-NLE_INVAL);
- }
-
- _LOGT ("kernel-add-%s: returned %s (%d)",
- nmp_class_from_type (obj_type)->obj_type_name, nl_geterror (nle), -nle);
-
- switch (nle) {
- case -NLE_SUCCESS:
- return -NLE_SUCCESS;
- case -NLE_EXIST:
- /* NLE_EXIST is considered equivalent to success to avoid race conditions. You
- * never know when something sends an identical object just before
- * NetworkManager. */
- if (obj_type != NMP_OBJECT_TYPE_LINK)
- return -NLE_SUCCESS;
- /* fall-through */
- default:
- return nle;
- }
-}
-
-static int
-kernel_delete_object (NMPlatform *platform, NMPObjectType object_type, const struct nl_object *object)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- int nle;
-
- switch (object_type) {
- case NMP_OBJECT_TYPE_LINK:
- nle = rtnl_link_delete (priv->nlh, (struct rtnl_link *) object);
- break;
- case NMP_OBJECT_TYPE_IP4_ADDRESS:
- case NMP_OBJECT_TYPE_IP6_ADDRESS:
- nle = rtnl_addr_delete (priv->nlh, (struct rtnl_addr *) object, 0);
- break;
- case NMP_OBJECT_TYPE_IP4_ROUTE:
- case NMP_OBJECT_TYPE_IP6_ROUTE:
- nle = rtnl_route_delete (priv->nlh, (struct rtnl_route *) object, 0);
- break;
- default:
- g_assert_not_reached ();
- }
-
- switch (nle) {
- case -NLE_SUCCESS:
- return NLE_SUCCESS;
- case -NLE_OBJ_NOTFOUND:
- _LOGT ("kernel-delete-%s: failed with \"%s\" (%d), meaning the object was already removed",
- nmp_class_from_type (object_type)->obj_type_name, nl_geterror (nle), -nle);
- return -NLE_SUCCESS;
- case -NLE_FAILURE:
- if (object_type == NMP_OBJECT_TYPE_IP6_ADDRESS) {
- /* On RHEL7 kernel, deleting a non existing address fails with ENXIO (which libnl maps to NLE_FAILURE) */
- _LOGT ("kernel-delete-%s: deleting address failed with \"%s\" (%d), meaning the address was already removed",
- nmp_class_from_type (object_type)->obj_type_name, nl_geterror (nle), -nle);
- return NLE_SUCCESS;
- }
- break;
- case -NLE_NOADDR:
- if (object_type == NMP_OBJECT_TYPE_IP4_ADDRESS || object_type == NMP_OBJECT_TYPE_IP6_ADDRESS) {
- _LOGT ("kernel-delete-%s: deleting address failed with \"%s\" (%d), meaning the address was already removed",
- nmp_class_from_type (object_type)->obj_type_name, nl_geterror (nle), -nle);
- return -NLE_SUCCESS;
- }
- break;
- default:
- break;
- }
- _LOGT ("kernel-delete-%s: failed with %s (%d)",
- nmp_class_from_type (object_type)->obj_type_name, nl_geterror (nle), -nle);
- return nle;
-}
-
-static int
-kernel_change_link (NMPlatform *platform, struct rtnl_link *nlo, gboolean *complete_from_cache)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- struct nl_msg *msg;
- int nle;
- const int nlflags = 0;
- int ifindex;
-
- ifindex = rtnl_link_get_ifindex (nlo);
-
- g_return_val_if_fail (ifindex > 0, FALSE);
-
- /* Previously, we were using rtnl_link_change(), which builds a request based
- * on the diff with an original link instance.
- *
- * The diff only reused ifi_family, ifi_index, ifi_flags, and name from
- * the original link (see rtnl_link_build_change_request()).
- *
- * We don't do that anymore as we don't have an "orig" netlink instance that
- * we can use. Instead the caller must ensure to properly initialize @nlo,
- * especially it must set family, ifindex (or ifname) and flags.
- * ifname should be set *only* if the caller wishes to change the name.
- *
- * @complete_from_cache is a convenience to copy the link flags over the link inside
- * the platform cache. */
-
- if (*complete_from_cache) {
- const NMPObject *obj_cache;
-
- obj_cache = nmp_cache_lookup_link (priv->cache, ifindex);
- if (!obj_cache || !obj_cache->_link.netlink.is_in_netlink) {
- _LOGT ("kernel-change-link: failure changing link %d: cannot complete link", ifindex);
- *complete_from_cache = FALSE;
- return -NLE_INVAL;
- }
-
- rtnl_link_set_flags (nlo, obj_cache->link.flags);
-
- /* If the caller wants to rename the link, he should explicitly set
- * rtnl_link_set_name(). In all other cases, it should leave the name
- * unset. Unfortunately, there is not public API in libnl to modify the
- * attribute mask and clear (link->ce_mask = ~LINK_ATTR_IFNAME), so we
- * require the caller to do the right thing -- i.e. don't set the name.
- */
- }
-
- /* We don't use rtnl_link_change() because we have no original rtnl_link object
- * at hand. We also don't use rtnl_link_add() because that doesn't have the
- * hack to retry with RTM_SETLINK. Reimplement a mix of both. */
-
- nle = rtnl_link_build_add_request (nlo, nlflags, &msg);
- if (nle < 0) {
- _LOGT ("kernel-change-link: failure changing link %d: cannot construct message (%s, %d)",
- ifindex, nl_geterror (nle), -nle);
- return nle;
- }
-
-retry:
- nle = nl_send_auto_complete (priv->nlh, msg);
- if (nle < 0)
- goto errout;
-
- nle = nl_wait_for_ack(priv->nlh);
- if (nle == -NLE_OPNOTSUPP && nlmsg_hdr (msg)->nlmsg_type == RTM_NEWLINK) {
- nlmsg_hdr (msg)->nlmsg_type = RTM_SETLINK;
- goto retry;
- }
-
-errout:
- nlmsg_free(msg);
-
- /* NLE_EXIST is considered equivalent to success to avoid race conditions. You
- * never know when something sends an identical object just before
- * NetworkManager.
- *
- * When netlink returns NLE_OBJ_NOTFOUND, it usually means it failed to find
- * firmware for the device, especially on nm_platform_link_set_up ().
- * This is basically the same check as in the original code and could
- * potentially be improved.
- */
- switch (nle) {
- case -NLE_SUCCESS:
- _LOGT ("kernel-change-link: success changing link %d", ifindex);
- break;
- case -NLE_EXIST:
- _LOGT ("kernel-change-link: success changing link %d: %s (%d)",
- ifindex, nl_geterror (nle), -nle);
- break;
- case -NLE_OBJ_NOTFOUND:
- _LOGT ("kernel-change-link: failure changing link %d: firmware not found (%s, %d)",
- ifindex, nl_geterror (nle), -nle);
- break;
- default:
- _LOGT ("kernel-change-link: failure changing link %d: netlink error (%s, %d)",
- ifindex, nl_geterror (nle), -nle);
- break;
- }
-
- return nle;
-}
-
-static void
-ref_object (struct nl_object *obj, void *data)
-{
- struct nl_object **out = data;
-
- nl_object_get (obj);
- *out = obj;
-}
-
static int
event_seq_check (struct nl_msg *msg, gpointer user_data)
{
@@ -2374,85 +3058,75 @@ event_notification (struct nl_msg *msg, gpointer user_data)
{
NMPlatform *platform = NM_PLATFORM (user_data);
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (user_data);
- auto_nl_object struct nl_object *nlo = NULL;
nm_auto_nmpobj NMPObject *obj = NULL;
+ nm_auto_nmpobj NMPObject *obj_cache = NULL;
struct nlmsghdr *msghdr;
char buf_nlmsg_type[16];
+ gboolean id_only = FALSE;
msghdr = nlmsg_hdr (msg);
if (_support_kernel_extended_ifa_flags_still_undecided () && msghdr->nlmsg_type == RTM_NEWADDR)
_support_kernel_extended_ifa_flags_detect (msg);
- nl_msg_parse (msg, ref_object, &nlo);
- if (!nlo)
- return NL_OK;
-
- if (_support_user_ipv6ll_still_undecided() && msghdr->nlmsg_type == RTM_NEWLINK)
- _support_user_ipv6ll_detect ((struct rtnl_link *) nlo);
+ if (NM_IN_SET (msghdr->nlmsg_type, RTM_DELLINK, RTM_DELADDR, RTM_DELROUTE)) {
+ /* The event notifies about a deleted object. We don't need to initialize all
+ * fields of the object. */
+ id_only = TRUE;
+ }
- switch (msghdr->nlmsg_type) {
- case RTM_DELADDR:
- case RTM_DELLINK:
- case RTM_DELROUTE:
- /* The event notifies about a deleted object. We don't need to initialize all the
- * fields of the nmp-object. Shortcut nmp_object_from_nl(). */
- obj = nmp_object_from_nl (platform, nlo, TRUE, TRUE);
- _LOGt ("event-notification: %s, seq %u: %s",
+ obj = nmp_object_new_from_nl (platform, priv->cache, msg, id_only);
+ if (!obj) {
+ _LOGt ("event-notification: %s, seq %u: ignore",
_nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)),
- msghdr->nlmsg_seq, nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
- break;
- default:
- obj = nmp_object_from_nl (platform, nlo, FALSE, TRUE);
- _LOGt ("event-notification: %s, seq %u: %s",
- _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)),
- msghdr->nlmsg_seq, nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
- break;
+ msghdr->nlmsg_seq);
+ return NL_OK;
}
- if (obj) {
- nm_auto_nmpobj NMPObject *obj_cache = NULL;
-
- switch (msghdr->nlmsg_type) {
+ _LOGt ("event-notification: %s, seq %u: %s",
+ _nl_nlmsg_type_to_str (msghdr->nlmsg_type, buf_nlmsg_type, sizeof (buf_nlmsg_type)),
+ msghdr->nlmsg_seq, nmp_object_to_string (obj,
+ id_only ? NMP_OBJECT_TO_STRING_ID : NMP_OBJECT_TO_STRING_PUBLIC, NULL, 0));
- case RTM_NEWLINK:
- if (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK) {
- if (g_hash_table_lookup (priv->delayed_deletion, obj) != NULL) {
- /* the object is scheduled for delayed deletion. Replace that object
- * by clearing the value from priv->delayed_deletion. */
- _LOGT ("delayed-deletion: clear delayed deletion of protected object %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
- g_hash_table_insert (priv->delayed_deletion, nmp_object_ref (obj), NULL);
- }
- delayed_action_clear_REFRESH_LINK (platform, obj->link.ifindex);
- }
- /* fall-through */
- case RTM_NEWADDR:
- case RTM_NEWROUTE:
- cache_update_netlink (platform, obj, &obj_cache, NULL, NM_PLATFORM_REASON_EXTERNAL);
- break;
+ switch (msghdr->nlmsg_type) {
- case RTM_DELLINK:
- if ( NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK
- && g_hash_table_contains (priv->delayed_deletion, obj)) {
- /* We sometimes receive spurious RTM_DELLINK events. In this case, we want to delay
- * the deletion of the object until later. */
- _LOGT ("delayed-deletion: delay deletion of protected object %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
- g_hash_table_insert (priv->delayed_deletion, nmp_object_ref (obj), nmp_object_ref (obj));
- break;
+ case RTM_NEWLINK:
+ if (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK) {
+ if (g_hash_table_lookup (priv->delayed_deletion, obj) != NULL) {
+ /* the object is scheduled for delayed deletion. Replace that object
+ * by clearing the value from priv->delayed_deletion. */
+ _LOGT ("delayed-deletion: clear delayed deletion of protected object %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
+ g_hash_table_insert (priv->delayed_deletion, nmp_object_ref (obj), NULL);
}
- /* fall-through */
- case RTM_DELADDR:
- case RTM_DELROUTE:
- cache_remove_netlink (platform, obj, &obj_cache, NULL, NM_PLATFORM_REASON_EXTERNAL);
- break;
+ delayed_action_clear_REFRESH_LINK (platform, obj->link.ifindex);
+ }
+ /* fall-through */
+ case RTM_NEWADDR:
+ case RTM_NEWROUTE:
+ cache_update_netlink (platform, obj, &obj_cache, NULL, NM_PLATFORM_REASON_EXTERNAL);
+ break;
- default:
+ case RTM_DELLINK:
+ if ( NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK
+ && g_hash_table_contains (priv->delayed_deletion, obj)) {
+ /* We sometimes receive spurious RTM_DELLINK events. In this case, we want to delay
+ * the deletion of the object until later. */
+ _LOGT ("delayed-deletion: delay deletion of protected object %s", nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_ID, NULL, 0));
+ g_hash_table_insert (priv->delayed_deletion, nmp_object_ref (obj), nmp_object_ref (obj));
break;
}
+ /* fall-through */
+ case RTM_DELADDR:
+ case RTM_DELROUTE:
+ cache_remove_netlink (platform, obj, &obj_cache, NULL, NM_PLATFORM_REASON_EXTERNAL);
+ break;
- cache_prune_candidates_drop (platform, obj_cache);
+ default:
+ break;
}
+ cache_prune_candidates_drop (platform, obj_cache);
+
return NL_OK;
}
@@ -2717,47 +3391,64 @@ _nm_platform_link_get_by_address (NMPlatform *platform,
return obj ? &obj->link : NULL;
}
-static struct nl_object *
-build_rtnl_link (int ifindex, const char *name, NMLinkType type)
+/*****************************************************************************/
+
+static const NMPObject *
+link_get_lnk (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link)
{
- struct rtnl_link *rtnllink;
- int nle;
+ const NMPObject *obj = cache_lookup_link (platform, ifindex);
- rtnllink = _nl_rtnl_link_alloc (ifindex, name);
- if (type) {
- nle = rtnl_link_set_type (rtnllink, nm_link_type_to_rtnl_type_string (type));
- g_assert (!nle);
- }
- return (struct nl_object *) rtnllink;
-}
+ if (!obj)
+ return NULL;
-struct nl_object *
-_nmp_vt_cmd_plobj_to_nl_link (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
-{
- const NMPlatformLink *obj = (const NMPlatformLink *) _obj;
+ NM_SET_OUT (out_link, &obj->link);
- return build_rtnl_link (obj->ifindex,
- obj->name[0] ? obj->name : NULL,
- obj->type);
+ if (!obj->_link.netlink.lnk)
+ return NULL;
+ if ( link_type != NM_LINK_TYPE_NONE
+ && ( link_type != obj->link.type
+ || link_type != NMP_OBJECT_GET_CLASS (obj->_link.netlink.lnk)->lnk_link_type))
+ return NULL;
+
+ return obj->_link.netlink.lnk;
}
+/*****************************************************************************/
+
static gboolean
-do_add_link (NMPlatform *platform, const char *name, const struct rtnl_link *nlo)
+do_add_link (NMPlatform *platform,
+ NMLinkType link_type,
+ const char *name,
+ struct nl_msg *nlmsg)
{
- NMPObject obj_needle;
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
int nle;
event_handler_read_netlink_all (platform, FALSE);
- nle = kernel_add_object (platform, NMP_OBJECT_TYPE_LINK, (const struct nl_object *) nlo);
+ nle = nl_send_auto (priv->nlh, nlmsg);
if (nle < 0) {
- _LOGE ("do-add-link: failure adding link '%s': %s", name, nl_geterror (nle));
+ _LOGE ("do-add-link[%s/%s]: failure sending netlink request \"%s\" (%d)",
+ name,
+ nm_link_type_to_string (link_type),
+ nl_geterror (nle), -nle);
return FALSE;
}
- _LOGD ("do-add-link: success adding link '%s'", name);
- nmp_object_stackinit_id_link (&obj_needle, 0);
- g_strlcpy (obj_needle.link.name, name, sizeof (obj_needle.link.name));
+ nle = nl_wait_for_ack (priv->nlh);
+ switch (nle) {
+ case -NLE_SUCCESS:
+ _LOGD ("do-add-link[%s/%s]: success adding",
+ name,
+ nm_link_type_to_string (link_type));
+ break;
+ default:
+ _LOGE ("do-add-link[%s/%s]: failed with \"%s\" (%d)",
+ name,
+ nm_link_type_to_string (link_type),
+ nl_geterror (nle), -nle);
+ return FALSE;
+ }
delayed_action_handle_all (platform, TRUE);
@@ -2765,35 +3456,40 @@ do_add_link (NMPlatform *platform, const char *name, const struct rtnl_link *nlo
* the notification is not yet ready via nlh_event, so we have to re-request the
* link so that it is in the cache. A better solution would be to do everything
* via one netlink socket. */
- if (!nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, 0, obj_needle.link.name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) {
- _LOGT ("do-add-link: reload: the added link is not yet ready. Request %s", obj_needle.link.name);
- do_request_link (platform, 0, obj_needle.link.name, TRUE);
+ if (!nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, 0, name, FALSE, NM_LINK_TYPE_NONE, NULL, NULL)) {
+ _LOGT ("do-add-link[%s/%s]: the added link is not yet ready. Request anew",
+ name,
+ nm_link_type_to_string (link_type));
+ do_request_link (platform, 0, name, TRUE);
}
- /* Return true, because kernel_add_object() succeeded. This doesn't indicate that the
- * object is now actuall in the cache, because there could be a race.
- *
- * For that, you'd have to look at @out_obj. */
+ /* Return true, because the netlink request succeeded. This doesn't indicate that the
+ * object is now actually in the cache, because there could be a race. */
return TRUE;
}
static gboolean
-do_add_link_with_lookup (NMPlatform *platform, const char *name, const struct rtnl_link *nlo, NMLinkType expected_link_type, NMPlatformLink *out_link)
+do_add_link_with_lookup (NMPlatform *platform,
+ NMLinkType link_type,
+ const char *name,
+ struct nl_msg *nlmsg,
+ NMPlatformLink *out_link)
{
const NMPObject *obj;
- do_add_link (platform, name, nlo);
+ do_add_link (platform, link_type, name, nlmsg);
obj = nmp_cache_lookup_link_full (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache,
- 0, name, FALSE, expected_link_type, NULL, NULL);
+ 0, name, FALSE, link_type, NULL, NULL);
if (out_link && obj)
*out_link = obj->link;
return !!obj;
}
static gboolean
-do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, const struct nl_object *nlo)
+do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
int nle;
nm_assert (NM_IN_SET (NMP_OBJECT_GET_TYPE (obj_id),
@@ -2802,50 +3498,109 @@ do_add_addrroute (NMPlatform *platform, const NMPObject *obj_id, const struct nl
event_handler_read_netlink_all (platform, FALSE);
- nle = kernel_add_object (platform, NMP_OBJECT_GET_CLASS (obj_id)->obj_type, (const struct nl_object *) nlo);
+ nle = nl_send_auto (priv->nlh, nlmsg);
if (nle < 0) {
- _LOGW ("do-add-%s: failure adding %s '%s': %s (%d)",
+ _LOGE ("do-add-%s[%s]: failure sending netlink request \"%s\" (%d)",
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
+ nl_geterror (nle), -nle);
+ return FALSE;
+ }
+
+ nle = nl_wait_for_ack (priv->nlh);
+ switch (nle) {
+ case -NLE_SUCCESS:
+ _LOGD ("do-add-%s[%s]: success adding", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
+ break;
+ case -NLE_EXIST:
+ /* NLE_EXIST is considered equivalent to success to avoid race conditions. You
+ * never know when something sends an identical object just before
+ * NetworkManager. */
+ _LOGD ("do-add-%s[%s]: adding link failed with \"%s\" (%d), meaning such a link already exists",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
+ nl_geterror (nle), -nle);
+ break;
+ default:
+ _LOGE ("do-add-%s[%s]: failed with \"%s\" (%d)",
NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
nl_geterror (nle), -nle);
return FALSE;
}
- _LOGD ("do-add-%s: success adding object %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
delayed_action_handle_all (platform, TRUE);
/* FIXME: instead of re-requesting the added object, add it via nlh_event
* so that the events are in sync. */
if (!nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, obj_id)) {
- _LOGT ("do-add-%s: reload: the added object is not yet ready. Request %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
+ _LOGT ("do-add-%s[%s]: the added object is not yet ready. Request anew",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id), TRUE);
}
/* The return value doesn't say, whether the object is in the platform cache after adding
- * it.
- * Instead the return value says, whether kernel_add_object() succeeded. */
+ * it. Instead the return value says, whether the netlink request succeeded. */
return TRUE;
}
-
static gboolean
-do_delete_object (NMPlatform *platform, const NMPObject *obj_id, const struct nl_object *nlo)
+do_delete_object (NMPlatform *platform, const NMPObject *obj_id, struct nl_msg *nlmsg)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- auto_nl_object struct nl_object *nlo_free = NULL;
int nle;
event_handler_read_netlink_all (platform, FALSE);
- if (!nlo)
- nlo = nlo_free = nmp_object_to_nl (platform, obj_id, FALSE);
+ nle = nl_send_auto (priv->nlh, nlmsg);
+ if (nle < 0) {
+ _LOGE ("do-delete-%s[%s]: failure sending netlink request \"%s\" (%d)",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
+ nl_geterror (nle), -nle);
+ return FALSE;
+ }
- nle = kernel_delete_object (platform, NMP_OBJECT_GET_TYPE (obj_id), nlo);
- if (nle < 0)
- _LOGE ("do-delete-%s: failure deleting '%s': %s (%d)", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0), nl_geterror (nle), -nle);
- else
- _LOGD ("do-delete-%s: success deleting '%s'", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
+ nle = nl_wait_for_ack (priv->nlh);
+ switch (nle) {
+ case -NLE_SUCCESS:
+ _LOGD ("do-delete-%s[%s]: success deleting", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
+ break;
+ case -NLE_OBJ_NOTFOUND:
+ _LOGD ("do-delete-%s[%s]: failed with \"%s\" (%d), meaning the object was already removed",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
+ nl_geterror (nle), -nle);
+ break;
+ case -NLE_FAILURE:
+ if (NMP_OBJECT_GET_TYPE (obj_id) != NMP_OBJECT_TYPE_IP6_ADDRESS)
+ goto nle_failure;
+
+ /* On RHEL7 kernel, deleting a non existing address fails with ENXIO (which libnl maps to NLE_FAILURE) */
+ _LOGD ("do-delete-%s[%s]: deleting address failed with \"%s\" (%d), meaning the address was already removed",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
+ nl_geterror (nle), -nle);
+ break;
+ case -NLE_NOADDR:
+ if ( NMP_OBJECT_GET_TYPE (obj_id) != NMP_OBJECT_TYPE_IP4_ADDRESS
+ && NMP_OBJECT_GET_TYPE (obj_id) != NMP_OBJECT_TYPE_IP6_ADDRESS)
+ goto nle_failure;
+
+ _LOGD ("do-delete-%s[%s]: deleting address failed with \"%s\" (%d), meaning the address was already removed",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
+ nl_geterror (nle), -nle);
+ break;
+ default:
+nle_failure:
+ _LOGE ("do-delete-%s[%s]: failed with \"%s\" (%d)",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0),
+ nl_geterror (nle), -nle);
+ return FALSE;
+ }
delayed_action_handle_all (platform, TRUE);
@@ -2856,50 +3611,63 @@ do_delete_object (NMPlatform *platform, const NMPObject *obj_id, const struct nl
obj = nmp_cache_lookup_link_full (priv->cache, obj_id->link.ifindex, obj_id->link.ifindex <= 0 && obj_id->link.name[0] ? obj_id->link.name : NULL, FALSE, NM_LINK_TYPE_NONE, NULL, NULL);
if (obj && obj->_link.netlink.is_in_netlink) {
- _LOGT ("do-delete-%s: reload: the deleted object is not yet removed. Request %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
+ _LOGT ("do-delete-%s[%s]: reload: the deleted object is not yet removed. Request anew",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
do_request_link (platform, obj_id->link.ifindex, obj_id->link.name, TRUE);
}
} else {
if (nmp_cache_lookup_obj (priv->cache, obj_id)) {
- _LOGT ("do-delete-%s: reload: the deleted object is not yet removed. Request %s", NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name, nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
+ _LOGT ("do-delete-%s[%s]: reload: the deleted object is not yet removed. Request anew",
+ NMP_OBJECT_GET_CLASS (obj_id)->obj_type_name,
+ nmp_object_to_string (obj_id, NMP_OBJECT_TO_STRING_ID, NULL, 0));
do_request_one_type (platform, NMP_OBJECT_GET_TYPE (obj_id), TRUE);
}
}
/* The return value doesn't say, whether the object is in the platform cache after adding
- * it.
- * Instead the return value says, whether kernel_add_object() succeeded. */
- return nle >= 0;
+ * it. Instead the return value says, whether the netlink request succeeded. */
+ return TRUE;
}
static NMPlatformError
-do_change_link (NMPlatform *platform, struct rtnl_link *nlo, gboolean complete_from_cache)
+do_change_link (NMPlatform *platform, int ifindex, struct nl_msg *nlmsg)
{
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
int nle;
- int ifindex;
- gboolean complete_from_cache2 = complete_from_cache;
- ifindex = rtnl_link_get_ifindex (nlo);
- if (ifindex <= 0)
- g_return_val_if_reached (NM_PLATFORM_ERROR_BUG);
+retry:
+ nle = nl_send_auto_complete (priv->nlh, nlmsg);
+ if (nle < 0) {
+ _LOGE ("do-change-link[%d]: failure sending netlink request \"%s\" (%d)",
+ ifindex,
+ nl_geterror (nle), -nle);
+ return NM_PLATFORM_ERROR_UNSPECIFIED;
+ }
- nle = kernel_change_link (platform, nlo, &complete_from_cache2);
+ nle = nl_wait_for_ack (priv->nlh);
+ if ( nle == -NLE_OPNOTSUPP
+ && nlmsg_hdr (nlmsg)->nlmsg_type == RTM_NEWLINK) {
+ nlmsg_hdr (nlmsg)->nlmsg_type = RTM_SETLINK;
+ goto retry;
+ }
switch (nle) {
case -NLE_SUCCESS:
- _LOGD ("do-change-link: success changing link %d", ifindex);
+ _LOGD ("do-change-link[%d]: success changing link", ifindex);
break;
case -NLE_EXIST:
- _LOGD ("do-change-link: success changing link %d: %s (%d)", ifindex, nl_geterror (nle), -nle);
+ _LOGD ("do-change-link[%d]: success changing link: %s (%d)",
+ ifindex, nl_geterror (nle), -nle);
break;
case -NLE_OBJ_NOTFOUND:
- /* fall-through */
+ _LOGD ("do-change-link[%d]: failure changing link: firmware not found (%s, %d)",
+ ifindex, nl_geterror (nle), -nle);
+ return NM_PLATFORM_ERROR_NO_FIRMWARE;
default:
- if (complete_from_cache != complete_from_cache2)
- _LOGD ("do-change-link: failure changing link %d: link does not exist in cache", ifindex);
- else
- _LOGE ("do-change-link: failure changing link %d: %s (%d)", ifindex, nl_geterror (nle), -nle);
- return nle == -NLE_OBJ_NOTFOUND ? NM_PLATFORM_ERROR_NO_FIRMWARE : NM_PLATFORM_ERROR_UNSPECIFIED;
+ _LOGE ("do-change-link[%d]: failure changing link: netlink error (%s, %d)",
+ ifindex, nl_geterror (nle), -nle);
+ return NM_PLATFORM_ERROR_UNSPECIFIED;
}
/* FIXME: as we modify the link via a separate socket, the cache is not in
@@ -2916,7 +3684,7 @@ link_add (NMPlatform *platform,
size_t address_len,
NMPlatformLink *out_link)
{
- auto_nl_object struct nl_object *l = NULL;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
if (type == NM_LINK_TYPE_BOND) {
/* When the kernel loads the bond module, either via explicit modprobe
@@ -2933,31 +3701,45 @@ link_add (NMPlatform *platform,
_LOGD ("link: add link '%s' of type '%s' (%d)",
name, nm_link_type_to_string (type), (int) type);
- l = build_rtnl_link (0, name, type);
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ NLM_F_CREATE,
+ 0,
+ name,
+ 0);
+ if (!nlmsg)
+ return FALSE;
- g_assert ( (address != NULL) ^ (address_len == 0) );
- if (address) {
- auto_nl_addr struct nl_addr *nladdr = _nl_addr_build (AF_LLC, address, address_len);
+ if (address && address_len)
+ NLA_PUT (nlmsg, IFLA_ADDRESS, address_len, address);
- rtnl_link_set_addr ((struct rtnl_link *) l, nladdr);
- }
+ if (!_nl_msg_new_link_set_linkinfo (nlmsg, type))
+ return FALSE;
- return do_add_link_with_lookup (platform, name, (struct rtnl_link *) l, type, out_link);
+ return do_add_link_with_lookup (platform, type, name, nlmsg, out_link);
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
}
static gboolean
link_delete (NMPlatform *platform, int ifindex)
{
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- NMPObject obj_needle;
+ NMPObject obj_id;
const NMPObject *obj;
obj = nmp_cache_lookup_link (priv->cache, ifindex);
if (!obj || !obj->_link.netlink.is_in_netlink)
return FALSE;
- nmp_object_stackinit_id_link (&obj_needle, ifindex);
- return do_delete_object (platform, &obj_needle, NULL);
+ nlmsg = _nl_msg_new_link (RTM_DELLINK,
+ 0,
+ ifindex,
+ NULL,
+ 0);
+
+ nmp_object_stackinit_id_link (&obj_id, ifindex);
+ return do_delete_object (platform, &obj_id, nlmsg);
}
static const char *
@@ -3010,26 +3792,32 @@ link_refresh (NMPlatform *platform, int ifindex)
static NMPlatformError
link_change_flags (NMPlatform *platform, int ifindex, unsigned int flags, gboolean value)
{
- auto_nl_object struct rtnl_link *change = _nl_rtnl_link_alloc (ifindex, NULL);
- const NMPObject *obj_cache;
- char buf[256];
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ unsigned f;
- obj_cache = cache_lookup_link (platform, ifindex);
- if (!obj_cache)
+ if (!_lookup_cached_link_data (platform, ifindex, "flags", &f))
return NM_PLATFORM_ERROR_NOT_FOUND;
- rtnl_link_set_flags (change, obj_cache->link.flags);
if (value)
- rtnl_link_set_flags (change, flags);
+ f |= flags;
else
- rtnl_link_unset_flags (change, flags);
+ f &= ~flags;
- _LOGD ("link: change %d: flags %s '%s' (%d)", ifindex,
+ _LOGD ("link: change %d: flags: %s '%s' (0x%x); new %s (0x%x)", ifindex,
value ? "set" : "unset",
- rtnl_link_flags2str (flags, buf, sizeof (buf)),
- flags);
+ nm_platform_link_flags2str (flags, NULL, 0),
+ flags,
+ nm_platform_link_flags2str (f, NULL, 0),
+ f);
- return do_change_link (platform, change, FALSE);
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ 0,
+ ifindex,
+ NULL,
+ f);
+ if (!nlmsg)
+ return NM_PLATFORM_ERROR_UNSPECIFIED;
+ return do_change_link (platform, ifindex, nlmsg);
}
static gboolean
@@ -3090,19 +3878,33 @@ link_get_udev_device (NMPlatform *platform, int ifindex)
static gboolean
link_set_user_ipv6ll_enabled (NMPlatform *platform, int ifindex, gboolean enabled)
{
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE
- if (_support_user_ipv6ll_get ()) {
- auto_nl_object struct rtnl_link *nlo = _nl_rtnl_link_alloc (ifindex, NULL);
- guint8 mode = enabled ? IN6_ADDR_GEN_MODE_NONE : IN6_ADDR_GEN_MODE_EUI64;
- char buf[32];
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ guint8 mode = enabled ? NM_IN6_ADDR_GEN_MODE_NONE : NM_IN6_ADDR_GEN_MODE_EUI64;
+ unsigned flags;
- rtnl_link_inet6_set_addr_gen_mode (nlo, mode);
- _LOGD ("link: change %d: set IPv6 address generation mode to %s",
- ifindex, rtnl_link_inet6_addrgenmode2str (mode, buf, sizeof (buf)));
- return do_change_link (platform, nlo, TRUE) == NM_PLATFORM_ERROR_SUCCESS;
+ if (!_support_user_ipv6ll_get ()) {
+ _LOGD ("link: change %d: user-ipv6ll: not supported", ifindex);
+ return FALSE;
}
-#endif
- return FALSE;
+
+ if (!_lookup_cached_link_data (platform, ifindex, "user-ipv6ll", &flags))
+ return FALSE;
+
+ _LOGD ("link: change %d: user-ipv6ll: set IPv6 address generation mode to %s",
+ ifindex,
+ nm_platform_link_inet6_addrgenmode2str (mode, NULL, 0));
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ 0,
+ ifindex,
+ NULL,
+ flags);
+ if ( !nlmsg
+ || !_nl_msg_new_link_set_afspec (nlmsg,
+ mode))
+ return FALSE;
+
+ return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
@@ -3137,16 +3939,33 @@ link_supports_vlans (NMPlatform *platform, int ifindex)
static gboolean
link_set_address (NMPlatform *platform, int ifindex, gconstpointer address, size_t length)
{
- auto_nl_object struct rtnl_link *change = _nl_rtnl_link_alloc (ifindex, NULL);
- auto_nl_addr struct nl_addr *nladdr = _nl_addr_build (AF_LLC, address, length);
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
gs_free char *mac = NULL;
+ unsigned flags;
- rtnl_link_set_addr (change, nladdr);
+ if (!address || !length)
+ g_return_val_if_reached (FALSE);
- _LOGD ("link: change %d: address %s (%lu bytes)", ifindex,
+ if (!_lookup_cached_link_data (platform, ifindex, "address", &flags))
+ return FALSE;
+
+ _LOGD ("link: change %d: address: %s (%lu bytes)", ifindex,
(mac = nm_utils_hwaddr_ntoa (address, length)),
(unsigned long) length);
- return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS;
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ 0,
+ ifindex,
+ NULL,
+ flags);
+ if (!nlmsg)
+ return FALSE;
+
+ NLA_PUT (nlmsg, IFLA_ADDRESS, length, address);
+
+ return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
}
static gboolean
@@ -3161,12 +3980,27 @@ link_get_permanent_address (NMPlatform *platform,
static gboolean
link_set_mtu (NMPlatform *platform, int ifindex, guint32 mtu)
{
- auto_nl_object struct rtnl_link *change = _nl_rtnl_link_alloc (ifindex, NULL);
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ unsigned flags;
- rtnl_link_set_mtu (change, mtu);
- _LOGD ("link: change %d: mtu %lu", ifindex, (unsigned long)mtu);
+ if (!_lookup_cached_link_data (platform, ifindex, "mtu", &flags))
+ return FALSE;
- return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS;
+ _LOGD ("link: change %d: mtu: %u", ifindex, (unsigned) mtu);
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ 0,
+ ifindex,
+ NULL,
+ flags);
+ if (!nlmsg)
+ return FALSE;
+
+ NLA_PUT_U32 (nlmsg, IFLA_MTU, mtu);
+
+ return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
}
static char *
@@ -3220,78 +4054,237 @@ vlan_add (NMPlatform *platform,
guint32 vlan_flags,
NMPlatformLink *out_link)
{
- auto_nl_object struct rtnl_link *rtnllink = (struct rtnl_link *) build_rtnl_link (0, name, NM_LINK_TYPE_VLAN);
- unsigned int kernel_flags;
- unsigned int all_flags = NM_VLAN_FLAGS_ALL;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
G_STATIC_ASSERT (NM_VLAN_FLAG_REORDER_HEADERS == (guint32) VLAN_FLAG_REORDER_HDR);
G_STATIC_ASSERT (NM_VLAN_FLAG_GVRP == (guint32) VLAN_FLAG_GVRP);
G_STATIC_ASSERT (NM_VLAN_FLAG_LOOSE_BINDING == (guint32) VLAN_FLAG_LOOSE_BINDING);
G_STATIC_ASSERT (NM_VLAN_FLAG_MVRP == (guint32) VLAN_FLAG_MVRP);
- kernel_flags = vlan_flags & ((guint32) NM_VLAN_FLAGS_ALL);
+ vlan_flags &= (guint32) NM_VLAN_FLAGS_ALL;
- rtnl_link_set_link (rtnllink, parent);
- rtnl_link_vlan_set_id (rtnllink, vlan_id);
- rtnl_link_vlan_unset_flags (rtnllink, all_flags);
- rtnl_link_vlan_set_flags (rtnllink, kernel_flags);
+ _LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X",
+ name, parent, vlan_id, (unsigned int) vlan_flags);
- _LOGD ("link: add vlan '%s', parent %d, vlan id %d, flags %X (native: %X)",
- name, parent, vlan_id, (unsigned int) vlan_flags, kernel_flags);
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ NLM_F_CREATE,
+ 0,
+ name,
+ 0);
+ if (!nlmsg)
+ return FALSE;
- return do_add_link_with_lookup (platform, name, rtnllink, NM_LINK_TYPE_VLAN, out_link);
-}
+ NLA_PUT_U32 (nlmsg, IFLA_LINK, parent);
-static gboolean
-vlan_get_info (NMPlatform *platform, int ifindex, int *parent, int *vlan_id)
-{
- const NMPObject *obj = cache_lookup_link (platform, ifindex);
- int p = 0, v = 0;
+ if (!_nl_msg_new_link_set_linkinfo_vlan (nlmsg,
+ vlan_id,
+ NM_VLAN_FLAGS_ALL,
+ vlan_flags,
+ NULL,
+ 0,
+ NULL,
+ 0))
+ return FALSE;
- if (obj) {
- p = obj->link.parent;
- v = obj->link.vlan_id;
- }
- if (parent)
- *parent = p;
- if (vlan_id)
- *vlan_id = v;
- return !!obj;
+ return do_add_link_with_lookup (platform, NM_LINK_TYPE_VLAN, name, nlmsg, out_link);
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
}
-static gboolean
-vlan_set_ingress_map (NMPlatform *platform, int ifindex, int from, int to)
-{
- auto_nl_object struct rtnl_link *change = (struct rtnl_link *) build_rtnl_link (ifindex, NULL, NM_LINK_TYPE_VLAN);
+static void
+_vlan_change_vlan_qos_mapping_create (gboolean is_ingress_map,
+ gboolean reset_all,
+ const NMVlanQosMapping *current_map,
+ guint current_n_map,
+ const NMVlanQosMapping *set_map,
+ guint set_n_map,
+ NMVlanQosMapping **out_map,
+ guint *out_n_map)
+{
+ NMVlanQosMapping *map;
+ guint i, j, len;
+ const guint INGRESS_RANGE_LEN = 8;
+
+ nm_assert (out_map && !*out_map);
+ nm_assert (out_n_map && !*out_n_map);
+
+ if (!reset_all)
+ current_n_map = 0;
+ else if (is_ingress_map)
+ current_n_map = INGRESS_RANGE_LEN;
+
+ len = current_n_map + set_n_map;
+
+ if (len == 0)
+ return;
- rtnl_link_vlan_set_ingress_map (change, from, to);
+ map = g_new (NMVlanQosMapping, len);
- _LOGD ("link: change %d: vlan ingress map %d -> %d", ifindex, from, to);
+ if (current_n_map) {
+ if (is_ingress_map) {
+ /* For the ingress-map, there are only 8 entries (0 to 7).
+ * When the user requests to reset all entires, we don't actually
+ * need the cached entries, we can just explicitly clear all possible
+ * ones.
+ *
+ * That makes only a real difference in case our cache is out-of-date.
+ *
+ * For the egress map we cannot do that, because there are far too
+ * many. There we can only clear the entries that we know about. */
+ for (i = 0; i < INGRESS_RANGE_LEN; i++) {
+ map[i].from = i;
+ map[i].to = 0;
+ }
+ } else {
+ for (i = 0; i < current_n_map; i++) {
+ map[i].from = current_map[i].from;
+ map[i].to = 0;
+ }
+ }
+ }
+ if (set_n_map)
+ memcpy (&map[current_n_map], set_map, sizeof (*set_map) * set_n_map);
+
+ g_qsort_with_data (map,
+ len,
+ sizeof (*map),
+ _vlan_qos_mapping_cmp_from,
+ NULL);
+
+ for (i = 0, j = 0; i < len; i++) {
+ if ( ( is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].from))
+ || (!is_ingress_map && !VLAN_XGRESS_PRIO_VALID (map[i].to)))
+ continue;
+ if ( j > 0
+ && map[j - 1].from == map[i].from)
+ map[j - 1] = map[i];
+ else
+ map[j++] = map[i];
+ }
- return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS;
+ *out_map = map;
+ *out_n_map = j;
}
static gboolean
-vlan_set_egress_map (NMPlatform *platform, int ifindex, int from, int to)
+link_vlan_change (NMPlatform *platform,
+ int ifindex,
+ NMVlanFlags flags_mask,
+ NMVlanFlags flags_set,
+ gboolean ingress_reset_all,
+ const NMVlanQosMapping *ingress_map,
+ gsize n_ingress_map,
+ gboolean egress_reset_all,
+ const NMVlanQosMapping *egress_map,
+ gsize n_egress_map)
{
- auto_nl_object struct rtnl_link *change = (struct rtnl_link *) build_rtnl_link (ifindex, NULL, NM_LINK_TYPE_VLAN);
-
- rtnl_link_vlan_set_egress_map (change, from, to);
+ NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
+ const NMPObject *obj_cache;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ unsigned flags;
+ 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;
+ char s_flags[64];
+ char s_ingress[256];
+ char s_egress[256];
+
+ obj_cache = nmp_cache_lookup_link (priv->cache, ifindex);
+ if ( !obj_cache
+ || !obj_cache->_link.netlink.is_in_netlink) {
+ _LOGD ("link: change %d: %s: link does not exist", ifindex, "vlan");
+ return FALSE;
+ }
- _LOGD ("link: change %d: vlan egress map %d -> %d", ifindex, from, to);
+ lnk = obj_cache->_link.netlink.lnk ? &obj_cache->_link.netlink.lnk->_lnk_vlan : NULL;
+ flags = obj_cache->link.flags;
+
+ flags_set &= flags_mask;
+
+ _vlan_change_vlan_qos_mapping_create (TRUE,
+ ingress_reset_all,
+ lnk ? lnk->ingress_qos_map : NULL,
+ lnk ? lnk->n_ingress_qos_map : 0,
+ ingress_map,
+ n_ingress_map,
+ &new_ingress_map,
+ &new_n_ingress_map);
+
+ _vlan_change_vlan_qos_mapping_create (FALSE,
+ egress_reset_all,
+ lnk ? lnk->egress_qos_map : NULL,
+ lnk ? lnk->n_egress_qos_map : 0,
+ egress_map,
+ n_egress_map,
+ &new_egress_map,
+ &new_n_egress_map);
+
+ _LOGD ("link: change %d: vlan:%s%s%s",
+ ifindex,
+ flags_mask
+ ? nm_sprintf_buf (s_flags, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask)
+ : "",
+ new_n_ingress_map
+ ? nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map",
+ new_ingress_map,
+ new_n_ingress_map,
+ s_ingress,
+ sizeof (s_ingress))
+ : "",
+ new_n_egress_map
+ ? nm_platform_vlan_qos_mapping_to_string (" egress-qos-map",
+ new_egress_map,
+ new_n_egress_map,
+ s_egress,
+ sizeof (s_egress))
+ : "");
+
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ 0,
+ ifindex,
+ NULL,
+ flags);
+ if ( !nlmsg
+ || !_nl_msg_new_link_set_linkinfo_vlan (nlmsg,
+ -1,
+ flags_mask,
+ flags_set,
+ new_ingress_map,
+ new_n_ingress_map,
+ new_egress_map,
+ new_n_egress_map))
+ return FALSE;
- return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS;
+ return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
}
static gboolean
link_enslave (NMPlatform *platform, int master, int slave)
{
- auto_nl_object struct rtnl_link *change = _nl_rtnl_link_alloc (slave, NULL);
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ unsigned flags;
+ int ifindex = slave;
+
+ if (!_lookup_cached_link_data (platform, ifindex, "enslave", &flags))
+ return FALSE;
+
+ _LOGD ("link: change %d: enslave: master %d", slave, master);
- rtnl_link_set_master (change, master);
- _LOGD ("link: change %d: enslave to master %d", slave, master);
+ nlmsg = _nl_msg_new_link (RTM_NEWLINK,
+ 0,
+ ifindex,
+ NULL,
+ flags);
+ if (!nlmsg)
+ return FALSE;
+
+ NLA_PUT_U32 (nlmsg, IFLA_MASTER, master);
- return do_change_link (platform, change, TRUE) == NM_PLATFORM_ERROR_SUCCESS;
+ return do_change_link (platform, ifindex, nlmsg) == NM_PLATFORM_ERROR_SUCCESS;
+nla_put_failure:
+ g_return_val_if_reached (FALSE);
}
static gboolean
@@ -3415,463 +4408,6 @@ infiniband_partition_add (NMPlatform *platform, int parent, int p_key, NMPlatfor
return !!obj;
}
-typedef struct {
- int p_key;
- const char *mode;
-} IpoibInfo;
-
-/* IFLA_IPOIB_* were introduced in the 3.7 kernel, but the kernel headers
- * we're building against might not have those properties even though the
- * running kernel might.
- */
-#define IFLA_IPOIB_UNSPEC 0
-#define IFLA_IPOIB_PKEY 1
-#define IFLA_IPOIB_MODE 2
-#define IFLA_IPOIB_UMCAST 3
-#undef IFLA_IPOIB_MAX
-#define IFLA_IPOIB_MAX IFLA_IPOIB_UMCAST
-
-#define IPOIB_MODE_DATAGRAM 0 /* using unreliable datagram QPs */
-#define IPOIB_MODE_CONNECTED 1 /* using connected QPs */
-
-static const struct nla_policy infiniband_info_policy[IFLA_IPOIB_MAX + 1] = {
- [IFLA_IPOIB_PKEY] = { .type = NLA_U16 },
- [IFLA_IPOIB_MODE] = { .type = NLA_U16 },
- [IFLA_IPOIB_UMCAST] = { .type = NLA_U16 },
-};
-
-static int
-infiniband_info_data_parser (struct nlattr *info_data, gpointer parser_data)
-{
- IpoibInfo *info = parser_data;
- struct nlattr *tb[IFLA_MACVLAN_MAX + 1];
- int err;
-
- err = nla_parse_nested (tb, IFLA_IPOIB_MAX, info_data,
- (struct nla_policy *) infiniband_info_policy);
- if (err < 0)
- return err;
- if (!tb[IFLA_IPOIB_PKEY] || !tb[IFLA_IPOIB_MODE])
- return -EINVAL;
-
- info->p_key = nla_get_u16 (tb[IFLA_IPOIB_PKEY]);
-
- switch (nla_get_u16 (tb[IFLA_IPOIB_MODE])) {
- case IPOIB_MODE_DATAGRAM:
- info->mode = "datagram";
- break;
- case IPOIB_MODE_CONNECTED:
- info->mode = "connected";
- break;
- default:
- return -NLE_PARSE_ERR;
- }
-
- return 0;
-}
-
-static gboolean
-infiniband_get_info (NMPlatform *platform, int ifindex, int *parent, int *p_key, const char **mode)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- const NMPObject *obj;
- IpoibInfo info = { -1, NULL };
-
- obj = cache_lookup_link (platform, ifindex);
- if (!obj)
- return FALSE;
-
- if (parent)
- *parent = obj->link.parent;
-
- if (_nl_link_parse_info_data (priv->nlh,
- ifindex,
- infiniband_info_data_parser,
- &info) != 0) {
- const char *iface = obj->link.name;
- char *path, *contents = NULL;
-
- /* Fall back to reading sysfs */
- path = g_strdup_printf ("/sys/class/net/%s/mode", ASSERT_VALID_PATH_COMPONENT (iface));
- contents = nm_platform_sysctl_get (platform, path);
- g_free (path);
- if (!contents)
- return FALSE;
-
- if (strstr (contents, "datagram"))
- info.mode = "datagram";
- else if (strstr (contents, "connected"))
- info.mode = "connected";
- g_free (contents);
-
- path = g_strdup_printf ("/sys/class/net/%s/pkey", ASSERT_VALID_PATH_COMPONENT (iface));
- contents = nm_platform_sysctl_get (platform, path);
- g_free (path);
- if (!contents)
- return FALSE;
-
- info.p_key = (int) _nm_utils_ascii_str_to_int64 (contents, 16, 0, 0xFFFF, -1);
- g_free (contents);
-
- if (info.p_key < 0)
- return FALSE;
- }
-
- if (p_key)
- *p_key = info.p_key;
- if (mode)
- *mode = info.mode;
- return TRUE;
-}
-
-/******************************************************************/
-
-static gboolean
-veth_get_properties (NMPlatform *platform, int ifindex, NMPlatformVethProperties *props)
-{
- const char *ifname;
- int peer_ifindex;
-
- ifname = nm_platform_link_get_name (platform, ifindex);
- if (!ifname)
- return FALSE;
-
- peer_ifindex = nmp_utils_ethtool_get_peer_ifindex (ifname);
- if (peer_ifindex <= 0)
- return FALSE;
-
- props->peer = peer_ifindex;
- return TRUE;
-}
-
-/******************************************************************/
-
-static gboolean
-tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props)
-{
- char *path, *val;
- gboolean success = TRUE;
-
- g_return_val_if_fail (props, FALSE);
-
- memset (props, 0, sizeof (*props));
- props->owner = -1;
- props->group = -1;
-
- if (!ifname || !nm_utils_iface_valid_name (ifname))
- return FALSE;
- ifname = ASSERT_VALID_PATH_COMPONENT (ifname);
-
- path = g_strdup_printf ("/sys/class/net/%s/owner", ifname);
- val = nm_platform_sysctl_get (platform, path);
- g_free (path);
- if (val) {
- props->owner = _nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1);
- if (errno)
- success = FALSE;
- g_free (val);
- } else
- success = FALSE;
-
- path = g_strdup_printf ("/sys/class/net/%s/group", ifname);
- val = nm_platform_sysctl_get (platform, path);
- g_free (path);
- if (val) {
- props->group = _nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1);
- if (errno)
- success = FALSE;
- g_free (val);
- } else
- success = FALSE;
-
- path = g_strdup_printf ("/sys/class/net/%s/tun_flags", ifname);
- val = nm_platform_sysctl_get (platform, path);
- g_free (path);
- if (val) {
- gint64 flags;
-
- flags = _nm_utils_ascii_str_to_int64 (val, 16, 0, G_MAXINT64, 0);
- if (!errno) {
-#ifndef IFF_MULTI_QUEUE
- const int IFF_MULTI_QUEUE = 0x0100;
-#endif
- props->mode = ((flags & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "tun" : "tap";
- props->no_pi = !!(flags & IFF_NO_PI);
- props->vnet_hdr = !!(flags & IFF_VNET_HDR);
- props->multi_queue = !!(flags & IFF_MULTI_QUEUE);
- } else
- success = FALSE;
- g_free (val);
- } else
- success = FALSE;
-
- return success;
-}
-
-static gboolean
-tun_get_properties (NMPlatform *platform, int ifindex, NMPlatformTunProperties *props)
-{
- return tun_get_properties_ifname (platform, nm_platform_link_get_name (platform, ifindex), props);
-}
-
-/******************************************************************/
-
-static const struct nla_policy macvlan_info_policy[IFLA_MACVLAN_MAX + 1] = {
- [IFLA_MACVLAN_MODE] = { .type = NLA_U32 },
-#ifdef MACVLAN_FLAG_NOPROMISC
- [IFLA_MACVLAN_FLAGS] = { .type = NLA_U16 },
-#endif
-};
-
-static int
-macvlan_info_data_parser (struct nlattr *info_data, gpointer parser_data)
-{
- NMPlatformMacvlanProperties *props = parser_data;
- struct nlattr *tb[IFLA_MACVLAN_MAX + 1];
- int err;
-
- err = nla_parse_nested (tb, IFLA_MACVLAN_MAX, info_data,
- (struct nla_policy *) macvlan_info_policy);
- if (err < 0)
- return err;
-
- switch (nla_get_u32 (tb[IFLA_MACVLAN_MODE])) {
- case MACVLAN_MODE_PRIVATE:
- props->mode = "private";
- break;
- case MACVLAN_MODE_VEPA:
- props->mode = "vepa";
- break;
- case MACVLAN_MODE_BRIDGE:
- props->mode = "bridge";
- break;
- case MACVLAN_MODE_PASSTHRU:
- props->mode = "passthru";
- break;
- default:
- return -NLE_PARSE_ERR;
- }
-
-#ifdef MACVLAN_FLAG_NOPROMISC
- props->no_promisc = !!(nla_get_u16 (tb[IFLA_MACVLAN_FLAGS]) & MACVLAN_FLAG_NOPROMISC);
-#else
- props->no_promisc = FALSE;
-#endif
-
- return 0;
-}
-
-static gboolean
-macvlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformMacvlanProperties *props)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- int err;
- const NMPObject *obj;
-
- obj = cache_lookup_link (platform, ifindex);
- if (!obj)
- return FALSE;
-
- props->parent_ifindex = obj->link.parent;
-
- err = _nl_link_parse_info_data (priv->nlh, ifindex,
- macvlan_info_data_parser, props);
- if (err != 0) {
- _LOGW ("(%s) could not read properties: %s",
- obj->link.name, nl_geterror (err));
- }
- return (err == 0);
-}
-
-/******************************************************************/
-
-/* The installed kernel headers might not have VXLAN stuff at all, or
- * they might have the original properties, but not PORT, GROUP6, or LOCAL6.
- * So until we depend on kernel >= 3.11, we just ignore the actual enum
- * in if_link.h and define the values ourselves.
- */
-#define IFLA_VXLAN_UNSPEC 0
-#define IFLA_VXLAN_ID 1
-#define IFLA_VXLAN_GROUP 2
-#define IFLA_VXLAN_LINK 3
-#define IFLA_VXLAN_LOCAL 4
-#define IFLA_VXLAN_TTL 5
-#define IFLA_VXLAN_TOS 6
-#define IFLA_VXLAN_LEARNING 7
-#define IFLA_VXLAN_AGEING 8
-#define IFLA_VXLAN_LIMIT 9
-#define IFLA_VXLAN_PORT_RANGE 10
-#define IFLA_VXLAN_PROXY 11
-#define IFLA_VXLAN_RSC 12
-#define IFLA_VXLAN_L2MISS 13
-#define IFLA_VXLAN_L3MISS 14
-#define IFLA_VXLAN_PORT 15
-#define IFLA_VXLAN_GROUP6 16
-#define IFLA_VXLAN_LOCAL6 17
-#undef IFLA_VXLAN_MAX
-#define IFLA_VXLAN_MAX IFLA_VXLAN_LOCAL6
-
-/* older kernel header might not contain 'struct ifla_vxlan_port_range'.
- * Redefine it. */
-struct nm_ifla_vxlan_port_range {
- guint16 low;
- guint16 high;
-};
-
-static const struct nla_policy vxlan_info_policy[IFLA_VXLAN_MAX + 1] = {
- [IFLA_VXLAN_ID] = { .type = NLA_U32 },
- [IFLA_VXLAN_GROUP] = { .type = NLA_U32 },
- [IFLA_VXLAN_GROUP6] = { .type = NLA_UNSPEC,
- .minlen = sizeof (struct in6_addr) },
- [IFLA_VXLAN_LINK] = { .type = NLA_U32 },
- [IFLA_VXLAN_LOCAL] = { .type = NLA_U32 },
- [IFLA_VXLAN_LOCAL6] = { .type = NLA_UNSPEC,
- .minlen = sizeof (struct in6_addr) },
- [IFLA_VXLAN_TOS] = { .type = NLA_U8 },
- [IFLA_VXLAN_TTL] = { .type = NLA_U8 },
- [IFLA_VXLAN_LEARNING] = { .type = NLA_U8 },
- [IFLA_VXLAN_AGEING] = { .type = NLA_U32 },
- [IFLA_VXLAN_LIMIT] = { .type = NLA_U32 },
- [IFLA_VXLAN_PORT_RANGE] = { .type = NLA_UNSPEC,
- .minlen = sizeof (struct nm_ifla_vxlan_port_range) },
- [IFLA_VXLAN_PROXY] = { .type = NLA_U8 },
- [IFLA_VXLAN_RSC] = { .type = NLA_U8 },
- [IFLA_VXLAN_L2MISS] = { .type = NLA_U8 },
- [IFLA_VXLAN_L3MISS] = { .type = NLA_U8 },
- [IFLA_VXLAN_PORT] = { .type = NLA_U16 },
-};
-
-static int
-vxlan_info_data_parser (struct nlattr *info_data, gpointer parser_data)
-{
- NMPlatformVxlanProperties *props = parser_data;
- struct nlattr *tb[IFLA_VXLAN_MAX + 1];
- struct nm_ifla_vxlan_port_range *range;
- int err;
-
- err = nla_parse_nested (tb, IFLA_VXLAN_MAX, info_data,
- (struct nla_policy *) vxlan_info_policy);
- if (err < 0)
- return err;
-
- memset (props, 0, sizeof (*props));
-
- if (tb[IFLA_VXLAN_LINK])
- props->parent_ifindex = nla_get_u32 (tb[IFLA_VXLAN_LINK]);
- if (tb[IFLA_VXLAN_ID])
- props->id = nla_get_u32 (tb[IFLA_VXLAN_ID]);
- if (tb[IFLA_VXLAN_GROUP])
- props->group = nla_get_u32 (tb[IFLA_VXLAN_GROUP]);
- if (tb[IFLA_VXLAN_LOCAL])
- props->local = nla_get_u32 (tb[IFLA_VXLAN_LOCAL]);
- if (tb[IFLA_VXLAN_GROUP6])
- memcpy (&props->group6, nla_data (tb[IFLA_VXLAN_GROUP6]), sizeof (props->group6));
- if (tb[IFLA_VXLAN_LOCAL6])
- memcpy (&props->local6, nla_data (tb[IFLA_VXLAN_LOCAL6]), sizeof (props->local6));
-
- if (tb[IFLA_VXLAN_AGEING])
- props->ageing = nla_get_u32 (tb[IFLA_VXLAN_AGEING]);
- if (tb[IFLA_VXLAN_LIMIT])
- props->limit = nla_get_u32 (tb[IFLA_VXLAN_LIMIT]);
- if (tb[IFLA_VXLAN_TOS])
- props->tos = nla_get_u8 (tb[IFLA_VXLAN_TOS]);
- if (tb[IFLA_VXLAN_TTL])
- props->ttl = nla_get_u8 (tb[IFLA_VXLAN_TTL]);
-
- if (tb[IFLA_VXLAN_PORT])
- props->dst_port = nla_get_u16 (tb[IFLA_VXLAN_PORT]);
-
- if (tb[IFLA_VXLAN_PORT_RANGE]) {
- range = nla_data (tb[IFLA_VXLAN_PORT_RANGE]);
- props->src_port_min = range->low;
- props->src_port_max = range->high;
- }
-
- if (tb[IFLA_VXLAN_LEARNING])
- props->learning = !!nla_get_u8 (tb[IFLA_VXLAN_LEARNING]);
- if (tb[IFLA_VXLAN_PROXY])
- props->proxy = !!nla_get_u8 (tb[IFLA_VXLAN_PROXY]);
- if (tb[IFLA_VXLAN_RSC])
- props->rsc = !!nla_get_u8 (tb[IFLA_VXLAN_RSC]);
- if (tb[IFLA_VXLAN_L2MISS])
- props->l2miss = !!nla_get_u8 (tb[IFLA_VXLAN_L2MISS]);
- if (tb[IFLA_VXLAN_L3MISS])
- props->l3miss = !!nla_get_u8 (tb[IFLA_VXLAN_L3MISS]);
-
- return 0;
-}
-
-static gboolean
-vxlan_get_properties (NMPlatform *platform, int ifindex, NMPlatformVxlanProperties *props)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- int err;
-
- err = _nl_link_parse_info_data (priv->nlh, ifindex,
- vxlan_info_data_parser, props);
- if (err != 0) {
- _LOGW ("(%s) could not read vxlan properties: %s",
- nm_platform_link_get_name (platform, ifindex), nl_geterror (err));
- }
- return (err == 0);
-}
-
-/******************************************************************/
-
-static const struct nla_policy gre_info_policy[IFLA_GRE_MAX + 1] = {
- [IFLA_GRE_LINK] = { .type = NLA_U32 },
- [IFLA_GRE_IFLAGS] = { .type = NLA_U16 },
- [IFLA_GRE_OFLAGS] = { .type = NLA_U16 },
- [IFLA_GRE_IKEY] = { .type = NLA_U32 },
- [IFLA_GRE_OKEY] = { .type = NLA_U32 },
- [IFLA_GRE_LOCAL] = { .type = NLA_U32 },
- [IFLA_GRE_REMOTE] = { .type = NLA_U32 },
- [IFLA_GRE_TTL] = { .type = NLA_U8 },
- [IFLA_GRE_TOS] = { .type = NLA_U8 },
- [IFLA_GRE_PMTUDISC] = { .type = NLA_U8 },
-};
-
-static int
-gre_info_data_parser (struct nlattr *info_data, gpointer parser_data)
-{
- NMPlatformGreProperties *props = parser_data;
- struct nlattr *tb[IFLA_GRE_MAX + 1];
- int err;
-
- err = nla_parse_nested (tb, IFLA_GRE_MAX, info_data,
- (struct nla_policy *) gre_info_policy);
- if (err < 0)
- return err;
-
- props->parent_ifindex = tb[IFLA_GRE_LINK] ? nla_get_u32 (tb[IFLA_GRE_LINK]) : 0;
- props->input_flags = nla_get_u16 (tb[IFLA_GRE_IFLAGS]);
- props->output_flags = nla_get_u16 (tb[IFLA_GRE_OFLAGS]);
- props->input_key = (props->input_flags & GRE_KEY) ? nla_get_u32 (tb[IFLA_GRE_IKEY]) : 0;
- props->output_key = (props->output_flags & GRE_KEY) ? nla_get_u32 (tb[IFLA_GRE_OKEY]) : 0;
- props->local = nla_get_u32 (tb[IFLA_GRE_LOCAL]);
- props->remote = nla_get_u32 (tb[IFLA_GRE_REMOTE]);
- props->tos = nla_get_u8 (tb[IFLA_GRE_TOS]);
- props->ttl = nla_get_u8 (tb[IFLA_GRE_TTL]);
- props->path_mtu_discovery = !!nla_get_u8 (tb[IFLA_GRE_PMTUDISC]);
-
- return 0;
-}
-
-static gboolean
-gre_get_properties (NMPlatform *platform, int ifindex, NMPlatformGreProperties *props)
-{
- NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- int err;
-
- err = _nl_link_parse_info_data (priv->nlh, ifindex,
- gre_info_data_parser, props);
- if (err != 0) {
- _LOGW ("(%s) could not read gre properties: %s",
- nm_platform_link_get_name (platform, ifindex), nl_geterror (err));
- }
- return (err == 0);
-}
-
/******************************************************************/
static WifiData *
@@ -4104,137 +4640,6 @@ ip6_address_get_all (NMPlatform *platform, int ifindex)
return ipx_address_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ADDRESS);
}
-#define IPV4LL_NETWORK (htonl (0xA9FE0000L))
-#define IPV4LL_NETMASK (htonl (0xFFFF0000L))
-
-static gboolean
-ip4_is_link_local (const struct in_addr *src)
-{
- return (src->s_addr & IPV4LL_NETMASK) == IPV4LL_NETWORK;
-}
-
-static struct nl_object *
-build_rtnl_addr (NMPlatform *platform,
- int family,
- int ifindex,
- gconstpointer addr,
- gconstpointer peer_addr,
- int plen,
- guint32 lifetime,
- guint32 preferred,
- guint flags,
- const char *label)
-{
- auto_nl_object struct rtnl_addr *rtnladdr = _nl_rtnl_addr_alloc (ifindex);
- struct rtnl_addr *rtnladdr_copy;
- int addrlen = family == AF_INET ? sizeof (in_addr_t) : sizeof (struct in6_addr);
- auto_nl_addr struct nl_addr *nladdr = _nl_addr_build (family, addr, addrlen);
- int nle;
-
- /* IP address */
- nle = rtnl_addr_set_local (rtnladdr, nladdr);
- if (nle) {
- _LOGE ("build_rtnl_addr(): rtnl_addr_set_local failed with %s (%d)", nl_geterror (nle), nle);
- return NULL;
- }
-
- /* Tighten scope (IPv4 only) */
- if (family == AF_INET && ip4_is_link_local (addr))
- rtnl_addr_set_scope (rtnladdr, RT_SCOPE_LINK);
-
- /* IPv4 Broadcast address */
- if (family == AF_INET) {
- in_addr_t bcast;
- auto_nl_addr struct nl_addr *bcaddr = NULL;
-
- bcast = *((in_addr_t *) addr) | ~nm_utils_ip4_prefix_to_netmask (plen);
- bcaddr = _nl_addr_build (family, &bcast, addrlen);
- g_assert (bcaddr);
- rtnl_addr_set_broadcast (rtnladdr, bcaddr);
- }
-
- /* Peer/point-to-point address */
- if (peer_addr) {
- auto_nl_addr struct nl_addr *nlpeer = _nl_addr_build (family, peer_addr, addrlen);
-
- nle = rtnl_addr_set_peer (rtnladdr, nlpeer);
- if (nle && nle != -NLE_AF_NOSUPPORT) {
- /* IPv6 doesn't support peer addresses yet */
- _LOGE ("build_rtnl_addr(): rtnl_addr_set_peer failed with %s (%d)", nl_geterror (nle), nle);
- return NULL;
- }
- }
-
- _nl_rtnl_addr_set_prefixlen (rtnladdr, plen);
- if ( (lifetime != 0 && lifetime != NM_PLATFORM_LIFETIME_PERMANENT)
- || (preferred != 0 && preferred != NM_PLATFORM_LIFETIME_PERMANENT)) {
- /* note that here we set the relative timestamps (ticking from *now*). */
- rtnl_addr_set_valid_lifetime (rtnladdr, lifetime);
- rtnl_addr_set_preferred_lifetime (rtnladdr, preferred);
- }
- if (flags) {
- if ((flags & ~0xFF) && !_support_kernel_extended_ifa_flags_get ()) {
- /* Older kernels don't accept unknown netlink attributes.
- *
- * With commit libnl commit 5206c050504f8676a24854519b9c351470fb7cc6, libnl will only set
- * the extended address flags attribute IFA_FLAGS when necessary (> 8 bit). But it's up to
- * us not to shove those extended flags on to older kernels.
- *
- * Just silently clear them. The kernel should ignore those unknown flags anyway. */
- flags &= 0xFF;
- }
- rtnl_addr_set_flags (rtnladdr, flags);
- }
- if (label && *label)
- rtnl_addr_set_label (rtnladdr, label);
-
- rtnladdr_copy = rtnladdr;
- rtnladdr = NULL;
- return (struct nl_object *) rtnladdr_copy;
-}
-
-struct nl_object *
-_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
-{
- const NMPlatformIP4Address *obj = (const NMPlatformIP4Address *) _obj;
- guint32 lifetime, preferred;
-
- nmp_utils_lifetime_get (obj->timestamp, obj->lifetime, obj->preferred,
- 0, 0, &lifetime, &preferred);
-
- return build_rtnl_addr (platform,
- AF_INET,
- obj->ifindex,
- &obj->address,
- obj->peer_address ? &obj->peer_address : NULL,
- obj->plen,
- lifetime,
- preferred,
- 0,
- obj->label[0] ? obj->label : NULL);
-}
-
-struct nl_object *
-_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
-{
- const NMPlatformIP6Address *obj = (const NMPlatformIP6Address *) _obj;
- guint32 lifetime, preferred;
-
- nmp_utils_lifetime_get (obj->timestamp, obj->lifetime, obj->preferred,
- 0, 0, &lifetime, &preferred);
-
- return build_rtnl_addr (platform,
- AF_INET6,
- obj->ifindex,
- &obj->address,
- !IN6_IS_ADDR_UNSPECIFIED (&obj->peer_address) ? &obj->peer_address : NULL,
- obj->plen,
- lifetime,
- preferred,
- 0,
- NULL);
-}
-
static gboolean
ip4_address_add (NMPlatform *platform,
int ifindex,
@@ -4245,16 +4650,24 @@ ip4_address_add (NMPlatform *platform,
guint32 preferred,
const char *label)
{
- NMPObject obj_needle;
- auto_nl_object struct nl_object *nlo = NULL;
+ NMPObject obj_id;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
- nlo = build_rtnl_addr (platform, AF_INET, ifindex, &addr,
- peer_addr ? &peer_addr : NULL,
- plen, lifetime, preferred, 0,
- label);
- return do_add_addrroute (platform,
- nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen, peer_addr),
- nlo);
+ nlmsg = _nl_msg_new_address (RTM_NEWADDR,
+ NLM_F_CREATE | NLM_F_REPLACE,
+ AF_INET,
+ ifindex,
+ &addr,
+ plen,
+ &peer_addr,
+ 0,
+ ip4_address_is_link_local (addr) ? RT_SCOPE_LINK : RT_SCOPE_UNIVERSE,
+ lifetime,
+ preferred,
+ label);
+
+ nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_addr);
+ return do_add_addrroute (platform, &obj_id, nlmsg);
}
static gboolean
@@ -4267,44 +4680,80 @@ ip6_address_add (NMPlatform *platform,
guint32 preferred,
guint flags)
{
- NMPObject obj_needle;
- auto_nl_object struct nl_object *nlo = NULL;
+ NMPObject obj_id;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+
+ nlmsg = _nl_msg_new_address (RTM_NEWADDR,
+ NLM_F_CREATE | NLM_F_REPLACE,
+ AF_INET6,
+ ifindex,
+ &addr,
+ plen,
+ &peer_addr,
+ flags,
+ RT_SCOPE_UNIVERSE,
+ lifetime,
+ preferred,
+ NULL);
- nlo = build_rtnl_addr (platform, AF_INET6, ifindex, &addr,
- IN6_IS_ADDR_UNSPECIFIED (&peer_addr) ? NULL : &peer_addr,
- plen, lifetime, preferred, flags,
- NULL);
- return do_add_addrroute (platform,
- nmp_object_stackinit_id_ip6_address (&obj_needle, ifindex, &addr, plen),
- nlo);
+ nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
+ return do_add_addrroute (platform, &obj_id, nlmsg);
}
static gboolean
ip4_address_delete (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address)
{
- NMPObject obj_needle;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ NMPObject obj_id;
- nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen, peer_address);
- return do_delete_object (platform, &obj_needle, NULL);
+ nlmsg = _nl_msg_new_address (RTM_DELADDR,
+ 0,
+ AF_INET,
+ ifindex,
+ &addr,
+ plen,
+ &peer_address,
+ 0,
+ RT_SCOPE_NOWHERE,
+ NM_PLATFORM_LIFETIME_PERMANENT,
+ NM_PLATFORM_LIFETIME_PERMANENT,
+ NULL);
+
+ nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address);
+ return do_delete_object (platform, &obj_id, nlmsg);
}
static gboolean
ip6_address_delete (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
{
- NMPObject obj_needle;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ NMPObject obj_id;
+
+ nlmsg = _nl_msg_new_address (RTM_DELADDR,
+ 0,
+ AF_INET6,
+ ifindex,
+ &addr,
+ plen,
+ NULL,
+ 0,
+ RT_SCOPE_NOWHERE,
+ NM_PLATFORM_LIFETIME_PERMANENT,
+ NM_PLATFORM_LIFETIME_PERMANENT,
+ NULL);
- nmp_object_stackinit_id_ip6_address (&obj_needle, ifindex, &addr, plen);
- return do_delete_object (platform, &obj_needle, NULL);
+ nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
+ return do_delete_object (platform, &obj_id, nlmsg);
}
static const NMPlatformIP4Address *
ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in_addr_t peer_address)
{
- NMPObject obj_needle;
+ NMPObject obj_id;
const NMPObject *obj;
- nmp_object_stackinit_id_ip4_address (&obj_needle, ifindex, addr, plen, peer_address);
- obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle);
+ nmp_object_stackinit_id_ip4_address (&obj_id, ifindex, addr, plen, peer_address);
+ obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
if (nmp_object_is_visible (obj))
return &obj->ip4_address;
return NULL;
@@ -4313,11 +4762,11 @@ ip4_address_get (NMPlatform *platform, int ifindex, in_addr_t addr, int plen, in
static const NMPlatformIP6Address *
ip6_address_get (NMPlatform *platform, int ifindex, struct in6_addr addr, int plen)
{
- NMPObject obj_needle;
+ NMPObject obj_id;
const NMPObject *obj;
- nmp_object_stackinit_id_ip6_address (&obj_needle, ifindex, &addr, plen);
- obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle);
+ nmp_object_stackinit_id_ip6_address (&obj_id, ifindex, &addr, plen);
+ obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
if (nmp_object_is_visible (obj))
return &obj->ip6_address;
return NULL;
@@ -4376,113 +4825,29 @@ ip6_route_get_all (NMPlatform *platform, int ifindex, NMPlatformGetRouteFlags fl
return ipx_route_get_all (platform, ifindex, NMP_OBJECT_TYPE_IP6_ROUTE, flags);
}
-static void
-clear_host_address (int family, const void *network, int plen, void *dst)
-{
- g_return_if_fail (plen == (guint8)plen);
- g_return_if_fail (network);
-
- switch (family) {
- case AF_INET:
- *((in_addr_t *) dst) = nm_utils_ip4_address_clear_host_address (*((in_addr_t *) network), plen);
- break;
- case AF_INET6:
- nm_utils_ip6_address_clear_host_address ((struct in6_addr *) dst, (const struct in6_addr *) network, plen);
- break;
- default:
- g_assert_not_reached ();
- }
-}
-
-static struct nl_object *
-build_rtnl_route (int family, int ifindex, NMIPConfigSource source,
- gconstpointer network, int plen, gconstpointer gateway,
- gconstpointer pref_src,
- guint32 metric, guint32 mss)
-{
- guint32 network_clean[4];
- struct rtnl_route *rtnlroute;
- struct rtnl_nexthop *nexthop;
- int addrlen = (family == AF_INET) ? sizeof (in_addr_t) : sizeof (struct in6_addr);
- /* Workaround a libnl bug by using zero destination address length for default routes */
- auto_nl_addr struct nl_addr *dst = NULL;
- auto_nl_addr struct nl_addr *gw = gateway ? _nl_addr_build (family, gateway, addrlen) : NULL;
- auto_nl_addr struct nl_addr *pref_src_nl = pref_src ? _nl_addr_build (family, pref_src, addrlen) : NULL;
-
- /* There seem to be problems adding a route with non-zero host identifier.
- * Adding IPv6 routes is simply ignored, without error message.
- * In the IPv4 case, we got an error. Thus, we have to make sure, that
- * the address is sane. */
- clear_host_address (family, network, plen, network_clean);
- dst = _nl_addr_build (family, network_clean, plen ? addrlen : 0);
- nl_addr_set_prefixlen (dst, plen);
-
- rtnlroute = _nl_rtnl_route_alloc ();
- rtnl_route_set_table (rtnlroute, RT_TABLE_MAIN);
- rtnl_route_set_tos (rtnlroute, 0);
- rtnl_route_set_dst (rtnlroute, dst);
- rtnl_route_set_priority (rtnlroute, metric);
- rtnl_route_set_family (rtnlroute, family);
- rtnl_route_set_protocol (rtnlroute, _nm_ip_config_source_to_rtprot (source));
-
- nexthop = _nl_rtnl_route_nh_alloc ();
- rtnl_route_nh_set_ifindex (nexthop, ifindex);
- if (gw && !nl_addr_iszero (gw))
- rtnl_route_nh_set_gateway (nexthop, gw);
- if (pref_src_nl)
- rtnl_route_set_pref_src (rtnlroute, pref_src_nl);
- rtnl_route_add_nexthop (rtnlroute, nexthop);
-
- if (mss > 0)
- rtnl_route_set_metric (rtnlroute, RTAX_ADVMSS, mss);
-
- return (struct nl_object *) rtnlroute;
-}
-
-struct nl_object *
-_nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
-{
- const NMPlatformIP4Route *obj = (const NMPlatformIP4Route *) _obj;
-
- return build_rtnl_route (AF_INET,
- obj->ifindex,
- obj->source,
- &obj->network,
- obj->plen,
- &obj->gateway,
- obj->pref_src ? &obj->pref_src : NULL,
- obj->metric,
- obj->mss);
-}
-
-struct nl_object *
-_nmp_vt_cmd_plobj_to_nl_ip6_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only)
-{
- const NMPlatformIP6Route *obj = (const NMPlatformIP6Route *) _obj;
-
- return build_rtnl_route (AF_INET6,
- obj->ifindex,
- obj->source,
- &obj->network,
- obj->plen,
- &obj->gateway,
- NULL,
- obj->metric,
- obj->mss);
-}
-
static gboolean
ip4_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
in_addr_t network, int plen, in_addr_t gateway,
in_addr_t pref_src, guint32 metric, guint32 mss)
{
- NMPObject obj_needle;
- auto_nl_object struct nl_object *nlo = NULL;
+ NMPObject obj_id;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+
+ nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
+ NLM_F_CREATE | NLM_F_REPLACE,
+ AF_INET,
+ ifindex,
+ source,
+ gateway ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
+ &network,
+ plen,
+ &gateway,
+ metric,
+ mss,
+ pref_src ? &pref_src : NULL);
- nlo = build_rtnl_route (AF_INET, ifindex, source, &network, plen, &gateway, pref_src ? &pref_src : NULL, metric, mss);
- return do_add_addrroute (platform,
- nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, network, plen, metric),
- nlo);
+ nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
+ return do_add_addrroute (platform, &obj_id, nlmsg);
}
static gboolean
@@ -4490,30 +4855,34 @@ ip6_route_add (NMPlatform *platform, int ifindex, NMIPConfigSource source,
struct in6_addr network, int plen, struct in6_addr gateway,
guint32 metric, guint32 mss)
{
- NMPObject obj_needle;
- auto_nl_object struct nl_object *nlo = NULL;
+ NMPObject obj_id;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
- metric = nm_utils_ip6_route_metric_normalize (metric);
+ nlmsg = _nl_msg_new_route (RTM_NEWROUTE,
+ NLM_F_CREATE | NLM_F_REPLACE,
+ AF_INET6,
+ ifindex,
+ source,
+ !IN6_IS_ADDR_UNSPECIFIED (&gateway) ? RT_SCOPE_UNIVERSE : RT_SCOPE_LINK,
+ &network,
+ plen,
+ &gateway,
+ metric,
+ mss,
+ NULL);
- nlo = build_rtnl_route (AF_INET6, ifindex, source, &network, plen, &gateway, NULL, metric, mss);
- return do_add_addrroute (platform,
- nmp_object_stackinit_id_ip6_route (&obj_needle, ifindex, &network, plen, metric),
- nlo);
+ nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
+ return do_add_addrroute (platform, &obj_id, nlmsg);
}
static gboolean
ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
{
NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform);
- in_addr_t gateway = 0;
- auto_nl_object struct nl_object *nlo = build_rtnl_route (AF_INET, ifindex, NM_IP_CONFIG_SOURCE_UNKNOWN, &network, plen, &gateway, NULL, metric, 0);
- uint8_t scope = RT_SCOPE_NOWHERE;
- const NMPObject *obj;
- NMPObject obj_needle;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ NMPObject obj_id;
- g_return_val_if_fail (nlo, FALSE);
-
- nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, network, plen, metric);
+ nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
if (metric == 0) {
/* Deleting an IPv4 route with metric 0 does not only delete an exectly matching route.
@@ -4523,94 +4892,81 @@ ip4_route_delete (NMPlatform *platform, int ifindex, in_addr_t network, int plen
* Instead, make sure that we have the most recent state and process all
* delayed actions (including re-reading data from netlink). */
delayed_action_handle_all (platform, TRUE);
- }
-
- obj = nmp_cache_lookup_obj (priv->cache, &obj_needle);
-
- if (metric == 0 && !obj) {
- /* hmm... we are about to delete an IP4 route with metric 0. We must only
- * send the delete request if such a route really exists. Above we refreshed
- * the platform cache, still no such route exists.
- *
- * Be extra careful and reload the routes. We must be sure that such a
- * route doesn't exists, because when we add an IPv4 address, we immediately
- * afterwards try to delete the kernel-added device route with metric 0.
- * It might be, that we didn't yet get the notification about that route.
- *
- * FIXME: once our ip4_address_add() is sure that upon return we have
- * the latest state from in the platform cache, we might save this
- * additional expensive cache-resync. */
- do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE, TRUE);
-
- obj = nmp_cache_lookup_obj (priv->cache, &obj_needle);
- if (!obj)
- return TRUE;
- }
- if (!_nl_has_capability (1 /* NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE */)) {
- /* When searching for a matching IPv4 route to delete, the kernel
- * searches for a matching scope, unless the RTM_DELROUTE message
- * specifies RT_SCOPE_NOWHERE (see fib_table_delete()).
- *
- * However, if we set the scope of @rtnlroute to RT_SCOPE_NOWHERE (or
- * leave it unset), rtnl_route_build_msg() will reset the scope to
- * rtnl_route_guess_scope() -- which probably guesses wrong.
- *
- * As a workaround, we look at the cached route and use that scope.
- *
- * Newer versions of libnl, no longer reset the scope if explicitly set to RT_SCOPE_NOWHERE.
- * So, this workaround is only needed unless we have NL_CAPABILITY_ROUTE_BUILD_MSG_SET_SCOPE.
- **/
-
- if (obj)
- scope = nm_platform_route_scope_inv (obj->ip4_route.scope_inv);
+ if (!nmp_cache_lookup_obj (priv->cache, &obj_id)) {
+ /* hmm... we are about to delete an IP4 route with metric 0. We must only
+ * send the delete request if such a route really exists. Above we refreshed
+ * the platform cache, still no such route exists.
+ *
+ * Be extra careful and reload the routes. We must be sure that such a
+ * route doesn't exists, because when we add an IPv4 address, we immediately
+ * afterwards try to delete the kernel-added device route with metric 0.
+ * It might be, that we didn't yet get the notification about that route.
+ *
+ * FIXME: once our ip4_address_add() is sure that upon return we have
+ * the latest state from in the platform cache, we might save this
+ * additional expensive cache-resync. */
+ do_request_one_type (platform, NMP_OBJECT_TYPE_IP4_ROUTE, TRUE);
- if (scope == RT_SCOPE_NOWHERE) {
- /* If we would set the scope to RT_SCOPE_NOWHERE, libnl would guess the scope.
- * But probably it will guess 'link' because we set the next hop of the route
- * to zero (0.0.0.0). A better guess is 'global'. */
- scope = RT_SCOPE_UNIVERSE;
+ if (!nmp_cache_lookup_obj (priv->cache, &obj_id))
+ return TRUE;
}
}
- rtnl_route_set_scope ((struct rtnl_route *) nlo, scope);
- /* we only support routes with TOS zero. As such, delete_route() is also only able to delete
- * routes with tos==0. build_rtnl_route() already initializes tos properly. */
-
- /* The following fields are also relevant when comparing the route, but the default values
- * are already as we want them:
- *
- * type: RTN_UNICAST (setting to zero would ignore the type, but we only want to delete RTN_UNICAST)
- * pref_src: NULL
- */
+ nlmsg = _nl_msg_new_route (RTM_DELROUTE,
+ 0,
+ AF_INET,
+ ifindex,
+ NM_IP_CONFIG_SOURCE_UNKNOWN,
+ RT_SCOPE_NOWHERE,
+ &network,
+ plen,
+ NULL,
+ metric,
+ 0,
+ NULL);
+ if (!nlmsg)
+ return FALSE;
- return do_delete_object (platform, &obj_needle, nlo);
+ return do_delete_object (platform, &obj_id, nlmsg);
}
static gboolean
ip6_route_delete (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
{
- struct in6_addr gateway = IN6ADDR_ANY_INIT;
- auto_nl_object struct nl_object *nlo = NULL;
- NMPObject obj_needle;
+ nm_auto_nlmsg struct nl_msg *nlmsg = NULL;
+ NMPObject obj_id;
metric = nm_utils_ip6_route_metric_normalize (metric);
- nlo = build_rtnl_route (AF_INET6, ifindex, NM_IP_CONFIG_SOURCE_UNKNOWN ,&network, plen, &gateway, NULL, metric, 0);
+ nlmsg = _nl_msg_new_route (RTM_DELROUTE,
+ 0,
+ AF_INET6,
+ ifindex,
+ NM_IP_CONFIG_SOURCE_UNKNOWN,
+ RT_SCOPE_NOWHERE,
+ &network,
+ plen,
+ NULL,
+ metric,
+ 0,
+ NULL);
+ if (!nlmsg)
+ return FALSE;
- nmp_object_stackinit_id_ip6_route (&obj_needle, ifindex, &network, plen, metric);
+ nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
- return do_delete_object (platform, &obj_needle, nlo);
+ return do_delete_object (platform, &obj_id, nlmsg);
}
static const NMPlatformIP4Route *
ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, guint32 metric)
{
- NMPObject obj_needle;
+ NMPObject obj_id;
const NMPObject *obj;
- nmp_object_stackinit_id_ip4_route (&obj_needle, ifindex, network, plen, metric);
- obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle);
+ nmp_object_stackinit_id_ip4_route (&obj_id, ifindex, network, plen, metric);
+ obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
if (nmp_object_is_visible (obj))
return &obj->ip4_route;
return NULL;
@@ -4619,13 +4975,13 @@ ip4_route_get (NMPlatform *platform, int ifindex, in_addr_t network, int plen, g
static const NMPlatformIP6Route *
ip6_route_get (NMPlatform *platform, int ifindex, struct in6_addr network, int plen, guint32 metric)
{
- NMPObject obj_needle;
+ NMPObject obj_id;
const NMPObject *obj;
metric = nm_utils_ip6_route_metric_normalize (metric);
- nmp_object_stackinit_id_ip6_route (&obj_needle, ifindex, &network, plen, metric);
- obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_needle);
+ nmp_object_stackinit_id_ip6_route (&obj_id, ifindex, &network, plen, metric);
+ obj = nmp_cache_lookup_obj (NM_LINUX_PLATFORM_GET_PRIVATE (platform)->cache, &obj_id);
if (nmp_object_is_visible (obj))
return &obj->ip6_route;
return NULL;
@@ -5080,6 +5436,8 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->link_get_type_name = link_get_type_name;
platform_class->link_get_unmanaged = link_get_unmanaged;
+ platform_class->link_get_lnk = link_get_lnk;
+
platform_class->link_refresh = link_refresh;
platform_class->link_set_up = link_set_up;
@@ -5112,18 +5470,9 @@ nm_linux_platform_class_init (NMLinuxPlatformClass *klass)
platform_class->slave_get_option = slave_get_option;
platform_class->vlan_add = vlan_add;
- platform_class->vlan_get_info = vlan_get_info;
- platform_class->vlan_set_ingress_map = vlan_set_ingress_map;
- platform_class->vlan_set_egress_map = vlan_set_egress_map;
+ platform_class->link_vlan_change = link_vlan_change;
platform_class->infiniband_partition_add = infiniband_partition_add;
- platform_class->infiniband_get_info = infiniband_get_info;
-
- platform_class->veth_get_properties = veth_get_properties;
- platform_class->tun_get_properties = tun_get_properties;
- platform_class->macvlan_get_properties = macvlan_get_properties;
- platform_class->vxlan_get_properties = vxlan_get_properties;
- platform_class->gre_get_properties = gre_get_properties;
platform_class->wifi_get_capabilities = wifi_get_capabilities;
platform_class->wifi_get_bssid = wifi_get_bssid;
diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c
index f28a544f87..35cfc885ec 100644
--- a/src/platform/nm-platform.c
+++ b/src/platform/nm-platform.c
@@ -28,11 +28,15 @@
#include <string.h>
#include <netlink/route/addr.h>
#include <netlink/route/rtnl.h>
+#include <linux/ip.h>
+#include <linux/if_tun.h>
+#include <linux/if_tunnel.h>
#include "NetworkManagerUtils.h"
#include "nm-utils.h"
#include "nm-platform.h"
#include "nm-platform-utils.h"
+#include "nmp-object.h"
#include "NetworkManagerUtils.h"
#include "nm-default.h"
#include "nm-enum-types.h"
@@ -67,6 +71,8 @@ G_STATIC_ASSERT (G_STRUCT_OFFSET (NMPlatformIPRoute, network_ptr) == G_STRUCT_OF
} \
} G_STMT_END
+/*****************************************************************************/
+
#define NM_PLATFORM_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_PLATFORM, NMPlatformPrivate))
G_DEFINE_TYPE (NMPlatform, nm_platform, G_TYPE_OBJECT)
@@ -207,22 +213,6 @@ nm_platform_error_to_string (NMPlatformError error)
/******************************************************************/
-#define IFA_F_MANAGETEMPADDR_STR "mngtmpaddr"
-#define IFA_F_NOPREFIXROUTE_STR "noprefixroute"
-gboolean
-nm_platform_check_support_libnl_extended_ifa_flags ()
-{
- static int supported = -1;
-
- /* support for extended ifa-flags was added together
- * with the IFA_F_MANAGETEMPADDR flag. So, check if libnl
- * is able to parse this flag. */
- if (supported == -1)
- supported = rtnl_addr_str2flags (IFA_F_MANAGETEMPADDR_STR) == IFA_F_MANAGETEMPADDR;
-
- return supported;
-}
-
gboolean
nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self)
{
@@ -430,7 +420,7 @@ nm_platform_link_get_all (NMPlatform *self)
for (i = 0; i < links->len; i++) {
item = &g_array_index (links, NMPlatformLink, i);
- _LOGT ("link-get: %3d: %s", i, nm_platform_link_to_string (item));
+ _LOGT ("link-get: %3d: %s", i, nm_platform_link_to_string (item, NULL, 0));
nm_assert (item->ifindex > 0 && !g_hash_table_contains (unseen, GINT_TO_POINTER (item->ifindex)));
@@ -453,8 +443,7 @@ nm_platform_link_get_all (NMPlatform *self)
if (item->parent != NM_PLATFORM_LINK_OTHER_NETNS) {
g_warn_if_fail (item->parent > 0);
g_warn_if_fail (item->parent != item->ifindex);
- g_warn_if_fail ( !nm_platform_check_support_libnl_link_netnsid ()
- || g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)));
+ g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)));
}
}
}
@@ -486,7 +475,7 @@ nm_platform_link_get_all (NMPlatform *self)
if (item->parent > 0 && g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)))
continue;
- _LOGT ("link-get: add %3d -> %3d: %s", i, j, nm_platform_link_to_string (item));
+ _LOGT ("link-get: add %3d -> %3d: %s", i, j, nm_platform_link_to_string (item, NULL, 0));
g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex));
g_array_index (result, NMPlatformLink, j++) = *item;
@@ -499,7 +488,7 @@ nm_platform_link_get_all (NMPlatform *self)
* This can happen for veth pairs where each peer is parent of the other end. */
item = &g_array_index (links, NMPlatformLink, first_idx);
- _LOGT ("link-get: add (loop) %3d -> %3d: %s", first_idx, j, nm_platform_link_to_string (item));
+ _LOGT ("link-get: add (loop) %3d -> %3d: %s", first_idx, j, nm_platform_link_to_string (item, NULL, 0));
g_hash_table_remove (unseen, GINT_TO_POINTER (item->ifindex));
g_array_index (result, NMPlatformLink, j++) = *item;
@@ -893,22 +882,19 @@ nm_platform_link_uses_arp (NMPlatform *self, int ifindex)
gboolean
nm_platform_link_get_ipv6_token (NMPlatform *self, int ifindex, NMUtilsIPv6IfaceId *iid)
{
+ const NMPlatformLink *pllink;
+
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex >= 0, FALSE);
g_return_val_if_fail (iid, FALSE);
-#if HAVE_LIBNL_INET6_TOKEN
- {
- const NMPlatformLink *pllink;
- pllink = nm_platform_link_get (self, ifindex);
- if (pllink && pllink->inet6_token.is_valid) {
- *iid = pllink->inet6_token.iid;
- return TRUE;
- }
+ pllink = nm_platform_link_get (self, ifindex);
+ if (pllink && pllink->inet6_token.is_valid) {
+ *iid = pllink->inet6_token.iid;
+ return TRUE;
}
-#endif
return FALSE;
}
@@ -950,23 +936,18 @@ nm_platform_link_get_udev_device (NMPlatform *self, int ifindex)
gboolean
nm_platform_link_get_user_ipv6ll_enabled (NMPlatform *self, int ifindex)
{
+ const NMPlatformLink *pllink;
+
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex >= 0, FALSE);
-#if HAVE_LIBNL_INET6_ADDR_GEN_MODE && HAVE_KERNEL_INET6_ADDR_GEN_MODE
- {
- const NMPlatformLink *pllink;
-
- pllink = nm_platform_link_get (self, ifindex);
- if (pllink && pllink->inet6_addr_gen_mode_inv)
- return _nm_platform_uint8_inv (pllink->inet6_addr_gen_mode_inv) == IN6_ADDR_GEN_MODE_NONE;
- }
-#endif
+ pllink = nm_platform_link_get (self, ifindex);
+ if (pllink && pllink->inet6_addr_gen_mode_inv)
+ return _nm_platform_uint8_inv (pllink->inet6_addr_gen_mode_inv) == NM_IN6_ADDR_GEN_MODE_NONE;
return FALSE;
}
-
/**
* nm_platform_link_set_user_ip6vll_enabled:
* @self: platform instance
@@ -1387,6 +1368,83 @@ nm_platform_link_get_master (NMPlatform *self, int slave)
return pllink ? pllink->master : 0;
}
+/*****************************************************************************/
+
+/**
+ * nm_platform_link_get_lnk:
+ * @self: the platform instance
+ * @ifindex: the link ifindex to lookup
+ * @link_type: filter by link-type.
+ * @out_link: (allow-none): returns the platform link instance
+ *
+ * If the function returns %NULL, that could mean that no such ifindex
+ * exists, of that the link has no lnk data. You can find that out
+ * by checking @out_link. @out_link will always be set if a link
+ * with @ifindex exists.
+ *
+ * If @link_type is %NM_LINK_TYPE_NONE, the function returns the lnk
+ * object if it is present. If you set link-type, you can be sure
+ * that only a link type of the matching type is returned (or %NULL).
+ *
+ * Returns: the internal link lnk object. The returned object
+ * is owned by the platform cache and must not be modified. Note
+ * however, that the object is guaranteed to be immutable, so
+ * you can savely take a reference and keep it for yourself
+ * (but don't modify it).
+ */
+const NMPObject *
+nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link)
+{
+ _CHECK_SELF (self, klass, FALSE);
+
+ NM_SET_OUT (out_link, NULL);
+
+ g_return_val_if_fail (ifindex > 0, NULL);
+
+ return klass->link_get_lnk (self, ifindex, link_type, out_link);
+}
+
+static gconstpointer
+_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link)
+{
+ const NMPObject *lnk;
+
+ lnk = nm_platform_link_get_lnk (self, ifindex, link_type, out_link);
+ return lnk ? &lnk->object : NULL;
+}
+
+const NMPlatformLnkGre *
+nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_GRE, out_link);
+}
+
+const NMPlatformLnkInfiniband *
+nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_INFINIBAND, out_link);
+}
+
+const NMPlatformLnkMacvlan *
+nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_MACVLAN, out_link);
+}
+
+const NMPlatformLnkVlan *
+nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VLAN, out_link);
+}
+
+const NMPlatformLnkVxlan *
+nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link)
+{
+ return _link_get_lnk (self, ifindex, NM_LINK_TYPE_VXLAN, out_link);
+}
+
+/*****************************************************************************/
+
/**
* nm_platform_bridge_add:
* @self: platform instance
@@ -1524,43 +1582,91 @@ nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option)
}
gboolean
-nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid)
+nm_platform_link_vlan_change (NMPlatform *self,
+ int ifindex,
+ NMVlanFlags flags_mask,
+ NMVlanFlags flags_set,
+ gboolean ingress_reset_all,
+ const NMVlanQosMapping *ingress_map,
+ gsize n_ingress_map,
+ gboolean egress_reset_all,
+ const NMVlanQosMapping *egress_map,
+ gsize n_egress_map)
{
_CHECK_SELF (self, klass, FALSE);
- g_return_val_if_fail (klass->vlan_get_info, FALSE);
+ nm_assert (klass->link_vlan_change);
- if (parent)
- *parent = 0;
- if (vlanid)
- *vlanid = 0;
+ g_return_val_if_fail (!n_ingress_map || ingress_map, FALSE);
+ g_return_val_if_fail (!n_egress_map || egress_map, FALSE);
- if (nm_platform_link_get_type (self, ifindex) != NM_LINK_TYPE_VLAN)
- return FALSE;
+ flags_set &= flags_mask;
+
+ if (_LOGD_ENABLED ()) {
+ char buf[512];
+ char *b = buf;
+ gsize len, i;
+
+ b[0] = '\0';
+ len = sizeof (buf);
+
+ if (flags_mask)
+ nm_utils_strbuf_append (&b, &len, " flags 0x%x/0x%x", (unsigned) flags_set, (unsigned) flags_mask);
+
+ if (ingress_reset_all || n_ingress_map) {
+ nm_utils_strbuf_append_str (&b, &len, " ingress-qos-map");
+ nm_platform_vlan_qos_mapping_to_string ("", ingress_map, n_ingress_map, b, len);
+ i = strlen (b);
+ b += i;
+ len -= i;
+ if (ingress_reset_all)
+ nm_utils_strbuf_append_str (&b, &len, " (reset-all)");
+ }
- return klass->vlan_get_info (self, ifindex, parent, vlanid);
+ if (egress_reset_all || n_egress_map) {
+ nm_utils_strbuf_append_str (&b, &len, " egress-qos-map");
+ nm_platform_vlan_qos_mapping_to_string ("", egress_map, n_egress_map, b, len);
+ i = strlen (b);
+ b += i;
+ len -= i;
+ if (egress_reset_all)
+ nm_utils_strbuf_append_str (&b, &len, " (reset-all)");
+ }
+
+ _LOGD ("link: change vlan %d:%s", ifindex, buf);
+ }
+ return klass->link_vlan_change (self,
+ ifindex,
+ flags_mask,
+ flags_set,
+ ingress_reset_all,
+ ingress_map,
+ n_ingress_map,
+ egress_reset_all,
+ egress_map,
+ n_egress_map);
}
gboolean
nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to)
{
- _CHECK_SELF (self, klass, FALSE);
+ NMVlanQosMapping map = {
+ .from = from,
+ .to = to,
+ };
- g_return_val_if_fail (klass->vlan_set_ingress_map, FALSE);
-
- _LOGD ("link: setting vlan ingress map for %d from %d to %d", ifindex, from, to);
- return klass->vlan_set_ingress_map (self, ifindex, from, to);
+ return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, &map, 1, FALSE, NULL, 0);
}
gboolean
nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to)
{
- _CHECK_SELF (self, klass, FALSE);
+ NMVlanQosMapping map = {
+ .from = from,
+ .to = to,
+ };
- g_return_val_if_fail (klass->vlan_set_egress_map, FALSE);
-
- _LOGD ("link: setting vlan egress map for %d from %d to %d", ifindex, from, to);
- return klass->vlan_set_egress_map (self, ifindex, from, to);
+ return nm_platform_link_vlan_change (self, ifindex, 0, 0, FALSE, NULL, 0, FALSE, &map, 1);
}
NMPlatformError
@@ -1594,73 +1700,175 @@ nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, N
}
gboolean
-nm_platform_infiniband_get_info (NMPlatform *self,
- int ifindex,
- int *parent,
- int *p_key,
- const char **mode)
-{
+nm_platform_infiniband_get_properties (NMPlatform *self,
+ int ifindex,
+ int *out_parent,
+ int *out_p_key,
+ const char **out_mode)
+{
+ const NMPlatformLnkInfiniband *plnk;
+ const NMPlatformLink *plink;
+ const char *iface;
+ char *path, *contents;
+ const char *mode;
+ int p_key = 0;
+
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex > 0, FALSE);
- g_return_val_if_fail (klass->infiniband_get_info, FALSE);
- return klass->infiniband_get_info (self, ifindex, parent, p_key, mode);
-}
+ plnk = nm_platform_link_get_lnk_infiniband (self, ifindex, &plink);
-gboolean
-nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *props)
-{
- _CHECK_SELF (self, klass, FALSE);
+ if ( !plink
+ || plink->type != NM_LINK_TYPE_INFINIBAND)
+ return FALSE;
- g_return_val_if_fail (ifindex > 0, FALSE);
- g_return_val_if_fail (props != NULL, FALSE);
+ if (plnk) {
+ NM_SET_OUT (out_parent, plink->parent);
+ NM_SET_OUT (out_p_key, plnk->p_key);
+ NM_SET_OUT (out_mode, plnk->mode);
+ return TRUE;
+ }
- return klass->veth_get_properties (self, ifindex, props);
-}
+ /* Could not get the link information via netlink. To support older kernels,
+ * fallback to reading sysfs. */
-gboolean
-nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props)
-{
- _CHECK_SELF (self, klass, FALSE);
+ iface = ASSERT_VALID_PATH_COMPONENT (plink->name);
- g_return_val_if_fail (ifindex > 0, FALSE);
- g_return_val_if_fail (props != NULL, FALSE);
+ /* Fall back to reading sysfs */
+ path = g_strdup_printf ("/sys/class/net/%s/mode", iface);
+ contents = nm_platform_sysctl_get (self, path);
+ g_free (path);
+ if (!contents)
+ return FALSE;
+
+ if (strstr (contents, "datagram"))
+ mode = "datagram";
+ else if (strstr (contents, "connected"))
+ mode = "connected";
+ else
+ mode = NULL;
+ g_free (contents);
- return klass->tun_get_properties (self, ifindex, props);
+ path = g_strdup_printf ("/sys/class/net/%s/pkey", iface);
+ contents = nm_platform_sysctl_get (self, path);
+ g_free (path);
+ if (!contents)
+ return FALSE;
+ p_key = (int) _nm_utils_ascii_str_to_int64 (contents, 16, 0, 0xFFFF, -1);
+ g_free (contents);
+ if (p_key < 0)
+ return FALSE;
+
+ NM_SET_OUT (out_parent, plink->parent);
+ NM_SET_OUT (out_p_key, p_key);
+ NM_SET_OUT (out_mode, mode);
+ return TRUE;
}
gboolean
-nm_platform_macvlan_get_properties (NMPlatform *self, int ifindex, NMPlatformMacvlanProperties *props)
+nm_platform_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex)
{
+ const NMPlatformLink *plink;
+ int peer_ifindex;
_CHECK_SELF (self, klass, FALSE);
- g_return_val_if_fail (ifindex > 0, FALSE);
- g_return_val_if_fail (props != NULL, FALSE);
+ plink = nm_platform_link_get (self, ifindex);
+
+ if (!plink)
+ return FALSE;
+ if (plink->type != NM_LINK_TYPE_VETH)
+ return FALSE;
+
+ if (plink->parent != 0) {
+ NM_SET_OUT (out_peer_ifindex, plink->parent);
+ return TRUE;
+ }
- return klass->macvlan_get_properties (self, ifindex, props);
+ /* Pre-4.1 kernel did not expose the peer_ifindex as IFA_LINK. Lookup via ethtool. */
+ if (out_peer_ifindex) {
+ peer_ifindex = nmp_utils_ethtool_get_peer_ifindex (plink->name);
+ if (peer_ifindex <= 0)
+ return FALSE;
+
+ *out_peer_ifindex = peer_ifindex;
+ }
+ return TRUE;
}
gboolean
-nm_platform_vxlan_get_properties (NMPlatform *self, int ifindex, NMPlatformVxlanProperties *props)
+nm_platform_tun_get_properties_ifname (NMPlatform *self, const char *ifname, NMPlatformTunProperties *props)
{
+ char *path, *val;
+ gboolean success = TRUE;
+
_CHECK_SELF (self, klass, FALSE);
- g_return_val_if_fail (ifindex > 0, FALSE);
- g_return_val_if_fail (props != NULL, FALSE);
+ g_return_val_if_fail (props, FALSE);
+
+ memset (props, 0, sizeof (*props));
+ props->owner = -1;
+ props->group = -1;
- return klass->vxlan_get_properties (self, ifindex, props);
+ if (!ifname || !nm_utils_iface_valid_name (ifname))
+ return FALSE;
+ ifname = ASSERT_VALID_PATH_COMPONENT (ifname);
+
+ path = g_strdup_printf ("/sys/class/net/%s/owner", ifname);
+ val = nm_platform_sysctl_get (self, path);
+ g_free (path);
+ if (val) {
+ props->owner = _nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1);
+ if (errno)
+ success = FALSE;
+ g_free (val);
+ } else
+ success = FALSE;
+
+ path = g_strdup_printf ("/sys/class/net/%s/group", ifname);
+ val = nm_platform_sysctl_get (self, path);
+ g_free (path);
+ if (val) {
+ props->group = _nm_utils_ascii_str_to_int64 (val, 10, -1, G_MAXINT64, -1);
+ if (errno)
+ success = FALSE;
+ g_free (val);
+ } else
+ success = FALSE;
+
+ path = g_strdup_printf ("/sys/class/net/%s/tun_flags", ifname);
+ val = nm_platform_sysctl_get (self, path);
+ g_free (path);
+ if (val) {
+ gint64 flags;
+
+ flags = _nm_utils_ascii_str_to_int64 (val, 16, 0, G_MAXINT64, 0);
+ if (!errno) {
+#ifndef IFF_MULTI_QUEUE
+ const int IFF_MULTI_QUEUE = 0x0100;
+#endif
+ props->mode = ((flags & (IFF_TUN | IFF_TAP)) == IFF_TUN) ? "tun" : "tap";
+ props->no_pi = !!(flags & IFF_NO_PI);
+ props->vnet_hdr = !!(flags & IFF_VNET_HDR);
+ props->multi_queue = !!(flags & IFF_MULTI_QUEUE);
+ } else
+ success = FALSE;
+ g_free (val);
+ } else
+ success = FALSE;
+
+ return success;
}
gboolean
-nm_platform_gre_get_properties (NMPlatform *self, int ifindex, NMPlatformGreProperties *props)
+nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *props)
{
_CHECK_SELF (self, klass, FALSE);
g_return_val_if_fail (ifindex > 0, FALSE);
g_return_val_if_fail (props != NULL, FALSE);
- return klass->gre_get_properties (self, ifindex, props);
+ return nm_platform_tun_get_properties_ifname (self, nm_platform_link_get_name (self, ifindex), props);
}
gboolean
@@ -1827,10 +2035,12 @@ _to_string_dev (NMPlatform *self, int ifindex, char *buf, size_t size)
/******************************************************************/
-in_addr_t
-nm_platform_ip4_address_get_peer (const NMPlatformIP4Address *addr)
+void
+nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, int plen)
{
- return addr->peer_address ?: addr->address;
+ addr->address = address;
+ addr->peer_address = address;
+ addr->plen = plen;
}
const struct in6_addr *
@@ -1842,28 +2052,6 @@ nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr)
return &addr->peer_address;
}
-in_addr_t
-nm_platform_ip4_address_get_peer_net (const NMPlatformIP4Address *addr)
-{
- return (addr->peer_address ?: addr->address) & nm_utils_ip4_prefix_to_netmask (addr->plen);
-}
-
-gboolean
-nm_platform_ip4_address_equal_peer_net (const NMPlatformIP4Address *addr1, const NMPlatformIP4Address *addr2)
-{
- guint32 a1, a2;
-
- if (addr1->plen != addr2->plen)
- return FALSE;
-
- /* For kernel, if the peer address is unset, that effectively means that
- * the peer address equals the local address. */
- a1 = addr1->peer_address ? addr1->peer_address : addr1->address;
- a2 = addr2->peer_address ? addr2->peer_address : addr2->address;
-
- return ((a1 ^ a2) & nm_utils_ip4_prefix_to_netmask (addr1->plen)) == 0;
-}
-
GArray *
nm_platform_ip4_address_get_all (NMPlatform *self, int ifindex)
{
@@ -1918,7 +2106,7 @@ nm_platform_ip4_address_add (NMPlatform *self,
if (label)
g_strlcpy (addr.label, label, sizeof (addr.label));
- _LOGD ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr));
+ _LOGD ("address: adding or updating IPv4 address: %s", nm_platform_ip4_address_to_string (&addr, NULL, 0));
}
return klass->ip4_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, label);
}
@@ -1953,7 +2141,7 @@ nm_platform_ip6_address_add (NMPlatform *self,
addr.preferred = preferred;
addr.flags = flags;
- _LOGD ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr));
+ _LOGD ("address: adding or updating IPv6 address: %s", nm_platform_ip6_address_to_string (&addr, NULL, 0));
}
return klass->ip6_address_add (self, ifindex, address, plen, peer_address, lifetime, preferred, flags);
}
@@ -1962,7 +2150,8 @@ gboolean
nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address)
{
char str_dev[TO_STRING_DEV_BUF_SIZE];
- char str_peer[NM_UTILS_INET_ADDRSTRLEN];
+ char str_peer2[NM_UTILS_INET_ADDRSTRLEN];
+ char str_peer[100];
_CHECK_SELF (self, klass, FALSE);
@@ -1970,11 +2159,10 @@ nm_platform_ip4_address_delete (NMPlatform *self, int ifindex, in_addr_t address
g_return_val_if_fail (plen > 0, FALSE);
g_return_val_if_fail (klass->ip4_address_delete, FALSE);
- _LOGD ("address: deleting IPv4 address %s/%d, %s%s%sifindex %d%s",
+ _LOGD ("address: deleting IPv4 address %s/%d, %sifindex %d%s",
nm_utils_inet4_ntop (address, NULL), plen,
- peer_address ? "peer " : "",
- peer_address ? nm_utils_inet4_ntop (peer_address, str_peer) : "",
- peer_address ? ", " : "",
+ peer_address != address
+ ? nm_sprintf_buf (str_peer, "peer %s, ", nm_utils_inet4_ntop (peer_address, str_peer2)) : "",
ifindex,
_to_string_dev (self, ifindex, str_dev, sizeof (str_dev)));
return klass->ip4_address_delete (self, ifindex, address, plen, peer_address);
@@ -2028,7 +2216,7 @@ array_contains_ip4_address (const GArray *addresses, const NMPlatformIP4Address
if ( candidate->address == address->address
&& candidate->plen == address->plen
- && nm_platform_ip4_address_equal_peer_net (candidate, address)) {
+ && ((candidate->peer_address & address->peer_address) & nm_utils_ip4_prefix_to_netmask (address->plen)) == 0) {
guint32 lifetime, preferred;
if (nmp_utils_lifetime_get (candidate->timestamp, candidate->lifetime, candidate->preferred,
@@ -2236,7 +2424,7 @@ nm_platform_ip4_route_add (NMPlatform *self,
route.mss = mss;
route.pref_src = pref_src;
- _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route));
+ _LOGD ("route: adding or updating IPv4 route: %s", nm_platform_ip4_route_to_string (&route, NULL, 0));
}
return klass->ip4_route_add (self, ifindex, source, network, plen, gateway, pref_src, metric, mss);
}
@@ -2263,7 +2451,7 @@ nm_platform_ip6_route_add (NMPlatform *self,
route.metric = metric;
route.mss = mss;
- _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route));
+ _LOGD ("route: adding or updating IPv6 route: %s", nm_platform_ip6_route_to_string (&route, NULL, 0));
}
return klass->ip6_route_add (self, ifindex, source, network, plen, gateway, metric, mss);
}
@@ -2316,6 +2504,40 @@ nm_platform_ip6_route_get (NMPlatform *self, int ifindex, struct in6_addr networ
/******************************************************************/
+const char *
+nm_platform_vlan_qos_mapping_to_string (const char *name,
+ const NMVlanQosMapping *map,
+ gsize n_map,
+ char *buf,
+ gsize len)
+{
+ gsize i;
+ char *b;
+
+ nm_utils_to_string_buffer_init (&buf, &len);
+
+ if (!n_map) {
+ nm_utils_strbuf_append_str (&buf, &len, "");
+ return buf;
+ }
+
+ if (!map)
+ g_return_val_if_reached ("");
+
+ b = buf;
+
+ if (name) {
+ nm_utils_strbuf_append_str (&b, &len, name);
+ nm_utils_strbuf_append_str (&b, &len, " {");
+ } else
+ nm_utils_strbuf_append_c (&b, &len, '{');
+
+ for (i = 0; i < n_map; i++)
+ nm_utils_strbuf_append (&b, &len, " %u:%u", map[i].from, map[i].to);
+ nm_utils_strbuf_append_str (&b, &len, " }");
+ return buf;
+}
+
static const char *
source_to_string (NMIPConfigSource source)
{
@@ -2368,21 +2590,29 @@ _lifetime_summary_to_string (gint32 now, guint32 timestamp, guint32 preferred, g
return buf;
}
-char _nm_platform_to_string_buffer[256];
-
+/**
+ * nm_platform_link_to_string:
+ * @route: pointer to NMPlatformLink address structure
+ * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used.
+ * @len: the size of the @buf. If @buf is %NULL, this argument is ignored.
+ *
+ * A method for converting an link struct into a string representation.
+ *
+ * Returns: a string representation of the link.
+ */
const char *
-nm_platform_link_to_string (const NMPlatformLink *link)
+nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len)
{
char master[20];
char parent[20];
- char str_vlan[16];
GString *str_flags;
char str_addrmode[30];
gs_free char *str_addr = NULL;
gs_free char *str_inet6_token = NULL;
+ const char *str_link_type;
- if (!link)
- return "(unknown link)";
+ if (!nm_utils_to_string_buffer_init_null (link, &buf, &len))
+ return buf;
str_flags = g_string_new (NULL);
if (NM_FLAGS_HAS (link->flags, IFF_NOARP))
@@ -2397,7 +2627,7 @@ nm_platform_link_to_string (const NMPlatformLink *link)
if (link->flags) {
char str_flags_buf[64];
- rtnl_link_flags2str (link->flags, str_flags_buf, sizeof (str_flags_buf));
+ nm_platform_link_flags2str (link->flags, str_flags_buf, sizeof (str_flags_buf));
g_string_append_printf (str_flags, ";%s", str_flags_buf);
}
@@ -2413,11 +2643,6 @@ nm_platform_link_to_string (const NMPlatformLink *link)
else
parent[0] = 0;
- if (link->vlan_id)
- g_snprintf (str_vlan, sizeof (str_vlan), " vlan %u", (guint) link->vlan_id);
- else
- str_vlan[0] = '\0';
-
if (link->inet6_addr_gen_mode_inv) {
switch (_nm_platform_uint8_inv (link->inet6_addr_gen_mode_inv)) {
case 0:
@@ -2438,14 +2663,15 @@ nm_platform_link_to_string (const NMPlatformLink *link)
if (link->inet6_token.is_valid)
str_inet6_token = nm_utils_hwaddr_ntoa (&link->inet6_token.iid, sizeof (link->inet6_token.iid));
- g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer),
+ str_link_type = nm_link_type_to_string (link->type);
+
+ g_snprintf (buf, len,
"%d: " /* ifindex */
"%s" /* name */
"%s" /* parent */
" <%s>" /* flags */
" mtu %d"
"%s" /* master */
- "%s" /* vlan */
" arp %u" /* arptype */
"%s%s" /* link->type */
"%s%s" /* kind */
@@ -2460,12 +2686,11 @@ nm_platform_link_to_string (const NMPlatformLink *link)
parent,
str_flags->str,
link->mtu, master,
- str_vlan,
link->arptype,
- nm_link_type_to_string (link->type) ? " " : "",
- str_if_set (nm_link_type_to_string (link->type), "???"),
- link->kind ? (g_strcmp0 (nm_link_type_to_string (link->type), link->kind) ? "/" : "*") : "",
- link->kind && g_strcmp0 (nm_link_type_to_string (link->type), link->kind) ? link->kind : "",
+ str_link_type ? " " : "",
+ str_if_set (str_link_type, "???"),
+ link->kind ? (g_strcmp0 (str_link_type, link->kind) ? "/" : "*") : "",
+ link->kind && g_strcmp0 (str_link_type, link->kind) ? link->kind : "",
link->initialized ? " init" : " not-init",
str_addrmode,
str_addr ? " addr " : "",
@@ -2475,23 +2700,205 @@ nm_platform_link_to_string (const NMPlatformLink *link)
link->driver ? " driver " : "",
link->driver ? link->driver : "");
g_string_free (str_flags, TRUE);
- return _nm_platform_to_string_buffer;
+ return buf;
+}
+
+const char *
+nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len)
+{
+ char str_local[30];
+ char str_local1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_remote[30];
+ char str_remote1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_ttl[30];
+ char str_tos[30];
+ char str_parent_ifindex[30];
+ char str_input_flags[30];
+ char str_output_flags[30];
+ char str_input_key[30];
+ char str_input_key1[NM_UTILS_INET_ADDRSTRLEN];
+ char str_output_key[30];
+ char str_output_key1[NM_UTILS_INET_ADDRSTRLEN];
+
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ g_snprintf (buf, len,
+ "gre"
+ "%s" /* remote */
+ "%s" /* local */
+ "%s" /* parent_ifindex */
+ "%s" /* ttl */
+ "%s" /* tos */
+ "%s" /* path_mtu_discovery */
+ "%s" /* iflags */
+ "%s" /* oflags */
+ "%s" /* ikey */
+ "%s" /* okey */
+ "",
+ lnk->remote ? nm_sprintf_buf (str_remote, " remote %s", nm_utils_inet4_ntop (lnk->remote, str_remote1)) : "",
+ lnk->local ? nm_sprintf_buf (str_local, " local %s", nm_utils_inet4_ntop (lnk->local, str_local1)) : "",
+ lnk->parent_ifindex ? nm_sprintf_buf (str_parent_ifindex, " dev %d", lnk->parent_ifindex) : "",
+ lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : " ttl inherit",
+ lnk->tos ? (lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos 0x%x", lnk->tos)) : "",
+ lnk->path_mtu_discovery ? "" : " nopmtudisc",
+ lnk->input_flags ? nm_sprintf_buf (str_input_flags, " iflags 0x%x", lnk->input_flags) : "",
+ lnk->output_flags ? nm_sprintf_buf (str_output_flags, " oflags 0x%x", lnk->output_flags) : "",
+ NM_FLAGS_HAS (lnk->input_flags, GRE_KEY) || lnk->input_key ? nm_sprintf_buf (str_input_key, " ikey %s", nm_utils_inet4_ntop (lnk->input_key, str_input_key1)) : "",
+ NM_FLAGS_HAS (lnk->output_flags, GRE_KEY) || lnk->output_key ? nm_sprintf_buf (str_output_key, " okey %s", nm_utils_inet4_ntop (lnk->output_key, str_output_key1)) : "");
+ return buf;
+}
+
+const char *
+nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len)
+{
+ char str_p_key[64];
+
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ g_snprintf (buf, len,
+ "infiniband"
+ "%s" /* p_key */
+ "%s%s" /* mode */
+ "",
+ lnk->p_key ? nm_sprintf_buf (str_p_key, " pkey %d", lnk->p_key) : "",
+ lnk->mode ? " mode " : "",
+ lnk->mode ?: "");
+ return buf;
+}
+
+const char *
+nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len)
+{
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ g_snprintf (buf, len,
+ "macvlan%s%s%s",
+ lnk->mode ? " mode " : "",
+ lnk->mode ?: "",
+ lnk->no_promisc ? " not-promisc" : " promisc");
+ return buf;
+}
+
+const char *
+nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len)
+{
+ char *b;
+
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ b = buf;
+
+ nm_utils_strbuf_append (&b, &len, "vlan %u", lnk->id);
+ if (lnk->flags)
+ nm_utils_strbuf_append (&b, &len, " flags 0x%x", lnk->flags);
+ return buf;
+}
+
+const char *
+nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len)
+{
+ char str_group[100];
+ char str_group6[100];
+ char str_local[100];
+ char str_local6[100];
+ char str_dev[25];
+ char str_limit[25];
+ char str_src_port[35];
+ char str_dst_port[25];
+ char str_tos[25];
+ char str_ttl[25];
+
+ if (!nm_utils_to_string_buffer_init_null (lnk, &buf, &len))
+ return buf;
+
+ if (lnk->group == 0)
+ str_group[0] = '\0';
+ else {
+ g_snprintf (str_group, sizeof (str_group),
+ " %s %s",
+ IN_MULTICAST (ntohl (lnk->group)) ? "group" : "remote",
+ nm_utils_inet4_ntop (lnk->group, NULL));
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED (&lnk->group6))
+ str_group6[0] = '\0';
+ else {
+ g_snprintf (str_group6, sizeof (str_group6),
+ " %s%s %s",
+ IN6_IS_ADDR_MULTICAST (&lnk->group6) ? "group" : "remote",
+ str_group[0] ? "6" : "", /* usually, a vxlan has either v4 or v6 only. */
+ nm_utils_inet6_ntop (&lnk->group6, NULL));
+ }
+
+ if (lnk->local == 0)
+ str_local[0] = '\0';
+ else {
+ g_snprintf (str_local, sizeof (str_local),
+ " local %s",
+ nm_utils_inet4_ntop (lnk->local, NULL));
+ }
+ if (IN6_IS_ADDR_UNSPECIFIED (&lnk->local6))
+ str_local6[0] = '\0';
+ else {
+ g_snprintf (str_local6, sizeof (str_local6),
+ " local%s %s",
+ str_local[0] ? "6" : "", /* usually, a vxlan has either v4 or v6 only. */
+ nm_utils_inet6_ntop (&lnk->local6, NULL));
+ }
+
+ g_snprintf (buf, len,
+ "vxlan"
+ " id %u" /* id */
+ "%s%s" /* group/group6 */
+ "%s%s" /* local/local6 */
+ "%s" /* dev */
+ "%s" /* src_port_min/src_port_max */
+ "%s" /* dst_port */
+ "%s" /* learning */
+ "%s" /* proxy */
+ "%s" /* rsc */
+ "%s" /* l2miss */
+ "%s" /* l3miss */
+ "%s" /* tos */
+ "%s" /* ttl */
+ " ageing %u" /* ageing */
+ "%s" /* limit */
+ "",
+ (guint) lnk->id,
+ str_group, str_group6,
+ str_local, str_local6,
+ lnk->parent_ifindex ? nm_sprintf_buf (str_dev, " dev %d", lnk->parent_ifindex) : "",
+ lnk->src_port_min || lnk->src_port_max ? nm_sprintf_buf (str_src_port, " srcport %u %u", lnk->src_port_min, lnk->src_port_max) : "",
+ lnk->dst_port ? nm_sprintf_buf (str_dst_port, " dstport %u", lnk->dst_port) : "",
+ !lnk->learning ? " nolearning" : "",
+ lnk->proxy ? " proxy" : "",
+ lnk->rsc ? " rsc" : "",
+ lnk->l2miss ? " l2miss" : "",
+ lnk->l3miss ? " l3miss" : "",
+ lnk->tos == 1 ? " tos inherit" : nm_sprintf_buf (str_tos, " tos %#x", lnk->tos),
+ lnk->ttl ? nm_sprintf_buf (str_ttl, " ttl %u", lnk->ttl) : "",
+ lnk->ageing,
+ lnk->limit ? nm_sprintf_buf (str_limit, " maxaddr %u", lnk->limit) : "");
+ return buf;
}
/**
* nm_platform_ip4_address_to_string:
* @route: pointer to NMPlatformIP4Address address structure
+ * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used.
+ * @len: the size of the @buf. If @buf is %NULL, this argument is ignored.
*
* A method for converting an address struct into a string representation.
*
* Example output: ""
*
- * Returns: a string representation of the address. The returned string
- * is an internal buffer, so do not keep or free the returned string.
- * Also, this function is not thread safe.
+ * Returns: a string representation of the address.
*/
const char *
-nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address)
+nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len)
{
char s_address[INET_ADDRSTRLEN];
char s_peer[INET_ADDRSTRLEN];
@@ -2502,11 +2909,12 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address)
const char *str_lft_p, *str_pref_p, *str_time_p;
gint32 now = nm_utils_get_monotonic_timestamp_s ();
- g_return_val_if_fail (address, "(unknown)");
+ if (!nm_utils_to_string_buffer_init_null (address, &buf, &len))
+ return buf;
inet_ntop (AF_INET, &address->address, s_address, sizeof (s_address));
- if (address->peer_address) {
+ if (address->peer_address != address->address) {
inet_ntop (AF_INET, &address->peer_address, s_peer, sizeof (s_peer));
str_peer = g_strconcat (" ptp ", s_peer, NULL);
}
@@ -2528,73 +2936,122 @@ nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address)
now, str_pref, sizeof (str_pref)) );
str_time_p = _lifetime_summary_to_string (now, address->timestamp, address->preferred, address->lifetime, str_time, sizeof (str_time));
- g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s",
+ g_snprintf (buf, len,
+ "%s/%d lft %s pref %s%s%s%s%s src %s",
s_address, address->plen, str_lft_p, str_pref_p, str_time_p,
str_peer ? str_peer : "",
str_dev,
str_label,
source_to_string (address->source));
g_free (str_peer);
- return _nm_platform_to_string_buffer;
+ return buf;
}
-/**
- * nm_platform_addr_flags2str: wrapper for rtnl_addr_flags2str(),
- * which might not yet support some recent address flags.
- **/
-void
-nm_platform_addr_flags2str (int flags, char *buf, size_t size)
+const char *
+nm_platform_link_flags2str (unsigned flags, char *buf, gsize len)
+{
+ static const NMUtilsFlags2StrDesc descs[] = {
+ NM_UTILS_FLAGS2STR (IFF_LOOPBACK, "loopback"),
+ NM_UTILS_FLAGS2STR (IFF_BROADCAST, "broadcast"),
+ NM_UTILS_FLAGS2STR (IFF_POINTOPOINT, "pointopoint"),
+ NM_UTILS_FLAGS2STR (IFF_MULTICAST, "multicast"),
+ NM_UTILS_FLAGS2STR (IFF_NOARP, "noarp"),
+ NM_UTILS_FLAGS2STR (IFF_ALLMULTI, "allmulti"),
+ NM_UTILS_FLAGS2STR (IFF_PROMISC, "promisc"),
+ NM_UTILS_FLAGS2STR (IFF_MASTER, "master"),
+ NM_UTILS_FLAGS2STR (IFF_SLAVE, "slave"),
+ NM_UTILS_FLAGS2STR (IFF_DEBUG, "debug"),
+ NM_UTILS_FLAGS2STR (IFF_DYNAMIC, "dynamic"),
+ NM_UTILS_FLAGS2STR (IFF_AUTOMEDIA, "automedia"),
+ NM_UTILS_FLAGS2STR (IFF_PORTSEL, "portsel"),
+ NM_UTILS_FLAGS2STR (IFF_NOTRAILERS, "notrailers"),
+ NM_UTILS_FLAGS2STR (IFF_UP, "up"),
+ NM_UTILS_FLAGS2STR (IFF_RUNNING, "running"),
+ NM_UTILS_FLAGS2STR (IFF_LOWER_UP, "lowerup"),
+ NM_UTILS_FLAGS2STR (IFF_DORMANT, "dormant"),
+ NM_UTILS_FLAGS2STR (IFF_ECHO, "echo"),
+ };
+ return nm_utils_flags2str (descs, G_N_ELEMENTS (descs), flags, buf, len);
+};
+
+const char *
+nm_platform_link_inet6_addrgenmode2str (guint8 mode, char *buf, gsize len)
{
- if ( !NM_FLAGS_ANY (flags, IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE)
- || nm_platform_check_support_libnl_extended_ifa_flags ())
- rtnl_addr_flags2str (flags, buf, size);
- else {
- /* There are two recent flags IFA_F_MANAGETEMPADDR and IFA_F_NOPREFIXROUTE.
- * If libnl does not yet support them, add them by hand.
- * These two flags were introduced together with the extended ifa_flags
- * so check for nm_platform_check_support_libnl_extended_ifa_flags (). */
- gboolean has_other_unknown_flags = FALSE;
- size_t len;
-
- /* if there are unknown flags to rtnl_addr_flags2str(), libnl appends ','
- * to indicate them. We want to keep this behavior, if there are other
- * unknown flags present. */
-
- rtnl_addr_flags2str (flags & ~(IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE), buf, size);
-
- len = strlen (buf);
- if (len > 0) {
- has_other_unknown_flags = (buf[len - 1] == ',');
- if (!has_other_unknown_flags)
- g_strlcat (buf, ",", size);
- }
+ nm_utils_to_string_buffer_init (&buf, &len);
- if (NM_FLAGS_ALL (flags, IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE))
- g_strlcat (buf, IFA_F_MANAGETEMPADDR_STR","IFA_F_NOPREFIXROUTE_STR, size);
- else if (NM_FLAGS_HAS (flags, IFA_F_MANAGETEMPADDR))
- g_strlcat (buf, IFA_F_MANAGETEMPADDR_STR, size);
- else
- g_strlcat (buf, IFA_F_NOPREFIXROUTE_STR, size);
+ switch (mode) {
+ case NM_IN6_ADDR_GEN_MODE_NONE:
+ g_snprintf (buf, len, "none");
+ break;
+ case NM_IN6_ADDR_GEN_MODE_EUI64:
+ g_snprintf (buf, len, "eui64");
+ break;
+ case NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY:
+ g_snprintf (buf, len, "stable-privacy");
+ break;
+ default:
+ g_snprintf (buf, len, "%u", (unsigned) mode);
+ break;
+ }
+ return buf;
+}
+
+const char *
+nm_platform_addr_flags2str (unsigned flags, char *buf, gsize len)
+{
+ static const NMUtilsFlags2StrDesc descs[] = {
+ NM_UTILS_FLAGS2STR (IFA_F_SECONDARY, "secondary"),
+ NM_UTILS_FLAGS2STR (IFA_F_NODAD, "nodad"),
+ NM_UTILS_FLAGS2STR (IFA_F_OPTIMISTIC, "optimistic"),
+ NM_UTILS_FLAGS2STR (IFA_F_HOMEADDRESS, "homeaddress"),
+ NM_UTILS_FLAGS2STR (IFA_F_DEPRECATED, "deprecated"),
+ NM_UTILS_FLAGS2STR (IFA_F_TENTATIVE, "tentative"),
+ NM_UTILS_FLAGS2STR (IFA_F_PERMANENT, "permanent"),
+ NM_UTILS_FLAGS2STR (IFA_F_MANAGETEMPADDR, "mngtmpaddr"),
+ NM_UTILS_FLAGS2STR (IFA_F_NOPREFIXROUTE, "noprefixroute"),
+ };
+ return nm_utils_flags2str (descs, G_N_ELEMENTS (descs), flags, buf, len);
+};
+
+const char *
+nm_platform_route_scope2str (int scope, char *buf, gsize len)
+{
+ nm_utils_to_string_buffer_init (&buf, &len);
- if (has_other_unknown_flags)
- g_strlcat (buf, ",", size);
+ switch (scope) {
+ case 255:
+ g_snprintf (buf, len, "nowhere");
+ break;
+ case 254:
+ g_snprintf (buf, len, "host");
+ break;
+ case 200:
+ g_snprintf (buf, len, "site");
+ break;
+ case 0:
+ g_snprintf (buf, len, "global");
+ break;
+ default:
+ g_snprintf (buf, len, "%d", scope);
+ break;
}
+ return buf;
}
/**
* nm_platform_ip6_address_to_string:
* @route: pointer to NMPlatformIP6Address address structure
+ * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used.
+ * @len: the size of the @buf. If @buf is %NULL, this argument is ignored.
*
* A method for converting an address struct into a string representation.
*
* Example output: "2001:db8:0:f101::1/64 lft 4294967295 pref 4294967295 time 16922666 on dev em1"
*
- * Returns: a string representation of the address. The returned string
- * is an internal buffer, so do not keep or free the returned string.
- * Also, this function is not thread safe.
+ * Returns: a string representation of the address.
*/
const char *
-nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address)
+nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len)
{
#define S_FLAGS_PREFIX " flags "
char s_flags[256];
@@ -2606,7 +3063,8 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address)
const char *str_lft_p, *str_pref_p, *str_time_p;
gint32 now = nm_utils_get_monotonic_timestamp_s ();
- g_return_val_if_fail (address, "(unknown)");
+ if (!nm_utils_to_string_buffer_init_null (address, &buf, &len))
+ return buf;
inet_ntop (AF_INET6, &address->address, s_address, sizeof (s_address));
@@ -2633,44 +3091,46 @@ nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address)
now, str_pref, sizeof (str_pref)) );
str_time_p = _lifetime_summary_to_string (now, address->timestamp, address->preferred, address->lifetime, str_time, sizeof (str_time));
- g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer), "%s/%d lft %s pref %s%s%s%s%s src %s",
+ g_snprintf (buf, len,
+ "%s/%d lft %s pref %s%s%s%s%s src %s",
s_address, address->plen, str_lft_p, str_pref_p, str_time_p,
str_peer ? str_peer : "",
str_dev,
s_flags,
source_to_string (address->source));
g_free (str_peer);
- return _nm_platform_to_string_buffer;
+ return buf;
}
/**
* nm_platform_ip4_route_to_string:
* @route: pointer to NMPlatformIP4Route route structure
+ * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used.
+ * @len: the size of the @buf. If @buf is %NULL, this argument is ignored.
*
* A method for converting a route struct into a string representation.
*
* Example output: "192.168.1.0/24 via 0.0.0.0 dev em1 metric 0 mss 0"
*
- * Returns: a string representation of the route. The returned string
- * is an internal buffer, so do not keep or free the returned string.
- * Also, this function is not thread safe.
+ * Returns: a string representation of the route.
*/
const char *
-nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route)
+nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len)
{
char s_network[INET_ADDRSTRLEN], s_gateway[INET_ADDRSTRLEN];
char s_pref_src[INET_ADDRSTRLEN];
char str_dev[TO_STRING_DEV_BUF_SIZE];
char str_scope[30];
- g_return_val_if_fail (route, "(unknown)");
+ if (!nm_utils_to_string_buffer_init_null (route, &buf, &len))
+ return buf;
inet_ntop (AF_INET, &route->network, s_network, sizeof(s_network));
inet_ntop (AF_INET, &route->gateway, s_gateway, sizeof(s_gateway));
_to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev));
- g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer),
+ g_snprintf (buf, len,
"%s/%d"
" via %s"
"%s"
@@ -2687,38 +3147,39 @@ nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route)
route->mss,
source_to_string (route->source),
route->scope_inv ? " scope " : "",
- route->scope_inv ? (rtnl_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "",
+ route->scope_inv ? (nm_platform_route_scope2str (nm_platform_route_scope_inv (route->scope_inv), str_scope, sizeof (str_scope))) : "",
route->pref_src ? " pref-src " : "",
route->pref_src ? inet_ntop (AF_INET, &route->pref_src, s_pref_src, sizeof(s_pref_src)) : "");
- return _nm_platform_to_string_buffer;
+ return buf;
}
/**
* nm_platform_ip6_route_to_string:
* @route: pointer to NMPlatformIP6Route route structure
+ * @buf: (allow-none): an optional buffer. If %NULL, a static buffer is used.
+ * @len: the size of the @buf. If @buf is %NULL, this argument is ignored.
*
* A method for converting a route struct into a string representation.
*
* Example output: "ff02::fb/128 via :: dev em1 metric 0"
*
- * Returns: a string representation of the route. The returned string
- * is an internal buffer, so do not keep or free the returned string.
- * Also, this function is not thread safe.
+ * Returns: a string representation of the route.
*/
const char *
-nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route)
+nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len)
{
char s_network[INET6_ADDRSTRLEN], s_gateway[INET6_ADDRSTRLEN];
char str_dev[TO_STRING_DEV_BUF_SIZE];
- g_return_val_if_fail (route, "(unknown)");
+ if (!nm_utils_to_string_buffer_init_null (route, &buf, &len))
+ return buf;
inet_ntop (AF_INET6, &route->network, s_network, sizeof(s_network));
inet_ntop (AF_INET6, &route->gateway, s_gateway, sizeof(s_gateway));
_to_string_dev (NULL, route->ifindex, str_dev, sizeof (str_dev));
- g_snprintf (_nm_platform_to_string_buffer, sizeof (_nm_platform_to_string_buffer),
+ g_snprintf (buf, len,
"%s/%d"
" via %s"
"%s"
@@ -2732,7 +3193,7 @@ nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route)
route->metric,
route->mss,
source_to_string (route->source));
- return _nm_platform_to_string_buffer;
+ return buf;
}
#define _CMP_SELF(a, b) \
@@ -2819,7 +3280,6 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
_CMP_FIELD_STR (a, b, name);
_CMP_FIELD (a, b, master);
_CMP_FIELD (a, b, parent);
- _CMP_FIELD (a, b, vlan_id);
_CMP_FIELD (a, b, flags);
_CMP_FIELD (a, b, connected);
_CMP_FIELD (a, b, mtu);
@@ -2838,22 +3298,83 @@ nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b)
}
int
-nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b)
+nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b)
+{
+ _CMP_SELF (a, b);
+ _CMP_FIELD (a, b, parent_ifindex);
+ _CMP_FIELD (a, b, input_flags);
+ _CMP_FIELD (a, b, output_flags);
+ _CMP_FIELD (a, b, input_key);
+ _CMP_FIELD (a, b, output_key);
+ _CMP_FIELD (a, b, local);
+ _CMP_FIELD (a, b, remote);
+ _CMP_FIELD (a, b, ttl);
+ _CMP_FIELD (a, b, tos);
+ _CMP_FIELD_BOOL (a, b, path_mtu_discovery);
+ return 0;
+}
+
+int
+nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b)
+{
+ _CMP_SELF (a, b);
+ _CMP_FIELD (a, b, p_key);
+ _CMP_FIELD_STR_INTERNED (a, b, mode);
+ return 0;
+}
+
+int
+nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b)
+{
+ _CMP_SELF (a, b);
+ _CMP_FIELD_STR_INTERNED (a, b, mode);
+ _CMP_FIELD_BOOL (a, b, no_promisc);
+ return 0;
+}
+
+int
+nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b)
+{
+ _CMP_SELF (a, b);
+ _CMP_FIELD (a, b, id);
+ _CMP_FIELD (a, b, flags);
+ return 0;
+}
+
+int
+nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b)
{
- in_addr_t p_a, p_b;
+ _CMP_SELF (a, b);
+ _CMP_FIELD (a, b, parent_ifindex);
+ _CMP_FIELD (a, b, id);
+ _CMP_FIELD (a, b, group);
+ _CMP_FIELD (a, b, local);
+ _CMP_FIELD_MEMCMP (a, b, group6);
+ _CMP_FIELD_MEMCMP (a, b, local6);
+ _CMP_FIELD (a, b, tos);
+ _CMP_FIELD (a, b, ttl);
+ _CMP_FIELD_BOOL (a, b, learning);
+ _CMP_FIELD (a, b, ageing);
+ _CMP_FIELD (a, b, limit);
+ _CMP_FIELD (a, b, dst_port);
+ _CMP_FIELD (a, b, src_port_min);
+ _CMP_FIELD (a, b, src_port_max);
+ _CMP_FIELD_BOOL (a, b, proxy);
+ _CMP_FIELD_BOOL (a, b, rsc);
+ _CMP_FIELD_BOOL (a, b, l2miss);
+ _CMP_FIELD_BOOL (a, b, l3miss);
+ return 0;
+}
+int
+nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b)
+{
_CMP_SELF (a, b);
_CMP_FIELD (a, b, ifindex);
_CMP_FIELD (a, b, source);
_CMP_FIELD (a, b, address);
_CMP_FIELD (a, b, plen);
-
- /* a peer-address of zero is the same as setting it to address.
- * Here we consider the full address, including the host-part. */
- p_a = nm_platform_ip4_address_get_peer (a);
- p_b = nm_platform_ip4_address_get_peer (b);
- _CMP_DIRECT (p_a, p_b);
-
+ _CMP_FIELD (a, b, peer_address);
_CMP_FIELD (a, b, timestamp);
_CMP_FIELD (a, b, lifetime);
_CMP_FIELD (a, b, preferred);
@@ -2983,31 +3504,31 @@ static void
log_link (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformLink *device, NMPlatformSignalChangeType change_type, gpointer user_data)
{
- _LOGD ("signal: link %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_link_to_string (device));
+ _LOGD ("signal: link %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_link_to_string (device, NULL, 0));
}
static void
log_ip4_address (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP4Address *address, NMPlatformSignalChangeType change_type, gpointer user_data)
{
- _LOGD ("signal: address 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_address_to_string (address));
+ _LOGD ("signal: address 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_address_to_string (address, NULL, 0));
}
static void
log_ip6_address (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP6Address *address, NMPlatformSignalChangeType change_type, gpointer user_data)
{
- _LOGD ("signal: address 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_address_to_string (address));
+ _LOGD ("signal: address 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_address_to_string (address, NULL, 0));
}
static void
log_ip4_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP4Route *route, NMPlatformSignalChangeType change_type, gpointer user_data)
{
- _LOGD ("signal: route 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_route_to_string (route));
+ _LOGD ("signal: route 4 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip4_route_to_string (route, NULL, 0));
}
static void
log_ip6_route (NMPlatform *self, NMPObjectType obj_type, int ifindex, NMPlatformIP6Route *route, NMPlatformSignalChangeType change_type, gpointer user_data)
{
- _LOGD ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route));
+ _LOGD ("signal: route 6 %7s: %s", nm_platform_signal_change_type_to_string (change_type), nm_platform_ip6_route_to_string (route, NULL, 0));
}
/******************************************************************/
@@ -3084,7 +3605,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v4 = {
.addr_family = AF_INET,
.sizeof_route = sizeof (NMPlatformIP4Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip4_route_cmp,
- .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route)) nm_platform_ip4_route_to_string,
+ .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip4_route_to_string,
.route_get_all = nm_platform_ip4_route_get_all,
.route_add = _vtr_v4_route_add,
.route_delete = _vtr_v4_route_delete,
@@ -3097,7 +3618,7 @@ const NMPlatformVTableRoute nm_platform_vtable_route_v6 = {
.addr_family = AF_INET6,
.sizeof_route = sizeof (NMPlatformIP6Route),
.route_cmp = (int (*) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b)) nm_platform_ip6_route_cmp,
- .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route)) nm_platform_ip6_route_to_string,
+ .route_to_string = (const char *(*) (const NMPlatformIPXRoute *route, char *buf, gsize len)) nm_platform_ip6_route_to_string,
.route_get_all = nm_platform_ip6_route_get_all,
.route_add = _vtr_v6_route_add,
.route_delete = _vtr_v6_route_delete,
diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h
index f7c44d4eb6..42c3b79390 100644
--- a/src/platform/nm-platform.h
+++ b/src/platform/nm-platform.h
@@ -25,9 +25,11 @@
#include <linux/if.h>
#include <linux/if_addr.h>
-#include <nm-dbus-interface.h>
+#include "nm-dbus-interface.h"
#include "nm-default.h"
#include "NetworkManagerUtils.h"
+#include "nm-setting-vlan.h"
+#include "nm-core-types-internal.h"
#define NM_TYPE_PLATFORM (nm_platform_get_type ())
#define NM_PLATFORM(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), NM_TYPE_PLATFORM, NMPlatform))
@@ -52,6 +54,13 @@ typedef struct _NMPlatform NMPlatform;
#define IFA_F_NOPREFIXROUTE 0x200
#endif
+/* Define of the IN6_ADDR_GEN_MODE_* values to workaround old kernel headers
+ * that don't define it. */
+#define NM_IN6_ADDR_GEN_MODE_UNKNOWN 255 /* no corresponding value. */
+#define NM_IN6_ADDR_GEN_MODE_EUI64 0 /* IN6_ADDR_GEN_MODE_EUI64 */
+#define NM_IN6_ADDR_GEN_MODE_NONE 1 /* IN6_ADDR_GEN_MODE_NONE */
+#define NM_IN6_ADDR_GEN_MODE_STABLE_PRIVACY 2 /* IN6_ADDR_GEN_MODE_STABLE_PRIVACY */
+
typedef enum { /*< skip >*/
/* dummy value, to enforce that the enum type is signed and has a size
@@ -85,6 +94,19 @@ typedef enum {
_NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL,
} NMPlatformReason;
+
+typedef struct {
+ union {
+ guint8 addr_ptr[1];
+ in_addr_t addr4;
+ struct in6_addr addr6;
+ };
+} NMIPAddr;
+
+extern const NMIPAddr nm_ip_addr_zero;
+
+#define NMIPAddrInit { .addr6 = IN6ADDR_ANY_INIT }
+
#define NM_PLATFORM_LINK_OTHER_NETNS (-1)
#define __NMPlatformObject_COMMON \
@@ -131,9 +153,6 @@ struct _NMPlatformLink {
* initialized with memset(0) has and unset value.*/
guint8 inet6_addr_gen_mode_inv;
- /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */
- guint16 vlan_id;
-
/* IFF_* flags as u32. Note that ifi_flags in 'struct ifinfomsg' is declared as 'unsigned',
* but libnl stores the flag internally as u32. */
guint32 flags;
@@ -218,8 +237,21 @@ typedef struct {
**/
struct _NMPlatformIP4Address {
__NMPlatformIPAddress_COMMON;
+
+ /* The local address IFA_LOCAL. */
in_addr_t address;
+
+ /* The IFA_ADDRESS PTP peer address. This field is rather important, because
+ * it constitutes the identifier for the IPv4 address (e.g. you can add two
+ * addresses that only differ by their peer's network-part.
+ *
+ * Beware that for most cases, NetworkManager doesn't want to set an explicit
+ * peer-address. Hoever, that corresponds to setting the peer address to @address
+ * itself. Leaving peer-address unset/zero, means explicitly setting the peer
+ * address to 0.0.0.0, which you probably don't want.
+ * */
in_addr_t peer_address; /* PTP peer address */
+
char label[IFNAMSIZ];
};
@@ -313,7 +345,7 @@ typedef struct {
int addr_family;
gsize sizeof_route;
int (*route_cmp) (const NMPlatformIPXRoute *a, const NMPlatformIPXRoute *b);
- const char *(*route_to_string) (const NMPlatformIPXRoute *route);
+ const char *(*route_to_string) (const NMPlatformIPXRoute *route, char *buf, gsize len);
GArray *(*route_get_all) (NMPlatform *self, int ifindex, NMPlatformGetRouteFlags flags);
gboolean (*route_add) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route, gint64 metric);
gboolean (*route_delete) (NMPlatform *self, int ifindex, const NMPlatformIPXRoute *route);
@@ -324,26 +356,34 @@ typedef struct {
extern const NMPlatformVTableRoute nm_platform_vtable_route_v4;
extern const NMPlatformVTableRoute nm_platform_vtable_route_v6;
-extern char _nm_platform_to_string_buffer[256];
-
typedef struct {
- int peer;
-} NMPlatformVethProperties;
+ int parent_ifindex;
+ guint16 input_flags;
+ guint16 output_flags;
+ guint32 input_key;
+ guint32 output_key;
+ in_addr_t local;
+ in_addr_t remote;
+ guint8 ttl;
+ guint8 tos;
+ gboolean path_mtu_discovery;
+} NMPlatformLnkGre;
typedef struct {
- gint64 owner;
- gint64 group;
+ int p_key;
const char *mode;
- gboolean no_pi;
- gboolean vnet_hdr;
- gboolean multi_queue;
-} NMPlatformTunProperties;
+} NMPlatformLnkInfiniband;
typedef struct {
- int parent_ifindex;
const char *mode;
gboolean no_promisc;
-} NMPlatformMacvlanProperties;
+} NMPlatformLnkMacvlan;
+
+typedef struct {
+ /* rtnl_link_vlan_get_id(), IFLA_VLAN_ID */
+ guint16 id;
+ NMVlanFlags flags;
+} NMPlatformLnkVlan;
typedef struct {
int parent_ifindex;
@@ -364,20 +404,16 @@ typedef struct {
gboolean rsc;
gboolean l2miss;
gboolean l3miss;
-} NMPlatformVxlanProperties;
+} NMPlatformLnkVxlan;
typedef struct {
- int parent_ifindex;
- guint16 input_flags;
- guint16 output_flags;
- guint32 input_key;
- guint32 output_key;
- in_addr_t local;
- in_addr_t remote;
- guint8 ttl;
- guint8 tos;
- gboolean path_mtu_discovery;
-} NMPlatformGreProperties;
+ gint64 owner;
+ gint64 group;
+ const char *mode;
+ gboolean no_pi;
+ gboolean vnet_hdr;
+ gboolean multi_queue;
+} NMPlatformTunProperties;
/******************************************************************/
@@ -423,6 +459,8 @@ typedef struct {
const NMPlatformLink *(*link_get_by_ifname) (NMPlatform *platform, const char *ifname);
const NMPlatformLink *(*link_get_by_address) (NMPlatform *platform, gconstpointer address, size_t length);
+ const NMPObject *(*link_get_lnk) (NMPlatform *platform, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link);
+
GArray *(*link_get_all) (NMPlatform *);
gboolean (*link_add) (NMPlatform *,
const char *name,
@@ -474,22 +512,18 @@ typedef struct {
char * (*slave_get_option) (NMPlatform *, int ifindex, const char *option);
gboolean (*vlan_add) (NMPlatform *, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link);
- gboolean (*vlan_get_info) (NMPlatform *, int ifindex, int *parent, int *vlan_id);
- gboolean (*vlan_set_ingress_map) (NMPlatform *, int ifindex, int from, int to);
- gboolean (*vlan_set_egress_map) (NMPlatform *, int ifindex, int from, int to);
+ gboolean (*link_vlan_change) (NMPlatform *self,
+ int ifindex,
+ NMVlanFlags flags_mask,
+ NMVlanFlags flags_set,
+ gboolean ingress_reset_all,
+ const NMVlanQosMapping *ingress_map,
+ gsize n_ingress_map,
+ gboolean egress_reset_all,
+ const NMVlanQosMapping *egress_map,
+ gsize n_egress_map);
gboolean (*infiniband_partition_add) (NMPlatform *, int parent, int p_key, NMPlatformLink *out_link);
- gboolean (*infiniband_get_info) (NMPlatform *,
- int ifindex,
- int *parent,
- int *p_key,
- const char **mode);
-
- gboolean (*veth_get_properties) (NMPlatform *, int ifindex, NMPlatformVethProperties *properties);
- gboolean (*tun_get_properties) (NMPlatform *, int ifindex, NMPlatformTunProperties *properties);
- gboolean (*macvlan_get_properties) (NMPlatform *, int ifindex, NMPlatformMacvlanProperties *props);
- gboolean (*vxlan_get_properties) (NMPlatform *, int ifindex, NMPlatformVxlanProperties *props);
- gboolean (*gre_get_properties) (NMPlatform *, int ifindex, NMPlatformGreProperties *props);
gboolean (*wifi_get_capabilities) (NMPlatform *, int ifindex, NMDeviceWifiCapabilities *caps);
gboolean (*wifi_get_bssid) (NMPlatform *, int ifindex, guint8 *bssid);
@@ -672,19 +706,35 @@ char *nm_platform_master_get_option (NMPlatform *self, int ifindex, const char *
gboolean nm_platform_slave_set_option (NMPlatform *self, int ifindex, const char *option, const char *value);
char *nm_platform_slave_get_option (NMPlatform *self, int ifindex, const char *option);
+const NMPObject *nm_platform_link_get_lnk (NMPlatform *self, int ifindex, NMLinkType link_type, const NMPlatformLink **out_link);
+const NMPlatformLnkGre *nm_platform_link_get_lnk_gre (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkInfiniband *nm_platform_link_get_lnk_infiniband (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkMacvlan *nm_platform_link_get_lnk_macvlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkVlan *nm_platform_link_get_lnk_vlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+const NMPlatformLnkVxlan *nm_platform_link_get_lnk_vxlan (NMPlatform *self, int ifindex, const NMPlatformLink **out_link);
+
NMPlatformError nm_platform_vlan_add (NMPlatform *self, const char *name, int parent, int vlanid, guint32 vlanflags, NMPlatformLink *out_link);
-gboolean nm_platform_vlan_get_info (NMPlatform *self, int ifindex, int *parent, int *vlanid);
gboolean nm_platform_vlan_set_ingress_map (NMPlatform *self, int ifindex, int from, int to);
gboolean nm_platform_vlan_set_egress_map (NMPlatform *self, int ifindex, int from, int to);
+gboolean nm_platform_link_vlan_change (NMPlatform *self,
+ int ifindex,
+ NMVlanFlags flags_mask,
+ NMVlanFlags flags_set,
+ gboolean ingress_reset_all,
+ const NMVlanQosMapping *ingress_map,
+ gsize n_ingress_map,
+ gboolean egress_reset_all,
+ const NMVlanQosMapping *egress_map,
+ gsize n_egress_map);
+
NMPlatformError nm_platform_infiniband_partition_add (NMPlatform *self, int parent, int p_key, NMPlatformLink *out_link);
-gboolean nm_platform_infiniband_get_info (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode);
+gboolean nm_platform_infiniband_get_properties (NMPlatform *self, int ifindex, int *parent, int *p_key, const char **mode);
-gboolean nm_platform_veth_get_properties (NMPlatform *self, int ifindex, NMPlatformVethProperties *properties);
+gboolean nm_platform_veth_get_properties (NMPlatform *self, int ifindex, int *out_peer_ifindex);
gboolean nm_platform_tun_get_properties (NMPlatform *self, int ifindex, NMPlatformTunProperties *properties);
-gboolean nm_platform_macvlan_get_properties (NMPlatform *self, int ifindex, NMPlatformMacvlanProperties *props);
-gboolean nm_platform_vxlan_get_properties (NMPlatform *self, int ifindex, NMPlatformVxlanProperties *props);
-gboolean nm_platform_gre_get_properties (NMPlatform *self, int ifindex, NMPlatformGreProperties *props);
+
+gboolean nm_platform_tun_get_properties_ifname (NMPlatform *platform, const char *ifname, NMPlatformTunProperties *props);
gboolean nm_platform_wifi_get_capabilities (NMPlatform *self, int ifindex, NMDeviceWifiCapabilities *caps);
gboolean nm_platform_wifi_get_bssid (NMPlatform *self, int ifindex, guint8 *bssid);
@@ -701,10 +751,8 @@ guint32 nm_platform_mesh_get_channel (NMPlatform *self, int ifindex);
gboolean nm_platform_mesh_set_channel (NMPlatform *self, int ifindex, guint32 channel);
gboolean nm_platform_mesh_set_ssid (NMPlatform *self, int ifindex, const guint8 *ssid, gsize len);
-in_addr_t nm_platform_ip4_address_get_peer (const NMPlatformIP4Address *addr);
+void nm_platform_ip4_address_set_addr (NMPlatformIP4Address *addr, in_addr_t address, int plen);
const struct in6_addr *nm_platform_ip6_address_get_peer (const NMPlatformIP6Address *addr);
-in_addr_t nm_platform_ip4_address_get_peer_net (const NMPlatformIP4Address *addr);
-gboolean nm_platform_ip4_address_equal_peer_net (const NMPlatformIP4Address *addr1, const NMPlatformIP4Address *addr2);
const NMPlatformIP4Address *nm_platform_ip4_address_get (NMPlatform *self, int ifindex, in_addr_t address, int plen, in_addr_t peer_address);
const NMPlatformIP6Address *nm_platform_ip6_address_get (NMPlatform *self, int ifindex, struct in6_addr address, int plen);
@@ -745,24 +793,41 @@ gboolean nm_platform_ip6_route_add (NMPlatform *self, int ifindex, NMIPConfigSou
gboolean nm_platform_ip4_route_delete (NMPlatform *self, int ifindex, in_addr_t network, int plen, guint32 metric);
gboolean nm_platform_ip6_route_delete (NMPlatform *self, int ifindex, struct in6_addr network, int plen, guint32 metric);
-const char *nm_platform_link_to_string (const NMPlatformLink *link);
-const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address);
-const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address);
-const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route);
-const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route);
+const char *nm_platform_link_to_string (const NMPlatformLink *link, char *buf, gsize len);
+const char *nm_platform_lnk_gre_to_string (const NMPlatformLnkGre *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_infiniband_to_string (const NMPlatformLnkInfiniband *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_macvlan_to_string (const NMPlatformLnkMacvlan *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_vlan_to_string (const NMPlatformLnkVlan *lnk, char *buf, gsize len);
+const char *nm_platform_lnk_vxlan_to_string (const NMPlatformLnkVxlan *lnk, char *buf, gsize len);
+const char *nm_platform_ip4_address_to_string (const NMPlatformIP4Address *address, char *buf, gsize len);
+const char *nm_platform_ip6_address_to_string (const NMPlatformIP6Address *address, char *buf, gsize len);
+const char *nm_platform_ip4_route_to_string (const NMPlatformIP4Route *route, char *buf, gsize len);
+const char *nm_platform_ip6_route_to_string (const NMPlatformIP6Route *route, char *buf, gsize len);
+
+const char *nm_platform_vlan_qos_mapping_to_string (const char *name,
+ const NMVlanQosMapping *map,
+ gsize n_map,
+ char *buf,
+ gsize len);
int nm_platform_link_cmp (const NMPlatformLink *a, const NMPlatformLink *b);
+int nm_platform_lnk_gre_cmp (const NMPlatformLnkGre *a, const NMPlatformLnkGre *b);
+int nm_platform_lnk_infiniband_cmp (const NMPlatformLnkInfiniband *a, const NMPlatformLnkInfiniband *b);
+int nm_platform_lnk_macvlan_cmp (const NMPlatformLnkMacvlan *a, const NMPlatformLnkMacvlan *b);
+int nm_platform_lnk_vlan_cmp (const NMPlatformLnkVlan *a, const NMPlatformLnkVlan *b);
+int nm_platform_lnk_vxlan_cmp (const NMPlatformLnkVxlan *a, const NMPlatformLnkVxlan *b);
int nm_platform_ip4_address_cmp (const NMPlatformIP4Address *a, const NMPlatformIP4Address *b);
int nm_platform_ip6_address_cmp (const NMPlatformIP6Address *a, const NMPlatformIP6Address *b);
int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4Route *b);
int nm_platform_ip6_route_cmp (const NMPlatformIP6Route *a, const NMPlatformIP6Route *b);
-gboolean nm_platform_check_support_libnl_extended_ifa_flags (void);
-gboolean nm_platform_check_support_libnl_link_netnsid (void);
gboolean nm_platform_check_support_kernel_extended_ifa_flags (NMPlatform *self);
gboolean nm_platform_check_support_user_ipv6ll (NMPlatform *self);
-void nm_platform_addr_flags2str (int flags, char *buf, size_t size);
+const char *nm_platform_link_flags2str (unsigned flags, char *buf, gsize len);
+const char *nm_platform_link_inet6_addrgenmode2str (guint8 mode, char *buf, gsize len);
+const char *nm_platform_addr_flags2str (unsigned flags, char *buf, gsize len);
+const char *nm_platform_route_scope2str (int scope, char *buf, gsize len);
int nm_platform_ip_address_cmp_expiry (const NMPlatformIPAddress *a, const NMPlatformIPAddress *b);
diff --git a/src/platform/nmp-object.c b/src/platform/nmp-object.c
index a8264827be..fbdc88771c 100644
--- a/src/platform/nmp-object.c
+++ b/src/platform/nmp-object.c
@@ -82,6 +82,42 @@ _id_hash_ip6_addr (const struct in6_addr *addr)
return hash;
}
+static int
+_vlan_xgress_qos_mappings_cmp (guint n_map,
+ const NMVlanQosMapping *map1,
+ const NMVlanQosMapping *map2)
+{
+ guint i;
+
+ for (i = 0; i < n_map; i++) {
+ if (map1[i].from != map2[i].from)
+ return map1[i].from < map2[i].from ? -1 : 1;
+ if (map1[i].to != map2[i].to)
+ return map1[i].to < map2[i].to ? -1 : 1;
+ }
+ return 0;
+}
+
+static void
+_vlan_xgress_qos_mappings_cpy (guint *dst_n_map,
+ const NMVlanQosMapping **dst_map,
+ guint src_n_map,
+ const NMVlanQosMapping *src_map)
+{
+ if (src_n_map == 0) {
+ g_clear_pointer (dst_map, g_free);
+ *dst_n_map = 0;
+ } else if ( src_n_map != *dst_n_map
+ || _vlan_xgress_qos_mappings_cmp (src_n_map, *dst_map, src_map) != 0) {
+ g_clear_pointer (dst_map, g_free);
+ *dst_n_map = src_n_map;
+ if (src_n_map > 0)
+ *dst_map = g_memdup (src_map, sizeof (*src_map) * src_n_map);
+ }
+}
+
+/******************************************************************/
+
static const char *
_link_get_driver (GUdevDevice *udev_device, const char *kind, const char *ifname)
{
@@ -207,6 +243,14 @@ static void
_vt_cmd_obj_dispose_link (NMPObject *obj)
{
g_clear_object (&obj->_link.udev.device);
+ nmp_object_unref (obj->_link.netlink.lnk);
+}
+
+static void
+_vt_cmd_obj_dispose_lnk_vlan (NMPObject *obj)
+{
+ g_free ((gpointer) obj->_lnk_vlan.ingress_qos_map);
+ g_free ((gpointer) obj->_lnk_vlan.egress_qos_map);
}
static NMPObject *
@@ -274,10 +318,16 @@ nmp_object_stackinit (NMPObject *obj, NMPObjectType obj_type, const NMPlatformOb
const NMPObject *
nmp_object_stackinit_id (NMPObject *obj, const NMPObject *src)
{
+ const NMPClass *klass;
+
nm_assert (NMP_OBJECT_IS_VALID (src));
nm_assert (obj);
- NMP_OBJECT_GET_CLASS (src)->cmd_obj_stackinit_id (obj, src);
+ klass = NMP_OBJECT_GET_CLASS (src);
+ if (!klass->cmd_obj_stackinit_id)
+ nmp_object_stackinit (obj, klass->obj_type, NULL);
+ else
+ klass->cmd_obj_stackinit_id (obj, src);
return obj;
}
@@ -370,50 +420,131 @@ const char *
nmp_object_to_string (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size)
{
const NMPClass *klass;
- char buf2[sizeof (_nm_platform_to_string_buffer)];
- char buf3[sizeof (_nm_platform_to_string_buffer)];
- const char *str;
-
- if (!buf) {
- buf = _nm_platform_to_string_buffer;
- buf_size = sizeof (_nm_platform_to_string_buffer);
- }
+ char buf2[sizeof (_nm_utils_to_string_buffer)];
- if (!obj) {
- g_strlcpy (buf, "NULL", buf_size);
+ if (!nm_utils_to_string_buffer_init_null (obj, &buf, &buf_size))
return buf;
- }
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), NULL);
klass = NMP_OBJECT_GET_CLASS (obj);
+ if (klass->cmd_obj_to_string)
+ return klass->cmd_obj_to_string (obj, to_string_mode, buf, buf_size);
+
switch (to_string_mode) {
case NMP_OBJECT_TO_STRING_ID:
+ if (!klass->cmd_plobj_to_string_id) {
+ g_snprintf (buf, buf_size, "%p", obj);
+ return buf;
+ }
return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size);
case NMP_OBJECT_TO_STRING_ALL:
- g_strlcpy (buf2, NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object), sizeof (buf2));
+ g_snprintf (buf, buf_size,
+ "[%s,%p,%d,%ccache,%calive,%cvisible; %s]",
+ klass->obj_type_name, obj, obj->_ref_count,
+ obj->is_cached ? '+' : '-',
+ nmp_object_is_alive (obj) ? '+' : '-',
+ nmp_object_is_visible (obj) ? '+' : '-',
+ NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2)));
+ return buf;
+ case NMP_OBJECT_TO_STRING_PUBLIC:
+ NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size);
+ return buf;
+ default:
+ g_return_val_if_reached ("ERROR");
+ }
+}
- if (NMP_OBJECT_GET_TYPE (obj) == NMP_OBJECT_TYPE_LINK) {
- g_snprintf (buf3, sizeof (buf3),
- ",%cin-nl,%p",
- obj->_link.netlink.is_in_netlink ? '+' : '-',
- obj->_link.udev.device);
+static const char *
+_vt_cmd_obj_to_string_link (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size)
+{
+ const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj);
+ char buf2[sizeof (_nm_utils_to_string_buffer)];
+ char buf3[sizeof (_nm_utils_to_string_buffer)];
+
+ switch (to_string_mode) {
+ case NMP_OBJECT_TO_STRING_ID:
+ return klass->cmd_plobj_to_string_id (&obj->object, buf, buf_size);
+ case NMP_OBJECT_TO_STRING_ALL:
+ g_snprintf (buf, buf_size,
+ "[%s,%p,%d,%ccache,%calive,%cvisible,%cin-nl,%p; %s]",
+ klass->obj_type_name, obj, obj->_ref_count,
+ obj->is_cached ? '+' : '-',
+ nmp_object_is_alive (obj) ? '+' : '-',
+ nmp_object_is_visible (obj) ? '+' : '-',
+ obj->_link.netlink.is_in_netlink ? '+' : '-',
+ obj->_link.udev.device,
+ nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)));
+ return buf;
+ case NMP_OBJECT_TO_STRING_PUBLIC:
+ if (obj->_link.netlink.lnk) {
+ NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf2, sizeof (buf2));
+ nmp_object_to_string (obj->_link.netlink.lnk, NMP_OBJECT_TO_STRING_PUBLIC, buf3, sizeof (buf3));
+ g_snprintf (buf, buf_size,
+ "%s; %s",
+ buf2, buf3);
} else
- buf3[0] = '\0';
+ NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size);
+ return buf;
+ default:
+ g_return_val_if_reached ("ERROR");
+ }
+}
+
+static const char *
+_vt_cmd_obj_to_string_lnk_vlan (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size)
+{
+ const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj);
+ char buf2[sizeof (_nm_utils_to_string_buffer)];
+ char *b;
+ gsize l;
+
+ klass = NMP_OBJECT_GET_CLASS (obj);
+
+ switch (to_string_mode) {
+ case NMP_OBJECT_TO_STRING_ID:
+ g_snprintf (buf, buf_size, "%p", obj);
+ return buf;
+ case NMP_OBJECT_TO_STRING_ALL:
g_snprintf (buf, buf_size,
- "[%s,%p,%d,%ccache,%calive,%cvisible%s; %s]",
+ "[%s,%p,%d,%ccache,%calive,%cvisible; %s]",
klass->obj_type_name, obj, obj->_ref_count,
obj->is_cached ? '+' : '-',
nmp_object_is_alive (obj) ? '+' : '-',
nmp_object_is_visible (obj) ? '+' : '-',
- buf3, buf2);
+ nmp_object_to_string (obj, NMP_OBJECT_TO_STRING_PUBLIC, buf2, sizeof (buf2)));
return buf;
case NMP_OBJECT_TO_STRING_PUBLIC:
- str = NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object);
- if (str != buf)
- g_strlcpy (buf, str, buf_size);
+ NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_string (&obj->object, buf, buf_size);
+
+ b = buf;
+ l = strlen (b);
+ b += l;
+ buf_size -= l;
+
+ if (obj->_lnk_vlan.n_ingress_qos_map) {
+ nm_platform_vlan_qos_mapping_to_string (" ingress-qos-map",
+ obj->_lnk_vlan.ingress_qos_map,
+ obj->_lnk_vlan.n_ingress_qos_map,
+ b,
+ buf_size);
+ l = strlen (b);
+ b += l;
+ buf_size -= l;
+ }
+ if (obj->_lnk_vlan.n_egress_qos_map) {
+ nm_platform_vlan_qos_mapping_to_string (" egress-qos-map",
+ obj->_lnk_vlan.egress_qos_map,
+ obj->_lnk_vlan.n_egress_qos_map,
+ b,
+ buf_size);
+ l = strlen (b);
+ b += l;
+ buf_size -= l;
+ }
+
return buf;
default:
g_return_val_if_reached ("ERROR");
@@ -436,8 +567,8 @@ _vt_cmd_plobj_to_string_id_##type (const NMPlatformObject *_obj, char *buf, gsiz
}
_vt_cmd_plobj_to_string_id (link, NMPlatformLink, "%d", obj->ifindex);
_vt_cmd_plobj_to_string_id (ip4_address, NMPlatformIP4Address, "%d: %s/%d%s%s", obj->ifindex, nm_utils_inet4_ntop ( obj->address, buf1), obj->plen,
- obj->peer_address && obj->peer_address != obj->address ? "," : "",
- obj->peer_address && obj->peer_address != obj->address ? nm_utils_inet4_ntop (nm_platform_ip4_address_get_peer_net (obj), buf2) : "");
+ obj->peer_address != obj->address ? "," : "",
+ obj->peer_address != obj->address ? nm_utils_inet4_ntop (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen), buf2) : "");
_vt_cmd_plobj_to_string_id (ip6_address, NMPlatformIP6Address, "%d: %s", obj->ifindex, nm_utils_inet6_ntop (&obj->address, buf1));
_vt_cmd_plobj_to_string_id (ip4_route, NMPlatformIP4Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet4_ntop ( obj->network, buf1), obj->plen, obj->metric);
_vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d", obj->ifindex, nm_utils_inet6_ntop (&obj->network, buf1), obj->plen, obj->metric);
@@ -445,6 +576,8 @@ _vt_cmd_plobj_to_string_id (ip6_route, NMPlatformIP6Route, "%d: %s/%d %d",
int
nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
{
+ const NMPClass *klass1, *klass2;
+
if (obj1 == obj2)
return 0;
if (!obj1)
@@ -455,49 +588,72 @@ nmp_object_cmp (const NMPObject *obj1, const NMPObject *obj2)
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj1), -1);
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj2), 1);
- if (NMP_OBJECT_GET_CLASS (obj1) != NMP_OBJECT_GET_CLASS (obj2))
- return NMP_OBJECT_GET_CLASS (obj1) < NMP_OBJECT_GET_CLASS (obj2) ? -1 : 1;
+ klass1 = NMP_OBJECT_GET_CLASS (obj1);
+ klass2 = NMP_OBJECT_GET_CLASS (obj2);
+
+ if (klass1 != klass2)
+ return klass1->obj_type < klass2->obj_type ? -1 : 1;
- return NMP_OBJECT_GET_CLASS (obj1)->cmd_plobj_cmp (&obj1->object, &obj2->object);
+ if (klass1->cmd_obj_cmp)
+ return klass1->cmd_obj_cmp (obj1, obj2);
+ return klass1->cmd_plobj_cmp (&obj1->object, &obj2->object);
}
-gboolean
-nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2)
+static int
+_vt_cmd_obj_cmp_link (const NMPObject *obj1, const NMPObject *obj2)
{
- const NMPClass *klass;
+ int i;
- g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj1), FALSE);
- g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj2), FALSE);
+ i = nm_platform_link_cmp (&obj1->link, &obj2->link);
+ if (i)
+ return i;
+ if (obj1->_link.netlink.is_in_netlink != obj2->_link.netlink.is_in_netlink)
+ return obj1->_link.netlink.is_in_netlink ? -1 : 1;
+ i = nmp_object_cmp (obj1->_link.netlink.lnk, obj2->_link.netlink.lnk);
+ if (i)
+ return i;
+ if (obj1->_link.udev.device != obj2->_link.udev.device) {
+ if (!obj1->_link.udev.device)
+ return -1;
+ if (!obj2->_link.udev.device)
+ return 1;
+
+ /* Only compare based on pointer values. That is ugly because it's not a
+ * stable sort order, but probably udev gives us always the same GUdevDevice
+ * instance.
+ *
+ * Have this check as very last. */
+ return (obj1->_link.udev.device < obj2->_link.udev.device) ? -1 : 1;
+ }
+ return 0;
+}
- if (obj1 == obj2)
- return TRUE;
+static int
+_vt_cmd_obj_cmp_lnk_vlan (const NMPObject *obj1, const NMPObject *obj2)
+{
+ int c;
- klass = NMP_OBJECT_GET_CLASS (obj1);
+ c = nm_platform_lnk_vlan_cmp (&obj1->lnk_vlan, &obj2->lnk_vlan);
+ if (c)
+ return c;
- if (klass != NMP_OBJECT_GET_CLASS (obj2))
- return FALSE;
+ if (obj1->_lnk_vlan.n_ingress_qos_map != obj2->_lnk_vlan.n_ingress_qos_map)
+ return obj1->_lnk_vlan.n_ingress_qos_map < obj2->_lnk_vlan.n_ingress_qos_map ? -1 : 1;
+ if (obj1->_lnk_vlan.n_egress_qos_map != obj2->_lnk_vlan.n_egress_qos_map)
+ return obj1->_lnk_vlan.n_egress_qos_map < obj2->_lnk_vlan.n_egress_qos_map ? -1 : 1;
- return klass->cmd_obj_equal (obj1, obj2);
-}
+ c = _vlan_xgress_qos_mappings_cmp (obj1->_lnk_vlan.n_ingress_qos_map, obj1->_lnk_vlan.ingress_qos_map, obj2->_lnk_vlan.ingress_qos_map);
+ if (c)
+ return c;
+ c = _vlan_xgress_qos_mappings_cmp (obj1->_lnk_vlan.n_egress_qos_map, obj1->_lnk_vlan.egress_qos_map, obj2->_lnk_vlan.egress_qos_map);
-static gboolean
-_vt_cmd_obj_equal_plain (const NMPObject *obj1, const NMPObject *obj2)
-{
- return NMP_OBJECT_GET_CLASS (obj1)->cmd_plobj_cmp (&obj1->object, &obj2->object) == 0;
+ return c;
}
-static gboolean
-_vt_cmd_obj_equal_link (const NMPObject *obj1, const NMPObject *obj2)
+gboolean
+nmp_object_equal (const NMPObject *obj1, const NMPObject *obj2)
{
- const NMPClass *klass = NMP_OBJECT_GET_CLASS (obj1);
-
- if (klass->cmd_plobj_cmp (&obj1->object, &obj2->object) != 0)
- return FALSE;
- if (obj1->_link.netlink.is_in_netlink != obj2->_link.netlink.is_in_netlink)
- return FALSE;
- if (obj1->_link.udev.device != obj2->_link.udev.device)
- return FALSE;
- return TRUE;
+ return nmp_object_cmp (obj1, obj2) == 0;
}
/* @src is a const object, which is not entirely correct for link types, where
@@ -516,13 +672,48 @@ nmp_object_copy (NMPObject *dst, const NMPObject *src, gboolean id_only)
g_return_if_fail (klass == NMP_OBJECT_GET_CLASS (src));
- if (id_only)
- klass->cmd_plobj_id_copy (&dst->object, &src->object);
- else
+ if (id_only) {
+ if (klass->cmd_plobj_id_copy)
+ klass->cmd_plobj_id_copy (&dst->object, &src->object);
+ } else if (klass->cmd_obj_copy)
klass->cmd_obj_copy (dst, src);
+ else
+ memcpy (&dst->object, &src->object, klass->sizeof_data);
}
}
+static void
+_vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src)
+{
+ if (dst->_link.udev.device != src->_link.udev.device) {
+ if (src->_link.udev.device)
+ g_object_ref (src->_link.udev.device);
+ if (dst->_link.udev.device)
+ g_object_unref (dst->_link.udev.device);
+ }
+ if (dst->_link.netlink.lnk != src->_link.netlink.lnk) {
+ if (src->_link.netlink.lnk)
+ nmp_object_ref (src->_link.netlink.lnk);
+ if (dst->_link.netlink.lnk)
+ nmp_object_unref (dst->_link.netlink.lnk);
+ }
+ dst->_link = src->_link;
+}
+
+static void
+_vt_cmd_obj_copy_lnk_vlan (NMPObject *dst, const NMPObject *src)
+{
+ dst->lnk_vlan = src->lnk_vlan;
+ _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_ingress_qos_map,
+ &dst->_lnk_vlan.ingress_qos_map,
+ src->_lnk_vlan.n_ingress_qos_map,
+ src->_lnk_vlan.ingress_qos_map);
+ _vlan_xgress_qos_mappings_cpy (&dst->_lnk_vlan.n_egress_qos_map,
+ &dst->_lnk_vlan.egress_qos_map,
+ src->_lnk_vlan.n_egress_qos_map,
+ src->_lnk_vlan.egress_qos_map);
+}
+
#define _vt_cmd_plobj_id_copy(type, plat_type, cmd) \
static void \
_vt_cmd_plobj_id_copy_##type (NMPlatformObject *_dst, const NMPlatformObject *_src) \
@@ -557,24 +748,6 @@ _vt_cmd_plobj_id_copy (ip6_route, NMPlatformIP6Route, {
dst->network = src->network;
});
-static void
-_vt_cmd_obj_copy_plain (NMPObject *dst, const NMPObject *src)
-{
- memcpy (&dst->object, &src->object, NMP_OBJECT_GET_CLASS (dst)->sizeof_data);
-}
-
-static void
-_vt_cmd_obj_copy_link (NMPObject *dst, const NMPObject *src)
-{
- if (dst->_link.udev.device != src->_link.udev.device) {
- if (dst->_link.udev.device)
- g_object_unref (dst->_link.udev.device);
- if (src->_link.udev.device)
- g_object_ref (src->_link.udev.device);
- }
- dst->_link = src->_link;
-}
-
/* Uses internally nmp_object_copy(), hence it also violates the const
* promise for @obj.
* */
@@ -608,6 +781,7 @@ nmp_object_id_equal (const NMPObject *obj1, const NMPObject *obj2)
klass = NMP_OBJECT_GET_CLASS (obj1);
return klass == NMP_OBJECT_GET_CLASS (obj2)
+ && klass->cmd_plobj_id_equal
&& klass->cmd_plobj_id_equal (&obj1->object, &obj2->object);
}
@@ -627,7 +801,7 @@ _vt_cmd_plobj_id_equal (ip4_address, NMPlatformIP4Address,
&& obj1->address == obj2->address
/* for IPv4 addresses, you can add the same local address with differing peer-adddress
* (IFA_ADDRESS), provided that their net-part differs. */
- && nm_platform_ip4_address_equal_peer_net (obj1, obj2));
+ && ((obj1->peer_address ^ obj2->peer_address) & nm_utils_ip4_prefix_to_netmask (obj1->plen)) == 0);
_vt_cmd_plobj_id_equal (ip6_address, NMPlatformIP6Address,
obj1->ifindex == obj2->ifindex
/* for IPv6 addresses, the prefix length is not part of the primary identifier. */
@@ -646,11 +820,20 @@ _vt_cmd_plobj_id_equal (ip6_route, NMPlatformIP6Route,
guint
nmp_object_id_hash (const NMPObject *obj)
{
+ const NMPClass *klass;
+
if (!obj)
return 0;
g_return_val_if_fail (NMP_OBJECT_IS_VALID (obj), 0);
- return NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_id_hash (&obj->object);
+
+ klass = NMP_OBJECT_GET_CLASS (obj);
+
+ if (klass->cmd_plobj_id_hash)
+ return klass->cmd_plobj_id_hash (&obj->object);
+
+ /* unhashable objects implement pointer equality. */
+ return g_direct_hash (obj);
}
#define _vt_cmd_plobj_id_hash(type, plat_type, cmd) \
@@ -673,7 +856,7 @@ _vt_cmd_plobj_id_hash (ip4_address, NMPlatformIP4Address, {
hash = hash * 33 + ((guint) obj->address);
/* for IPv4 we must also consider the net-part of the peer-address (IFA_ADDRESS) */
- hash = hash * 33 + ((guint) (nm_platform_ip4_address_get_peer_net (obj)));
+ hash = hash * 33 + ((guint) (obj->peer_address & nm_utils_ip4_prefix_to_netmask (obj->plen)));
})
_vt_cmd_plobj_id_hash (ip6_address, NMPlatformIP6Address, {
hash = (guint) 2907861637u;
@@ -699,11 +882,15 @@ _vt_cmd_plobj_id_hash (ip6_route, NMPlatformIP6Route, {
gboolean
nmp_object_is_alive (const NMPObject *obj)
{
+ const NMPClass *klass;
+
/* for convenience, allow NULL. */
if (!obj)
return FALSE;
- return NMP_OBJECT_GET_CLASS (obj)->cmd_obj_is_alive (obj);
+ klass = NMP_OBJECT_GET_CLASS (obj);
+ return !klass->cmd_obj_is_alive
+ || klass->cmd_obj_is_alive (obj);
}
static gboolean
@@ -741,13 +928,17 @@ _vt_cmd_obj_is_alive_ipx_route (const NMPObject *obj)
gboolean
nmp_object_is_visible (const NMPObject *obj)
-
{
+ const NMPClass *klass;
+
/* for convenience, allow NULL. */
if (!obj)
return FALSE;
- return NMP_OBJECT_GET_CLASS (obj)->cmd_obj_is_visible (obj);
+ klass = NMP_OBJECT_GET_CLASS (obj);
+
+ return !klass->cmd_obj_is_visible
+ || klass->cmd_obj_is_visible (obj);
}
static gboolean
@@ -774,46 +965,6 @@ _vt_cmd_obj_is_visible_ipx_route (const NMPObject *obj)
/******************************************************************/
-/**
- * nmp_object_from_nl:
- * @platform: platform instance (needed to lookup sysctl)
- * @nlo:
- * @id_only: if %TRUE, only fill the id fields of the object and leave the
- * other fields unset. This is useful to create a needle to lookup a matching
- * item in the cache.
- * @complete_from_cache: sometimes the netlink object doesn't contain all information.
- * If true, look them up in the cache and preserve the original value.
- *
- * Convert a libnl object to a platform object.
- * Returns: a NMPObject containing @nlo. If @id_only is %TRUE, only the id fields
- * are defined.
- **/
-NMPObject *
-nmp_object_from_nl (NMPlatform *platform, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache)
-{
- NMPObjectType obj_type = _nlo_get_object_type (nlo);
- NMPObject *obj;
-
- if (obj_type == NMP_OBJECT_TYPE_UNKNOWN)
- return NULL;
-
- obj = nmp_object_new (obj_type, NULL);
-
- if (!NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_init_from_nl (platform, &obj->object, nlo, id_only, complete_from_cache)) {
- nmp_object_unref (obj);
- return NULL;
- }
- return obj;
-}
-
-struct nl_object *
-nmp_object_to_nl (NMPlatform *platform, const NMPObject *obj, gboolean id_only)
-{
- return NMP_OBJECT_GET_CLASS (obj)->cmd_plobj_to_nl (platform, &obj->object, id_only);
-}
-
-/******************************************************************/
-
gboolean
nmp_cache_id_equal (const NMPCacheId *a, const NMPCacheId *b)
{
@@ -939,17 +1090,12 @@ _nmp_object_init_cache_id (const NMPObject *obj, NMPCacheIdType id_type, NMPCach
*out_id = NULL;
return TRUE;
default:
- return klass->cmd_obj_init_cache_id (obj, id_type, id, out_id);
+ return klass->cmd_obj_init_cache_id
+ && klass->cmd_obj_init_cache_id (obj, id_type, id, out_id);
}
}
static gboolean
-_vt_cmd_obj_init_cache_id_link (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id)
-{
- return FALSE;
-}
-
-static gboolean
_vt_cmd_obj_init_cache_id_ipx_address (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id)
{
switch (id_type) {
@@ -1505,8 +1651,8 @@ nmp_cache_update_netlink (NMPCache *cache, NMPObject *obj, NMPObject **out_obj,
* We could add efficient reverse lookup by adding a reverse index to NMMultiIndex. But that
* also adds some cost to support an (uncommon?) usage pattern.
*
- * Instead we just don't support it. Actually, we expect the user to
- * create a new instance with nmp_object_from_nl(). That is what nmp_cache_update_netlink().
+ * Instead we just don't support it, instead we expect the user to
+ * create a new instance from netlink.
*
* TL;DR: a cached object must never be modified.
*/
@@ -1783,24 +1929,21 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.sizeof_data = sizeof (NMPObjectLink),
.sizeof_public = sizeof (NMPlatformLink),
.obj_type_name = "link",
- .nl_type = "route/link",
.addr_family = AF_UNSPEC,
.rtm_gettype = RTM_GETLINK,
.signal_type = NM_PLATFORM_SIGNAL_LINK_CHANGED,
- .cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_link,
- .cmd_obj_equal = _vt_cmd_obj_equal_link,
+ .cmd_obj_cmp = _vt_cmd_obj_cmp_link,
.cmd_obj_copy = _vt_cmd_obj_copy_link,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_link,
.cmd_obj_dispose = _vt_cmd_obj_dispose_link,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_link,
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_link,
- .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_link,
- .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_link,
+ .cmd_obj_to_string = _vt_cmd_obj_to_string_link,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_link,
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_link,
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_link,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_link,
- .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_link_to_string,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_link_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_link_cmp,
},
[NMP_OBJECT_TYPE_IP4_ADDRESS - 1] = {
@@ -1808,23 +1951,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.sizeof_data = sizeof (NMPObjectIP4Address),
.sizeof_public = sizeof (NMPlatformIP4Address),
.obj_type_name = "ip4-address",
- .nl_type = "route/addr",
.addr_family = AF_INET,
.rtm_gettype = RTM_GETADDR,
.signal_type = NM_PLATFORM_SIGNAL_IP4_ADDRESS_CHANGED,
.cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_address,
- .cmd_obj_equal = _vt_cmd_obj_equal_plain,
- .cmd_obj_copy = _vt_cmd_obj_copy_plain,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip4_address,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address,
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_address,
- .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_ip4_address,
- .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip4_address,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_address,
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip4_address,
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_address,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_address,
- .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_ip4_address_to_string,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_address_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_address_cmp,
},
[NMP_OBJECT_TYPE_IP6_ADDRESS - 1] = {
@@ -1832,23 +1970,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.sizeof_data = sizeof (NMPObjectIP6Address),
.sizeof_public = sizeof (NMPlatformIP6Address),
.obj_type_name = "ip6-address",
- .nl_type = "route/addr",
.addr_family = AF_INET6,
.rtm_gettype = RTM_GETADDR,
.signal_type = NM_PLATFORM_SIGNAL_IP6_ADDRESS_CHANGED,
.cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_address,
- .cmd_obj_equal = _vt_cmd_obj_equal_plain,
- .cmd_obj_copy = _vt_cmd_obj_copy_plain,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip6_address,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_address,
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_address,
- .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_ip6_address,
- .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip6_address,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_address,
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip6_address,
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_address,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_address,
- .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_ip6_address_to_string,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_address_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_address_cmp
},
[NMP_OBJECT_TYPE_IP4_ROUTE - 1] = {
@@ -1856,23 +1989,18 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.sizeof_data = sizeof (NMPObjectIP4Route),
.sizeof_public = sizeof (NMPlatformIP4Route),
.obj_type_name = "ip4-route",
- .nl_type = "route/route",
.addr_family = AF_INET,
.rtm_gettype = RTM_GETROUTE,
.signal_type = NM_PLATFORM_SIGNAL_IP4_ROUTE_CHANGED,
.cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_route,
- .cmd_obj_equal = _vt_cmd_obj_equal_plain,
- .cmd_obj_copy = _vt_cmd_obj_copy_plain,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip4_route,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_route,
- .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_ip4_route,
- .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip4_route,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip4_route,
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip4_route,
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip4_route,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip4_route,
- .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_ip4_route_to_string,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip4_route_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip4_route_cmp,
},
[NMP_OBJECT_TYPE_IP6_ROUTE - 1] = {
@@ -1880,24 +2008,68 @@ const NMPClass _nmp_classes[NMP_OBJECT_TYPE_MAX] = {
.sizeof_data = sizeof (NMPObjectIP6Route),
.sizeof_public = sizeof (NMPlatformIP6Route),
.obj_type_name = "ip6-route",
- .nl_type = "route/route",
.addr_family = AF_INET6,
.rtm_gettype = RTM_GETROUTE,
.signal_type = NM_PLATFORM_SIGNAL_IP6_ROUTE_CHANGED,
.cmd_obj_init_cache_id = _vt_cmd_obj_init_cache_id_ipx_route,
- .cmd_obj_equal = _vt_cmd_obj_equal_plain,
- .cmd_obj_copy = _vt_cmd_obj_copy_plain,
.cmd_obj_stackinit_id = _vt_cmd_obj_stackinit_id_ip6_route,
.cmd_obj_is_alive = _vt_cmd_obj_is_alive_ipx_route,
.cmd_obj_is_visible = _vt_cmd_obj_is_visible_ipx_route,
- .cmd_plobj_init_from_nl = _nmp_vt_cmd_plobj_init_from_nl_ip6_route,
- .cmd_plobj_to_nl = _nmp_vt_cmd_plobj_to_nl_ip6_route,
.cmd_plobj_id_copy = _vt_cmd_plobj_id_copy_ip6_route,
.cmd_plobj_id_equal = _vt_cmd_plobj_id_equal_ip6_route,
.cmd_plobj_id_hash = _vt_cmd_plobj_id_hash_ip6_route,
.cmd_plobj_to_string_id = _vt_cmd_plobj_to_string_id_ip6_route,
- .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj)) nm_platform_ip6_route_to_string,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_ip6_route_to_string,
.cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_ip6_route_cmp,
},
+ [NMP_OBJECT_TYPE_LNK_GRE - 1] = {
+ .obj_type = NMP_OBJECT_TYPE_LNK_GRE,
+ .sizeof_data = sizeof (NMPObjectLnkGre),
+ .sizeof_public = sizeof (NMPlatformLnkGre),
+ .obj_type_name = "gre",
+ .lnk_link_type = NM_LINK_TYPE_GRE,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_gre_to_string,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_gre_cmp,
+ },
+ [NMP_OBJECT_TYPE_LNK_INFINIBAND - 1] = {
+ .obj_type = NMP_OBJECT_TYPE_LNK_INFINIBAND,
+ .sizeof_data = sizeof (NMPObjectLnkInfiniband),
+ .sizeof_public = sizeof (NMPlatformLnkInfiniband),
+ .obj_type_name = "infiniband",
+ .lnk_link_type = NM_LINK_TYPE_INFINIBAND,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_infiniband_to_string,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_infiniband_cmp,
+ },
+ [NMP_OBJECT_TYPE_LNK_MACVLAN - 1] = {
+ .obj_type = NMP_OBJECT_TYPE_LNK_MACVLAN,
+ .sizeof_data = sizeof (NMPObjectLnkMacvlan),
+ .sizeof_public = sizeof (NMPlatformLnkMacvlan),
+ .obj_type_name = "macvlan",
+ .lnk_link_type = NM_LINK_TYPE_MACVLAN,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_macvlan_to_string,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_macvlan_cmp,
+ },
+ [NMP_OBJECT_TYPE_LNK_VLAN - 1] = {
+ .obj_type = NMP_OBJECT_TYPE_LNK_VLAN,
+ .sizeof_data = sizeof (NMPObjectLnkVlan),
+ .sizeof_public = sizeof (NMPlatformLnkVlan),
+ .obj_type_name = "vlan",
+ .lnk_link_type = NM_LINK_TYPE_VLAN,
+ .cmd_obj_cmp = _vt_cmd_obj_cmp_lnk_vlan,
+ .cmd_obj_copy = _vt_cmd_obj_copy_lnk_vlan,
+ .cmd_obj_dispose = _vt_cmd_obj_dispose_lnk_vlan,
+ .cmd_obj_to_string = _vt_cmd_obj_to_string_lnk_vlan,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vlan_to_string,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vlan_cmp,
+ },
+ [NMP_OBJECT_TYPE_LNK_VXLAN - 1] = {
+ .obj_type = NMP_OBJECT_TYPE_LNK_VXLAN,
+ .sizeof_data = sizeof (NMPObjectLnkVxlan),
+ .sizeof_public = sizeof (NMPlatformLnkVxlan),
+ .obj_type_name = "vxlan",
+ .lnk_link_type = NM_LINK_TYPE_VXLAN,
+ .cmd_plobj_to_string = (const char *(*) (const NMPlatformObject *obj, char *buf, gsize len)) nm_platform_lnk_vxlan_to_string,
+ .cmd_plobj_cmp = (int (*) (const NMPlatformObject *obj1, const NMPlatformObject *obj2)) nm_platform_lnk_vxlan_cmp,
+ },
};
diff --git a/src/platform/nmp-object.h b/src/platform/nmp-object.h
index cc8e801f92..e49d358675 100644
--- a/src/platform/nmp-object.h
+++ b/src/platform/nmp-object.h
@@ -117,28 +117,29 @@ typedef struct {
int sizeof_data;
int sizeof_public;
const char *obj_type_name;
- const char *nl_type;
const char *signal_type;
+ /* Only for NMPObjectLnk* types. */
+ NMLinkType lnk_link_type;
+
/* returns %FALSE, if the obj type would never have an entry for index type @id_type. If @obj has an index,
* initialize @id and set @out_id to it. Otherwise, @out_id is NULL. */
gboolean (*cmd_obj_init_cache_id) (const NMPObject *obj, NMPCacheIdType id_type, NMPCacheId *id, const NMPCacheId **out_id);
- gboolean (*cmd_obj_equal) (const NMPObject *obj1, const NMPObject *obj2);
+ int (*cmd_obj_cmp) (const NMPObject *obj1, const NMPObject *obj2);
void (*cmd_obj_copy) (NMPObject *dst, const NMPObject *src);
void (*cmd_obj_stackinit_id) (NMPObject *obj, const NMPObject *src);
void (*cmd_obj_dispose) (NMPObject *obj);
gboolean (*cmd_obj_is_alive) (const NMPObject *obj);
gboolean (*cmd_obj_is_visible) (const NMPObject *obj);
+ const char *(*cmd_obj_to_string) (const NMPObject *obj, NMPObjectToStringMode to_string_mode, char *buf, gsize buf_size);
/* functions that operate on NMPlatformObject */
- gboolean (*cmd_plobj_init_from_nl) (NMPlatform *platform, NMPlatformObject *obj, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache);
- struct nl_object *(*cmd_plobj_to_nl) (NMPlatform *platform, const NMPlatformObject *obj, gboolean id_only);
void (*cmd_plobj_id_copy) (NMPlatformObject *dst, const NMPlatformObject *src);
gboolean (*cmd_plobj_id_equal) (const NMPlatformObject *obj1, const NMPlatformObject *obj2);
guint (*cmd_plobj_id_hash) (const NMPlatformObject *obj);
const char *(*cmd_plobj_to_string_id) (const NMPlatformObject *obj, char *buf, gsize buf_size);
- const char *(*cmd_plobj_to_string) (const NMPlatformObject *obj);
+ const char *(*cmd_plobj_to_string) (const NMPlatformObject *obj, char *buf, gsize len);
int (*cmd_plobj_cmp) (const NMPlatformObject *obj1, const NMPlatformObject *obj2);
} NMPClass;
@@ -149,6 +150,9 @@ typedef struct {
struct {
guint8 is_in_netlink;
+
+ /* Additional data that depends on the link-type (IFLA_INFO_DATA) */
+ NMPObject *lnk;
} netlink;
struct {
@@ -157,6 +161,31 @@ typedef struct {
} NMPObjectLink;
typedef struct {
+ NMPlatformLnkGre _public;
+} NMPObjectLnkGre;
+
+typedef struct {
+ NMPlatformLnkInfiniband _public;
+} NMPObjectLnkInfiniband;
+
+typedef struct {
+ NMPlatformLnkMacvlan _public;
+} NMPObjectLnkMacvlan;
+
+typedef struct {
+ NMPlatformLnkVlan _public;
+
+ guint n_ingress_qos_map;
+ guint n_egress_qos_map;
+ const NMVlanQosMapping *ingress_qos_map;
+ const NMVlanQosMapping *egress_qos_map;
+} NMPObjectLnkVlan;
+
+typedef struct {
+ NMPlatformLnkVxlan _public;
+} NMPObjectLnkVxlan;
+
+typedef struct {
NMPlatformIP4Address _public;
} NMPObjectIP4Address;
@@ -182,6 +211,21 @@ struct _NMPObject {
NMPlatformLink link;
NMPObjectLink _link;
+ NMPlatformLnkGre lnk_gre;
+ NMPObjectLnkGre _lnk_gre;
+
+ NMPlatformLnkInfiniband lnk_infiniband;
+ NMPObjectLnkInfiniband _lnk_infiniband;
+
+ NMPlatformLnkMacvlan lnk_macvlan;
+ NMPObjectLnkMacvlan _lnk_macvlan;
+
+ NMPlatformLnkVlan lnk_vlan;
+ NMPObjectLnkVlan _lnk_vlan;
+
+ NMPlatformLnkVxlan lnk_vxlan;
+ NMPObjectLnkVxlan _lnk_vxlan;
+
NMPlatformIPAddress ip_address;
NMPlatformIPXAddress ipx_address;
NMPlatformIP4Address ip4_address;
@@ -341,21 +385,4 @@ NMPCacheOpsType nmp_cache_update_link_master_connected (NMPCache *cache, int ifi
NMPCache *nmp_cache_new (void);
void nmp_cache_free (NMPCache *cache);
-NMPObject *nmp_object_from_nl (NMPlatform *platform, const struct nl_object *nlo, gboolean id_only, gboolean complete_from_cache);
-struct nl_object *nmp_object_to_nl (NMPlatform *platform, const NMPObject *obj, gboolean id_only);
-
-/* the following functions are currently implemented inside nm-linux-platform, because
- * they depend on utility functions there. */
-NMPObjectType _nlo_get_object_type (const struct nl_object *nlo);
-gboolean _nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
-gboolean _nmp_vt_cmd_plobj_init_from_nl_ip4_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
-gboolean _nmp_vt_cmd_plobj_init_from_nl_ip6_address (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
-gboolean _nmp_vt_cmd_plobj_init_from_nl_ip4_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
-gboolean _nmp_vt_cmd_plobj_init_from_nl_ip6_route (NMPlatform *platform, NMPlatformObject *_obj, const struct nl_object *_nlo, gboolean id_only, gboolean complete_from_cache);
-struct nl_object *_nmp_vt_cmd_plobj_to_nl_link (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
-struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
-struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_address (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
-struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip4_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
-struct nl_object *_nmp_vt_cmd_plobj_to_nl_ip6_route (NMPlatform *platform, const NMPlatformObject *_obj, gboolean id_only);
-
#endif /* __NMP_OBJECT_H__ */
diff --git a/src/platform/tests/Makefile.am b/src/platform/tests/Makefile.am
index 1fb621d752..bc6ec39e20 100644
--- a/src/platform/tests/Makefile.am
+++ b/src/platform/tests/Makefile.am
@@ -31,7 +31,6 @@ PLATFORM_LDADD = \
@GNOME_CODE_COVERAGE_RULES@
noinst_PROGRAMS = \
- dump \
monitor \
platform \
test-link-fake \
@@ -50,9 +49,6 @@ EXTRA_DIST = test-common.h
monitor_SOURCES = monitor.c $(PLATFORM_SOURCES)
monitor_LDADD = $(PLATFORM_LDADD)
-dump_SOURCES = dump.c $(PLATFORM_SOURCES)
-dump_LDADD = $(PLATFORM_LDADD)
-
platform_SOURCES = platform.c $(PLATFORM_SOURCES)
platform_LDADD = $(PLATFORM_LDADD)
diff --git a/src/platform/tests/dump.c b/src/platform/tests/dump.c
deleted file mode 100644
index b1f8012350..0000000000
--- a/src/platform/tests/dump.c
+++ /dev/null
@@ -1,137 +0,0 @@
-#include "config.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <arpa/inet.h>
-
-#include "nm-platform.h"
-#include "nm-linux-platform.h"
-#include "nm-fake-platform.h"
-#include "nm-macros-internal.h"
-
-static void
-dump_interface (NMPlatformLink *link)
-{
- GArray *ip6_addresses;
- GArray *ip4_addresses;
- const NMPlatformIP6Address *ip6_address;
- const NMPlatformIP4Address *ip4_address;
- GArray *ip6_routes;
- GArray *ip4_routes;
- const NMPlatformIP6Route *ip6_route;
- const NMPlatformIP4Route *ip4_route;
- char networkstr[INET6_ADDRSTRLEN];
- char gatewaystr[INET6_ADDRSTRLEN];
- int vlan_id, vlan_parent;
- const char *address;
- size_t addrlen;
- int i;
-
- g_assert (NM_FLAGS_HAS (link->flags, IFF_UP) || !link->connected);
-
- printf ("%d: %s: %s", link->ifindex, link->name, nm_link_type_to_string (link->type));
- if (NM_FLAGS_HAS (link->flags, IFF_UP))
- printf (" %s", link->connected ? "CONNECTED" : "DISCONNECTED");
- else
- printf (" DOWN");
- if (NM_FLAGS_HAS (link->flags, IFF_NOARP))
- printf (" noarp");
- if (link->master)
- printf (" master %d", link->master);
- if (link->parent)
- printf (" parent %d", link->parent);
- printf (" mtu %d", link->mtu);
- printf ("\n");
- if (link->driver)
- printf (" driver: %s\n", link->driver);
- printf (" UDI: %s\n", nm_platform_link_get_udi (NM_PLATFORM_GET, link->ifindex));
- if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, link->ifindex, &vlan_parent, &vlan_id))
- g_assert_not_reached ();
- if (vlan_parent)
- printf (" vlan parent %d id %d\n", vlan_parent, vlan_id);
-
- if (nm_platform_link_is_software (NM_PLATFORM_GET, link->ifindex))
- printf (" class software\n");
- if (nm_platform_link_supports_slaves (NM_PLATFORM_GET, link->ifindex))
- printf (" class supports-slaves\n");
- if (nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, link->ifindex))
- printf (" feature carrier-detect\n");
- if (nm_platform_link_supports_vlans (NM_PLATFORM_GET, link->ifindex))
- printf (" feature vlans\n");
-
- address = nm_platform_link_get_address (NM_PLATFORM_GET, link->ifindex, &addrlen);
- if (address) {
- printf (" link-address ");
- for (i = 0; i < addrlen; i++)
- printf ("%s%02hhx", i ? ":" : "", address[i]);
- printf ("\n");
- }
-
- ip4_addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, link->ifindex);
- ip6_addresses = nm_platform_ip6_address_get_all (NM_PLATFORM_GET, link->ifindex);
-
- g_assert (ip4_addresses);
- g_assert (ip6_addresses);
-
- for (i = 0; i < ip4_addresses->len; i++) {
- ip4_address = &g_array_index (ip4_addresses, NMPlatformIP4Address, i);
- printf (" ip4-address %s\n", nm_platform_ip4_address_to_string (ip4_address));
- }
-
- for (i = 0; i < ip6_addresses->len; i++) {
- ip6_address = &g_array_index (ip6_addresses, NMPlatformIP6Address, i);
- printf (" ip6-address %s\n", nm_platform_ip6_address_to_string (ip6_address));
- }
-
- g_array_unref (ip4_addresses);
- g_array_unref (ip6_addresses);
-
- ip4_routes = nm_platform_ip4_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
- ip6_routes = nm_platform_ip6_route_get_all (NM_PLATFORM_GET, link->ifindex, NM_PLATFORM_GET_ROUTE_FLAGS_WITH_DEFAULT | NM_PLATFORM_GET_ROUTE_FLAGS_WITH_NON_DEFAULT);
-
- g_assert (ip4_routes);
- g_assert (ip6_routes);
-
- for (i = 0; i < ip4_routes->len; i++) {
- ip4_route = &g_array_index (ip4_routes, NMPlatformIP4Route, i);
- inet_ntop (AF_INET, &ip4_route->network, networkstr, sizeof (networkstr));
- inet_ntop (AF_INET, &ip4_route->gateway, gatewaystr, sizeof (gatewaystr));
- printf (" ip4-route %s/%d via %s\n", networkstr, ip4_route->plen, gatewaystr);
- }
-
- for (i = 0; i < ip6_routes->len; i++) {
- ip6_route = &g_array_index (ip6_routes, NMPlatformIP6Route, i);
- inet_ntop (AF_INET6, &ip6_route->network, networkstr, sizeof (networkstr));
- inet_ntop (AF_INET6, &ip6_route->gateway, gatewaystr, sizeof (gatewaystr));
- printf (" ip6-route %s/%d via %s\n", networkstr, ip6_route->plen, gatewaystr);
- }
-
- g_array_unref (ip4_routes);
- g_array_unref (ip6_routes);
-}
-
-static void
-dump_all (void)
-{
- GArray *links = nm_platform_link_get_all (NM_PLATFORM_GET);
- int i;
-
- for (i = 0; i < links->len; i++)
- dump_interface (&g_array_index (links, NMPlatformLink, i));
-}
-
-int
-main (int argc, char **argv)
-{
- nm_g_type_init ();
-
- g_assert (argc <= 2);
- if (argc > 1 && !g_strcmp0 (argv[1], "--fake"))
- nm_fake_platform_setup ();
- else
- nm_linux_platform_setup ();
-
- dump_all ();
-
- return EXIT_SUCCESS;
-}
diff --git a/src/platform/tests/monitor.c b/src/platform/tests/monitor.c
index 6c95830678..4d721ce947 100644
--- a/src/platform/tests/monitor.c
+++ b/src/platform/tests/monitor.c
@@ -4,25 +4,27 @@
#include <syslog.h>
#include "nm-default.h"
-#include "nm-fake-platform.h"
#include "nm-linux-platform.h"
+#include "nm-test-utils.h"
+
+NMTST_DEFINE ();
+
int
main (int argc, char **argv)
{
GMainLoop *loop;
- nm_g_type_init ();
+ if (!g_getenv ("G_MESSAGES_DEBUG"))
+ g_setenv ("G_MESSAGES_DEBUG", "all", TRUE);
+
+ nmtst_init_with_logging (&argc, &argv, "DEBUG", "ALL");
+
+ nm_log_info (LOGD_PLATFORM, "platform monitor start");
loop = g_main_loop_new (NULL, FALSE);
- nm_logging_setup ("debug", NULL, NULL, NULL);
- openlog (G_LOG_DOMAIN, LOG_CONS | LOG_PERROR, LOG_DAEMON);
-
- g_assert (argc <= 2);
- if (argc > 1 && !g_strcmp0 (argv[1], "--fake"))
- nm_fake_platform_setup ();
- else
- nm_linux_platform_setup ();
+
+ nm_linux_platform_setup ();
g_main_loop_run (loop);
diff --git a/src/platform/tests/platform.c b/src/platform/tests/platform.c
index 08e89007ff..33ef8928dc 100644
--- a/src/platform/tests/platform.c
+++ b/src/platform/tests/platform.c
@@ -30,6 +30,7 @@
#include "nm-platform.h"
#include "nm-linux-platform.h"
#include "nm-fake-platform.h"
+#include "nm-utils.h"
#define error(...) fprintf (stderr, __VA_ARGS__)
@@ -324,13 +325,14 @@ static gboolean
do_vlan_get_info (char **argv)
{
int ifindex = parse_ifindex (*argv++);
- int parent;
- int vlanid;
+ const NMPlatformLink *plink;
+ const NMPlatformLnkVlan *plnk;
- if (!nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &parent, &vlanid))
+ plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, &plink);
+ if (!plnk)
return FALSE;
- printf ("%d %d\n", parent, vlanid);
+ printf ("%d %d\n", plink->parent, plnk->id);
return TRUE;
}
@@ -356,20 +358,6 @@ do_vlan_set_egress_map (char **argv)
}
static gboolean
-do_veth_get_properties (char **argv)
-{
- int ifindex = parse_ifindex (*argv++);
- NMPlatformVethProperties props;
-
- if (!nm_platform_veth_get_properties (NM_PLATFORM_GET, ifindex, &props))
- return FALSE;
-
- printf ("peer: %d\n", props.peer);
-
- return TRUE;
-}
-
-static gboolean
do_tun_get_properties (char **argv)
{
int ifindex = parse_ifindex (*argv++);
@@ -401,15 +389,17 @@ static gboolean
do_macvlan_get_properties (char **argv)
{
int ifindex = parse_ifindex (*argv++);
- NMPlatformMacvlanProperties props;
+ const NMPlatformLink *plink;
+ const NMPlatformLnkMacvlan *props;
- if (!nm_platform_macvlan_get_properties (NM_PLATFORM_GET, ifindex, &props))
+ props = nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, ifindex, &plink);
+ if (!props)
return FALSE;
- printf ("parent: %d\n", props.parent_ifindex);
- printf ("mode: %s\n", props.mode);
+ printf ("parent: %d\n", plink->parent);
+ printf ("mode: %s\n", props->mode);
printf ("no-promisc: ");
- print_boolean (props.no_promisc);
+ print_boolean (props->no_promisc);
return TRUE;
}
@@ -417,45 +407,46 @@ static gboolean
do_vxlan_get_properties (char **argv)
{
int ifindex = parse_ifindex (*argv++);
- NMPlatformVxlanProperties props;
+ const NMPlatformLnkVxlan *props;
char addrstr[INET6_ADDRSTRLEN];
- if (!nm_platform_vxlan_get_properties (NM_PLATFORM_GET, ifindex, &props))
+ props = nm_platform_link_get_lnk_vxlan (NM_PLATFORM_GET, ifindex, NULL);
+ if (props)
return FALSE;
- printf ("parent-ifindex: %u\n", props.parent_ifindex);
- printf ("id: %u\n", props.id);
- if (props.group)
- inet_ntop (AF_INET, &props.group, addrstr, sizeof (addrstr));
- else if (props.group6.s6_addr[0])
- inet_ntop (AF_INET6, &props.group6, addrstr, sizeof (addrstr));
+ printf ("parent-ifindex: %u\n", props->parent_ifindex);
+ printf ("id: %u\n", props->id);
+ if (props->group)
+ inet_ntop (AF_INET, &props->group, addrstr, sizeof (addrstr));
+ else if (props->group6.s6_addr[0])
+ inet_ntop (AF_INET6, &props->group6, addrstr, sizeof (addrstr));
else
strcpy (addrstr, "-");
printf ("group: %s\n", addrstr);
- if (props.local)
- inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr));
- else if (props.local6.s6_addr[0])
- inet_ntop (AF_INET6, &props.local6, addrstr, sizeof (addrstr));
+ if (props->local)
+ inet_ntop (AF_INET, &props->local, addrstr, sizeof (addrstr));
+ else if (props->local6.s6_addr[0])
+ inet_ntop (AF_INET6, &props->local6, addrstr, sizeof (addrstr));
else
strcpy (addrstr, "-");
printf ("local: %s\n", addrstr);
- printf ("tos: %u\n", props.tos);
- printf ("ttl: %u\n", props.ttl);
+ printf ("tos: %u\n", props->tos);
+ printf ("ttl: %u\n", props->ttl);
printf ("learning: ");
- print_boolean (props.learning);
- printf ("ageing: %u\n", props.ageing);
- printf ("limit: %u\n", props.limit);
- printf ("dst-port: %u\n", props.dst_port);
- printf ("src-port-min: %u\n", props.src_port_min);
- printf ("src-port-max: %u\n", props.src_port_max);
+ print_boolean (props->learning);
+ printf ("ageing: %u\n", props->ageing);
+ printf ("limit: %u\n", props->limit);
+ printf ("dst-port: %u\n", props->dst_port);
+ printf ("src-port-min: %u\n", props->src_port_min);
+ printf ("src-port-max: %u\n", props->src_port_max);
printf ("proxy: ");
- print_boolean (props.proxy);
+ print_boolean (props->proxy);
printf ("rsc: ");
- print_boolean (props.rsc);
+ print_boolean (props->rsc);
printf ("l2miss: ");
- print_boolean (props.l2miss);
+ print_boolean (props->l2miss);
printf ("l3miss: ");
- print_boolean (props.l3miss);
+ print_boolean (props->l3miss);
return TRUE;
}
@@ -464,31 +455,32 @@ static gboolean
do_gre_get_properties (char **argv)
{
int ifindex = parse_ifindex (*argv++);
- NMPlatformGreProperties props;
+ const NMPlatformLnkGre *props;
char addrstr[INET_ADDRSTRLEN];
- if (!nm_platform_gre_get_properties (NM_PLATFORM_GET, ifindex, &props))
+ props = nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL);
+ if (!props)
return FALSE;
- printf ("parent-ifindex: %u\n", props.parent_ifindex);
- printf ("input-flags: %u\n", props.input_flags);
- printf ("output-flags: %u\n", props.input_flags);
- printf ("input-key: %u\n", props.input_key);
- printf ("output-key: %u\n", props.output_key);
- if (props.local)
- inet_ntop (AF_INET, &props.local, addrstr, sizeof (addrstr));
+ printf ("parent-ifindex: %u\n", props->parent_ifindex);
+ printf ("input-flags: %u\n", props->input_flags);
+ printf ("output-flags: %u\n", props->input_flags);
+ printf ("input-key: %u\n", props->input_key);
+ printf ("output-key: %u\n", props->output_key);
+ if (props->local)
+ inet_ntop (AF_INET, &props->local, addrstr, sizeof (addrstr));
else
strcpy (addrstr, "-");
printf ("local: %s\n", addrstr);
- if (props.remote)
- inet_ntop (AF_INET, &props.remote, addrstr, sizeof (addrstr));
+ if (props->remote)
+ inet_ntop (AF_INET, &props->remote, addrstr, sizeof (addrstr));
else
strcpy (addrstr, "-");
printf ("remote: %s\n", addrstr);
- printf ("ttl: %u\n", props.ttl);
- printf ("tos: %u\n", props.tos);
+ printf ("ttl: %u\n", props->ttl);
+ printf ("tos: %u\n", props->tos);
printf ("path-mtu-discovery: ");
- print_boolean (props.path_mtu_discovery);
+ print_boolean (props->path_mtu_discovery);
return TRUE;
}
@@ -499,15 +491,17 @@ do_ip4_address_get_all (char **argv)
int ifindex = parse_ifindex (argv[0]);
GArray *addresses;
NMPlatformIP4Address *address;
- char addrstr[INET_ADDRSTRLEN];
int i;
if (ifindex) {
addresses = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
for (i = 0; i < addresses->len; i++) {
address = &g_array_index (addresses, NMPlatformIP4Address, i);
- inet_ntop (AF_INET, &address->address, addrstr, sizeof (addrstr));
- printf ("%s/%d\n", addrstr, address->plen);
+
+ printf ("%s", nm_utils_inet4_ntop (address->address, NULL));
+ if (address->address != address->peer_address)
+ printf (" peer %s", nm_utils_inet4_ntop (address->peer_address, NULL));
+ printf ("/%d\n", address->plen);
}
g_array_unref (addresses);
}
@@ -583,7 +577,7 @@ do_ip4_address_add (char **argv)
guint32 lifetime = strtol (*argv++, NULL, 10);
guint32 preferred = strtol (*argv++, NULL, 10);
- gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, plen, 0, lifetime, preferred, NULL);
+ gboolean value = nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, address, plen, address, lifetime, preferred, NULL);
return value;
} else
return FALSE;
@@ -599,7 +593,7 @@ do_ip6_address_add (char **argv)
if (ifindex && parse_ip6_address (*argv++, &address, &plen)) {
guint32 lifetime = strtol (*argv++, NULL, 10);
guint32 preferred = strtol (*argv++, NULL, 10);
- guint flags = (*argv) ? rtnl_addr_str2flags (*argv++) : 0;
+ guint flags = 0; /* don't support flags */
gboolean value = nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, address, plen, in6addr_any, lifetime, preferred, flags);
return value;
@@ -624,11 +618,11 @@ do_ip6_address_add (char **argv)
} else \
return FALSE; \
}
-#define ADDR_CMD(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, FALSE, 0, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, FALSE)
+#define ADDR_CMD(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, FALSE, address, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, FALSE)
#define ADDR_CMD_PRINT(cmdname, ...) ADDR_CMD_FULL (ip4, cmdname, TRUE, ##__VA_ARGS__) ADDR_CMD_FULL (ip6, cmdname, TRUE)
ADDR_CMD (delete)
-ADDR_CMD_PRINT (get, 0)
+ADDR_CMD_PRINT (get, address)
static gboolean
do_ip4_route_get_all (char **argv)
@@ -820,8 +814,6 @@ static const command_t commands[] = {
"<ifname/ifindex> <from> <to>" },
{ "vlan-set-egress-map", "set vlan egress map", do_vlan_set_egress_map, 3,
"<ifname/ifindex> <from> <to>" },
- { "veth-get-properties", "get veth properties", do_veth_get_properties, 1,
- "<ifname/ifindex>" },
{ "tun-get-properties", "get tun/tap properties", do_tun_get_properties, 1,
"<ifname/ifindex>" },
{ "macvlan-get-properties", "get macvlan properties", do_macvlan_get_properties, 1,
diff --git a/src/platform/tests/test-address.c b/src/platform/tests/test-address.c
index f37b05ceae..2cdd29622b 100644
--- a/src/platform/tests/test-address.c
+++ b/src/platform/tests/test-address.c
@@ -73,13 +73,13 @@ test_ip4_address_general (void)
inet_pton (AF_INET, IP4_ADDRESS, &addr);
/* Add address */
- g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
- nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL);
- g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
+ g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
+ nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL);
+ g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
accept_signal (address_added);
/* Add address again (aka update) */
- nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime + 100, preferred + 50, NULL);
+ nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime + 100, preferred + 50, NULL);
accept_signals (address_changed, 0, 1);
/* Test address listing */
@@ -89,16 +89,17 @@ test_ip4_address_general (void)
address = &g_array_index (addresses, NMPlatformIP4Address, 0);
g_assert_cmpint (address->ifindex, ==, ifindex);
g_assert_cmphex (address->address, ==, addr);
+ g_assert_cmphex (address->peer_address, ==, addr);
g_assert_cmpint (address->plen, ==, IP4_PLEN);
g_array_unref (addresses);
/* Remove address */
- nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0);
- g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
+ nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr);
+ g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
accept_signal (address_removed);
/* Remove address again */
- nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0);
+ nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr);
free_signal (address_added);
free_signal (address_changed);
@@ -173,16 +174,16 @@ test_ip4_address_general_2 (void)
g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, DEVICE_IFINDEX, NULL));
/* Add/delete notification */
- nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL);
+ nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL);
accept_signal (address_added);
- g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
- nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, 0);
+ g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
+ nmtstp_ip4_address_del (EX, ifindex, addr, IP4_PLEN, addr);
accept_signal (address_removed);
- g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
+ g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
/* Add/delete conflict */
- nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, 0, lifetime, preferred, NULL);
- g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, 0));
+ nmtstp_ip4_address_add (EX, ifindex, addr, IP4_PLEN, addr, lifetime, preferred, NULL);
+ g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, IP4_PLEN, addr));
accept_signal (address_added);
free_signal (address_added);
@@ -275,6 +276,59 @@ test_ip4_address_peer (void)
/*****************************************************************************/
+static void
+test_ip4_address_peer_zero (void)
+{
+ const int ifindex = DEVICE_IFINDEX;
+ in_addr_t addr, addr_peer;
+ guint32 lifetime = 2000;
+ guint32 preferred = 1000;
+ const int plen = 24;
+ const char *label = NULL;
+ in_addr_t peers[3], r_peers[3];
+ int i;
+ GArray *addrs;
+
+ g_assert (ifindex > 0);
+
+ inet_pton (AF_INET, "192.168.5.2", &addr);
+ inet_pton (AF_INET, "192.168.6.2", &addr_peer);
+ peers[0] = addr;
+ peers[1] = addr_peer;
+ peers[2] = 0;
+
+ g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
+
+ nmtst_rand_perm (NULL, r_peers, peers, sizeof (peers[0]), G_N_ELEMENTS (peers));
+ for (i = 0; i < G_N_ELEMENTS (peers); i++) {
+ g_assert (!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i]));
+
+ nmtstp_ip4_address_add (EX, ifindex, addr, plen, r_peers[i], lifetime, preferred, label);
+
+ addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
+ g_assert (addrs);
+ g_assert_cmpint (addrs->len, ==, i + 1);
+ g_array_unref (addrs);
+ }
+
+ if (nmtst_is_debug ())
+ nmtstp_run_command_check ("ip address show dev %s", DEVICE_NAME);
+
+ nmtst_rand_perm (NULL, r_peers, peers, sizeof (peers[0]), G_N_ELEMENTS (peers));
+ for (i = 0; i < G_N_ELEMENTS (peers); i++) {
+ g_assert (nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, addr, plen, r_peers[i]));
+
+ nmtstp_ip4_address_del (EX, ifindex, addr, plen, r_peers[i]);
+
+ addrs = nm_platform_ip4_address_get_all (NM_PLATFORM_GET, ifindex);
+ g_assert (addrs);
+ g_assert_cmpint (addrs->len, ==, G_N_ELEMENTS (peers) - i - 1);
+ g_array_unref (addrs);
+ }
+}
+
+/*****************************************************************************/
+
void
init_tests (int *argc, char ***argv)
{
@@ -342,4 +396,5 @@ setup_tests (void)
_g_test_add_func ("/address/ipv6/general-2", test_ip6_address_general_2);
_g_test_add_func ("/address/ipv4/peer", test_ip4_address_peer);
+ _g_test_add_func ("/address/ipv4/peer/zero", test_ip4_address_peer_zero);
}
diff --git a/src/platform/tests/test-cleanup.c b/src/platform/tests/test-cleanup.c
index 4ef6908588..94ce05491d 100644
--- a/src/platform/tests/test-cleanup.c
+++ b/src/platform/tests/test-cleanup.c
@@ -43,7 +43,7 @@ test_cleanup_internal (void)
g_assert (ifindex > 0);
/* Add routes and addresses */
- g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, 0, lifetime, preferred, NULL));
+ g_assert (nm_platform_ip4_address_add (NM_PLATFORM_GET, ifindex, addr4, plen4, addr4, lifetime, preferred, NULL));
g_assert (nm_platform_ip6_address_add (NM_PLATFORM_GET, ifindex, addr6, plen6, in6addr_any, lifetime, preferred, flags));
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, gateway4, 32, INADDR_ANY, 0, metric, mss));
g_assert (nm_platform_ip4_route_add (NM_PLATFORM_GET, ifindex, NM_IP_CONFIG_SOURCE_USER, network4, plen4, gateway4, 0, metric, mss));
diff --git a/src/platform/tests/test-common.c b/src/platform/tests/test-common.c
index af41a0380e..98280b4527 100644
--- a/src/platform/tests/test-common.c
+++ b/src/platform/tests/test-common.c
@@ -10,14 +10,6 @@
#define SIGNAL_DATA_FMT "'%s-%s' ifindex %d%s%s%s (%d times received)"
#define SIGNAL_DATA_ARG(data) (data)->name, nm_platform_signal_change_type_to_string ((data)->change_type), (data)->ifindex, (data)->ifname ? " ifname '" : "", (data)->ifname ? (data)->ifname : "", (data)->ifname ? "'" : "", (data)->received_count
-typedef struct {
- union {
- guint8 addr_ptr[1];
- in_addr_t addr4;
- struct in6_addr addr6;
- };
-} IPAddr;
-
gboolean
nmtstp_is_root_test (void)
{
@@ -374,6 +366,50 @@ nmtstp_wait_for_signal_until (gint64 until_ms)
}
}
+const NMPlatformLink *
+nmtstp_wait_for_link (const char *ifname, guint timeout_ms)
+{
+ return nmtstp_wait_for_link_until (ifname, nm_utils_get_monotonic_timestamp_ms () + timeout_ms);
+}
+
+const NMPlatformLink *
+nmtstp_wait_for_link_until (const char *ifname, gint64 until_ms)
+{
+ const NMPlatformLink *plink;
+ gint64 now;
+
+ while (TRUE) {
+ now = nm_utils_get_monotonic_timestamp_ms ();
+
+ plink = nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname);
+ if (plink)
+ return plink;
+
+ if (until_ms < now)
+ return NULL;
+
+ nmtstp_wait_for_signal (MAX (1, until_ms - now));
+ }
+}
+
+const NMPlatformLink *
+nmtstp_assert_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms)
+{
+ return nmtstp_assert_wait_for_link_until (ifname, expected_link_type, nm_utils_get_monotonic_timestamp_ms () + timeout_ms);
+}
+
+const NMPlatformLink *
+nmtstp_assert_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms)
+{
+ const NMPlatformLink *plink;
+
+ plink = nmtstp_wait_for_link_until (ifname, until_ms);
+ g_assert (plink);
+ if (expected_link_type != NM_LINK_TYPE_NONE)
+ g_assert_cmpint (plink->type, ==, expected_link_type);
+ return plink;
+}
+
int
nmtstp_run_command_check_external_global (void)
{
@@ -502,9 +538,9 @@ static void
_ip_address_add (gboolean external_command,
gboolean is_v4,
int ifindex,
- const IPAddr *address,
+ const NMIPAddr *address,
int plen,
- const IPAddr *peer_address,
+ const NMIPAddr *peer_address,
guint32 lifetime,
guint32 preferred,
const char *label,
@@ -524,9 +560,6 @@ _ip_address_add (gboolean external_command,
ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex);
g_assert (ifname);
- if (peer_address == address)
- peer_address = 0;
-
if (lifetime != NM_PLATFORM_LIFETIME_PERMANENT)
s_valid = g_strdup_printf (" valid_lft %d", lifetime);
if (preferred != NM_PLATFORM_LIFETIME_PERMANENT)
@@ -535,11 +568,20 @@ _ip_address_add (gboolean external_command,
s_label = g_strdup_printf ("%s:%s", ifname, label);
if (is_v4) {
+ char s_peer[100];
+
g_assert (flags == 0);
- nmtstp_run_command_check ("ip address change %s%s%s/%d dev %s%s%s%s",
+
+ if ( peer_address->addr4 != address->addr4
+ || nmtst_get_rand_int () % 2) {
+ /* If the peer is the same as the local address, we can omit it. The result should be identical */
+ g_snprintf (s_peer, sizeof (s_peer), " peer %s", nm_utils_inet4_ntop (peer_address->addr4, b2));
+ } else
+ s_peer[0] = '\0';
+
+ nmtstp_run_command_check ("ip address change %s%s/%d dev %s%s%s%s",
nm_utils_inet4_ntop (address->addr4, b1),
- peer_address->addr4 ? " peer " : "",
- peer_address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "",
+ s_peer,
plen,
ifname,
s_valid ?: "",
@@ -601,7 +643,7 @@ _ip_address_add (gboolean external_command,
g_assert (flags == 0);
a = nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4);
if ( a
- && nm_platform_ip4_address_get_peer (a) == (peer_address->addr4 ? peer_address->addr4 : address->addr4)
+ && a->peer_address == peer_address->addr4
&& nmtstp_ip_address_check_lifetime ((NMPlatformIPAddress*) a, -1, lifetime, preferred)
&& strcmp (a->label, label ?: "") == 0)
break;
@@ -624,9 +666,6 @@ _ip_address_add (gboolean external_command,
/* for internal command, we expect not to reach this line.*/
g_assert (external_command);
- /* timeout? */
- g_assert (nm_utils_get_monotonic_timestamp_ms () < end_time);
-
g_assert (nmtstp_wait_for_signal_until (end_time));
} while (TRUE);
}
@@ -644,9 +683,9 @@ nmtstp_ip4_address_add (gboolean external_command,
_ip_address_add (external_command,
TRUE,
ifindex,
- (IPAddr *) &address,
+ (NMIPAddr *) &address,
plen,
- (IPAddr *) &peer_address,
+ (NMIPAddr *) &peer_address,
lifetime,
preferred,
label,
@@ -666,9 +705,9 @@ nmtstp_ip6_address_add (gboolean external_command,
_ip_address_add (external_command,
FALSE,
ifindex,
- (IPAddr *) &address,
+ (NMIPAddr *) &address,
plen,
- (IPAddr *) &peer_address,
+ (NMIPAddr *) &peer_address,
lifetime,
preferred,
NULL,
@@ -679,9 +718,9 @@ static void
_ip_address_del (gboolean external_command,
gboolean is_v4,
int ifindex,
- const IPAddr *address,
+ const NMIPAddr *address,
int plen,
- const IPAddr *peer_address)
+ const NMIPAddr *peer_address)
{
gint64 end_time;
@@ -696,9 +735,6 @@ _ip_address_del (gboolean external_command,
ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex);
g_assert (ifname);
- if (peer_address == address)
- peer_address = 0;
-
/* let's wait until we see the address as we added it. */
if (is_v4)
had_address = !!nm_platform_ip4_address_get (NM_PLATFORM_GET, ifindex, address->addr4, plen, peer_address->addr4);
@@ -708,8 +744,8 @@ _ip_address_del (gboolean external_command,
if (is_v4) {
success = nmtstp_run_command ("ip address delete %s%s%s/%d dev %s",
nm_utils_inet4_ntop (address->addr4, b1),
- peer_address->addr4 ? " peer " : "",
- peer_address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "",
+ peer_address->addr4 != address->addr4 ? " peer " : "",
+ peer_address->addr4 != address->addr4 ? nm_utils_inet4_ntop (peer_address->addr4, b2) : "",
plen,
ifname);
} else {
@@ -763,9 +799,6 @@ _ip_address_del (gboolean external_command,
/* for internal command, we expect not to reach this line.*/
g_assert (external_command);
- /* timeout? */
- g_assert (nm_utils_get_monotonic_timestamp_ms () < end_time);
-
g_assert (nmtstp_wait_for_signal_until (end_time));
} while (TRUE);
}
@@ -780,9 +813,9 @@ nmtstp_ip4_address_del (gboolean external_command,
_ip_address_del (external_command,
TRUE,
ifindex,
- (IPAddr *) &address,
+ (NMIPAddr *) &address,
plen,
- (IPAddr *) &peer_address);
+ (NMIPAddr *) &peer_address);
}
void
@@ -794,11 +827,57 @@ nmtstp_ip6_address_del (gboolean external_command,
_ip_address_del (external_command,
FALSE,
ifindex,
- (IPAddr *) &address,
+ (NMIPAddr *) &address,
plen,
NULL);
}
+void
+nmtstp_link_set_updown (gboolean external_command,
+ int ifindex,
+ gboolean up)
+{
+ const NMPlatformLink *plink;
+ gint64 end_time;
+
+ external_command = nmtstp_run_command_check_external (external_command);
+
+ if (external_command) {
+ const char *ifname;
+
+ ifname = nm_platform_link_get_name (NM_PLATFORM_GET, ifindex);
+ g_assert (ifname);
+
+ nmtstp_run_command_check ("ip link set %s %s",
+ ifname,
+ up ? "up" : "down");
+ } else {
+ if (up)
+ g_assert (nm_platform_link_set_up (NM_PLATFORM_GET, ifindex, NULL));
+ else
+ g_assert (nm_platform_link_set_down (NM_PLATFORM_GET, ifindex));
+ }
+
+ /* Let's wait until we get the result */
+ end_time = nm_utils_get_monotonic_timestamp_ms () + 250;
+ do {
+ if (external_command)
+ nm_platform_process_events (NM_PLATFORM_GET);
+
+ /* let's wait until we see the address as we added it. */
+ plink = nm_platform_link_get (NM_PLATFORM_GET, ifindex);
+ g_assert (plink);
+
+ if (NM_FLAGS_HAS (plink->flags, IFF_UP) == !!up)
+ break;
+
+ /* for internal command, we expect not to reach this line.*/
+ g_assert (external_command);
+
+ g_assert (nmtstp_wait_for_signal_until (end_time));
+ } while (TRUE);
+}
+
/*****************************************************************************/
NMTST_DEFINE();
diff --git a/src/platform/tests/test-common.h b/src/platform/tests/test-common.h
index 626e9d2fde..a2794af7e3 100644
--- a/src/platform/tests/test-common.h
+++ b/src/platform/tests/test-common.h
@@ -75,6 +75,11 @@ int nmtstp_run_command (const char *format, ...) __attribute__((__format__ (__pr
gboolean nmtstp_wait_for_signal (guint timeout_ms);
gboolean nmtstp_wait_for_signal_until (gint64 until_ms);
+const NMPlatformLink *nmtstp_wait_for_link (const char *ifname, guint timeout_ms);
+const NMPlatformLink *nmtstp_wait_for_link_until (const char *ifname, gint64 until_ms);
+
+const NMPlatformLink *nmtstp_assert_wait_for_link (const char *ifname, NMLinkType expected_link_type, guint timeout_ms);
+const NMPlatformLink *nmtstp_assert_wait_for_link_until (const char *ifname, NMLinkType expected_link_type, gint64 until_ms);
int nmtstp_run_command_check_external_global (void);
gboolean nmtstp_run_command_check_external (int external_command);
@@ -113,6 +118,9 @@ void nmtstp_ip6_address_del (gboolean external_command,
struct in6_addr address,
int plen);
+void nmtstp_link_set_updown (gboolean external_command,
+ int ifindex,
+ gboolean up);
void init_tests (int *argc, char ***argv);
void setup_tests (void);
diff --git a/src/platform/tests/test-general.c b/src/platform/tests/test-general.c
index b1dd454e28..f342e5653e 100644
--- a/src/platform/tests/test-general.c
+++ b/src/platform/tests/test-general.c
@@ -53,37 +53,6 @@ test_link_get_all (void)
/******************************************************************/
-static void
-test_nm_platform_ip6_address_to_string_flags (void)
-{
- NMPlatformIP6Address addr = { 0 };
-
- g_assert_cmpstr (strstr (nm_platform_ip6_address_to_string (&addr), " flags "), ==, NULL);
-
- addr.flags = IFA_F_MANAGETEMPADDR;
- nmtst_assert_str_has_substr (nm_platform_ip6_address_to_string (&addr), " flags mngtmpaddr ");
-
- addr.flags = IFA_F_NOPREFIXROUTE;
- nmtst_assert_str_has_substr (nm_platform_ip6_address_to_string (&addr), " flags noprefixroute ");
-
- addr.flags = IFA_F_MANAGETEMPADDR | IFA_F_NOPREFIXROUTE;
- nmtst_assert_str_has_substr (nm_platform_ip6_address_to_string (&addr), " flags mngtmpaddr,noprefixroute ");
-
- addr.flags = IFA_F_TENTATIVE | IFA_F_NOPREFIXROUTE;
- nmtst_assert_str_has_substr (nm_platform_ip6_address_to_string (&addr), " flags tentative,noprefixroute ");
-
- addr.flags = IFA_F_TENTATIVE | IFA_F_PERMANENT | IFA_F_MANAGETEMPADDR| IFA_F_NOPREFIXROUTE;
- nmtst_assert_str_has_substr (nm_platform_ip6_address_to_string (&addr), " flags tentative,permanent,mngtmpaddr,noprefixroute ");
-
- addr.flags = IFA_F_TENTATIVE | IFA_F_PERMANENT | IFA_F_MANAGETEMPADDR| IFA_F_NOPREFIXROUTE | 0x8000;
- nmtst_assert_str_has_substr (nm_platform_ip6_address_to_string (&addr), " flags tentative,permanent,mngtmpaddr,noprefixroute, ");
-
- addr.flags = IFA_F_TENTATIVE | IFA_F_PERMANENT | IFA_F_MANAGETEMPADDR| IFA_F_NOPREFIXROUTE | ((G_MAXUINT - (G_MAXUINT >> 1)) >> 1);
- nmtst_assert_str_has_substr (nm_platform_ip6_address_to_string (&addr), " flags tentative,permanent,mngtmpaddr,noprefixroute, ");
-}
-
-/******************************************************************/
-
NMTST_DEFINE ();
int
@@ -93,7 +62,6 @@ main (int argc, char **argv)
g_test_add_func ("/general/init_linux_platform", test_init_linux_platform);
g_test_add_func ("/general/link_get_all", test_link_get_all);
- g_test_add_func ("/general/nm_platform_ip6_address_to_string/flags", test_nm_platform_ip6_address_to_string_flags);
return g_test_run ();
}
diff --git a/src/platform/tests/test-link.c b/src/platform/tests/test-link.c
index e6ab6bdd84..9030f0e4df 100644
--- a/src/platform/tests/test-link.c
+++ b/src/platform/tests/test-link.c
@@ -1,5 +1,7 @@
#include "config.h"
+#include "nmp-object.h"
+
#include "test-common.h"
#include "nm-test-utils.h"
@@ -45,7 +47,7 @@ test_bogus(void)
g_assert (!nm_platform_link_supports_carrier_detect (NM_PLATFORM_GET, BOGUS_IFINDEX));
g_assert (!nm_platform_link_supports_vlans (NM_PLATFORM_GET, BOGUS_IFINDEX));
- g_assert (!nm_platform_vlan_get_info (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL, NULL));
+ g_assert (!nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, BOGUS_IFINDEX, NULL));
g_assert (!nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
g_assert (!nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, BOGUS_IFINDEX, 0, 0));
}
@@ -305,7 +307,7 @@ test_software (NMLinkType link_type, const char *link_typename)
{
int ifindex;
char *value;
- int vlan_parent, vlan_id;
+ int vlan_parent = -1, vlan_id;
SignalData *link_added, *link_changed, *link_removed;
@@ -321,7 +323,15 @@ test_software (NMLinkType link_type, const char *link_typename)
link_changed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_CHANGED, link_callback, ifindex);
link_removed = add_signal_ifindex (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_REMOVED, link_callback, ifindex);
if (link_type == NM_LINK_TYPE_VLAN) {
- g_assert (nm_platform_vlan_get_info (NM_PLATFORM_GET, ifindex, &vlan_parent, &vlan_id));
+ const NMPlatformLink *plink;
+ const NMPlatformLnkVlan *plnk;
+
+ plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, &plink);
+ g_assert (plnk);
+ g_assert (plink);
+
+ vlan_parent = plink->parent;
+ vlan_id = plnk->id;
g_assert_cmpint (vlan_parent, ==, nm_platform_link_get_ifindex (NM_PLATFORM_GET, PARENT_NAME));
g_assert_cmpint (vlan_id, ==, VLAN_ID);
}
@@ -430,6 +440,52 @@ test_vlan (void)
test_software (NM_LINK_TYPE_VLAN, "vlan");
}
+/*****************************************************************************/
+
+static void
+test_bridge_addr (void)
+{
+ char addr[ETH_ALEN];
+ NMPlatformLink link;
+ const NMPlatformLink *plink;
+
+ nm_utils_hwaddr_aton ("de:ad:be:ef:00:11", addr, sizeof (addr));
+
+ g_assert_cmpint (nm_platform_bridge_add (NM_PLATFORM_GET, DEVICE_NAME, addr, sizeof (addr), &link), ==, NM_PLATFORM_ERROR_SUCCESS);
+ g_assert_cmpstr (link.name, ==, DEVICE_NAME);
+
+ g_assert_cmpint (link.addr.len, ==, sizeof (addr));
+ g_assert (!memcmp (link.addr.data, addr, sizeof (addr)));
+
+ plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex);
+ g_assert (plink);
+
+ if (nm_platform_check_support_user_ipv6ll (NM_PLATFORM_GET)) {
+ g_assert (!nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex));
+ g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_EUI64);
+
+ g_assert (nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex, TRUE));
+ g_assert (nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex));
+ plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex);
+ g_assert (plink);
+ g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_NONE);
+
+ g_assert (nm_platform_link_set_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex, FALSE));
+ g_assert (!nm_platform_link_get_user_ipv6ll_enabled (NM_PLATFORM_GET, link.ifindex));
+ plink = nm_platform_link_get (NM_PLATFORM_GET, link.ifindex);
+ g_assert (plink);
+ g_assert_cmpint (_nm_platform_uint8_inv (plink->inet6_addr_gen_mode_inv), ==, NM_IN6_ADDR_GEN_MODE_EUI64);
+ }
+
+ g_assert_cmpint (plink->addr.len, ==, sizeof (addr));
+ g_assert (!memcmp (plink->addr.data, addr, sizeof (addr)));
+
+ g_assert (nm_platform_link_delete (NM_PLATFORM_GET, link.ifindex));
+ g_assert (!nm_platform_link_get (NM_PLATFORM_GET, link.ifindex));
+}
+
+/*****************************************************************************/
+
static void
test_internal (void)
{
@@ -511,14 +567,17 @@ test_internal (void)
free_signal (link_removed);
}
+/*****************************************************************************/
+
static void
test_external (void)
{
const NMPlatformLink *pllink;
- SignalData *link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
- SignalData *link_changed, *link_removed;
+ SignalData *link_added, *link_changed, *link_removed;
int ifindex;
+ link_added = add_signal_ifname (NM_PLATFORM_SIGNAL_LINK_CHANGED, NM_PLATFORM_SIGNAL_ADDED, link_callback, DEVICE_NAME);
+
nmtstp_run_command_check ("ip link add %s type %s", DEVICE_NAME, "dummy");
wait_signal (link_added);
@@ -570,6 +629,731 @@ test_external (void)
free_signal (link_removed);
}
+/*****************************************************************************/
+
+typedef struct {
+ NMLinkType link_type;
+ int test_mode;
+} TestAddSoftwareDetectData;
+
+static void
+test_software_detect (gconstpointer user_data)
+{
+ const TestAddSoftwareDetectData *test_data = user_data;
+ int ifindex, ifindex_parent;
+ const NMPlatformLink *plink;
+ const NMPObject *lnk;
+ guint i_step;
+ int exit_code;
+
+ nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME);
+ ifindex_parent = nmtstp_assert_wait_for_link (PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex;
+
+ switch (test_data->link_type) {
+ case NM_LINK_TYPE_GRE: {
+ gboolean gracefully_skip = FALSE;
+
+ if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, "gre0")) {
+ /* Seems that the ip_gre module is not loaded... try to load it. */
+ gracefully_skip = nm_utils_modprobe (NULL, TRUE, "ip_gre", NULL) != 0;
+ }
+ exit_code = nmtstp_run_command ("ip tunnel add %s mode gre remote 172.168.10.25 local 192.168.233.204 ttl 174", DEVICE_NAME);
+ if (exit_code != 0) {
+ if (gracefully_skip) {
+ g_test_skip ("Cannot create gre tunnel because of missing ip_gre module (modprobe ip_gre)");
+ goto out_delete_parent;
+ }
+ g_error ("Failed adding GRE tunnel: exit code %d", exit_code);
+ }
+ break;
+ }
+ case NM_LINK_TYPE_MACVLAN:
+ nmtstp_run_command_check ("ip link add name %s link %s type macvlan", DEVICE_NAME, PARENT_NAME);
+ break;
+ case NM_LINK_TYPE_VLAN:
+ nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1242", DEVICE_NAME, PARENT_NAME);
+ break;
+ case NM_LINK_TYPE_VXLAN:
+ switch (test_data->test_mode) {
+ case 0:
+ nmtstp_run_command_check ("ip link add %s type vxlan id 42 local 23.1.2.164 group 239.1.2.134 dev %s ageing 1245 dstport 4789", DEVICE_NAME, PARENT_NAME);
+ break;
+ case 1:
+ nmtstp_run_command_check ("ip link add %s type vxlan id 11214423 local 1:2:3:4:334:23::23 group ff0e::115 dev %s ageing 3245 dstport 57412", DEVICE_NAME, PARENT_NAME);
+ break;
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ ifindex = nmtstp_assert_wait_for_link (DEVICE_NAME, test_data->link_type, 100)->ifindex;
+
+ nmtstp_link_set_updown (-1, ifindex_parent, TRUE);
+
+ for (i_step = 0; i_step < 5; i_step++) {
+
+ _LOGD ("test-software-detect: step %u", i_step);
+ if (nmtst_is_debug ())
+ nmtstp_run_command_check ("ip -d link show %s", DEVICE_NAME);
+
+ if (i_step > 0) {
+ gboolean set_up = (i_step % 2) == 1;
+
+ if ( test_data->link_type == NM_LINK_TYPE_VXLAN
+ && set_up) {
+ /* On RHEL-7, we need to add a tiny sleep here, otherwise,
+ * upping the vxlan device fails with EADDRINUSE.
+ * https://bugzilla.redhat.com/show_bug.cgi?id=1277131 */
+ g_usleep (1);
+ }
+ nmtstp_link_set_updown (-1, ifindex, set_up);
+ }
+
+ lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, test_data->link_type, &plink);
+ g_assert (plink);
+ g_assert_cmpint (plink->ifindex, ==, ifindex);
+ g_assert (lnk);
+
+ switch (test_data->link_type) {
+ case NM_LINK_TYPE_GRE: {
+ const NMPlatformLnkGre *plnk = &lnk->lnk_gre;
+
+ g_assert (plnk == nm_platform_link_get_lnk_gre (NM_PLATFORM_GET, ifindex, NULL));
+ g_assert_cmpint (plnk->parent_ifindex, ==, 0);
+ g_assert_cmpint (plnk->input_flags, ==, 0);
+ g_assert_cmpint (plnk->output_flags, ==, 0);
+ g_assert_cmpint (plnk->input_key, ==, 0);
+ g_assert_cmpint (plnk->output_key, ==, 0);
+ nmtst_assert_ip4_address (plnk->local, "192.168.233.204");
+ nmtst_assert_ip4_address (plnk->remote, "172.168.10.25");
+ g_assert_cmpint (plnk->ttl, ==, 174);
+ g_assert_cmpint (plnk->tos, ==, 0);
+ g_assert_cmpint (plnk->path_mtu_discovery, ==, TRUE);
+ break;
+ }
+ case NM_LINK_TYPE_MACVLAN: {
+ const NMPlatformLnkMacvlan *plnk = &lnk->lnk_macvlan;
+
+ g_assert (plnk == nm_platform_link_get_lnk_macvlan (NM_PLATFORM_GET, ifindex, NULL));
+ g_assert_cmpint (plnk->no_promisc, ==, FALSE);
+ g_assert_cmpstr (plnk->mode, ==, "vepa");
+ break;
+ }
+ case NM_LINK_TYPE_VLAN: {
+ const NMPlatformLnkVlan *plnk = &lnk->lnk_vlan;
+
+ g_assert (plnk == nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL));
+ g_assert_cmpint (plnk->id, ==, 1242);
+ break;
+ }
+ case NM_LINK_TYPE_VXLAN: {
+ const NMPlatformLnkVxlan *plnk = &lnk->lnk_vxlan;
+
+ g_assert (plnk == nm_platform_link_get_lnk_vxlan (NM_PLATFORM_GET, ifindex, NULL));
+ g_assert_cmpint (plnk->parent_ifindex, !=, 0);
+ g_assert_cmpint (plnk->tos, ==, 0);
+ g_assert_cmpint (plnk->ttl, ==, 0);
+ g_assert_cmpint (plnk->learning, ==, TRUE);
+ g_assert_cmpint (plnk->limit, ==, 0);
+ g_assert_cmpint (plnk->src_port_min, ==, 0);
+ g_assert_cmpint (plnk->src_port_max, ==, 0);
+ g_assert_cmpint (plnk->proxy, ==, FALSE);
+ g_assert_cmpint (plnk->rsc, ==, FALSE);
+ g_assert_cmpint (plnk->l2miss, ==, FALSE);
+ g_assert_cmpint (plnk->l3miss, ==, FALSE);
+
+ switch (test_data->test_mode) {
+ case 0:
+ g_assert_cmpint (plnk->id, ==, 42);
+ nmtst_assert_ip4_address (plnk->local, "23.1.2.164");
+ nmtst_assert_ip4_address (plnk->group, "239.1.2.134");
+ nmtst_assert_ip6_address (&plnk->group6, "::");
+ nmtst_assert_ip6_address (&plnk->local6, "::");
+ g_assert_cmpint (plnk->ageing, ==, 1245);
+ g_assert_cmpint (plnk->dst_port, ==, 4789);
+ break;
+ case 1:
+ g_assert_cmpint (plnk->id, ==, 11214423);
+ nmtst_assert_ip4_address (plnk->local, "0.0.0.0");
+ nmtst_assert_ip4_address (plnk->group, "0.0.0.0");
+ nmtst_assert_ip6_address (&plnk->group6, "ff0e::115");
+ nmtst_assert_ip6_address (&plnk->local6, "1:2:3:4:334:23::23");
+ g_assert_cmpint (plnk->ageing, ==, 3245);
+ g_assert_cmpint (plnk->dst_port, ==, 57412);
+ break;
+ }
+ break;
+ }
+ default:
+ g_assert_not_reached ();
+ }
+ }
+
+ g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
+out_delete_parent:
+ g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex_parent));
+}
+
+static void
+test_software_detect_add (const char *testpath,
+ NMLinkType link_type,
+ int test_mode)
+{
+ TestAddSoftwareDetectData *test_data;
+
+ test_data = g_new0 (TestAddSoftwareDetectData, 1);
+ test_data->link_type = link_type;
+ test_data->test_mode = test_mode;
+
+ g_test_add_data_func_full (testpath, test_data, test_software_detect, g_free);
+}
+
+/*****************************************************************************/
+
+static void
+_assert_xgress_qos_mappings_impl (int ifindex,
+ gboolean is_ingress_map ,
+ int n_entries,
+ int n,
+ ...)
+{
+ const NMPlatformLink *plink;
+ const NMPObject *lnk;
+ guint n_map;
+ const NMVlanQosMapping *map;
+ va_list ap;
+ guint i;
+
+ lnk = nm_platform_link_get_lnk (NM_PLATFORM_GET, ifindex, NM_LINK_TYPE_VLAN, &plink);
+
+ g_assert (plink);
+ g_assert_cmpint (plink->ifindex, ==, ifindex);
+ g_assert (lnk);
+ g_assert (&lnk->lnk_vlan == nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL));
+
+ if (nmtst_is_debug ())
+ nmtstp_run_command_check ("ip -d link show %s", plink->name);
+
+ if (is_ingress_map) {
+ map = lnk->_lnk_vlan.ingress_qos_map;
+ n_map = lnk->_lnk_vlan.n_ingress_qos_map;
+ } else {
+ map = lnk->_lnk_vlan.egress_qos_map;
+ n_map = lnk->_lnk_vlan.n_egress_qos_map;
+ }
+
+ if (n_entries != -1)
+ g_assert_cmpint (n_map, ==, n_entries);
+
+ for (i = 0; i < n_map; i++) {
+ if (is_ingress_map) {
+ g_assert_cmpint (map[i].from, >=, 0);
+ g_assert_cmpint (map[i].from, <=, 7);
+ }
+ if (i > 0)
+ g_assert_cmpint (map[i - 1].from, <, map[i].from);
+ }
+
+ va_start (ap, n);
+ for (; n > 0; n--) {
+ gboolean found = FALSE;
+ guint from = va_arg (ap, guint);
+ guint to = va_arg (ap, guint);
+
+ for (i = 0; i < n_map; i++) {
+ if (map[i].from == from) {
+ g_assert (!found);
+ found = TRUE;
+
+ g_assert (map[i].to == to);
+ }
+ }
+ g_assert (found);
+ }
+ va_end (ap);
+}
+#define _assert_xgress_qos_mappings(ifindex, is_ingress_map, n_entries, ...) \
+ _assert_xgress_qos_mappings_impl ((ifindex), (is_ingress_map), (n_entries), \
+ (G_STATIC_ASSERT_EXPR ((NM_NARG (__VA_ARGS__) % 2) == 0), NM_NARG (__VA_ARGS__) / 2), \
+ __VA_ARGS__)
+#define _assert_ingress_qos_mappings(ifindex, n_entries, ...) _assert_xgress_qos_mappings (ifindex, TRUE, n_entries, __VA_ARGS__)
+#define _assert_egress_qos_mappings(ifindex, n_entries, ...) _assert_xgress_qos_mappings (ifindex, FALSE, n_entries, __VA_ARGS__)
+
+static void
+_assert_vlan_flags (int ifindex, NMVlanFlags flags)
+{
+ const NMPlatformLnkVlan *plnk;
+
+ plnk = nm_platform_link_get_lnk_vlan (NM_PLATFORM_GET, ifindex, NULL);
+ g_assert (plnk);
+ g_assert_cmpint (plnk->flags, ==, flags);
+}
+
+static void
+test_vlan_set_xgress (void)
+{
+ int ifindex, ifindex_parent;
+
+ nmtstp_run_command_check ("ip link add %s type dummy", PARENT_NAME);
+ ifindex_parent = nmtstp_assert_wait_for_link (PARENT_NAME, NM_LINK_TYPE_DUMMY, 100)->ifindex;
+
+ nmtstp_run_command_check ("ip link add name %s link %s type vlan id 1245", DEVICE_NAME, PARENT_NAME);
+ ifindex = nmtstp_assert_wait_for_link (DEVICE_NAME, NM_LINK_TYPE_VLAN, 100)->ifindex;
+
+ /* ingress-qos-map */
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 4, 5));
+ _assert_ingress_qos_mappings (ifindex, 1,
+ 4, 5);
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 7));
+ _assert_ingress_qos_mappings (ifindex, 2,
+ 3, 7,
+ 4, 5);
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 3, 8));
+ _assert_ingress_qos_mappings (ifindex, 2,
+ 3, 8,
+ 4, 5);
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 4));
+ _assert_ingress_qos_mappings (ifindex, 3,
+ 0, 4,
+ 3, 8,
+ 4, 5);
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32));
+ _assert_ingress_qos_mappings (ifindex, 3,
+ 0, G_MAXUINT32,
+ 3, 8,
+ 4, 5);
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, G_MAXUINT32 - 1));
+ _assert_ingress_qos_mappings (ifindex, 3,
+ 0, G_MAXUINT32 - 1,
+ 3, 8,
+ 4, 5);
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 5));
+ _assert_ingress_qos_mappings (ifindex, 3,
+ 0, 5,
+ 3, 8,
+ 4, 5);
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 0, 5));
+ _assert_ingress_qos_mappings (ifindex, 3,
+ 0, 5,
+ 3, 8,
+ 4, 5);
+
+ /* Set invalid values: */
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 8, 3));
+ _assert_ingress_qos_mappings (ifindex, 3,
+ 0, 5,
+ 3, 8,
+ 4, 5);
+
+ g_assert (nm_platform_vlan_set_ingress_map (NM_PLATFORM_GET, ifindex, 9, 4));
+ _assert_ingress_qos_mappings (ifindex, 3,
+ 0, 5,
+ 3, 8,
+ 4, 5);
+
+ /* egress-qos-map */
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 7, 3));
+ _assert_egress_qos_mappings (ifindex, 1,
+ 7, 3);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 4));
+ _assert_egress_qos_mappings (ifindex, 2,
+ 7, 3,
+ 8, 4);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 0, 4));
+ _assert_egress_qos_mappings (ifindex, 3,
+ 0, 4,
+ 7, 3,
+ 8, 4);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 4));
+ _assert_egress_qos_mappings (ifindex, 4,
+ 0, 4,
+ 1, 4,
+ 7, 3,
+ 8, 4);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 5));
+ _assert_egress_qos_mappings (ifindex, 4,
+ 0, 4,
+ 1, 5,
+ 7, 3,
+ 8, 4);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 9, 5));
+ _assert_egress_qos_mappings (ifindex, 5,
+ 0, 4,
+ 1, 5,
+ 7, 3,
+ 8, 4,
+ 9, 5);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 5));
+ _assert_egress_qos_mappings (ifindex, 5,
+ 0, 4,
+ 1, 5,
+ 7, 3,
+ 8, 5,
+ 9, 5);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 8, 0));
+ _assert_egress_qos_mappings (ifindex, 4,
+ 0, 4,
+ 1, 5,
+ 7, 3,
+ 9, 5);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 0, 0));
+ _assert_egress_qos_mappings (ifindex, 3,
+ 1, 5,
+ 7, 3,
+ 9, 5);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 100, 4));
+ _assert_egress_qos_mappings (ifindex, 4,
+ 1, 5,
+ 7, 3,
+ 9, 5,
+ 100, 4);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 4));
+ _assert_egress_qos_mappings (ifindex, 5,
+ 1, 5,
+ 7, 3,
+ 9, 5,
+ 100, 4,
+ G_MAXUINT32, 4);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 8));
+ _assert_egress_qos_mappings (ifindex, 5,
+ 1, 5,
+ 7, 3,
+ 9, 5,
+ 100, 4,
+ G_MAXUINT32, 4);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, G_MAXUINT32, 0));
+ _assert_egress_qos_mappings (ifindex, 4,
+ 1, 5,
+ 7, 3,
+ 9, 5,
+ 100, 4);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 100, 0));
+ _assert_egress_qos_mappings (ifindex, 3,
+ 1, 5,
+ 7, 3,
+ 9, 5);
+
+ g_assert (nm_platform_vlan_set_egress_map (NM_PLATFORM_GET, ifindex, 1, 0));
+ _assert_egress_qos_mappings (ifindex, 2,
+ 7, 3,
+ 9, 5);
+
+ {
+ const NMVlanQosMapping ingress_map[] = {
+ { .from = 1, .to = 5 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ TRUE,
+ ingress_map,
+ G_N_ELEMENTS (ingress_map),
+ FALSE,
+ NULL,
+ 0));
+ _assert_ingress_qos_mappings (ifindex, 1,
+ 1, 5);
+ }
+
+ {
+ const NMVlanQosMapping ingress_map[] = {
+ { .from = 3, .to = 5 },
+ { .from = 7, .to = 1655 },
+ { .from = 7, .to = 17655 },
+ { .from = 5, .to = 754 },
+ { .from = 4, .to = 12 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ TRUE,
+ ingress_map,
+ G_N_ELEMENTS (ingress_map),
+ FALSE,
+ NULL,
+ 0));
+ _assert_ingress_qos_mappings (ifindex, 4,
+ 3, 5,
+ 4, 12,
+ 7, 17655,
+ 5, 754);
+ }
+
+ {
+ const NMVlanQosMapping ingress_map[] = {
+ { .from = 3, .to = 18 },
+ { .from = 6, .to = 121 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ FALSE,
+ ingress_map,
+ G_N_ELEMENTS (ingress_map),
+ FALSE,
+ NULL,
+ 0));
+ _assert_ingress_qos_mappings (ifindex, 5,
+ 3, 18,
+ 4, 12,
+ 6, 121,
+ 7, 17655,
+ 5, 754);
+ }
+
+ {
+ const NMVlanQosMapping ingress_map[] = {
+ { .from = 3, .to = 0 },
+ { .from = 6, .to = 7 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ TRUE,
+ ingress_map,
+ G_N_ELEMENTS (ingress_map),
+ FALSE,
+ NULL,
+ 0));
+ _assert_ingress_qos_mappings (ifindex, 1,
+ 6, 7);
+ }
+
+
+ {
+ const NMVlanQosMapping ingress_map[] = {
+ { .from = 1, .to = 5 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ TRUE,
+ ingress_map,
+ G_N_ELEMENTS (ingress_map),
+ FALSE,
+ NULL,
+ 0));
+ _assert_ingress_qos_mappings (ifindex, 1,
+ 1, 5);
+ }
+
+ {
+ const NMVlanQosMapping egress_map[] = {
+ { .from = 5, .to = 1 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ FALSE,
+ NULL,
+ 0,
+ TRUE,
+ egress_map,
+ G_N_ELEMENTS (egress_map)));
+ _assert_egress_qos_mappings (ifindex, 1,
+ 5, 1);
+ }
+
+ {
+ const NMVlanQosMapping egress_map[] = {
+ { .from = 5, .to = 3 },
+ { .from = 1655, .to = 5 },
+ { .from = 1655, .to = 7 },
+ { .from = G_MAXUINT32, .to = 6 },
+ { .from = G_MAXUINT32, .to = 8 },
+ { .from = 754, .to = 4 },
+ { .from = 3, .to = 2 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ FALSE,
+ NULL,
+ 0,
+ TRUE,
+ egress_map,
+ G_N_ELEMENTS (egress_map)));
+ _assert_egress_qos_mappings (ifindex, 5,
+ 3, 2,
+ 5, 3,
+ 754, 4,
+ 1655, 7,
+ G_MAXUINT32, 6);
+ }
+
+ {
+ const NMVlanQosMapping egress_map[] = {
+ { .from = 754, .to = 3 },
+ { .from = 755, .to = 8 },
+ { .from = 1655, .to = 0 },
+ { .from = 6, .to = 1 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ FALSE,
+ NULL,
+ 0,
+ FALSE,
+ egress_map,
+ G_N_ELEMENTS (egress_map)));
+ _assert_egress_qos_mappings (ifindex, 5,
+ 3, 2,
+ 5, 3,
+ 6, 1,
+ 754, 3,
+ G_MAXUINT32, 6);
+ }
+
+ {
+ const NMVlanQosMapping egress_map[] = {
+ { .from = 6, .to = 0 },
+ { .from = 3, .to = 4 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ FALSE,
+ NULL,
+ 0,
+ TRUE,
+ egress_map,
+ G_N_ELEMENTS (egress_map)));
+ _assert_egress_qos_mappings (ifindex, 1,
+ 3, 4);
+ }
+
+ {
+ const NMVlanQosMapping egress_map[] = {
+ { .from = 1, .to = 5 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ 0,
+ 0,
+ FALSE,
+ NULL,
+ 0,
+ TRUE,
+ egress_map,
+ G_N_ELEMENTS (egress_map)));
+ _assert_egress_qos_mappings (ifindex, 1,
+ 1, 5);
+ }
+
+ {
+ const NMVlanQosMapping ingress_map[] = {
+ { .from = 6, .to = 145 },
+ { .from = 4, .to = 1 },
+ { .from = 6, .to = 12 },
+ };
+ const NMVlanQosMapping egress_map[] = {
+ { .from = 1, .to = 5 },
+ { .from = 3232, .to = 7 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP,
+ NM_VLAN_FLAG_REORDER_HEADERS,
+ TRUE,
+ ingress_map,
+ G_N_ELEMENTS (ingress_map),
+ TRUE,
+ egress_map,
+ G_N_ELEMENTS (egress_map)));
+ _assert_ingress_qos_mappings (ifindex, 2,
+ 4, 1,
+ 6, 12);
+ _assert_egress_qos_mappings (ifindex, 2,
+ 1, 5,
+ 3232, 7);
+ _assert_vlan_flags (ifindex, NM_VLAN_FLAG_REORDER_HEADERS);
+ }
+
+ {
+ const NMVlanQosMapping ingress_map[] = {
+ { .from = 6, .to = 145 },
+ { .from = 4, .to = 1 },
+ { .from = 6, .to = 12 },
+ };
+ const NMVlanQosMapping egress_map[] = {
+ { .from = 1, .to = 7 },
+ { .from = 64, .to = 10 },
+ { .from = 64, .to = 10 },
+ { .from = 64, .to = 10 },
+ { .from = 64, .to = 10 },
+ { .from = 3232, .to = 0 },
+ { .from = 64, .to = 4 },
+ };
+
+ g_assert (nm_platform_link_vlan_change (NM_PLATFORM_GET,
+ ifindex,
+ NM_VLAN_FLAG_GVRP,
+ NM_VLAN_FLAG_GVRP,
+ FALSE,
+ ingress_map,
+ G_N_ELEMENTS (ingress_map),
+ FALSE,
+ egress_map,
+ G_N_ELEMENTS (egress_map)));
+ _assert_ingress_qos_mappings (ifindex, 2,
+ 4, 1,
+ 6, 12);
+ _assert_egress_qos_mappings (ifindex, 2,
+ 1, 7,
+ 64, 4);
+ _assert_vlan_flags (ifindex, NM_VLAN_FLAG_REORDER_HEADERS | NM_VLAN_FLAG_GVRP);
+ }
+
+ g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex));
+ g_assert (nm_platform_link_delete (NM_PLATFORM_GET, ifindex_parent));
+}
+
+/*****************************************************************************/
+
void
init_tests (int *argc, char ***argv)
{
@@ -593,7 +1377,17 @@ setup_tests (void)
g_test_add_func ("/link/software/bond", test_bond);
g_test_add_func ("/link/software/team", test_team);
g_test_add_func ("/link/software/vlan", test_vlan);
+ g_test_add_func ("/link/software/bridge/addr", test_bridge_addr);
- if (strcmp (g_type_name (G_TYPE_FROM_INSTANCE (nm_platform_get ())), "NMFakePlatform"))
+ if (nmtstp_is_root_test ()) {
g_test_add_func ("/link/external", test_external);
+
+ test_software_detect_add ("/link/software/detect/gre", NM_LINK_TYPE_GRE, 0);
+ test_software_detect_add ("/link/software/detect/macvlan", NM_LINK_TYPE_MACVLAN, 0);
+ test_software_detect_add ("/link/software/detect/vlan", NM_LINK_TYPE_VLAN, 0);
+ test_software_detect_add ("/link/software/detect/vxlan/0", NM_LINK_TYPE_VXLAN, 0);
+ test_software_detect_add ("/link/software/detect/vxlan/1", NM_LINK_TYPE_VXLAN, 1);
+
+ g_test_add_func ("/link/software/vlan/set-xgress", test_vlan_set_xgress);
+ }
}
diff --git a/src/platform/wifi/wifi-utils-nl80211.c b/src/platform/wifi/wifi-utils-nl80211.c
index a4d4017bc2..e05104f374 100644
--- a/src/platform/wifi/wifi-utils-nl80211.c
+++ b/src/platform/wifi/wifi-utils-nl80211.c
@@ -28,12 +28,8 @@
#include <net/ethernet.h>
#include <unistd.h>
#include <math.h>
-
-
-#include <netlink/genl/genl.h>
-#include <netlink/genl/family.h>
-#include <netlink/genl/ctrl.h>
-
+#include <netlink/netlink.h>
+#include <netlink/msg.h>
#include <linux/nl80211.h>
#include "nm-default.h"
@@ -42,6 +38,198 @@
#include "nm-platform.h"
#include "nm-utils.h"
+
+/*****************************************************************************
+ * Copied from libnl3/genl:
+ *****************************************************************************/
+
+static void *
+genlmsg_put (struct nl_msg *msg, uint32_t port, uint32_t seq, int family,
+ int hdrlen, int flags, uint8_t cmd, uint8_t version)
+{
+ struct nlmsghdr *nlh;
+ struct genlmsghdr hdr = {
+ .cmd = cmd,
+ .version = version,
+ };
+
+ nlh = nlmsg_put (msg, port, seq, family, GENL_HDRLEN + hdrlen, flags);
+ if (nlh == NULL)
+ return NULL;
+
+ memcpy (nlmsg_data (nlh), &hdr, sizeof (hdr));
+
+ return (char *) nlmsg_data (nlh) + GENL_HDRLEN;
+}
+
+static void *
+genlmsg_data (const struct genlmsghdr *gnlh)
+{
+ return ((unsigned char *) gnlh + GENL_HDRLEN);
+}
+
+static void *
+genlmsg_user_hdr (const struct genlmsghdr *gnlh)
+{
+ return genlmsg_data (gnlh);
+}
+
+static struct genlmsghdr *
+genlmsg_hdr (struct nlmsghdr *nlh)
+{
+ return nlmsg_data (nlh);
+}
+
+static void *
+genlmsg_user_data (const struct genlmsghdr *gnlh, const int hdrlen)
+{
+ return (char *) genlmsg_user_hdr (gnlh) + NLMSG_ALIGN (hdrlen);
+}
+
+static struct nlattr *
+genlmsg_attrdata (const struct genlmsghdr *gnlh, int hdrlen)
+{
+ return genlmsg_user_data (gnlh, hdrlen);
+}
+
+static int
+genlmsg_len (const struct genlmsghdr *gnlh)
+{
+ const struct nlmsghdr *nlh;
+
+ nlh = (const struct nlmsghdr *) ((const unsigned char *) gnlh - NLMSG_HDRLEN);
+ return (nlh->nlmsg_len - GENL_HDRLEN - NLMSG_HDRLEN);
+}
+
+static int
+genlmsg_attrlen (const struct genlmsghdr *gnlh, int hdrlen)
+{
+ return genlmsg_len (gnlh) - NLMSG_ALIGN (hdrlen);
+}
+
+static int
+genlmsg_valid_hdr (struct nlmsghdr *nlh, int hdrlen)
+{
+ struct genlmsghdr *ghdr;
+
+ if (!nlmsg_valid_hdr (nlh, GENL_HDRLEN))
+ return 0;
+
+ ghdr = nlmsg_data (nlh);
+ if (genlmsg_len (ghdr) < NLMSG_ALIGN (hdrlen))
+ return 0;
+
+ return 1;
+}
+
+static int
+genlmsg_parse (struct nlmsghdr *nlh, int hdrlen, struct nlattr *tb[],
+ int maxtype, struct nla_policy *policy)
+{
+ struct genlmsghdr *ghdr;
+
+ if (!genlmsg_valid_hdr (nlh, hdrlen))
+ return -NLE_MSG_TOOSHORT;
+
+ ghdr = nlmsg_data (nlh);
+ return nla_parse (tb, maxtype, genlmsg_attrdata (ghdr, hdrlen),
+ genlmsg_attrlen (ghdr, hdrlen), policy);
+}
+
+/*****************************************************************************
+ * Reimplementation of libnl3/genl functions:
+ *****************************************************************************/
+
+static int
+probe_response (struct nl_msg *msg, void *arg)
+{
+ static struct nla_policy ctrl_policy[CTRL_ATTR_MAX+1] = {
+ [CTRL_ATTR_FAMILY_ID] = { .type = NLA_U16 },
+ [CTRL_ATTR_FAMILY_NAME] = { .type = NLA_STRING,
+ .maxlen = GENL_NAMSIZ },
+ [CTRL_ATTR_VERSION] = { .type = NLA_U32 },
+ [CTRL_ATTR_HDRSIZE] = { .type = NLA_U32 },
+ [CTRL_ATTR_MAXATTR] = { .type = NLA_U32 },
+ [CTRL_ATTR_OPS] = { .type = NLA_NESTED },
+ [CTRL_ATTR_MCAST_GROUPS] = { .type = NLA_NESTED },
+ };
+ struct nlattr *tb[CTRL_ATTR_MAX+1];
+ struct nlmsghdr *nlh = nlmsg_hdr (msg);
+ gint32 *response_data = arg;
+
+ if (genlmsg_parse (nlh, 0, tb, CTRL_ATTR_MAX, ctrl_policy))
+ return NL_SKIP;
+
+ if (tb[CTRL_ATTR_FAMILY_ID])
+ *response_data = nla_get_u16 (tb[CTRL_ATTR_FAMILY_ID]);
+
+ return NL_STOP;
+}
+
+static int
+genl_ctrl_resolve (struct nl_sock *sk, const char *name)
+{
+ struct nl_msg *msg;
+ struct nl_cb *cb, *orig;
+ int rc;
+ int result = -NLE_OBJ_NOTFOUND;
+ gint32 response_data = -1;
+
+ if (!(orig = nl_socket_get_cb (sk)))
+ goto out;
+
+ cb = nl_cb_clone (orig);
+ nl_cb_put (orig);
+ if (!cb)
+ goto out;
+
+ msg = nlmsg_alloc ();
+ if (!msg)
+ goto out_cb_free;
+
+ if (!genlmsg_put (msg, NL_AUTO_PORT, NL_AUTO_SEQ, GENL_ID_CTRL,
+ 0, 0, CTRL_CMD_GETFAMILY, 1))
+ goto out_msg_free;
+
+ if (nla_put_string (msg, CTRL_ATTR_FAMILY_NAME, name) < 0)
+ goto out_msg_free;
+
+ rc = nl_cb_set (cb, NL_CB_VALID, NL_CB_CUSTOM, probe_response, &response_data);
+ if (rc < 0)
+ goto out_msg_free;
+
+ rc = nl_send_auto_complete (sk, msg);
+ if (rc < 0)
+ goto out_msg_free;
+
+ rc = nl_recvmsgs (sk, cb);
+ if (rc < 0)
+ goto out_msg_free;
+
+ /* If search was successful, request may be ACKed after data */
+ rc = nl_wait_for_ack (sk);
+ if (rc < 0)
+ goto out_msg_free;
+
+ if (response_data > 0)
+ result = response_data;
+
+out_msg_free:
+ nlmsg_free (msg);
+out_cb_free:
+ nl_cb_put (cb);
+out:
+ if (result >= 0)
+ nm_log_dbg (LOGD_WIFI, "genl_ctrl_resolve: resolved \"%s\" as 0x%x", name, result);
+ else
+ nm_log_err (LOGD_WIFI, "genl_ctrl_resolve: failed resolve \"%s\"", name);
+ return result;
+}
+
+/*****************************************************************************
+ * </libn-genl-3>
+ *****************************************************************************/
+
typedef struct {
WifiData parent;
struct nl_sock *nl_sock;
@@ -143,7 +331,7 @@ _nl80211_send_and_recv (struct nl_sock *nl_sock,
* not warn on DUMP_INTR error for get scan command.
*/
if (err == -NLE_DUMP_INTR &&
- genlmsg_hdr(nlmsg_hdr(msg))->cmd == NL80211_CMD_GET_SCAN)
+ genlmsg_hdr (nlmsg_hdr (msg))->cmd == NL80211_CMD_GET_SCAN)
break;
nm_log_warn (LOGD_WIFI, "nl_recvmsgs() error: (%d) %s",
@@ -290,7 +478,7 @@ nl80211_xbm_to_percent (gint32 xbm, guint32 divisor)
#define SIGNAL_MAX_DBM -20
xbm /= divisor;
- xbm = CLAMP(xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM);
+ xbm = CLAMP (xbm, NOISE_FLOOR_DBM, SIGNAL_MAX_DBM);
return 100 - 70 * (((float) SIGNAL_MAX_DBM - (float) xbm) /
((float) SIGNAL_MAX_DBM - (float) NOISE_FLOOR_DBM));
@@ -370,7 +558,7 @@ nl80211_bss_dump_handler (struct nl_msg *msg, void *arg)
if (bss[NL80211_BSS_BSSID] == NULL)
return NL_SKIP;
- memcpy(info->bssid, nla_data (bss[NL80211_BSS_BSSID]), ETH_ALEN);
+ memcpy (info->bssid, nla_data (bss[NL80211_BSS_BSSID]), ETH_ALEN);
if (bss[NL80211_BSS_FREQUENCY])
info->freq = nla_get_u32 (bss[NL80211_BSS_FREQUENCY]);
@@ -387,7 +575,7 @@ nl80211_bss_dump_handler (struct nl_msg *msg, void *arg)
guint8 *ssid;
guint32 ssid_len;
- find_ssid(nla_data (bss[NL80211_BSS_INFORMATION_ELEMENTS]),
+ find_ssid (nla_data (bss[NL80211_BSS_INFORMATION_ELEMENTS]),
nla_len (bss[NL80211_BSS_INFORMATION_ELEMENTS]),
&ssid, &ssid_len);
if (ssid && ssid_len && ssid_len <= sizeof (info->ssid)) {
@@ -407,7 +595,7 @@ nl80211_get_bss_info (WifiDataNl80211 *nl80211,
{
struct nl_msg *msg;
- memset(bss_info, 0, sizeof (*bss_info));
+ memset (bss_info, 0, sizeof (*bss_info));
msg = nl80211_alloc_msg (nl80211, NL80211_CMD_GET_SCAN, NLM_F_DUMP);
@@ -450,7 +638,7 @@ wifi_nl80211_get_bssid (WifiData *data, guint8 *out_bssid)
nl80211_get_bss_info (nl80211, &bss_info);
if (bss_info.valid)
- memcpy(out_bssid, bss_info.bssid, ETH_ALEN);
+ memcpy (out_bssid, bss_info.bssid, ETH_ALEN);
return bss_info.valid;
}
@@ -532,7 +720,7 @@ nl80211_get_ap_info (WifiDataNl80211 *nl80211,
struct nl_msg *msg;
struct nl80211_bss_info bss_info;
- memset(sta_info, 0, sizeof (*sta_info));
+ memset (sta_info, 0, sizeof (*sta_info));
nl80211_get_bss_info (nl80211, &bss_info);
if (!bss_info.valid)
@@ -620,7 +808,7 @@ nl80211_wowlan_handler (struct nl_msg *msg, void *arg)
info->enabled = FALSE;
- if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
genlmsg_attrlen (gnlh, 0), NULL) < 0)
return NL_SKIP;
@@ -694,7 +882,7 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
G_STATIC_ASSERT (NL80211_FREQUENCY_ATTR_PASSIVE_SCAN != NL80211_FREQUENCY_ATTR_NO_IBSS);
#endif
- if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
+ if (nla_parse (tb, NL80211_ATTR_MAX, genlmsg_attrdata (gnlh, 0),
genlmsg_attrlen (gnlh, 0), NULL) < 0)
return NL_SKIP;
@@ -742,13 +930,13 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
nla_for_each_nested (nl_band, tb[NL80211_ATTR_WIPHY_BANDS], rem_band) {
if (nla_parse_nested (tb_band, NL80211_BAND_ATTR_MAX, nl_band,
- NULL) < 0)
+ NULL) < 0)
return NL_SKIP;
- nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
- rem_freq) {
+ nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
+ rem_freq) {
nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
- nl_freq, freq_policy);
+ nl_freq, freq_policy);
if (!tb_freq[NL80211_FREQUENCY_ATTR_FREQ])
continue;
@@ -766,7 +954,7 @@ static int nl80211_wiphy_info_handler (struct nl_msg *msg, void *arg)
NULL) < 0)
return NL_SKIP;
- nla_for_each_nested(nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
+ nla_for_each_nested (nl_freq, tb_band[NL80211_BAND_ATTR_FREQS],
rem_freq) {
nla_parse_nested (tb_freq, NL80211_FREQUENCY_ATTR_MAX,
nl_freq, freq_policy);
@@ -867,7 +1055,7 @@ wifi_nl80211_init (const char *iface, int ifindex)
if (nl80211->nl_sock == NULL)
goto error;
- if (genl_connect (nl80211->nl_sock))
+ if (nl_connect (nl80211->nl_sock, NETLINK_GENERIC))
goto error;
nl80211->id = genl_ctrl_resolve (nl80211->nl_sock, "nl80211");
@@ -885,22 +1073,22 @@ wifi_nl80211_init (const char *iface, int ifindex)
if (nl80211_send_and_recv (nl80211, msg, nl80211_wiphy_info_handler,
&device_info) < 0) {
nm_log_dbg (LOGD_HW | LOGD_WIFI,
- "(%s): NL80211_CMD_GET_WIPHY request failed",
- nl80211->parent.iface);
+ "(%s): NL80211_CMD_GET_WIPHY request failed",
+ nl80211->parent.iface);
goto error;
}
if (!device_info.success) {
nm_log_dbg (LOGD_HW | LOGD_WIFI,
- "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
- nl80211->parent.iface);
+ "(%s): NL80211_CMD_GET_WIPHY request indicated failure",
+ nl80211->parent.iface);
goto error;
}
if (!device_info.supported) {
nm_log_dbg (LOGD_HW | LOGD_WIFI,
- "(%s): driver does not fully support nl80211, falling back to WEXT",
- nl80211->parent.iface);
+ "(%s): driver does not fully support nl80211, falling back to WEXT",
+ nl80211->parent.iface);
goto error;
}
@@ -913,8 +1101,8 @@ wifi_nl80211_init (const char *iface, int ifindex)
if (device_info.num_freqs == 0 || device_info.freqs == NULL) {
nm_log_err (LOGD_HW | LOGD_WIFI,
- "(%s): driver reports no supported frequencies",
- nl80211->parent.iface);
+ "(%s): driver reports no supported frequencies",
+ nl80211->parent.iface);
goto error;
}
diff --git a/src/ppp-manager/nm-ppp-manager.c b/src/ppp-manager/nm-ppp-manager.c
index 825cb9b496..7695063398 100644
--- a/src/ppp-manager/nm-ppp-manager.c
+++ b/src/ppp-manager/nm-ppp-manager.c
@@ -470,13 +470,14 @@ impl_ppp_manager_set_ip4_config (NMPPPManager *manager,
memset (&address, 0, sizeof (address));
address.plen = 32;
+ if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32))
+ address.address = u32;
+
if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_GATEWAY, "u", &u32)) {
nm_ip4_config_set_gateway (config, u32);
address.peer_address = u32;
- }
-
- if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_ADDRESS, "u", &u32))
- address.address = u32;
+ } else
+ address.peer_address = address.address;
if (g_variant_lookup (config_dict, NM_PPP_IP4_CONFIG_PREFIX, "u", &u32))
address.plen = u32;
diff --git a/src/tests/test-general.c b/src/tests/test-general.c
index 3985d23ebe..2eb524c3b4 100644
--- a/src/tests/test-general.c
+++ b/src/tests/test-general.c
@@ -971,6 +971,116 @@ test_nm_match_spec_match_config (void)
/*******************************************/
+static void
+test_nm_utils_strbuf_append (void)
+{
+#define BUF_ORIG "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define STR_ORIG "abcdefghijklmnopqrstuvwxyz"
+ int buf_len;
+ int rep;
+ char buf[STRLEN (BUF_ORIG) + 1];
+ char str[STRLEN (BUF_ORIG) + 1];
+
+ for (buf_len = 0; buf_len < 10; buf_len++) {
+ for (rep = 0; rep < 50; rep++) {
+ const int s_len = nmtst_get_rand_int () % (sizeof (str) - 5);
+ char *t_buf;
+ gsize t_len;
+ int test_mode;
+
+ strcpy (str, STR_ORIG);
+ str[s_len] = '\0';
+
+ g_assert_cmpint (str[sizeof (str) - 1], ==, '\0');
+ g_assert_cmpint (strlen (str), ==, s_len);
+
+ strcpy (buf, BUF_ORIG);
+
+ t_buf = buf;
+ t_len = buf_len;
+
+ test_mode = nmtst_get_rand_int () % 4;
+
+ switch (test_mode) {
+ case 0:
+ if (s_len == 1) {
+ nm_utils_strbuf_append_c (&t_buf, &t_len, str[0]);
+ break;
+ }
+ /* fall-through */
+ case 1:
+ nm_utils_strbuf_append_str (&t_buf, &t_len, str);
+ break;
+ case 2:
+ if (s_len == 1) {
+ nm_utils_strbuf_append (&t_buf, &t_len, "%c", str[0]);
+ break;
+ }
+ /* fall-through */
+ case 3:
+ nm_utils_strbuf_append (&t_buf, &t_len, "%s", str);
+ break;
+ }
+
+ /* Assert that the source-buffer is unmodified. */
+ g_assert_cmpint (str[s_len], ==, '\0');
+ str[s_len] = STR_ORIG[s_len];
+ g_assert (!memcmp (str, STR_ORIG, sizeof (str)));
+ str[s_len] = '\0';
+
+ g_assert_cmpint (t_len, >=, 0);
+ g_assert_cmpint (t_len, <=, buf_len);
+ g_assert (t_buf >= buf);
+
+ /* Assert what was written to the destination buffer. */
+ switch (buf_len) {
+ case 0:
+ g_assert_cmpint (t_len, ==, 0);
+ g_assert (t_buf == buf);
+ g_assert (!memcmp (buf, BUF_ORIG, sizeof (buf)));
+ break;
+ case 1:
+ if (s_len == 0) {
+ g_assert_cmpint (t_len, ==, 1);
+ g_assert (t_buf == buf);
+ g_assert (buf[0] == '\0');
+ g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1));
+ } else {
+ g_assert_cmpint (t_len, ==, 0);
+ g_assert (t_buf == &buf[1]);
+ g_assert (buf[0] == '\0');
+ g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1));
+ }
+ break;
+ default:
+ if (s_len == 0) {
+ g_assert_cmpint (t_len, ==, buf_len);
+ g_assert (t_buf == buf);
+ g_assert (buf[0] == '\0');
+ g_assert (!memcmp (&buf[1], &BUF_ORIG[1], sizeof (buf) - 1));
+ } else if (buf_len <= s_len) {
+ g_assert_cmpint (t_len, ==, 0);
+ g_assert (t_buf == &buf[buf_len]);
+ g_assert (!memcmp (buf, STR_ORIG, buf_len - 1));
+ g_assert (buf[buf_len - 1] == '\0');
+ g_assert (!memcmp (&buf[buf_len], &BUF_ORIG[buf_len], sizeof (buf) - buf_len));
+ } else {
+ g_assert_cmpint (t_len, >, 0);
+ g_assert_cmpint (buf_len - t_len, ==, s_len);
+ g_assert_cmpint (strlen (buf), ==, s_len);
+ g_assert (t_buf == &buf[s_len]);
+ g_assert (!memcmp (buf, STR_ORIG, s_len));
+ g_assert (buf[s_len] == '\0');
+ g_assert (!memcmp (&buf[s_len + 1], &BUF_ORIG[s_len + 1], sizeof (buf) - s_len - 1));
+ }
+ break;
+ }
+ }
+ }
+}
+
+/*******************************************/
+
NMTST_DEFINE ();
int
@@ -978,6 +1088,8 @@ main (int argc, char **argv)
{
nmtst_init_with_logging (&argc, &argv, NULL, "ALL");
+ g_test_add_func ("/general/nm_utils_strbuf_append", test_nm_utils_strbuf_append);
+
g_test_add_func ("/general/nm_utils_ip6_address_clear_host_address", test_nm_utils_ip6_address_clear_host_address);
g_test_add_func ("/general/nm_utils_log_connection_diff", test_nm_utils_log_connection_diff);
diff --git a/src/tests/test-ip4-config.c b/src/tests/test-ip4-config.c
index abf623b15a..58fe213b5a 100644
--- a/src/tests/test-ip4-config.c
+++ b/src/tests/test-ip4-config.c
@@ -36,6 +36,8 @@ addr_init (NMPlatformIP4Address *a, const char *addr, const char *peer, guint pl
g_assert (inet_pton (AF_INET, addr, (void *) &a->address) == 1);
if (peer)
g_assert (inet_pton (AF_INET, peer, (void *) &a->peer_address) == 1);
+ else
+ a->peer_address = a->address;
a->plen = plen;
}
@@ -152,7 +154,7 @@ test_subtract (void)
test_addr = nm_ip4_config_get_address (dst, 0);
g_assert (test_addr != NULL);
g_assert_cmpuint (test_addr->address, ==, addr_to_num (expected_addr));
- g_assert_cmpuint (test_addr->peer_address, ==, 0);
+ g_assert_cmpuint (test_addr->peer_address, ==, test_addr->address);
g_assert_cmpuint (test_addr->plen, ==, expected_addr_plen);
g_assert_cmpuint (nm_ip4_config_get_gateway (dst), ==, 0);
diff --git a/src/tests/test-ip6-config.c b/src/tests/test-ip6-config.c
index 8b59f6c477..0977ded43b 100644
--- a/src/tests/test-ip6-config.c
+++ b/src/tests/test-ip6-config.c
@@ -264,8 +264,8 @@ test_nm_ip6_config_addresses_sort_check (NMIP6Config *config, NMSettingIP6Config
if (!nm_ip6_config_equal (copy, config)) {
g_message ("%s", "SORTING yields unexpected output:");
for (i = 0; i < addr_count; i++) {
- g_message (" >> [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i)));
- g_message (" << [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (copy, i)));
+ g_message (" >> [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (config, i), NULL, 0));
+ g_message (" << [%d] = %s", i, nm_platform_ip6_address_to_string (nm_ip6_config_get_address (copy, i), NULL, 0));
}
g_assert_not_reached ();
}
diff --git a/src/tests/test-route-manager.c b/src/tests/test-route-manager.c
index d5902af4bc..eba7d9ef77 100644
--- a/src/tests/test-route-manager.c
+++ b/src/tests/test-route-manager.c
@@ -797,10 +797,12 @@ _assert_route_check (const NMPlatformVTableRoute *vtable, gboolean has, const NM
if (!has) {
g_assert (!r);
} else {
+ char buf[sizeof (_nm_utils_to_string_buffer)];
+
if (!r || vtable->route_cmp (route, r) != 0)
g_error ("Invalid route. Expect %s, has %s",
- nmtst_static_1024_01 (vtable->route_to_string (route)),
- nmtst_static_1024_02 (vtable->route_to_string (r)));
+ vtable->route_to_string (route, NULL, 0),
+ vtable->route_to_string (r, buf, sizeof (buf)));
g_assert (r);
}
}
diff --git a/src/vpn-manager/nm-vpn-connection.c b/src/vpn-manager/nm-vpn-connection.c
index b3ef60bb56..b3ac9d3e05 100644
--- a/src/vpn-manager/nm-vpn-connection.c
+++ b/src/vpn-manager/nm-vpn-connection.c
@@ -1409,6 +1409,8 @@ nm_vpn_connection_ip4_config_get (NMVpnConnection *self, GVariant *dict)
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PTP, "u", &u32))
address.peer_address = u32;
+ else
+ address.peer_address = address.address;
if (g_variant_lookup (dict, NM_VPN_PLUGIN_IP4_CONFIG_PREFIX, "u", &u32))
address.plen = u32;