diff options
author | Lennart Poettering <lennart@poettering.net> | 2021-04-21 21:59:35 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-04-21 21:59:35 +0200 |
commit | 6f4a5f25fc0644158325bb5960f4d40a83ac3fc0 (patch) | |
tree | 0013189c73495e3c35b983be13c9102dba4e9ac8 /src/network | |
parent | Merge pull request #19365 from keszybz/sd_id128_equals (diff) | |
parent | network: dhcp: constify link_get_duid() (diff) | |
download | systemd-6f4a5f25fc0644158325bb5960f4d40a83ac3fc0.tar.xz systemd-6f4a5f25fc0644158325bb5960f4d40a83ac3fc0.zip |
Merge pull request #19271 from yuwata/dhcp-duid-uuid
network: fix issues arround DHCP DUID-UUID
Diffstat (limited to 'src/network')
-rw-r--r-- | src/network/networkd-conf.c | 153 | ||||
-rw-r--r-- | src/network/networkd-conf.h | 3 | ||||
-rw-r--r-- | src/network/networkd-dhcp-common.c | 459 | ||||
-rw-r--r-- | src/network/networkd-dhcp-common.h | 22 | ||||
-rw-r--r-- | src/network/networkd-dhcp4.c | 39 | ||||
-rw-r--r-- | src/network/networkd-dhcp4.h | 1 | ||||
-rw-r--r-- | src/network/networkd-dhcp6.c | 35 | ||||
-rw-r--r-- | src/network/networkd-dhcp6.h | 1 | ||||
-rw-r--r-- | src/network/networkd-gperf.gperf | 10 | ||||
-rw-r--r-- | src/network/networkd-link.c | 43 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 10 | ||||
-rw-r--r-- | src/network/networkd-manager.h | 7 | ||||
-rw-r--r-- | src/network/networkd-ndisc.c | 11 | ||||
-rw-r--r-- | src/network/networkd-ndisc.h | 1 | ||||
-rw-r--r-- | src/network/networkd-network-gperf.gperf | 16 | ||||
-rw-r--r-- | src/network/networkd-network.c | 7 | ||||
-rw-r--r-- | src/network/networkd-network.h | 10 | ||||
-rw-r--r-- | src/network/networkd.conf | 6 |
18 files changed, 509 insertions, 325 deletions
diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index c413f16739..7907fa8140 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -3,20 +3,11 @@ Copyright © 2014 Vinay Kulkarni <kulkarniv@vmware.com> ***/ -#include <ctype.h> -#include <netinet/ip.h> - #include "conf-parser.h" #include "def.h" -#include "dhcp-identifier.h" -#include "extract-word.h" -#include "hexdecoct.h" #include "networkd-conf.h" #include "networkd-manager.h" -#include "networkd-network.h" #include "networkd-speed-meter.h" -#include "networkd-dhcp4.h" -#include "string-table.h" int manager_parse_config_file(Manager *m) { int r; @@ -45,147 +36,3 @@ int manager_parse_config_file(Manager *m) { return 0; } - -static const char* const duid_type_table[_DUID_TYPE_MAX] = { - [DUID_TYPE_LLT] = "link-layer-time", - [DUID_TYPE_EN] = "vendor", - [DUID_TYPE_LL] = "link-layer", - [DUID_TYPE_UUID] = "uuid", -}; -DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); - -int config_parse_duid_type( - 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) { - - _cleanup_free_ char *type_string = NULL; - const char *p = rvalue; - DUID *duid = data; - DUIDType type; - int r; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(duid); - - r = extract_first_word(&p, &type_string, ":", 0); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - if (r == 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, - "Failed to extract DUID type from '%s', ignoring.", rvalue); - return 0; - } - - type = duid_type_from_string(type_string); - if (type < 0) { - log_syntax(unit, LOG_WARNING, filename, line, type, - "Failed to parse DUID type '%s', ignoring.", type_string); - return 0; - } - - if (!isempty(p)) { - usec_t u; - - if (type != DUID_TYPE_LLT) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Invalid syntax, ignoring: %s", rvalue); - return 0; - } - - r = parse_timestamp(p, &u); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, - "Failed to parse timestamp, ignoring: %s", p); - return 0; - } - - duid->llt_time = u; - } - - duid->type = type; - - return 0; -} - -int config_parse_duid_rawdata( - 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) { - - DUID *ret = data; - uint8_t raw_data[MAX_DUID_LEN]; - unsigned count = 0; - - assert(filename); - assert(lvalue); - assert(rvalue); - assert(ret); - - /* RawData contains DUID in format "NN:NN:NN..." */ - for (const char *p = rvalue;;) { - int n1, n2, len, r; - uint32_t byte; - _cleanup_free_ char *cbyte = NULL; - - r = extract_first_word(&p, &cbyte, ":", 0); - if (r == -ENOMEM) - return log_oom(); - if (r < 0) { - log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue); - return 0; - } - if (r == 0) - break; - - if (count >= MAX_DUID_LEN) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue); - return 0; - } - - len = strlen(cbyte); - if (!IN_SET(len, 1, 2)) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue); - return 0; - } - n1 = unhexchar(cbyte[0]); - if (len == 2) - n2 = unhexchar(cbyte[1]); - else - n2 = 0; - - if (n1 < 0 || n2 < 0) { - log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue); - return 0; - } - - byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2; - raw_data[count++] = byte; - } - - assert_cc(sizeof(raw_data) == sizeof(ret->raw_data)); - memcpy(ret->raw_data, raw_data, count); - ret->raw_data_len = count; - return 0; -} diff --git a/src/network/networkd-conf.h b/src/network/networkd-conf.h index b485e9e541..6f8612ac91 100644 --- a/src/network/networkd-conf.h +++ b/src/network/networkd-conf.h @@ -12,6 +12,3 @@ typedef struct Manager Manager; int manager_parse_config_file(Manager *m); const struct ConfigPerfItem* networkd_gperf_lookup(const char *key, GPERF_LEN_TYPE length); - -CONFIG_PARSER_PROTOTYPE(config_parse_duid_type); -CONFIG_PARSER_PROTOTYPE(config_parse_duid_rawdata); diff --git a/src/network/networkd-dhcp-common.c b/src/network/networkd-dhcp-common.c index bb0b204467..8357b2b99d 100644 --- a/src/network/networkd-dhcp-common.c +++ b/src/network/networkd-dhcp-common.c @@ -4,9 +4,11 @@ #include <linux/if_arp.h> #include "bus-error.h" +#include "dhcp-identifier.h" #include "dhcp-internal.h" #include "dhcp6-internal.h" #include "escape.h" +#include "hexdecoct.h" #include "in-addr-util.h" #include "networkd-dhcp-common.h" #include "networkd-link.h" @@ -61,31 +63,75 @@ void network_adjust_dhcp(Network *network) { network_adjust_dhcp4(network); } -static struct DUID fallback_duid = { .type = DUID_TYPE_EN }; -DUID* link_get_duid(Link *link) { - if (link->network->duid.type != _DUID_TYPE_INVALID) - return &link->network->duid; - else if (link->hw_addr.length == 0 && IN_SET(link->manager->duid.type, DUID_TYPE_LLT, DUID_TYPE_LL)) +static bool duid_needs_product_uuid(const DUID *duid) { + assert(duid); + + return duid->type == DUID_TYPE_UUID && duid->raw_data_len == 0; +} + +static const struct DUID fallback_duid = { .type = DUID_TYPE_EN }; + +const DUID *link_get_duid(Link *link, int family) { + const DUID *duid; + + assert(link); + assert(IN_SET(family, AF_INET, AF_INET6)); + + if (link->network) { + duid = family == AF_INET ? &link->network->dhcp_duid : &link->network->dhcp6_duid; + if (duid->type != _DUID_TYPE_INVALID) { + if (duid_needs_product_uuid(duid)) + return &link->manager->duid_product_uuid; + else + return duid; + } + } + + duid = family == AF_INET ? &link->manager->dhcp_duid : &link->manager->dhcp6_duid; + if (link->hw_addr.length == 0 && IN_SET(duid->type, DUID_TYPE_LLT, DUID_TYPE_LL)) /* Fallback to DUID that works without MAC address. * This is useful for tunnel devices without MAC address. */ return &fallback_duid; - else - return &link->manager->duid; + + return duid; } -static int duid_set_uuid(DUID *duid, sd_id128_t uuid) { - assert(duid); +static int link_configure_and_start_dhcp_delayed(Link *link) { + int r; + + assert(link); - if (duid->raw_data_len > 0) + if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED)) return 0; - if (duid->type != DUID_TYPE_UUID) - return -EINVAL; + if (!link->dhcp_client) { + r = dhcp4_configure(link); + if (r < 0) + return r; + } - memcpy(&duid->raw_data, &uuid, sizeof(sd_id128_t)); - duid->raw_data_len = sizeof(sd_id128_t); + if (!link->dhcp6_client) { + r = dhcp6_configure(link); + if (r < 0) + return r; + } - return 1; + if (!link_has_carrier(link)) + return 0; + + r = dhcp4_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m"); + + r = ndisc_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m"); + + r = dhcp6_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m"); + + return 0; } static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) { @@ -93,7 +139,6 @@ static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_er const sd_bus_error *e; const void *a; size_t sz; - DUID *duid; Link *link; int r; @@ -119,56 +164,37 @@ static int get_product_uuid_handler(sd_bus_message *m, void *userdata, sd_bus_er goto configure; } - memcpy(&manager->product_uuid, a, sz); - while ((duid = set_steal_first(manager->duids_requesting_uuid))) - (void) duid_set_uuid(duid, manager->product_uuid); - - manager->duids_requesting_uuid = set_free(manager->duids_requesting_uuid); + memcpy(&manager->duid_product_uuid.raw_data, a, sz); + manager->duid_product_uuid.raw_data_len = sz; configure: - while ((link = set_steal_first(manager->links_requesting_uuid))) { - link_unref(link); + /* To avoid calling GetProductUUID() bus method so frequently, set the flag below + * even if the method fails. */ + manager->has_product_uuid = true; - r = link_configure(link); + while ((link = set_steal_first(manager->links_requesting_uuid))) { + r = link_configure_and_start_dhcp_delayed(link); if (r < 0) link_enter_failed(link); + + link_unref(link); } manager->links_requesting_uuid = set_free(manager->links_requesting_uuid); - /* To avoid calling GetProductUUID() bus method so frequently, set the flag below - * even if the method fails. */ - manager->has_product_uuid = true; - return 1; } -int manager_request_product_uuid(Manager *m, Link *link) { +int manager_request_product_uuid(Manager *m) { int r; assert(m); - if (m->has_product_uuid) + if (m->product_uuid_requested) return 0; log_debug("Requesting product UUID"); - if (link) { - DUID *duid; - - assert_se(duid = link_get_duid(link)); - - r = set_ensure_put(&m->links_requesting_uuid, NULL, link); - if (r < 0) - return log_oom(); - if (r > 0) - link_ref(link); - - r = set_ensure_put(&m->duids_requesting_uuid, NULL, duid); - if (r < 0) - return log_oom(); - } - if (sd_bus_is_ready(m->bus) <= 0) { log_debug("Not connected to system bus, requesting product UUID later."); return 0; @@ -188,71 +214,40 @@ int manager_request_product_uuid(Manager *m, Link *link) { if (r < 0) return log_warning_errno(r, "Failed to get product UUID: %m"); - return 0; -} - -static bool link_requires_uuid(Link *link) { - const DUID *duid; + m->product_uuid_requested = true; - assert(link); - assert(link->manager); - assert(link->network); - - duid = link_get_duid(link); - if (duid->type != DUID_TYPE_UUID || duid->raw_data_len != 0) - return false; - - if (link_dhcp4_enabled(link) && IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY)) - return true; - - if (link_dhcp6_enabled(link) || link_ipv6_accept_ra_enabled(link)) - return true; - - return false; + return 0; } -int link_configure_duid(Link *link) { +int dhcp_configure_duid(Link *link, const DUID *duid) { Manager *m; - DUID *duid; int r; assert(link); assert(link->manager); - assert(link->network); + assert(duid); m = link->manager; - duid = link_get_duid(link); - if (!link_requires_uuid(link)) + if (!duid_needs_product_uuid(duid)) return 1; - if (m->has_product_uuid) { - (void) duid_set_uuid(duid, m->product_uuid); + if (m->has_product_uuid) return 1; - } - - if (!m->links_requesting_uuid) { - r = manager_request_product_uuid(m, link); - if (r < 0) { - if (r == -ENOMEM) - return r; - log_link_warning_errno(link, r, - "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m"); - return 1; - } - } else { - r = set_put(m->links_requesting_uuid, link); - if (r < 0) - return log_oom(); - if (r > 0) - link_ref(link); - - r = set_put(m->duids_requesting_uuid, duid); - if (r < 0) - return log_oom(); + r = manager_request_product_uuid(m); + if (r < 0) { + log_link_warning_errno(link, r, + "Failed to get product UUID. Falling back to use machine-app-specific ID as DUID-UUID: %m"); + return 1; } + r = set_ensure_put(&m->links_requesting_uuid, NULL, link); + if (r < 0) + return log_oom(); + if (r > 0) + link_ref(link); + return 0; } @@ -523,6 +518,7 @@ int config_parse_iaid(const char *unit, const char *rvalue, void *data, void *userdata) { + Network *network = userdata; uint32_t iaid; int r; @@ -531,6 +527,7 @@ int config_parse_iaid(const char *unit, assert(lvalue); assert(rvalue); assert(network); + assert(IN_SET(ltype, AF_INET, AF_INET6)); r = safe_atou32(rvalue, &iaid); if (r < 0) { @@ -539,8 +536,21 @@ int config_parse_iaid(const char *unit, return 0; } - network->iaid = iaid; - network->iaid_set = true; + if (ltype == AF_INET) { + network->dhcp_iaid = iaid; + network->dhcp_iaid_set = true; + if (!network->dhcp6_iaid_set_explicitly) { + /* Backward compatibility. Previously, IAID is shared by DHCP4 and DHCP6. + * If DHCP6 IAID is not specified explicitly, then use DHCP4 IAID for DHCP6. */ + network->dhcp6_iaid = iaid; + network->dhcp6_iaid_set = true; + } + } else { + assert(ltype == AF_INET6); + network->dhcp6_iaid = iaid; + network->dhcp6_iaid_set = true; + network->dhcp6_iaid_set_explicitly = true; + } return 0; } @@ -924,3 +934,260 @@ static const char * const dhcp_option_data_type_table[_DHCP_OPTION_DATA_MAX] = { }; DEFINE_STRING_TABLE_LOOKUP(dhcp_option_data_type, DHCPOptionDataType); + +static const char* const duid_type_table[_DUID_TYPE_MAX] = { + [DUID_TYPE_LLT] = "link-layer-time", + [DUID_TYPE_EN] = "vendor", + [DUID_TYPE_LL] = "link-layer", + [DUID_TYPE_UUID] = "uuid", +}; +DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(duid_type, DUIDType); + +int config_parse_duid_type( + 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) { + + _cleanup_free_ char *type_string = NULL; + const char *p = rvalue; + bool force = ltype; + DUID *duid = data; + DUIDType type; + int r; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(duid); + + if (!force && duid->set) + return 0; + + r = extract_first_word(&p, &type_string, ":", 0); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + if (r == 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, + "Failed to extract DUID type from '%s', ignoring.", rvalue); + return 0; + } + + type = duid_type_from_string(type_string); + if (type < 0) { + log_syntax(unit, LOG_WARNING, filename, line, type, + "Failed to parse DUID type '%s', ignoring.", type_string); + return 0; + } + + if (!isempty(p)) { + usec_t u; + + if (type != DUID_TYPE_LLT) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Invalid syntax, ignoring: %s", rvalue); + return 0; + } + + r = parse_timestamp(p, &u); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, + "Failed to parse timestamp, ignoring: %s", p); + return 0; + } + + duid->llt_time = u; + } + + duid->type = type; + duid->set = force; + + return 0; +} + +int config_parse_manager_duid_type( + 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) { + + Manager *manager = userdata; + int r; + + assert(manager); + + /* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */ + + r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager); + if (r < 0) + return r; + + return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp6_duid, manager); +} + +int config_parse_network_duid_type( + 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) { + + Network *network = userdata; + int r; + + assert(network); + + r = config_parse_duid_type(unit, filename, line, section, section_line, lvalue, true, rvalue, &network->dhcp_duid, network); + if (r < 0) + return r; + + /* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */ + return config_parse_duid_type(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network); +} + +int config_parse_duid_rawdata( + 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) { + + uint8_t raw_data[MAX_DUID_LEN]; + unsigned count = 0; + bool force = ltype; + DUID *duid = data; + + assert(filename); + assert(lvalue); + assert(rvalue); + assert(duid); + + if (!force && duid->set) + return 0; + + /* RawData contains DUID in format "NN:NN:NN..." */ + for (const char *p = rvalue;;) { + int n1, n2, len, r; + uint32_t byte; + _cleanup_free_ char *cbyte = NULL; + + r = extract_first_word(&p, &cbyte, ":", 0); + if (r == -ENOMEM) + return log_oom(); + if (r < 0) { + log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to read DUID, ignoring assignment: %s.", rvalue); + return 0; + } + if (r == 0) + break; + + if (count >= MAX_DUID_LEN) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Max DUID length exceeded, ignoring assignment: %s.", rvalue); + return 0; + } + + len = strlen(cbyte); + if (!IN_SET(len, 1, 2)) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid length - DUID byte: %s, ignoring assignment: %s.", cbyte, rvalue); + return 0; + } + n1 = unhexchar(cbyte[0]); + if (len == 2) + n2 = unhexchar(cbyte[1]); + else + n2 = 0; + + if (n1 < 0 || n2 < 0) { + log_syntax(unit, LOG_WARNING, filename, line, 0, "Invalid DUID byte: %s. Ignoring assignment: %s.", cbyte, rvalue); + return 0; + } + + byte = ((uint8_t) n1 << (4 * (len-1))) | (uint8_t) n2; + raw_data[count++] = byte; + } + + assert_cc(sizeof(raw_data) == sizeof(duid->raw_data)); + memcpy(duid->raw_data, raw_data, count); + duid->raw_data_len = count; + duid->set = force; + + return 0; +} + +int config_parse_manager_duid_rawdata( + 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) { + + Manager *manager = userdata; + int r; + + assert(manager); + + /* For backward compatibility. Setting both DHCP4 and DHCP6 DUID if they are not specified explicitly. */ + + r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp_duid, manager); + if (r < 0) + return r; + + return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &manager->dhcp6_duid, manager); +} + +int config_parse_network_duid_rawdata( + 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) { + + Network *network = userdata; + int r; + + assert(network); + + r = config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, true, rvalue, &network->dhcp_duid, network); + if (r < 0) + return r; + + /* For backward compatibility, also set DHCP6 DUID if not specified explicitly. */ + return config_parse_duid_rawdata(unit, filename, line, section, section_line, lvalue, false, rvalue, &network->dhcp6_duid, network); +} diff --git a/src/network/networkd-dhcp-common.h b/src/network/networkd-dhcp-common.h index acf80e6255..316f5cf10b 100644 --- a/src/network/networkd-dhcp-common.h +++ b/src/network/networkd-dhcp-common.h @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: LGPL-2.1-or-later */ #pragma once +#include <netinet/in.h> + #include "conf-parser.h" #include "dhcp-identifier.h" #include "time-util.h" @@ -37,6 +39,7 @@ typedef struct DUID { uint8_t raw_data_len; uint8_t raw_data[MAX_DUID_LEN]; usec_t llt_time; + bool set; } DUID; bool link_dhcp_enabled(Link *link, int family); @@ -49,9 +52,16 @@ static inline bool link_dhcp6_enabled(Link *link) { void network_adjust_dhcp(Network *network); -DUID* link_get_duid(Link *link); -int link_configure_duid(Link *link); -int manager_request_product_uuid(Manager *m, Link *link); +const DUID *link_get_duid(Link *link, int family); +static inline const DUID *link_get_dhcp4_duid(Link *link) { + return link_get_duid(link, AF_INET); +} +static inline const DUID *link_get_dhcp6_duid(Link *link) { + return link_get_duid(link, AF_INET6); +} + +int dhcp_configure_duid(Link *link, const DUID *duid); +int manager_request_product_uuid(Manager *m); const char* dhcp_use_domains_to_string(DHCPUseDomains p) _const_; DHCPUseDomains dhcp_use_domains_from_string(const char *s) _pure_; @@ -69,3 +79,9 @@ CONFIG_PARSER_PROTOTYPE(config_parse_section_route_table); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_user_or_vendor_class); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_send_option); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_request_options); +CONFIG_PARSER_PROTOTYPE(config_parse_duid_type); +CONFIG_PARSER_PROTOTYPE(config_parse_manager_duid_type); +CONFIG_PARSER_PROTOTYPE(config_parse_network_duid_type); +CONFIG_PARSER_PROTOTYPE(config_parse_duid_rawdata); +CONFIG_PARSER_PROTOTYPE(config_parse_manager_duid_rawdata); +CONFIG_PARSER_PROTOTYPE(config_parse_network_duid_rawdata); diff --git a/src/network/networkd-dhcp4.c b/src/network/networkd-dhcp4.c index 85b909e576..4987c8fc53 100644 --- a/src/network/networkd-dhcp4.c +++ b/src/network/networkd-dhcp4.c @@ -1225,17 +1225,17 @@ static int dhcp4_set_client_identifier(Link *link) { switch (link->network->dhcp_client_identifier) { case DHCP_CLIENT_ID_DUID: { /* If configured, apply user specified DUID and IAID */ - const DUID *duid = link_get_duid(link); + const DUID *duid = link_get_dhcp4_duid(link); if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client, - link->network->iaid_set, - link->network->iaid, + link->network->dhcp_iaid_set, + link->network->dhcp_iaid, duid->llt_time); else r = sd_dhcp_client_set_iaid_duid(link->dhcp_client, - link->network->iaid_set, - link->network->iaid, + link->network->dhcp_iaid_set, + link->network->dhcp_iaid, duid->type, duid->raw_data_len > 0 ? duid->raw_data : NULL, duid->raw_data_len); @@ -1245,7 +1245,7 @@ static int dhcp4_set_client_identifier(Link *link) { } case DHCP_CLIENT_ID_DUID_ONLY: { /* If configured, apply user specified DUID */ - const DUID *duid = link_get_duid(link); + const DUID *duid = link_get_dhcp4_duid(link); if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) r = sd_dhcp_client_set_duid_llt(link->dhcp_client, @@ -1284,6 +1284,15 @@ static int dhcp4_set_client_identifier(Link *link) { return 0; } +static int dhcp4_configure_duid(Link *link) { + assert(link); + + if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY)) + return 1; + + return dhcp_configure_duid(link, link_get_dhcp4_duid(link)); +} + static int dhcp4_set_request_address(Link *link) { Address *a; @@ -1323,6 +1332,10 @@ int dhcp4_configure(Link *link) { if (link->dhcp_client) return -EBUSY; /* Already configured. */ + r = dhcp4_configure_duid(link); + if (r <= 0) + return r; + r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize); if (r < 0) return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m"); @@ -1505,6 +1518,20 @@ int dhcp4_update_mac(Link *link) { return 0; } +int dhcp4_start(Link *link) { + assert(link); + + if (!link->dhcp_client) + return 0; + + if (sd_dhcp_client_is_running(link->dhcp_client) > 0) + return 0; + + log_link_debug(link, "Acquiring DHCPv4 lease"); + + return sd_dhcp_client_start(link->dhcp_client); +} + int config_parse_dhcp_max_attempts( const char *unit, const char *filename, diff --git a/src/network/networkd-dhcp4.h b/src/network/networkd-dhcp4.h index cfad656c3d..a33fe403be 100644 --- a/src/network/networkd-dhcp4.h +++ b/src/network/networkd-dhcp4.h @@ -20,6 +20,7 @@ typedef enum DHCPClientIdentifier { void network_adjust_dhcp4(Network *network); int dhcp4_configure(Link *link); int dhcp4_update_mac(Link *link); +int dhcp4_start(Link *link); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_client_identifier); CONFIG_PARSER_PROTOTYPE(config_parse_dhcp_acl_ip_address); diff --git a/src/network/networkd-dhcp6.c b/src/network/networkd-dhcp6.c index a1211b86fb..f4b309636f 100644 --- a/src/network/networkd-dhcp6.c +++ b/src/network/networkd-dhcp6.c @@ -1354,6 +1354,31 @@ int dhcp6_request_address(Link *link, int ir) { return 0; } +int dhcp6_start(Link *link) { + assert(link); + + if (!link->dhcp6_client) + return 0; + + if (!link_dhcp6_enabled(link)) + return 0; + + if (link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_NO) + return 0; + + if (!in6_addr_is_link_local(&link->ipv6ll_address)) { + log_link_debug(link, "IPv6 link-local address is not set, delaying to start DHCPv6 client."); + return 0; + } + + if (sd_dhcp6_client_is_running(link->dhcp6_client) > 0) + return 0; + + log_link_debug(link, "Acquiring DHCPv6 lease"); + + return dhcp6_request_address(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST); +} + int dhcp6_request_prefix_delegation(Link *link) { Link *l; @@ -1488,13 +1513,13 @@ static int dhcp6_set_identifier(Link *link, sd_dhcp6_client *client) { if (r < 0) return r; - if (link->network->iaid_set) { - r = sd_dhcp6_client_set_iaid(client, link->network->iaid); + if (link->network->dhcp6_iaid_set) { + r = sd_dhcp6_client_set_iaid(client, link->network->dhcp6_iaid); if (r < 0) return r; } - duid = link_get_duid(link); + duid = link_get_dhcp6_duid(link); if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0) r = sd_dhcp6_client_set_duid_llt(client, duid->llt_time); else @@ -1524,6 +1549,10 @@ int dhcp6_configure(Link *link) { if (link->dhcp6_client) return -EBUSY; + r = dhcp_configure_duid(link, link_get_dhcp6_duid(link)); + if (r <= 0) + return r; + r = sd_dhcp6_client_new(&client); if (r == -ENOMEM) return log_oom(); diff --git a/src/network/networkd-dhcp6.h b/src/network/networkd-dhcp6.h index a8028a95ab..025bbb6188 100644 --- a/src/network/networkd-dhcp6.h +++ b/src/network/networkd-dhcp6.h @@ -31,6 +31,7 @@ bool link_dhcp6_pd_is_enabled(Link *link); int dhcp6_pd_remove(Link *link); int dhcp6_configure(Link *link); int dhcp6_update_mac(Link *link); +int dhcp6_start(Link *link); int dhcp6_request_address(Link *link, int ir); int dhcp6_request_prefix_delegation(Link *link); diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index 74d509896a..20c33e8c80 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -6,6 +6,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include <stddef.h> #include "conf-parser.h" #include "networkd-conf.h" +#include "networkd-dhcp-common.h" #include "networkd-manager.h" #include "networkd-route.h" %} @@ -25,5 +26,10 @@ Network.SpeedMeterIntervalSec, config_parse_sec, Network.ManageForeignRoutingPolicyRules, config_parse_bool, 0, offsetof(Manager, manage_foreign_rules) Network.ManageForeignRoutes, config_parse_bool, 0, offsetof(Manager, manage_foreign_routes) Network.RouteTable, config_parse_route_table_names, 0, 0 -DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Manager, duid) -DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, duid) +DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp_duid) +DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp_duid) +DHCPv6.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp6_duid) +DHCPv6.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp6_duid) +/* 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 127780ec60..a46aa5b9c3 100644 --- a/src/network/networkd-link.c +++ b/src/network/networkd-link.c @@ -1179,14 +1179,6 @@ static int link_acquire_ipv6_conf(Link *link) { assert(link); - if (link->ndisc) { - log_link_debug(link, "Discovering IPv6 routers"); - - r = sd_ndisc_start(link->ndisc); - if (r < 0 && r != -EBUSY) - return log_link_warning_errno(link, r, "Could not start IPv6 Router Discovery: %m"); - } - if (link->radv) { assert(link->radv); assert(in6_addr_is_link_local(&link->ipv6ll_address)); @@ -1202,18 +1194,13 @@ static int link_acquire_ipv6_conf(Link *link) { return log_link_warning_errno(link, r, "Could not start IPv6 Router Advertisement: %m"); } - if (link_dhcp6_enabled(link) && IN_SET(link->network->dhcp6_without_ra, - DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST, - DHCP6_CLIENT_START_MODE_SOLICIT)) { - assert(link->dhcp6_client); - assert(in6_addr_is_link_local(&link->ipv6ll_address)); + r = ndisc_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start IPv6 Router Discovery: %m"); - r = dhcp6_request_address(link, link->network->dhcp6_without_ra == DHCP6_CLIENT_START_MODE_INFORMATION_REQUEST); - if (r < 0 && r != -EBUSY) - return log_link_warning_errno(link, r, "Could not acquire DHCPv6 lease: %m"); - else - log_link_debug(link, "Acquiring DHCPv6 lease"); - } + r = dhcp6_start(link); + if (r < 0) + return log_link_warning_errno(link, r, "Failed to start DHCPv6 client: %m"); r = dhcp6_request_prefix_delegation(link); if (r < 0) @@ -1230,11 +1217,9 @@ static int link_acquire_ipv4_conf(Link *link) { assert(link->manager->event); if (link->dhcp_client) { - log_link_debug(link, "Acquiring DHCPv4 lease"); - - r = sd_dhcp_client_start(link->dhcp_client); + r = dhcp4_start(link); if (r < 0) - return log_link_warning_errno(link, r, "Could not acquire DHCPv4 lease: %m"); + return log_link_warning_errno(link, r, "Failed to start DHCPv4 client: %m"); } else if (link->ipv4ll) { log_link_debug(link, "Acquiring IPv4 link-local address"); @@ -2254,12 +2239,6 @@ static int link_reconfigure_internal(Link *link, sd_netlink_message *m, bool for link_set_state(link, LINK_STATE_INITIALIZED); link->activated = false; - /* link_configure_duid() returns 0 if it requests product UUID. In that case, - * link_configure() is called later asynchronously. */ - r = link_configure_duid(link); - if (r <= 0) - return r; - r = link_configure(link); if (r < 0) return r; @@ -2374,12 +2353,6 @@ static int link_initialized_and_synced(Link *link) { if (r < 0) return r; - /* link_configure_duid() returns 0 if it requests product UUID. In that case, - * link_configure() is called later asynchronously. */ - r = link_configure_duid(link); - if (r <= 0) - return r; - r = link_configure(link); if (r < 0) return r; diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 20957ecd89..562ce5ca54 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -100,8 +100,8 @@ static int on_connected(sd_bus_message *message, void *userdata, sd_bus_error *r (void) manager_set_hostname(m, m->dynamic_hostname); if (m->dynamic_timezone) (void) manager_set_timezone(m, m->dynamic_timezone); - if (m->links_requesting_uuid) - (void) manager_request_product_uuid(m, NULL); + if (!set_isempty(m->links_requesting_uuid)) + (void) manager_request_product_uuid(m); return 0; } @@ -382,6 +382,9 @@ int manager_new(Manager **ret) { .manage_foreign_routes = true, .manage_foreign_rules = true, .ethtool_fd = -1, + .dhcp_duid.type = DUID_TYPE_EN, + .dhcp6_duid.type = DUID_TYPE_EN, + .duid_product_uuid.type = DUID_TYPE_UUID, }; m->state_file = strdup("/run/systemd/netif/state"); @@ -427,8 +430,6 @@ int manager_new(Manager **ret) { if (r < 0) return r; - m->duid.type = DUID_TYPE_EN; - *ret = TAKE_PTR(m); return 0; @@ -452,7 +453,6 @@ Manager* manager_free(Manager *m) { m->links_requesting_uuid = set_free_with_destructor(m->links_requesting_uuid, link_unref); m->links = hashmap_free_with_destructor(m->links, link_unref); - m->duids_requesting_uuid = set_free(m->duids_requesting_uuid); m->networks = ordered_hashmap_free_with_destructor(m->networks, network_unref); m->netdevs = hashmap_free_with_destructor(m->netdevs, netdev_unref); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index c7f743f56f..e02c4ab59e 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -52,11 +52,12 @@ struct Manager { usec_t network_dirs_ts_usec; - DUID duid; - sd_id128_t product_uuid; + DUID dhcp_duid; + DUID dhcp6_duid; + DUID duid_product_uuid; bool has_product_uuid; + bool product_uuid_requested; Set *links_requesting_uuid; - Set *duids_requesting_uuid; char* dynamic_hostname; char* dynamic_timezone; diff --git a/src/network/networkd-ndisc.c b/src/network/networkd-ndisc.c index b02f67c770..af2d6a3ef7 100644 --- a/src/network/networkd-ndisc.c +++ b/src/network/networkd-ndisc.c @@ -1341,6 +1341,17 @@ int ndisc_configure(Link *link) { return 0; } +int ndisc_start(Link *link) { + assert(link); + + if (!link->ndisc || !link->dhcp6_client) + return 0; + + log_link_debug(link, "Discovering IPv6 routers"); + + return sd_ndisc_start(link->ndisc); +} + void ndisc_vacuum(Link *link) { NDiscRDNSS *r; NDiscDNSSL *d; diff --git a/src/network/networkd-ndisc.h b/src/network/networkd-ndisc.h index 13e9547311..2ff9a8969d 100644 --- a/src/network/networkd-ndisc.h +++ b/src/network/networkd-ndisc.h @@ -73,6 +73,7 @@ bool link_ipv6_accept_ra_enabled(Link *link); void network_adjust_ipv6_accept_ra(Network *network); int ndisc_configure(Link *link); +int ndisc_start(Link *link); void ndisc_vacuum(Link *link); void ndisc_flush(Link *link); diff --git a/src/network/networkd-network-gperf.gperf b/src/network/networkd-network-gperf.gperf index 568c34f51b..16638a2543 100644 --- a/src/network/networkd-network-gperf.gperf +++ b/src/network/networkd-network-gperf.gperf @@ -10,7 +10,6 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #include "networkd-address-label.h" #include "networkd-address.h" #include "networkd-can.h" -#include "networkd-conf.h" #include "networkd-dhcp-common.h" #include "networkd-dhcp-server.h" #include "networkd-dhcp4.h" @@ -213,12 +212,12 @@ DHCPv4.VendorClassIdentifier, config_parse_string, DHCPv4.MUDURL, config_parse_dhcp_mud_url, 0, 0 DHCPv4.MaxAttempts, config_parse_dhcp_max_attempts, 0, 0 DHCPv4.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class) -DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid) -DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) +DHCPv4.IAID, config_parse_iaid, AF_INET, 0 +DHCPv4.DUIDType, config_parse_network_duid_type, 0, 0 +DHCPv4.DUIDRawData, config_parse_network_duid_rawdata, 0, 0 DHCPv4.RouteMetric, config_parse_dhcp_route_metric, 0, 0 DHCPv4.RouteTable, config_parse_section_route_table, 0, 0 DHCPv4.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) -DHCPv4.IAID, config_parse_iaid, 0, 0 DHCPv4.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port) DHCPv4.SendRelease, config_parse_bool, 0, offsetof(Network, dhcp_send_release) DHCPv4.SendDecline, config_parse_bool, 0, offsetof(Network, dhcp_send_decline) @@ -244,6 +243,9 @@ DHCPv6.ForceDHCPv6PDOtherInformation, config_parse_bool, DHCPv6.PrefixDelegationHint, config_parse_dhcp6_pd_hint, 0, 0 DHCPv6.WithoutRA, config_parse_dhcp6_client_start_mode, 0, offsetof(Network, dhcp6_without_ra) DHCPv6.SendOption, config_parse_dhcp_send_option, AF_INET6, offsetof(Network, dhcp6_client_send_options) +DHCPv6.IAID, config_parse_iaid, AF_INET6, 0 +DHCPv6.DUIDType, config_parse_duid_type, 0, offsetof(Network, dhcp6_duid) +DHCPv6.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, dhcp6_duid) IPv6AcceptRA.UseAutonomousPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_autonomous_prefix) IPv6AcceptRA.UseOnLinkPrefix, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_onlink_prefix) IPv6AcceptRA.UseDNS, config_parse_bool, 0, offsetof(Network, ipv6_accept_ra_use_dns) @@ -483,12 +485,12 @@ DHCP.RequestBroadcast, config_parse_bool, DHCP.CriticalConnection, config_parse_tristate, 0, offsetof(Network, dhcp_critical) DHCP.VendorClassIdentifier, config_parse_string, 0, offsetof(Network, dhcp_vendor_class_identifier) DHCP.UserClass, config_parse_dhcp_user_or_vendor_class, AF_INET, offsetof(Network, dhcp_user_class) -DHCP.DUIDType, config_parse_duid_type, 0, offsetof(Network, duid) -DHCP.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Network, duid) +DHCP.IAID, config_parse_iaid, AF_INET, 0 +DHCP.DUIDType, config_parse_network_duid_type, 0, 0 +DHCP.DUIDRawData, config_parse_network_duid_rawdata, 0, 0 DHCP.RouteMetric, config_parse_dhcp_route_metric, 0, 0 DHCP.RouteTable, config_parse_section_route_table, 0, 0 DHCP.UseTimezone, config_parse_bool, 0, offsetof(Network, dhcp_use_timezone) -DHCP.IAID, config_parse_iaid, 0, 0 DHCP.ListenPort, config_parse_uint16, 0, offsetof(Network, dhcp_client_port) DHCP.RapidCommit, config_parse_bool, 0, offsetof(Network, dhcp6_rapid_commit) DHCP.ForceDHCPv6PDOtherInformation, config_parse_bool, 0, offsetof(Network, dhcp6_force_pd_other_information) diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 6c81f2cca7..239cb1e7cb 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -301,7 +301,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .ignore_carrier_loss = -1, .keep_configuration = _KEEP_CONFIGURATION_INVALID, - .duid.type = _DUID_TYPE_INVALID, + .dhcp_duid.type = _DUID_TYPE_INVALID, .dhcp_critical = -1, .dhcp_use_ntp = true, .dhcp_use_sip = true, @@ -321,6 +321,7 @@ int network_load_one(Manager *manager, OrderedHashmap **networks, const char *fi .dhcp6_use_hostname = true, .dhcp6_use_ntp = true, .dhcp6_rapid_commit = true, + .dhcp6_duid.type = _DUID_TYPE_INVALID, .dhcp6_pd = -1, .dhcp6_pd_announce = true, @@ -599,10 +600,6 @@ static Network *network_free(Network *network) { ordered_hashmap_free_with_destructor(network->sr_iov_by_section, sr_iov_free); ordered_hashmap_free_with_destructor(network->tc_by_section, traffic_control_free); - if (network->manager && - network->manager->duids_requesting_uuid) - set_remove(network->manager->duids_requesting_uuid, &network->duid); - free(network->name); free(network->dhcp_server_timezone); diff --git a/src/network/networkd-network.h b/src/network/networkd-network.h index db0fbbdf1a..02bbfbad9a 100644 --- a/src/network/networkd-network.h +++ b/src/network/networkd-network.h @@ -118,9 +118,9 @@ struct Network { /* DHCP Client Support */ AddressFamily dhcp; DHCPClientIdentifier dhcp_client_identifier; - DUID duid; - uint32_t iaid; - bool iaid_set; + DUID dhcp_duid; + uint32_t dhcp_iaid; + bool dhcp_iaid_set; char *dhcp_vendor_class_identifier; char *dhcp_mudurl; char **dhcp_user_class; @@ -169,6 +169,10 @@ struct Network { bool dhcp6_rapid_commit; DHCPUseDomains dhcp6_use_domains; bool dhcp6_use_domains_set; + uint32_t dhcp6_iaid; + bool dhcp6_iaid_set; + bool dhcp6_iaid_set_explicitly; + DUID dhcp6_duid; uint8_t dhcp6_pd_length; char *dhcp6_mudurl; char **dhcp6_user_class; diff --git a/src/network/networkd.conf b/src/network/networkd.conf index 4e4e8b8d07..76f9f8454f 100644 --- a/src/network/networkd.conf +++ b/src/network/networkd.conf @@ -19,6 +19,10 @@ #ManageForeignRoutes=yes #RouteTable= -[DHCP] +[DHCPv4] +#DUIDType=vendor +#DUIDRawData= + +[DHCPv6] #DUIDType=vendor #DUIDRawData= |