manager: don't activate device if the parent is missing

In multiple places we currently proceed to creating a virtual device
even if the connection specifies a parent device which is
missing. This can be easily reproduced with:

  nmcli con add type vxlan ifname vxlan1 \
                vxlan.parent not-exists \
                id 43 remote 172.25.1.1

which creates a vxlan1 interface without activating any
connection. Add a check to prevent this.

https://bugzilla.redhat.com/show_bug.cgi?id=1774074
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/344
This commit is contained in:
Beniamino Galvani
2019-11-21 18:05:11 +01:00
parent 0521e06ff1
commit a73efb059f
3 changed files with 35 additions and 9 deletions

View File

@@ -5934,6 +5934,7 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError **
conn_iface = nm_manager_get_connection_iface (NM_MANAGER_GET,
connection,
NULL,
NULL,
&local);
/* We always need a interface name for virtual devices, but for

View File

@@ -1715,7 +1715,10 @@ nm_manager_get_state (NMManager *manager)
/*****************************************************************************/
static NMDevice *
find_parent_device_for_connection (NMManager *self, NMConnection *connection, NMDeviceFactory *cached_factory)
find_parent_device_for_connection (NMManager *self,
NMConnection *connection,
NMDeviceFactory *cached_factory,
const char **out_parent_spec)
{
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
NMDeviceFactory *factory;
@@ -1725,6 +1728,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM
NMDevice *candidate;
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
NM_SET_OUT (out_parent_spec, NULL);
if (!cached_factory) {
factory = nm_device_factory_manager_find_factory_for_connection (connection);
@@ -1737,6 +1741,8 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM
if (!parent_name)
return NULL;
NM_SET_OUT (out_parent_spec, parent_name);
/* Try as an interface name of a parent device */
parent = find_device_by_iface (self, parent_name, NULL, NULL);
if (parent)
@@ -1778,6 +1784,9 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM
* @self: the #NMManager
* @connection: the #NMConnection to get the interface for
* @out_parent: on success, the parent device if any
* @out_parent_spec: on return, a string specifying the parent device
* in the connection. This can be a device name, a MAC address or a
* connection UUID.
* @error: an error if determining the virtual interface name failed
*
* Given @connection, returns the interface name that the connection
@@ -1791,14 +1800,15 @@ char *
nm_manager_get_connection_iface (NMManager *self,
NMConnection *connection,
NMDevice **out_parent,
const char **out_parent_spec,
GError **error)
{
NMDeviceFactory *factory;
char *iface = NULL;
NMDevice *parent = NULL;
if (out_parent)
*out_parent = NULL;
NM_SET_OUT (out_parent, NULL);
NM_SET_OUT (out_parent_spec, NULL);
factory = nm_device_factory_manager_find_factory_for_connection (connection);
if (!factory) {
@@ -1821,7 +1831,7 @@ nm_manager_get_connection_iface (NMManager *self,
goto return_ifname_fom_connection;
}
parent = find_parent_device_for_connection (self, connection, factory);
parent = find_parent_device_for_connection (self, connection, factory, out_parent_spec);
iface = nm_device_factory_get_connection_iface (factory,
connection,
parent ? nm_device_get_ip_iface (parent) : NULL,
@@ -1918,6 +1928,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
gs_free NMSettingsConnection **connections = NULL;
guint i;
gs_free char *iface = NULL;
const char *parent_spec;
NMDevice *device = NULL, *parent = NULL;
NMDevice *dev_candidate;
GError *error = NULL;
@@ -1926,7 +1937,7 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
g_return_val_if_fail (NM_IS_MANAGER (self), NULL);
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
iface = nm_manager_get_connection_iface (self, connection, &parent, &error);
iface = nm_manager_get_connection_iface (self, connection, &parent, &parent_spec, &error);
if (!iface) {
_LOG3D (LOGD_DEVICE, connection, "can't get a name of a virtual device: %s",
error->message);
@@ -1934,6 +1945,11 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
return NULL;
}
if (parent_spec && !parent) {
/* parent is not ready, wait */
return NULL;
}
/* See if there's a device that is already compatible with this connection */
c_list_for_each_entry (dev_candidate, &priv->devices_lst_head, devices_lst) {
if (nm_device_check_connection_compatible (dev_candidate, connection, NULL)) {
@@ -2047,10 +2063,10 @@ retry_connections_for_parent_device (NMManager *self, NMDevice *device)
gs_free char *ifname = NULL;
NMDevice *parent;
parent = find_parent_device_for_connection (self, connection, NULL);
parent = find_parent_device_for_connection (self, connection, NULL, NULL);
if (parent == device) {
/* Only try to activate devices that don't already exist */
ifname = nm_manager_get_connection_iface (self, connection, &parent, &error);
ifname = nm_manager_get_connection_iface (self, connection, &parent, NULL, &error);
if (ifname) {
if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname))
connection_changed (self, sett_conn);
@@ -4552,6 +4568,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
NMAuthSubject *subject;
GError *local = NULL;
NMConnectionMultiConnect multi_connect;
const char *parent_spec;
g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), FALSE);
@@ -4604,7 +4621,14 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
parent = find_parent_device_for_connection (self,
nm_settings_connection_get_connection (sett_conn),
NULL);
NULL,
&parent_spec);
if (parent_spec && !parent) {
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_DEPENDENCY_FAILED,
"parent device '%s' not found", parent_spec);
return FALSE;
}
if (parent && !nm_device_is_real (parent)) {
NMSettingsConnection *parent_con;
@@ -5159,7 +5183,7 @@ validate_activation_request (NMManager *self,
}
/* Look for an existing device with the connection's interface name */
iface = nm_manager_get_connection_iface (self, connection, NULL, error);
iface = nm_manager_get_connection_iface (self, connection, NULL, NULL, error);
if (!iface)
return NULL;

View File

@@ -149,6 +149,7 @@ void nm_manager_device_route_metric_clear (NMManager *self,
char * nm_manager_get_connection_iface (NMManager *self,
NMConnection *connection,
NMDevice **out_parent,
const char **out_parent_spec,
GError **error);
const char * nm_manager_iface_for_uuid (NMManager *self,