assert(address);
assert(ret);
+ r = address_acquire_from_dhcp_server_leases_file(link, address, ret);
+ if (r != -ENOENT)
+ return r;
+
r = address_pool_acquire(link->manager, address->family, address->prefixlen, &a);
if (r < 0)
return r;
bool scope_set:1;
bool ip_masquerade_done:1;
bool requested_as_null:1;
+ bool used_by_dhcp_server:1;
/* duplicate_address_detection is only used by static or IPv4 dynamic addresses.
* To control DAD for IPv6 dynamic addresses, set IFA_F_NODAD to flags. */
#include "sd-dhcp-server.h"
#include "dhcp-protocol.h"
+#include "dhcp-server-lease-internal.h"
#include "fd-util.h"
#include "fileio.h"
#include "network-common.h"
/* TODO: check if the prefix length is small enough for the pool. */
network->dhcp_server_address = address;
+ address->used_by_dhcp_server = true;
break;
}
if (!network->dhcp_server_address) {
a->prefixlen = network->dhcp_server_address_prefixlen;
a->in_addr.in = network->dhcp_server_address_in_addr;
a->requested_as_null = !in4_addr_is_set(&network->dhcp_server_address_in_addr);
+ a->used_by_dhcp_server = true;
r = address_section_verify(a);
if (r < 0)
return 0;
}
+int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret) {
+ struct in_addr a;
+ uint8_t prefixlen;
+ int r;
+
+ assert(link);
+ assert(link->manager);
+ assert(address);
+ assert(ret);
+
+ /* If the DHCP server address is configured as a null address, reuse the server address of the
+ * previous instance. */
+ if (address->family != AF_INET)
+ return -ENOENT;
+
+ if (!address->used_by_dhcp_server)
+ return -ENOENT;
+
+ if (!link_dhcp4_server_enabled(link))
+ return -ENOENT;
+
+ if (link->manager->persistent_storage_fd < 0)
+ return -EBUSY; /* The persistent storage is not ready, try later again. */
+
+ _cleanup_free_ char *lease_file = path_join("dhcp-server-lease", link->ifname);
+ if (!lease_file)
+ return -ENOMEM;
+
+ r = dhcp_server_leases_file_get_server_address(
+ link->manager->persistent_storage_fd,
+ lease_file,
+ &a,
+ &prefixlen);
+ if (r < 0)
+ return r;
+
+ if (prefixlen != address->prefixlen)
+ return -ENOENT;
+
+ ret->in = a;
+ return 0;
+}
+
int link_start_dhcp4_server(Link *link) {
int r;
#pragma once
#include "conf-parser.h"
+#include "in-addr-util.h"
#include "set.h"
+typedef struct Address Address;
typedef struct Link Link;
typedef struct Manager Manager;
typedef struct Network Network;
int network_adjust_dhcp_server(Network *network, Set **addresses);
-
+int address_acquire_from_dhcp_server_leases_file(Link *link, const Address *address, union in_addr_union *ret);
int link_request_dhcp_server(Link *link);
int link_start_dhcp4_server(Link *link);
output = networkctl_status('veth-peer')
self.assertIn(f'Offered DHCP leases: {client_address}', output)
+ # Check if the same addresses are used even if the service is restarted.
+ restart_networkd()
+ self.wait_online('veth99:routable', 'veth-peer:routable')
+
+ output = check_output('ip -4 address show dev veth-peer')
+ print(output)
+ self.assertIn(f'{server_address}', output)
+
+ output = check_output('ip -4 address show dev veth99')
+ print(output)
+ self.assertIn(f'{client_address}', output)
+
+ output = networkctl_status('veth99')
+ print(output)
+ self.assertRegex(output, rf'Address: {client_address} \(DHCP4 via {server_address}\)')
+ self.assertIn(f'Gateway: {server_address}', output)
+ self.assertIn(f'DNS: {server_address}', output)
+ self.assertIn(f'NTP: {server_address}', output)
+
+ output = networkctl_status('veth-peer')
+ self.assertIn(f'Offered DHCP leases: {client_address}', output)
+
def test_dhcp_server_with_uplink(self):
copy_network_unit('25-veth.netdev', '25-dhcp-client.network', '25-dhcp-server-downstream.network',
'12-dummy.netdev', '25-dhcp-server-uplink.network')