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;