Compare commits

..

6 Commits

Author SHA1 Message Date
Zbigniew Jędrzejewski-Szmek 8195283265
Merge pull request #16725 from yuwata/network-fix-ndisc-multiple-routers
network: fix NDisc behavior when multiple routers exist
2020-09-08 08:16:33 +02:00
Michal Sekletár 332d387f47 core: introduce support for setting NUMAMask= to special "all" value
Fixes #14113
2020-09-08 08:16:03 +02:00
Yu Watanabe 50550722e3 network: fix NDisc handling for the case when multiple routers exist
69203fba70 does not consider the case that
multiple routers exist, and causes #16719.

Fixes #16719.
2020-09-08 02:30:04 +09:00
Yu Watanabe 501b09dbf2 network: expose route_{hash,compare}_func() 2020-09-08 02:30:04 +09:00
Yu Watanabe 99a2878457 network: expose address_{hash,compare}_func() 2020-09-08 02:30:04 +09:00
Yu Watanabe badd49288d util: expose in6_addr_{hash,compare}_func() 2020-09-08 02:30:04 +09:00
17 changed files with 437 additions and 101 deletions

View File

@ -1042,7 +1042,8 @@ CapabilityBoundingSet=~CAP_B CAP_C</programlisting>
<listitem><para>Controls the NUMA node list which will be applied alongside with selected NUMA policy. <listitem><para>Controls the NUMA node list which will be applied alongside with selected NUMA policy.
Takes a list of NUMA nodes and has the same syntax as a list of CPUs for <varname>CPUAffinity=</varname> Takes a list of NUMA nodes and has the same syntax as a list of CPUs for <varname>CPUAffinity=</varname>
option. Note that the list of NUMA nodes is not required for <option>default</option> and <option>local</option> option or special "all" value which will include all available NUMA nodes in the mask. Note that the list
of NUMA nodes is not required for <option>default</option> and <option>local</option>
policies and for <option>preferred</option> policy we expect a single NUMA node.</para></listitem> policies and for <option>preferred</option> policy we expect a single NUMA node.</para></listitem>
</varlistentry> </varlistentry>

View File

@ -755,13 +755,13 @@ static int in_addr_data_compare_func(const struct in_addr_data *x, const struct
DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func); DEFINE_HASH_OPS(in_addr_data_hash_ops, struct in_addr_data, in_addr_data_hash_func, in_addr_data_compare_func);
static void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) { void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state) {
assert(addr); assert(addr);
siphash24_compress(addr, sizeof(*addr), state); siphash24_compress(addr, sizeof(*addr), state);
} }
static int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) { int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b) {
return memcmp(a, b, sizeof(*a)); return memcmp(a, b, sizeof(*a));
} }

View File

@ -80,5 +80,8 @@ static inline size_t FAMILY_ADDRESS_SIZE(int family) {
* See also oss-fuzz#11344. */ * See also oss-fuzz#11344. */
#define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} }) #define IN_ADDR_NULL ((union in_addr_union) { .in6 = {} })
void in6_addr_hash_func(const struct in6_addr *addr, struct siphash *state);
int in6_addr_compare_func(const struct in6_addr *a, const struct in6_addr *b);
extern const struct hash_ops in_addr_data_hash_ops; extern const struct hash_ops in_addr_data_hash_ops;
extern const struct hash_ops in6_addr_hash_ops; extern const struct hash_ops in6_addr_hash_ops;

View File

@ -1370,11 +1370,19 @@ int config_parse_numa_mask(const char *unit,
assert(rvalue); assert(rvalue);
assert(data); assert(data);
if (streq(rvalue, "all")) {
r = numa_mask_add_all(&p->nodes);
if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to create NUMA mask representing \"all\" NUMA nodes, ignoring: %m");
return 0;
}
} else {
r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue); r = parse_cpu_set_extend(rvalue, &p->nodes, true, unit, filename, line, lvalue);
if (r < 0) { if (r < 0) {
log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue); log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse NUMA node mask, ignoring: %s", rvalue);
return 0; return 0;
} }
}
return r; return r;
} }

View File

