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',