Merge pull request #24001 from yuwata/network-lifetime-fix

network: fixes for lifetime handling
This commit is contained in:
Luca Boccassi 2022-07-18 10:02:02 +01:00 committed by GitHub
commit 9b9ddaf09d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
7 changed files with 93 additions and 56 deletions

View file

@ -212,39 +212,32 @@ void address_set_broadcast(Address *a, Link *link) {
a->broadcast.s_addr = a->in_addr.in.s_addr | htobe32(UINT32_C(0xffffffff) >> a->prefixlen);
}
static struct ifa_cacheinfo *address_set_cinfo(const Address *a, struct ifa_cacheinfo *cinfo) {
static void address_set_cinfo(Manager *m, const Address *a, struct ifa_cacheinfo *cinfo) {
usec_t now_usec;
assert(m);
assert(a);
assert(cinfo);
now_usec = now(CLOCK_BOOTTIME);
assert_se(sd_event_now(m->event, CLOCK_BOOTTIME, &now_usec) >= 0);
*cinfo = (struct ifa_cacheinfo) {
.ifa_valid = MIN(usec_sub_unsigned(a->lifetime_valid_usec, now_usec) / USEC_PER_SEC, UINT32_MAX),
.ifa_prefered = MIN(usec_sub_unsigned(a->lifetime_preferred_usec, now_usec) / USEC_PER_SEC, UINT32_MAX),
.ifa_valid = usec_to_sec(a->lifetime_valid_usec, now_usec),
.ifa_prefered = usec_to_sec(a->lifetime_preferred_usec, now_usec),
};
return cinfo;
}
static void address_set_lifetime(Address *a, const struct ifa_cacheinfo *cinfo) {
static void address_set_lifetime(Manager *m, Address *a, const struct ifa_cacheinfo *cinfo) {
usec_t now_usec;
assert(m);
assert(a);
assert(cinfo);
now_usec = now(CLOCK_BOOTTIME);
assert_se(sd_event_now(m->event, CLOCK_BOOTTIME, &now_usec) >= 0);
if (cinfo->ifa_valid == UINT32_MAX)
a->lifetime_valid_usec = USEC_INFINITY;
else
a->lifetime_valid_usec = usec_add(cinfo->ifa_valid * USEC_PER_SEC, now_usec);
if (cinfo->ifa_prefered == UINT32_MAX)
a->lifetime_preferred_usec = USEC_INFINITY;
else
a->lifetime_preferred_usec = usec_add(cinfo->ifa_prefered * USEC_PER_SEC, now_usec);
a->lifetime_valid_usec = sec_to_usec(cinfo->ifa_valid, now_usec);
a->lifetime_preferred_usec = sec_to_usec(cinfo->ifa_prefered, now_usec);
}
static uint32_t address_prefix(const Address *a) {
@ -1035,12 +1028,13 @@ int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m,
return 1;
}
static int address_configure(const Address *address, Link *link, Request *req) {
static int address_configure(const Address *address, const struct ifa_cacheinfo *c, Link *link, Request *req) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
assert(address);
assert(IN_SET(address->family, AF_INET, AF_INET6));
assert(c);
assert(link);
assert(link->ifindex > 0);
assert(link->manager);
@ -1077,8 +1071,7 @@ static int address_configure(const Address *address, Link *link, Request *req) {
return r;
}
r = sd_netlink_message_append_cache_info(m, IFA_CACHEINFO,
address_set_cinfo(address, &(struct ifa_cacheinfo) {}));
r = sd_netlink_message_append_cache_info(m, IFA_CACHEINFO, c);
if (r < 0)
return r;
@ -1107,6 +1100,7 @@ static bool address_is_ready_to_configure(Link *link, const Address *address) {
}
static int address_process_request(Request *req, Link *link, Address *address) {
struct ifa_cacheinfo c;
int r;
assert(req);
@ -1116,7 +1110,16 @@ static int address_process_request(Request *req, Link *link, Address *address) {
if (!address_is_ready_to_configure(link, address))
return 0;
r = address_configure(address, link, req);
address_set_cinfo(link->manager, address, &c);
if (c.ifa_valid == 0) {
log_link_debug(link, "Refuse to configure %s address %s, as its valid lifetime is zero.",
network_config_source_to_string(address->source),
IN_ADDR_PREFIX_TO_STRING(address->family, &address->in_addr, address->prefixlen));
address_cancel_requesting(address);
return 1;
}
r = address_configure(address, &c, link, req);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure address: %m");
@ -1455,18 +1458,18 @@ int manager_rtnl_process_address(sd_netlink *rtnl, sd_netlink_message *message,
/* update flags and etc. */
address->flags = tmp->flags;
address->scope = tmp->scope;
address_set_lifetime(address, &cinfo);
address_set_lifetime(m, address, &cinfo);
address_enter_configured(address);
log_address_debug(address, "Received updated", link);
} else {
address_set_lifetime(tmp, &cinfo);
address_set_lifetime(m, tmp, &cinfo);
address_enter_configured(tmp);
log_address_debug(tmp, "Received new", link);
r = address_add(link, tmp);
if (r < 0) {
log_link_warning_errno(link, r, "Failed to remember foreign address %s, ignoring: %m",
IN_ADDR_PREFIX_TO_STRING(tmp->family, &tmp->in_addr, tmp->prefixlen));
IN_ADDR_PREFIX_TO_STRING(tmp->family, &tmp->in_addr, tmp->prefixlen));
return 0;
}

View file

@ -854,11 +854,12 @@ static int dhcp4_pd_assign_subnet_prefix(Link *link, Link *uplink) {
const struct in_addr *br_addresses;
struct in_addr ipv4address;
uint32_t lifetime_sec;
usec_t lifetime_usec;
usec_t lifetime_usec, now_usec;
int r;
assert(link);
assert(uplink);
assert(uplink->manager);
assert(uplink->dhcp_lease);
r = sd_dhcp_lease_get_address(uplink->dhcp_lease, &ipv4address);
@ -869,7 +870,8 @@ static int dhcp4_pd_assign_subnet_prefix(Link *link, Link *uplink) {
if (r < 0)
return log_link_warning_errno(uplink, r, "Failed to get lifetime of DHCPv4 lease: %m");
lifetime_usec = usec_add(lifetime_sec * USEC_PER_SEC, now(CLOCK_BOOTTIME));
assert_se(sd_event_now(uplink->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
lifetime_usec = sec_to_usec(lifetime_sec, now_usec);
r = sd_dhcp_lease_get_6rd(uplink->dhcp_lease, &ipv4masklen, &sixrd_prefixlen, &sixrd_prefix, &br_addresses, NULL);
if (r < 0)
@ -926,11 +928,12 @@ int dhcp4_pd_prefix_acquired(Link *uplink) {
union in_addr_union server_address;
const struct in_addr *br_addresses;
uint32_t lifetime_sec;
usec_t lifetime_usec;
usec_t lifetime_usec, now_usec;
Link *link;
int r;
assert(uplink);
assert(uplink->manager);
assert(uplink->dhcp_lease);
r = sd_dhcp_lease_get_address(uplink->dhcp_lease, &ipv4address);
@ -941,7 +944,8 @@ int dhcp4_pd_prefix_acquired(Link *uplink) {
if (r < 0)
return log_link_warning_errno(uplink, r, "Failed to get lifetime of DHCPv4 lease: %m");
lifetime_usec = usec_add(lifetime_sec * USEC_PER_SEC, now(CLOCK_BOOTTIME));
assert_se(sd_event_now(uplink->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
lifetime_usec = sec_to_usec(lifetime_sec, now_usec);
r = sd_dhcp_lease_get_server_identifier(uplink->dhcp_lease, &server_address.in);
if (r < 0)
@ -1032,7 +1036,6 @@ static int dhcp6_pd_assign_subnet_prefixes(Link *link, Link *uplink) {
for (sd_dhcp6_lease_reset_pd_prefix_iter(uplink->dhcp6_lease);;) {
uint32_t lifetime_preferred_sec, lifetime_valid_sec;
usec_t lifetime_preferred_usec, lifetime_valid_usec;
struct in6_addr pd_prefix;
uint8_t pd_prefix_len;
@ -1049,11 +1052,9 @@ static int dhcp6_pd_assign_subnet_prefixes(Link *link, Link *uplink) {
if (r < 0)
return r;
lifetime_preferred_usec = usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec);
lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec);
r = dhcp_pd_assign_subnet_prefix(link, &pd_prefix, pd_prefix_len,
lifetime_preferred_usec, lifetime_valid_usec,
sec_to_usec(lifetime_preferred_sec, timestamp_usec),
sec_to_usec(lifetime_valid_sec, timestamp_usec),
/* is_uplink = */ link == uplink);
if (r < 0)
return r;
@ -1082,7 +1083,6 @@ int dhcp6_pd_prefix_acquired(Link *uplink) {
/* First, logs acquired prefixes and request unreachable routes. */
for (sd_dhcp6_lease_reset_pd_prefix_iter(uplink->dhcp6_lease);;) {
uint32_t lifetime_preferred_sec, lifetime_valid_sec;
usec_t lifetime_valid_usec;
struct in6_addr pd_prefix;
uint8_t pd_prefix_len;
@ -1096,13 +1096,13 @@ int dhcp6_pd_prefix_acquired(Link *uplink) {
if (r < 0)
return log_link_error_errno(uplink, r, "Failed to mask DHCPv6 delegated prefix: %m");
lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec);
r = dhcp_pd_prefix_add(uplink, &pd_prefix, pd_prefix_len);
if (r < 0)
return r;
r = dhcp6_request_unreachable_route(uplink, &pd_prefix, pd_prefix_len, lifetime_valid_usec, &server_address);
r = dhcp6_request_unreachable_route(uplink, &pd_prefix, pd_prefix_len,
sec_to_usec(lifetime_valid_sec, timestamp_usec),
&server_address);
if (r < 0)
return r;
}

View file

@ -797,6 +797,7 @@ static int dhcp4_request_address(Link *link, bool announce) {
int r;
assert(link);
assert(link->manager);
assert(link->network);
assert(link->dhcp_lease);
@ -814,12 +815,14 @@ static int dhcp4_request_address(Link *link, bool announce) {
if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
uint32_t lifetime_sec;
usec_t now_usec;
r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime_sec);
if (r < 0)
return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
lifetime_usec = usec_add(lifetime_sec * USEC_PER_SEC, now(CLOCK_BOOTTIME));
assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
lifetime_usec = sec_to_usec(lifetime_sec, now_usec);
} else
lifetime_usec = USEC_INFINITY;

View file

@ -266,8 +266,8 @@ static int dhcp6_address_acquired(Link *link) {
break;
r = dhcp6_request_address(link, &server_address, &ip6_addr,
usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec),
usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec));
sec_to_usec(lifetime_preferred_sec, timestamp_usec),
sec_to_usec(lifetime_valid_sec, timestamp_usec));
if (r < 0)
return r;
}

View file

@ -314,7 +314,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
if (r < 0)
return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
lifetime_usec = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
lifetime_usec = sec16_to_usec(lifetime_sec, timestamp_usec);
r = sd_ndisc_router_get_address(rt, &gateway);
if (r < 0)
@ -436,8 +436,8 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
if (lifetime_preferred_sec > lifetime_valid_sec)
return 0;
lifetime_valid_usec = usec_add(lifetime_valid_sec * USEC_PER_SEC, timestamp_usec);
lifetime_preferred_usec = usec_add(lifetime_preferred_sec * USEC_PER_SEC, timestamp_usec);
lifetime_valid_usec = sec_to_usec(lifetime_valid_sec, timestamp_usec);
lifetime_preferred_usec = sec_to_usec(lifetime_preferred_sec, timestamp_usec);
r = ndisc_generate_addresses(link, &prefix, prefixlen, &addresses);
if (r < 0)
@ -513,7 +513,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
route->family = AF_INET6;
route->flags = RTM_F_PREFIX;
route->dst_prefixlen = prefixlen;
route->lifetime_usec = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
route->lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
if (r < 0)
@ -646,7 +646,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
route->gw_family = AF_INET6;
route->dst.in6 = dst;
route->dst_prefixlen = prefixlen;
route->lifetime_usec = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
route->lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
r = ndisc_request_route(TAKE_PTR(route), link, rt);
if (r < 0)
@ -700,7 +700,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
if (lifetime_sec == 0)
return 0;
lifetime_usec = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
if (n < 0)
@ -794,7 +794,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
if (lifetime_sec == 0)
return 0;
lifetime_usec = usec_add(timestamp_usec, lifetime_sec * USEC_PER_SEC);
lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
r = sd_ndisc_router_dnssl_get_domains(rt, &l);
if (r < 0)
@ -1137,20 +1137,21 @@ int link_request_ndisc(Link *link) {
void ndisc_vacuum(Link *link) {
NDiscRDNSS *r;
NDiscDNSSL *d;
usec_t time_now;
usec_t now_usec;
assert(link);
assert(link->manager);
/* Removes all RDNSS and DNSSL entries whose validity time has passed */
time_now = now(CLOCK_BOOTTIME);
assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
SET_FOREACH(r, link->ndisc_rdnss)
if (r->lifetime_usec < time_now)
if (r->lifetime_usec < now_usec)
free(set_remove(link->ndisc_rdnss, r));
SET_FOREACH(d, link->ndisc_dnssl)
if (d->lifetime_usec < time_now)
if (d->lifetime_usec < now_usec)
free(set_remove(link->ndisc_dnssl, d));
}

View file

@ -1153,7 +1153,7 @@ int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Li
return 1;
}
static int route_configure(const Route *route, Link *link, Request *req) {
static int route_configure(const Route *route, uint32_t lifetime_sec, Link *link, Request *req) {
_cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL;
int r;
@ -1179,9 +1179,8 @@ static int route_configure(const Route *route, Link *link, Request *req) {
if (r < 0)
return r;
if (route->lifetime_usec != USEC_INFINITY) {
r = sd_netlink_message_append_u32(m, RTA_EXPIRES,
MIN(DIV_ROUND_UP(usec_sub_unsigned(route->lifetime_usec, now(CLOCK_BOOTTIME)), USEC_PER_SEC), UINT32_MAX));
if (lifetime_sec != UINT32_MAX) {
r = sd_netlink_message_append_u32(m, RTA_EXPIRES, lifetime_sec);
if (r < 0)
return r;
}
@ -1318,6 +1317,7 @@ static int route_process_request(Request *req, Link *link, Route *route) {
assert(req);
assert(link);
assert(link->manager);
assert(route);
r = route_is_ready_to_configure(route, link);
@ -1356,7 +1356,25 @@ static int route_process_request(Request *req, Link *link, Route *route) {
}
}
r = route_configure(route, link, req);
usec_t now_usec;
assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
uint32_t sec = usec_to_sec(route->lifetime_usec, now_usec);
if (sec == 0) {
log_link_debug(link, "Refuse to configure %s route with zero lifetime.",
network_config_source_to_string(route->source));
if (converted)
for (size_t i = 0; i < converted->n; i++) {
Route *existing;
assert_se(route_get(link->manager, converted->links[i] ?: link, converted->routes[i], &existing) >= 0);
route_cancel_requesting(existing);
}
else
route_cancel_requesting(route);
}
r = route_configure(route, sec, link, req);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure route: %m");

View file

@ -37,6 +37,18 @@ typedef enum NetworkConfigState {
NETWORK_CONFIG_STATE_REMOVING = 1 << 5, /* e.g. address_remove() is called, but no response is received yet */
} NetworkConfigState;
static inline usec_t sec16_to_usec(uint16_t sec, usec_t timestamp_usec) {
return sec == UINT16_MAX ? USEC_INFINITY : usec_add(timestamp_usec, sec * USEC_PER_SEC);
}
static inline usec_t sec_to_usec(uint32_t sec, usec_t timestamp_usec) {
return sec == UINT32_MAX ? USEC_INFINITY : usec_add(timestamp_usec, sec * USEC_PER_SEC);
}
static inline uint32_t usec_to_sec(usec_t usec, usec_t now_usec) {
return MIN(DIV_ROUND_UP(usec_sub_unsigned(usec, now_usec), USEC_PER_SEC), UINT32_MAX);
}
CONFIG_PARSER_PROTOTYPE(config_parse_link_local_address_family);
CONFIG_PARSER_PROTOTYPE(config_parse_address_family_with_kernel);
CONFIG_PARSER_PROTOTYPE(config_parse_ip_masquerade);