From fe307dbd3e22203b10cf1f1fcaffb14b52a0a347 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Mon, 12 Nov 2012 13:29:06 -0500 Subject: [PATCH] core: move carrier-detect NMDeviceState handling into NMDevice Move some duplicated carrier-handling code into NMDevice (which can introspect itself to see if it's a subclass that has carrier). The "mostly ignore carrier" special handling for bridges and bonds is now also handled as part of the NMDevice-level carrier handling. https://bugzilla.gnome.org/show_bug.cgi?id=688284 --- src/nm-device-adsl.c | 15 ------ src/nm-device-bond.c | 20 ------- src/nm-device-bridge.c | 17 ------ src/nm-device-vlan.c | 76 +++------------------------ src/nm-device-wired.c | 113 +++------------------------------------- src/nm-device-wired.h | 3 -- src/nm-device.c | 115 +++++++++++++++++++++++++++++++++++++++++ 7 files changed, 127 insertions(+), 232 deletions(-) diff --git a/src/nm-device-adsl.c b/src/nm-device-adsl.c index db678d9f27..dd03699389 100644 --- a/src/nm-device-adsl.c +++ b/src/nm-device-adsl.c @@ -608,7 +608,6 @@ static void set_carrier (NMDeviceAdsl *self, const gboolean carrier) { NMDeviceAdslPrivate *priv; - NMDeviceState state; g_return_if_fail (NM_IS_DEVICE (self)); @@ -619,20 +618,6 @@ set_carrier (NMDeviceAdsl *self, const gboolean carrier) priv->carrier = carrier; g_object_notify (G_OBJECT (self), NM_DEVICE_ADSL_CARRIER); - - state = nm_device_get_state (NM_DEVICE (self)); - nm_log_info (LOGD_HW, "(%s): carrier now %s (device state %d)", - nm_device_get_iface (NM_DEVICE (self)), - carrier ? "ON" : "OFF", - state); - - if (state == NM_DEVICE_STATE_UNAVAILABLE) { - if (priv->carrier) - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); - } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { - if (!priv->carrier) - nm_device_state_changed (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); - } } static gboolean diff --git a/src/nm-device-bond.c b/src/nm-device-bond.c index 7f47a3a628..21d78575a9 100644 --- a/src/nm-device-bond.c +++ b/src/nm-device-bond.c @@ -80,23 +80,6 @@ nm_bond_error_quark (void) /******************************************************************/ -static void -carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier) -{ - /* Carrier can't be used to signal availability of the bond master because - * the bond's carrier follows the slaves' carriers. So carrier gets - * ignored when determining whether or not the device can be activated. - * - * Second, just because all slaves have been removed or have lost carrier - * does not mean the master should be deactivated. This could be due to - * user addition/removal of slaves, and is also normal operation with some - * failover modes. - * - * For these reasons, carrier changes are effectively ignored by overriding - * the parent class' carrier handling and doing nothing. - */ -} - static void update_hw_address (NMDevice *dev) { @@ -463,7 +446,6 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - NMDeviceWiredClass *wired_class = NM_DEVICE_WIRED_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMDeviceBondPrivate)); @@ -487,8 +469,6 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; - wired_class->carrier_action = carrier_action; - /* properties */ g_object_class_install_property (object_class, PROP_HW_ADDRESS, diff --git a/src/nm-device-bridge.c b/src/nm-device-bridge.c index 39275c8b41..1ec8305a37 100644 --- a/src/nm-device-bridge.c +++ b/src/nm-device-bridge.c @@ -80,20 +80,6 @@ nm_bridge_error_quark (void) /******************************************************************/ -static void -carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier) -{ - /* Bridge carrier state follows IFF_UP with no ports, and port carrier - * states when ports are added. Thus carrier isn't useful when deciding - * to auto-activate the bridge master. Also, like bond masters, when the - * carrier state changes due to slave changes, we shouldn't deactivate the - * bridge since the user may be reconfiguring ports. - * - * For these reasons, carrier changes are effectively ignored by overriding - * the parent class' carrier handling and doing nothing. - */ -} - static void update_hw_address (NMDevice *dev) { @@ -516,7 +502,6 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - NMDeviceWiredClass *wired_class = NM_DEVICE_WIRED_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMDeviceBridgePrivate)); @@ -540,8 +525,6 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; - wired_class->carrier_action = carrier_action; - /* properties */ g_object_class_install_property (object_class, PROP_HW_ADDRESS, diff --git a/src/nm-device-vlan.c b/src/nm-device-vlan.c index d8e1f3c1d4..c224fcfd0f 100644 --- a/src/nm-device-vlan.c +++ b/src/nm-device-vlan.c @@ -61,7 +61,6 @@ typedef struct { NMNetlinkMonitor *monitor; gulong link_connected_id; gulong link_disconnected_id; - guint carrier_action_defer_id; } NMDeviceVlanPrivate; enum { @@ -83,8 +82,7 @@ enum { static void set_carrier (NMDeviceVlan *self, - const gboolean carrier, - const gboolean defer_action); + const gboolean carrier); /******************************************************************/ @@ -147,7 +145,7 @@ hw_bring_up (NMDevice *dev, gboolean *no_firmware) i = 20; while (i-- > 0) { carrier = get_carrier_sync (NM_DEVICE_VLAN (dev)); - set_carrier (NM_DEVICE_VLAN (dev), carrier, carrier ? FALSE : TRUE); + set_carrier (NM_DEVICE_VLAN (dev), carrier); if (carrier) break; g_usleep (100); @@ -441,66 +439,17 @@ connection_match_config (NMDevice *self, const GSList *connections) /******************************************************************/ -static void -carrier_action_defer_clear (NMDeviceVlan *self) -{ - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - - if (priv->carrier_action_defer_id) { - g_source_remove (priv->carrier_action_defer_id); - priv->carrier_action_defer_id = 0; - } -} - -static gboolean -carrier_action_defer_cb (gpointer user_data) -{ - NMDeviceVlan *self = NM_DEVICE_VLAN (user_data); - NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - NMDeviceState state; - - priv->carrier_action_defer_id = 0; - - state = nm_device_get_state (NM_DEVICE (self)); - if (state == NM_DEVICE_STATE_UNAVAILABLE) { - if (priv->carrier) - nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); - } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { - if (!priv->carrier) - nm_device_queue_state (NM_DEVICE (self), NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); - } - return FALSE; -} - static void set_carrier (NMDeviceVlan *self, - const gboolean carrier, - const gboolean defer_action) + const gboolean carrier) { NMDeviceVlanPrivate *priv = NM_DEVICE_VLAN_GET_PRIVATE (self); - NMDeviceState state; if (priv->carrier == carrier) return; - /* Clear any previous deferred action */ - carrier_action_defer_clear (self); - priv->carrier = carrier; g_object_notify (G_OBJECT (self), NM_DEVICE_VLAN_CARRIER); - - state = nm_device_get_state (NM_DEVICE (self)); - nm_log_info (LOGD_HW | LOGD_VLAN, - "(%s): carrier now %s (device state %d%s)", - nm_device_get_iface (NM_DEVICE (self)), - carrier ? "ON" : "OFF", - state, - defer_action ? ", deferring action for 4 seconds" : ""); - - if (defer_action) - priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self); - else - carrier_action_defer_cb (self); } static void @@ -508,27 +457,15 @@ carrier_on (NMNetlinkMonitor *monitor, int idx, NMDevice *device) { /* Make sure signal is for us */ if (idx == nm_device_get_ifindex (device)) - set_carrier (NM_DEVICE_VLAN (device), TRUE, FALSE); + set_carrier (NM_DEVICE_VLAN (device), TRUE); } static void carrier_off (NMNetlinkMonitor *monitor, int idx, NMDevice *device) { - NMDeviceState state; - gboolean defer = FALSE; - /* Make sure signal is for us */ - if (idx == nm_device_get_ifindex (device)) { - /* Defer carrier-off event actions while connected by a few seconds - * so that tripping over a cable, power-cycling a switch, or breaking - * off the RJ45 locking tab isn't so catastrophic. - */ - state = nm_device_get_state (device); - if (state > NM_DEVICE_STATE_DISCONNECTED) - defer = TRUE; - - set_carrier (NM_DEVICE_VLAN (device), FALSE, defer); - } + if (idx == nm_device_get_ifindex (device)) + set_carrier (NM_DEVICE_VLAN (device), FALSE); } static void @@ -704,7 +641,6 @@ dispose (GObject *object) g_signal_handler_disconnect (priv->monitor, priv->link_connected_id); if (priv->link_disconnected_id) g_signal_handler_disconnect (priv->monitor, priv->link_disconnected_id); - carrier_action_defer_clear (self); g_object_unref (priv->monitor); diff --git a/src/nm-device-wired.c b/src/nm-device-wired.c index 6d4596302a..fef10b63a9 100644 --- a/src/nm-device-wired.c +++ b/src/nm-device-wired.c @@ -55,7 +55,6 @@ typedef struct { NMNetlinkMonitor * monitor; gulong link_connected_id; gulong link_disconnected_id; - guint carrier_action_defer_id; } NMDeviceWiredPrivate; @@ -120,67 +119,17 @@ set_speed (NMDeviceWired *self, const guint32 speed) speed); } -static void -carrier_action_defer_clear (NMDeviceWired *self) -{ - NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); - - if (priv->carrier_action_defer_id) { - g_source_remove (priv->carrier_action_defer_id); - priv->carrier_action_defer_id = 0; - } -} - -static void -carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier) -{ - NMDevice *device = NM_DEVICE (self); - - if (state == NM_DEVICE_STATE_UNAVAILABLE) { - if (carrier) - nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); - else { - /* clear any queued state changes if they wouldn't be valid when the - * carrier is off. - */ - if (nm_device_queued_state_peek (device) >= NM_DEVICE_STATE_DISCONNECTED) - nm_device_queued_state_clear (device); - } - } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { - if (!carrier && !nm_device_get_enslaved (device)) - nm_device_queue_state (device, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); - } -} - -static gboolean -carrier_action_defer_cb (gpointer user_data) -{ - NMDeviceWired *self = NM_DEVICE_WIRED (user_data); - NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); - - priv->carrier_action_defer_id = 0; - NM_DEVICE_WIRED_GET_CLASS (self)->carrier_action (self, - nm_device_get_state (NM_DEVICE (self)), - priv->carrier); - return FALSE; -} - static void set_carrier (NMDeviceWired *self, - const gboolean carrier, - const gboolean defer_action) + gboolean carrier) { - NMDeviceWiredPrivate *priv = NM_DEVICE_WIRED_GET_PRIVATE (self); NMDevice *device = NM_DEVICE (self); - NMDeviceState state; + NMDeviceWiredPrivate *priv; guint32 caps; if (priv->carrier == carrier) return; - /* Clear any previous deferred action */ - carrier_action_defer_clear (self); - /* Warn if we try to set carrier down on a device that * doesn't support carrier detect. These devices assume * the carrier is always up. @@ -189,32 +138,7 @@ set_carrier (NMDeviceWired *self, g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT); priv->carrier = carrier; - - state = nm_device_get_state (device); - if (state >= NM_DEVICE_STATE_UNAVAILABLE) { - nm_log_info (LOGD_HW | NM_DEVICE_WIRED_LOG_LEVEL (device), - "(%s): carrier now %s (device state %d%s)", - nm_device_get_iface (device), - carrier ? "ON" : "OFF", - state, - defer_action ? ", deferring action for 4 seconds" : ""); - } - g_object_notify (G_OBJECT (self), "carrier"); - - /* Retry IP configuration for master devices now that the carrier is on */ - if (nm_device_is_master (device) && priv->carrier) { - if (nm_device_activate_ip4_state_in_wait (device)) - nm_device_activate_stage3_ip4_start (device); - - if (nm_device_activate_ip6_state_in_wait (device)) - nm_device_activate_stage3_ip6_start (device); - } - - if (defer_action) - priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self); - else - carrier_action_defer_cb (self); } static void @@ -224,14 +148,10 @@ carrier_on (NMNetlinkMonitor *monitor, { NMDevice *device = NM_DEVICE (user_data); NMDeviceWired *self = NM_DEVICE_WIRED (device); - guint32 caps; /* Make sure signal is for us */ if (idx == nm_device_get_ifindex (device)) { - caps = nm_device_get_capabilities (device); - g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT); - - set_carrier (self, TRUE, FALSE); + set_carrier (self, TRUE); set_speed (self, ethtool_get_speed (self)); } } @@ -243,26 +163,10 @@ carrier_off (NMNetlinkMonitor *monitor, { NMDevice *device = NM_DEVICE (user_data); NMDeviceWired *self = NM_DEVICE_WIRED (device); - guint32 caps; /* Make sure signal is for us */ - if (idx == nm_device_get_ifindex (device)) { - NMDeviceState state; - gboolean defer = FALSE; - - caps = nm_device_get_capabilities (device); - g_return_if_fail (caps & NM_DEVICE_CAP_CARRIER_DETECT); - - /* Defer carrier-off event actions while connected by a few seconds - * so that tripping over a cable, power-cycling a switch, or breaking - * off the RJ45 locking tab isn't so catastrophic. - */ - state = nm_device_get_state (device); - if (state > NM_DEVICE_STATE_DISCONNECTED) - defer = TRUE; - - set_carrier (self, FALSE, defer); - } + if (idx == nm_device_get_ifindex (device)) + set_carrier (self, FALSE); } static gboolean @@ -362,7 +266,7 @@ hw_bring_up (NMDevice *dev, gboolean *no_firmware) caps = nm_device_get_capabilities (dev); if (caps & NM_DEVICE_CAP_CARRIER_DETECT) { carrier = get_carrier_sync (NM_DEVICE_WIRED (dev)); - set_carrier (NM_DEVICE_WIRED (dev), carrier, carrier ? FALSE : TRUE); + set_carrier (NM_DEVICE_WIRED (dev), carrier); } } return result; @@ -458,8 +362,6 @@ dispose (GObject *object) priv->link_disconnected_id = 0; } - carrier_action_defer_clear (self); - if (priv->monitor) { g_object_unref (priv->monitor); priv->monitor = NULL; @@ -473,7 +375,6 @@ nm_device_wired_class_init (NMDeviceWiredClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMDeviceClass *parent_class = NM_DEVICE_CLASS (klass); - NMDeviceWiredClass *wired_class = NM_DEVICE_WIRED_CLASS (klass); g_type_class_add_private (object_class, sizeof (NMDeviceWiredPrivate)); @@ -487,8 +388,6 @@ nm_device_wired_class_init (NMDeviceWiredClass *klass) parent_class->connection_match_config = connection_match_config; parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; - - wired_class->carrier_action = carrier_action; } /** diff --git a/src/nm-device-wired.h b/src/nm-device-wired.h index a808435217..c88f2b8f3e 100644 --- a/src/nm-device-wired.h +++ b/src/nm-device-wired.h @@ -42,9 +42,6 @@ typedef struct { typedef struct { NMDeviceClass parent; - void (*carrier_action) (NMDeviceWired *self, - NMDeviceState state, - gboolean carrier); } NMDeviceWiredClass; GType nm_device_wired_get_type (void); diff --git a/src/nm-device.c b/src/nm-device.c index 089aebb0f5..bd7d70b50a 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -262,6 +262,10 @@ typedef struct { guint cp_loaded_id; guint cp_removed_id; guint cp_updated_id; + + /* Deferred carrier handling */ + guint carrier_action_defer_id; + } NMDevicePrivate; static void nm_device_take_down (NMDevice *dev, gboolean wait, NMDeviceStateReason reason); @@ -294,6 +298,9 @@ static void cp_connection_updated (NMConnectionProvider *cp, NMConnection *conne static const char *state_to_string (NMDeviceState state); +static void carrier_changed (GObject *object, GParamSpec *param, gpointer user_data); +static void carrier_action_defer_clear (NMDevice *self); + static void nm_device_init (NMDevice *self) { @@ -463,6 +470,9 @@ constructor (GType type, update_accept_ra_save (dev); update_ip6_privacy_save (dev); + if (g_object_class_find_property (G_OBJECT_GET_CLASS (dev), "carrier")) + g_signal_connect (dev, "notify::carrier", G_CALLBACK (carrier_changed), NULL); + priv->initialized = TRUE; return object; @@ -1151,6 +1161,109 @@ nm_device_get_act_request (NMDevice *self) return NM_DEVICE_GET_PRIVATE (self)->act_request; } +static void +carrier_action_defer_clear (NMDevice *self) +{ + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + + if (priv->carrier_action_defer_id) { + g_source_remove (priv->carrier_action_defer_id); + priv->carrier_action_defer_id = 0; + } +} + +static gboolean +carrier_action_defer_cb (gpointer user_data) +{ + NMDevice *self = NM_DEVICE (user_data); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + NMDeviceState state; + + priv->carrier_action_defer_id = 0; + + /* We know that carrier is FALSE */ + + state = nm_device_get_state (self); + if (state >= NM_DEVICE_STATE_DISCONNECTED) + nm_device_queue_state (self, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); + + return FALSE; +} + +static void +carrier_changed (GObject *object, GParamSpec *param, gpointer user_data) +{ + NMDevice *self = NM_DEVICE (object); + NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self); + gboolean carrier, defer_action = FALSE; + NMDeviceState state; + + /* Clear any previous deferred action */ + carrier_action_defer_clear (self); + + state = nm_device_get_state (self); + if (state < NM_DEVICE_STATE_UNAVAILABLE) + return; + + g_object_get (object, "carrier", &carrier, NULL); + + if (nm_device_is_master (self)) { + /* Bridge/bond carrier does not affect its own activation, but + * when carrier comes on, if there are slaves waiting, it will + * restart them. + */ + if (!carrier) + return; + + if (!nm_device_activate_ip4_state_in_wait (self) && + !nm_device_activate_ip6_state_in_wait (self)) + return; + } else if (nm_device_get_enslaved (self) && !carrier) { + /* Slaves don't deactivate when they lose carrier; for bonds + * in particular that would be actively counterproductive. + */ + return; + } + + if (priv->act_request && !carrier) + defer_action = TRUE; + + nm_log_info (LOGD_HW | LOGD_DEVICE, "(%s): carrier now %s (device state %d%s)", + nm_device_get_iface (self), + carrier ? "ON" : "OFF", + state, + defer_action ? ", deferring action for 4 seconds" : ""); + + if (nm_device_is_master (self)) { + if (nm_device_activate_ip4_state_in_wait (self)) + nm_device_activate_stage3_ip4_start (self); + + if (nm_device_activate_ip6_state_in_wait (self)) + nm_device_activate_stage3_ip6_start (self); + + return; + } + + if (state == NM_DEVICE_STATE_UNAVAILABLE) { + if (carrier) + nm_device_queue_state (self, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); + else { + /* clear any queued state changes if they wouldn't be valid when the + * carrier is off. + */ + if (nm_device_queued_state_peek (self) >= NM_DEVICE_STATE_DISCONNECTED) + nm_device_queued_state_clear (self); + } + } else if (state >= NM_DEVICE_STATE_DISCONNECTED) { + if (!carrier) { + if (defer_action) + priv->carrier_action_defer_id = g_timeout_add_seconds (4, carrier_action_defer_cb, self); + else + nm_device_queue_state (self, NM_DEVICE_STATE_UNAVAILABLE, NM_DEVICE_STATE_REASON_CARRIER); + } + } +} + NMConnection * nm_device_get_connection (NMDevice *self) { @@ -4328,6 +4441,8 @@ dispose (GObject *object) priv->cp_updated_id = 0; } + carrier_action_defer_clear (self); + g_hash_table_unref (priv->available_connections); activation_source_clear (self, TRUE, AF_INET);