device: delay handling of link-changed platform event
When inside a state-change, we set for example the device up. This triggers a link-changed event, which then causes further state-changes of the devices. A state-change in process of a device is not reentrant, so we must delay the handling of the link-changed event.
This commit is contained in:
@@ -179,6 +179,9 @@ typedef struct {
|
|||||||
gboolean initialized;
|
gboolean initialized;
|
||||||
gboolean platform_link_initialized;
|
gboolean platform_link_initialized;
|
||||||
|
|
||||||
|
guint device_link_changed_id;
|
||||||
|
guint device_ip_link_changed_id;
|
||||||
|
|
||||||
NMDeviceState state;
|
NMDeviceState state;
|
||||||
NMDeviceStateReason state_reason;
|
NMDeviceStateReason state_reason;
|
||||||
QueuedState queued_state;
|
QueuedState queued_state;
|
||||||
@@ -1333,8 +1336,8 @@ device_set_master (NMDevice *self, int ifindex)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
device_link_changed (NMDevice *self, NMPlatformLink *info)
|
device_link_changed (NMDevice *self)
|
||||||
{
|
{
|
||||||
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
|
NMDeviceClass *klass = NM_DEVICE_GET_CLASS (self);
|
||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
@@ -1342,8 +1345,16 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
|||||||
gboolean ip_ifname_changed = FALSE;
|
gboolean ip_ifname_changed = FALSE;
|
||||||
gboolean platform_unmanaged = FALSE;
|
gboolean platform_unmanaged = FALSE;
|
||||||
const char *udi;
|
const char *udi;
|
||||||
|
NMPlatformLink info;
|
||||||
|
int ifindex;
|
||||||
|
|
||||||
udi = nm_platform_link_get_udi (NM_PLATFORM_GET, info->ifindex);
|
priv->device_link_changed_id = 0;
|
||||||
|
|
||||||
|
ifindex = nm_device_get_ifindex (self);
|
||||||
|
if (!nm_platform_link_get (NM_PLATFORM_GET, ifindex, &info))
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
|
||||||
|
udi = nm_platform_link_get_udi (NM_PLATFORM_GET, info.ifindex);
|
||||||
if (udi && g_strcmp0 (udi, priv->udi)) {
|
if (udi && g_strcmp0 (udi, priv->udi)) {
|
||||||
/* Update UDI to what udev gives us */
|
/* Update UDI to what udev gives us */
|
||||||
g_free (priv->udi);
|
g_free (priv->udi);
|
||||||
@@ -1351,24 +1362,24 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
|||||||
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
|
g_object_notify (G_OBJECT (self), NM_DEVICE_UDI);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (g_strcmp0 (info->driver, priv->driver)) {
|
if (g_strcmp0 (info.driver, priv->driver)) {
|
||||||
/* Update driver to what udev gives us */
|
/* Update driver to what udev gives us */
|
||||||
g_free (priv->driver);
|
g_free (priv->driver);
|
||||||
priv->driver = g_strdup (info->driver);
|
priv->driver = g_strdup (info.driver);
|
||||||
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
|
g_object_notify (G_OBJECT (self), NM_DEVICE_DRIVER);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Update MTU if it has changed. */
|
/* Update MTU if it has changed. */
|
||||||
if (priv->mtu != info->mtu) {
|
if (priv->mtu != info.mtu) {
|
||||||
priv->mtu = info->mtu;
|
priv->mtu = info.mtu;
|
||||||
g_object_notify (G_OBJECT (self), NM_DEVICE_MTU);
|
g_object_notify (G_OBJECT (self), NM_DEVICE_MTU);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (info->name[0] && strcmp (priv->iface, info->name) != 0) {
|
if (info.name[0] && strcmp (priv->iface, info.name) != 0) {
|
||||||
_LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'",
|
_LOGI (LOGD_DEVICE, "interface index %d renamed iface from '%s' to '%s'",
|
||||||
priv->ifindex, priv->iface, info->name);
|
priv->ifindex, priv->iface, info.name);
|
||||||
g_free (priv->iface);
|
g_free (priv->iface);
|
||||||
priv->iface = g_strdup (info->name);
|
priv->iface = g_strdup (info.name);
|
||||||
|
|
||||||
/* If the device has no explicit ip_iface, then changing iface changes ip_iface too. */
|
/* If the device has no explicit ip_iface, then changing iface changes ip_iface too. */
|
||||||
ip_ifname_changed = !priv->ip_iface;
|
ip_ifname_changed = !priv->ip_iface;
|
||||||
@@ -1387,10 +1398,10 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Update slave status for external changes */
|
/* Update slave status for external changes */
|
||||||
if (priv->enslaved && info->master != nm_device_get_ifindex (priv->master))
|
if (priv->enslaved && info.master != nm_device_get_ifindex (priv->master))
|
||||||
nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE);
|
nm_device_release_one_slave (priv->master, self, FALSE, NM_DEVICE_STATE_REASON_NONE);
|
||||||
if (info->master && !priv->enslaved) {
|
if (info.master && !priv->enslaved) {
|
||||||
device_set_master (self, info->master);
|
device_set_master (self, info.master);
|
||||||
if (priv->master)
|
if (priv->master)
|
||||||
nm_device_enslave_slave (priv->master, self, NULL);
|
nm_device_enslave_slave (priv->master, self, NULL);
|
||||||
}
|
}
|
||||||
@@ -1402,21 +1413,21 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (klass->link_changed)
|
if (klass->link_changed)
|
||||||
klass->link_changed (self, info);
|
klass->link_changed (self, &info);
|
||||||
|
|
||||||
/* Update DHCP, etc, if needed */
|
/* Update DHCP, etc, if needed */
|
||||||
if (ip_ifname_changed)
|
if (ip_ifname_changed)
|
||||||
update_for_ip_ifname_change (self);
|
update_for_ip_ifname_change (self);
|
||||||
|
|
||||||
if (priv->up != NM_FLAGS_HAS (info->flags, IFF_UP)) {
|
if (priv->up != NM_FLAGS_HAS (info.flags, IFF_UP)) {
|
||||||
priv->up = NM_FLAGS_HAS (info->flags, IFF_UP);
|
priv->up = NM_FLAGS_HAS (info.flags, IFF_UP);
|
||||||
|
|
||||||
/* Manage externally-created software interfaces only when they are IFF_UP */
|
/* Manage externally-created software interfaces only when they are IFF_UP */
|
||||||
g_assert (priv->ifindex > 0);
|
g_assert (priv->ifindex > 0);
|
||||||
if (NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
|
if (NM_DEVICE_GET_CLASS (self)->can_unmanaged_external_down (self)) {
|
||||||
gboolean external_down = nm_device_get_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN);
|
gboolean external_down = nm_device_get_unmanaged_flag (self, NM_UNMANAGED_EXTERNAL_DOWN);
|
||||||
|
|
||||||
if (external_down && NM_FLAGS_HAS (info->flags, IFF_UP)) {
|
if (external_down && NM_FLAGS_HAS (info.flags, IFF_UP)) {
|
||||||
if (nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED) {
|
if (nm_device_get_state (self) < NM_DEVICE_STATE_DISCONNECTED) {
|
||||||
/* Ensure the assume check is queued before any queued state changes
|
/* Ensure the assume check is queued before any queued state changes
|
||||||
* from the transition to UNAVAILABLE.
|
* from the transition to UNAVAILABLE.
|
||||||
@@ -1439,7 +1450,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
|||||||
*/
|
*/
|
||||||
priv->unmanaged_flags &= ~NM_UNMANAGED_EXTERNAL_DOWN;
|
priv->unmanaged_flags &= ~NM_UNMANAGED_EXTERNAL_DOWN;
|
||||||
}
|
}
|
||||||
} else if (!external_down && !NM_FLAGS_HAS (info->flags, IFF_UP) && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) {
|
} else if (!external_down && !NM_FLAGS_HAS (info.flags, IFF_UP) && nm_device_get_state (self) <= NM_DEVICE_STATE_DISCONNECTED) {
|
||||||
/* If the device is already disconnected and is set !IFF_UP,
|
/* If the device is already disconnected and is set !IFF_UP,
|
||||||
* unmanage it.
|
* unmanage it.
|
||||||
*/
|
*/
|
||||||
@@ -1451,7 +1462,7 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (priv->ifindex > 0 && !priv->platform_link_initialized && info->initialized) {
|
if (priv->ifindex > 0 && !priv->platform_link_initialized && info.initialized) {
|
||||||
priv->platform_link_initialized = TRUE;
|
priv->platform_link_initialized = TRUE;
|
||||||
|
|
||||||
if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) {
|
if (nm_platform_link_get_unmanaged (NM_PLATFORM_GET, priv->ifindex, &platform_unmanaged)) {
|
||||||
@@ -1466,23 +1477,34 @@ device_link_changed (NMDevice *self, NMPlatformLink *info)
|
|||||||
FALSE,
|
FALSE,
|
||||||
NM_DEVICE_STATE_REASON_NOW_MANAGED);
|
NM_DEVICE_STATE_REASON_NOW_MANAGED);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static gboolean
|
||||||
device_ip_link_changed (NMDevice *self, NMPlatformLink *info)
|
device_ip_link_changed (NMDevice *self)
|
||||||
{
|
{
|
||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
NMPlatformLink info;
|
||||||
|
int ip_ifindex;
|
||||||
|
|
||||||
if (info->name[0] && g_strcmp0 (priv->ip_iface, info->name)) {
|
priv->device_ip_link_changed_id = 0;
|
||||||
|
|
||||||
|
ip_ifindex = nm_device_get_ip_ifindex (self);
|
||||||
|
if (!nm_platform_link_get (NM_PLATFORM_GET, ip_ifindex, &info))
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
|
|
||||||
|
if (info.name[0] && g_strcmp0 (priv->ip_iface, info.name)) {
|
||||||
_LOGI (LOGD_DEVICE, "interface index %d renamed ip_iface (%d) from '%s' to '%s'",
|
_LOGI (LOGD_DEVICE, "interface index %d renamed ip_iface (%d) from '%s' to '%s'",
|
||||||
priv->ifindex, nm_device_get_ip_ifindex (self),
|
priv->ifindex, nm_device_get_ip_ifindex (self),
|
||||||
priv->ip_iface, info->name);
|
priv->ip_iface, info.name);
|
||||||
g_free (priv->ip_iface);
|
g_free (priv->ip_iface);
|
||||||
priv->ip_iface = g_strdup (info->name);
|
priv->ip_iface = g_strdup (info.name);
|
||||||
|
|
||||||
g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
|
g_object_notify (G_OBJECT (self), NM_DEVICE_IP_IFACE);
|
||||||
update_for_ip_ifname_change (self);
|
update_for_ip_ifname_change (self);
|
||||||
}
|
}
|
||||||
|
return G_SOURCE_REMOVE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -1493,19 +1515,30 @@ link_changed_cb (NMPlatform *platform,
|
|||||||
NMPlatformReason reason,
|
NMPlatformReason reason,
|
||||||
NMDevice *self)
|
NMDevice *self)
|
||||||
{
|
{
|
||||||
|
NMDevicePrivate *priv;
|
||||||
|
|
||||||
if (change_type != NM_PLATFORM_SIGNAL_CHANGED)
|
if (change_type != NM_PLATFORM_SIGNAL_CHANGED)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
/* We don't filter by 'reason' because we are interested in *all* link
|
/* We don't filter by 'reason' because we are interested in *all* link
|
||||||
* changes. For example a call to nm_platform_link_set_up() may result
|
* changes. For example a call to nm_platform_link_set_up() may result
|
||||||
* in an internal carrier change (i.e. we ask the kernel to set IFF_UP
|
* in an internal carrier change (i.e. we ask the kernel to set IFF_UP
|
||||||
* and it results in also setting IFF_LOWER_UP.
|
* and it results in also setting IFF_LOWER_UP.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (ifindex == nm_device_get_ifindex (self))
|
if (ifindex == nm_device_get_ifindex (self)) {
|
||||||
device_link_changed (self, info);
|
if (!priv->device_link_changed_id) {
|
||||||
else if (ifindex == nm_device_get_ip_ifindex (self))
|
priv->device_link_changed_id = g_idle_add ((GSourceFunc) device_link_changed, self);
|
||||||
device_ip_link_changed (self, info);
|
_LOGD (LOGD_DEVICE, "queued link change for ifindex %d", ifindex);
|
||||||
|
}
|
||||||
|
} else if (ifindex == nm_device_get_ip_ifindex (self)) {
|
||||||
|
if (!priv->device_ip_link_changed_id) {
|
||||||
|
priv->device_ip_link_changed_id = g_idle_add ((GSourceFunc) device_ip_link_changed, self);
|
||||||
|
_LOGD (LOGD_DEVICE, "queued link change for ip-ifindex %d", ifindex);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@@ -7136,11 +7169,11 @@ device_ip_changed (NMPlatform *platform,
|
|||||||
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
|
||||||
|
|
||||||
if (nm_device_get_ip_ifindex (self) == ifindex) {
|
if (nm_device_get_ip_ifindex (self) == ifindex) {
|
||||||
if (!priv->queued_ip_config_id)
|
if (!priv->queued_ip_config_id) {
|
||||||
priv->queued_ip_config_id = g_idle_add (queued_ip_config_change, self);
|
priv->queued_ip_config_id = g_idle_add (queued_ip_config_change, self);
|
||||||
|
|
||||||
_LOGD (LOGD_DEVICE, "queued IP config change");
|
_LOGD (LOGD_DEVICE, "queued IP config change");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -8888,6 +8921,9 @@ dispose (GObject *object)
|
|||||||
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ip_changed), self);
|
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (device_ip_changed), self);
|
||||||
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self);
|
g_signal_handlers_disconnect_by_func (platform, G_CALLBACK (link_changed_cb), self);
|
||||||
|
|
||||||
|
nm_clear_g_source (&priv->device_link_changed_id);
|
||||||
|
nm_clear_g_source (&priv->device_ip_link_changed_id);
|
||||||
|
|
||||||
G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
|
G_OBJECT_CLASS (nm_device_parent_class)->dispose (object);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user