summary refs log tree commit diff
path: root/src/nm-device-bond.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-device-bond.c')
-rw-r--r--src/nm-device-bond.c207
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