From 479163db59c02cf79eea94103ab7e976552ed661 Mon Sep 17 00:00:00 2001 From: Dan Williams Date: Fri, 25 Jan 2013 11:59:05 -0600 Subject: [PATCH] core: generalize waiting for IP config until slaves are ready Instead of duplicating the code in bridge and bond, move the logic to the base class and key it off whether or not the device is a master. --- src/nm-device-bond.c | 123 ----------------------------------------- src/nm-device-bridge.c | 123 ----------------------------------------- src/nm-device.c | 98 ++++++++++++++++++++++++++++++++ src/nm-device.h | 3 + 4 files changed, 101 insertions(+), 246 deletions(-) diff --git a/src/nm-device-bond.c b/src/nm-device-bond.c index 4ae898d7d7..7f47a3a628 100644 --- a/src/nm-device-bond.c +++ b/src/nm-device-bond.c @@ -46,8 +46,6 @@ G_DEFINE_TYPE (NMDeviceBond, nm_device_bond, NM_TYPE_DEVICE_WIRED) #define NM_BOND_ERROR (nm_bond_error_quark ()) typedef struct { - gboolean ip4_waiting; - gboolean ip6_waiting; guint8 hw_addr[NM_UTILS_HWADDR_LEN_MAX]; gsize hw_addr_len; } NMDeviceBondPrivate; @@ -82,20 +80,6 @@ nm_bond_error_quark (void) /******************************************************************/ -static void -device_state_changed (NMDevice *device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device); - - if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state > NM_DEVICE_STATE_ACTIVATED) { - priv->ip4_waiting = FALSE; - priv->ip6_waiting = FALSE; - } -} - static void carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier) { @@ -330,9 +314,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - NM_DEVICE_BOND_GET_PRIVATE (dev)->ip4_waiting = FALSE; - NM_DEVICE_BOND_GET_PRIVATE (dev)->ip6_waiting = FALSE; - ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { connection = nm_device_get_connection (dev); @@ -354,7 +335,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) static gboolean enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection) { - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device); gboolean success, no_firmware = FALSE; const char *iface = nm_device_get_ip_iface (device); const char *slave_iface = nm_device_get_ip_iface (slave); @@ -371,19 +351,6 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection) if (success) { nm_log_info (LOGD_BOND, "(%s): enslaved bond slave %s", iface, slave_iface); g_object_notify (G_OBJECT (device), "slaves"); - - /* If waiting for a slave to continue with IP config, start now */ - if (priv->ip4_waiting) { - nm_log_info (LOGD_BOND | LOGD_IP4, "(%s): retrying IPv4 config with first slave", iface); - priv->ip4_waiting = FALSE; - nm_device_activate_stage3_ip4_start (device); - } - - if (priv->ip6_waiting) { - nm_log_info (LOGD_BOND | LOGD_IP6, "(%s): retrying IPv6 config with first slave", iface); - priv->ip6_waiting = FALSE; - nm_device_activate_stage3_ip6_start (device); - } } return success; @@ -416,92 +383,6 @@ release_slave (NMDevice *device, NMDevice *slave) return success; } -static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *reason) -{ - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - NMConnection *connection; - NMSettingIP4Config *s_ip4; - const char *method = NULL; - GSList *slaves; - - priv->ip4_waiting = FALSE; - - slaves = nm_device_master_get_slaves (device); - if (slaves == NULL) { - connection = nm_device_get_connection (device); - g_assert (connection); - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4) - method = nm_setting_ip4_config_get_method (s_ip4); - - if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) - priv->ip4_waiting = TRUE; - } - g_slist_free (slaves); - - if (priv->ip4_waiting) { - ret = NM_ACT_STAGE_RETURN_WAIT; - nm_log_info (LOGD_BOND | LOGD_IP4, "(%s): IPv4 config waiting until slaves are present", - nm_device_get_ip_iface (device)); - } else { - /* We have slaves; proceed with normal IPv4 configuration */ - ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage3_ip4_config_start (device, out_config, reason); - } - - return ret; -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *reason) -{ - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - NMConnection *connection; - NMSettingIP6Config *s_ip6; - const char *method = NULL; - GSList *slaves; - - priv->ip6_waiting = FALSE; - - slaves = nm_device_master_get_slaves (device); - if (slaves == NULL) { - connection = nm_device_get_connection (device); - g_assert (connection); - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (s_ip6) - method = nm_setting_ip6_config_get_method (s_ip6); - - /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) - * to complete addressing. SLAAC and DHCP obviously need a peer to - * provide a prefix, while Link-Local must perform DAD on the local link. - */ - if ( !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) - || !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) - || !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - priv->ip6_waiting = TRUE; - } - g_slist_free (slaves); - - if (priv->ip6_waiting) { - ret = NM_ACT_STAGE_RETURN_WAIT; - nm_log_info (LOGD_BOND | LOGD_IP6, "(%s): IPv6 config waiting until slaves are present", - nm_device_get_ip_iface (device)); - } else { - /* We have slaves; proceed with normal IPv6 configuration */ - ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage3_ip6_config_start (device, out_config, reason); - } - - return ret; -} - /******************************************************************/ NMDevice * @@ -603,13 +484,9 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->connection_match_config = connection_match_config; parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; - parent_class->state_changed = device_state_changed; - wired_class->carrier_action = carrier_action; /* properties */ diff --git a/src/nm-device-bridge.c b/src/nm-device-bridge.c index 46c2e4141c..39275c8b41 100644 --- a/src/nm-device-bridge.c +++ b/src/nm-device-bridge.c @@ -46,8 +46,6 @@ G_DEFINE_TYPE (NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE_WIRED) #define NM_BRIDGE_ERROR (nm_bridge_error_quark ()) typedef struct { - gboolean ip4_waiting; - gboolean ip6_waiting; guint8 hw_addr[NM_UTILS_HWADDR_LEN_MAX]; gsize hw_addr_len; } NMDeviceBridgePrivate; @@ -82,20 +80,6 @@ nm_bridge_error_quark (void) /******************************************************************/ -static void -device_state_changed (NMDevice *device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) -{ - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device); - - if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state > NM_DEVICE_STATE_ACTIVATED) { - priv->ip4_waiting = FALSE; - priv->ip6_waiting = FALSE; - } -} - static void carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier) { @@ -384,9 +368,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); - NM_DEVICE_BRIDGE_GET_PRIVATE (dev)->ip4_waiting = FALSE; - NM_DEVICE_BRIDGE_GET_PRIVATE (dev)->ip6_waiting = FALSE; - ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage1_prepare (dev, reason); if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { connection = nm_device_get_connection (dev); @@ -411,7 +392,6 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason) static gboolean enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection) { - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device); gboolean success; NMSettingBridgePort *s_port; const char *iface = nm_device_get_ip_iface (device); @@ -436,19 +416,6 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection) g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES); - /* If waiting for a slave to continue with IP config, start now */ - if (priv->ip4_waiting) { - nm_log_info (LOGD_DEVICE | LOGD_IP4, "(%s): retrying IPv4 config with first slave", iface); - priv->ip4_waiting = FALSE; - nm_device_activate_stage3_ip4_start (device); - } - - if (priv->ip6_waiting) { - nm_log_info (LOGD_DEVICE | LOGD_IP6, "(%s): retrying IPv6 config with first slave", iface); - priv->ip6_waiting = FALSE; - nm_device_activate_stage3_ip6_start (device); - } - return TRUE; } @@ -469,92 +436,6 @@ release_slave (NMDevice *device, NMDevice *slave) return success; } -static NMActStageReturn -act_stage3_ip4_config_start (NMDevice *device, - NMIP4Config **out_config, - NMDeviceStateReason *reason) -{ - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - NMConnection *connection; - NMSettingIP4Config *s_ip4; - const char *method = NULL; - GSList *slaves; - - priv->ip4_waiting = FALSE; - - slaves = nm_device_master_get_slaves (device); - if (slaves == NULL) { - connection = nm_device_get_connection (device); - g_assert (connection); - - s_ip4 = nm_connection_get_setting_ip4_config (connection); - if (s_ip4) - method = nm_setting_ip4_config_get_method (s_ip4); - - if (g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0) - priv->ip4_waiting = TRUE; - } - g_slist_free (slaves); - - if (priv->ip4_waiting) { - ret = NM_ACT_STAGE_RETURN_WAIT; - nm_log_info (LOGD_DEVICE | LOGD_IP4, "(%s): IPv4 config waiting until slaves are present", - nm_device_get_ip_iface (device)); - } else { - /* We have slaves; proceed with normal IPv4 configuration */ - ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage3_ip4_config_start (device, out_config, reason); - } - - return ret; -} - -static NMActStageReturn -act_stage3_ip6_config_start (NMDevice *device, - NMIP6Config **out_config, - NMDeviceStateReason *reason) -{ - NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device); - NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS; - NMConnection *connection; - NMSettingIP6Config *s_ip6; - const char *method = NULL; - GSList *slaves; - - priv->ip6_waiting = FALSE; - - slaves = nm_device_master_get_slaves (device); - if (slaves == NULL) { - connection = nm_device_get_connection (device); - g_assert (connection); - - s_ip6 = nm_connection_get_setting_ip6_config (connection); - if (s_ip6) - method = nm_setting_ip6_config_get_method (s_ip6); - - /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) - * to complete addressing. SLAAC and DHCP obviously need a peer to - * provide a prefix, while Link-Local must perform DAD on the local link. - */ - if ( !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) - || !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) - || !g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL)) - priv->ip6_waiting = TRUE; - } - g_slist_free (slaves); - - if (priv->ip6_waiting) { - ret = NM_ACT_STAGE_RETURN_WAIT; - nm_log_info (LOGD_DEVICE | LOGD_IP6, "(%s): IPv6 config waiting until slaves are present", - nm_device_get_ip_iface (device)); - } else { - /* We have slaves; proceed with normal IPv6 configuration */ - ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage3_ip6_config_start (device, out_config, reason); - } - - return ret; -} - /******************************************************************/ NMDevice * @@ -656,13 +537,9 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass) parent_class->connection_match_config = connection_match_config; parent_class->act_stage1_prepare = act_stage1_prepare; - parent_class->act_stage3_ip4_config_start = act_stage3_ip4_config_start; - parent_class->act_stage3_ip6_config_start = act_stage3_ip6_config_start; parent_class->enslave_slave = enslave_slave; parent_class->release_slave = release_slave; - parent_class->state_changed = device_state_changed; - wired_class->carrier_action = carrier_action; /* properties */ diff --git a/src/nm-device.c b/src/nm-device.c index 88f5c8c6fd..855ce6399f 100644 --- a/src/nm-device.c +++ b/src/nm-device.c @@ -859,6 +859,18 @@ nm_device_enslave_slave (NMDevice *dev, NMDevice *slave, NMConnection *connectio if (NM_DEVICE_GET_CLASS (dev)->update_hw_address) NM_DEVICE_GET_CLASS (dev)->update_hw_address (dev); + /* Restart IP configuration if we're waiting for slaves. Do this + * after updating the hardware address as IP config may need the + * new address. + */ + if (success) { + if (NM_DEVICE_GET_PRIVATE (dev)->ip4_state == IP_WAIT) + nm_device_activate_stage3_ip4_start (dev); + + if (NM_DEVICE_GET_PRIVATE (dev)->ip6_state == IP_WAIT) + nm_device_activate_stage3_ip6_start (dev); + } + return success; } @@ -2124,6 +2136,35 @@ shared4_new_config (NMDevice *self, NMDeviceStateReason *reason) /*********************************************/ +static gboolean +have_any_ready_slaves (NMDevice *device, const GSList *slaves) +{ + const GSList *iter; + + /* Any enslaved slave is "ready" in the generic case as it's + * at least >= NM_DEVCIE_STATE_IP_CONFIG and has had Layer 2 + * properties set up. + */ + for (iter = slaves; iter; iter = g_slist_next (iter)) { + if (nm_device_get_enslaved (iter->data)) + return TRUE; + } + return FALSE; +} + +static gboolean +ip4_requires_slaves (NMConnection *connection) +{ + NMSettingIP4Config *s_ip4; + const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + + s_ip4 = nm_connection_get_setting_ip4_config (connection); + if (s_ip4) + method = nm_setting_ip4_config_get_method (s_ip4); + + return g_strcmp0 (method, NM_SETTING_IP4_CONFIG_METHOD_AUTO) == 0; +} + static NMActStageReturn act_stage3_ip4_config_start (NMDevice *self, NMIP4Config **out_config, @@ -2134,12 +2175,30 @@ act_stage3_ip4_config_start (NMDevice *self, NMSettingIP4Config *s_ip4; NMActStageReturn ret = NM_ACT_STAGE_RETURN_FAILURE; const char *method = NM_SETTING_IP4_CONFIG_METHOD_AUTO; + GSList *slaves; + gboolean ready_slaves; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); connection = nm_device_get_connection (self); g_assert (connection); + if (priv->is_master && ip4_requires_slaves (connection)) { + /* If the master has no ready slaves, and depends on slaves for + * a successful IPv4 attempt, then postpone IPv4 addressing. + */ + slaves = nm_device_master_get_slaves (self); + ready_slaves = NM_DEVICE_GET_CLASS (self)->have_any_ready_slaves (self, slaves); + g_slist_free (slaves); + + if (ready_slaves == FALSE) { + nm_log_info (LOGD_DEVICE | LOGD_IP4, + "(%s): IPv4 config waiting until slaves are ready", + nm_device_get_ip_iface (self)); + return NM_ACT_STAGE_RETURN_WAIT; + } + } + /* If we did not receive IP4 configuration information, default to DHCP */ s_ip4 = nm_connection_get_setting_ip4_config (connection); if (s_ip4) @@ -2670,6 +2729,25 @@ done: return ret; } +static gboolean +ip6_requires_slaves (NMConnection *connection) +{ + NMSettingIP6Config *s_ip6; + const char *method = NM_SETTING_IP6_CONFIG_METHOD_AUTO; + + s_ip6 = nm_connection_get_setting_ip6_config (connection); + if (s_ip6) + method = nm_setting_ip6_config_get_method (s_ip6); + + /* SLAAC, DHCP, and Link-Local depend on connectivity (and thus slaves) + * to complete addressing. SLAAC and DHCP obviously need a peer to + * provide a prefix, while Link-Local must perform DAD on the local link. + */ + return g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_AUTO) == 0 + || g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_DHCP) == 0 + || g_strcmp0 (method, NM_SETTING_IP6_CONFIG_METHOD_LINK_LOCAL) == 0; +} + static NMActStageReturn act_stage3_ip6_config_start (NMDevice *self, NMIP6Config **out_config, @@ -2683,6 +2761,8 @@ act_stage3_ip6_config_start (NMDevice *self, int conf_use_tempaddr; NMSettingIP6ConfigPrivacy ip6_privacy = NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN; const char *ip6_privacy_str = "0\n"; + GSList *slaves; + gboolean ready_slaves; g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE); @@ -2691,6 +2771,22 @@ act_stage3_ip6_config_start (NMDevice *self, ip_iface = nm_device_get_ip_iface (self); + if (priv->is_master && ip6_requires_slaves (connection)) { + /* If the master has no ready slaves, and depends on slaves for + * a successful IPv6 attempt, then postpone IPv6 addressing. + */ + slaves = nm_device_master_get_slaves (self); + ready_slaves = NM_DEVICE_GET_CLASS (self)->have_any_ready_slaves (self, slaves); + g_slist_free (slaves); + + if (ready_slaves == FALSE) { + nm_log_info (LOGD_DEVICE | LOGD_IP6, + "(%s): IPv6 config waiting until slaves are ready", + ip_iface); + return NM_ACT_STAGE_RETURN_WAIT; + } + } + update_accept_ra_save (self); update_ip6_privacy_save (self); @@ -4464,6 +4560,8 @@ nm_device_class_init (NMDeviceClass *klass) klass->act_stage3_ip6_config_start = act_stage3_ip6_config_start; klass->act_stage4_ip4_config_timeout = act_stage4_ip4_config_timeout; klass->act_stage4_ip6_config_timeout = act_stage4_ip6_config_timeout; + klass->have_any_ready_slaves = have_any_ready_slaves; + klass->check_connection_available = check_connection_available; klass->hw_is_up = hw_is_up; klass->hw_bring_up = hw_bring_up; diff --git a/src/nm-device.h b/src/nm-device.h index c878745f31..87e428f596 100644 --- a/src/nm-device.h +++ b/src/nm-device.h @@ -188,6 +188,9 @@ typedef struct { gboolean (* release_slave) (NMDevice *self, NMDevice *slave); + + gboolean (* have_any_ready_slaves) (NMDevice *self, + const GSList *slaves); } NMDeviceClass;