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.
This commit is contained in:
@@ -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;
|
||||
|
||||
|
@@ -113,7 +113,10 @@ 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);
|
||||
else
|
||||
parent = NULL;
|
||||
nm_utils_g_value_set_object_path (value, parent);
|
||||
break;
|
||||
case PROP_MODE:
|
||||
|
@@ -151,11 +151,14 @@ realize (NMDevice *device,
|
||||
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,11 +450,14 @@ 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);
|
||||
|
||||
if (parent_ifindex != NM_PLATFORM_LINK_OTHER_NETNS)
|
||||
parent = nm_manager_get_device_by_ifindex (nm_manager_get (), parent_ifindex);
|
||||
g_assert (parent);
|
||||
else
|
||||
parent = NULL;
|
||||
nm_device_vlan_set_parent (NM_DEVICE_VLAN (device), parent);
|
||||
|
||||
/* Update parent in the connection; default to parent's interface name */
|
||||
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)) {
|
||||
@@ -463,6 +470,8 @@ update_connection (NMDevice *device, NMConnection *connection)
|
||||
}
|
||||
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
|
||||
|
@@ -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
|
||||
@@ -156,12 +159,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;
|
||||
@@ -173,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
|
||||
@@ -978,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);
|
||||
|
||||
@@ -997,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);
|
||||
|
||||
|
@@ -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) {
|
||||
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)
|
||||
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;
|
||||
|
||||
|
@@ -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);
|
||||
|
||||
|
Reference in New Issue
Block a user