networkd: use OrderedSets instead of strvs to store lists of domains

We were already using OrderedSets in the manager object, but strvs in the
configuration parsing code. Using sets gives us better scaling when many
domains are used.

In oss-fuzz #13059 the attached reproducer takes approximately 30.5 s to be
parsed. Converting to sets makes this go down to 10s. This is not _vastly_
faster, but using sets seems like a nicer approach anyway. In particular, we
avoid the quadratic de-unification operation after each addition.
This commit is contained in:
Zbigniew Jędrzejewski-Szmek 2019-02-20 22:50:25 +01:00
parent 53ae3f6467
commit 5e2a51d588
6 changed files with 39 additions and 36 deletions

View file

@ -4083,9 +4083,7 @@ int link_save(Link *link) {
(void) sd_dhcp6_lease_get_domains(dhcp6_lease, &dhcp6_domains);
}
fputs("DOMAINS=", f);
space = false;
fputstrv(f, link->network->search_domains, NULL, &space);
ordered_set_print(f, "DOMAINS=", link->network->search_domains);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_YES) {
NDiscDNSSL *dd;
@ -4103,9 +4101,7 @@ int link_save(Link *link) {
fputc('\n', f);
fputs("ROUTE_DOMAINS=", f);
space = false;
fputstrv(f, link->network->route_domains, NULL, &space);
ordered_set_print(f, "ROUTE_DOMAINS=", link->network->route_domains);
if (link->network->dhcp_use_domains == DHCP_USE_DOMAINS_ROUTE) {
NDiscDNSSL *dd;

View file

@ -1108,11 +1108,11 @@ static int manager_save(Manager *m) {
if (r < 0)
return r;
r = ordered_set_put_strdupv(search_domains, link->network->search_domains);
r = ordered_set_put_string_set(search_domains, link->network->search_domains);
if (r < 0)
return r;
r = ordered_set_put_strdupv(route_domains, link->network->route_domains);
r = ordered_set_put_string_set(route_domains, link->network->route_domains);
if (r < 0)
return r;

View file

@ -385,11 +385,11 @@ void network_free(Network *network) {
strv_free(network->ntp);
free(network->dns);
strv_free(network->search_domains);
strv_free(network->route_domains);
ordered_set_free_free(network->search_domains);
ordered_set_free_free(network->route_domains);
strv_free(network->bind_carrier);
strv_free(network->router_search_domains);
ordered_set_free_free(network->router_search_domains);
free(network->router_dns);
netdev_unref(network->bridge);
@ -553,8 +553,8 @@ int network_apply(Network *network, Link *link) {
if (network->n_dns > 0 ||
!strv_isempty(network->ntp) ||
!strv_isempty(network->search_domains) ||
!strv_isempty(network->route_domains))
!ordered_set_isempty(network->search_domains) ||
!ordered_set_isempty(network->route_domains))
link_dirty(link);
return 0;
@ -686,8 +686,8 @@ int config_parse_domains(
assert(rvalue);
if (isempty(rvalue)) {
n->search_domains = strv_free(n->search_domains);
n->route_domains = strv_free(n->route_domains);
n->search_domains = ordered_set_free_free(n->search_domains);
n->route_domains = ordered_set_free_free(n->route_domains);
return 0;
}
@ -733,17 +733,16 @@ int config_parse_domains(
}
}
if (is_route)
r = strv_extend(&n->route_domains, domain);
else
r = strv_extend(&n->search_domains, domain);
OrderedSet **set = is_route ? &n->route_domains : &n->search_domains;
r = ordered_set_ensure_allocated(set, &string_hash_ops);
if (r < 0)
return r;
r = ordered_set_put_strdup(*set, domain);
if (r < 0)
return log_oom();
}
strv_uniq(n->route_domains);
strv_uniq(n->search_domains);
return 0;
}
@ -1218,16 +1217,17 @@ int config_parse_radv_search_domains(
log_syntax(unit, LOG_ERR, filename, line, r,
"Failed to apply IDNA to domain name '%s', ignoring: %m", w);
continue;
}
if (r > 0) {
r = strv_push(&n->router_search_domains, idna);
if (r >= 0)
idna = NULL;
} else {
r = strv_push(&n->router_search_domains, w);
if (r >= 0)
w = NULL;
}
} else if (r == 0)
/* transfer ownership to simplify subsequent operations */
idna = TAKE_PTR(w);
r = ordered_set_ensure_allocated(&n->router_search_domains, &string_hash_ops);
if (r < 0)
return r;
r = ordered_set_consume(n->router_search_domains, TAKE_PTR(idna));
if (r < 0)
return r;
}
return 0;

View file

@ -20,6 +20,7 @@
#include "networkd-route.h"
#include "networkd-routing-policy-rule.h"
#include "networkd-util.h"
#include "ordered-set.h"
#include "resolve-util.h"
#define DHCP_ROUTE_METRIC 1024
@ -173,7 +174,7 @@ struct Network {
usec_t router_dns_lifetime_usec;
struct in6_addr *router_dns;
unsigned n_router_dns;
char **router_search_domains;
OrderedSet *router_search_domains;
bool dhcp6_force_pd_other_information; /* Start DHCPv6 PD also when 'O'
RA flag is set, see RFC 7084,
WPD-4 */
@ -267,7 +268,8 @@ struct Network {
/* All kinds of DNS configuration */
struct in_addr_data *dns;
unsigned n_dns;
char **search_domains, **route_domains;
OrderedSet *search_domains, *route_domains;
int dns_default_route;
ResolveSupport llmnr;
ResolveSupport mdns;

View file

@ -391,8 +391,9 @@ static int radv_set_dns(Link *link, Link *uplink) {
}
static int radv_set_domains(Link *link, Link *uplink) {
char **search_domains;
OrderedSet *search_domains;
usec_t lifetime_usec;
_cleanup_free_ char **s = NULL; /* just free() because the strings are owned by the set */
if (!link->network->router_emit_domains)
return 0;
@ -423,9 +424,13 @@ static int radv_set_domains(Link *link, Link *uplink) {
return 0;
set_domains:
s = ordered_set_get_strv(search_domains);
if (!s)
return log_oom();
return sd_radv_set_dnssl(link->radv,
DIV_ROUND_UP(lifetime_usec, USEC_PER_SEC),
search_domains);
s);
}

Binary file not shown.