From e133b289aa50b18fb10285fa27d2daef1ddbafde Mon Sep 17 00:00:00 2001 From: Patrik Flykt Date: Thu, 4 Jan 2018 15:11:58 +0200 Subject: [PATCH] networkd: Add hashmap to store prefixes and associated link Add a hashmap to the Manager struct that stores the association between an IPv6 prefix and the network Link it is assigned to. This is added in order to keep assigning the same prefixes with the same links even though they are delegated at different times or by different DHCPv6 clients. --- src/network/networkd-manager.c | 79 ++++++++++++++++++++++++++++++++++ src/network/networkd-manager.h | 6 +++ 2 files changed, 85 insertions(+) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index e3c514c8044..9d9d96ec8f1 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -1234,6 +1234,77 @@ static int manager_dirty_handler(sd_event_source *s, void *userdata) { return 1; } +Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr) { + assert_return(m, NULL); + assert_return(m->dhcp6_prefixes, NULL); + assert_return(addr, NULL); + + return hashmap_get(m->dhcp6_prefixes, addr); +} + +int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link) { + assert_return(m, -EINVAL); + assert_return(m->dhcp6_prefixes, -ENODATA); + assert_return(addr, -EINVAL); + + return hashmap_put(m->dhcp6_prefixes, addr, link); +} + +int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr) { + Link *l; + + assert_return(m, -EINVAL); + assert_return(m->dhcp6_prefixes, -ENODATA); + assert_return(addr, -EINVAL); + + l = hashmap_remove(m->dhcp6_prefixes, addr); + if (!l) + return -EINVAL; + + (void) sd_radv_remove_prefix(l->radv, addr, 64); + + return 0; +} + +int manager_dhcp6_prefix_remove_all(Manager *m, Link *link) { + Iterator i; + Link *l; + struct in6_addr *addr; + + assert_return(m, -EINVAL); + assert_return(l, -EINVAL); + + HASHMAP_FOREACH_KEY(l, addr, m->dhcp6_prefixes, i) { + if (l != link) + continue; + + (void) sd_radv_remove_prefix(l->radv, addr, 64); + + hashmap_remove(m->dhcp6_prefixes, addr); + } + + return 0; +} + +static void dhcp6_prefixes_hash_func(const void *p, struct siphash *state) { + const struct in6_addr *addr = p; + + assert(p); + + siphash24_compress(addr, sizeof(*addr), state); +} + +static int dhcp6_prefixes_compare_func(const void *_a, const void *_b) { + const struct in6_addr *a = _a, *b = _b; + + return memcmp(&a, &b, sizeof(*a)); +} + +static const struct hash_ops dhcp6_prefixes_hash_ops = { + .hash = dhcp6_prefixes_hash_func, + .compare = dhcp6_prefixes_compare_func, +}; + int manager_new(Manager **ret, sd_event *event) { _cleanup_manager_free_ Manager *m = NULL; int r; @@ -1270,6 +1341,10 @@ int manager_new(Manager **ret, sd_event *event) { if (r < 0) return r; + m->dhcp6_prefixes = hashmap_new(&dhcp6_prefixes_hash_ops); + if (!m->dhcp6_prefixes) + return -ENOMEM; + m->duid.type = DUID_TYPE_EN; (void) routing_policy_load_rules(m->state_file, &m->rules_saved); @@ -1294,6 +1369,10 @@ void manager_free(Manager *m) { while ((network = m->networks)) network_free(network); + while ((link = hashmap_first(m->dhcp6_prefixes))) + link_unref(link); + hashmap_free(m->dhcp6_prefixes); + while ((link = hashmap_first(m->links))) link_unref(link); hashmap_free(m->links); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 186cb418911..c46914f78d6 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -58,6 +58,7 @@ struct Manager { Hashmap *links; Hashmap *netdevs; Hashmap *networks_by_name; + Hashmap *dhcp6_prefixes; LIST_HEAD(Network, networks); LIST_HEAD(AddressPool, address_pools); @@ -109,5 +110,10 @@ Link* manager_find_uplink(Manager *m, Link *exclude); int manager_set_hostname(Manager *m, const char *hostname); int manager_set_timezone(Manager *m, const char *timezone); +Link *manager_dhcp6_prefix_get(Manager *m, struct in6_addr *addr); +int manager_dhcp6_prefix_add(Manager *m, struct in6_addr *addr, Link *link); +int manager_dhcp6_prefix_remove(Manager *m, struct in6_addr *addr); +int manager_dhcp6_prefix_remove_all(Manager *m, Link *link); + DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_free); #define _cleanup_manager_free_ _cleanup_(manager_freep)