IPv6 RA: Support the Retrans Timer field (IPv6 Conformance Test: v6LC.2.1.5)

The RA's Retransmission Timer field was being ignored. This resolves the IPv6
Core Conformance test, v6LC.2.1.5 [1].

Retransmission Timer is a 32-bit unsigned integer. The time, in milliseconds,
between retransmitted Neighbor Solicitation messages. Used by the Address
Resolution and Neighbor Unreachability Detection (NUD) algorithm.

Support setting a default value for the neighbour retransmission timer value with:

    [Network]
    IPv6RetransmissionTimeSec=<int>

By default, upon receiving a Router Advertisement with the Retransmission Timer
field set to a non-zero value, it will update the kernel's retransmit timer value.
To disable this behaviour, configure the UseIPv6RetransmissionTime= under the
[IPv6AcceptRA] section.

    [IPv6AcceptRA]
    UseIPv6RetransmissionTime=<bool>

RFC4861: Neighbor Discovery in IPv6
  * Section 4.2 RA Message Format.
  * Section 6.3.4 Processing Received Router Advertisements

A Router Advertisement field (e.g., Cur Hop Limit, Reachable Time,
and Retrans Timer) may contain a value denoting that it is
unspecified. In such cases, the parameter should be ignored and the
host should continue using whatever value it is already using. In
particular, a host MUST NOT interpret the unspecified value as
meaning change back to the default value that was in use before the
first Router Advertisement was received.

The RetransTimer variable SHOULD be copied from the Retrans Timer
field, if the received value is non-zero.

References
[1] IPv6 Core Conformance Spec (PDF)
This commit is contained in:
Matt Muggeridge
2024-01-23 03:18:01 +09:00
committed by Yu Watanabe
parent afd08d7740
commit d4c8de21a0
21 changed files with 255 additions and 1 deletions
+9
View File
@@ -144,6 +144,7 @@ int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
rt->lifetime_usec = be16_sec_to_usec(a->nd_ra_router_lifetime, /* max_as_infinity = */ false);
rt->icmp6_ratelimit_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
rt->retransmission_time_usec = be32_msec_to_usec(a->nd_ra_retransmit, /* max_as_infinity = */ false);
rt->preference = (rt->flags >> 3) & 3;
if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
@@ -275,6 +276,14 @@ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
return 0;
}
int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret) {
assert_return(rt, -EINVAL);
assert_return(ret, -EINVAL);
*ret = rt->retransmission_time_usec;
return 0;
}
int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint64_t *ret) {
assert_return(rt, -EINVAL);
assert_return(ret, -EINVAL);
+1
View File
@@ -24,6 +24,7 @@ struct sd_ndisc_router {
uint64_t flags;
unsigned preference;
uint64_t lifetime_usec;
usec_t retransmission_time_usec;
uint8_t hop_limit;
uint32_t mtu;
+4 -1
View File
@@ -28,7 +28,7 @@ static sd_ndisc *test_timeout_nd;
static void router_dump(sd_ndisc_router *rt) {
struct in6_addr addr;
uint8_t hop_limit;
usec_t t, lifetime;
usec_t t, lifetime, retrans_time;
uint64_t flags;
uint32_t mtu;
unsigned preference;
@@ -65,6 +65,9 @@ static void router_dump(sd_ndisc_router *rt) {
assert_se(sd_ndisc_router_get_lifetime_timestamp(rt, CLOCK_REALTIME, &t) >= 0);
log_info("Lifetime: %s (%s)", FORMAT_TIMESPAN(lifetime, USEC_PER_SEC), FORMAT_TIMESTAMP(t));
assert_se(sd_ndisc_router_get_retransmission_time(rt, &retrans_time) >= 0);
log_info("Retransmission Time: %s", FORMAT_TIMESPAN(retrans_time, USEC_PER_SEC));
if (sd_ndisc_router_get_mtu(rt, &mtu) < 0)
log_info("No MTU set");
else