Skip to content

Commit aef83fc

Browse files
jukkarkartben
authored andcommitted
net: if: Allow selecting deprecated IPv6 address as src addr
This adjust the IPv6 source address selection so that it is possible to select deprecated IPv6 address if no better preferred address is found. From RFC 6724 chapter 5: Rule 3: Avoid deprecated addresses. If one of the two source addresses is "preferred" and one of them is "deprecated" (in the RFC 4862 sense), then prefer the one that is "preferred". Rule 8: Use longest matching prefix. If CommonPrefixLen(SA, D) > CommonPrefixLen(SB, D), then prefer SA. Similarly, if CommonPrefixLen(SB, D) > CommonPrefixLen(SA, D), then prefer SB. So the fix allows deprecated address to be selected if it is a better match than the preferred one. The reasoning here is that an address with a longer matching prefix is generally considered topologically closer to the destination. Using such a source address can lead to more efficient routing, as it's more likely that the source and destination are within the same network segment or a closely related one. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
1 parent 1b7eae4 commit aef83fc

File tree

1 file changed

+33
-3
lines changed

1 file changed

+33
-3
lines changed

subsys/net/ip/net_if.c

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3085,10 +3085,12 @@ static uint8_t get_diff_ipv6(const struct in6_addr *src,
30853085

30863086
static inline bool is_proper_ipv6_address(struct net_if_addr *addr)
30873087
{
3088-
if (addr->is_used && addr->addr_state == NET_ADDR_PREFERRED &&
3089-
addr->address.family == AF_INET6 &&
3088+
if (addr->is_used && addr->address.family == AF_INET6 &&
30903089
!net_ipv6_is_ll_addr(&addr->address.in6_addr)) {
3091-
return true;
3090+
if (addr->addr_state == NET_ADDR_PREFERRED ||
3091+
addr->addr_state == NET_ADDR_DEPRECATED) {
3092+
return true;
3093+
}
30923094
}
30933095

30943096
return false;
@@ -3122,6 +3124,7 @@ static struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface,
31223124
uint8_t *best_so_far,
31233125
int flags)
31243126
{
3127+
enum net_addr_state addr_state = NET_ADDR_ANY_STATE;
31253128
struct net_if_ipv6 *ipv6 = iface->config.ip.ipv6;
31263129
struct net_if_addr *public_addr = NULL;
31273130
struct in6_addr *src = NULL;
@@ -3179,6 +3182,25 @@ static struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface,
31793182
continue;
31803183
}
31813184

3185+
if (len == *best_so_far &&
3186+
ipv6->unicast[i].addr_state == NET_ADDR_DEPRECATED &&
3187+
addr_state == NET_ADDR_PREFERRED) {
3188+
/* We have a preferred address and a deprecated
3189+
* address. We prefer the preferred address if the
3190+
* prefix lengths are the same.
3191+
* See RFC 6724 chapter 5.
3192+
*/
3193+
continue;
3194+
}
3195+
3196+
addr_state = ipv6->unicast[i].addr_state;
3197+
3198+
NET_DBG("[%zd] Checking %s (%s) dst %s/%d", i,
3199+
net_sprint_ipv6_addr(&ipv6->unicast[i].address.in6_addr),
3200+
addr_state == NET_ADDR_PREFERRED ? "preferred" :
3201+
addr_state == NET_ADDR_DEPRECATED ? "deprecated" : "?",
3202+
net_sprint_ipv6_addr(dst), prefix_len);
3203+
31823204
ret = use_public_address(iface->pe_prefer_public,
31833205
ipv6->unicast[i].is_temporary,
31843206
flags);
@@ -3228,6 +3250,14 @@ static struct in6_addr *net_if_ipv6_get_best_match(struct net_if *iface,
32283250
out:
32293251
net_if_unlock(iface);
32303252

3253+
if (src != NULL) {
3254+
NET_DBG("Selected %s (%s) dst %s/%d",
3255+
net_sprint_ipv6_addr(src),
3256+
addr_state == NET_ADDR_PREFERRED ? "preferred" :
3257+
addr_state == NET_ADDR_DEPRECATED ? "deprecated" : "?",
3258+
net_sprint_ipv6_addr(dst), prefix_len);
3259+
}
3260+
32313261
return src;
32323262
}
32333263

0 commit comments

Comments
 (0)