bridge: allow independent IPv4 and IPv6 configuration with no slaves

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.
This commit is contained in:
Dan Williams 2012-11-16 09:48:43 -06:00
parent dcecc41327
commit 445e8755bc

View file

@ -46,7 +46,8 @@ G_DEFINE_TYPE (NMDeviceBridge, nm_device_bridge, NM_TYPE_DEVICE_WIRED)
#define NM_BRIDGE_ERROR (nm_bridge_error_quark ()) #define NM_BRIDGE_ERROR (nm_bridge_error_quark ())
typedef struct { typedef struct {
gboolean unused; gboolean ip4_waiting;
gboolean ip6_waiting;
} NMDeviceBridgePrivate; } NMDeviceBridgePrivate;
enum { enum {
@ -85,10 +86,17 @@ device_state_changed (NMDevice *device,
NMDeviceState old_state, NMDeviceState old_state,
NMDeviceStateReason reason) NMDeviceStateReason reason)
{ {
NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device);
if (new_state == NM_DEVICE_STATE_UNAVAILABLE) { if (new_state == NM_DEVICE_STATE_UNAVAILABLE) {
/* Use NM_DEVICE_STATE_REASON_CARRIER to make sure num retries is reset */ /* 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); 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 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); 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); ret = NM_DEVICE_CLASS (nm_device_bridge_parent_class)->act_stage1_prepare (dev, reason);
if (ret == NM_ACT_STAGE_RETURN_SUCCESS) { if (ret == NM_ACT_STAGE_RETURN_SUCCESS) {
connection = nm_device_get_connection (dev); connection = nm_device_get_connection (dev);
@ -387,6 +398,7 @@ act_stage1_prepare (NMDevice *dev, NMDeviceStateReason *reason)
static gboolean static gboolean
enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection) enslave_slave (NMDevice *device, NMDevice *slave, NMConnection *connection)
{ {
NMDeviceBridgePrivate *priv = NM_DEVICE_BRIDGE_GET_PRIVATE (device);
gboolean success; gboolean success;
NMSettingBridgePort *s_port; NMSettingBridgePort *s_port;
const char *iface = nm_device_get_ip_iface (device); 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); nm_log_info (LOGD_DEVICE, "(%s): attached bridge port %s", iface, slave_iface);
g_object_notify (G_OBJECT (device), NM_DEVICE_BRIDGE_SLAVES); 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; return TRUE;
} }
@ -430,6 +456,92 @@ release_slave (NMDevice *device, NMDevice *slave)
return success; 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 * NMDevice *
@ -527,6 +639,8 @@ nm_device_bridge_class_init (NMDeviceBridgeClass *klass)
parent_class->connection_match_config = connection_match_config; parent_class->connection_match_config = connection_match_config;
parent_class->act_stage1_prepare = act_stage1_prepare; 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->enslave_slave = enslave_slave;
parent_class->release_slave = release_slave; parent_class->release_slave = release_slave;