summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-08-29 16:03:42 -0500
committerDan Williams <dcbw@redhat.com>2014-08-29 16:03:42 -0500
commit0c54a617e9b4019c24b5f2da047885cfae843c08 (patch)
treed0856d28a69057140987cd10b014f13637bfbff7
parentbc18992dd8fbbc1ce5e0c3ca6a6e13b62ae93d91 (diff)
parentcbcca18149544ab97564871b1626eb269cac026e (diff)
downloadNetworkManager-0c54a617e9b4019c24b5f2da047885cfae843c08.tar.gz
merge: apply static IPv6 configuration before starting SLAAC (rh #1101809)
-rw-r--r--src/devices/nm-device.c81
-rw-r--r--src/devices/nm-device.h2
-rw-r--r--src/rdisc/nm-lndp-rdisc.c84
-rw-r--r--src/rdisc/nm-rdisc.c9
-rw-r--r--src/rdisc/nm-rdisc.h2
5 files changed, 137 insertions, 41 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c
index 265cf938e2..5996a779ac 100644
--- a/src/devices/nm-device.c
+++ b/src/devices/nm-device.c
@@ -270,7 +270,8 @@ typedef struct {
NMIP6Config * ext_ip6_config; /* Stuff added outside NM */
NMRDisc * rdisc;
- gulong rdisc_config_changed_sigid;
+ gulong rdisc_changed_id;
+ gulong rdisc_timeout_id;
NMSettingIP6ConfigPrivacy rdisc_use_tempaddr;
/* IP6 config from autoconf */
NMIP6Config * ac_ip6_config;
@@ -3053,6 +3054,12 @@ ip6_config_merge_and_apply (NMDevice *self,
nm_ip6_config_addresses_sort (composite,
priv->rdisc ? priv->rdisc_use_tempaddr : NM_SETTING_IP6_CONFIG_PRIVACY_UNKNOWN);
+ /* Allow setting MTU etc */
+ if (commit) {
+ if (NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit)
+ NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit (self, composite);
+ }
+
success = nm_device_set_ip6_config (self, composite, commit, out_reason);
g_object_unref (composite);
return success;
@@ -3289,9 +3296,9 @@ nm_device_dhcp6_renew (NMDevice *self, gboolean release)
/******************************************/
static gboolean
-linklocal6_config_is_ready (const NMIP6Config *ip6_config)
+have_ip6_address (const NMIP6Config *ip6_config, gboolean linklocal)
{
- int i;
+ guint i;
if (!ip6_config)
return FALSE;
@@ -3299,7 +3306,7 @@ linklocal6_config_is_ready (const NMIP6Config *ip6_config)
for (i = 0; i < nm_ip6_config_get_num_addresses (ip6_config); i++) {
const NMPlatformIP6Address *addr = nm_ip6_config_get_address (ip6_config, i);
- if (IN6_IS_ADDR_LINKLOCAL (&addr->address) &&
+ if ((IN6_IS_ADDR_LINKLOCAL (&addr->address) == linklocal) &&
!(addr->flags & IFA_F_TENTATIVE))
return TRUE;
}
@@ -3339,7 +3346,7 @@ linklocal6_complete (NMDevice *self)
const char *method;
g_assert (priv->linklocal6_timeout_id);
- g_assert (linklocal6_config_is_ready (priv->ip6_config));
+ g_assert (have_ip6_address (priv->ip6_config, TRUE));
linklocal6_cleanup (self);
@@ -3370,7 +3377,7 @@ linklocal6_start (NMDevice *self)
linklocal6_cleanup (self);
- if (linklocal6_config_is_ready (priv->ip6_config))
+ if (have_ip6_address (priv->ip6_config, TRUE))
return NM_ACT_STAGE_RETURN_SUCCESS;
connection = nm_device_get_connection (self);
@@ -3591,6 +3598,30 @@ rdisc_config_changed (NMRDisc *rdisc, NMRDiscConfigMap changed, NMDevice *self)
nm_device_activate_schedule_ip6_config_result (self);
}
+static void
+rdisc_ra_timeout (NMRDisc *rdisc, NMDevice *self)
+{
+ NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
+
+ /* We don't want to stop listening for router advertisements completely,
+ * but instead let device activation continue activating. If an RA
+ * shows up later, we'll use it as long as the device is not disconnected.
+ */
+
+ _LOGD (LOGD_IP6, "timed out waiting for IPv6 router advertisement");
+ if (priv->ip6_state == IP_CONF) {
+ /* If RA is our only source of addressing information and we don't
+ * ever receive one, then time out IPv6. But if there is other
+ * IPv6 configuration, like manual IPv6 addresses or external IPv6
+ * config, consider that sufficient for IPv6 success.
+ */
+ if (have_ip6_address (priv->ip6_config, FALSE))
+ nm_device_activate_schedule_ip6_config_result (self);
+ else
+ nm_device_activate_schedule_ip6_config_timeout (self);
+ }
+}
+
static gboolean
addrconf6_start_with_link_ready (NMDevice *self)
{
@@ -3605,13 +3636,23 @@ addrconf6_start_with_link_ready (NMDevice *self)
}
nm_rdisc_set_iid (priv->rdisc, iid);
+ /* Apply any manual configuration before starting RA */
+ if (!ip6_config_merge_and_apply (self, TRUE, NULL))
+ _LOGW (LOGD_IP6, "failed to apply manual IPv6 configuration");
+
nm_device_ipv6_sysctl_set (self, "accept_ra", "1");
nm_device_ipv6_sysctl_set (self, "accept_ra_defrtr", "0");
nm_device_ipv6_sysctl_set (self, "accept_ra_pinfo", "0");
nm_device_ipv6_sysctl_set (self, "accept_ra_rtr_pref", "0");
- priv->rdisc_config_changed_sigid = g_signal_connect (priv->rdisc, NM_RDISC_CONFIG_CHANGED,
- G_CALLBACK (rdisc_config_changed), self);
+ priv->rdisc_changed_id = g_signal_connect (priv->rdisc,
+ NM_RDISC_CONFIG_CHANGED,
+ G_CALLBACK (rdisc_config_changed),
+ self);
+ priv->rdisc_timeout_id = g_signal_connect (priv->rdisc,
+ NM_RDISC_RA_TIMEOUT,
+ G_CALLBACK (rdisc_ra_timeout),
+ self);
nm_rdisc_start (priv->rdisc);
return TRUE;
}
@@ -3662,10 +3703,14 @@ addrconf6_cleanup (NMDevice *self)
{
NMDevicePrivate *priv = NM_DEVICE_GET_PRIVATE (self);
- if (priv->rdisc_config_changed_sigid) {
- g_signal_handler_disconnect (priv->rdisc,
- priv->rdisc_config_changed_sigid);
- priv->rdisc_config_changed_sigid = 0;
+ if (priv->rdisc_changed_id) {
+ g_signal_handler_disconnect (priv->rdisc, priv->rdisc_changed_id);
+ priv->rdisc_changed_id = 0;
+ }
+
+ if (priv->rdisc_timeout_id) {
+ g_signal_handler_disconnect (priv->rdisc, priv->rdisc_timeout_id);
+ priv->rdisc_timeout_id = 0;
}
nm_device_remove_pending_action (self, PENDING_ACTION_AUTOCONF6, FALSE);
@@ -4600,10 +4645,6 @@ nm_device_activate_ip6_config_commit (gpointer user_data)
/* Device should be up before we can do anything with it */
g_warn_if_fail (nm_platform_link_is_up (nm_device_get_ip_ifindex (self)));
- /* Allow setting MTU etc */
- if (NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit)
- NM_DEVICE_GET_CLASS (self)->ip6_config_pre_commit (self);
-
if (ip6_config_merge_and_apply (self, TRUE, &reason)) {
/* If IPv6 wasn't the first IP to complete, and DHCP was used,
* then ensure dispatcher scripts get the DHCP lease information.
@@ -4647,6 +4688,12 @@ nm_device_activate_schedule_ip6_config_result (NMDevice *self)
g_return_if_fail (NM_IS_DEVICE (self));
+ /* If IP had previously failed, move it back to IP_CONF since we
+ * clearly now have configuration.
+ */
+ if (priv->ip6_state == IP_FAIL)
+ priv->ip6_state = IP_CONF;
+
activation_source_schedule (self, nm_device_activate_ip6_config_commit, AF_INET6);
_LOG (level, LOGD_DEVICE | LOGD_IP6,
@@ -5821,7 +5868,7 @@ update_ip_config (NMDevice *self, gboolean initial)
/* Check this before modifying ext_ip6_config */
linklocal6_just_completed = priv->linklocal6_timeout_id &&
- linklocal6_config_is_ready (priv->ext_ip6_config);
+ have_ip6_address (priv->ext_ip6_config, TRUE);
if (priv->ac_ip6_config)
nm_ip6_config_subtract (priv->ext_ip6_config, priv->ac_ip6_config);
diff --git a/src/devices/nm-device.h b/src/devices/nm-device.h
index e570803fa8..3ac3fd6897 100644
--- a/src/devices/nm-device.h
+++ b/src/devices/nm-device.h
@@ -180,7 +180,7 @@ typedef struct {
/* Called right before IP config is set; use for setting MTU etc */
void (* ip4_config_pre_commit) (NMDevice *self, NMIP4Config *config);
- void (* ip6_config_pre_commit) (NMDevice *self);
+ void (* ip6_config_pre_commit) (NMDevice *self, NMIP6Config *config);
void (* deactivate) (NMDevice *self);
diff --git a/src/rdisc/nm-lndp-rdisc.c b/src/rdisc/nm-lndp-rdisc.c
index 87934e65a8..1ec8921ee9 100644
--- a/src/rdisc/nm-lndp-rdisc.c
+++ b/src/rdisc/nm-lndp-rdisc.c
@@ -40,7 +40,8 @@ typedef struct {
guint send_rs_id;
GIOChannel *event_channel;
guint event_id;
- guint timeout_id;
+ guint timeout_id; /* prefix/dns/etc lifetime timeout */
+ guint ra_timeout_id; /* first RA timeout */
int solicitations_left;
} NMLNDPRDiscPrivate;
@@ -433,11 +434,32 @@ translate_preference (enum ndp_route_preference preference)
}
}
+static void
+clear_rs_timeout (NMLNDPRDisc *rdisc)
+{
+ NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
+
+ if (priv->send_rs_id) {
+ g_source_remove (priv->send_rs_id);
+ priv->send_rs_id = 0;
+ }
+}
+
+static void
+clear_ra_timeout (NMLNDPRDisc *rdisc)
+{
+ NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
+
+ if (priv->ra_timeout_id) {
+ g_source_remove (priv->ra_timeout_id);
+ priv->ra_timeout_id = 0;
+ }
+}
+
static int
receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
{
NMRDisc *rdisc = (NMRDisc *) user_data;
- NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
NMRDiscConfigMap changed = 0;
struct ndp_msgra *msgra = ndp_msgra (msg);
NMRDiscGateway gateway;
@@ -458,10 +480,8 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
*/
debug ("(%s): received router advertisement at %u", rdisc->ifname, now);
- if (priv->send_rs_id) {
- g_source_remove (priv->send_rs_id);
- priv->send_rs_id = 0;
- }
+ clear_ra_timeout (NM_LNDP_RDISC (rdisc));
+ clear_rs_timeout (NM_LNDP_RDISC (rdisc));
/* DHCP level:
*
@@ -606,21 +626,25 @@ receive_ra (struct ndp *ndp, struct ndp_msg *msg, gpointer user_data)
return 0;
}
-static void
-process_events (NMRDisc *rdisc)
+static gboolean
+event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc)
{
NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
debug ("(%s): processing libndp events.", rdisc->ifname);
ndp_callall_eventfd_handler (priv->ndp);
+ return G_SOURCE_CONTINUE;
}
static gboolean
-event_ready (GIOChannel *source, GIOCondition condition, NMRDisc *rdisc)
+rdisc_ra_timeout_cb (gpointer user_data)
{
- process_events (rdisc);
+ NMLNDPRDisc *rdisc = NM_LNDP_RDISC (user_data);
+ NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
- return TRUE;
+ priv->ra_timeout_id = 0;
+ g_signal_emit_by_name (rdisc, NM_RDISC_RA_TIMEOUT);
+ return G_SOURCE_REMOVE;
}
static void
@@ -628,14 +652,20 @@ start (NMRDisc *rdisc)
{
NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
int fd = ndp_get_eventfd (priv->ndp);
+ guint ra_wait_secs;
priv->event_channel = g_io_channel_unix_new (fd);
priv->event_id = g_io_add_watch (priv->event_channel, G_IO_IN, (GIOFunc) event_ready, rdisc);
+ clear_ra_timeout (NM_LNDP_RDISC (rdisc));
+ ra_wait_secs = CLAMP (rdisc->rtr_solicitations * rdisc->rtr_solicitation_interval, 30, 120);
+ priv->ra_timeout_id = g_timeout_add_seconds (ra_wait_secs, rdisc_ra_timeout_cb, rdisc);
+ debug ("(%s): scheduling RA timeout in %d seconds", rdisc->ifname, ra_wait_secs);
+
/* Flush any pending messages to avoid using obsolete information */
- process_events (rdisc);
+ event_ready (priv->event_channel, 0, rdisc);
- ndp_msgrcv_handler_register (priv->ndp, &receive_ra, NDP_MSG_RA, rdisc->ifindex, rdisc);
+ ndp_msgrcv_handler_register (priv->ndp, receive_ra, NDP_MSG_RA, rdisc->ifindex, rdisc);
solicit (rdisc);
}
@@ -647,21 +677,29 @@ nm_lndp_rdisc_init (NMLNDPRDisc *lndp_rdisc)
}
static void
-nm_lndp_rdisc_finalize (GObject *object)
+dispose (GObject *object)
{
- NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (object);
+ NMLNDPRDisc *rdisc = NM_LNDP_RDISC (object);
+ NMLNDPRDiscPrivate *priv = NM_LNDP_RDISC_GET_PRIVATE (rdisc);
- if (priv->send_rs_id)
- g_source_remove (priv->send_rs_id);
- if (priv->timeout_id)
+ clear_rs_timeout (rdisc);
+ clear_ra_timeout (rdisc);
+
+ if (priv->timeout_id) {
g_source_remove (priv->timeout_id);
- if (priv->event_channel)
- g_io_channel_unref (priv->event_channel);
- if (priv->event_id)
+ priv->timeout_id = 0;
+ }
+
+ if (priv->event_id) {
g_source_remove (priv->event_id);
+ priv->event_id = 0;
+ }
+ g_clear_pointer (&priv->event_channel, g_io_channel_unref);
- if (priv->ndp)
+ if (priv->ndp) {
ndp_close (priv->ndp);
+ priv->ndp = NULL;
+ }
}
static void
@@ -672,6 +710,6 @@ nm_lndp_rdisc_class_init (NMLNDPRDiscClass *klass)
g_type_class_add_private (klass, sizeof (NMLNDPRDiscPrivate));
- object_class->finalize = nm_lndp_rdisc_finalize;
+ object_class->dispose = dispose;
rdisc_class->start = start;
}
diff --git a/src/rdisc/nm-rdisc.c b/src/rdisc/nm-rdisc.c
index d3dc14a194..a326e6f03f 100644
--- a/src/rdisc/nm-rdisc.c
+++ b/src/rdisc/nm-rdisc.c
@@ -32,6 +32,7 @@ G_DEFINE_TYPE (NMRDisc, nm_rdisc, G_TYPE_OBJECT)
enum {
CONFIG_CHANGED,
+ RA_TIMEOUT,
LAST_SIGNAL
};
@@ -184,4 +185,12 @@ nm_rdisc_class_init (NMRDiscClass *klass)
G_STRUCT_OFFSET (NMRDiscClass, config_changed),
NULL, NULL, NULL,
G_TYPE_NONE, 1, G_TYPE_INT);
+
+ signals[RA_TIMEOUT] = g_signal_new (
+ NM_RDISC_RA_TIMEOUT,
+ G_OBJECT_CLASS_TYPE (klass),
+ G_SIGNAL_RUN_FIRST,
+ G_STRUCT_OFFSET (NMRDiscClass, ra_timeout),
+ NULL, NULL, NULL,
+ G_TYPE_NONE, 0);
}
diff --git a/src/rdisc/nm-rdisc.h b/src/rdisc/nm-rdisc.h
index 35db3c917f..f4ebc228a9 100644
--- a/src/rdisc/nm-rdisc.h
+++ b/src/rdisc/nm-rdisc.h
@@ -36,6 +36,7 @@
#define NM_RDISC_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_RDISC, NMRDiscClass))
#define NM_RDISC_CONFIG_CHANGED "config-changed"
+#define NM_RDISC_RA_TIMEOUT "ra-timeout"
typedef enum {
NM_RDISC_DHCP_LEVEL_UNKNOWN,
@@ -131,6 +132,7 @@ typedef struct {
void (*start) (NMRDisc *rdisc);
void (*config_changed) (NMRDisc *rdisc, NMRDiscConfigMap changed);
+ void (*ra_timeout) (NMRDisc *rdisc);
} NMRDiscClass;
GType nm_rdisc_get_type (void);