diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 38a0173cf09..fcf37a19b82 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -3076,6 +3076,15 @@ Token=prefixstable:2002:da8:1:: + + RetransmitSec= + + Takes a timespan. Configures the retransmit time, used by clients to retransmit Neighbor + Solicitation messages on address resolution and the Neighbor Unreachability Detection algorithm. + An integer the default unit of seconds, in the range 0…4294967295 msec. Defaults to 0. + + + RouterPreference= diff --git a/src/libsystemd-network/radv-internal.h b/src/libsystemd-network/radv-internal.h index 1a268757ad2..4bb32f21283 100644 --- a/src/libsystemd-network/radv-internal.h +++ b/src/libsystemd-network/radv-internal.h @@ -87,6 +87,7 @@ struct sd_radv { uint8_t hop_limit; uint8_t flags; uint32_t mtu; + uint32_t retransmit_msec; usec_t lifetime_usec; /* timespan */ int fd; diff --git a/src/libsystemd-network/sd-radv.c b/src/libsystemd-network/sd-radv.c index 839c9a9ee6f..5d4dfdef028 100644 --- a/src/libsystemd-network/sd-radv.c +++ b/src/libsystemd-network/sd-radv.c @@ -179,6 +179,7 @@ static int radv_send(sd_radv *ra, const struct in6_addr *dst, usec_t lifetime_us adv.nd_ra_type = ND_ROUTER_ADVERT; adv.nd_ra_curhoplimit = ra->hop_limit; + adv.nd_ra_retransmit = htobe32(ra->retransmit_msec); adv.nd_ra_flags_reserved = ra->flags; assert_cc(RADV_MAX_ROUTER_LIFETIME_USEC <= UINT16_MAX * USEC_PER_SEC); adv.nd_ra_router_lifetime = htobe16(DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC)); @@ -494,6 +495,17 @@ int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit) { return 0; } +int sd_radv_set_retransmit(sd_radv *ra, uint32_t retransmit_msec) { + assert_return(ra, -EINVAL); + + if (ra->state != RADV_STATE_IDLE) + return -EBUSY; + + ra->retransmit_msec = retransmit_msec; + + return 0; +} + int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec) { assert_return(ra, -EINVAL); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 2e062ce3197..a364abf2b47 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -368,6 +368,7 @@ DHCPPrefixDelegation.Token, config_parse_address_generation_typ DHCPPrefixDelegation.RouteMetric, config_parse_uint32, 0, offsetof(Network, dhcp_pd_route_metric) DHCPPrefixDelegation.NetLabel, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(Network, dhcp_pd_netlabel) IPv6SendRA.RouterLifetimeSec, config_parse_router_lifetime, 0, offsetof(Network, router_lifetime_usec) +IPv6SendRA.RetransmitSec, config_parse_router_retransmit, 0, offsetof(Network, router_retransmit_usec) IPv6SendRA.Managed, config_parse_bool, 0, offsetof(Network, router_managed) IPv6SendRA.OtherInformation, config_parse_bool, 0, offsetof(Network, router_other_information) IPv6SendRA.RouterPreference, config_parse_router_preference, 0, 0 diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index f3b3271811e..75f1be442aa 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -227,6 +227,7 @@ struct Network { RADVPrefixDelegation router_prefix_delegation; usec_t router_lifetime_usec; uint8_t router_preference; + usec_t router_retransmit_usec; bool router_managed; bool router_other_information; bool router_emit_dns; diff --git a/src/network/networkd-radv.c b/src/network/networkd-radv.c index 0f67ff09732..e6ef3974f28 100644 --- a/src/network/networkd-radv.c +++ b/src/network/networkd-radv.c @@ -486,6 +486,12 @@ static int radv_configure(Link *link) { return r; } + if (link->network->router_retransmit_usec > 0) { + r = sd_radv_set_retransmit(link->radv, DIV_ROUND_UP(link->network->router_retransmit_usec, USEC_PER_MSEC)); + if (r < 0) + return r; + } + HASHMAP_FOREACH(p, link->network->prefixes_by_section) { r = radv_set_prefix(link, p); if (r < 0 && r != -EEXIST) @@ -1305,6 +1311,49 @@ int config_parse_router_lifetime( return 0; } +int config_parse_router_retransmit( + const char *unit, + const char *filename, + unsigned line, + const char *section, + unsigned section_line, + const char *lvalue, + int ltype, + const char *rvalue, + void *data, + void *userdata) { + + usec_t usec, *router_retransmit_usec = ASSERT_PTR(data); + int r; + + assert(filename); + assert(section); + assert(lvalue); + assert(rvalue); + + if (isempty(rvalue)) { + *router_retransmit_usec = 0; + return 0; + } + + r = parse_sec(rvalue, &usec); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue); + return 0; + } + + if (usec != USEC_INFINITY && + DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Invalid %s= must be in the range 0...%"PRIu32"Sec, ignoring: %s", lvalue, UINT32_MAX, rvalue); + return 0; + } + + *router_retransmit_usec = usec; + return 0; +} + int config_parse_router_preference( const char *unit, const char *filename, diff --git a/src/network/networkd-radv.h b/src/network/networkd-radv.h index ebebb3942b8..e1c22d054f2 100644 --- a/src/network/networkd-radv.h +++ b/src/network/networkd-radv.h @@ -74,6 +74,7 @@ RADVPrefixDelegation radv_prefix_delegation_from_string(const char *s) _pure_; CONFIG_PARSER_PROTOTYPE(config_parse_router_prefix_delegation); CONFIG_PARSER_PROTOTYPE(config_parse_router_lifetime); +CONFIG_PARSER_PROTOTYPE(config_parse_router_retransmit); CONFIG_PARSER_PROTOTYPE(config_parse_router_preference); CONFIG_PARSER_PROTOTYPE(config_parse_prefix); CONFIG_PARSER_PROTOTYPE(config_parse_prefix_boolean); diff --git a/src/systemd/sd-radv.h b/src/systemd/sd-radv.h index 5e8d06f18f4..98fda297a72 100644 --- a/src/systemd/sd-radv.h +++ b/src/systemd/sd-radv.h @@ -53,6 +53,7 @@ int sd_radv_get_ifname(sd_radv *ra, const char **ret); int sd_radv_set_mac(sd_radv *ra, const struct ether_addr *mac_addr); int sd_radv_set_mtu(sd_radv *ra, uint32_t mtu); int sd_radv_set_hop_limit(sd_radv *ra, uint8_t hop_limit); +int sd_radv_set_retransmit(sd_radv *ra, uint32_t retransmit_msec); int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec); int sd_radv_set_managed_information(sd_radv *ra, int managed); int sd_radv_set_other_information(sd_radv *ra, int other);