summary refs log tree commit diff
path: root/src/devices/nm-device-bond.c
diff options
context:
space:
mode:
authorMichael Biebl <biebl@debian.org>2017-05-11 14:55:55 +0200
committerMichael Biebl <biebl@debian.org>2017-05-11 14:55:55 +0200
commitc333f062ddcba9b35330647bf6cbd0a07f2d786e (patch)
tree257c3a0c74c09f4ad2328eab5b932806405f0c1c /src/devices/nm-device-bond.c
parenta222e56e103f949b148a6942e385ccca2c26d9f3 (diff)
New upstream version 1.8.0 upstream/1.8.0
Diffstat (limited to 'src/devices/nm-device-bond.c')
-rw-r--r--src/devices/nm-device-bond.c156
1 files changed, 143 insertions, 13 deletions
diff --git a/src/devices/nm-device-bond.c b/src/devices/nm-device-bond.c
index 34d34eb4..3325c948 100644
--- a/src/devices/nm-device-bond.c
+++ b/src/devices/nm-device-bond.c
@@ -101,7 +101,7 @@ complete_connection (NMDevice *device,
 {
 	NMSettingBond *s_bond;
 
-	nm_utils_complete_generic (NM_PLATFORM_GET,
+	nm_utils_complete_generic (nm_device_get_platform (device),
 	                           connection,
 	                           NM_SETTING_BOND_SETTING_NAME,
 	                           existing_connections,
@@ -131,7 +131,7 @@ set_bond_attr (NMDevice *device, NMBondMode mode, const char *attr, const char *
 	if (!_nm_setting_bond_option_supported (attr, mode))
 		return FALSE;
 
-	ret = nm_platform_sysctl_master_set_option (NM_PLATFORM_GET, ifindex, attr, value);
+	ret = nm_platform_sysctl_master_set_option (nm_device_get_platform (device), ifindex, attr, value);
 	if (!ret)
 		_LOGW (LOGD_PLATFORM, "failed to set bonding attribute '%s' to '%s'", attr, value);
 	return ret;
@@ -165,7 +165,7 @@ update_connection (NMDevice *device, NMConnection *connection)
 	/* Read bond options from sysfs and update the Bond setting to match */
 	options = nm_setting_bond_get_valid_options (s_bond);
 	while (options && *options) {
-		gs_free char *value = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex, *options);
+		gs_free char *value = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex, *options);
 		const char *defvalue = nm_setting_bond_get_option_default (s_bond, *options);
 		char *p;
 
@@ -328,7 +328,7 @@ apply_bonding_config (NMDevice *device)
 	set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_PRIMARY, value ? value : "");
 
 	/* ARP targets: clear and initialize the list */
-	contents = nm_platform_sysctl_master_get_option (NM_PLATFORM_GET, ifindex,
+	contents = nm_platform_sysctl_master_get_option (nm_device_get_platform (device), ifindex,
 	                                                 NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
 	set_arp_targets (device, mode, contents, " \n", "-");
 	value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_ARP_IP_TARGET);
@@ -363,21 +363,19 @@ apply_bonding_config (NMDevice *device)
 }
 
 static NMActStageReturn
-act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
+act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *out_failure_reason)
 {
 	NMActStageReturn ret = NM_ACT_STAGE_RETURN_SUCCESS;
 	gboolean no_firmware = FALSE;
 
-	g_return_val_if_fail (reason != NULL, NM_ACT_STAGE_RETURN_FAILURE);
-
-	ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, reason);
+	ret = NM_DEVICE_CLASS (nm_device_bond_parent_class)->act_stage1_prepare (dev, out_failure_reason);
 	if (ret != NM_ACT_STAGE_RETURN_SUCCESS)
 		return ret;
 
 	/* Interface must be down to set bond options */
 	nm_device_take_down (dev, TRUE);
 	ret = apply_bonding_config (dev);
-	if (ret)
+	if (ret != NM_ACT_STAGE_RETURN_FAILURE)
 		ret = nm_device_hw_addr_set_cloned (dev, nm_device_get_applied_connection (dev), FALSE);
 	nm_device_bring_up (dev, TRUE, &no_firmware);
 
@@ -393,12 +391,13 @@ enslave_slave (NMDevice *device,
 	NMDeviceBond *self = NM_DEVICE_BOND (device);
 	gboolean success = TRUE, no_firmware = FALSE;
 	const char *slave_iface = nm_device_get_ip_iface (slave);
+	NMConnection *master_con;
 
 	nm_device_master_check_slave_physical_port (device, slave, LOGD_BOND);
 
 	if (configure) {
 		nm_device_take_down (slave, TRUE);
-		success = nm_platform_link_enslave (NM_PLATFORM_GET,
+		success = nm_platform_link_enslave (nm_device_get_platform (device),
 		                                    nm_device_get_ip_ifindex (device),
 		                                    nm_device_get_ip_ifindex (slave));
 		nm_device_bring_up (slave, TRUE, &no_firmware);
@@ -407,6 +406,25 @@ enslave_slave (NMDevice *device,
 			return FALSE;
 
 		_LOGI (LOGD_BOND, "enslaved bond slave %s", slave_iface);
+
+		/* The active_slave option can be set only after the interface is enslaved */
+		master_con = nm_device_get_applied_connection (device);
+		if (master_con) {
+			NMSettingBond *s_bond = nm_connection_get_setting_bond (master_con);
+			const char *active;
+
+			if (s_bond) {
+				active = nm_setting_bond_get_option_by_name (s_bond, "active_slave");
+				if (active && nm_streq0 (active, nm_device_get_iface (slave))) {
+					nm_platform_sysctl_master_set_option (nm_device_get_platform (device),
+					                                      nm_device_get_ifindex (device),
+					                                      "active_slave",
+					                                      active);
+					_LOGD (LOGD_BOND, "setting slave %s as active one for master %s",
+					       active, nm_device_get_iface (device));
+				}
+			}
+		}
 	} else
 		_LOGI (LOGD_BOND, "bond slave %s was enslaved", slave_iface);
 
@@ -428,7 +446,7 @@ release_slave (NMDevice *device,
 		 */
 		address = g_strdup (nm_device_get_hw_address (device));
 
-		success = nm_platform_link_release (NM_PLATFORM_GET,
+		success = nm_platform_link_release (nm_device_get_platform (device),
 		                                    nm_device_get_ip_ifindex (device),
 		                                    nm_device_get_ip_ifindex (slave));
 
@@ -440,7 +458,7 @@ release_slave (NMDevice *device,
 			       nm_device_get_ip_iface (slave));
 		}
 
-		nm_platform_process_events (NM_PLATFORM_GET);
+		nm_platform_process_events (nm_device_get_platform (device));
 		if (nm_device_update_hw_address (device))
 			nm_device_hw_addr_set (device, address, "restore", FALSE);
 
@@ -468,7 +486,7 @@ create_and_realize (NMDevice *device,
 
 	g_assert (iface);
 
-	plerr = nm_platform_link_bond_add (NM_PLATFORM_GET, iface, out_plink);
+	plerr = nm_platform_link_bond_add (nm_device_get_platform (device), iface, out_plink);
 	if (plerr != NM_PLATFORM_ERROR_SUCCESS) {
 		g_set_error (error, NM_DEVICE_ERROR, NM_DEVICE_ERROR_CREATION_FAILED,
 		             "Failed to create bond interface '%s' for '%s': %s",
@@ -480,6 +498,116 @@ create_and_realize (NMDevice *device,
 	return TRUE;
 }
 
+static gboolean
+check_changed_options (NMSettingBond *s_a, NMSettingBond *s_b, GError **error)
+{
+	guint i, num;
+	const char *name = NULL, *value_a = NULL, *value_b = NULL;
+
+	/* Check that options in @s_a have compatible changes in @s_b */
+
+	num = nm_setting_bond_get_num_options (s_a);
+	for (i = 0; i < num; i++) {
+		nm_setting_bond_get_option (s_a, i, &name, &value_a);
+
+		/* We support changes to these */
+		if (NM_IN_STRSET (name,
+		                  NM_SETTING_BOND_OPTION_ACTIVE_SLAVE,
+		                  NM_SETTING_BOND_OPTION_PRIMARY)) {
+			continue;
+		}
+
+		/* Missing in @s_b, but has a default value in @s_a */
+		value_b = nm_setting_bond_get_option_by_name (s_b, name);
+		if (   !value_b
+		    && nm_streq0 (value_a, nm_setting_bond_get_option_default (s_a, name))) {
+			continue;
+		}
+
+		/* Reject any other changes */
+		if (!nm_streq0 (value_a, value_b)) {
+			g_set_error (error,
+			             NM_DEVICE_ERROR,
+			             NM_DEVICE_ERROR_INCOMPATIBLE_CONNECTION,
+			             "Can't reapply '%s' bond option",
+			             name);
+			return FALSE;
+		}
+	}
+
+	return TRUE;
+}
+
+static gboolean
+can_reapply_change (NMDevice *device,
+                    const char *setting_name,
+                    NMSetting *s_old,
+                    NMSetting *s_new,
+                    GHashTable *diffs,
+                    GError **error)
+{
+	NMDeviceClass *device_class;
+	NMSettingBond *s_bond_old, *s_bond_new;
+
+	/* Only handle bond setting here, delegate other settings to parent class */
+	if (nm_streq (setting_name, NM_SETTING_BOND_SETTING_NAME)) {
+		if (!nm_device_hash_check_invalid_keys (diffs,
+		                                        NM_SETTING_BOND_SETTING_NAME,
+		                                        error,
+		                                        NM_SETTING_BOND_OPTIONS))
+			return FALSE;
+
+		s_bond_old = NM_SETTING_BOND (s_old);
+		s_bond_new = NM_SETTING_BOND (s_new);
+
+		if (   !check_changed_options (s_bond_old, s_bond_new, error)
+		    || !check_changed_options (s_bond_new, s_bond_old, error)) {
+			return FALSE;
+		}
+
+		return TRUE;
+	}
+
+	device_class = NM_DEVICE_CLASS (nm_device_bond_parent_class);
+	return device_class->can_reapply_change (device,
+	                                         setting_name,
+	                                         s_old,
+	                                         s_new,
+	                                         diffs,
+	                                         error);
+}
+
+static void
+reapply_connection (NMDevice *device, NMConnection *con_old, NMConnection *con_new)
+{
+	NMDeviceBond *self = NM_DEVICE_BOND (device);
+	const char *value;
+	NMSettingBond *s_bond;
+	NMBondMode mode;
+
+	NM_DEVICE_CLASS (nm_device_bond_parent_class)->reapply_connection (device,
+	                                                                   con_old,
+	                                                                   con_new);
+
+	_LOGD (LOGD_BOND, "reapplying bond settings");
+	s_bond = nm_connection_get_setting_bond (con_new);
+	g_return_if_fail (s_bond);
+
+	value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_MODE);
+	if (!value)
+		value = "balance-rr";
+
+	mode = _nm_setting_bond_mode_from_string (value);
+	g_return_if_fail (mode != NM_BOND_MODE_UNKNOWN);
+
+	/* Primary */
+	value = nm_setting_bond_get_option_by_name (s_bond, NM_SETTING_BOND_OPTION_PRIMARY);
+	set_bond_attr (device, mode, NM_SETTING_BOND_OPTION_PRIMARY, value ? value : "");
+
+	/* Active slave */
+	set_simple_option (device, mode, s_bond, NM_SETTING_BOND_OPTION_ACTIVE_SLAVE);
+}
+
 /*****************************************************************************/
 
 static void
@@ -508,6 +636,8 @@ nm_device_bond_class_init (NMDeviceBondClass *klass)
 	parent_class->get_configured_mtu = nm_device_get_configured_mtu_for_wired;
 	parent_class->enslave_slave = enslave_slave;
 	parent_class->release_slave = release_slave;
+	parent_class->can_reapply_change = can_reapply_change;
+	parent_class->reapply_connection = reapply_connection;
 
 	nm_exported_object_class_add_interface (NM_EXPORTED_OBJECT_CLASS (klass),
 	                                        NMDBUS_TYPE_DEVICE_BOND_SKELETON,