mirror of
https://github.com/systemd/systemd.git
synced 2026-07-13 02:51:14 +00:00
Merge pull request #24900 from yuwata/network-ndisc-drop-outdated
network: ndisc: fix zero lifetime handling
This commit is contained in:
@@ -765,6 +765,18 @@ int address_remove(Address *address) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int address_remove_and_drop(Address *address) {
|
||||
if (!address)
|
||||
return 0;
|
||||
|
||||
address_cancel_request(address);
|
||||
|
||||
if (address_exists(address))
|
||||
return address_remove(address);
|
||||
|
||||
return address_drop(address);
|
||||
}
|
||||
|
||||
bool link_address_is_dynamic(const Link *link, const Address *address) {
|
||||
Route *route;
|
||||
|
||||
@@ -1142,7 +1154,7 @@ int link_request_address(
|
||||
address_netlink_handler_t netlink_handler,
|
||||
Request **ret) {
|
||||
|
||||
Address *acquired, *existing;
|
||||
Address *acquired, *existing = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@@ -1175,7 +1187,13 @@ int link_request_address(
|
||||
address_set_broadcast(address, link);
|
||||
}
|
||||
|
||||
if (address_get(link, address, &existing) < 0) {
|
||||
(void) address_get(link, address, &existing);
|
||||
|
||||
if (address->lifetime_valid_usec == 0)
|
||||
/* The requested address is outdated. Let's remove it. */
|
||||
return address_remove_and_drop(existing);
|
||||
|
||||
if (!existing) {
|
||||
_cleanup_(address_freep) Address *tmp = NULL;
|
||||
|
||||
if (consume_object)
|
||||
|
||||
@@ -78,6 +78,7 @@ Address* address_free(Address *address);
|
||||
int address_get(Link *link, const Address *in, Address **ret);
|
||||
int address_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
|
||||
int address_remove(Address *address);
|
||||
int address_remove_and_drop(Address *address);
|
||||
int address_dup(const Address *src, Address **ret);
|
||||
bool address_is_ready(const Address *a);
|
||||
void address_set_broadcast(Address *a, Link *link);
|
||||
|
||||
@@ -332,7 +332,7 @@ int link_stop_engines(Link *link, bool may_keep_dhcp) {
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not remove DHCPv6 PD addresses and routes: %m");
|
||||
|
||||
k = sd_ndisc_stop(link->ndisc);
|
||||
k = ndisc_stop(link);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Could not stop IPv6 Router Discovery: %m");
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@ typedef struct Link {
|
||||
sd_dhcp_server *dhcp_server;
|
||||
|
||||
sd_ndisc *ndisc;
|
||||
sd_event_source *ndisc_expire;
|
||||
Set *ndisc_rdnss;
|
||||
Set *ndisc_dnssl;
|
||||
unsigned ndisc_messages;
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include "sd-ndisc.h"
|
||||
|
||||
#include "event-util.h"
|
||||
#include "missing_network.h"
|
||||
#include "networkd-address-generation.h"
|
||||
#include "networkd-address.h"
|
||||
@@ -234,9 +235,6 @@ 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 gateway lifetime from RA: %m");
|
||||
|
||||
if (lifetime_sec == 0) /* not a default router */
|
||||
return 0;
|
||||
|
||||
r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, ×tamp_usec);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
|
||||
@@ -350,11 +348,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix valid lifetime: %m");
|
||||
|
||||
if (lifetime_valid_sec == 0) {
|
||||
log_link_debug(link, "Ignoring prefix as its valid lifetime is zero.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_ndisc_router_prefix_get_preferred_lifetime(rt, &lifetime_preferred_sec);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix preferred lifetime: %m");
|
||||
@@ -372,7 +365,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
||||
|
||||
SET_FOREACH(a, addresses) {
|
||||
_cleanup_(address_freep) Address *address = NULL;
|
||||
Address *e;
|
||||
|
||||
r = address_new(&address);
|
||||
if (r < 0)
|
||||
@@ -385,17 +377,6 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
|
||||
address->lifetime_valid_usec = lifetime_valid_usec;
|
||||
address->lifetime_preferred_usec = lifetime_preferred_usec;
|
||||
|
||||
/* See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by
|
||||
* honoring all valid lifetimes to improve the reaction of SLAAC to renumbering events.
|
||||
* See draft-ietf-6man-slaac-renum-02, section 4.2. */
|
||||
r = address_get(link, address, &e);
|
||||
if (r > 0) {
|
||||
/* If the address is already assigned, but not valid anymore, then refuse to
|
||||
* update the address, and it will be removed. */
|
||||
if (e->lifetime_valid_usec < timestamp_usec)
|
||||
continue;
|
||||
}
|
||||
|
||||
r = ndisc_request_address(TAKE_PTR(address), link, rt);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not request SLAAC address: %m");
|
||||
@@ -408,6 +389,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
|
||||
_cleanup_(route_freep) Route *route = NULL;
|
||||
usec_t timestamp_usec;
|
||||
uint32_t lifetime_sec;
|
||||
struct in6_addr prefix;
|
||||
unsigned prefixlen;
|
||||
int r;
|
||||
|
||||
@@ -422,13 +404,14 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix lifetime: %m");
|
||||
|
||||
if (lifetime_sec == 0)
|
||||
return 0;
|
||||
|
||||
r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, ×tamp_usec);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
|
||||
|
||||
r = sd_ndisc_router_prefix_get_address(rt, &prefix);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
||||
|
||||
r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix length: %m");
|
||||
@@ -439,13 +422,10 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
|
||||
|
||||
route->family = AF_INET6;
|
||||
route->flags = RTM_F_PREFIX;
|
||||
route->dst.in6 = prefix;
|
||||
route->dst_prefixlen = prefixlen;
|
||||
route->lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
|
||||
|
||||
r = sd_ndisc_router_prefix_get_address(rt, &route->dst.in6);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
||||
|
||||
r = ndisc_request_route(TAKE_PTR(route), link, rt);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Could not request prefix route: %m");
|
||||
@@ -467,6 +447,14 @@ static int ndisc_router_process_prefix(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix address: %m");
|
||||
|
||||
/* RFC 4861 Section 4.6.2:
|
||||
* A router SHOULD NOT send a prefix option for the link-local prefix and a host SHOULD ignore such
|
||||
* a prefix option. */
|
||||
if (in6_addr_is_link_local(&a)) {
|
||||
log_link_debug(link, "Received link-local prefix, ignoring autonomous prefix.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_ndisc_router_prefix_get_prefixlen(rt, &prefixlen);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get prefix length: %m");
|
||||
@@ -516,9 +504,6 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get route lifetime from RA: %m");
|
||||
|
||||
if (lifetime_sec == 0)
|
||||
return 0;
|
||||
|
||||
r = sd_ndisc_router_route_get_address(rt, &dst);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get route destination address: %m");
|
||||
@@ -602,7 +587,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
||||
uint32_t lifetime_sec;
|
||||
const struct in6_addr *a;
|
||||
struct in6_addr router;
|
||||
bool updated = false;
|
||||
bool updated = false, logged_about_too_many = false;
|
||||
int n, r;
|
||||
|
||||
assert(link);
|
||||
@@ -624,26 +609,25 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get RDNSS lifetime: %m");
|
||||
|
||||
if (lifetime_sec == 0)
|
||||
return 0;
|
||||
|
||||
lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
|
||||
|
||||
n = sd_ndisc_router_rdnss_get_addresses(rt, &a);
|
||||
if (n < 0)
|
||||
return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
|
||||
|
||||
if (n >= (int) NDISC_RDNSS_MAX) {
|
||||
log_link_warning(link, "Too many RDNSS records per link. Only first %u records will be used.", NDISC_RDNSS_MAX);
|
||||
n = NDISC_RDNSS_MAX;
|
||||
}
|
||||
|
||||
for (int j = 0; j < n; j++) {
|
||||
_cleanup_free_ NDiscRDNSS *x = NULL;
|
||||
NDiscRDNSS *rdnss, d = {
|
||||
.address = a[j],
|
||||
};
|
||||
|
||||
if (lifetime_usec == 0) {
|
||||
/* The entry is outdated. */
|
||||
free(set_remove(link->ndisc_rdnss, &d));
|
||||
updated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
rdnss = set_get(link->ndisc_rdnss, &d);
|
||||
if (rdnss) {
|
||||
rdnss->router = router;
|
||||
@@ -651,6 +635,13 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (set_size(link->ndisc_rdnss) >= NDISC_RDNSS_MAX) {
|
||||
if (!logged_about_too_many)
|
||||
log_link_warning(link, "Too many RDNSS records per link. Only first %u records will be used.", NDISC_RDNSS_MAX);
|
||||
logged_about_too_many = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
x = new(NDiscRDNSS, 1);
|
||||
if (!x)
|
||||
return log_oom();
|
||||
@@ -695,7 +686,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
||||
usec_t lifetime_usec, timestamp_usec;
|
||||
struct in6_addr router;
|
||||
uint32_t lifetime_sec;
|
||||
bool updated = false;
|
||||
bool updated = false, logged_about_too_many = false;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@@ -717,21 +708,12 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get DNSSL lifetime: %m");
|
||||
|
||||
if (lifetime_sec == 0)
|
||||
return 0;
|
||||
|
||||
lifetime_usec = sec_to_usec(lifetime_sec, timestamp_usec);
|
||||
|
||||
r = sd_ndisc_router_dnssl_get_domains(rt, &l);
|
||||
if (r < 0)
|
||||
return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
|
||||
|
||||
if (strv_length(l) >= NDISC_DNSSL_MAX) {
|
||||
log_link_warning(link, "Too many DNSSL records per link. Only first %u records will be used.", NDISC_DNSSL_MAX);
|
||||
STRV_FOREACH(j, l + NDISC_DNSSL_MAX)
|
||||
*j = mfree(*j);
|
||||
}
|
||||
|
||||
STRV_FOREACH(j, l) {
|
||||
_cleanup_free_ NDiscDNSSL *s = NULL;
|
||||
NDiscDNSSL *dnssl;
|
||||
@@ -742,6 +724,13 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
||||
|
||||
strcpy(NDISC_DNSSL_DOMAIN(s), *j);
|
||||
|
||||
if (lifetime_usec == 0) {
|
||||
/* The entry is outdated. */
|
||||
free(set_remove(link->ndisc_dnssl, s));
|
||||
updated = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
dnssl = set_get(link->ndisc_dnssl, s);
|
||||
if (dnssl) {
|
||||
dnssl->router = router;
|
||||
@@ -749,6 +738,13 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (set_size(link->ndisc_dnssl) >= NDISC_DNSSL_MAX) {
|
||||
if (!logged_about_too_many)
|
||||
log_link_warning(link, "Too many DNSSL records per link. Only first %u records will be used.", NDISC_DNSSL_MAX);
|
||||
logged_about_too_many = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
s->router = router;
|
||||
s->lifetime_usec = lifetime_usec;
|
||||
|
||||
@@ -814,6 +810,131 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
|
||||
}
|
||||
}
|
||||
|
||||
static int ndisc_drop_outdated(Link *link, usec_t timestamp_usec) {
|
||||
bool updated = false;
|
||||
NDiscDNSSL *dnssl;
|
||||
NDiscRDNSS *rdnss;
|
||||
Address *address;
|
||||
Route *route;
|
||||
int r = 0, k;
|
||||
|
||||
assert(link);
|
||||
|
||||
/* If an address or friends is already assigned, but not valid anymore, then refuse to update it,
|
||||
* and let's immediately remove it.
|
||||
* See RFC4862, section 5.5.3.e. But the following logic is deviated from RFC4862 by honoring all
|
||||
* valid lifetimes to improve the reaction of SLAAC to renumbering events.
|
||||
* See draft-ietf-6man-slaac-renum-02, section 4.2. */
|
||||
|
||||
SET_FOREACH(route, link->routes) {
|
||||
if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
|
||||
if (route->lifetime_usec >= timestamp_usec)
|
||||
continue; /* the route is still valid */
|
||||
|
||||
k = route_remove_and_drop(route);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC route, ignoring: %m");
|
||||
}
|
||||
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
|
||||
if (address->lifetime_valid_usec >= timestamp_usec)
|
||||
continue; /* the address is still valid */
|
||||
|
||||
k = address_remove_and_drop(address);
|
||||
if (k < 0)
|
||||
r = log_link_warning_errno(link, k, "Failed to remove outdated SLAAC address, ignoring: %m");
|
||||
}
|
||||
|
||||
SET_FOREACH(rdnss, link->ndisc_rdnss) {
|
||||
if (rdnss->lifetime_usec >= timestamp_usec)
|
||||
continue; /* the DNS server is still valid */
|
||||
|
||||
free(set_remove(link->ndisc_rdnss, rdnss));
|
||||
updated = true;
|
||||
}
|
||||
|
||||
SET_FOREACH(dnssl, link->ndisc_dnssl) {
|
||||
if (dnssl->lifetime_usec >= timestamp_usec)
|
||||
continue; /* the DNS domain is still valid */
|
||||
|
||||
free(set_remove(link->ndisc_dnssl, dnssl));
|
||||
updated = true;
|
||||
}
|
||||
|
||||
if (updated)
|
||||
link_dirty(link);
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
static int ndisc_setup_expire(Link *link);
|
||||
|
||||
static int ndisc_expire_handler(sd_event_source *s, uint64_t usec, void *userdata) {
|
||||
Link *link = ASSERT_PTR(userdata);
|
||||
usec_t now_usec;
|
||||
|
||||
assert(link->manager);
|
||||
|
||||
assert_se(sd_event_now(link->manager->event, CLOCK_BOOTTIME, &now_usec) >= 0);
|
||||
|
||||
(void) ndisc_drop_outdated(link, now_usec);
|
||||
(void) ndisc_setup_expire(link);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_setup_expire(Link *link) {
|
||||
usec_t lifetime_usec = USEC_INFINITY;
|
||||
NDiscDNSSL *dnssl;
|
||||
NDiscRDNSS *rdnss;
|
||||
Address *address;
|
||||
Route *route;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
assert(link->manager);
|
||||
|
||||
SET_FOREACH(route, link->routes) {
|
||||
if (route->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
|
||||
if (!route_exists(route))
|
||||
continue;
|
||||
|
||||
lifetime_usec = MIN(lifetime_usec, route->lifetime_usec);
|
||||
}
|
||||
|
||||
SET_FOREACH(address, link->addresses) {
|
||||
if (address->source != NETWORK_CONFIG_SOURCE_NDISC)
|
||||
continue;
|
||||
|
||||
if (!address_exists(address))
|
||||
continue;
|
||||
|
||||
lifetime_usec = MIN(lifetime_usec, address->lifetime_valid_usec);
|
||||
}
|
||||
|
||||
SET_FOREACH(rdnss, link->ndisc_rdnss)
|
||||
lifetime_usec = MIN(lifetime_usec, rdnss->lifetime_usec);
|
||||
|
||||
SET_FOREACH(dnssl, link->ndisc_dnssl)
|
||||
lifetime_usec = MIN(lifetime_usec, dnssl->lifetime_usec);
|
||||
|
||||
if (lifetime_usec == USEC_INFINITY)
|
||||
return 0;
|
||||
|
||||
r = event_reset_time(link->manager->event, &link->ndisc_expire, CLOCK_BOOTTIME,
|
||||
lifetime_usec, 0, ndisc_expire_handler, link, 0, "ndisc-expiration", true);
|
||||
if (r < 0)
|
||||
return log_link_warning_errno(link, r, "Failed to update expiration timer for ndisc: %m");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
|
||||
int r;
|
||||
|
||||
@@ -859,6 +980,7 @@ static int ndisc_start_dhcp6_client(Link *link, sd_ndisc_router *rt) {
|
||||
|
||||
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||
struct in6_addr router;
|
||||
usec_t timestamp_usec;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@@ -880,6 +1002,14 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
r = sd_ndisc_router_get_timestamp(rt, CLOCK_BOOTTIME, ×tamp_usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ndisc_drop_outdated(link, timestamp_usec);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ndisc_start_dhcp6_client(link, rt);
|
||||
if (r < 0)
|
||||
return r;
|
||||
@@ -892,6 +1022,10 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
r = ndisc_setup_expire(link);
|
||||
if (r < 0)
|
||||
return r;
|
||||
|
||||
if (link->ndisc_messages == 0)
|
||||
link->ndisc_configured = true;
|
||||
else
|
||||
@@ -1032,6 +1166,15 @@ int link_request_ndisc(Link *link) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int ndisc_stop(Link *link) {
|
||||
assert(link);
|
||||
|
||||
link->ndisc_expire = sd_event_source_disable_unref(link->ndisc_expire);
|
||||
|
||||
return sd_ndisc_stop(link->ndisc);
|
||||
}
|
||||
|
||||
|
||||
void ndisc_vacuum(Link *link) {
|
||||
NDiscRDNSS *r;
|
||||
NDiscDNSSL *d;
|
||||
|
||||
@@ -40,6 +40,7 @@ bool link_ipv6_accept_ra_enabled(Link *link);
|
||||
void network_adjust_ipv6_accept_ra(Network *network);
|
||||
|
||||
int ndisc_start(Link *link);
|
||||
int ndisc_stop(Link *link);
|
||||
void ndisc_vacuum(Link *link);
|
||||
void ndisc_flush(Link *link);
|
||||
|
||||
|
||||
@@ -781,6 +781,21 @@ int route_remove(Route *route) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int route_remove_and_drop(Route *route) {
|
||||
if (!route)
|
||||
return 0;
|
||||
|
||||
route_cancel_request(route, NULL);
|
||||
|
||||
if (route_exists(route))
|
||||
return route_remove(route);
|
||||
|
||||
if (route->state == 0)
|
||||
route_free(route);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void manager_mark_routes(Manager *manager, bool foreign, const Link *except) {
|
||||
Route *route;
|
||||
Link *link;
|
||||
@@ -1411,7 +1426,7 @@ int link_request_route(
|
||||
route_netlink_handler_t netlink_handler,
|
||||
Request **ret) {
|
||||
|
||||
Route *existing;
|
||||
Route *existing = NULL;
|
||||
int r;
|
||||
|
||||
assert(link);
|
||||
@@ -1420,7 +1435,13 @@ int link_request_route(
|
||||
assert(route->source != NETWORK_CONFIG_SOURCE_FOREIGN);
|
||||
assert(!route_needs_convert(route));
|
||||
|
||||
if (route_get(link->manager, link, route, &existing) < 0) {
|
||||
(void) route_get(link->manager, link, route, &existing);
|
||||
|
||||
if (route->lifetime_usec == 0)
|
||||
/* The requested route is outdated. Let's remove it. */
|
||||
return route_remove_and_drop(existing);
|
||||
|
||||
if (!existing) {
|
||||
_cleanup_(route_freep) Route *tmp = NULL;
|
||||
|
||||
if (consume_object)
|
||||
|
||||
@@ -85,6 +85,7 @@ int route_dup(const Route *src, Route **ret);
|
||||
|
||||
int route_configure_handler_internal(sd_netlink *rtnl, sd_netlink_message *m, Link *link, const char *error_msg);
|
||||
int route_remove(Route *route);
|
||||
int route_remove_and_drop(Route *route);
|
||||
|
||||
int route_get(Manager *manager, Link *link, const Route *in, Route **ret);
|
||||
|
||||
|
||||
@@ -36,12 +36,15 @@ typedef enum NetworkConfigState {
|
||||
NETWORK_CONFIG_STATE_REMOVING = 1 << 4, /* 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 == 0 ? 0 :
|
||||
sec == UINT32_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 usec_t sec16_to_usec(uint16_t sec, usec_t timestamp_usec) {
|
||||
return sec_to_usec(sec == UINT16_MAX ? UINT32_MAX : (uint32_t) sec, timestamp_usec);
|
||||
}
|
||||
|
||||
static inline uint32_t usec_to_sec(usec_t usec, usec_t now_usec) {
|
||||
|
||||
Reference in New Issue
Block a user