sd-radv: make sd_radv always take timespan in usec

This commit is contained in:
Yu Watanabe
2023-09-21 04:01:14 +09:00
parent 7c52d5236a
commit eca280c8c0
5 changed files with 58 additions and 57 deletions
+13 -7
View File
@@ -42,6 +42,10 @@
#define RADV_MIN_ROUTER_LIFETIME_USEC RADV_MIN_MAX_TIMEOUT_USEC
#define RADV_MAX_ROUTER_LIFETIME_USEC (9000 * USEC_PER_SEC)
#define RADV_DEFAULT_ROUTER_LIFETIME_USEC (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
/* RFC 4861 section 4.2.
* Retrans Timer
* 32-bit unsigned integer. The time, in milliseconds. */
#define RADV_MAX_RETRANSMIT_USEC (UINT32_MAX * USEC_PER_MSEC)
/* draft-ietf-6man-slaac-renum-02 section 4.1.1.
* AdvPreferredLifetime: max(AdvDefaultLifetime, 3 * MaxRtrAdvInterval)
* AdvValidLifetime: 2 * AdvPreferredLifetime */
@@ -60,7 +64,14 @@
#define RADV_MAX_RA_DELAY_TIME_USEC (500 * USEC_PER_MSEC)
/* From RFC 8781 section 4.1
* By default, the value of the Scaled Lifetime field SHOULD be set to the lesser of 3 x MaxRtrAdvInterval */
#define RADV_DEFAULT_PRE64_LIFETIME_USEC (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
#define RADV_PREF64_DEFAULT_LIFETIME_USEC (3 * RADV_DEFAULT_MAX_TIMEOUT_USEC)
#define RADV_RDNSS_MAX_LIFETIME_USEC (UINT32_MAX * USEC_PER_SEC)
#define RADV_DNSSL_MAX_LIFETIME_USEC (UINT32_MAX * USEC_PER_SEC)
/* rfc6275 7.4 Neighbor Discovery Home Agent Lifetime.
* The default value is the same as the Router Lifetime.
* The maximum value corresponds to 18.2 hours. 0 MUST NOT be used. */
#define RADV_HOME_AGENT_MAX_LIFETIME_USEC (UINT16_MAX * USEC_PER_SEC)
#define RADV_OPT_ROUTE_INFORMATION 24
#define RADV_OPT_RDNSS 25
@@ -68,11 +79,6 @@
/* Pref64 option type (RFC8781, section 4) */
#define RADV_OPT_PREF64 38
/* rfc6275 7.4 Neighbor Discovery Home Agent Lifetime.
* The default value is the same as the Router Lifetime
* The maximum value corresponds to 18.2 hours. value of 0 MUST NOT be used.*/
#define RADV_MAX_HOME_AGENT_LIFETIME_USEC (65535 * USEC_PER_SEC)
enum RAdvState {
RADV_STATE_IDLE = 0,
RADV_STATE_ADVERTISING = 1,
@@ -100,7 +106,7 @@ struct sd_radv {
uint8_t hop_limit;
uint8_t flags;
uint32_t mtu;
uint32_t retransmit_msec;
usec_t retransmit_usec;
usec_t lifetime_usec; /* timespan */
int fd;
+25 -16
View File
@@ -169,10 +169,10 @@ 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_retransmit = usec_to_be32_msec(ra->retransmit_usec);
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));
adv.nd_ra_router_lifetime = usec_to_be16_sec(lifetime_usec);
iov[msg.msg_iovlen++] = IOVEC_MAKE(&adv, sizeof(adv));
/* MAC address is optional, either because the link does not use L2
@@ -501,34 +501,35 @@ 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) {
int sd_radv_set_retransmit(sd_radv *ra, uint64_t usec) {
assert_return(ra, -EINVAL);
if (ra->state != RADV_STATE_IDLE)
return -EBUSY;
ra->retransmit_msec = retransmit_msec;
if (usec > RADV_MAX_RETRANSMIT_USEC)
return -EINVAL;
ra->retransmit_usec = usec;
return 0;
}
int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec) {
assert_return(ra, -EINVAL);
if (ra->state != RADV_STATE_IDLE)
return -EBUSY;
if (!router_lifetime_is_valid(lifetime_usec))
if (!router_lifetime_is_valid(usec))
return -EINVAL;
/* RFC 4191, Section 2.2, "...If the Router Lifetime is zero, the preference value MUST be set
* to (00) by the sender..." */
if (lifetime_usec == 0 &&
if (usec == 0 &&
(ra->flags & (0x3 << 3)) != (SD_NDISC_PREFERENCE_MEDIUM << 3))
return -EINVAL;
ra->lifetime_usec = lifetime_usec;
ra->lifetime_usec = usec;
return 0;
}
@@ -593,14 +594,16 @@ int sd_radv_set_home_agent_preference(sd_radv *ra, uint16_t preference) {
return 0;
}
int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint16_t lifetime) {
int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t lifetime_usec) {
assert_return(ra, -EINVAL);
if (ra->state != RADV_STATE_IDLE)
return -EBUSY;
ra->home_agent.nd_opt_home_agent_info_lifetime = htobe16(lifetime);
if (lifetime_usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC)
return -EINVAL;
ra->home_agent.nd_opt_home_agent_info_lifetime = usec_to_be16_sec(lifetime_usec);
return 0;
}
@@ -851,7 +854,7 @@ int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p) {
int sd_radv_set_rdnss(
sd_radv *ra,
uint32_t lifetime,
uint64_t lifetime_usec,
const struct in6_addr *dns,
size_t n_dns) {
@@ -861,6 +864,9 @@ int sd_radv_set_rdnss(
assert_return(ra, -EINVAL);
assert_return(n_dns < 128, -EINVAL);
if (lifetime_usec > RADV_RDNSS_MAX_LIFETIME_USEC)
return -EINVAL;
if (!dns || n_dns == 0) {
ra->rdnss = mfree(ra->rdnss);
ra->n_rdnss = 0;
@@ -876,7 +882,7 @@ int sd_radv_set_rdnss(
opt_rdnss->type = RADV_OPT_RDNSS;
opt_rdnss->length = len / 8;
opt_rdnss->lifetime = htobe32(lifetime);
opt_rdnss->lifetime = usec_to_be32_sec(lifetime_usec);
memcpy(opt_rdnss + 1, dns, n_dns * sizeof(struct in6_addr));
@@ -889,7 +895,7 @@ int sd_radv_set_rdnss(
int sd_radv_set_dnssl(
sd_radv *ra,
uint32_t lifetime,
uint64_t lifetime_usec,
char **search_list) {
_cleanup_free_ struct sd_radv_opt_dns *opt_dnssl = NULL;
@@ -898,6 +904,9 @@ int sd_radv_set_dnssl(
assert_return(ra, -EINVAL);
if (lifetime_usec > RADV_DNSSL_MAX_LIFETIME_USEC)
return -EINVAL;
if (strv_isempty(search_list)) {
ra->dnssl = mfree(ra->dnssl);
return 0;
@@ -914,7 +923,7 @@ int sd_radv_set_dnssl(
opt_dnssl->type = RADV_OPT_DNSSL;
opt_dnssl->length = len / 8;
opt_dnssl->lifetime = htobe32(lifetime);
opt_dnssl->lifetime = usec_to_be32_sec(lifetime_usec);
p = (uint8_t *)(opt_dnssl + 1);
len -= sizeof(struct sd_radv_opt_dns);
@@ -1134,7 +1143,7 @@ int sd_radv_pref64_prefix_set_prefix(
if (r < 0)
return log_radv_errno(NULL, r, "Unsupported PREF64 prefix length %u. Valid lengths are 32, 40, 48, 56, 64 and 96", prefixlen);
if (lifetime_usec == USEC_INFINITY || DIV_ROUND_UP(lifetime_usec, 8 * USEC_PER_SEC) >= UINT64_C(1) << 13)
if (lifetime_usec > PREF64_MAX_LIFETIME_USEC)
return -EINVAL;
/* RFC 8781 - 4.1 rounding up lifetime to multiply of 8 */
+6 -6
View File
@@ -193,15 +193,15 @@ TEST(radv) {
assert_se(sd_radv_set_rdnss(NULL, 0, NULL, 0) < 0);
assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
assert_se(sd_radv_set_rdnss(ra, 0, NULL, 128) < 0);
assert_se(sd_radv_set_rdnss(ra, 600, &test_rdnss, 0) >= 0);
assert_se(sd_radv_set_rdnss(ra, 600, &test_rdnss, 1) >= 0);
assert_se(sd_radv_set_rdnss(ra, 600 * USEC_PER_SEC, &test_rdnss, 0) >= 0);
assert_se(sd_radv_set_rdnss(ra, 600 * USEC_PER_SEC, &test_rdnss, 1) >= 0);
assert_se(sd_radv_set_rdnss(ra, 0, &test_rdnss, 1) >= 0);
assert_se(sd_radv_set_rdnss(ra, 0, NULL, 0) >= 0);
assert_se(sd_radv_set_dnssl(ra, 0, NULL) >= 0);
assert_se(sd_radv_set_dnssl(ra, 600, NULL) >= 0);
assert_se(sd_radv_set_dnssl(ra, 600 * USEC_PER_SEC, NULL) >= 0);
assert_se(sd_radv_set_dnssl(ra, 0, (char **)test_dnssl) >= 0);
assert_se(sd_radv_set_dnssl(ra, 600, (char **)test_dnssl) >= 0);
assert_se(sd_radv_set_dnssl(ra, 600 * USEC_PER_SEC, (char **)test_dnssl) >= 0);
ra = sd_radv_unref(ra);
assert_se(!ra);
@@ -273,8 +273,8 @@ TEST(ra) {
assert_se(sd_radv_set_hop_limit(ra, 64) >= 0);
assert_se(sd_radv_set_managed_information(ra, true) >= 0);
assert_se(sd_radv_set_other_information(ra, true) >= 0);
assert_se(sd_radv_set_rdnss(ra, 60, &test_rdnss, 1) >= 0);
assert_se(sd_radv_set_dnssl(ra, 60, (char **)test_dnssl) >= 0);
assert_se(sd_radv_set_rdnss(ra, 60 * USEC_PER_SEC, &test_rdnss, 1) >= 0);
assert_se(sd_radv_set_dnssl(ra, 60 * USEC_PER_SEC, (char **)test_dnssl) >= 0);
for (unsigned i = 0; i < ELEMENTSOF(prefix); i++) {
sd_radv_prefix *p;
+9 -23
View File
@@ -222,7 +222,7 @@ static int pref64_prefix_new_static(Network *network, const char *filename, unsi
.network = network,
.section = TAKE_PTR(n),
.lifetime = RADV_DEFAULT_PRE64_LIFETIME_USEC,
.lifetime = RADV_PREF64_DEFAULT_LIFETIME_USEC,
};
r = hashmap_ensure_put(&network->pref64_prefixes_by_section, &config_section_hash_ops, prefix->section, prefix);
@@ -279,19 +279,6 @@ int link_request_radv_addresses(Link *link) {
return 0;
}
static uint32_t usec_to_lifetime(usec_t usec) {
uint64_t t;
if (usec == USEC_INFINITY)
return UINT32_MAX;
t = DIV_ROUND_UP(usec, USEC_PER_SEC);
if (t >= UINT32_MAX)
return UINT32_MAX;
return (uint32_t) t;
}
static int radv_set_prefix(Link *link, Prefix *prefix) {
_cleanup_(sd_radv_prefix_unrefp) sd_radv_prefix *p = NULL;
int r;
@@ -446,7 +433,7 @@ static int radv_set_dns(Link *link, Link *uplink) {
set_dns:
return sd_radv_set_rdnss(link->radv,
usec_to_lifetime(link->network->router_dns_lifetime_usec),
link->network->router_dns_lifetime_usec,
dns, n_dns);
}
@@ -482,7 +469,7 @@ set_domains:
return log_oom();
return sd_radv_set_dnssl(link->radv,
usec_to_lifetime(link->network->router_dns_lifetime_usec),
link->network->router_dns_lifetime_usec,
s);
}
@@ -567,7 +554,7 @@ static int radv_configure(Link *link) {
}
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));
r = sd_radv_set_retransmit(link->radv, link->network->router_retransmit_usec);
if (r < 0)
return r;
}
@@ -608,7 +595,7 @@ static int radv_configure(Link *link) {
if (r < 0)
return r;
r = sd_radv_set_home_agent_lifetime(link->radv, DIV_ROUND_UP(link->network->home_agent_lifetime_usec, USEC_PER_SEC));
r = sd_radv_set_home_agent_lifetime(link->radv, link->network->home_agent_lifetime_usec);
if (r < 0)
return r;
@@ -1545,9 +1532,9 @@ int config_parse_router_retransmit(
}
if (usec != USEC_INFINITY &&
DIV_ROUND_UP(usec, USEC_PER_MSEC) > UINT32_MAX) {
usec > RADV_MAX_RETRANSMIT_USEC) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid %s= must be in the range 0...%"PRIu32"Sec, ignoring: %s", lvalue, UINT32_MAX, rvalue);
"Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
return 0;
}
@@ -1621,10 +1608,9 @@ int config_parse_router_home_agent_lifetime(
}
if (usec == USEC_INFINITY || usec == 0 ||
DIV_ROUND_UP(usec, USEC_PER_SEC) > RADV_MAX_HOME_AGENT_LIFETIME_USEC) {
usec > RADV_HOME_AGENT_MAX_LIFETIME_USEC) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Invalid %s= must be in the range 1…%s, ignoring: %s", lvalue,
FORMAT_TIMESPAN(RADV_MAX_HOME_AGENT_LIFETIME_USEC, USEC_PER_SEC), rvalue);
"Invalid [%s] %s=, ignoring assignment: %s", section, lvalue, rvalue);
return 0;
}
+5 -5
View File
@@ -54,8 +54,8 @@ 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_retransmit(sd_radv *ra, uint64_t usec);
int sd_radv_set_router_lifetime(sd_radv *ra, uint64_t usec);
int sd_radv_set_managed_information(sd_radv *ra, int managed);
int sd_radv_set_other_information(sd_radv *ra, int other);
int sd_radv_set_preference(sd_radv *ra, unsigned preference);
@@ -63,9 +63,9 @@ int sd_radv_add_prefix(sd_radv *ra, sd_radv_prefix *p);
int sd_radv_add_route_prefix(sd_radv *ra, sd_radv_route_prefix *p);
int sd_radv_add_pref64_prefix(sd_radv *ra, sd_radv_pref64_prefix *p);
void sd_radv_remove_prefix(sd_radv *ra, const struct in6_addr *prefix, unsigned char prefixlen);
int sd_radv_set_rdnss(sd_radv *ra, uint32_t lifetime,
int sd_radv_set_rdnss(sd_radv *ra, uint64_t lifetime_usec,
const struct in6_addr *dns, size_t n_dns);
int sd_radv_set_dnssl(sd_radv *ra, uint32_t lifetime, char **search_list);
int sd_radv_set_dnssl(sd_radv *ra, uint64_t lifetime_usec, char **search_list);
/* Advertised prefixes */
int sd_radv_prefix_new(sd_radv_prefix **ret);
@@ -98,7 +98,7 @@ sd_radv_pref64_prefix *sd_radv_pref64_prefix_unref(sd_radv_pref64_prefix *ra);
/* Mobile IPv6 extension: Home Agent Info. */
int sd_radv_set_home_agent_information(sd_radv *ra, int home_agent);
int sd_radv_set_home_agent_preference(sd_radv *ra, uint16_t preference);
int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint16_t lifetime);
int sd_radv_set_home_agent_lifetime(sd_radv *ra, uint64_t usec);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv, sd_radv_unref);
_SD_DEFINE_POINTER_CLEANUP_FUNC(sd_radv_prefix, sd_radv_prefix_unref);