nd6: improve address autoconfiguration support

In summary, this patch aims to resolve bugs #47923 and #48162, by
decoupling address autoconfiguration from the on-link prefix list,
since those are not related. Important necessary changes are needed
to meet this goal, ultimately bringing the lwIP ND6 implementation
closer to compliance with RFC 4862. The main changes are:

  1. support for address lifetimes, and,
  2. addition of a new DUPLICATED address state.

The decoupling implies that the prefix list can no longer be used to
maintain state for address autoconfiguration. Most importantly, the
lifetime of each address, which was previously derived from the
prefix slot's lifetime, must now be associated with the address
itself. This patch implements address lifetime tracking, maintaining
both a valid and a preferred lifetime for each address, along with
the corresponding address state changes (e.g., between PREFERRED and
DEPRECATED), all as required by RFC 4862.

The support for address lifetimes can be enabled with a new
LWIP_IPV6_ADDRESS_LIFETIMES setting in lwipopts.h. It is required for
autoconfiguration and enabled by default if autoconfiguration is
enabled as well, but it may also be enabled separately, so as to allow
application-controlled lifetime management (e.g., if autoconfiguration
is implemented in a separate application). A special valid-lifetime of
zero is used to denote a static address--that is, an address that was
configured manually, that does not have lifetimes, and that should be
left alone by the autoconfiguration functionality. Addresses assigned
without setting a lifetime are deemed static, thus preserving
compatibility with existing lwIP-based applications in this respect.

Similarly, the decoupling implies that the prefix list can no longer
be used to remember cases of address duplication. Previously, the
detection of a duplicated address would simply result in removal of
the address altogether. Instead, this patch introduces a new state
"DUPLICATED", indicating that the address, while technically still
present, has been found to conflict with other node addresses, and no
attempt should be made to produce an autoconfiguration address for
that prefix.

Manually added addresses, including the link-local address, once set
to DUPLICATED, will remain in that state until manual intervention.
Autoconfigured DUPLICATED addresses will expire according to their
valid-lifetime, essentially preserving the current behavior but
without the use of the prefix list. As a first attempt to approach
compliance with RFC 4862 Sec. 5.4.5, if the link-local address is
detected to be duplicated, all derived addresses are marked duplicated
as well, and no new addresses will be autoconfigured. More work is to
be done for full compliance with that section, however.

Together, those two main changes indeed do fully decouple address
autoconfiguration from the on-link prefix list. Changes to the latter
thus no longer affect the former, resolving bug #47923. Moreover, as a
result, autoconfiguration can, and does, now also take place on
advertised prefixes that do not have the on-link flag set, resolving
bug #48162. The routing changes mentioned in the discussion of that
bug are left to a separate patch, though.
This commit is contained in:
David van Moolenbroek
2016-12-29 21:03:41 +00:00
committed by Dirk Ziegelmeier
parent 3cc7b319d9
commit e0c5e1988f
6 changed files with 292 additions and 115 deletions

View File

