summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2012-11-16 09:48:43 -0600
committerDan Williams <dcbw@redhat.com>2012-11-29 15:50:27 -0600
commit19ddcb8ad78bf043bf0892a26e7ef24b5b793a24 (patch)
tree5a44c1326d341734b33f24f488b1b8add2948fa7
parentc2a3dd1648d56083c417af54aa6540f8f6b681b9 (diff)
downloadNetworkManager-bridge.tar.gz
bridge: allow independent IPv4 and IPv6 configuration with no slavesbridge
When no slave is present, dynamic IP configuration (DHCPv4, DHCPv6, IPv6 autoconf) cannot proceed. But static and link-local configuration can. So if IPv4 requires DHCP but IPv6 is static, it makes no sense to block IPv6 configuration from proceeding just because DHCPv4 cannot.
-rw-r--r--src/nm-device-bridge.c116
1 files changed, 115 insertions, 1 deletions
diff --git a/src/nm-device-bridge.c b/src/nm-device-bridge.c
index 35ff2af26b..6f3d70e4b3 100644
--- a/src/nm-device-bridge.c
+++ b/src/nm-device-bridge.c
@@ -46,7 +46,8 @@ G_DEFINE_TYPE (NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE_WIRED)
#define NM_BRIDGE_ERROR (nm_bridge_error_quark ())
typedef struct {
- gboolean unused;
+ gboolean ip4_waiting;
+ gboolean ip6_waiting;
} NMDeviceBridgePrivate;
enum {
@@ -85,10 +86,17 @@ device_state_changed (NMDevice *device,
NMDeviceState old_state,
NMDeviceStateReason reason)
{
+ 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;
+ }
}
static void
@@ -363,6 +371,9 @@ 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);
@@ -387,6 +398,7 @@ 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);
@@ -410,6 +422,20 @@ enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
nm_log_info (LOGD_DEVICE, "(%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;
}
@@ -430,6 +456,92 @@ 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 *
@@ -527,6 +639,8 @@ 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;