-
Notifications
You must be signed in to change notification settings - Fork 2.1k
gnrc_netif: only use prefix matching as tie-breaker in source selection #12408
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
f8de22a
e96faca
2458a61
e787f6b
e9d75f5
020af41
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -474,7 +474,6 @@ void gnrc_netif_release(gnrc_netif_t *netif) | |||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| #ifdef MODULE_GNRC_IPV6 | ||||||||||||||||||
| static inline bool _addr_anycast(const gnrc_netif_t *netif, unsigned idx); | ||||||||||||||||||
| static int _addr_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr); | ||||||||||||||||||
| static int _group_idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr); | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -501,18 +500,14 @@ static unsigned _match_to_len(const gnrc_netif_t *netif, | |||||||||||||||||
| * | ||||||||||||||||||
| * @param[in] netif the network interface | ||||||||||||||||||
| * @param[in] addr the address to match | ||||||||||||||||||
| * @param[in] filter a bitfield with the bits at the position equal to the | ||||||||||||||||||
| * indexes of the addresses you want to include in the | ||||||||||||||||||
| * search set to one. NULL for all addresses | ||||||||||||||||||
| * | ||||||||||||||||||
| * @return index of the best match for @p addr | ||||||||||||||||||
| * @return -1 if no match was found | ||||||||||||||||||
| * | ||||||||||||||||||
| * @pre `netif != NULL` and `addr != NULL` | ||||||||||||||||||
| */ | ||||||||||||||||||
| static int _match_to_idx(const gnrc_netif_t *netif, | ||||||||||||||||||
| const ipv6_addr_t *addr, | ||||||||||||||||||
| const uint8_t *filter); | ||||||||||||||||||
| const ipv6_addr_t *addr); | ||||||||||||||||||
| /** | ||||||||||||||||||
| * @brief Determines the scope of the given address. | ||||||||||||||||||
| * | ||||||||||||||||||
|
|
@@ -700,7 +695,7 @@ int gnrc_netif_ipv6_addr_match(gnrc_netif_t *netif, | |||||||||||||||||
| { | ||||||||||||||||||
| assert((netif != NULL) && (addr != NULL)); | ||||||||||||||||||
| gnrc_netif_acquire(netif); | ||||||||||||||||||
| int idx = _match_to_idx(netif, addr, NULL); | ||||||||||||||||||
| int idx = _match_to_idx(netif, addr); | ||||||||||||||||||
| gnrc_netif_release(netif); | ||||||||||||||||||
| return idx; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
@@ -818,11 +813,6 @@ int gnrc_netif_ipv6_group_idx(gnrc_netif_t *netif, const ipv6_addr_t *addr) | |||||||||||||||||
| return idx; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| static inline bool _addr_anycast(const gnrc_netif_t *netif, unsigned idx) | ||||||||||||||||||
| { | ||||||||||||||||||
| return (netif->ipv6.addrs_flags[idx] & GNRC_NETIF_IPV6_ADDRS_FLAGS_ANYCAST); | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| static int _idx(const gnrc_netif_t *netif, const ipv6_addr_t *addr, bool mcast) | ||||||||||||||||||
| { | ||||||||||||||||||
| if (!ipv6_addr_is_unspecified(addr)) { | ||||||||||||||||||
|
|
@@ -852,13 +842,12 @@ static unsigned _match_to_len(const gnrc_netif_t *netif, | |||||||||||||||||
| { | ||||||||||||||||||
| assert((netif != NULL) && (addr != NULL)); | ||||||||||||||||||
|
|
||||||||||||||||||
| int n = _match_to_idx(netif, addr, NULL); | ||||||||||||||||||
| int n = _match_to_idx(netif, addr); | ||||||||||||||||||
| return (n >= 0) ? ipv6_addr_match_prefix(&(netif->ipv6.addrs[n]), addr) : 0; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| static int _match_to_idx(const gnrc_netif_t *netif, | ||||||||||||||||||
| const ipv6_addr_t *addr, | ||||||||||||||||||
| const uint8_t *filter) | ||||||||||||||||||
| const ipv6_addr_t *addr) | ||||||||||||||||||
| { | ||||||||||||||||||
| assert((netif != NULL) && (addr != NULL)); | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
@@ -867,15 +856,11 @@ static int _match_to_idx(const gnrc_netif_t *netif, | |||||||||||||||||
| for (int i = 0; i < GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { | ||||||||||||||||||
| unsigned match; | ||||||||||||||||||
|
|
||||||||||||||||||
| if ((netif->ipv6.addrs_flags[i] == 0) || | ||||||||||||||||||
| ((filter != NULL) && _addr_anycast(netif, i)) || | ||||||||||||||||||
| /* discard const intentionally */ | ||||||||||||||||||
| ((filter != NULL) && !(bf_isset((uint8_t *)filter, i)))) { | ||||||||||||||||||
| if (netif->ipv6.addrs_flags[i] == 0) { | ||||||||||||||||||
| continue; | ||||||||||||||||||
| } | ||||||||||||||||||
| match = ipv6_addr_match_prefix(&(netif->ipv6.addrs[i]), addr); | ||||||||||||||||||
| if (((match > 64U) || !ipv6_addr_is_link_local(&(netif->ipv6.addrs[i]))) && | ||||||||||||||||||
| (match >= best_match)) { | ||||||||||||||||||
| if (match > best_match) { | ||||||||||||||||||
| idx = i; | ||||||||||||||||||
| best_match = match; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
@@ -885,17 +870,15 @@ static int _match_to_idx(const gnrc_netif_t *netif, | |||||||||||||||||
| ipv6_addr_to_str(addr_str, &netif->ipv6.addrs[idx], | ||||||||||||||||||
| sizeof(addr_str)), | ||||||||||||||||||
| netif->pid); | ||||||||||||||||||
| DEBUG("%s by %u bits (used as source address = %s)\n", | ||||||||||||||||||
| DEBUG("%s by %u bits\n", | ||||||||||||||||||
| ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), | ||||||||||||||||||
| best_match, | ||||||||||||||||||
| (filter != NULL) ? "true" : "false"); | ||||||||||||||||||
| best_match); | ||||||||||||||||||
| } | ||||||||||||||||||
| else { | ||||||||||||||||||
| DEBUG("gnrc_netif: Did not found any address on interface %" PRIkernel_pid | ||||||||||||||||||
| " matching %s (used as source address = %s)\n", | ||||||||||||||||||
| " matching %s\n", | ||||||||||||||||||
| netif->pid, | ||||||||||||||||||
| ipv6_addr_to_str(addr_str, addr, sizeof(addr_str)), | ||||||||||||||||||
| (filter != NULL) ? "true" : "false"); | ||||||||||||||||||
| ipv6_addr_to_str(addr_str, addr, sizeof(addr_str))); | ||||||||||||||||||
| } | ||||||||||||||||||
| return idx; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
@@ -955,8 +938,19 @@ static int _create_candidate_set(const gnrc_netif_t *netif, | |||||||||||||||||
| ipv6_addr_to_str(addr_str, tmp, sizeof(addr_str))); | ||||||||||||||||||
| /* "In any case, multicast addresses and the unspecified address MUST NOT | ||||||||||||||||||
| * be included in a candidate set." | ||||||||||||||||||
| * | ||||||||||||||||||
| * flags are set if not unspecfied and multicast addresses are in | ||||||||||||||||||
| * `netif->ipv6.groups` so not considered here. | ||||||||||||||||||
| */ | ||||||||||||||||||
| if ((netif->ipv6.addrs_flags[i] == 0) || | ||||||||||||||||||
| /* https://tools.ietf.org/html/rfc4862#section-2: | ||||||||||||||||||
| * A tentative address is not considered assigned to an interface | ||||||||||||||||||
| * in the usual sense. An interface discards received packets | ||||||||||||||||||
| * addressed to a tentative address, but accepts Neighbor Discovery | ||||||||||||||||||
| * packets related to Duplicate Address Detection for the tentative | ||||||||||||||||||
| * address. | ||||||||||||||||||
| * (so don't consider tentative addresses for source address | ||||||||||||||||||
| * selection) */ | ||||||||||||||||||
| gnrc_netif_ipv6_addr_dad_trans(netif, i)) { | ||||||||||||||||||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I know this line is not part of this PR, but could you clarify why addresses are not considered that have How can we deduce that the address is tentative from that result?
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The number of DAD transmissions is encoded in the tentative state in our DAD implementation (that's why you see
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See also doc for tentative state: RIOT/sys/include/net/gnrc/netif/ipv6.h Lines 48 to 55 in 55adbee
|
||||||||||||||||||
| continue; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
@@ -993,10 +987,46 @@ static int _create_candidate_set(const gnrc_netif_t *netif, | |||||||||||||||||
| /* number of "points" assigned to an source address candidate in preferred state */ | ||||||||||||||||||
| #define RULE_3_PTS (1) | ||||||||||||||||||
|
|
||||||||||||||||||
| /** | ||||||||||||||||||
| * @brief Caps the match at a source addresses prefix length | ||||||||||||||||||
| * | ||||||||||||||||||
| * @see https://tools.ietf.org/html/rfc6724#section-2.2 | ||||||||||||||||||
| * | ||||||||||||||||||
| * @param[in] netif The network interface @p src was selected from | ||||||||||||||||||
| * @param[in] src A potential source address | ||||||||||||||||||
| * @param[in] match The number of bits matching of @p src with another address | ||||||||||||||||||
| * | ||||||||||||||||||
| * @return @p match or a number lesser than @p match, if @p src has a shorter | ||||||||||||||||||
| * prefix. | ||||||||||||||||||
| */ | ||||||||||||||||||
| static unsigned _cap_match(const gnrc_netif_t *netif, const ipv6_addr_t *src, | ||||||||||||||||||
| unsigned match) | ||||||||||||||||||
| { | ||||||||||||||||||
| unsigned best_prefix = 0; | ||||||||||||||||||
|
|
||||||||||||||||||
| if (ipv6_addr_is_link_local(src)) { | ||||||||||||||||||
| best_prefix = 64U; /* Link-local prefix is always of length 64 */ | ||||||||||||||||||
| } | ||||||||||||||||||
| #ifdef MODULE_GNRC_IPV6_NIB | ||||||||||||||||||
| else { | ||||||||||||||||||
| void *state = NULL; | ||||||||||||||||||
| gnrc_ipv6_nib_pl_t ple; | ||||||||||||||||||
|
|
||||||||||||||||||
| while (gnrc_ipv6_nib_pl_iter(netif->pid, &state, &ple)) { | ||||||||||||||||||
| if ((ipv6_addr_match_prefix(&ple.pfx, src) > best_prefix)) { | ||||||||||||||||||
| best_prefix = ple.pfx_len; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| #endif /* MODULE_GNRC_IPV6_NIB */ | ||||||||||||||||||
| return ((best_prefix > 0) && (best_prefix < match)) ? best_prefix : match; | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| static ipv6_addr_t *_src_addr_selection(gnrc_netif_t *netif, | ||||||||||||||||||
| const ipv6_addr_t *dst, | ||||||||||||||||||
| uint8_t *candidate_set) | ||||||||||||||||||
| { | ||||||||||||||||||
| int idx = -1; | ||||||||||||||||||
| /* create temporary set for assigning "points" to candidates winning in the | ||||||||||||||||||
| * corresponding rules. | ||||||||||||||||||
| */ | ||||||||||||||||||
|
|
@@ -1031,24 +1061,16 @@ static ipv6_addr_t *_src_addr_selection(gnrc_netif_t *netif, | |||||||||||||||||
| if (candidate_scope == dst_scope) { | ||||||||||||||||||
| DEBUG("winner for rule 2 (same scope) found\n"); | ||||||||||||||||||
| winner_set[i] += RULE_2A_PTS; | ||||||||||||||||||
| if (winner_set[i] > max_pts) { | ||||||||||||||||||
| max_pts = RULE_2A_PTS; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| else if (candidate_scope < dst_scope) { | ||||||||||||||||||
| DEBUG("winner for rule 2 (smaller scope) found\n"); | ||||||||||||||||||
| winner_set[i] += RULE_2B_PTS; | ||||||||||||||||||
| if (winner_set[i] > max_pts) { | ||||||||||||||||||
| max_pts = winner_set[i]; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /* Rule 3: Avoid deprecated addresses. */ | ||||||||||||||||||
| if (_get_state(netif, i) != GNRC_NETIF_IPV6_ADDRS_FLAGS_STATE_DEPRECATED) { | ||||||||||||||||||
| DEBUG("winner for rule 3 found\n"); | ||||||||||||||||||
| winner_set[i] += RULE_3_PTS; | ||||||||||||||||||
| if (winner_set[i] > max_pts) { | ||||||||||||||||||
| max_pts = winner_set[i]; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
|
|
||||||||||||||||||
| /* Rule 4: Prefer home addresses. | ||||||||||||||||||
|
|
@@ -1077,19 +1099,39 @@ static ipv6_addr_t *_src_addr_selection(gnrc_netif_t *netif, | |||||||||||||||||
| * Temporary addresses are currently not supported by gnrc. | ||||||||||||||||||
| * TODO: update as soon as gnrc supports temporary addresses | ||||||||||||||||||
| */ | ||||||||||||||||||
|
|
||||||||||||||||||
| if (winner_set[i] > max_pts) { | ||||||||||||||||||
| idx = i; | ||||||||||||||||||
| max_pts = winner_set[i]; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| /* reset candidate set to mark winners */ | ||||||||||||||||||
| memset(candidate_set, 0, (GNRC_NETIF_IPV6_ADDRS_NUMOF + 7) / 8); | ||||||||||||||||||
| /* check if we have a clear winner */ | ||||||||||||||||||
| /* check if we have a clear winner, otherwise | ||||||||||||||||||
| * rule 8: Use longest matching prefix.*/ | ||||||||||||||||||
| uint8_t best_match = 0; | ||||||||||||||||||
| /* collect candidates with maximum points */ | ||||||||||||||||||
| for (int i = 0; i < GNRC_NETIF_IPV6_ADDRS_NUMOF; i++) { | ||||||||||||||||||
| if (winner_set[i] == max_pts) { | ||||||||||||||||||
| bf_set(candidate_set, i); | ||||||||||||||||||
| const ipv6_addr_t *addr = &netif->ipv6.addrs[i]; | ||||||||||||||||||
| unsigned match = ipv6_addr_match_prefix(addr, dst); | ||||||||||||||||||
|
|
||||||||||||||||||
| match = _cap_match(netif, addr, match); | ||||||||||||||||||
| /* if match == 0 for all case, it takes above selected idx */ | ||||||||||||||||||
|
miri64 marked this conversation as resolved.
|
||||||||||||||||||
| if (match > best_match) { | ||||||||||||||||||
| idx = i; | ||||||||||||||||||
| best_match = match; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| /* otherwise apply rule 8: Use longest matching prefix. */ | ||||||||||||||||||
| int idx = _match_to_idx(netif, dst, candidate_set); | ||||||||||||||||||
| return (idx < 0) ? NULL : &netif->ipv6.addrs[idx]; | ||||||||||||||||||
| if (idx < 0) { | ||||||||||||||||||
| DEBUG("No winner found\n"); | ||||||||||||||||||
| return NULL; | ||||||||||||||||||
| } | ||||||||||||||||||
| else { | ||||||||||||||||||
| DEBUG("Winner is: %s\n", ipv6_addr_to_str(addr_str, | ||||||||||||||||||
| &netif->ipv6.addrs[idx], | ||||||||||||||||||
| sizeof(addr_str))); | ||||||||||||||||||
| return &netif->ipv6.addrs[idx]; | ||||||||||||||||||
| } | ||||||||||||||||||
| } | ||||||||||||||||||
| #endif /* MODULE_GNRC_IPV6 */ | ||||||||||||||||||
|
|
||||||||||||||||||
|
|
||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See RFC 6724, page 30, point 3: This can be removed without alternative.