diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2019-11-21 18:05:11 +0100 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2019-11-21 18:22:25 +0100 |
commit | 1788ca1878970786eea94abeab547e979dce0804 (patch) | |
tree | d8da14bea7d0cec6eed6739ea3ce078f405ce665 | |
parent | 037aa02aba10ed0280d915e0850a4c6b3e517783 (diff) | |
download | NetworkManager-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.c | 1 | ||||
-rw-r--r-- | src/nm-manager.c | 42 | ||||
-rw-r--r-- | src/nm-manager.h | 1 |
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, |