diff options
Diffstat (limited to 'src/nm-device-bond.c')
| -rw-r--r-- | src/nm-device-bond.c | 207 |
1 files changed, 60 insertions, 147 deletions
diff --git a/src/nm-device-bond.c b/src/nm-device-bond.c index 30df94fa..7f47a3a6 100644 --- a/src/nm-device-bond.c +++ b/src/nm-device-bond.c @@ -46,8 +46,8 @@ 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; enum { @@ -81,44 +81,42 @@ nm_bond_error_quark (void) /******************************************************************/ static void -device_state_changed (NMDevice *device, - NMDeviceState new_state, - NMDeviceState old_state, - NMDeviceStateReason reason) +carrier_action (NMDeviceWired *self, NMDeviceState state, gboolean carrier) { - NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device); - - if (new_state == NM_DEVICE_STATE_UNAVAILABLE) { - /* Use NM_DEVICE_STATE_REASON_CARRIER to make sure num retries is reset */ - nm_device_queue_state (device, NM_DEVICE_STATE_DISCONNECTED, NM_DEVICE_STATE_REASON_CARRIER); - } - - if (new_state <= NM_DEVICE_STATE_DISCONNECTED || new_state > NM_DEVICE_STATE_ACTIVATED) { - priv->ip4_waiting = FALSE; - priv->ip6_waiting = FALSE; - } + /* 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) { - const guint8 *hw_addr; - guint8 old_addr[NM_UTILS_HWADDR_LEN_MAX]; - int addrtype, addrlen; - - addrtype = nm_device_wired_get_hwaddr_type (NM_DEVICE_WIRED (dev)); - g_assert (addrtype >= 0); - addrlen = nm_utils_hwaddr_len (addrtype); - g_assert (addrlen > 0); - - hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev)); - memcpy (old_addr, hw_addr, addrlen); - - NM_DEVICE_CLASS (nm_device_bond_parent_class)->update_hw_address (dev); + NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (dev); + gsize addrlen; + gboolean changed = FALSE; + + addrlen = nm_device_read_hwaddr (dev, priv->hw_addr, sizeof (priv->hw_addr), &changed); + if (addrlen) { + priv->hw_addr_len = addrlen; + if (changed) + g_object_notify (G_OBJECT (dev), NM_DEVICE_BOND_HW_ADDRESS); + } +} - hw_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (dev)); - if (memcmp (old_addr, hw_addr, addrlen)) - g_object_notify (G_OBJECT (dev), NM_DEVICE_BOND_HW_ADDRESS); +static const guint8 * +get_hw_address (NMDevice *device, guint *out_len) +{ + *out_len = NM_DEVICE_BOND_GET_PRIVATE (device)->hw_addr_len; + return NM_DEVICE_BOND_GET_PRIVATE (device)->hw_addr; } static guint32 @@ -128,6 +126,14 @@ get_generic_capabilities (NMDevice *dev) } static gboolean +is_available (NMDevice *dev) +{ + if (NM_DEVICE_GET_CLASS (dev)->hw_is_up) + return NM_DEVICE_GET_CLASS (dev)->hw_is_up (dev); + return FALSE; +} + +static gboolean match_bond_connection (NMDevice *device, NMConnection *connection, GError **error) { const char *iface; @@ -162,12 +168,8 @@ get_best_auto_connection (NMDevice *dev, for (iter = connections; iter; iter = g_slist_next (iter)) { NMConnection *connection = NM_CONNECTION (iter->data); - NMSettingConnection *s_con; - s_con = nm_connection_get_setting_connection (connection); - g_assert (s_con); - if ( nm_setting_connection_get_autoconnect (s_con) - && match_bond_connection (dev, connection, NULL)) + if (match_bond_connection (dev, connection, NULL)) return connection; } return NULL; @@ -241,10 +243,11 @@ complete_connection (NMDevice *device, static gboolean spec_match_list (NMDevice *device, const GSList *specs) { + NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (device); char *hwaddr; gboolean matched; - hwaddr = nm_utils_hwaddr_ntoa (nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (device)), ARPHRD_ETHER); + hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, nm_utils_hwaddr_type (priv->hw_addr_len)); matched = nm_match_spec_hwaddr (specs, hwaddr); g_free (hwaddr); @@ -311,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); @@ -335,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); @@ -352,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; @@ -373,7 +359,7 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection) static gboolean release_slave (NMDevice *device, NMDevice *slave) { - gboolean success; + gboolean success, no_firmware = FALSE; success = nm_system_bond_release (nm_device_get_ip_ifindex (device), nm_device_get_ip_iface (device), @@ -384,93 +370,17 @@ release_slave (NMDevice *device, NMDevice *slave) nm_device_get_ip_iface (slave), success); g_object_notify (G_OBJECT (device), "slaves"); - 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); + /* Kernel bonding code "closes" the slave when releasing it, (which clears + * IFF_UP), so we must bring it back up here to ensure carrier changes and + * other state is noticed by the now-released slave. + */ + if (!nm_device_hw_bring_up (slave, TRUE, &no_firmware)) { + nm_log_warn (LOGD_BOND, "(%s): released bond slave could not be brought up.", + nm_device_get_iface (slave)); } - return ret; + return success; } /******************************************************************/ @@ -487,6 +397,7 @@ nm_device_bond_new (const char *udi, const char *iface) NM_DEVICE_DRIVER, "bonding", NM_DEVICE_TYPE_DESC, "Bond", NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BOND, + NM_DEVICE_IS_MASTER, TRUE, NULL); } @@ -509,14 +420,15 @@ static void get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { - const guint8 *current_addr; + NMDeviceBondPrivate *priv = NM_DEVICE_BOND_GET_PRIVATE (object); GPtrArray *slaves; GSList *list, *iter; + char *hwaddr; switch (prop_id) { case PROP_HW_ADDRESS: - current_addr = nm_device_wired_get_hwaddr (NM_DEVICE_WIRED (object)); - g_value_take_string (value, nm_utils_hwaddr_ntoa (current_addr, ARPHRD_ETHER)); + hwaddr = nm_utils_hwaddr_ntoa (priv->hw_addr, nm_utils_hwaddr_type (priv->hw_addr_len)); + g_value_take_string (value, hwaddr); break; case PROP_CARRIER: g_value_set_boolean (value, nm_device_wired_get_carrier (NM_DEVICE_WIRED (object))); @@ -551,6 +463,7 @@ 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)); @@ -561,6 +474,8 @@ nm_device_bond_class_init (NMDeviceBondClass *klass) parent_class->get_generic_capabilities = get_generic_capabilities; parent_class->update_hw_address = update_hw_address; + parent_class->get_hw_address = get_hw_address; + parent_class->is_available = is_available; parent_class->get_best_auto_connection = get_best_auto_connection; parent_class->check_connection_compatible = check_connection_compatible; parent_class->complete_connection = complete_connection; @@ -569,12 +484,10 @@ 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 */ g_object_class_install_property |