sd-dhcp-relay: reimplement DHCP relay agent and drop legacy DHCP relay mode from sd-dhcp-server (#42130)

This commit is contained in:
Daan De Meyer
2026-05-21 16:23:44 +02:00
committed by GitHub
53 changed files with 2674 additions and 470 deletions
+1
View File
@@ -43,6 +43,7 @@ systemd_networkd_extract_sources = files(
'networkd-conf.c',
'networkd-dhcp-common.c',
'networkd-dhcp-prefix-delegation.c',
'networkd-dhcp-relay.c',
'networkd-dhcp-server-bus.c',
'networkd-dhcp-server-static-lease.c',
'networkd-dhcp-server.c',
+7
View File
@@ -19,6 +19,7 @@
#include "networkd-address.h"
#include "networkd-address-pool.h"
#include "networkd-dhcp-prefix-delegation.h"
#include "networkd-dhcp-relay.h"
#include "networkd-dhcp-server.h"
#include "networkd-ipv4acd.h"
#include "networkd-link.h"
@@ -245,6 +246,9 @@ static Address* address_detach_impl(Address *address) {
if (address->network->dhcp_server_address == address)
address->network->dhcp_server_address = NULL;
if (address->network->dhcp_relay_agent_address == address)
address->network->dhcp_relay_agent_address = NULL;
address->network = NULL;
return address;
}
@@ -925,6 +929,8 @@ static int address_drop(Address *in, bool removed_by_us) {
ipv4acd_detach(link, address);
(void) link_dhcp_relay_address_dropped(link, address);
address_detach(address);
if (!removed_by_us) {
@@ -2517,5 +2523,6 @@ int network_drop_invalid_addresses(Network *network) {
if (r < 0)
return r;
network_adjust_dhcp_relay(network);
return 0;
}
+1
View File
@@ -22,6 +22,7 @@ int manager_parse_config_file(Manager *m) {
"DHCPv4\0"
"DHCPv6\0"
"DHCPServer\0"
"DHCPRelay\0"
"DHCP\0",
config_item_perf_lookup, networkd_gperf_lookup,
CONFIG_PARSE_WARN,
+380
View File
@@ -0,0 +1,380 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#include <linux/rtnetlink.h>
#include "sd-event.h"
#include "sd-id128.h"
#include "conf-parser.h"
#include "dhcp-relay-internal.h"
#include "hashmap.h"
#include "iovec-util.h"
#include "networkd-address.h"
#include "networkd-dhcp-relay.h"
#include "networkd-link.h"
#include "networkd-manager.h"
#include "networkd-network.h"
#include "networkd-queue.h"
#include "string-table.h"
#include "string-util.h" /* IWYU pragma: keep */
#define DHCP_RELAY_APP_REMOTE_ID SD_ID128_MAKE(85,bb,eb,d2,b8,56,47,0b,b0,86,4c,f3,d3,9b,c1,b5)
void network_adjust_dhcp_relay(Network *network) {
assert(network);
assert(network->manager);
if (network->dhcp_relay_interface_mode < 0)
return;
if (network->bond) {
log_warning("%s: DHCPRelay= is enabled for bond slave. Disabling DHCP relay agent.",
network->filename);
network->dhcp_relay_interface_mode = _DHCP_RELAY_INTERFACE_INVALID;
return;
}
if (network->dhcp_server) {
log_warning("%s: DHCPRelay= cannot be enabled when DHCPServer= is enabled. Disabling DHCP relay agent.",
network->filename);
network->dhcp_relay_interface_mode = _DHCP_RELAY_INTERFACE_INVALID;
return;
}
if (FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4)) {
log_warning("%s: DHCPRelay= cannot be enabled when DHCPv4 client is enabled. Disabling DHCP relay agent.",
network->filename);
network->dhcp_relay_interface_mode = _DHCP_RELAY_INTERFACE_INVALID;
return;
}
if (in4_addr_is_null(&network->manager->dhcp_relay_server_address)) {
log_warning("%s: DHCPRelay= is enabled, but [DHCPRelay] ServerAddress= in networkd.conf is not configured. Disabling DHCP relay agent.",
network->filename);
network->dhcp_relay_interface_mode = _DHCP_RELAY_INTERFACE_INVALID;
return;
}
Address *a;
ORDERED_HASHMAP_FOREACH(a, network->addresses_by_section) {
assert(!section_is_invalid(a->section));
if (a->family != AF_INET)
continue;
if (in4_addr_is_set(&a->in_addr_peer.in))
continue;
if (in4_addr_is_set(&network->dhcp_relay_agent_address_in_addr)) {
if (!in4_addr_equal(&a->in_addr.in, &network->dhcp_relay_agent_address_in_addr))
continue;
} else {
if (in4_addr_is_localhost(&a->in_addr.in))
continue;
if (in4_addr_is_link_local(&a->in_addr.in))
continue;
if (a->scope != RT_SCOPE_UNIVERSE)
continue;
}
network->dhcp_relay_agent_address = a;
break;
}
if (!network->dhcp_relay_agent_address) {
if (in4_addr_is_set(&network->dhcp_relay_agent_address_in_addr))
log_warning("%s: Configured AgentAddress=%s not found among static addresses. Disabling DHCP relay agent.",
network->filename, IN4_ADDR_TO_STRING(&network->dhcp_relay_agent_address_in_addr));
else
log_warning("%s: DHCPRelay= is enabled, but no suitable static address configured. Disabling DHCP relay agent.",
network->filename);
network->dhcp_relay_interface_mode = _DHCP_RELAY_INTERFACE_INVALID;
return;
}
}
static int manager_configure_dhcp_relay(Manager *manager) {
int r;
assert(manager);
assert(manager->event);
if (manager->dhcp_relay)
return 0;
if (in4_addr_is_null(&manager->dhcp_relay_server_address))
return -EADDRNOTAVAIL;
_cleanup_(sd_dhcp_relay_unrefp) sd_dhcp_relay *relay = NULL;
r = sd_dhcp_relay_new(&relay);
if (r < 0)
return r;
r = sd_dhcp_relay_attach_event(relay, manager->event, SD_EVENT_PRIORITY_NORMAL);
if (r < 0)
return r;
r = sd_dhcp_relay_set_server_address(relay, &manager->dhcp_relay_server_address);
if (r < 0)
return r;
if (iovec_is_set(&manager->dhcp_relay_remote_id)) {
r = sd_dhcp_relay_set_remote_id(relay, &manager->dhcp_relay_remote_id);
if (r < 0)
return r;
} else {
sd_id128_t id;
r = sd_id128_get_machine_app_specific(DHCP_RELAY_APP_REMOTE_ID, &id);
if (r < 0)
return r;
r = sd_dhcp_relay_set_remote_id(relay, &IOVEC_MAKE_STRING(SD_ID128_TO_STRING(id)));
if (r < 0)
return r;
}
r = sd_dhcp_relay_set_server_identifier_override(relay, manager->dhcp_relay_override_server_id);
if (r < 0)
return r;
r = dhcp_relay_set_extra_options(relay, &manager->dhcp_relay_extra_options);
if (r < 0)
return r;
manager->dhcp_relay = TAKE_PTR(relay);
return 0;
}
static int link_configure_dhcp_relay(Link *link) {
int r;
assert(link);
assert(link->manager);
assert(link->network);
assert(!link->dhcp_relay_interface);
assert(link->network->dhcp_relay_agent_address);
assert(link->network->dhcp_relay_interface_mode >= 0 && link->network->dhcp_relay_interface_mode < _DHCP_RELAY_INTERFACE_MAX);
r = manager_configure_dhcp_relay(link->manager);
if (r < 0)
return r;
bool upstream = link->network->dhcp_relay_interface_mode == DHCP_RELAY_INTERFACE_UPSTREAM;
_cleanup_(sd_dhcp_relay_interface_unrefp) sd_dhcp_relay_interface *interface = NULL;
r = sd_dhcp_relay_add_interface(link->manager->dhcp_relay, link->ifindex, upstream, &interface);
if (r < 0)
return r;
r = sd_dhcp_relay_interface_set_ifname(interface, link->ifname);
if (r < 0)
return r;
r = sd_dhcp_relay_interface_set_address(
interface,
&link->network->dhcp_relay_agent_address->in_addr.in,
link->network->dhcp_relay_agent_address->prefixlen);
if (r < 0)
return r;
if (upstream) {
r = sd_dhcp_relay_upstream_set_priority(interface, link->network->dhcp_relay_interface_priority);
if (r < 0)
return r;
} else {
if (in4_addr_is_set(&link->network->dhcp_relay_gateway_address))
r = sd_dhcp_relay_downstream_set_gateway_address(interface, &link->network->dhcp_relay_gateway_address);
else
r = sd_dhcp_relay_downstream_set_gateway_address(interface, &link->network->dhcp_relay_agent_address->in_addr.in);
if (r < 0)
return r;
if (iovec_is_set(&link->network->dhcp_relay_circuit_id))
r = sd_dhcp_relay_downstream_set_circuit_id(interface, &link->network->dhcp_relay_circuit_id);
else
r = sd_dhcp_relay_downstream_set_circuit_id(interface, &IOVEC_MAKE_STRING(link->ifname));
if (r < 0)
return r;
r = sd_dhcp_relay_downstream_set_virtual_subnet_selection(interface, &link->network->dhcp_relay_vss);
if (r < 0)
return r;
r = downstream_set_extra_options(interface, &link->network->dhcp_relay_extra_options);
if (r < 0)
return r;
}
link->dhcp_relay_interface = TAKE_PTR(interface);
if (link->network->dhcp_relay_interface_mode == DHCP_RELAY_INTERFACE_COMPAT &&
!link->dhcp_relay_interface_compat) {
r = sd_dhcp_relay_add_interface(
link->manager->dhcp_relay,
DHCP_RELAY_IFINDEX_UNBOUND,
/* is_upstream= */ true,
&link->dhcp_relay_interface_compat);
if (r < 0)
return r;
}
return 0;
}
static bool dhcp_relay_is_ready_to_configure(Link *link) {
assert(link);
assert(link->network);
if (!link_is_ready_to_configure(link, /* allow_unmanaged= */ false))
return false;
if (!link_has_carrier(link))
return false;
if (!link->static_addresses_configured)
return false;
Address *a;
if (address_get(link, link->network->dhcp_relay_agent_address, &a) < 0)
return false;
if (!address_is_ready(a))
return false;
return true;
}
static int dhcp_relay_process_request(Request *req, Link *link, void *userdata) {
int r;
assert(link);
if (!dhcp_relay_is_ready_to_configure(link))
return 0;
r = link_configure_dhcp_relay(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to configure DHCP relay agent: %m");
log_link_debug(link, "DHCP relay agent is configured.");
r = link_start_dhcp_relay(link);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to start DHCP relay agent: %m");
return 1;
}
int link_request_dhcp_relay(Link *link) {
int r;
assert(link);
assert(link->manager);
if (link->manager->state != MANAGER_RUNNING)
return 0;
if (!link->network)
return 0;
if (link->network->dhcp_relay_interface_mode < 0)
return 0;
if (link->dhcp_relay_interface)
return 0;
r = link_queue_request(link, REQUEST_TYPE_DHCP_RELAY, dhcp_relay_process_request, NULL);
if (r < 0)
return log_link_warning_errno(link, r, "Failed to request configuring of the DHCP relay agent: %m");
log_link_debug(link, "Requested configuring of the DHCP relay agent.");
return 0;
}
int link_start_dhcp_relay(Link *link) {
int r;
assert(link);
assert(link->manager);
if (!link->dhcp_relay_interface)
return 0; /* Not configured yet. */
if (!link_has_carrier(link))
return 0;
r = sd_dhcp_relay_interface_start(link->dhcp_relay_interface);
if (r < 0)
return r;
if (link->dhcp_relay_interface_compat) {
r = sd_dhcp_relay_interface_start(link->dhcp_relay_interface_compat);
if (r < 0)
return r;
}
log_link_debug(link, "Relaying DHCPv4 messages.");
return 0;
}
int link_dhcp_relay_address_dropped(Link *link, const Address *address) {
int r;
assert(link);
assert(link->manager);
assert(address);
/* This is called when an address is removed from the interface. */
if (link->manager->state != MANAGER_RUNNING)
return 0;
if (!link->network)
return 0;
if (!link->dhcp_relay_interface)
return 0;
if (address->family != AF_INET)
return 0;
struct in_addr a;
uint8_t prefixlen;
r = sd_dhcp_relay_interface_get_address(link->dhcp_relay_interface, &a, &prefixlen);
if (r <= 0)
return r;
if (!in4_addr_equal(&address->in_addr.in, &a))
return 0;
if (address->prefixlen != prefixlen)
return 0;
r = sd_dhcp_relay_interface_stop(link->dhcp_relay_interface);
if (r < 0)
return r;
link->dhcp_relay_interface = sd_dhcp_relay_interface_unref(link->dhcp_relay_interface);
if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
return 0;
/* The address may be reconfigured later. Let's reconfigure DHCP relay interface when the address comes back. */
return link_request_dhcp_relay(link);
}
static const char * const dhcp_relay_interface_mode_table[_DHCP_RELAY_INTERFACE_MAX] = {
[DHCP_RELAY_INTERFACE_UPSTREAM] = "upstream",
[DHCP_RELAY_INTERFACE_DOWNSTREAM] = "downstream",
};
DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_relay_interface_mode, DHCPRelayInterfaceMode);
DEFINE_CONFIG_PARSE_ENUM_WITH_DEFAULT(
config_parse_dhcp_relay_interface_mode,
dhcp_relay_interface_mode,
DHCPRelayInterfaceMode,
_DHCP_RELAY_INTERFACE_INVALID);
+20
View File
@@ -0,0 +1,20 @@
/* SPDX-License-Identifier: LGPL-2.1-or-later */
#pragma once
#include "networkd-forward.h"
typedef enum DHCPRelayInterfaceMode {
DHCP_RELAY_INTERFACE_UPSTREAM,
DHCP_RELAY_INTERFACE_DOWNSTREAM,
DHCP_RELAY_INTERFACE_COMPAT,
_DHCP_RELAY_INTERFACE_MAX,
_DHCP_RELAY_INTERFACE_INVALID = -EINVAL,
} DHCPRelayInterfaceMode;
void network_adjust_dhcp_relay(Network *network);
int link_request_dhcp_relay(Link *link);
int link_start_dhcp_relay(Link *link);
int link_dhcp_relay_address_dropped(Link *link, const Address *address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_relay_interface_mode);
+4 -13
View File
@@ -30,9 +30,6 @@ static int property_get_leases(
if (!s)
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Link %s has no DHCP server.", l->ifname);
if (sd_dhcp_server_is_in_relay_mode(s))
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Link %s has DHCP relay agent active.", l->ifname);
r = sd_bus_message_open_container(reply, 'a', "(uayayayayt)");
if (r < 0)
return r;
@@ -82,15 +79,12 @@ static int property_get_pool_size(
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Link *l = ASSERT_PTR(userdata);
sd_dhcp_server *s;
uint32_t v;
assert(reply);
s = l->dhcp_server;
v = s && !sd_dhcp_server_is_in_relay_mode(s) ? s->pool_size : UINT32_MAX;
uint32_t v = l->dhcp_server ? l->dhcp_server->pool_size : UINT32_MAX;
return sd_bus_message_append_basic(reply, 'u', &v);
}
@@ -102,15 +96,12 @@ static int property_get_pool_offset(
sd_bus_message *reply,
void *userdata,
sd_bus_error *error) {
Link *l = ASSERT_PTR(userdata);
sd_dhcp_server *s;
uint32_t v;
assert(reply);
s = l->dhcp_server;
v = s && !sd_dhcp_server_is_in_relay_mode(s) ? s->pool_offset : UINT32_MAX;
uint32_t v = l->dhcp_server ? l->dhcp_server->pool_offset : UINT32_MAX;
return sd_bus_message_append_basic(reply, 'u', &v);
}
+26 -49
View File
@@ -16,6 +16,7 @@
#include "fileio.h"
#include "hashmap.h"
#include "hostname-setup.h"
#include "iovec-util.h"
#include "network-common.h"
#include "networkd-address.h"
#include "networkd-dhcp-server.h"
@@ -66,6 +67,31 @@ int network_adjust_dhcp_server(Network *network, Set **addresses) {
return 0;
}
if (in4_addr_is_set(&network->dhcp_relay_target_address)) {
if (!in4_addr_is_set(&network->manager->dhcp_relay_server_address)) {
/* [DHCPServer] RelayTarget= in .network file is replaced with
* [DHCPRelay] ServerAddress= in networkd.conf. */
network->manager->dhcp_relay_server_address = network->dhcp_relay_target_address;
/* [DHCPServer] RelayAgentRemoteId= in .network file is replaced with
* [DHCPRelay] RemoteId= in networkd.conf. */
if (!iovec_is_set(&network->manager->dhcp_relay_remote_id)) {
iovec_done(&network->manager->dhcp_relay_remote_id);
network->manager->dhcp_relay_remote_id = TAKE_STRUCT(network->dhcp_relay_remote_id);
}
}
/* Copy [DHCPServer] ServerAddress= to [DHCPRelay] AgentAddress= if unspecified. */
if (!in4_addr_is_set(&network->dhcp_relay_agent_address_in_addr))
network->dhcp_relay_agent_address_in_addr = network->dhcp_server_address_in_addr;
/* Assume this interface acts as a downstream interface of the DHCP relay agent. Also,
* configure a catch-all upstream socket. */
network->dhcp_relay_interface_mode = DHCP_RELAY_INTERFACE_COMPAT;
network->dhcp_server = false;
return 0;
}
assert(network->dhcp_server_address_prefixlen <= 32);
if (network->dhcp_server_address_prefixlen == 0) {
@@ -160,9 +186,6 @@ static DHCPServerPersistLeases link_get_dhcp_server_persist_leases(Link *link) {
assert(link->manager);
assert(link->network);
if (in4_addr_is_set(&link->network->dhcp_server_relay_target))
return DHCP_SERVER_PERSIST_LEASES_NO; /* On relay mode. Nothing saved in the persistent storage. */
if (link->network->dhcp_server_persist_leases >= 0)
return link->network->dhcp_server_persist_leases;
@@ -571,7 +594,6 @@ static int dhcp4_server_configure(Link *link) {
DHCPStaticLease *static_lease;
Link *uplink = NULL;
Address *address;
bool bind_to_interface;
int r;
assert(link);
@@ -681,19 +703,6 @@ static int dhcp4_server_configure(Link *link) {
return log_link_error_errno(link, r, "Failed to set router address for DHCP server: %m");
}
r = sd_dhcp_server_set_relay_target(link->dhcp_server, &link->network->dhcp_server_relay_target);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set relay target for DHCP server: %m");
bind_to_interface = sd_dhcp_server_is_in_relay_mode(link->dhcp_server) ? false : link->network->dhcp_server_bind_to_interface;
r = sd_dhcp_server_set_bind_to_interface(link->dhcp_server, bind_to_interface);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set interface binding for DHCP server: %m");
r = sd_dhcp_server_set_relay_agent_information(link->dhcp_server, link->network->dhcp_server_relay_agent_circuit_id, link->network->dhcp_server_relay_agent_remote_id);
if (r < 0)
return log_link_error_errno(link, r, "Failed to set agent circuit/remote id for DHCP server: %m");
if (link->network->dhcp_server_emit_timezone) {
_cleanup_free_ char *buffer = NULL;
const char *tz = NULL;
@@ -815,38 +824,6 @@ int link_request_dhcp_server(Link *link) {
return 0;
}
int config_parse_dhcp_server_relay_agent_suboption(
const char *unit,
const char *filename,
unsigned line,
const char *section,
unsigned section_line,
const char *lvalue,
int ltype,
const char *rvalue,
void *data,
void *userdata) {
char **suboption_value = data;
assert(filename);
assert(lvalue);
assert(rvalue);
if (isempty(rvalue)) {
*suboption_value = mfree(*suboption_value);
return 0;
}
const char *p = startswith(rvalue, "string:");
if (!p) {
log_syntax(unit, LOG_WARNING, filename, line, 0,
"Failed to parse %s=%s'. Invalid format, ignoring.", lvalue, rvalue);
return 0;
}
return free_and_strdup(suboption_value, empty_to_null(p));
}
int config_parse_dhcp_server_emit(
const char *unit,
const char *filename,
-1
View File
@@ -18,7 +18,6 @@ int link_request_dhcp_server(Link *link);
int link_start_dhcp4_server(Link *link);
void manager_toggle_dhcp4_server_state(Manager *manager, bool start);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_relay_agent_suboption);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_emit);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_address);
CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_server_ipv6_only_preferred);
+4
View File
@@ -45,6 +45,10 @@ DHCPv6.UseDomains, config_parse_use_domains,
DHCPv6.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp6_duid)
DHCPv6.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp6_duid)
DHCPServer.PersistLeases, config_parse_dhcp_server_persist_leases, 0, offsetof(Manager, dhcp_server_persist_leases)
DHCPRelay.ServerAddress, config_parse_in_addr_non_null, AF_INET, offsetof(Manager, dhcp_relay_server_address)
DHCPRelay.OverrideServerIdentifier, config_parse_bool, 0, offsetof(Manager, dhcp_relay_override_server_id)
DHCPRelay.RemoteId, config_parse_dhcp_option, /* check_length= */ true, offsetof(Manager, dhcp_relay_remote_id)
DHCPRelay.ExtraOption, config_parse_dhcp_option_tlv, 0, offsetof(Manager, dhcp_relay_extra_options)
/* Deprecated */
DHCP.DUIDType, config_parse_manager_duid_type, 0, 0
DHCP.DUIDRawData, config_parse_manager_duid_rawdata, 0, 0
+1 -2
View File
@@ -855,8 +855,7 @@ int link_object_find(sd_bus *bus, const char *path, const char *interface, void
if (r < 0)
return 0;
if (streq(interface, "org.freedesktop.network1.DHCPServer") &&
(!link->dhcp_server || sd_dhcp_server_is_in_relay_mode(link->dhcp_server)))
if (streq(interface, "org.freedesktop.network1.DHCPServer") && !link->dhcp_server)
return 0;
if (streq(interface, "org.freedesktop.network1.DHCPv4Client") && !link->dhcp_client)
+28
View File
@@ -10,6 +10,7 @@
#include "sd-bus.h"
#include "sd-dhcp-client.h"
#include "sd-dhcp-relay.h"
#include "sd-dhcp-server.h"
#include "sd-dhcp6-client.h"
#include "sd-dhcp6-lease.h"
@@ -41,6 +42,7 @@
#include "networkd-bridge-mdb.h"
#include "networkd-bridge-vlan.h"
#include "networkd-dhcp-prefix-delegation.h"
#include "networkd-dhcp-relay.h"
#include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
@@ -240,6 +242,8 @@ static void link_free_engines(Link *link) {
if (!link)
return;
link->dhcp_relay_interface = sd_dhcp_relay_interface_unref(link->dhcp_relay_interface);
link->dhcp_relay_interface_compat = sd_dhcp_relay_interface_unref(link->dhcp_relay_interface_compat);
link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server);
link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client);
@@ -424,6 +428,14 @@ int link_stop_engines(Link *link, bool may_keep_dynamic) {
ndisc_flush(link);
}
r = sd_dhcp_relay_interface_stop(link->dhcp_relay_interface);
if (r < 0)
RET_GATHER(ret, log_link_warning_errno(link, r, "Could not stop DHCP relay agent: %m"));
r = sd_dhcp_relay_interface_stop(link->dhcp_relay_interface_compat);
if (r < 0)
RET_GATHER(ret, log_link_warning_errno(link, r, "Could not stop DHCP relay agent (compat): %m"));
r = sd_dhcp_server_stop(link->dhcp_server);
if (r < 0)
RET_GATHER(ret, log_link_warning_errno(link, r, "Could not stop DHCPv4 server: %m"));
@@ -739,6 +751,10 @@ static int link_acquire_dynamic_ipv4_conf(Link *link) {
log_link_debug(link, "Acquiring IPv4 link-local address.");
}
r = link_start_dhcp_relay(link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not start DHCP relay agent: %m");
r = link_start_dhcp4_server(link);
if (r < 0)
return log_link_warning_errno(link, r, "Could not start DHCP server: %m");
@@ -1196,6 +1212,8 @@ static int link_drop_dynamic_config(Link *link, Network *network) {
RET_GATHER(r, link_drop_dhcp4_config(link, network));
RET_GATHER(r, link_drop_dhcp6_config(link, network));
RET_GATHER(r, link_drop_dhcp_pd_config(link, network));
link->dhcp_relay_interface = sd_dhcp_relay_interface_unref(link->dhcp_relay_interface);
link->dhcp_relay_interface_compat = sd_dhcp_relay_interface_unref(link->dhcp_relay_interface_compat);
link->dhcp_server = sd_dhcp_server_unref(link->dhcp_server);
link->lldp_rx = sd_lldp_rx_unref(link->lldp_rx); /* TODO: keep the received neighbors. */
link->lldp_tx = sd_lldp_tx_unref(link->lldp_tx);
@@ -1314,6 +1332,10 @@ static int link_configure(Link *link) {
if (r < 0)
return r;
r = link_request_dhcp_relay(link);
if (r < 0)
return r;
r = link_request_dhcp_server(link);
if (r < 0)
return r;
@@ -2645,6 +2667,12 @@ static int link_update_name(Link *link, sd_netlink_message *message) {
return log_link_debug_errno(link, r, "Failed to update interface name in NDisc: %m");
}
if (link->dhcp_relay_interface) {
r = sd_dhcp_relay_interface_set_ifname(link->dhcp_relay_interface, link->ifname);
if (r < 0)
return log_link_debug_errno(link, r, "Failed to update interface name in DHCP relay interface: %m");
}
if (link->dhcp_server) {
r = sd_dhcp_server_set_ifname(link->dhcp_server, link->ifname);
if (r < 0)
+2
View File
@@ -143,6 +143,8 @@ typedef struct Link {
bool bridge_vlan_set:1;
bool bearer_configured:1;
sd_dhcp_relay_interface *dhcp_relay_interface;
sd_dhcp_relay_interface *dhcp_relay_interface_compat;
sd_dhcp_server *dhcp_server;
sd_ndisc *ndisc;
+7
View File
@@ -5,6 +5,7 @@
#include <sys/socket.h>
#include "sd-bus.h"
#include "sd-dhcp-relay.h"
#include "sd-event.h"
#include "sd-netlink.h"
#include "sd-resolve.h"
@@ -25,6 +26,7 @@
#include "errno-util.h"
#include "fd-util.h"
#include "initrd-util.h"
#include "iovec-util.h"
#include "mount-util.h"
#include "netlink-internal.h"
#include "netlink-util.h"
@@ -701,6 +703,7 @@ int manager_new(Manager **ret, bool test_mode) {
.dhcp_duid.type = DUID_TYPE_EN,
.dhcp6_duid.type = DUID_TYPE_EN,
.duid_product_uuid.type = DUID_TYPE_UUID,
.dhcp_relay_extra_options = TLV_INIT(TLV_DHCP4_SUBOPTION),
.dhcp_server_persist_leases = DHCP_SERVER_PERSIST_LEASES_YES,
.serialization_fd = -EBADF,
.ip_forwarding = { -1, -1, },
@@ -760,6 +763,10 @@ Manager* manager_free(Manager *m) {
sd_netlink_unref(m->nfnl);
sd_resolve_unref(m->resolve);
iovec_done(&m->dhcp_relay_remote_id);
tlv_done(&m->dhcp_relay_extra_options);
sd_dhcp_relay_unref(m->dhcp_relay);
m->routes = set_free(m->routes);
m->nexthops_by_id = hashmap_free(m->nexthops_by_id);
+8
View File
@@ -3,6 +3,7 @@
#include "networkd-forward.h"
#include "networkd-network.h"
#include "tlv-util.h"
typedef enum ManagerState {
MANAGER_RUNNING,
@@ -74,6 +75,13 @@ typedef struct Manager {
bool has_product_uuid;
bool product_uuid_requested;
/* DHCP relay agent */
sd_dhcp_relay *dhcp_relay;
struct in_addr dhcp_relay_server_address;
bool dhcp_relay_override_server_id;
struct iovec dhcp_relay_remote_id;
TLV dhcp_relay_extra_options;
char* dynamic_hostname;
char* dynamic_timezone;
+11 -4
View File
@@ -132,6 +132,7 @@ Network.VLAN, config_parse_stacked_netdev,
Network.VXLAN, config_parse_stacked_netdev, NETDEV_KIND_VXLAN, offsetof(Network, stacked_netdev_names)
Network.Xfrm, config_parse_stacked_netdev, NETDEV_KIND_XFRM, offsetof(Network, stacked_netdev_names)
Network.DHCP, config_parse_dhcp, 0, offsetof(Network, dhcp)
Network.DHCPRelay, config_parse_dhcp_relay_interface_mode, 0, offsetof(Network, dhcp_relay_interface_mode)
Network.DHCPServer, config_parse_bool, 0, offsetof(Network, dhcp_server)
Network.LinkLocalAddressing, config_parse_link_local_address_family, 0, offsetof(Network, link_local)
Network.IPv6LinkLocalAddressGenerationMode, config_parse_ipv6_link_local_address_gen_mode, 0, offsetof(Network, ipv6ll_address_gen_mode)
@@ -360,11 +361,17 @@ IPv6AcceptRA.RouteDenyList, config_parse_in_addr_prefixes,
IPv6AcceptRA.Token, config_parse_address_generation_type, 0, offsetof(Network, ndisc_tokens)
IPv6AcceptRA.NetLabel, config_parse_string, CONFIG_PARSE_STRING_SAFE, offsetof(Network, ndisc_netlabel)
IPv6AcceptRA.NFTSet, config_parse_nft_set, NFT_SET_PARSE_NETWORK, offsetof(Network, ndisc_nft_set_context)
DHCPRelay.AgentAddress, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_relay_agent_address_in_addr)
DHCPRelay.GatewayAddress, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_relay_gateway_address)
DHCPRelay.CircuitId, config_parse_dhcp_option, /* check_length= */ true, offsetof(Network, dhcp_relay_circuit_id)
DHCPRelay.VirtualSubnetSelection, config_parse_dhcp_option, /* check_length= */ true, offsetof(Network, dhcp_relay_vss)
DHCPRelay.ExtraOption, config_parse_dhcp_option_tlv, 0, offsetof(Network, dhcp_relay_extra_options)
DHCPRelay.InterfacePriority, config_parse_int, 0, offsetof(Network, dhcp_relay_interface_priority)
DHCPServer.ServerAddress, config_parse_dhcp_server_address, 0, 0
DHCPServer.UplinkInterface, config_parse_uplink, 0, 0
DHCPServer.RelayTarget, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_relay_target)
DHCPServer.RelayAgentCircuitId, config_parse_dhcp_server_relay_agent_suboption, 0, offsetof(Network, dhcp_server_relay_agent_circuit_id)
DHCPServer.RelayAgentRemoteId, config_parse_dhcp_server_relay_agent_suboption, 0, offsetof(Network, dhcp_server_relay_agent_remote_id)
DHCPServer.RelayTarget, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_relay_target_address) /* deprecated */
DHCPServer.RelayAgentCircuitId, config_parse_dhcp_option, /* check_length= */ true, offsetof(Network, dhcp_relay_circuit_id) /* deprecated */
DHCPServer.RelayAgentRemoteId, config_parse_dhcp_option, /* check_length= */ true, offsetof(Network, dhcp_relay_remote_id) /* deprecated */
DHCPServer.MaxLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_max_lease_time_usec)
DHCPServer.DefaultLeaseTimeSec, config_parse_sec, 0, offsetof(Network, dhcp_server_default_lease_time_usec)
DHCPServer.IPv6OnlyPreferredSec, config_parse_dhcp_server_ipv6_only_preferred, 0, offsetof(Network, dhcp_server_ipv6_only_preferred_usec)
@@ -390,7 +397,7 @@ DHCPServer.PoolOffset, config_parse_uint32,
DHCPServer.PoolSize, config_parse_uint32, 0, offsetof(Network, dhcp_server_pool_size)
DHCPServer.SendOption, config_parse_dhcp_option_tlv, 0, offsetof(Network, dhcp_server_extra_options)
DHCPServer.SendVendorOption, config_parse_dhcp_option_tlv, 0, offsetof(Network, dhcp_server_vendor_options)
DHCPServer.BindToInterface, config_parse_bool, 0, offsetof(Network, dhcp_server_bind_to_interface)
DHCPServer.BindToInterface, config_parse_warn_compat, DISABLED_LEGACY, 0
DHCPServer.BootServerAddress, config_parse_in_addr_non_null, AF_INET, offsetof(Network, dhcp_server_boot_server_address)
DHCPServer.BootServerName, config_parse_dns_name, 0, offsetof(Network, dhcp_server_boot_server_name)
DHCPServer.BootFilename, config_parse_string, CONFIG_PARSE_STRING_SAFE_AND_ASCII, offsetof(Network, dhcp_server_boot_filename)
+11 -3
View File
@@ -7,6 +7,7 @@
#include "conf-files.h"
#include "conf-parser.h"
#include "in-addr-util.h"
#include "iovec-util.h"
#include "net-condition.h"
#include "netdev/macvlan.h"
#include "netif-sriov.h"
@@ -433,7 +434,9 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
.dhcp_pd_subnet_id = -1,
.dhcp_pd_route_metric = DHCP6PD_ROUTE_METRIC,
.dhcp_server_bind_to_interface = true,
.dhcp_relay_interface_mode = _DHCP_RELAY_INTERFACE_INVALID,
.dhcp_relay_extra_options = TLV_INIT(TLV_DHCP4_SUBOPTION),
.dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true,
.dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true,
.dhcp_server_emit[SD_DHCP_LEASE_SIP].emit = true,
@@ -547,6 +550,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi
"DHCPv6\0"
"DHCPv6PrefixDelegation\0" /* compat */
"DHCPPrefixDelegation\0"
"DHCPRelay\0"
"DHCPServer\0"
"DHCPServerStaticLease\0"
"IPv6AcceptRA\0"
@@ -767,9 +771,13 @@ static Network *network_free(Network *network) {
ordered_set_free(network->route_domains);
set_free(network->dnssec_negative_trust_anchors);
/* DHCP relay agent */
iovec_done(&network->dhcp_relay_remote_id);
iovec_done(&network->dhcp_relay_circuit_id);
iovec_done(&network->dhcp_relay_vss);
tlv_done(&network->dhcp_relay_extra_options);
/* DHCP server */
free(network->dhcp_server_relay_agent_circuit_id);
free(network->dhcp_server_relay_agent_remote_id);
free(network->dhcp_server_boot_server_name);
free(network->dhcp_server_boot_filename);
free(network->dhcp_server_timezone);
+13 -4
View File
@@ -12,6 +12,7 @@
#include "network-util.h"
#include "networkd-bridge-vlan.h"
#include "networkd-dhcp-common.h"
#include "networkd-dhcp-relay.h"
#include "networkd-dhcp-server.h"
#include "networkd-dhcp4.h"
#include "networkd-dhcp6.h"
@@ -208,17 +209,25 @@ typedef struct Network {
uint32_t dhcp6_route_table;
bool dhcp6_route_table_set;
/* DHCP Relay Agent Support */
DHCPRelayInterfaceMode dhcp_relay_interface_mode;
Address *dhcp_relay_agent_address;
struct in_addr dhcp_relay_target_address; /* for deprecated DHCPServer.RelayTarget= */
struct in_addr dhcp_relay_agent_address_in_addr;
struct in_addr dhcp_relay_gateway_address;
struct iovec dhcp_relay_remote_id; /* for deprecated DHCPServer.RelayAgentRemoteId= */
struct iovec dhcp_relay_circuit_id;
struct iovec dhcp_relay_vss;
TLV dhcp_relay_extra_options;
int dhcp_relay_interface_priority;
/* DHCP Server Support */
bool dhcp_server;
bool dhcp_server_bind_to_interface;
unsigned char dhcp_server_address_prefixlen;
struct in_addr dhcp_server_address_in_addr;
const Address *dhcp_server_address;
int dhcp_server_uplink_index;
char *dhcp_server_uplink_name;
struct in_addr dhcp_server_relay_target;
char *dhcp_server_relay_agent_circuit_id;
char *dhcp_server_relay_agent_remote_id;
NetworkDHCPServerEmitAddress dhcp_server_emit[_SD_DHCP_LEASE_SERVER_TYPE_MAX];
bool dhcp_server_emit_router;
struct in_addr dhcp_server_router;
+1
View File
@@ -365,6 +365,7 @@ static const char *const request_type_table[_REQUEST_TYPE_MAX] = {
[REQUEST_TYPE_ADDRESS_LABEL] = "address label",
[REQUEST_TYPE_BRIDGE_FDB] = "bridge FDB",
[REQUEST_TYPE_BRIDGE_MDB] = "bridge MDB",
[REQUEST_TYPE_DHCP_RELAY] = "DHCP relay agent",
[REQUEST_TYPE_DHCP_SERVER] = "DHCP server",
[REQUEST_TYPE_DHCP4_CLIENT] = "DHCPv4 client",
[REQUEST_TYPE_DHCP6_CLIENT] = "DHCPv6 client",
+1
View File
@@ -13,6 +13,7 @@ typedef enum RequestType {
REQUEST_TYPE_ADDRESS_LABEL,
REQUEST_TYPE_BRIDGE_FDB,
REQUEST_TYPE_BRIDGE_MDB,
REQUEST_TYPE_DHCP_RELAY,
REQUEST_TYPE_DHCP_SERVER,
REQUEST_TYPE_DHCP4_CLIENT,
REQUEST_TYPE_DHCP6_CLIENT,