diff options
author | Lennart Poettering <lennart@poettering.net> | 2014-06-18 18:22:14 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2014-06-18 18:28:29 +0200 |
commit | 11bf3cced13c885ca215c108cb0bdb7a148520d6 (patch) | |
tree | a4b0af55dee44c786b80bcfab13e3eb0f3f84a4e /src/network/networkd-address.c | |
parent | 059f6c42b744a18d0deec0c79a9e0730ec6c1c76 (diff) |
networkd: add address pool support
When an address is configured to be all zeroes, networkd will now
automatically find a locally unused network of the right size from a
list of pre-configured pools. Currently those pools are 10.0.0.0/8,
172.16.0.0/12, 192.168.0.0/16 and fc00::/7, i.e. the network ranges for
private networks. They are compiled in, but should be configurable
eventually.
This allows applying the same configuration to a large number of
interfaces with each time a different IP range block, and management of
these IP ranges is fully automatic.
When allocating an address range from the pool it is made sure the range
is not used otherwise.
Diffstat (limited to 'src/network/networkd-address.c')
-rw-r--r-- | src/network/networkd-address.c | 66 |
1 files changed, 66 insertions, 0 deletions
diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index afd36a0dfc..ce015004de 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -228,6 +228,68 @@ int address_update(Address *address, Link *link, return 0; } +static int address_acquire(Link *link, Address *original, Address **ret) { + union in_addr_union in_addr = {}; + struct in_addr broadcast = {}; + Address *na = NULL; + int r; + + assert(link); + assert(original); + assert(ret); + + /* Something useful was configured? just use it */ + if (in_addr_null(original->family, &original->in_addr) <= 0) + return 0; + + /* The address is configured to be 0.0.0.0 or [::] by the user? + * Then let's acquire something more useful from the pool. */ + r = manager_address_pool_acquire(link->manager, original->family, original->prefixlen, &in_addr); + if (r < 0) { + log_error_link(link, "Failed to acquire address from pool: %s", strerror(-r)); + return r; + } + if (r == 0) { + log_error_link(link, "Couldn't find free address for interface, all taken."); + return -EBUSY; + } + + if (original->family == AF_INET) { + /* Pick first address in range for ourselves ...*/ + in_addr.in.s_addr = in_addr.in.s_addr | htobe32(1); + + /* .. and use last as broadcast address */ + broadcast.s_addr = in_addr.in.s_addr | htobe32(0xFFFFFFFFUL >> original->prefixlen); + } else if (original->family == AF_INET6) + in_addr.in6.s6_addr[15] |= 1; + + r = address_new_dynamic(&na); + if (r < 0) + return r; + + na->family = original->family; + na->prefixlen = original->prefixlen; + na->scope = original->scope; + na->cinfo = original->cinfo; + + if (original->label) { + na->label = strdup(original->label); + + if (!na->label) { + free(na); + return -ENOMEM; + } + } + + na->broadcast = broadcast; + na->in_addr = in_addr; + + LIST_PREPEND(addresses, link->pool_addresses, na); + + *ret = na; + return 0; +} + int address_configure(Address *address, Link *link, sd_rtnl_message_handler_t callback) { _cleanup_rtnl_message_unref_ sd_rtnl_message *req = NULL; @@ -240,6 +302,10 @@ int address_configure(Address *address, Link *link, assert(link->manager); assert(link->manager->rtnl); + r = address_acquire(link, address, &address); + if (r < 0) + return r; + r = sd_rtnl_message_new_addr(link->manager->rtnl, &req, RTM_NEWADDR, link->ifindex, address->family); if (r < 0) { |