From a59725d2ad0c5b644a823975a4f299a83ac2edc0 Mon Sep 17 00:00:00 2001 From: Lubomir Rintel Date: Wed, 19 Aug 2015 15:27:41 +0200 Subject: [PATCH 1/6] platform: parent link can be in a different NETNS (cherry picked from commit ced33345d363237141e4e5f1ae80f1dc14b16095) --- src/platform/nm-platform.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index f4b2ca9016..629a759087 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -449,7 +449,6 @@ nm_platform_link_get_all (NMPlatform *self) if (item->parent != 0) { g_warn_if_fail (item->parent > 0); g_warn_if_fail (item->parent != item->ifindex); - g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent))); } } #endif From 4da484f26ce3314a82104060a3cfe0c23f2f8c14 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 17 Aug 2015 17:25:52 +0200 Subject: [PATCH 2/6] platform: assert we loaded the right libnl library (cherry picked from commit 19ebe51e2e62673f929d98be76f6546f82961d10) --- src/platform/nm-linux-platform.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 280c9e442d..656058f5f4 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -164,7 +164,8 @@ _nl_get_vtable (void) if (!vtable.f_nl_has_capability) vtable.f_nl_has_capability = &_nl_f_nl_has_capability; - g_return_val_if_fail (vtable.handle, &vtable); + g_return_val_if_fail (handle, &vtable); + g_return_val_if_fail (&nl_connect == (int (*) (struct nl_sock *, int)) dlsym (handle, "nl_connect"), &vtable); } return &vtable; From 6370f7b92649d85b02cf1463c4cc333e028ab318 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 17 Aug 2015 17:31:44 +0200 Subject: [PATCH 3/6] platform: return const argument from _nl_get_vtable() (cherry picked from commit 2189c7c75bacd2e5445e562270e11f4070d55626) --- src/platform/nm-linux-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 656058f5f4..b0fd484ccb 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -147,7 +147,7 @@ _nl_f_nl_has_capability (int capability) return FALSE; } -static struct libnl_vtable * +static const struct libnl_vtable * _nl_get_vtable (void) { static struct libnl_vtable vtable; From c2c192cd458f229200b577ec4b896ed887c25308 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 17 Aug 2015 18:31:12 +0200 Subject: [PATCH 4/6] platform: minor fix in nm_platform_link_to_string() This had not real consequences, because @master and @parent are of the same size. (cherry picked from commit 677d802be60d1dd21d9bc4dc85ce7edb073021d9) --- src/platform/nm-platform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 629a759087..0180bd156c 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -2355,7 +2355,7 @@ nm_platform_link_to_string (const NMPlatformLink *link) master[0] = 0; if (link->parent) - g_snprintf (parent, sizeof (master), "@%d", link->parent); + g_snprintf (parent, sizeof (parent), "@%d", link->parent); else parent[0] = 0; From 424ff90497853c85565c563f127313b60f478c38 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Tue, 25 Aug 2015 22:24:10 +0200 Subject: [PATCH 5/6] platform: minor refactoring in _nl_get_vtable() (cherry picked from commit 31902f8f6bcafd9efe351d9efcf554b757902007) --- src/platform/nm-linux-platform.c | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index b0fd484ccb..a05af2e522 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -153,19 +153,16 @@ _nl_get_vtable (void) static struct libnl_vtable vtable; if (G_UNLIKELY (!vtable.f_nl_has_capability)) { - void *handle; - - handle = dlopen ("libnl-3.so.200", RTLD_LAZY | RTLD_NOLOAD); - if (handle) { - vtable.handle = handle; - vtable.f_nl_has_capability = dlsym (handle, "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"); } if (!vtable.f_nl_has_capability) vtable.f_nl_has_capability = &_nl_f_nl_has_capability; - g_return_val_if_fail (handle, &vtable); - g_return_val_if_fail (&nl_connect == (int (*) (struct nl_sock *, int)) dlsym (handle, "nl_connect"), &vtable); + g_return_val_if_fail (vtable.handle, &vtable); + g_return_val_if_fail (&nl_connect == (int (*) (struct nl_sock *, int)) dlsym (vtable.handle, "nl_connect"), &vtable); } return &vtable; From 9302639cfe6ab3ae3d51c57810e3352fac26995c Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Mon, 17 Aug 2015 17:48:37 +0200 Subject: [PATCH 6/6] platform: handle parent interfaces in other netns The parent of a link (IFLA_LINK) can be in another network namespace and thus invisible to NM. This requires the netlink attribute IFLA_LINK_NETNSID which is supported by recent versions of kernel and libnl. In this case, set the parent field to NM_PLATFORM_LINK_OTHER_NETNS and properly handle this special case. (cherry picked from commit 790a0713d20d6093ed54c6663953b607f6ea03e9) --- src/devices/nm-device-infiniband.c | 2 +- src/devices/nm-device-macvlan.c | 5 +++- src/devices/nm-device-vlan.c | 39 ++++++++++++++++----------- src/platform/nm-linux-platform.c | 43 +++++++++++++++++++++++++++++- src/platform/nm-platform.c | 12 ++++++--- src/platform/nm-platform.h | 7 +++++ 6 files changed, 87 insertions(+), 21 deletions(-) diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 2e2483c0cf..2d519f6111 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -313,7 +313,7 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, NM_DEVICE_PLATFORM_DEVICE, plink, NM_DEVICE_TYPE_DESC, "InfiniBand", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_INFINIBAND, - NM_DEVICE_INFINIBAND_IS_PARTITION, (plink->parent > 0), + NM_DEVICE_INFINIBAND_IS_PARTITION, (plink->parent > 0 || plink->parent == NM_PLATFORM_LINK_OTHER_NETNS), NULL); } diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 0bfe3fe9fc..2a815cfddb 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -114,7 +114,10 @@ get_property (GObject *object, guint prop_id, switch (prop_id) { case PROP_PARENT: - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); + if (priv->props.parent_ifindex > 0) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), priv->props.parent_ifindex); + else + parent = NULL; g_value_set_boxed (value, parent ? nm_device_get_path (parent) : "/"); break; case PROP_MODE: diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 158e7de5bf..e523e6bb6e 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -181,7 +181,8 @@ component_added (NMDevice *device, GObject *component) return FALSE; } - if (nm_device_get_ifindex (added_device) != parent_ifindex) + if ( parent_ifindex <= 0 + || nm_device_get_ifindex (added_device) != parent_ifindex) return FALSE; nm_device_vlan_set_parent (self, added_device, FALSE); @@ -356,23 +357,28 @@ update_connection (NMDevice *device, NMConnection *connection) if (vlan_id != nm_setting_vlan_get_id (s_vlan)) g_object_set (s_vlan, NM_SETTING_VLAN_ID, priv->vlan_id, NULL); - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); - g_assert (parent); + if (parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + else + parent = NULL; nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent, FALSE); /* Update parent in the connection; default to parent's interface name */ - new_parent = nm_device_get_iface (parent); - setting_parent = nm_setting_vlan_get_parent (s_vlan); - if (setting_parent && nm_utils_is_uuid (setting_parent)) { - NMConnection *parent_connection; + if (parent) { + new_parent = nm_device_get_iface (parent); + setting_parent = nm_setting_vlan_get_parent (s_vlan); + if (setting_parent && nm_utils_is_uuid (setting_parent)) { + NMConnection *parent_connection; - /* Don't change a parent specified by UUID if it's still valid */ - parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent); - if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) - new_parent = NULL; - } - if (new_parent) - g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL); + /* Don't change a parent specified by UUID if it's still valid */ + parent_connection = nm_connection_provider_get_connection_by_uuid (nm_connection_provider_get (), setting_parent); + if (parent_connection && nm_device_check_connection_compatible (parent, parent_connection)) + new_parent = NULL; + } + if (new_parent) + g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, new_parent, NULL); + } else + g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, NULL, NULL); } static NMActStageReturn @@ -628,7 +634,10 @@ new_link (NMDeviceFactory *factory, NMPlatformLink *plink, gboolean *out_ignore, "VLAN parent ifindex unknown"); return NULL; } - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + if (parent_ifindex > 0) + parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); + else + parent = NULL; device = (NMDevice *) g_object_new (NM_TYPE_DEVICE_VLAN, NM_DEVICE_PLATFORM_DEVICE, plink, diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index a05af2e522..383388c1f1 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -91,6 +91,7 @@ } \ } G_STMT_END +#define trace(...) _LOG (LOGL_TRACE, _NMLOG_DOMAIN, NULL, __VA_ARGS__) #define debug(...) _LOG (LOGL_DEBUG, _NMLOG_DOMAIN, NULL, __VA_ARGS__) #define info(...) _LOG (LOGL_INFO, _NMLOG_DOMAIN, NULL, __VA_ARGS__) #define warning(...) _LOG (LOGL_WARN , _NMLOG_DOMAIN, NULL, __VA_ARGS__) @@ -137,8 +138,10 @@ static NMPCacheOpsType cache_remove_netlink (NMPlatform *platform, const NMPObje 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 @@ -157,12 +160,21 @@ _nl_get_vtable (void) 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; + trace ("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 (&nl_connect == (int (*) (struct nl_sock *, int)) dlsym (vtable.handle, "nl_connect"), &vtable); + + g_return_val_if_fail (vtable.handle_route, &vtable); + g_return_val_if_fail (&rtnl_link_alloc == (struct rtnl_link *(*) (void)) dlsym (vtable.handle_route, "rtnl_link_alloc"), &vtable); } return &vtable; @@ -174,6 +186,26 @@ _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 @@ -979,6 +1011,7 @@ _nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_ob 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; nm_assert (memcmp (obj, ((char [sizeof (NMPObjectLink)]) { 0 }), sizeof (NMPObjectLink)) == 0); @@ -998,7 +1031,15 @@ _nmp_vt_cmd_plobj_init_from_nl_link (NMPlatform *platform, NMPlatformObject *_ob obj->flags = rtnl_link_get_flags (nlo); obj->connected = NM_FLAGS_HAS (obj->flags, IFF_LOWER_UP); obj->master = rtnl_link_get_master (nlo); - obj->parent = rtnl_link_get_link (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); diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 0180bd156c..fcb5b06113 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -447,8 +447,12 @@ nm_platform_link_get_all (NMPlatform *self) g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->master))); } if (item->parent != 0) { - g_warn_if_fail (item->parent > 0); - g_warn_if_fail (item->parent != item->ifindex); + 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))); + } } } #endif @@ -2354,8 +2358,10 @@ nm_platform_link_to_string (const NMPlatformLink *link) else master[0] = 0; - if (link->parent) + if (link->parent > 0) g_snprintf (parent, sizeof (parent), "@%d", link->parent); + else if (link->parent == NM_PLATFORM_LINK_OTHER_NETNS) + g_strlcpy (parent, "@other-netns", sizeof (parent)); else parent[0] = 0; diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 4d25419505..3219dd5a74 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -87,6 +87,8 @@ typedef enum { _NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL, } NMPlatformReason; +#define NM_PLATFORM_LINK_OTHER_NETNS (-1) + #define __NMPlatformObject_COMMON \ int ifindex; \ ; @@ -105,6 +107,10 @@ struct _NMPlatformLink { gboolean initialized; int master; + + /* rtnl_link_get_link(), IFLA_LINK. + * If IFLA_LINK_NETNSID indicates that the parent is in another namespace, + * this field be set to (negative) NM_PLATFORM_LINK_OTHER_NETNS. */ int parent; /* rtnl_link_get_arptype(), ifinfomsg.ifi_type. */ @@ -734,6 +740,7 @@ int nm_platform_ip4_route_cmp (const NMPlatformIP4Route *a, const NMPlatformIP4R 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);