mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-01-30 21:32:46 +00:00
ip6/nd6: route using on-link prefixes, not addresses
As laid out in RFC 5942, the assumption that a dynamically assigned (SLAAC/DHCPv6) address implies an on-link subnet, is wrong. lwIP does currently make that assumption, routing packets according to local address subnets rather than the on-link prefix list. The result is that packets may not make it to their destination due to incorrect routing decisions. This patch changes the routing algorithms to be (more) compliant with RFC 5942, by implementing the following new routing policies: - all routing decisions check the on-link prefix list first, and select a default router for off-link routing only if there is no matching entry in the on-link prefix list; - dynamically assigned addresses (from address autoconfiguration) are considered /128 assignments, and thus, no routing decisions are taken based on matches against their (/64) subnet anymore; - more generally, all addresses that have a lifetime are considered dynamically assigned and thus of size /128, which is the required behavior for externally implemented SLAAC clients and DHCPv6; - statically assigned (i.e., manually configured) addresses are still considered /64 assignments, and thus, their associated subnet is considered for routing decisions, in order to behave as generally expected by end users and to retain backward compatibility; - the link-local address in IPv6 address slot #0 is considered static and thus has no lifetime and an implied /64 subnet, although link- local routing is currently always handled separately anyway. IPv6 source address selection is kept as is, as the subnet tests in the algorithm serve as poor man's longest-common-prefix equivalent there (RFC 6724 Sec. 5, Rule 8).
This commit is contained in:
parent
22c2fd1b58
commit
08de0e9617
@ -68,7 +68,7 @@
|
||||
* this is a tricky case because with multiple netifs, link-local addresses only have
|
||||
* meaning within a particular subnet/link.
|
||||
* 3) tries to match the destination subnet to a configured address
|
||||
* 4) tries to find a router
|
||||
* 4) tries to find a router-announced route
|
||||
* 5) tries to match the source address to the netif
|
||||
* 6) returns the default netif, if configured
|
||||
*
|
||||
@ -130,20 +130,27 @@ ip6_route(const ip6_addr_t *src, const ip6_addr_t *dest)
|
||||
}
|
||||
#endif
|
||||
|
||||
/* See if the destination subnet matches a configured address. */
|
||||
/* See if the destination subnet matches a configured address. In accordance
|
||||
* with RFC 5942, dynamically configured addresses do not have an implied
|
||||
* local subnet, and thus should be considered /128 assignments. However, as
|
||||
* such, the destination address may still match a local address, and so we
|
||||
* still need to check for exact matches here. By (lwIP) policy, statically
|
||||
* configured addresses do always have an implied local /64 subnet. */
|
||||
for (netif = netif_list; netif != NULL; netif = netif->next) {
|
||||
if (!netif_is_up(netif) || !netif_is_link_up(netif)) {
|
||||
continue;
|
||||
}
|
||||
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
|
||||
ip6_addr_netcmp(dest, netif_ip6_addr(netif, i))) {
|
||||
ip6_addr_netcmp(dest, netif_ip6_addr(netif, i)) &&
|
||||
(netif_ip6_addr_isstatic(netif, i) ||
|
||||
ip6_addr_nethostcmp(dest, netif_ip6_addr(netif, i)))) {
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Get the netif for a suitable router. */
|
||||
/* Get the netif for a suitable router-announced route. */
|
||||
netif = nd6_find_route(dest);
|
||||
if (netif != NULL) {
|
||||
return netif;
|
||||
|
@ -1484,7 +1484,8 @@ nd6_clear_destination_cache(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether an address matches an on-link prefix.
|
||||
* Determine whether an address matches an on-link prefix or the subnet of a
|
||||
* statically assigned address.
|
||||
*
|
||||
* @param ip6addr the IPv6 address to match
|
||||
* @return 1 if the address is on-link, 0 otherwise
|
||||
@ -1493,6 +1494,8 @@ static s8_t
|
||||
nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif)
|
||||
{
|
||||
s8_t i;
|
||||
|
||||
/* Check to see if the address matches an on-link prefix. */
|
||||
for (i = 0; i < LWIP_ND6_NUM_PREFIXES; i++) {
|
||||
if ((prefix_list[i].netif == netif) &&
|
||||
(prefix_list[i].invalidation_timer > 0) &&
|
||||
@ -1500,9 +1503,13 @@ nd6_is_prefix_in_netif(const ip6_addr_t *ip6addr, struct netif *netif)
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
/* Check to see if address prefix matches a (manually?) configured address. */
|
||||
/* Check to see if address prefix matches a manually configured (= static)
|
||||
* address. Static addresses have an implied /64 subnet assignment. Dynamic
|
||||
* addresses (from autoconfiguration) have no implied subnet assignment, and
|
||||
* are thus effectively /128 assignments. See RFC 5942 for more on this. */
|
||||
for (i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) {
|
||||
if (ip6_addr_isvalid(netif_ip6_addr_state(netif, i)) &&
|
||||
netif_ip6_addr_isstatic(netif, i) &&
|
||||
ip6_addr_netcmp(ip6addr, netif_ip6_addr(netif, i))) {
|
||||
return 1;
|
||||
}
|
||||
@ -1586,7 +1593,8 @@ nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif)
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a router-announced route to the given destination.
|
||||
* Find a router-announced route to the given destination. This route may be
|
||||
* based on an on-link prefix or a default router.
|
||||
*
|
||||
* If a suitable route is found, the returned netif is guaranteed to be in a
|
||||
* suitable state (up, link up) to be used for packet transmission.
|
||||
@ -1597,8 +1605,22 @@ nd6_select_router(const ip6_addr_t *ip6addr, struct netif *netif)
|
||||
struct netif *
|
||||
nd6_find_route(const ip6_addr_t *ip6addr)
|
||||
{
|
||||
struct netif *netif;
|
||||
s8_t i;
|
||||
|
||||
/* @todo decide if it makes sense to check the destination cache first */
|
||||
|
||||
/* Check if there is a matching on-link prefix. There may be multiple
|
||||
* matches. Pick the first one that is associated with a suitable netif. */
|
||||
for (i = 0; i < LWIP_ND6_NUM_PREFIXES; ++i) {
|
||||
netif = prefix_list[i].netif;
|
||||
if ((netif != NULL) && ip6_addr_netcmp(&prefix_list[i].prefix, ip6addr) &&
|
||||
netif_is_up(netif) && netif_is_link_up(netif)) {
|
||||
return netif;
|
||||
}
|
||||
}
|
||||
|
||||
/* No on-link prefix match. Find a router that can forward the packet. */
|
||||
i = nd6_select_router(ip6addr, NULL);
|
||||
if (i >= 0) {
|
||||
LWIP_ASSERT("selected router must have a neighbor entry",
|
||||
|
@ -133,6 +133,10 @@ typedef struct ip6_addr ip6_addr_t;
|
||||
#define ip6_addr_netcmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
|
||||
((addr1)->addr[1] == (addr2)->addr[1]))
|
||||
|
||||
/* Exact-host comparison *after* ip6_addr_netcmp() succeeded, for efficiency. */
|
||||
#define ip6_addr_nethostcmp(addr1, addr2) (((addr1)->addr[2] == (addr2)->addr[2]) && \
|
||||
((addr1)->addr[3] == (addr2)->addr[3]))
|
||||
|
||||
#define ip6_addr_cmp(addr1, addr2) (((addr1)->addr[0] == (addr2)->addr[0]) && \
|
||||
((addr1)->addr[1] == (addr2)->addr[1]) && \
|
||||
((addr1)->addr[2] == (addr2)->addr[2]) && \
|
||||
|
Loading…
x
Reference in New Issue
Block a user