summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2019-11-21 18:05:11 +0100
committerBeniamino Galvani <bgalvani@redhat.com>2019-11-21 18:22:25 +0100
commit1788ca1878970786eea94abeab547e979dce0804 (patch)
treed8da14bea7d0cec6eed6739ea3ce078f405ce665
parent037aa02aba10ed0280d915e0850a4c6b3e517783 (diff)
downloadNetworkManager-bg/device-parent-rh1774074.tar.gz
manager: don't activate device if the parent is missingbg/device-parent-rh1774074
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
-rw-r--r--src/devices/nm-device.c1
-rw-r--r--src/nm-manager.c42
-rw-r--r--src/nm-manager.h1
3 files changed, 35 insertions, 9 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index e7291f0b54..40483be689 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -5887,6 +5887,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
diff --git a/src/nm-manager.c b/src/nm-manager.c
index aff7f587e2..f4cbc6ec2e 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -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;
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 1c71736bcd..ad06e318f4 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -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,