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:
committed by
Yu Watanabe
parent
afd08d7740
commit
d4c8de21a0
@@ -393,6 +393,42 @@ static int ndisc_router_process_icmp6_ratelimit(Link *link, sd_ndisc_router *rt)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_router_process_retransmission_time(Link *link, sd_ndisc_router *rt) {
|
||||
usec_t retrans_time, msec;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->network);
|
||||
assert(rt);
|
||||
|
||||
if (!link->network->ipv6_accept_ra_use_retransmission_time)
|
||||
return 0;
|
||||
|
||||
r = sd_ndisc_router_get_retransmission_time(rt, &retrans_time);
|
||||
if (r < 0) {
|
||||
log_link_debug_errno(link, r, "Failed to get retransmission time from RA, ignoring: %m");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 0 is the unspecified value and must not be set (see RFC4861, 6.3.4) */
|
||||
if (!timestamp_is_set(retrans_time))
|
||||
return 0;
|
||||
|
||||
msec = DIV_ROUND_UP(retrans_time, USEC_PER_MSEC);
|
||||
if (msec <= 0 || msec > UINT32_MAX) {
|
||||
log_link_debug(link, "Failed to get retransmission time from RA - out of range (%"PRIu64"), ignoring", msec);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Set the retransmission time for Neigbor Solicitations. */
|
||||
r = sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", (uint32_t) msec);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(
|
||||
link, r, "Failed to apply neighbor retransmission time (%"PRIu64"), ignoring: %m", msec);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *rt) {
|
||||
usec_t lifetime_valid_usec, lifetime_preferred_usec;
|
||||
_cleanup_set_free_ Set *addresses = NULL;
|
||||
@@ -1354,6 +1390,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ndisc_router_process_retransmission_time(link, rt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ndisc_router_process_options(link, rt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
@@ -131,6 +131,7 @@ Network.IPv6AcceptRA, config_parse_tristate,
|
||||
Network.IPv6AcceptRouterAdvertisements, config_parse_tristate, 0, offsetof(Network, ipv6_accept_ra)
|
||||
Network.IPv6DuplicateAddressDetection, config_parse_int, 0, offsetof(Network, ipv6_dad_transmits)
|
||||
Network.IPv6HopLimit, config_parse_uint8, 0, offsetof(Network, ipv6_hop_limit)
|
||||
Network.IPv6RetransmissionTimeSec, config_parse_sec, 0, offsetof(Network, ipv6_retransmission_time)
|
||||
Network.IPv6ProxyNDP, config_parse_tristate, 0, offsetof(Network, ipv6_proxy_ndp)
|
||||
Network.IPv6MTUBytes, config_parse_mtu, AF_INET6, offsetof(Network, ipv6_mtu)
|
||||
Network.IPv4AcceptLocal, config_parse_tristate, 0, offsetof(Network, ipv4_accept_local)
|
||||
@@ -297,6 +298,7 @@ IPv6AcceptRA.UseDNS, config_parse_bool,
|
||||
IPv6AcceptRA.UseDomains, config_parse_ipv6_accept_ra_use_domains, 0, offsetof(Network, ipv6_accept_ra_use_domains)
|
||||
IPv6AcceptRA.UseMTU, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_mtu)
|
||||
IPv6AcceptRA.UseHopLimit, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_hop_limit)
|
||||
IPv6AcceptRA.UseRetransmissionTime, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_retransmission_time)
|
||||
IPv6AcceptRA.UseICMP6RateLimit, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_icmp6_ratelimit)
|
||||
IPv6AcceptRA.DHCPv6Client, config_parse_ipv6_accept_ra_start_dhcp6_client, 0, offsetof(Network, ipv6_accept_ra_start_dhcp6_client)
|
||||
IPv6AcceptRA.RouteTable, config_parse_dhcp_or_ra_route_table, AF_INET6, 0
|
||||
|
||||
@@ -483,6 +483,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
|
||||
.ipv6_accept_ra_use_onlink_prefix = true,
|
||||
.ipv6_accept_ra_use_mtu = true,
|
||||
.ipv6_accept_ra_use_hop_limit = true,
|
||||
.ipv6_accept_ra_use_retransmission_time = true,
|
||||
.ipv6_accept_ra_use_icmp6_ratelimit = true,
|
||||
.ipv6_accept_ra_route_table = RT_TABLE_MAIN,
|
||||
.ipv6_accept_ra_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
|
||||
|
||||
@@ -324,6 +324,7 @@ struct Network {
|
||||
int ipv4_route_localnet;
|
||||
int ipv6_dad_transmits;
|
||||
uint8_t ipv6_hop_limit;
|
||||
usec_t ipv6_retransmission_time;
|
||||
int proxy_arp;
|
||||
int proxy_arp_pvlan;
|
||||
uint32_t ipv6_mtu;
|
||||
@@ -341,6 +342,7 @@ struct Network {
|
||||
bool ipv6_accept_ra_use_onlink_prefix;
|
||||
bool ipv6_accept_ra_use_mtu;
|
||||
bool ipv6_accept_ra_use_hop_limit;
|
||||
bool ipv6_accept_ra_use_retransmission_time;
|
||||
bool ipv6_accept_ra_use_icmp6_ratelimit;
|
||||
bool ipv6_accept_ra_quickack;
|
||||
bool ipv6_accept_ra_use_captive_portal;
|
||||
|
||||
@@ -179,6 +179,24 @@ static int link_set_ipv6_hop_limit(Link *link) {
|
||||
return sysctl_write_ip_property_int(AF_INET6, link->ifname, "hop_limit", link->network->ipv6_hop_limit);
|
||||
}
|
||||
|
||||
static int link_set_ipv6_retransmission_time(Link *link) {
|
||||
usec_t retrans_time_ms;
|
||||
|
||||
assert(link);
|
||||
|
||||
if (!link_is_configured_for_family(link, AF_INET6))
|
||||
return 0;
|
||||
|
||||
if (!timestamp_is_set(link->network->ipv6_retransmission_time))
|
||||
return 0;
|
||||
|
||||
retrans_time_ms = DIV_ROUND_UP(link->network->ipv6_retransmission_time, USEC_PER_MSEC);
|
||||
if (retrans_time_ms <= 0 || retrans_time_ms > UINT32_MAX)
|
||||
return 0;
|
||||
|
||||
return sysctl_write_ip_neighbor_property_uint32(AF_INET6, link->ifname, "retrans_time_ms", retrans_time_ms);
|
||||
}
|
||||
|
||||
static int link_set_ipv6_proxy_ndp(Link *link) {
|
||||
bool v;
|
||||
|
||||
@@ -297,6 +315,10 @@ int link_set_sysctl(Link *link) {
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Cannot set IPv6 hop limit for interface, ignoring: %m");
|
||||
|
||||
r = link_set_ipv6_retransmission_time(link);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Cannot set IPv6 retransmission time for interface, ignoring: %m");
|
||||
|
||||
r = link_set_ipv6_proxy_ndp(link);
|
||||
if (r < 0)
|
||||
log_link_warning_errno(link, r, "Cannot set IPv6 proxy NDP, ignoring: %m");
|
||||
|
||||
Reference in New Issue
Block a user