diff --git a/src/network/meson.build b/src/network/meson.build index 9844229ebd..110af9511c 100644 --- a/src/network/meson.build +++ b/src/network/meson.build @@ -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', diff --git a/src/network/networkd-address.c b/src/network/networkd-address.c index 193c4a04b5..9737ae0288 100644 --- a/src/network/networkd-address.c +++ b/src/network/networkd-address.c @@ -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; } @@ -893,6 +897,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) { @@ -2485,5 +2491,6 @@ int network_drop_invalid_addresses(Network *network) { if (r < 0) return r; + network_adjust_dhcp_relay(network); return 0; } diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index bce16284f8..ba3e2f5a43 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -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, diff --git a/src/network/networkd-dhcp-relay.c b/src/network/networkd-dhcp-relay.c new file mode 100644 index 0000000000..5e793a0a12 --- /dev/null +++ b/src/network/networkd-dhcp-relay.c @@ -0,0 +1,362 @@ +/* SPDX-License-Identifier: LGPL-2.1-or-later */ + +#include + +#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); + 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; + + 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); diff --git a/src/network/networkd-dhcp-relay.h b/src/network/networkd-dhcp-relay.h new file mode 100644 index 0000000000..7d56740ede --- /dev/null +++ b/src/network/networkd-dhcp-relay.h @@ -0,0 +1,19 @@ +/* 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_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); diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index 3684a696ff..242da72c27 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -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 diff --git a/src/network/networkd-link.c b/src/network/networkd-link.c index a69a5e8979..969818e9f7 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -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,7 @@ 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_server = sd_dhcp_server_unref(link->dhcp_server); link->dhcp_client = sd_dhcp_client_unref(link->dhcp_client); @@ -424,6 +427,10 @@ 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_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 +746,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"); @@ -1156,6 +1167,7 @@ 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_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); @@ -1274,6 +1286,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; @@ -2605,6 +2621,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) diff --git a/src/network/networkd-link.h b/src/network/networkd-link.h index 456ec99185..4c3e53b93e 100644 --- a/src/network/networkd-link.h +++ b/src/network/networkd-link.h @@ -143,6 +143,7 @@ typedef struct Link { bool bridge_vlan_set:1; bool bearer_configured:1; + sd_dhcp_relay_interface *dhcp_relay_interface; sd_dhcp_server *dhcp_server; sd_ndisc *ndisc; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index f43709da35..63ba0c166f 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -5,6 +5,7 @@ #include #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); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index bacf3df444..2e1b643090 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -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; diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 9e6eb7c799..4b54c6d88d 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -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,6 +361,12 @@ 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) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index dfe524d150..b1569866d1 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -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,6 +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_relay_interface_mode = _DHCP_RELAY_INTERFACE_INVALID, + .dhcp_relay_extra_options = TLV_INIT(TLV_DHCP4_SUBOPTION), + .dhcp_server_bind_to_interface = true, .dhcp_server_emit[SD_DHCP_LEASE_DNS].emit = true, .dhcp_server_emit[SD_DHCP_LEASE_NTP].emit = true, @@ -547,6 +551,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,6 +772,11 @@ 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_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); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index 625b3b9a08..d9e516ff4e 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -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,6 +209,16 @@ 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_agent_address_in_addr; + struct in_addr dhcp_relay_gateway_address; + 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; diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c index 0ab372b4b2..ea846327b0 100644 --- a/src/network/networkd-queue.c +++ b/src/network/networkd-queue.c @@ -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", diff --git a/src/network/networkd-queue.h b/src/network/networkd-queue.h index d656d7aa7a..70c8b2ca9e 100644 --- a/src/network/networkd-queue.h +++ b/src/network/networkd-queue.h @@ -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,