[PATCH v2] ip6-manager: Fix SLAAC/DHCPv6 interaction



This patch fixes NM's incorrect assumption that SLAAC and Stateful
DHCPv6 are mutually exclusive configuration methods. It does this by
lowering the initial target state of the device to "got-ra" rather than
the previous "got-address" (which implies SLAAC has been performed, not
DHCPv6). If an RA is seen containing a prefix with the Autonomous flag
set, the target state is increased to "got-address" so that NM will
expect the kernel to perform SLAAC.

A side-effect of lowering the initial target state to "got-ra" is that
will be possible for a connection to succeed even if NM has not
configured any (non-link-local) addresses. This will happen if the RA
received has the Managed flag unset, and also contains no Prefix
Information Options (or that all PIOs have the Autonomous flag unset).
While such a connection may be of questionable usability to an end user,
calling it a success it not really unreasonable; after all, NM will have
successfully configured the host according to the network admin's
specifications (which could include addition of a default routes,
on-link prefix routes, recursive DNS servers, and so forth).

It also improves some debugging output that incorrectly implied that
Stateful DHCPv6 supersede RA/SLAAC and that Information-Only DHCPv6 is
the only form of DHCPv6 that should be done in parallel with SLAAC.

The patch will not apply cleanly without "[PATCH] ip6-manager: Accept
RAs when forwarding". The two patches are functionally independent of
each other, though.

(rh #720188)
---
 src/ip6-manager/nm-ip6-manager.c |   33 ++++++++++++++++++++-------------
 1 files changed, 20 insertions(+), 13 deletions(-)

diff --git a/src/ip6-manager/nm-ip6-manager.c b/src/ip6-manager/nm-ip6-manager.c
index 03f5cc4..8ccdc11 100644
--- a/src/ip6-manager/nm-ip6-manager.c
+++ b/src/ip6-manager/nm-ip6-manager.c
@@ -41,6 +41,8 @@
 #define IF_RA_MANAGED   0x40
 #define IF_RA_RCVD      0x20
 #define IF_RS_SENT      0x10
+#define IF_PREFIX_ONLINK	0x01
+#define IF_PREFIX_AUTOCONF	0x02
 
 typedef struct {
 	NMNetlinkMonitor *monitor;
@@ -68,7 +70,7 @@ typedef enum {
 	NM_IP6_DEVICE_UNCONFIGURED,
 	NM_IP6_DEVICE_GOT_LINK_LOCAL,
 	NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT,
-	NM_IP6_DEVICE_GOT_ADDRESS,
+	NM_IP6_DEVICE_GOT_ADDRESS, /* Note: Used for SLAAC only, not DHCPv6 */
 	NM_IP6_DEVICE_TIMED_OUT
 } NMIP6DeviceState;
 
@@ -459,8 +461,7 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
 	nm_log_dbg (LOGD_IP6, "(%s): addresses synced (state %s)",
 	            device->iface, state_to_string (device->state));
 
-	/* We only care about router advertisements if we want a real IPv6 address */
-	if (   (device->target_state == NM_IP6_DEVICE_GOT_ADDRESS)
+	if (   (device->target_state >= NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
 	    && (device->ra_flags & IF_RA_RCVD)) {
 
 		if (device->state < NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT)
@@ -468,27 +469,22 @@ nm_ip6_device_sync_from_netlink (NMIP6Device *device, gboolean config_changed)
 
 		if (device->ra_flags & IF_RA_MANAGED) {
 			dhcp_opts = IP6_DHCP_OPT_MANAGED;
-			nm_log_dbg (LOGD_IP6, "router advertisement deferred to DHCPv6");
+			nm_log_dbg (LOGD_IP6, "router advertisement requests Stateful DHCPv6");
 		} else if (device->ra_flags & IF_RA_OTHERCONF) {
 			dhcp_opts = IP6_DHCP_OPT_OTHERCONF;
-			nm_log_dbg (LOGD_IP6, "router advertisement requests parallel DHCPv6");
+			nm_log_dbg (LOGD_IP6, "router advertisement requests Information-Only DHCPv6");
 		}
 	}
 
 	if (!device->addrconf_complete) {
-		/* Managed mode (ie DHCP only) short-circuits automatic addrconf, so
-		 * we don't bother waiting for the device's target state to be reached
-		 * when the RA requests managed mode.
-		 */
-		if (   (device->state >= device->target_state)
-		    || (dhcp_opts == IP6_DHCP_OPT_MANAGED)) {
+		if (device->state >= device->target_state) {
 			/* device->finish_addrconf_id may currently be a timeout
 			 * rather than an idle, so we remove the existing source.
 			 */
 			if (device->finish_addrconf_id)
 				g_source_remove (device->finish_addrconf_id);
 
-			nm_log_dbg (LOGD_IP6, "(%s): reached target state or Managed-mode requested (state '%s') (dhcp opts 0x%X)",
+			nm_log_dbg (LOGD_IP6, "(%s): reached target state (state '%s') (dhcp opts 0x%X)",
 			            device->iface, state_to_string (device->state),
 			            dhcp_opts);
 
@@ -631,6 +627,12 @@ process_prefix (NMIP6Manager *manager, struct nl_msg *msg)
 		return NULL;
 	}
 
+	if(pmsg->prefix_flags & IF_PREFIX_AUTOCONF) {
+		nm_log_dbg (LOGD_IP6, "(%s): prefix requests stateless autoconf",
+			    device->iface);
+		device->target_state = NM_IP6_DEVICE_GOT_ADDRESS;
+	}
+
 	return device;
 }
 
@@ -1088,7 +1090,12 @@ nm_ip6_manager_prepare_interface (NMIP6Manager *manager,
 		device->target_state = NM_IP6_DEVICE_GOT_LINK_LOCAL;
 		nm_utils_do_sysctl (accept_ra_path, "0\n");
 	} else {
-		device->target_state = NM_IP6_DEVICE_GOT_ADDRESS;
+		/* To begin with, the target state is only got-ra. We will
+		 * increase it to got-address later, if we see a prefix
+		 * being advertised with the Autonomous flag set, cf.
+		 * process_prefix() above.
+		 */
+		device->target_state = NM_IP6_DEVICE_GOT_ROUTER_ADVERTISEMENT;
 		nm_utils_do_sysctl (accept_ra_path, "2\n");
 	}
 
-- 
1.7.6



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]