summary refs log tree commit diff
path: root/src/nm-device-bridge.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-device-bridge.c')
-rw-r--r--src/nm-device-bridge.c208
1 files changed, 52 insertions, 156 deletions
diff --git a/src/nm-device-bridge.c b/src/nm-device-bridge.c
index 6f3d70e4..39275c8b 100644
--- a/src/nm-device-bridge.c
+++ b/src/nm-device-bridge.c
@@ -46,8 +46,8 @@ 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;
 
 enum {
@@ -81,44 +81,39 @@ nm_bridge_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)
 {
-	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_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;
-	}
+	/* Bridge carrier state follows IFF_UP with no ports, and port carrier
+	 * states when ports are added.  Thus carrier isn't useful when deciding
+	 * to auto-activate the bridge master.  Also, like bond masters, when the
+	 * carrier state changes due to slave changes, we shouldn't deactivate the
+	 * bridge since the user may be reconfiguring ports.
+	 *
+	 * 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_bridge_parent_class)->update_hw_address (dev);
+	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_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_BRIDGE_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_BRIDGE_HW_ADDRESS);
+static const guint8 *
+get_hw_address (NMDevice *device, guint *out_len)
+{
+	*out_len = NM_DEVICE_BRIDGE_GET_PRIVATE (device)->hw_addr_len;
+	return NM_DEVICE_BRIDGE_GET_PRIVATE (device)->hw_addr;
 }
 
 static guint32
@@ -247,10 +242,11 @@ complete_connection (NMDevice *device,
 static gboolean
 spec_match_list (NMDevice *device, const GSList *specs)
 {
+	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_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,6 +307,7 @@ static void
 set_sysfs_uint (const char *iface,
                 GObject *obj,
                 const char *obj_prop,
+                const char *dir,
                 const char *sysfs_prop,
                 gboolean default_if_zero,
                 gboolean user_hz_compensate)
@@ -353,7 +350,7 @@ set_sysfs_uint (const char *iface,
 	if (user_hz_compensate)
 		uval *= 100;
 
-	path = g_strdup_printf ("/sys/class/net/%s/bridge/%s", iface, sysfs_prop);
+	path = g_strdup_printf ("/sys/class/net/%s/%s/%s", iface, dir, sysfs_prop);
 	s = g_strdup_printf ("%u", uval);
 	/* FIXME: how should failure be handled? */
 	nm_utils_do_sysctl (path, s);
@@ -371,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);
@@ -385,12 +379,12 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
 		iface = nm_device_get_ip_iface (dev);
 		g_assert (iface);
 
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_STP, "stp_state", FALSE, FALSE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_PRIORITY, "priority", TRUE, FALSE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY, "forward_delay", TRUE, TRUE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME, "hello_time", TRUE, TRUE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_MAX_AGE, "max_age", TRUE, TRUE);
-		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME, "ageing_time", TRUE, TRUE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_STP, "bridge", "stp_state", FALSE, FALSE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_PRIORITY, "bridge", "priority", TRUE, FALSE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_FORWARD_DELAY, "bridge", "forward_delay", TRUE, TRUE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_HELLO_TIME, "bridge", "hello_time", TRUE, TRUE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_MAX_AGE, "bridge", "max_age", TRUE, TRUE);
+		set_sysfs_uint (iface, G_OBJECT (s_bridge), NM_SETTING_BRIDGE_AGEING_TIME, "bridge", "ageing_time", TRUE, TRUE);
 	}
 	return ret;
 }
@@ -398,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);
@@ -414,28 +407,15 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
 	/* Set port properties */
 	s_port = nm_connection_get_setting_bridge_port (connection);
 	if (s_port) {
-		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY, "priority", TRUE, FALSE);
-		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST, "path_cost", TRUE, FALSE);
-		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "hairpin_mode", FALSE, FALSE);
+		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PRIORITY, "brport", "priority", TRUE, FALSE);
+		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_PATH_COST, "brport", "path_cost", TRUE, FALSE);
+		set_sysfs_uint (slave_iface, G_OBJECT (s_port), NM_SETTING_BRIDGE_PORT_HAIRPIN_MODE, "brport", "hairpin_mode", FALSE, FALSE);
 	}
 
-	nm_log_info (LOGD_DEVICE, "(%s): attached bridge port %s", iface, slave_iface);
+	nm_log_info (LOGD_BRIDGE, "(%s): attached bridge port %s", iface, slave_iface);
 
 	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;
 }
 
@@ -448,7 +428,7 @@ release_slave (NMDevice *device, NMDevice *slave)
 	                                   nm_device_get_ip_iface (device),
 	                                   nm_device_get_ip_ifindex (slave),
 	                                   nm_device_get_ip_iface (slave));
-	nm_log_info (LOGD_DEVICE, "(%s): detached bridge port %s (success %d)",
+	nm_log_info (LOGD_BRIDGE, "(%s): detached bridge port %s (success %d)",
 	             nm_device_get_ip_iface (device),
 	             nm_device_get_ip_iface (slave),
 	             success);
@@ -456,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 *
@@ -556,6 +450,7 @@ nm_device_bridge_new (const char *udi, const char *iface)
 	                                  NM_DEVICE_DRIVER, "bridge",
 	                                  NM_DEVICE_TYPE_DESC, "Bridge",
 	                                  NM_DEVICE_DEVICE_TYPE, NM_DEVICE_TYPE_BRIDGE,
+	                                  NM_DEVICE_IS_MASTER, TRUE,
 	                                  NULL);
 }
 
@@ -564,7 +459,7 @@ constructed (GObject *object)
 {
 	G_OBJECT_CLASS (nm_device_bridge_parent_class)->constructed (object);
 
-	nm_log_dbg (LOGD_HW | LOGD_DEVICE, "(%s): kernel ifindex %d",
+	nm_log_dbg (LOGD_HW | LOGD_BRIDGE, "(%s): kernel ifindex %d",
 	            nm_device_get_iface (NM_DEVICE (object)),
 	            nm_device_get_ifindex (NM_DEVICE (object)));
 }
@@ -578,14 +473,15 @@ static void
 get_property (GObject *object, guint prop_id,
               GValue *value, GParamSpec *pspec)
 {
-	const guint8 *current_addr;
+	NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_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)));
@@ -620,6 +516,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *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 (NMDeviceBridgePrivate));
 
@@ -630,6 +527,7 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *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;
@@ -639,12 +537,10 @@ 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 */
 	g_object_class_install_property