From d4c8de21a07d015f2f2c787e0735be5e4d02fb3c Mon Sep 17 00:00:00 2001 From: Matt Muggeridge Date: Mon, 22 Jan 2024 19:55:41 +1000 Subject: [PATCH] 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= 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= 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) --- man/systemd.network.xml | 24 +++++++ src/basic/sysctl-util.c | 20 ++++++ src/basic/sysctl-util.h | 7 ++ src/libsystemd-network/ndisc-router.c | 9 +++ src/libsystemd-network/ndisc-router.h | 1 + src/libsystemd-network/test-ndisc-rs.c | 5 +- src/network/networkd-ndisc.c | 40 +++++++++++ src/network/networkd-network-gperf.gperf | 2 + src/network/networkd-network.c | 1 + src/network/networkd-network.h | 2 + src/network/networkd-sysctl.c | 22 ++++++ src/systemd/sd-ndisc.h | 1 + test/test-network/conf/25-dummy.netdev | 4 ++ test/test-network/conf/25-dummy.network | 6 ++ .../25-ipv6-neigh-retrans-time-0s.network | 7 ++ .../25-ipv6-neigh-retrans-time-3s.network | 7 ++ .../25-ipv6-neigh-retrans-time-4s.network | 7 ++ ...5-ipv6-neigh-retrans-time-infinity.network | 7 ++ ...25-ipv6-neigh-retrans-time-invalid.network | 7 ++ .../25-ipv6-neigh-retrans-time-toobig.network | 7 ++ test/test-network/systemd-networkd-tests.py | 70 +++++++++++++++++++ 21 files changed, 255 insertions(+), 1 deletion(-) create mode 100644 test/test-network/conf/25-dummy.netdev create mode 100644 test/test-network/conf/25-dummy.network create mode 100644 test/test-network/conf/25-ipv6-neigh-retrans-time-0s.network create mode 100644 test/test-network/conf/25-ipv6-neigh-retrans-time-3s.network create mode 100644 test/test-network/conf/25-ipv6-neigh-retrans-time-4s.network create mode 100644 test/test-network/conf/25-ipv6-neigh-retrans-time-infinity.network create mode 100644 test/test-network/conf/25-ipv6-neigh-retrans-time-invalid.network create mode 100644 test/test-network/conf/25-ipv6-neigh-retrans-time-toobig.network diff --git a/man/systemd.network.xml b/man/systemd.network.xml index ef4a0fd430..c1b0eec1a7 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -882,6 +882,18 @@ Table=1234 + + IPv6RetransmissionTimeSec= + + Configures IPv6 Retransmission Time. The time between retransmitted Neighbor + Solicitation messages. Used by address resolution and the Neighbor Unreachability + Detection algorithm. A value of zero is ignored and the kernel's current value + will be used. Defaults to unset, and the kernel's current value will be used. + + + + + IPv4ReversePathFilter= @@ -3306,6 +3318,18 @@ Token=prefixstable:2002:da8:1:: + + UseRetransmissionTime= + + Takes a boolean. When true, the retransmission time received in the Router Advertisement will be set + on the interface receiving the advertisement. It is used as the time between retransmissions of Neighbor + Solicitation messages to a neighbor when resolving the address or when probing the reachability of a neighbor. + Defaults to true. + + + + + UseICMP6RateLimit= diff --git a/src/basic/sysctl-util.c b/src/basic/sysctl-util.c index b66a6622ae..9a1933f579 100644 --- a/src/basic/sysctl-util.c +++ b/src/basic/sysctl-util.c @@ -96,6 +96,26 @@ int sysctl_write_ip_property(int af, const char *ifname, const char *property, c return sysctl_write(p, value); } +int sysctl_write_ip_neighbor_property(int af, const char *ifname, const char *property, const char *value) { + const char *p; + + assert(property); + assert(value); + assert(ifname); + + if (!IN_SET(af, AF_INET, AF_INET6)) + return -EAFNOSUPPORT; + + if (ifname) { + if (!ifname_valid_full(ifname, IFNAME_VALID_SPECIAL)) + return -EINVAL; + p = strjoina("net/", af_to_ipv4_ipv6(af), "/neigh/", ifname, "/", property); + } else + p = strjoina("net/", af_to_ipv4_ipv6(af), "/neigh/default/", property); + + return sysctl_write(p, value); +} + int sysctl_read(const char *property, char **ret) { char *p; int r; diff --git a/src/basic/sysctl-util.h b/src/basic/sysctl-util.h index 32364196f9..7192e8c0b0 100644 --- a/src/basic/sysctl-util.h +++ b/src/basic/sysctl-util.h @@ -19,6 +19,13 @@ static inline int sysctl_write_ip_property_boolean(int af, const char *ifname, c return sysctl_write_ip_property(af, ifname, property, one_zero(value)); } +int sysctl_write_ip_neighbor_property(int af, const char *ifname, const char *property, const char *value); +static inline int sysctl_write_ip_neighbor_property_uint32(int af, const char *ifname, const char *property, uint32_t value) { + char buf[DECIMAL_STR_MAX(uint32_t)]; + xsprintf(buf, "%u", value); + return sysctl_write_ip_neighbor_property(af, ifname, property, buf); +} + #define DEFINE_SYSCTL_WRITE_IP_PROPERTY(name, type, format) \ static inline int sysctl_write_ip_property_##name(int af, const char *ifname, const char *property, type value) { \ char buf[DECIMAL_STR_MAX(type)]; \ diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c index 5162df799c..89681d0075 100644 --- a/src/libsystemd-network/ndisc-router.c +++ b/src/libsystemd-network/ndisc-router.c @@ -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); diff --git a/src/libsystemd-network/ndisc-router.h b/src/libsystemd-network/ndisc-router.h index 0a55e1ac57..63d4f90ba9 100644 --- a/src/libsystemd-network/ndisc-router.h +++ b/src/libsystemd-network/ndisc-router.h @@ -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; diff --git a/src/libsystemd-network/test-ndisc-rs.c b/src/libsystemd-network/test-ndisc-rs.c index d94cc1ceb7..d0648b95fa 100644 --- a/src/libsystemd-network/test-ndisc-rs.c +++ b/src/libsystemd-network/test-ndisc-rs.c @@ -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 diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index 9f56fd23d4..ca8bbb2d5e 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -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; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index f0650a0c88..ce37450938 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -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 diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 08c7da5699..16c679b343 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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, diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 1d7a7da798..3ab115c3b9 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -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; diff --git a/src/network/networkd-sysctl.c b/src/network/networkd-sysctl.c index 9d188c022e..8fa0ede5c2 100644 --- a/src/network/networkd-sysctl.c +++ b/src/network/networkd-sysctl.c @@ -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"); diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h index 3f93e3a406..a5ccd5f644 100644 --- a/src/systemd/sd-ndisc.h +++ b/src/systemd/sd-ndisc.h @@ -96,6 +96,7 @@ int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret); int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret); int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint64_t *ret); int sd_ndisc_router_get_lifetime_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t *ret); +int sd_ndisc_router_get_retransmission_time(sd_ndisc_router *rt, uint64_t *ret); int sd_ndisc_router_get_mtu(sd_ndisc_router *rt, uint32_t *ret); /* Generic option access */ diff --git a/test/test-network/conf/25-dummy.netdev b/test/test-network/conf/25-dummy.netdev new file mode 100644 index 0000000000..d7cf7b4878 --- /dev/null +++ b/test/test-network/conf/25-dummy.netdev @@ -0,0 +1,4 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[NetDev] +Name=test25 +Kind=dummy diff --git a/test/test-network/conf/25-dummy.network b/test/test-network/conf/25-dummy.network new file mode 100644 index 0000000000..a6e93fd0a0 --- /dev/null +++ b/test/test-network/conf/25-dummy.network @@ -0,0 +1,6 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=test25 + +[Network] +IPv6AcceptRA=no diff --git a/test/test-network/conf/25-ipv6-neigh-retrans-time-0s.network b/test/test-network/conf/25-ipv6-neigh-retrans-time-0s.network new file mode 100644 index 0000000000..04c7c494a9 --- /dev/null +++ b/test/test-network/conf/25-ipv6-neigh-retrans-time-0s.network @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=test25 + +[Network] +IPv6AcceptRA=no +IPv6RetransmissionTimeSec=0 diff --git a/test/test-network/conf/25-ipv6-neigh-retrans-time-3s.network b/test/test-network/conf/25-ipv6-neigh-retrans-time-3s.network new file mode 100644 index 0000000000..b4dbd06ead --- /dev/null +++ b/test/test-network/conf/25-ipv6-neigh-retrans-time-3s.network @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=test25 + +[Network] +IPv6AcceptRA=no +IPv6RetransmissionTimeSec=3 diff --git a/test/test-network/conf/25-ipv6-neigh-retrans-time-4s.network b/test/test-network/conf/25-ipv6-neigh-retrans-time-4s.network new file mode 100644 index 0000000000..cbdf4f306a --- /dev/null +++ b/test/test-network/conf/25-ipv6-neigh-retrans-time-4s.network @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=test25 + +[Network] +IPv6AcceptRA=no +IPv6RetransmissionTimeSec=4 diff --git a/test/test-network/conf/25-ipv6-neigh-retrans-time-infinity.network b/test/test-network/conf/25-ipv6-neigh-retrans-time-infinity.network new file mode 100644 index 0000000000..085cb30cd7 --- /dev/null +++ b/test/test-network/conf/25-ipv6-neigh-retrans-time-infinity.network @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=test25 + +[Network] +IPv6AcceptRA=no +IPv6RetransmissionTimeSec=infinity diff --git a/test/test-network/conf/25-ipv6-neigh-retrans-time-invalid.network b/test/test-network/conf/25-ipv6-neigh-retrans-time-invalid.network new file mode 100644 index 0000000000..8a0bf8320b --- /dev/null +++ b/test/test-network/conf/25-ipv6-neigh-retrans-time-invalid.network @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=test25 + +[Network] +IPv6AcceptRA=no +IPv6RetransmissionTimeSec=-2 diff --git a/test/test-network/conf/25-ipv6-neigh-retrans-time-toobig.network b/test/test-network/conf/25-ipv6-neigh-retrans-time-toobig.network new file mode 100644 index 0000000000..0976bae8c7 --- /dev/null +++ b/test/test-network/conf/25-ipv6-neigh-retrans-time-toobig.network @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +[Match] +Name=test25 + +[Network] +IPv6AcceptRA=no +IPv6RetransmissionTimeSec=999999999999999999 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 3bb0166f4e..064ca53193 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -4,6 +4,16 @@ # These tests can be executed in the systemd mkosi image when booted in QEMU. After booting the QEMU VM, # simply run this file which can be found in the VM at /usr/lib/systemd/tests/testdata/test-network/systemd-networkd-tests.py. +# +# To run an individual test, specify it as a command line argument in the form +# of .. E.g. the NetworkdMTUTests class has a test +# function called test_ipv6_mtu(). To run just that test use: +# +# sudo ./systemd-networkd-tests.py NetworkdMTUTests.test_ipv6_mtu +# +# Similarly, other indivdual tests can be run, eg.: +# +# sudo ./systemd-networkd-tests.py NetworkdNetworkTests.test_ipv6_neigh_retrans_time import argparse import datetime @@ -582,9 +592,16 @@ def read_ip_sysctl_attr(link, attribute, ipv): with open(os.path.join('/proc/sys/net', ipv, 'conf', link, attribute), encoding='utf-8') as f: return f.readline().strip() +def read_ip_neigh_sysctl_attr(link, attribute, ipv): + with open(os.path.join('/proc/sys/net', ipv, 'neigh', link, attribute), encoding='utf-8') as f: + return f.readline().strip() + def read_ipv6_sysctl_attr(link, attribute): return read_ip_sysctl_attr(link, attribute, 'ipv6') +def read_ipv6_neigh_sysctl_attr(link, attribute): + return read_ip_neigh_sysctl_attr(link, attribute, 'ipv6') + def read_ipv4_sysctl_attr(link, attribute): return read_ip_sysctl_attr(link, attribute, 'ipv4') @@ -915,6 +932,9 @@ class Utilities(): def check_ipv6_sysctl_attr(self, link, attribute, expected): self.assertEqual(read_ipv6_sysctl_attr(link, attribute), expected) + def check_ipv6_neigh_sysctl_attr(self, link, attribute, expected): + self.assertEqual(read_ipv6_neigh_sysctl_attr(link, attribute), expected) + def wait_links(self, *links, timeout=20, fail_assert=True): def links_exist(*links): for link in links: @@ -3505,6 +3525,56 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): for i in range(1, 5): self.assertRegex(output, f'2607:5300:203:5215:{i}::1 *proxy') + def test_ipv6_neigh_retrans_time(self): + link='test25' + copy_network_unit('25-dummy.netdev', '25-dummy.network') + start_networkd() + + self.wait_online([f'{link}:degraded']) + remove_network_unit('25-dummy.network') + + # expect retrans_time_ms updated + copy_network_unit('25-ipv6-neigh-retrans-time-3s.network') + networkctl_reload() + self.wait_online([f'{link}:degraded']) + self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000') + remove_network_unit('25-ipv6-neigh-retrans-time-3s.network') + + # expect retrans_time_ms unchanged + copy_network_unit('25-ipv6-neigh-retrans-time-0s.network') + networkctl_reload() + self.wait_online([f'{link}:degraded']) + self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000') + remove_network_unit('25-ipv6-neigh-retrans-time-0s.network') + + # expect retrans_time_ms unchanged + copy_network_unit('25-ipv6-neigh-retrans-time-toobig.network') + networkctl_reload() + self.wait_online([f'{link}:degraded']) + self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000') + remove_network_unit('25-ipv6-neigh-retrans-time-toobig.network') + + # expect retrans_time_ms unchanged + copy_network_unit('25-ipv6-neigh-retrans-time-infinity.network') + networkctl_reload() + self.wait_online([f'{link}:degraded']) + self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000') + remove_network_unit('25-ipv6-neigh-retrans-time-infinity.network') + + # expect retrans_time_ms unchanged + copy_network_unit('25-ipv6-neigh-retrans-time-invalid.network') + networkctl_reload() + self.wait_online([f'{link}:degraded']) + self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '3000') + remove_network_unit('25-ipv6-neigh-retrans-time-invalid.network') + + # expect retrans_time_ms updated + copy_network_unit('25-ipv6-neigh-retrans-time-4s.network') + networkctl_reload() + self.wait_online([f'{link}:degraded']) + self.check_ipv6_neigh_sysctl_attr(link, 'retrans_time_ms', '4000') + remove_network_unit('25-ipv6-neigh-retrans-time-4s.network') + def test_neighbor(self): copy_network_unit('12-dummy.netdev', '25-neighbor-dummy.network', '25-neighbor-dummy.network.d/10-step1.conf', '25-gre-tunnel-remote-any.netdev', '25-neighbor-ip.network', -- 2.25.1