@ -10,6 +10,7 @@
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-address.h" #include "networkd-address.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "parse-util.h" #include "parse-util.h"
#include "set.h" #include "set.h"
#include "socket-util.h" #include "socket-util.h"
@ -123,6 +124,9 @@ void address_free(Address *address) {
} }
if (address->link && !address->acd) { if (address->link && !address->acd) {
NDiscAddress *n;
Iterator i;
set_remove(address->link->addresses, address); set_remove(address->link->addresses, address);
set_remove(address->link->addresses_foreign, address); set_remove(address->link->addresses_foreign, address);
set_remove(address->link->static_addresses, address); set_remove(address->link->static_addresses, address);
@ -134,8 +138,9 @@ void address_free(Address *address) {
set_remove(address->link->dhcp6_addresses_old, address); set_remove(address->link->dhcp6_addresses_old, address);
set_remove(address->link->dhcp6_pd_addresses, address); set_remove(address->link->dhcp6_pd_addresses, address);
set_remove(address->link->dhcp6_pd_addresses_old, address); set_remove(address->link->dhcp6_pd_addresses_old, address);
set_remove(address->link->ndisc_addresses, address); SET_FOREACH(n, address->link->ndisc_addresses, i)
set_remove(address->link->ndisc_addresses_old, address); if (n->address == address)
free(set_remove(address->link->ndisc_addresses, n));
if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address)) if (in_addr_equal(AF_INET6, &address->in_addr, (const union in_addr_union *) &address->link->ipv6ll_address))
memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr)); memzero(&address->link->ipv6ll_address, sizeof(struct in6_addr));
@ -162,7 +167,7 @@ static uint32_t address_prefix(const Address *a) {
return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen); return be32toh(a->in_addr.in.s_addr) >> (32 - a->prefixlen);
} }
static void address_hash_func(const Address *a, struct siphash *state) { void address_hash_func(const Address *a, struct siphash *state) {
assert(a); assert(a);
siphash24_compress(&a->family, sizeof(a->family), state); siphash24_compress(&a->family, sizeof(a->family), state);
@ -187,7 +192,7 @@ static void address_hash_func(const Address *a, struct siphash *state) {
} }
} }
static int address_compare_func(const Address *a1, const Address *a2) { int address_compare_func(const Address *a1, const Address *a2) {
int r; int r;
r = CMP(a1->family, a2->family); r = CMP(a1->family, a2->family);

View File

@ -75,6 +75,8 @@ int generate_ipv6_eui_64_address(Link *link, struct in6_addr *ret);
DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free); DEFINE_NETWORK_SECTION_FUNCTIONS(Address, address_free);
void address_hash_func(const Address *a, struct siphash *state);
int address_compare_func(const Address *a1, const Address *a2);
extern const struct hash_ops address_hash_ops; extern const struct hash_ops address_hash_ops;
CONFIG_PARSER_PROTOTYPE(config_parse_address); CONFIG_PARSER_PROTOTYPE(config_parse_address);

View File

@ -720,7 +720,6 @@ static Link *link_free(Link *link) {
link->dhcp6_pd_routes = set_free(link->dhcp6_pd_routes); link->dhcp6_pd_routes = set_free(link->dhcp6_pd_routes);
link->dhcp6_pd_routes_old = set_free(link->dhcp6_pd_routes_old); link->dhcp6_pd_routes_old = set_free(link->dhcp6_pd_routes_old);
link->ndisc_routes = set_free(link->ndisc_routes); link->ndisc_routes = set_free(link->ndisc_routes);
link->ndisc_routes_old = set_free(link->ndisc_routes_old);
link->nexthops = set_free(link->nexthops); link->nexthops = set_free(link->nexthops);
link->nexthops_foreign = set_free(link->nexthops_foreign); link->nexthops_foreign = set_free(link->nexthops_foreign);
@ -736,7 +735,6 @@ static Link *link_free(Link *link) {
link->dhcp6_pd_addresses = set_free(link->dhcp6_pd_addresses); link->dhcp6_pd_addresses = set_free(link->dhcp6_pd_addresses);
link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old); link->dhcp6_pd_addresses_old = set_free(link->dhcp6_pd_addresses_old);
link->ndisc_addresses = set_free(link->ndisc_addresses); link->ndisc_addresses = set_free(link->ndisc_addresses);
link->ndisc_addresses_old = set_free(link->ndisc_addresses_old);
while ((address = link->pool_addresses)) { while ((address = link->pool_addresses)) {
LIST_REMOVE(addresses, link->pool_addresses, address); LIST_REMOVE(addresses, link->pool_addresses, address);
@ -1163,6 +1161,8 @@ void link_check_ready(Link *link) {
} }
if (link_has_carrier(link) || !link->network->configure_without_carrier) { if (link_has_carrier(link) || !link->network->configure_without_carrier) {
bool has_ndisc_address = false;
NDiscAddress *n;
if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) { if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_IPV4) && !link->ipv4ll_address_configured) {
log_link_debug(link, "%s(): IPv4LL is not configured.", __func__); log_link_debug(link, "%s(): IPv4LL is not configured.", __func__);
@ -1175,8 +1175,14 @@ void link_check_ready(Link *link) {
return; return;
} }
SET_FOREACH(n, link->ndisc_addresses, i)
if (!n->marked) {
has_ndisc_address = true;
break;
}
if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) && if ((link_dhcp4_enabled(link) || link_dhcp6_enabled(link)) &&
!link->dhcp_address && set_isempty(link->dhcp6_addresses) && set_isempty(link->ndisc_addresses) && !link->dhcp_address && set_isempty(link->dhcp6_addresses) && !has_ndisc_address &&
!(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) { !(link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4) && link->ipv4ll_address_configured)) {
log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__); log_link_debug(link, "%s(): DHCP4 or DHCP6 is enabled but no dynamic address is assigned yet.", __func__);
return; return;

View File

@ -132,8 +132,8 @@ typedef struct Link {
sd_ndisc *ndisc; sd_ndisc *ndisc;
Set *ndisc_rdnss; Set *ndisc_rdnss;
Set *ndisc_dnssl; Set *ndisc_dnssl;
Set *ndisc_addresses, *ndisc_addresses_old; Set *ndisc_addresses;
Set *ndisc_routes, *ndisc_routes_old; Set *ndisc_routes;
unsigned ndisc_addresses_messages; unsigned ndisc_addresses_messages;
unsigned ndisc_routes_messages; unsigned ndisc_routes_messages;
bool ndisc_addresses_configured:1; bool ndisc_addresses_configured:1;

View File

@ -35,79 +35,218 @@
#define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e) #define NDISC_APP_ID SD_ID128_MAKE(13,ac,81,a7,d5,3f,49,78,92,79,5d,0c,29,3a,bc,7e)
static int ndisc_remove_old(Link *link, bool force); static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force);
static int ndisc_address_callback(Address *address) { static int ndisc_address_callback(Address *address) {
Address *a; struct in6_addr router = {};
NDiscAddress *n;
Iterator i; Iterator i;
assert(address); assert(address);
assert(address->link); assert(address->link);
/* Make this called only once */ SET_FOREACH(n, address->link->ndisc_addresses, i)
SET_FOREACH(a, address->link->ndisc_addresses, i) if (n->address == address) {
a->callback = NULL; router = n->router;
break;
return ndisc_remove_old(address->link, true);
} }
static int ndisc_remove_old(Link *link, bool force) { if (IN6_IS_ADDR_UNSPECIFIED(&router)) {
Address *address; _cleanup_free_ char *buf = NULL;
Route *route;
(void) in_addr_to_string(address->family, &address->in_addr, &buf);
log_link_debug(address->link, "%s is called for %s/%u, but it is already removed, ignoring.",
__func__, strna(buf), address->prefixlen);
return 0;
}
/* Make this called only once */
SET_FOREACH(n, address->link->ndisc_addresses, i)
if (IN6_ARE_ADDR_EQUAL(&n->router, &router))
n->address->callback = NULL;
return ndisc_remove_old_one(address->link, &router, true);
}
static int ndisc_remove_old_one(Link *link, const struct in6_addr *router, bool force) {
NDiscAddress *na;
NDiscRoute *nr;
NDiscDNSSL *dnssl; NDiscDNSSL *dnssl;
NDiscRDNSS *rdnss; NDiscRDNSS *rdnss;
Iterator i; Iterator i;
int k, r = 0; int k, r = 0;
assert(link); assert(link);
assert(router);
if (!force) { if (!force) {
bool set_callback = !set_isempty(link->ndisc_addresses); bool set_callback = false;
if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured) if (!link->ndisc_addresses_configured || !link->ndisc_routes_configured)
return 0; return 0;
SET_FOREACH(address, link->ndisc_addresses, i) SET_FOREACH(na, link->ndisc_addresses, i)
if (address_is_ready(address)) { if (!na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
set_callback = true;
break;
}
if (set_callback)
SET_FOREACH(na, link->ndisc_addresses, i)
if (!na->marked && address_is_ready(na->address)) {
set_callback = false; set_callback = false;
break; break;
} }
if (set_callback) { if (set_callback) {
SET_FOREACH(address, link->ndisc_addresses, i) SET_FOREACH(na, link->ndisc_addresses, i)
address->callback = ndisc_address_callback; if (!na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router))
na->address->callback = ndisc_address_callback;
if (DEBUG_LOGGING) {
_cleanup_free_ char *buf = NULL;
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) router, &buf);
log_link_debug(link, "No SLAAC address obtained from %s is ready. "
"The old NDisc information will be removed later.",
strna(buf));
}
return 0; return 0;
} }
} }
if (!set_isempty(link->ndisc_addresses_old) || !set_isempty(link->ndisc_routes_old)) if (DEBUG_LOGGING) {
log_link_debug(link, "Removing old NDisc addresses and routes."); _cleanup_free_ char *buf = NULL;
(void) in_addr_to_string(AF_INET6, (union in_addr_union *) router, &buf);
log_link_debug(link, "Removing old NDisc information obtained from %s.", strna(buf));
}
link_dirty(link); link_dirty(link);
SET_FOREACH(address, link->ndisc_addresses_old, i) { SET_FOREACH(na, link->ndisc_addresses, i)
k = address_remove(address, link, NULL); if (na->marked && IN6_ARE_ADDR_EQUAL(&na->router, router)) {
k = address_remove(na->address, link, NULL);
if (k < 0) if (k < 0)
r = k; r = k;
} }
SET_FOREACH(route, link->ndisc_routes_old, i) { SET_FOREACH(nr, link->ndisc_routes, i)
k = route_remove(route, link, NULL); if (nr->marked && IN6_ARE_ADDR_EQUAL(&nr->router, router)) {
k = route_remove(nr->route, link, NULL);
if (k < 0) if (k < 0)
r = k; r = k;
} }
SET_FOREACH(rdnss, link->ndisc_rdnss, i) SET_FOREACH(rdnss, link->ndisc_rdnss, i)
if (rdnss->marked) if (rdnss->marked && IN6_ARE_ADDR_EQUAL(&rdnss->router, router))
free(set_remove(link->ndisc_rdnss, rdnss)); free(set_remove(link->ndisc_rdnss, rdnss));
SET_FOREACH(dnssl, link->ndisc_dnssl, i) SET_FOREACH(dnssl, link->ndisc_dnssl, i)
if (dnssl->marked) if (dnssl->marked && IN6_ARE_ADDR_EQUAL(&dnssl->router, router))
free(set_remove(link->ndisc_dnssl, dnssl)); free(set_remove(link->ndisc_dnssl, dnssl));
return r; return r;
} }
static int ndisc_remove_old(Link *link) {
_cleanup_set_free_free_ Set *routers = NULL;
_cleanup_free_ struct in6_addr *router = NULL;
struct in6_addr *a;
NDiscAddress *na;
NDiscRoute *nr;
NDiscDNSSL *dnssl;
NDiscRDNSS *rdnss;
Iterator i;
int k, r;
assert(link);
routers = set_new(&in6_addr_hash_ops);
if (!routers)
return -ENOMEM;
SET_FOREACH(na, link->ndisc_addresses, i)
if (!set_contains(routers, &na->router)) {
router = newdup(struct in6_addr, &na->router, 1);
if (!router)
return -ENOMEM;
r = set_put(routers, router);
if (r < 0)
return r;
assert(r > 0);
TAKE_PTR(router);
}
SET_FOREACH(nr, link->ndisc_routes, i)
if (!set_contains(routers, &nr->router)) {
router = newdup(struct in6_addr, &nr->router, 1);
if (!router)
return -ENOMEM;
r = set_put(routers, router);
if (r < 0)
return r;
assert(r > 0);
TAKE_PTR(router);
}
SET_FOREACH(rdnss, link->ndisc_rdnss, i)
if (!set_contains(routers, &rdnss->router)) {
router = newdup(struct in6_addr, &rdnss->router, 1);
if (!router)
return -ENOMEM;
r = set_put(routers, router);
if (r < 0)
return r;
assert(r > 0);
TAKE_PTR(router);
}
SET_FOREACH(dnssl, link->ndisc_dnssl, i)
if (!set_contains(routers, &dnssl->router)) {
router = newdup(struct in6_addr, &dnssl->router, 1);
if (!router)
return -ENOMEM;
r = set_put(routers, router);
if (r < 0)
return r;
assert(r > 0);
TAKE_PTR(router);
}
r = 0;
SET_FOREACH(a, routers, i) {
k = ndisc_remove_old_one(link, a, false);
if (k < 0)
r = k;
}
return r;
}
static void ndisc_route_hash_func(const NDiscRoute *x, struct siphash *state) {
route_hash_func(x->route, state);
}
static int ndisc_route_compare_func(const NDiscRoute *a, const NDiscRoute *b) {
return route_compare_func(a->route, b->route);
}
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ndisc_route_hash_ops,
NDiscRoute,
ndisc_route_hash_func,
ndisc_route_compare_func,
free);
static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
@ -130,7 +269,7 @@ static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
log_link_debug(link, "NDisc routes set."); log_link_debug(link, "NDisc routes set.");
link->ndisc_routes_configured = true; link->ndisc_routes_configured = true;
r = ndisc_remove_old(link, false); r = ndisc_remove_old(link);
if (r < 0) { if (r < 0) {
link_enter_failed(link); link_enter_failed(link);
return 1; return 1;
@ -142,6 +281,67 @@ static int ndisc_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *li
return 1; return 1;
} }
static int ndisc_route_configure(Route *route, Link *link, sd_ndisc_router *rt) {
_cleanup_free_ NDiscRoute *nr = NULL;
NDiscRoute *nr_exist;
struct in6_addr router;
Route *ret;
int r;
assert(route);
assert(link);
assert(rt);
r = route_configure(route, link, ndisc_route_handler, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
link->ndisc_routes_messages++;
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
nr = new(NDiscRoute, 1);
if (!nr)
return log_oom();
*nr = (NDiscRoute) {
.router = router,
.route = ret,
};
nr_exist = set_get(link->ndisc_routes, nr);
if (nr_exist) {
nr_exist->marked = false;
nr_exist->router = router;
return 0;
}
r = set_ensure_put(&link->ndisc_routes, &ndisc_route_hash_ops, nr);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC route: %m");
assert(r > 0);
TAKE_PTR(nr);
return 0;
}
static void ndisc_address_hash_func(const NDiscAddress *x, struct siphash *state) {
address_hash_func(x->address, state);
}
static int ndisc_address_compare_func(const NDiscAddress *a, const NDiscAddress *b) {
return address_compare_func(a->address, b->address);
}
DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
ndisc_address_hash_ops,
NDiscAddress,
ndisc_address_hash_func,
ndisc_address_compare_func,
free);
static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
int r; int r;
@ -165,7 +365,7 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
log_link_debug(link, "NDisc SLAAC addresses set."); log_link_debug(link, "NDisc SLAAC addresses set.");
link->ndisc_addresses_configured = true; link->ndisc_addresses_configured = true;
r = ndisc_remove_old(link, false); r = ndisc_remove_old(link);
if (r < 0) { if (r < 0) {
link_enter_failed(link); link_enter_failed(link);
return 1; return 1;
@ -181,34 +381,16 @@ static int ndisc_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *
return 1; return 1;
} }
static int ndisc_route_configure(Route *route, Link *link) { static int ndisc_address_configure(Address *address, Link *link, sd_ndisc_router *rt) {
Route *ret; _cleanup_free_ NDiscAddress *na = NULL;
int r; NDiscAddress *na_exist;
struct in6_addr router;
assert(route);
assert(link);
r = route_configure(route, link, ndisc_route_handler, &ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set NDisc route: %m");
link->ndisc_routes_messages++;
r = set_ensure_put(&link->ndisc_routes, &route_hash_ops, ret);
if (r < 0)
return log_link_error_errno(link, r, "Failed to store NDisc route: %m");
(void) set_remove(link->ndisc_routes_old, ret);
return 0;
}
static int ndisc_address_configure(Address *address, Link *link) {
Address *ret; Address *ret;
int r; int r;
assert(address); assert(address);
assert(link); assert(link);
assert(rt);
r = address_configure(address, link, ndisc_address_handler, true, &ret); r = address_configure(address, link, ndisc_address_handler, true, &ret);
if (r < 0) if (r < 0)
@ -216,11 +398,31 @@ static int ndisc_address_configure(Address *address, Link *link) {
link->ndisc_addresses_messages++; link->ndisc_addresses_messages++;
r = set_ensure_put(&link->ndisc_addresses, &address_hash_ops, ret); r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
na = new(NDiscAddress, 1);
if (!na)
return log_oom();
*na = (NDiscAddress) {
.router = router,
.address = ret,
};
na_exist = set_get(link->ndisc_addresses, na);
if (na_exist) {
na_exist->marked = false;
na_exist->router = router;
return 0;
}
r = set_ensure_put(&link->ndisc_addresses, &ndisc_address_hash_ops, na);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m"); return log_link_error_errno(link, r, "Failed to store NDisc SLAAC address: %m");
assert(r > 0);
(void) set_remove(link->ndisc_addresses_old, ret); TAKE_PTR(na);
return 0; return 0;
} }
@ -286,7 +488,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route->lifetime = time_now + lifetime * USEC_PER_SEC; route->lifetime = time_now + lifetime * USEC_PER_SEC;
route->mtu = mtu; route->mtu = mtu;
r = ndisc_route_configure(route, link); r = ndisc_route_configure(route, link, rt);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set default route: %m"); return log_link_error_errno(link, r, "Could not set default route: %m");
@ -300,7 +502,7 @@ static int ndisc_router_process_default(Link *link, sd_ndisc_router *rt) {
route_gw->gw = gateway; route_gw->gw = gateway;
r = ndisc_route_configure(route_gw, link); r = ndisc_route_configure(route_gw, link, rt);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set gateway: %m"); return log_link_error_errno(link, r, "Could not set gateway: %m");
} }
@ -514,7 +716,7 @@ static int ndisc_router_process_autonomous_prefix(Link *link, sd_ndisc_router *r
address->in_addr.in6 = *a; address->in_addr.in6 = *a;
r = ndisc_address_configure(address, link); r = ndisc_address_configure(address, link, rt);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set SLAAC address: %m"); return log_link_error_errno(link, r, "Could not set SLAAC address: %m");
} }
@ -560,7 +762,7 @@ static int ndisc_router_process_onlink_prefix(Link *link, sd_ndisc_router *rt) {
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get prefix address: %m"); return log_link_error_errno(link, r, "Failed to get prefix address: %m");
r = ndisc_route_configure(route, link); r = ndisc_route_configure(route, link, rt);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set prefix route: %m");; return log_link_error_errno(link, r, "Could not set prefix route: %m");;
@ -617,7 +819,7 @@ static int ndisc_router_process_route(Link *link, sd_ndisc_router *rt) {
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get route address: %m"); return log_link_error_errno(link, r, "Failed to get route address: %m");
r = ndisc_route_configure(route, link); r = ndisc_route_configure(route, link, rt);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Could not set additional route: %m"); return log_link_error_errno(link, r, "Could not set additional route: %m");
@ -642,6 +844,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) { static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
uint32_t lifetime; uint32_t lifetime;
const struct in6_addr *a; const struct in6_addr *a;
struct in6_addr router;
NDiscRDNSS *rdnss; NDiscRDNSS *rdnss;
usec_t time_now; usec_t time_now;
Iterator i; Iterator i;
@ -650,6 +853,10 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
assert(link); assert(link);
assert(rt); assert(rt);
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get RA timestamp: %m"); return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
@ -663,6 +870,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m"); return log_link_error_errno(link, n, "Failed to get RDNSS addresses: %m");
SET_FOREACH(rdnss, link->ndisc_rdnss, i) SET_FOREACH(rdnss, link->ndisc_rdnss, i)
if (IN6_ARE_ADDR_EQUAL(&rdnss->router, &router))
rdnss->marked = true; rdnss->marked = true;
if (lifetime == 0) if (lifetime == 0)
@ -682,6 +890,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
rdnss = set_get(link->ndisc_rdnss, &d); rdnss = set_get(link->ndisc_rdnss, &d);
if (rdnss) { if (rdnss) {
rdnss->marked = false; rdnss->marked = false;
rdnss->router = router;
rdnss->valid_until = time_now + lifetime * USEC_PER_SEC; rdnss->valid_until = time_now + lifetime * USEC_PER_SEC;
continue; continue;
} }
@ -692,6 +901,7 @@ static int ndisc_router_process_rdnss(Link *link, sd_ndisc_router *rt) {
*x = (NDiscRDNSS) { *x = (NDiscRDNSS) {
.address = a[j], .address = a[j],
.router = router,
.valid_until = time_now + lifetime * USEC_PER_SEC, .valid_until = time_now + lifetime * USEC_PER_SEC,
}; };
@ -721,6 +931,7 @@ DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) { static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
_cleanup_strv_free_ char **l = NULL; _cleanup_strv_free_ char **l = NULL;
struct in6_addr router;
uint32_t lifetime; uint32_t lifetime;
usec_t time_now; usec_t time_now;
NDiscDNSSL *dnssl; NDiscDNSSL *dnssl;
@ -731,6 +942,10 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
assert(link); assert(link);
assert(rt); assert(rt);
r = sd_ndisc_router_get_address(rt, &router);
if (r < 0)
return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now); r = sd_ndisc_router_get_timestamp(rt, clock_boottime_or_monotonic(), &time_now);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to get RA timestamp: %m"); return log_link_error_errno(link, r, "Failed to get RA timestamp: %m");
@ -744,6 +959,7 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m"); return log_link_error_errno(link, r, "Failed to get DNSSL addresses: %m");
SET_FOREACH(dnssl, link->ndisc_dnssl, i) SET_FOREACH(dnssl, link->ndisc_dnssl, i)
if (IN6_ARE_ADDR_EQUAL(&dnssl->router, &router))
dnssl->marked = true; dnssl->marked = true;
if (lifetime == 0) if (lifetime == 0)
@ -767,10 +983,12 @@ static int ndisc_router_process_dnssl(Link *link, sd_ndisc_router *rt) {
dnssl = set_get(link->ndisc_dnssl, s); dnssl = set_get(link->ndisc_dnssl, s);
if (dnssl) { if (dnssl) {
dnssl->marked = false; dnssl->marked = false;
dnssl->router = router;
dnssl->valid_until = time_now + lifetime * USEC_PER_SEC; dnssl->valid_until = time_now + lifetime * USEC_PER_SEC;
continue; continue;
} }
s->router = router;
s->valid_until = time_now + lifetime * USEC_PER_SEC; s->valid_until = time_now + lifetime * USEC_PER_SEC;
r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s)); r = set_ensure_consume(&link->ndisc_dnssl, &ndisc_dnssl_hash_ops, TAKE_PTR(s));
@ -865,9 +1083,11 @@ static int ndisc_router_process_options(Link *link, sd_ndisc_router *rt) {
} }
static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) { static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
Address *address; struct in6_addr router;
Route *route;
uint64_t flags; uint64_t flags;
NDiscAddress *na;
NDiscRoute *nr;
Iterator i;
int r; int r;
assert(link); assert(link);
@ -880,17 +1100,17 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
link_dirty(link); link_dirty(link);
while ((address = set_steal_first(link->ndisc_addresses))) { r = sd_ndisc_router_get_address(rt, &router);
r = set_ensure_put(&link->ndisc_addresses_old, &address_hash_ops, address);
if (r < 0) if (r < 0)
return log_link_error_errno(link, r, "Failed to store old NDisc SLAAC address: %m"); return log_link_error_errno(link, r, "Failed to get router address from RA: %m");
}
while ((route = set_steal_first(link->ndisc_routes))) { SET_FOREACH(na, link->ndisc_addresses, i)
r = set_ensure_put(&link->ndisc_routes_old, &route_hash_ops, route); if (IN6_ARE_ADDR_EQUAL(&na->router, &router))
if (r < 0) na->marked = true;
return log_link_error_errno(link, r, "Failed to store old NDisc route: %m");
} SET_FOREACH(nr, link->ndisc_routes, i)
if (IN6_ARE_ADDR_EQUAL(&nr->router, &router))
nr->marked = true;
r = sd_ndisc_router_get_flags(rt, &flags); r = sd_ndisc_router_get_flags(rt, &flags);
if (r < 0) if (r < 0)
@ -933,7 +1153,7 @@ static int ndisc_router_handler(Link *link, sd_ndisc_router *rt) {
else else
log_link_debug(link, "Setting NDisc routes."); log_link_debug(link, "Setting NDisc routes.");
r = ndisc_remove_old(link, false); r = ndisc_remove_old(link);
if (r < 0) if (r < 0)
return r; return r;

View File

@ -2,7 +2,9 @@
#pragma once #pragma once
#include "conf-parser.h" #include "conf-parser.h"
#include "networkd-address.h"
#include "networkd-link.h" #include "networkd-link.h"
#include "networkd-route.h"
#include "time-util.h" #include "time-util.h"
typedef struct IPv6Token IPv6Token; typedef struct IPv6Token IPv6Token;
@ -23,9 +25,24 @@ typedef enum IPv6AcceptRAStartDHCP6Client {
_IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -1, _IPV6_ACCEPT_RA_START_DHCP6_CLIENT_INVALID = -1,
} IPv6AcceptRAStartDHCP6Client; } IPv6AcceptRAStartDHCP6Client;
typedef struct NDiscAddress {
/* Used when GC'ing old DNS servers when configuration changes. */
bool marked;
struct in6_addr router;
Address *address;
} NDiscAddress;
typedef struct NDiscRoute {
/* Used when GC'ing old DNS servers when configuration changes. */
bool marked;
struct in6_addr router;
Route *route;
} NDiscRoute;
typedef struct NDiscRDNSS { typedef struct NDiscRDNSS {
/* Used when GC'ing old DNS servers when configuration changes. */ /* Used when GC'ing old DNS servers when configuration changes. */
bool marked; bool marked;
struct in6_addr router;
usec_t valid_until; usec_t valid_until;
struct in6_addr address; struct in6_addr address;
} NDiscRDNSS; } NDiscRDNSS;
@ -33,6 +50,7 @@ typedef struct NDiscRDNSS {
typedef struct NDiscDNSSL { typedef struct NDiscDNSSL {
/* Used when GC'ing old domains when configuration changes. */ /* Used when GC'ing old domains when configuration changes. */
bool marked; bool marked;
struct in6_addr router;
usec_t valid_until; usec_t valid_until;
/* The domain name follows immediately. */ /* The domain name follows immediately. */
} NDiscDNSSL; } NDiscDNSSL;

View File

@ -9,6 +9,7 @@
#include "netlink-util.h" #include "netlink-util.h"
#include "networkd-ipv4ll.h" #include "networkd-ipv4ll.h"
#include "networkd-manager.h" #include "networkd-manager.h"
#include "networkd-ndisc.h"
#include "networkd-route.h" #include "networkd-route.h"
#include "parse-util.h" #include "parse-util.h"
#include "set.h" #include "set.h"
@ -142,6 +143,9 @@ void route_free(Route *route) {
network_config_section_free(route->section); network_config_section_free(route->section);
if (route->link) { if (route->link) {
NDiscRoute *n;
Iterator i;
set_remove(route->link->routes, route); set_remove(route->link->routes, route);
set_remove(route->link->routes_foreign, route); set_remove(route->link->routes_foreign, route);
set_remove(route->link->dhcp_routes, route); set_remove(route->link->dhcp_routes, route);
@ -150,8 +154,9 @@ void route_free(Route *route) {
set_remove(route->link->dhcp6_routes_old, route); set_remove(route->link->dhcp6_routes_old, route);
set_remove(route->link->dhcp6_pd_routes, route); set_remove(route->link->dhcp6_pd_routes, route);
set_remove(route->link->dhcp6_pd_routes_old, route); set_remove(route->link->dhcp6_pd_routes_old, route);
set_remove(route->link->ndisc_routes, route); SET_FOREACH(n, route->link->ndisc_routes, i)
set_remove(route->link->ndisc_routes_old, route); if (n->route == route)
free(set_remove(route->link->ndisc_routes, n));
} }
ordered_set_free_free(route->multipath_routes); ordered_set_free_free(route->multipath_routes);
@ -161,7 +166,7 @@ void route_free(Route *route) {
free(route); free(route);
} }
static void route_hash_func(const Route *route, struct siphash *state) { void route_hash_func(const Route *route, struct siphash *state) {
assert(route); assert(route);
siphash24_compress(&route->family, sizeof(route->family), state); siphash24_compress(&route->family, sizeof(route->family), state);
@ -196,7 +201,7 @@ static void route_hash_func(const Route *route, struct siphash *state) {
} }
} }
static int route_compare_func(const Route *a, const Route *b) { int route_compare_func(const Route *a, const Route *b) {
int r; int r;
r = CMP(a->family, b->family); r = CMP(a->family, b->family);

View File

@ -62,6 +62,8 @@ struct Route {
LIST_FIELDS(Route, routes); LIST_FIELDS(Route, routes);
}; };
void route_hash_func(const Route *route, struct siphash *state);
int route_compare_func(const Route *a, const Route *b);
extern const struct hash_ops route_hash_ops; extern const struct hash_ops route_hash_ops;
int route_new(Route **ret); int route_new(Route **ret);

View File

@ -1275,9 +1275,15 @@ static int bus_append_execute_property(sd_bus_message *m, const char *field, con
_cleanup_free_ uint8_t *array = NULL; _cleanup_free_ uint8_t *array = NULL;
size_t allocated; size_t allocated;
if (eq && streq(eq, "all")) {
r = numa_mask_add_all(&nodes);
if (r < 0)
return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
} else {
r = parse_cpu_set(eq, &nodes); r = parse_cpu_set(eq, &nodes);
if (r < 0) if (r < 0)
return log_error_errno(r, "Failed to parse %s value: %s", field, eq); return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
}
r = cpu_set_to_dbus(&nodes, &array, &allocated); r = cpu_set_to_dbus(&nodes, &array, &allocated);
if (r < 0) if (r < 0)

View File

@ -105,7 +105,7 @@ int cpu_set_realloc(CPUSet *cpu_set, unsigned ncpus) {
return 0; return 0;
} }
static int cpu_set_add(CPUSet *cpu_set, unsigned cpu) { int cpu_set_add(CPUSet *cpu_set, unsigned cpu) {
int r; int r;
if (cpu >= 8192) if (cpu >= 8192)

View File

@ -20,6 +20,7 @@ static inline void cpu_set_reset(CPUSet *a) {
} }
int cpu_set_add_all(CPUSet *a, const CPUSet *b); int cpu_set_add_all(CPUSet *a, const CPUSet *b);
int cpu_set_add(CPUSet *a, unsigned cpu);
char* cpu_set_to_string(const CPUSet *a); char* cpu_set_to_string(const CPUSet *a);
char *cpu_set_to_range_string(const CPUSet *a); char *cpu_set_to_range_string(const CPUSet *a);

View File

@ -5,6 +5,8 @@
#include "alloc-util.h" #include "alloc-util.h"
#include "cpu-set-util.h" #include "cpu-set-util.h"
#include "dirent-util.h"
#include "fd-util.h"
#include "fileio.h" #include "fileio.h"
#include "macro.h" #include "macro.h"
#include "missing_syscall.h" #include "missing_syscall.h"
@ -124,6 +126,61 @@ int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *ret) {
return 0; return 0;
} }
static int numa_max_node(void) {
_cleanup_closedir_ DIR *d = NULL;
struct dirent *de;
int r, max_node = 0;
d = opendir("/sys/devices/system/node");
if (!d)
return -errno;
FOREACH_DIRENT(de, d, break) {
int node;
const char *n;
(void) dirent_ensure_type(d, de);
if (de->d_type != DT_DIR)
continue;
n = startswith(de->d_name, "node");
if (!n)
continue;
r = safe_atoi(n, &node);
if (r < 0)
continue;
if (node > max_node)
max_node = node;
}
return max_node;
}
int numa_mask_add_all(CPUSet *mask) {
int m;
assert(mask);
m = numa_max_node();
if (m < 0) {
log_debug_errno(m, "Failed to determine maximum NUMA node index, assuming 1023: %m");
m = 1023; /* CONFIG_NODES_SHIFT is set to 10 on x86_64, i.e. 1024 NUMA nodes in total */
}
for (int i = 0; i <= m; i++) {
int r;
r = cpu_set_add(mask, i);
if (r < 0)
return r;
}
return 0;
}
static const char* const mpol_table[] = { static const char* const mpol_table[] = {
[MPOL_DEFAULT] = "default", [MPOL_DEFAULT] = "default",
[MPOL_PREFERRED] = "preferred", [MPOL_PREFERRED] = "preferred",

View File

@ -29,5 +29,7 @@ static inline void numa_policy_reset(NUMAPolicy *p) {
int apply_numa_policy(const NUMAPolicy *policy); int apply_numa_policy(const NUMAPolicy *policy);
int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *set); int numa_to_cpu_set(const NUMAPolicy *policy, CPUSet *set);
int numa_mask_add_all(CPUSet *mask);
const char* mpol_to_string(int i) _const_; const char* mpol_to_string(int i) _const_;
int mpol_from_string(const char *s) _pure_; int mpol_from_string(const char *s) _pure_;