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

(cherry picked from commit 01580195fa)
This commit is contained in:
Thomas Haller 2015-08-25 22:36:50 +02:00
commit e16ebfb4a6
6 changed files with 93 additions and 30 deletions

View file

@ -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);
}

View file

@ -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:

View file

@ -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,

View file

@ -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
@ -147,24 +150,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;
@ -176,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
@ -981,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);
@ -1000,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);

View file

@ -447,9 +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);
g_warn_if_fail (g_hash_table_contains (unseen, GINT_TO_POINTER (item->parent)));
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
@ -2355,8 +2358,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;

View file

@ -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);