@@ -234,6 +234,7 @@ typedef struct ip6_addr ip6_addr_t;
#define IP6_ADDR_VALID 0x10 /* This bit marks an address as valid (preferred or deprecated) */
#define IP6_ADDR_PREFERRED 0x30
#define IP6_ADDR_DEPRECATED 0x10 /* Same as VALID (valid but not preferred) */
#define IP6_ADDR_DUPLICATED 0x40 /* Failed DAD test, not valid */
#define IP6_ADDR_TENTATIVE_COUNT_MASK 0x07 /* 1-7 probes sent */
@@ -242,6 +243,14 @@ typedef struct ip6_addr ip6_addr_t;
#define ip6_addr_isvalid(addr_state) (addr_state & IP6_ADDR_VALID) /* Include valid, preferred, and deprecated. */
#define ip6_addr_ispreferred(addr_state) (addr_state == IP6_ADDR_PREFERRED)
#define ip6_addr_isdeprecated(addr_state) (addr_state == IP6_ADDR_DEPRECATED)
#define ip6_addr_isduplicated(addr_state) (addr_state == IP6_ADDR_DUPLICATED)
#if LWIP_IPV6_ADDRESS_LIFETIMES
#define IP6_ADDR_LIFE_STATIC (0)
#define IP6_ADDR_LIFE_INFINITE (0xffffffffUL)
#define ip6_addr_life_isstatic(addr_life) ((addr_life) == IP6_ADDR_LIFE_STATIC)
#define ip6_addr_life_isinfinite(addr_life) ((addr_life) == IP6_ADDR_LIFE_INFINITE)
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
#define ip6_addr_debug_print_parts(debug, a, b, c, d, e, f, g, h) \
LWIP_DEBUGF(debug, ("%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F ":%" X16_F, \

View File

@@ -238,6 +238,13 @@ struct netif {
/** The state of each IPv6 address (Tentative, Preferred, etc).
* @see ip6_addr.h */
u8_t ip6_addr_state[LWIP_IPV6_NUM_ADDRESSES];
#if LWIP_IPV6_ADDRESS_LIFETIMES
/** Remaining valid and preferred lifetime of each IPv6 address, in seconds.
* For valid lifetimes, the special value of IP6_ADDR_LIFE_STATIC (0)
* indicates the address is static and has no lifetimes. */
u32_t ip6_addr_valid_life[LWIP_IPV6_NUM_ADDRESSES];
u32_t ip6_addr_pref_life[LWIP_IPV6_NUM_ADDRESSES];
#endif /* LWIP_IPV6_ADDRESS_LIFETIMES */
#endif /* LWIP_IPV6 */
/** This function is called by the network device driver
* to pass a packet up the TCP/IP stack. */
@@ -459,6 +466,20 @@ s8_t netif_get_ip6_addr_match(struct netif *netif, const ip6_addr_t *ip6addr);
void netif_create_ip6_linklocal_address(struct netif *netif, u8_t from_mac_48bit);
err_t netif_add_ip6_address(struct netif *netif, const ip6_addr_t *ip6addr, s8_t *chosen_idx);
#define netif_set_ip6_autoconfig_enabled(netif, action) do { if(netif) { (netif)->ip6_autoconfig_enabled = (action); }}while(0)
#if LWIP_IPV6_ADDRESS_LIFETIMES
#define netif_ip6_addr_valid_life(netif, i) \
(((netif) != NULL) ? ((netif)->ip6_addr_valid_life[i]) : IP6_ADDR_LIFE_STATIC)
#define netif_ip6_addr_set_valid_life(netif, i, secs) \
do { if (netif != NULL) { (netif)->ip6_addr_valid_life[i] = (secs); }} while (0)
#define netif_ip6_addr_pref_life(netif, i) \
(((netif) != NULL) ? ((netif)->ip6_addr_pref_life[i]) : IP6_ADDR_LIFE_STATIC)
#define netif_ip6_addr_set_pref_life(netif, i, secs) \
do { if (netif != NULL) { (netif)->ip6_addr_pref_life[i] = (secs); }} while (0)
#define netif_ip6_addr_isstatic(netif, i) \
(netif_ip6_addr_valid_life((netif), (i)) == IP6_ADDR_LIFE_STATIC)
#else /* !LWIP_IPV6_ADDRESS_LIFETIMES */
#define netif_ip6_addr_isstatic(netif, i) (1) /* all addresses are static */
#endif /* !LWIP_IPV6_ADDRESS_LIFETIMES */
#endif /* LWIP_IPV6 */
#if LWIP_NETIF_HWADDRHINT

View File

@@ -2198,6 +2198,17 @@
#define LWIP_IPV6_AUTOCONFIG (LWIP_IPV6)
#endif
/**
* LWIP_IPV6_ADDRESS_LIFETIMES==1: Keep valid and preferred lifetimes for each
* IPv6 address. Required for LWIP_IPV6_AUTOCONFIG. May still be enabled
* otherwise, in which case the application may assign address lifetimes with
* the appropriate macros. Addresses with no lifetime are assumed to be static.
* If this option is disabled, all addresses are assumed to be static.
*/
#if !defined LWIP_IPV6_ADDRESS_LIFETIMES || defined __DOXYGEN__
#define LWIP_IPV6_ADDRESS_LIFETIMES (LWIP_IPV6_AUTOCONFIG)
#endif
/**
* LWIP_IPV6_DUP_DETECT_ATTEMPTS=[0..7]: Number of duplicate address detection attempts.
*/

View File

@@ -83,7 +83,7 @@ struct nd6_neighbor_cache_entry {
u8_t state;
u8_t isrouter;
union {
u32_t reachable_time; /* in ms since value may originate from network packet */
u32_t reachable_time; /* in seconds */
u32_t delay_time; /* ticks (ND6_TMR_INTERVAL) */
u32_t probes_sent;
u32_t stale_time; /* ticks (ND6_TMR_INTERVAL) */
@@ -100,18 +100,12 @@ struct nd6_destination_cache_entry {
struct nd6_prefix_list_entry {
ip6_addr_t prefix;
struct netif *netif;
u32_t invalidation_timer; /* in ms since value may originate from network packet */
#if LWIP_IPV6_AUTOCONFIG
u8_t flags;
#define ND6_PREFIX_AUTOCONFIG_AUTONOMOUS 0x01
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_GENERATED 0x02
#define ND6_PREFIX_AUTOCONFIG_ADDRESS_DUPLICATE 0x04
#endif /* LWIP_IPV6_AUTOCONFIG */
u32_t invalidation_timer; /* in seconds */
};
struct nd6_router_list_entry {
struct nd6_neighbor_cache_entry *neighbor_entry;
u32_t invalidation_timer; /* in ms since value may originate from network packet */
u32_t invalidation_timer; /* in seconds */
u8_t flags;
};
@@ -124,6 +118,8 @@ enum nd6_neighbor_cache_entry_state {
ND6_PROBE
};
#define ND6_2HRS 7200 /* two hours, expressed in number of seconds */
/* Router tables. */
/* @todo make these static? and entries accessible through API? */
extern struct nd6_neighbor_cache_entry neighbor_cache[];