diff options
author | Thomas Haller <thaller@redhat.com> | 2015-08-25 22:36:50 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-08-25 22:36:54 +0200 |
commit | 01580195fabbf59c903ffa9ba307820c62164db0 (patch) | |
tree | b0fcace483cbf9466508562b8dc74ff0a3c3c65b | |
parent | 803fc616fd9d1f9cf6e92c6e1530fef16fc0c0d9 (diff) | |
parent | 790a0713d20d6093ed54c6663953b607f6ea03e9 (diff) | |
download | NetworkManager-01580195fabbf59c903ffa9ba307820c62164db0.tar.gz |
platform: merge branch 'th/platform-parent-other-netns-bgo753726'
Add support for IFLA_LINK_NETNSID to properly handle linked parent
interfaces that reside in another netns.
This requires support of the IFLA_LINK_NETNSID from both the kernel
and libnl3.
https://bugzilla.gnome.org/show_bug.cgi?id=753726
-rw-r--r-- | src/devices/nm-device-infiniband.c | 2 | ||||
-rw-r--r-- | src/devices/nm-device-macvlan.c | 5 | ||||
-rw-r--r-- | src/devices/nm-device-vlan.c | 49 | ||||
-rw-r--r-- | src/platform/nm-linux-platform.c | 55 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 14 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 7 |
6 files changed, 98 insertions, 34 deletions
diff --git a/src/devices/nm-device-infiniband.c b/src/devices/nm-device-infiniband.c index 13ee252bb4..df50cb6019 100644 --- a/src/devices/nm-device-infiniband.c +++ b/src/devices/nm-device-infiniband.c @@ -368,7 +368,7 @@ create_device (NMDeviceFactory *factory, gboolean is_partition = FALSE; if (plink) - is_partition = (plink->parent > 0); + is_partition = (plink->parent > 0 || plink->parent == NM_PLATFORM_LINK_OTHER_NETNS); else if (connection) { NMSettingInfiniband *s_infiniband; diff --git a/src/devices/nm-device-macvlan.c b/src/devices/nm-device-macvlan.c index 743e2db21e..26ea0be9b7 100644 --- a/src/devices/nm-device-macvlan.c +++ b/src/devices/nm-device-macvlan.c @@ -113,7 +113,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; nm_utils_g_value_set_object_path (value, parent); break; case PROP_MODE: diff --git a/src/devices/nm-device-vlan.c b/src/devices/nm-device-vlan.c index 4306d16887..a4117f03a6 100644 --- a/src/devices/nm-device-vlan.c +++ b/src/devices/nm-device-vlan.c @@ -151,11 +151,14 @@ realize (NMDevice *device, return FALSE; } - parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex); - if (!parent) { - nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", 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 (!parent) { + nm_log_dbg (LOGD_HW, "(%s): VLAN parent interface unknown", plink->name); + return FALSE; + } + } else + parent = NULL; g_warn_if_fail (priv->parent == NULL); nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent); @@ -271,7 +274,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); @@ -446,23 +450,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); /* 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; - - /* 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); + 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); + } else + g_object_set (s_vlan, NM_SETTING_VLAN_PARENT, NULL, NULL); } static NMActStageReturn diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 0c5d725203..c69ca68139 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -90,6 +90,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__) @@ -136,8 +137,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 @@ -146,24 +149,31 @@ _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; 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"); + } + 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; @@ -175,6 +185,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 @@ -980,6 +1010,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); @@ -999,7 +1030,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 5888ed5c87..1549321db4 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -446,8 +446,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 @@ -2359,8 +2363,10 @@ nm_platform_link_to_string (const NMPlatformLink *link) else master[0] = 0; - if (link->parent) - g_snprintf (parent, sizeof (master), "@%d", 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 59e8901140..756101c8fc 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -85,6 +85,8 @@ typedef enum { _NM_PLATFORM_REASON_CACHE_CHECK_INTERNAL, } NMPlatformReason; +#define NM_PLATFORM_LINK_OTHER_NETNS (-1) + #define __NMPlatformObject_COMMON \ int ifindex; \ ; @@ -103,6 +105,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. */ @@ -733,6 +739,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); |