diff --git a/man/systemd.network.xml b/man/systemd.network.xml
index db9a9ac25d..da4282e502 100644
--- a/man/systemd.network.xml
+++ b/man/systemd.network.xml
@@ -2652,6 +2652,14 @@ Token=prefixstable:2002:da8:1::
+
+ UseICMP6RateLimit=
+
+ Takes a boolean. When true, the ICMP6 rate limit received in the Router Advertisement will be set to ICMP6
+ rate limit based on the advertisement. Defaults to true.
+
+
+
UseGateway=
diff --git a/src/libsystemd-network/ndisc-router.c b/src/libsystemd-network/ndisc-router.c
index e25b3c2d9b..86f8ca0364 100644
--- a/src/libsystemd-network/ndisc-router.c
+++ b/src/libsystemd-network/ndisc-router.c
@@ -95,6 +95,7 @@ int ndisc_router_parse(sd_ndisc *nd, sd_ndisc_router *rt) {
rt->hop_limit = a->nd_ra_curhoplimit;
rt->flags = a->nd_ra_flags_reserved; /* the first 8 bits */
rt->lifetime = be16toh(a->nd_ra_router_lifetime);
+ rt->icmp6_ratelimit_msec = be32toh(a->nd_ra_retransmit);
rt->preference = (rt->flags >> 3) & 3;
if (!IN_SET(rt->preference, SD_NDISC_PREFERENCE_LOW, SD_NDISC_PREFERENCE_HIGH))
@@ -221,6 +222,14 @@ int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret) {
return 0;
}
+int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint32_t *ret) {
+ assert_return(rt, -EINVAL);
+ assert_return(ret, -EINVAL);
+
+ *ret = rt->icmp6_ratelimit_msec;
+ return 0;
+}
+
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags) {
assert_return(rt, -EINVAL);
assert_return(ret_flags, -EINVAL);
diff --git a/src/libsystemd-network/ndisc-router.h b/src/libsystemd-network/ndisc-router.h
index f5293c96e0..cf702f52c3 100644
--- a/src/libsystemd-network/ndisc-router.h
+++ b/src/libsystemd-network/ndisc-router.h
@@ -27,6 +27,7 @@ struct sd_ndisc_router {
uint8_t hop_limit;
uint32_t mtu;
+ uint32_t icmp6_ratelimit_msec;
};
static inline void* NDISC_ROUTER_RAW(const sd_ndisc_router *rt) {
diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c
index b2b222147d..7570d37662 100644
--- a/src/network/networkd-ndisc.c
+++ b/src/network/networkd-ndisc.c
@@ -23,6 +23,7 @@
#include "string-table.h"
#include "string-util.h"
#include "strv.h"
+#include "sysctl-util.h"
#define NDISC_DNSSL_MAX 64U
#define NDISC_RDNSS_MAX 64U
@@ -272,6 +273,7 @@ static int ndisc_request_address(Address *in, Link *link, sd_ndisc_router *rt) {
static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
usec_t lifetime_usec, timestamp_usec;
+ uint32_t icmp6_ratelimit = 0;
struct in6_addr gateway;
uint16_t lifetime_sec;
unsigned preference;
@@ -352,6 +354,20 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
return log_link_warning_errno(link, r, "Could not request gateway: %m");
}
+ r = sd_ndisc_router_get_icmp6_ratelimit(rt, &icmp6_ratelimit);
+ if (r < 0)
+ log_link_debug(link, "Failed to get default router preference from RA: %m");
+
+ if (icmp6_ratelimit > 0 && link->network->ipv6_accept_ra_use_icmp6_ratelimit) {
+ char buf[DECIMAL_STR_MAX(unsigned)];
+
+ xsprintf(buf, "%u", icmp6_ratelimit);
+
+ r = sysctl_write("net/ipv6/icmp/ratelimit", buf);
+ if (r < 0)
+ log_link_warning_errno(link, r, "Could not configure icmp6 rate limit: %m");
+ }
+
return 0;
}
diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf
index c3f286e8bd..69db429fcd 100644
--- a/src/network/networkd-network-gperf.gperf
+++ b/src/network/networkd-network-gperf.gperf
@@ -286,6 +286,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.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
IPv6AcceptRA.RouteMetric, config_parse_ipv6_accept_ra_route_metric, 0, 0
diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c
index dbe8c59a62..b5eef894be 100644
--- a/src/network/networkd-network.c
+++ b/src/network/networkd-network.c
@@ -487,6 +487,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_icmp6_ratelimit = true,
.ipv6_accept_ra_route_table = RT_TABLE_MAIN,
.ipv6_accept_ra_route_metric_high = IPV6RA_ROUTE_METRIC_HIGH,
.ipv6_accept_ra_route_metric_medium = IPV6RA_ROUTE_METRIC_MEDIUM,
diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h
index 031ba398e7..f3b3271811 100644
--- a/src/network/networkd-network.h
+++ b/src/network/networkd-network.h
@@ -320,6 +320,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_icmp6_ratelimit;
bool ipv6_accept_ra_quickack;
bool ipv6_accept_ra_use_captive_portal;
bool active_slave;
diff --git a/src/systemd/sd-ndisc.h b/src/systemd/sd-ndisc.h
index b4faa4428e..be702f68a5 100644
--- a/src/systemd/sd-ndisc.h
+++ b/src/systemd/sd-ndisc.h
@@ -90,6 +90,7 @@ int sd_ndisc_router_get_timestamp(sd_ndisc_router *rt, clockid_t clock, uint64_t
int sd_ndisc_router_get_raw(sd_ndisc_router *rt, const void **ret, size_t *size);
int sd_ndisc_router_get_hop_limit(sd_ndisc_router *rt, uint8_t *ret);
+int sd_ndisc_router_get_icmp6_ratelimit(sd_ndisc_router *rt, uint32_t *ret);
int sd_ndisc_router_get_flags(sd_ndisc_router *rt, uint64_t *ret_flags);
int sd_ndisc_router_get_preference(sd_ndisc_router *rt, unsigned *ret);
int sd_ndisc_router_get_lifetime(sd_ndisc_router *rt, uint16_t *ret_lifetime);