diff options
author | Dan Williams <dcbw@redhat.com> | 2014-08-29 16:03:42 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2014-08-29 16:03:42 -0500 |
commit | 0c54a617e9b4019c24b5f2da047885cfae843c08 (patch) | |
tree | d0856d28a69057140987cd10b014f13637bfbff7 | |
parent | bc18992dd8fbbc1ce5e0c3ca6a6e13b62ae93d91 (diff) | |
parent | cbcca18149544ab97564871b1626eb269cac026e (diff) | |
download | NetworkManager-0c54a617e9b4019c24b5f2da047885cfae843c08.tar.gz |
merge: apply static IPv6 configuration before starting SLAAC (rh #1101809)
-rw-r--r-- | src/devices/nm-device.c | 81 | ||||
-rw-r--r-- | src/devices/nm-device.h | 2 | ||||
-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 |
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); |