diff options
author | Thomas Haller <thaller@redhat.com> | 2015-08-17 17:48:37 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2015-08-25 19:24:47 +0200 |
commit | 5618b8a73de1d28239ae12b9b0b38a33176bf159 (patch) | |
tree | 2bd23aadacf41781ffb30ef8093a2519e0f60928 | |
parent | 9f46cb2faa2ec9f13684b96e9fac30a0dfe00e1b (diff) | |
download | NetworkManager-th/platform-parent-other-netns-bgo753726.tar.gz |
platform: handle parent interfaces in other netnsth/platform-parent-other-netns-bgo753726
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.
-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 | 29 | ||||
-rw-r--r-- | src/platform/nm-platform.c | 11 | ||||
-rw-r--r-- | src/platform/nm-platform.h | 6 |
6 files changed, 76 insertions, 26 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 7fde0a7ae0..ac7f6e8aab 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -138,6 +138,7 @@ struct libnl_vtable void *handle; 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 @@ -158,11 +159,14 @@ _nl_get_vtable (void) if (handle) { vtable.handle = handle; vtable.f_nl_has_capability = dlsym (handle, "nl_has_capability"); + vtable.f_rtnl_link_get_link_netnsid = dlsym (handle, "rtnl_link_get_link_netnsid"); } if (!vtable.f_nl_has_capability) vtable.f_nl_has_capability = &_nl_f_nl_has_capability; + debug ("libnl: rtnl_link_get_link_netnsid() %s", vtable.f_rtnl_link_get_link_netnsid ? "supported" : "not supported"); + g_return_val_if_fail (handle, &vtable); g_return_val_if_fail (&nl_connect == (int (*)(struct nl_sock *, int)) dlsym (handle, "nl_connect"), &vtable); } @@ -176,6 +180,20 @@ _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; +} + /* Automatic deallocation of local variables */ #define auto_nl_object __attribute__((cleanup(_nl_auto_nl_object))) static void @@ -981,6 +999,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); @@ -1000,7 +1019,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 fd1f5bd029..b1d4b3b14d 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -446,8 +446,11 @@ 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 (g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent))); + } } } #endif @@ -2359,8 +2362,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 59e8901140..a357918b7e 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. */ |