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:
@@ -5934,6 +5934,7 @@ check_connection_compatible (NMDevice *self, NMConnection *connection, GError **
|
|||||||
conn_iface = nm_manager_get_connection_iface (NM_MANAGER_GET,
|
conn_iface = nm_manager_get_connection_iface (NM_MANAGER_GET,
|
||||||
connection,
|
connection,
|
||||||
NULL,
|
NULL,
|
||||||
|
NULL,
|
||||||
&local);
|
&local);
|
||||||
|
|
||||||
/* We always need a interface name for virtual devices, but for
|
/* We always need a interface name for virtual devices, but for
|
||||||
|
@@ -1715,7 +1715,10 @@ nm_manager_get_state (NMManager *manager)
|
|||||||
/*****************************************************************************/
|
/*****************************************************************************/
|
||||||
|
|
||||||
static NMDevice *
|
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);
|
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||||
NMDeviceFactory *factory;
|
NMDeviceFactory *factory;
|
||||||
@@ -1725,6 +1728,7 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM
|
|||||||
NMDevice *candidate;
|
NMDevice *candidate;
|
||||||
|
|
||||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
|
g_return_val_if_fail (NM_IS_CONNECTION (connection), NULL);
|
||||||
|
NM_SET_OUT (out_parent_spec, NULL);
|
||||||
|
|
||||||
if (!cached_factory) {
|
if (!cached_factory) {
|
||||||
factory = nm_device_factory_manager_find_factory_for_connection (connection);
|
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)
|
if (!parent_name)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
NM_SET_OUT (out_parent_spec, parent_name);
|
||||||
|
|
||||||
/* Try as an interface name of a parent device */
|
/* Try as an interface name of a parent device */
|
||||||
parent = find_device_by_iface (self, parent_name, NULL, NULL);
|
parent = find_device_by_iface (self, parent_name, NULL, NULL);
|
||||||
if (parent)
|
if (parent)
|
||||||
@@ -1778,6 +1784,9 @@ find_parent_device_for_connection (NMManager *self, NMConnection *connection, NM
|
|||||||
* @self: the #NMManager
|
* @self: the #NMManager
|
||||||
* @connection: the #NMConnection to get the interface for
|
* @connection: the #NMConnection to get the interface for
|
||||||
* @out_parent: on success, the parent device if any
|
* @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
|
* @error: an error if determining the virtual interface name failed
|
||||||
*
|
*
|
||||||
* Given @connection, returns the interface name that the connection
|
* Given @connection, returns the interface name that the connection
|
||||||
@@ -1791,14 +1800,15 @@ char *
|
|||||||
nm_manager_get_connection_iface (NMManager *self,
|
nm_manager_get_connection_iface (NMManager *self,
|
||||||
NMConnection *connection,
|
NMConnection *connection,
|
||||||
NMDevice **out_parent,
|
NMDevice **out_parent,
|
||||||
|
const char **out_parent_spec,
|
||||||
GError **error)
|
GError **error)
|
||||||
{
|
{
|
||||||
NMDeviceFactory *factory;
|
NMDeviceFactory *factory;
|
||||||
char *iface = NULL;
|
char *iface = NULL;
|
||||||
NMDevice *parent = NULL;
|
NMDevice *parent = NULL;
|
||||||
|
|
||||||
if (out_parent)
|
NM_SET_OUT (out_parent, NULL);
|
||||||
*out_parent = NULL;
|
NM_SET_OUT (out_parent_spec, NULL);
|
||||||
|
|
||||||
factory = nm_device_factory_manager_find_factory_for_connection (connection);
|
factory = nm_device_factory_manager_find_factory_for_connection (connection);
|
||||||
if (!factory) {
|
if (!factory) {
|
||||||
@@ -1821,7 +1831,7 @@ nm_manager_get_connection_iface (NMManager *self,
|
|||||||
goto return_ifname_fom_connection;
|
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,
|
iface = nm_device_factory_get_connection_iface (factory,
|
||||||
connection,
|
connection,
|
||||||
parent ? nm_device_get_ip_iface (parent) : NULL,
|
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;
|
gs_free NMSettingsConnection **connections = NULL;
|
||||||
guint i;
|
guint i;
|
||||||
gs_free char *iface = NULL;
|
gs_free char *iface = NULL;
|
||||||
|
const char *parent_spec;
|
||||||
NMDevice *device = NULL, *parent = NULL;
|
NMDevice *device = NULL, *parent = NULL;
|
||||||
NMDevice *dev_candidate;
|
NMDevice *dev_candidate;
|
||||||
GError *error = NULL;
|
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_MANAGER (self), NULL);
|
||||||
g_return_val_if_fail (NM_IS_CONNECTION (connection), 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) {
|
if (!iface) {
|
||||||
_LOG3D (LOGD_DEVICE, connection, "can't get a name of a virtual device: %s",
|
_LOG3D (LOGD_DEVICE, connection, "can't get a name of a virtual device: %s",
|
||||||
error->message);
|
error->message);
|
||||||
@@ -1934,6 +1945,11 @@ system_create_virtual_device (NMManager *self, NMConnection *connection)
|
|||||||
return NULL;
|
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 */
|
/* 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) {
|
c_list_for_each_entry (dev_candidate, &priv->devices_lst_head, devices_lst) {
|
||||||
if (nm_device_check_connection_compatible (dev_candidate, connection, NULL)) {
|
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;
|
gs_free char *ifname = NULL;
|
||||||
NMDevice *parent;
|
NMDevice *parent;
|
||||||
|
|
||||||
parent = find_parent_device_for_connection (self, connection, NULL);
|
parent = find_parent_device_for_connection (self, connection, NULL, NULL);
|
||||||
if (parent == device) {
|
if (parent == device) {
|
||||||
/* Only try to activate devices that don't already exist */
|
/* 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 (ifname) {
|
||||||
if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname))
|
if (!nm_platform_link_get_by_ifname (NM_PLATFORM_GET, ifname))
|
||||||
connection_changed (self, sett_conn);
|
connection_changed (self, sett_conn);
|
||||||
@@ -4552,6 +4568,7 @@ _internal_activate_device (NMManager *self, NMActiveConnection *active, GError *
|
|||||||
NMAuthSubject *subject;
|
NMAuthSubject *subject;
|
||||||
GError *local = NULL;
|
GError *local = NULL;
|
||||||
NMConnectionMultiConnect multi_connect;
|
NMConnectionMultiConnect multi_connect;
|
||||||
|
const char *parent_spec;
|
||||||
|
|
||||||
g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
|
g_return_val_if_fail (NM_IS_MANAGER (self), FALSE);
|
||||||
g_return_val_if_fail (NM_IS_ACTIVE_CONNECTION (active), 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,
|
parent = find_parent_device_for_connection (self,
|
||||||
nm_settings_connection_get_connection (sett_conn),
|
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)) {
|
if (parent && !nm_device_is_real (parent)) {
|
||||||
NMSettingsConnection *parent_con;
|
NMSettingsConnection *parent_con;
|
||||||
@@ -5159,7 +5183,7 @@ validate_activation_request (NMManager *self,
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Look for an existing device with the connection's interface name */
|
/* 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)
|
if (!iface)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
|
@@ -149,6 +149,7 @@ void nm_manager_device_route_metric_clear (NMManager *self,
|
|||||||
char * nm_manager_get_connection_iface (NMManager *self,
|
char * nm_manager_get_connection_iface (NMManager *self,
|
||||||
NMConnection *connection,
|
NMConnection *connection,
|
||||||
NMDevice **out_parent,
|
NMDevice **out_parent,
|
||||||
|
const char **out_parent_spec,
|
||||||
GError **error);
|
GError **error);
|
||||||
|
|
||||||
const char * nm_manager_iface_for_uuid (NMManager *self,
|
const char * nm_manager_iface_for_uuid (NMManager *self,
|
||||||
|
Reference in New Issue
Block a user