diff options
author | Richard Maw <richard.maw@codethink.co.uk> | 2017-06-09 16:18:25 +0100 |
---|---|---|
committer | Richard Maw <richard.maw@codethink.co.uk> | 2017-06-12 16:54:42 +0100 |
commit | 45a9eac9a0c85c0c76b46388a530edd335ae44af (patch) | |
tree | 17549add403c49048202acb0fcd2eddb22c0a91f /src | |
parent | c1835a427fddac41dcc780cf733b53e01721e8f2 (diff) | |
download | systemd-45a9eac9a0c85c0c76b46388a530edd335ae44af.tar.gz |
networkd: Allow DHCP servers to be re-configured on carrier gain
In normal operation this would trigger an assertion
when a DHCP server is configured every time the link goes up.
This change makes sd_dhcp_server_configure_pool idempotent
and stops the DHCP server when the link loses carrier.
In addition to this stopping the assertion being triggered,
this has the useful side-effect of allowing the link to be taken down
and then brought back up as a way to have it use DNS from an "upstream"
interface that got its DNS configuration via DHCP
after the downstream link was configured.
Diffstat (limited to 'src')
-rw-r--r-- | src/libsystemd-network/sd-dhcp-server.c | 46 | ||||
-rw-r--r-- | src/libsystemd-network/test-dhcp-server.c | 2 | ||||
-rw-r--r-- | src/network/networkd-link.c | 2 |
3 files changed, 30 insertions, 20 deletions
diff --git a/src/libsystemd-network/sd-dhcp-server.c b/src/libsystemd-network/sd-dhcp-server.c index 315cbf1ac5..5a59c377f8 100644 --- a/src/libsystemd-network/sd-dhcp-server.c +++ b/src/libsystemd-network/sd-dhcp-server.c @@ -34,6 +34,14 @@ #define DHCP_DEFAULT_LEASE_TIME_USEC USEC_PER_HOUR #define DHCP_MAX_LEASE_TIME_USEC (USEC_PER_HOUR*12) +static void dhcp_lease_free(DHCPLease *lease) { + if (!lease) + return; + + free(lease->client_id.data); + free(lease); +} + /* configures the server's address and subnet, and optionally the pool's size and offset into the subnet * the whole pool must fit into the subnet, and may not contain the first (any) nor last (broadcast) address * moreover, the server's own address may be in the pool, and is in that case reserved in order not to @@ -47,7 +55,6 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres assert_return(address, -EINVAL); assert_return(address->s_addr != INADDR_ANY, -EINVAL); assert_return(prefixlen <= 32, -ERANGE); - assert_return(server->address == INADDR_ANY, -EBUSY); assert_se(in_addr_prefixlen_to_netmask(&netmask_addr, prefixlen)); netmask = netmask_addr.s_addr; @@ -78,19 +85,28 @@ int sd_dhcp_server_configure_pool(sd_dhcp_server *server, struct in_addr *addres else size = size_max; - server->bound_leases = new0(DHCPLease*, size); - if (!server->bound_leases) - return -ENOMEM; + if (server->address != address->s_addr || server->netmask != netmask || server->pool_size != size || server->pool_offset != offset) { + DHCPLease *lease; + + free(server->bound_leases); + server->bound_leases = new0(DHCPLease*, size); + if (!server->bound_leases) + return -ENOMEM; - server->pool_offset = offset; - server->pool_size = size; + server->pool_offset = offset; + server->pool_size = size; - server->address = address->s_addr; - server->netmask = netmask; - server->subnet = address->s_addr & netmask; + server->address = address->s_addr; + server->netmask = netmask; + server->subnet = address->s_addr & netmask; - if (server_off >= offset && server_off - offset < size) - server->bound_leases[server_off - offset] = &server->invalid_lease; + if (server_off >= offset && server_off - offset < size) + server->bound_leases[server_off - offset] = &server->invalid_lease; + + /* Drop any leases associated with the old address range */ + while ((lease = hashmap_steal_first(server->leases_by_client_id))) + dhcp_lease_free(lease); + } return 0; } @@ -143,14 +159,6 @@ static const struct hash_ops client_id_hash_ops = { .compare = client_id_compare_func }; -static void dhcp_lease_free(DHCPLease *lease) { - if (!lease) - return; - - free(lease->client_id.data); - free(lease); -} - sd_dhcp_server *sd_dhcp_server_unref(sd_dhcp_server *server) { DHCPLease *lease; diff --git a/src/libsystemd-network/test-dhcp-server.c b/src/libsystemd-network/test-dhcp-server.c index e81c508c7f..26f217835f 100644 --- a/src/libsystemd-network/test-dhcp-server.c +++ b/src/libsystemd-network/test-dhcp-server.c @@ -63,7 +63,7 @@ static int test_basic(sd_event *event) { assert_se(sd_dhcp_server_configure_pool(server, &address_any, 28, 0, 0) == -EINVAL); assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 38, 0, 0) == -ERANGE); assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0); - assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) == -EBUSY); + assert_se(sd_dhcp_server_configure_pool(server, &address_lo, 8, 0, 0) >= 0); test_pool(&address_any, 1, -EINVAL); test_pool(&address_lo, 1, 0); diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index 4af61df7ff..4c57fa1793 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -3060,6 +3060,8 @@ static int link_carrier_lost(Link *link) { return r; } + (void) sd_dhcp_server_stop(link->dhcp_server); + r = link_drop_config(link); if (r < 0) return r; |