mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-05-09 04:48:10 +02:00
device: fix bug when deactivating port connections asynchronously
When the attach_port()/detach_port() methods do not return immediately (currently, only for OVS ports), the following situation can arise: - nm_device_controller_attach_port() starts the attachment by sending the command to ovsdb. Note that here we don't set `PortInfo->port_is_attached` to TRUE yet; that happens only after the asynchronous command returns; - the activation of the port gets interrupted because the connection is deleted; - the port device enters the deactivating state, triggering function port_state_changed() - the function calls nm_device_controller_release_port() which checks whether the port is already attached; since `PortInfo->port_is_attached` is not set yet, it assumes the port doesn't need to be detached; - in the meantime, the ovsdb operation succeeds. As a consequence, the kernel link is created even if the connection no longer exists. Fix this by turning `port_is_attached` into a tri-state variable that also tracks when the port is attaching. When it is, we need to perform an explicit detach during deactivation. Fixes:9fcbc6b37d('device: make attach_port() asynchronous') https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/2043 Resolves: https://issues.redhat.com/browse/RHEL-58026 (cherry picked from commita8329587c8) (cherry picked from commitd809ca6db2) (cherry picked from commitca6ca684b2) (cherry picked from commit83c32e9f17)
This commit is contained in:
parent
c1e83dfdb9
commit
55e8fa129f
1 changed files with 22 additions and 5 deletions
|
|
@ -122,12 +122,18 @@ typedef enum _nm_packed {
|
||||||
ADDR_METHOD_STATE_FAILED,
|
ADDR_METHOD_STATE_FAILED,
|
||||||
} AddrMethodState;
|
} AddrMethodState;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
PORT_STATE_NOT_ATTACHED,
|
||||||
|
PORT_STATE_ATTACHED,
|
||||||
|
PORT_STATE_ATTACHING,
|
||||||
|
} PortState;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
CList lst_slave;
|
CList lst_slave;
|
||||||
NMDevice *slave;
|
NMDevice *slave;
|
||||||
GCancellable *cancellable;
|
GCancellable *cancellable;
|
||||||
gulong watch_id;
|
gulong watch_id;
|
||||||
bool slave_is_enslaved;
|
PortState port_state;
|
||||||
bool configure;
|
bool configure;
|
||||||
} SlaveInfo;
|
} SlaveInfo;
|
||||||
|
|
||||||
|
|
@ -6336,7 +6342,7 @@ attach_port_done(NMDevice *self, NMDevice *slave, gboolean success)
|
||||||
if (!info)
|
if (!info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
info->slave_is_enslaved = success;
|
info->port_state = (success ? PORT_STATE_ATTACHED : PORT_STATE_NOT_ATTACHED);
|
||||||
|
|
||||||
nm_device_slave_notify_enslave(info->slave, success);
|
nm_device_slave_notify_enslave(info->slave, success);
|
||||||
|
|
||||||
|
|
@ -6399,7 +6405,7 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co
|
||||||
if (!info)
|
if (!info)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (info->slave_is_enslaved)
|
if (info->port_state == PORT_STATE_ATTACHED)
|
||||||
success = TRUE;
|
success = TRUE;
|
||||||
else {
|
else {
|
||||||
configure = (info->configure && connection != NULL);
|
configure = (info->configure && connection != NULL);
|
||||||
|
|
@ -6408,6 +6414,7 @@ nm_device_master_enslave_slave(NMDevice *self, NMDevice *slave, NMConnection *co
|
||||||
|
|
||||||
nm_clear_g_cancellable(&info->cancellable);
|
nm_clear_g_cancellable(&info->cancellable);
|
||||||
info->cancellable = g_cancellable_new();
|
info->cancellable = g_cancellable_new();
|
||||||
|
info->port_state = PORT_STATE_ATTACHING;
|
||||||
success = NM_DEVICE_GET_CLASS(self)->attach_port(self,
|
success = NM_DEVICE_GET_CLASS(self)->attach_port(self,
|
||||||
slave,
|
slave,
|
||||||
connection,
|
connection,
|
||||||
|
|
@ -6462,6 +6469,7 @@ nm_device_master_release_slave(NMDevice *self,
|
||||||
SlaveInfo *info;
|
SlaveInfo *info;
|
||||||
gs_unref_object NMDevice *self_free = NULL;
|
gs_unref_object NMDevice *self_free = NULL;
|
||||||
gs_unref_object NMDevice *slave_free = NULL;
|
gs_unref_object NMDevice *slave_free = NULL;
|
||||||
|
const char *port_state_str;
|
||||||
|
|
||||||
g_return_if_fail(NM_DEVICE(self));
|
g_return_if_fail(NM_DEVICE(self));
|
||||||
g_return_if_fail(NM_DEVICE(slave));
|
g_return_if_fail(NM_DEVICE(slave));
|
||||||
|
|
@ -6473,11 +6481,20 @@ nm_device_master_release_slave(NMDevice *self,
|
||||||
|
|
||||||
info = find_slave_info(self, slave);
|
info = find_slave_info(self, slave);
|
||||||
|
|
||||||
|
if (info->port_state == PORT_STATE_ATTACHED)
|
||||||
|
port_state_str = "(attached)";
|
||||||
|
else if (info->port_state == PORT_STATE_NOT_ATTACHED)
|
||||||
|
port_state_str = "(not attached)";
|
||||||
|
else {
|
||||||
|
nm_assert(info->port_state == PORT_STATE_ATTACHING);
|
||||||
|
port_state_str = "(attaching)";
|
||||||
|
}
|
||||||
|
|
||||||
_LOGT(LOGD_CORE,
|
_LOGT(LOGD_CORE,
|
||||||
"master: release one slave " NM_HASH_OBFUSCATE_PTR_FMT "/%s %s%s",
|
"master: release one slave " NM_HASH_OBFUSCATE_PTR_FMT "/%s %s%s",
|
||||||
NM_HASH_OBFUSCATE_PTR(slave),
|
NM_HASH_OBFUSCATE_PTR(slave),
|
||||||
nm_device_get_iface(slave),
|
nm_device_get_iface(slave),
|
||||||
!info ? "(not registered)" : (info->slave_is_enslaved ? "(enslaved)" : "(not enslaved)"),
|
!info ? "(not registered)" : port_state_str,
|
||||||
release_type == RELEASE_SLAVE_TYPE_CONFIG_FORCE
|
release_type == RELEASE_SLAVE_TYPE_CONFIG_FORCE
|
||||||
? " (force-configure)"
|
? " (force-configure)"
|
||||||
: (release_type == RELEASE_SLAVE_TYPE_CONFIG ? " (configure)" : "(no-config)"));
|
: (release_type == RELEASE_SLAVE_TYPE_CONFIG ? " (configure)" : "(no-config)"));
|
||||||
|
|
@ -6493,7 +6510,7 @@ nm_device_master_release_slave(NMDevice *self,
|
||||||
nm_clear_g_cancellable(&info->cancellable);
|
nm_clear_g_cancellable(&info->cancellable);
|
||||||
|
|
||||||
/* first, let subclasses handle the release ... */
|
/* first, let subclasses handle the release ... */
|
||||||
if (info->slave_is_enslaved || nm_device_sys_iface_state_is_external(slave)
|
if (info->port_state != PORT_STATE_NOT_ATTACHED || nm_device_sys_iface_state_is_external(slave)
|
||||||
|| release_type >= RELEASE_SLAVE_TYPE_CONFIG_FORCE) {
|
|| release_type >= RELEASE_SLAVE_TYPE_CONFIG_FORCE) {
|
||||||
NMTernary ret;
|
NMTernary ret;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue