diff options
author | Dan Williams <dcbw@redhat.com> | 2014-08-13 09:40:08 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2014-08-29 16:03:36 -0500 |
commit | 7c9d4e8f5a0f4d64ae0ec218928ca2641ae7e9c9 (patch) | |
tree | 38d2be09e2c0582208e9ecadffc2092e52b27081 | |
parent | bc18992dd8fbbc1ce5e0c3ca6a6e13b62ae93d91 (diff) | |
download | NetworkManager-7c9d4e8f5a0f4d64ae0ec218928ca2641ae7e9c9.tar.gz |
rdisc: add RA wait timeout
Add an advisory timeout when waiting for router advertisements so
we can fail IPv6 addressing attempts when no router advertisement
has been received.
-rw-r--r-- | src/devices/nm-device.c | 46 | ||||
-rw-r--r-- | src/rdisc/nm-lndp-rdisc.c | 84 | ||||
-rw-r--r-- | src/rdisc/nm-rdisc.c | 9 | ||||
-rw-r--r-- | src/rdisc/nm-rdisc.h | 2 |
4 files changed, 111 insertions, 30 deletions
diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 265cf938e2..7edd2a7310 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; @@ -3591,6 +3592,21 @@ 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) + nm_device_activate_schedule_ip6_config_timeout (self); +} + static gboolean addrconf6_start_with_link_ready (NMDevice *self) { @@ -3610,8 +3626,14 @@ addrconf6_start_with_link_ready (NMDevice *self) 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 +3684,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); @@ -4647,6 +4673,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, 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); |