diff options
author | Yu Watanabe <watanabe.yu+github@gmail.com> | 2024-08-20 19:05:22 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-08-20 19:05:22 +0200 |
commit | 2656f44c3c9b3c7825381a1620aa4cd8c26acd70 (patch) | |
tree | 64d2775e54008f7ba1aee39d6692a724122918c3 /src | |
parent | process-util: handle pidfd_spawn() returning E2BIG (diff) | |
parent | network/address-label: allow to configure IPv6 address label in networkd.conf (diff) | |
download | systemd-2656f44c3c9b3c7825381a1620aa4cd8c26acd70.tar.xz systemd-2656f44c3c9b3c7825381a1620aa4cd8c26acd70.zip |
Merge pull request #34018 from yuwata/network-address-label
network: allow to configure IPv6 address label in networkd.conf
Diffstat (limited to 'src')
-rw-r--r-- | src/network/networkd-address-label.c | 202 | ||||
-rw-r--r-- | src/network/networkd-address-label.h | 4 | ||||
-rw-r--r-- | src/network/networkd-conf.c | 4 | ||||
-rw-r--r-- | src/network/networkd-gperf.gperf | 3 | ||||
-rw-r--r-- | src/network/networkd-manager.c | 7 | ||||
-rw-r--r-- | src/network/networkd-manager.h | 5 | ||||
-rw-r--r-- | src/network/networkd-network.c | 2 | ||||
-rw-r--r-- | src/network/networkd-queue.c | 17 | ||||
-rw-r--r-- | src/network/networkd-queue.h | 12 |
9 files changed, 226 insertions, 30 deletions
diff --git a/src/network/networkd-address-label.c b/src/network/networkd-address-label.c index e91ce3d2fa..3ac0cca72e 100644 --- a/src/network/networkd-address-label.c +++ b/src/network/networkd-address-label.c @@ -22,27 +22,49 @@ AddressLabel *address_label_free(AddressLabel *label) { hashmap_remove(label->network->address_labels_by_section, label->section); } + if (label->manager) { + assert(label->section); + hashmap_remove(label->manager->address_labels_by_section, label->section); + } + config_section_free(label->section); return mfree(label); } DEFINE_SECTION_CLEANUP_FUNCTIONS(AddressLabel, address_label_free); -static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) { +DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( + address_label_section_hash_ops, + ConfigSection, + config_section_hash_func, + config_section_compare_func, + AddressLabel, + address_label_free); + +static int address_label_new_static( + Manager *manager, + Network *network, + const char *filename, + unsigned section_line, + AddressLabel **ret) { + _cleanup_(config_section_freep) ConfigSection *n = NULL; _cleanup_(address_label_freep) AddressLabel *label = NULL; + Hashmap **address_labels_by_section; int r; - assert(network); + assert(!manager != !network); assert(ret); assert(filename); assert(section_line > 0); + address_labels_by_section = manager ? &manager->address_labels_by_section : &network->address_labels_by_section; + r = config_section_new(filename, section_line, &n); if (r < 0) return r; - label = hashmap_get(network->address_labels_by_section, n); + label = hashmap_get(*address_labels_by_section, n); if (label) { *ret = TAKE_PTR(label); return 0; @@ -53,12 +75,13 @@ static int address_label_new_static(Network *network, const char *filename, unsi return -ENOMEM; *label = (AddressLabel) { + .manager = manager, .network = network, .section = TAKE_PTR(n), .label = UINT32_MAX, }; - r = hashmap_ensure_put(&network->address_labels_by_section, &config_section_hash_ops, label->section, label); + r = hashmap_ensure_put(address_labels_by_section, &address_label_section_hash_ops, label->section, label); if (r < 0) return r; @@ -66,7 +89,7 @@ static int address_label_new_static(Network *network, const char *filename, unsi return 0; } -static int address_label_configure_handler( +static int link_address_label_configure_handler( sd_netlink *rtnl, sd_netlink_message *m, Request *req, @@ -86,7 +109,7 @@ static int address_label_configure_handler( } if (link->static_address_label_messages == 0) { - log_link_debug(link, "Addresses label set"); + log_link_debug(link, "Addresses label set."); link->static_address_labels_configured = true; link_check_ready(link); } @@ -94,7 +117,51 @@ static int address_label_configure_handler( return 1; } -static int address_label_configure(AddressLabel *label, Link *link, Request *req) { +static int manager_address_label_configure_handler( + sd_netlink *rtnl, + sd_netlink_message *m, + Request *req, + Link *link, + void *userdata) { + + Manager *manager = ASSERT_PTR(ASSERT_PTR(req)->manager); + int r; + + assert(m); + assert(!link); + + r = sd_netlink_message_get_errno(m); + if (r < 0 && r != -EEXIST) { + log_message_warning_errno(m, r, "Could not set address label"); + return 1; + } + + if (manager->static_address_label_messages == 0) { + log_debug("Addresses label set."); + manager->static_address_labels_configured = true; + } + + return 1; +} + +static int address_label_fill_message(AddressLabel *label, sd_netlink_message *m) { + int r; + + assert(label); + assert(m); + + r = sd_rtnl_message_addrlabel_set_prefixlen(m, label->prefixlen); + if (r < 0) + return r; + + r = sd_netlink_message_append_u32(m, IFAL_LABEL, label->label); + if (r < 0) + return r; + + return sd_netlink_message_append_in6_addr(m, IFA_ADDRESS, &label->prefix); +} + +static int link_address_label_configure(AddressLabel *label, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -110,38 +177,69 @@ static int address_label_configure(AddressLabel *label, Link *link, Request *req if (r < 0) return r; - r = sd_rtnl_message_addrlabel_set_prefixlen(m, label->prefixlen); + r = address_label_fill_message(label, m); if (r < 0) return r; - r = sd_netlink_message_append_u32(m, IFAL_LABEL, label->label); + return request_call_netlink_async(link->manager->rtnl, m, req); +} + +static int manager_address_label_configure(AddressLabel *label, Manager *manager, Request *req) { + _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; + int r; + + assert(label); + assert(manager); + assert(manager->rtnl); + assert(req); + + r = sd_rtnl_message_new_addrlabel(manager->rtnl, &m, RTM_NEWADDRLABEL, 0, AF_INET6); if (r < 0) return r; - r = sd_netlink_message_append_in6_addr(m, IFA_ADDRESS, &label->prefix); + r = address_label_fill_message(label, m); if (r < 0) return r; - return request_call_netlink_async(link->manager->rtnl, m, req); + return request_call_netlink_async(manager->rtnl, m, req); } -static int address_label_process_request(Request *req, Link *link, void *userdata) { +static int link_address_label_process_request(Request *req, Link *link, void *userdata) { AddressLabel *label = ASSERT_PTR(userdata); int r; assert(req); assert(link); + assert(link->manager); + + if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false)) + return 0; - if (!link_is_ready_to_configure(link, false)) + if (!link->manager->static_address_labels_configured) return 0; - r = address_label_configure(label, link, req); + r = link_address_label_configure(label, link, req); if (r < 0) return log_link_warning_errno(link, r, "Failed to configure address label: %m"); return 1; } +static int manager_address_label_process_request(Request *req, Link *link, void *userdata) { + AddressLabel *label = ASSERT_PTR(userdata); + int r; + + assert(req); + assert(req->manager); + assert(!link); + + r = manager_address_label_configure(label, req->manager, req); + if (r < 0) + return log_warning_errno(r, "Failed to configure address label: %m"); + + return 1; +} + int link_request_static_address_labels(Link *link) { AddressLabel *label; int r; @@ -154,9 +252,9 @@ int link_request_static_address_labels(Link *link) { HASHMAP_FOREACH(label, link->network->address_labels_by_section) { r = link_queue_request_full(link, REQUEST_TYPE_ADDRESS_LABEL, label, NULL, trivial_hash_func, trivial_compare_func, - address_label_process_request, + link_address_label_process_request, &link->static_address_label_messages, - address_label_configure_handler, NULL); + link_address_label_configure_handler, NULL); if (r < 0) return log_link_warning_errno(link, r, "Failed to request address label: %m"); } @@ -172,6 +270,32 @@ int link_request_static_address_labels(Link *link) { return 0; } +int manager_request_static_address_labels(Manager *manager) { + AddressLabel *label; + int r; + + assert(manager); + + manager->static_address_labels_configured = false; + + HASHMAP_FOREACH(label, manager->address_labels_by_section) { + r = manager_queue_request_full(manager, REQUEST_TYPE_ADDRESS_LABEL, + label, NULL, trivial_hash_func, trivial_compare_func, + manager_address_label_process_request, + &manager->static_address_label_messages, + manager_address_label_configure_handler, NULL); + if (r < 0) + return log_warning_errno(r, "Failed to request address label: %m"); + } + + if (manager->static_address_label_messages == 0) + manager->static_address_labels_configured = true; + else + log_debug("Setting address labels."); + + return 0; +} + static int address_label_section_verify(AddressLabel *label) { assert(label); assert(label->section); @@ -194,16 +318,24 @@ static int address_label_section_verify(AddressLabel *label) { return 0; } -void network_drop_invalid_address_labels(Network *network) { +static void drop_invalid_address_labels(Hashmap *address_labels_by_section) { AddressLabel *label; - assert(network); - - HASHMAP_FOREACH(label, network->address_labels_by_section) + HASHMAP_FOREACH(label, address_labels_by_section) if (address_label_section_verify(label) < 0) address_label_free(label); } +void network_drop_invalid_address_labels(Network *network) { + assert(network); + drop_invalid_address_labels(network->address_labels_by_section); +} + +void manager_drop_invalid_address_labels(Manager *manager) { + assert(manager); + drop_invalid_address_labels(manager->address_labels_by_section); +} + int config_parse_address_label_prefix( const char *unit, const char *filename, @@ -217,7 +349,8 @@ int config_parse_address_label_prefix( void *userdata) { _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL; - Network *network = userdata; + Manager *manager = ltype ? userdata : NULL; + Network *network = ltype ? NULL : userdata; unsigned char prefixlen; union in_addr_union a; int r; @@ -226,12 +359,18 @@ int config_parse_address_label_prefix( assert(section); assert(lvalue); assert(rvalue); - assert(data); + assert(userdata); - r = address_label_new_static(network, filename, section_line, &n); + r = address_label_new_static(manager, network, filename, section_line, &n); if (r < 0) return log_oom(); + if (isempty(rvalue)) { + n->prefix_set = false; + TAKE_PTR(n); + return 0; + } + r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, @@ -249,7 +388,6 @@ int config_parse_address_label_prefix( n->prefix = a.in6; n->prefixlen = prefixlen; n->prefix_set = true; - TAKE_PTR(n); return 0; } @@ -267,7 +405,8 @@ int config_parse_address_label( void *userdata) { _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL; - Network *network = userdata; + Manager *manager = ltype ? userdata : NULL; + Network *network = ltype ? NULL : userdata; uint32_t k; int r; @@ -275,25 +414,30 @@ int config_parse_address_label( assert(section); assert(lvalue); assert(rvalue); - assert(data); + assert(userdata); - r = address_label_new_static(network, filename, section_line, &n); + r = address_label_new_static(manager, network, filename, section_line, &n); if (r < 0) return log_oom(); + if (isempty(rvalue)) { + n->label = UINT32_MAX; + TAKE_PTR(n); + return 0; + } + r = safe_atou32(rvalue, &k); if (r < 0) { log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse address label, ignoring: %s", rvalue); return 0; } - if (k == UINT_MAX) { + if (k == UINT32_MAX) { log_syntax(unit, LOG_WARNING, filename, line, 0, "Address label is invalid, ignoring: %s", rvalue); return 0; } n->label = k; TAKE_PTR(n); - return 0; } diff --git a/src/network/networkd-address-label.h b/src/network/networkd-address-label.h index 1e2ee70dee..d2165719c3 100644 --- a/src/network/networkd-address-label.h +++ b/src/network/networkd-address-label.h @@ -8,9 +8,11 @@ #include "networkd-util.h" typedef struct Link Link; +typedef struct Manager Manager; typedef struct Network Network; typedef struct AddressLabel { + Manager *manager; Network *network; ConfigSection *section; @@ -23,8 +25,10 @@ typedef struct AddressLabel { AddressLabel *address_label_free(AddressLabel *label); void network_drop_invalid_address_labels(Network *network); +void manager_drop_invalid_address_labels(Manager *manager); int link_request_static_address_labels(Link *link); +int manager_request_static_address_labels(Manager *manager); CONFIG_PARSER_PROTOTYPE(config_parse_address_label); CONFIG_PARSER_PROTOTYPE(config_parse_address_label_prefix); diff --git a/src/network/networkd-conf.c b/src/network/networkd-conf.c index 6a6814d59c..0ec45d3dd9 100644 --- a/src/network/networkd-conf.c +++ b/src/network/networkd-conf.c @@ -5,6 +5,7 @@ #include "conf-parser.h" #include "constants.h" +#include "networkd-address-label.h" #include "networkd-conf.h" #include "networkd-manager.h" #include "networkd-speed-meter.h" @@ -18,6 +19,7 @@ int manager_parse_config_file(Manager *m) { "systemd/networkd.conf", "Network\0" "IPv6AcceptRA\0" + "IPv6AddressLabel\0" "DHCPv4\0" "DHCPv6\0" "DHCPServer\0" @@ -34,5 +36,7 @@ int manager_parse_config_file(Manager *m) { m->speed_meter_interval_usec = SPEED_METER_MINIMUM_TIME_INTERVAL; } + manager_drop_invalid_address_labels(m); + return 0; } diff --git a/src/network/networkd-gperf.gperf b/src/network/networkd-gperf.gperf index f02dfd7a05..8b64b3af30 100644 --- a/src/network/networkd-gperf.gperf +++ b/src/network/networkd-gperf.gperf @@ -5,6 +5,7 @@ _Pragma("GCC diagnostic ignored \"-Wimplicit-fallthrough\"") #endif #include <stddef.h> #include "conf-parser.h" +#include "networkd-address-label.h" #include "networkd-conf.h" #include "networkd-dhcp-common.h" #include "networkd-dns.h" @@ -33,6 +34,8 @@ Network.IPv6Forwarding, config_parse_tristate, Network.IPv6PrivacyExtensions, config_parse_ipv6_privacy_extensions, 0, offsetof(Manager, ipv6_privacy_extensions) Network.UseDomains, config_parse_use_domains, 0, offsetof(Manager, use_domains) IPv6AcceptRA.UseDomains, config_parse_use_domains, 0, offsetof(Manager, ndisc_use_domains) +IPv6AddressLabel.Prefix, config_parse_address_label_prefix, 1, 0 +IPv6AddressLabel.Label, config_parse_address_label, 1, 0 DHCPv4.UseDomains, config_parse_use_domains, 0, offsetof(Manager, dhcp_use_domains) DHCPv4.DUIDType, config_parse_duid_type, 0, offsetof(Manager, dhcp_duid) DHCPv4.DUIDRawData, config_parse_duid_rawdata, 0, offsetof(Manager, dhcp_duid) diff --git a/src/network/networkd-manager.c b/src/network/networkd-manager.c index 4ec4550caf..6893ade66a 100644 --- a/src/network/networkd-manager.c +++ b/src/network/networkd-manager.c @@ -32,6 +32,7 @@ #include "local-addresses.h" #include "netlink-util.h" #include "network-internal.h" +#include "networkd-address-label.h" #include "networkd-address-pool.h" #include "networkd-address.h" #include "networkd-dhcp-server-bus.h" @@ -664,6 +665,8 @@ Manager* manager_free(Manager *m) { m->nexthops_by_id = hashmap_free(m->nexthops_by_id); m->nexthop_ids = set_free(m->nexthop_ids); + m->address_labels_by_section = hashmap_free(m->address_labels_by_section); + sd_event_source_unref(m->speed_meter_event_source); sd_event_unref(m->event); @@ -692,6 +695,10 @@ int manager_start(Manager *m) { manager_set_sysctl(m); + r = manager_request_static_address_labels(m); + if (r < 0) + return r; + r = manager_start_speed_meter(m); if (r < 0) return log_error_errno(r, "Failed to initialize speed meter: %m"); diff --git a/src/network/networkd-manager.h b/src/network/networkd-manager.h index 354cc6273e..a70b3e708f 100644 --- a/src/network/networkd-manager.h +++ b/src/network/networkd-manager.h @@ -88,6 +88,11 @@ struct Manager { unsigned route_remove_messages; Set *routes; + /* IPv6 Address Label */ + Hashmap *address_labels_by_section; + unsigned static_address_label_messages; + bool static_address_labels_configured; + /* Route table name */ Hashmap *route_table_numbers_by_name; Hashmap *route_table_names_by_number; diff --git a/src/network/networkd-network.c b/src/network/networkd-network.c index 5335376e15..94666c2bdd 100644 --- a/src/network/networkd-network.c +++ b/src/network/networkd-network.c @@ -794,7 +794,7 @@ static Network *network_free(Network *network) { hashmap_free_with_destructor(network->bridge_fdb_entries_by_section, bridge_fdb_free); hashmap_free_with_destructor(network->bridge_mdb_entries_by_section, bridge_mdb_free); ordered_hashmap_free(network->neighbors_by_section); - hashmap_free_with_destructor(network->address_labels_by_section, address_label_free); + hashmap_free(network->address_labels_by_section); hashmap_free_with_destructor(network->prefixes_by_section, prefix_free); hashmap_free_with_destructor(network->route_prefixes_by_section, route_prefix_free); hashmap_free_with_destructor(network->pref64_prefixes_by_section, prefix64_free); diff --git a/src/network/networkd-queue.c b/src/network/networkd-queue.c index 98c629f161..7943ab5fb0 100644 --- a/src/network/networkd-queue.c +++ b/src/network/networkd-queue.c @@ -216,6 +216,23 @@ int link_queue_request_full( process, counter, netlink_handler, ret); } +int manager_queue_request_full( + Manager *manager, + RequestType type, + void *userdata, + mfree_func_t free_func, + hash_func_t hash_func, + compare_func_t compare_func, + request_process_func_t process, + unsigned *counter, + request_netlink_handler_t netlink_handler, + Request **ret) { + + return request_new(manager, NULL, type, + userdata, free_func, hash_func, compare_func, + process, counter, netlink_handler, ret); +} + int link_requeue_request(Link *link, Request *req, void *userdata, Request **ret) { assert(link); assert(req); diff --git a/src/network/networkd-queue.h b/src/network/networkd-queue.h index e35cd73efd..3289183f2d 100644 --- a/src/network/networkd-queue.h +++ b/src/network/networkd-queue.h @@ -107,6 +107,18 @@ int link_queue_request_full( request_netlink_handler_t netlink_handler, Request **ret); +int manager_queue_request_full( + Manager *manager, + RequestType type, + void *userdata, + mfree_func_t free_func, + hash_func_t hash_func, + compare_func_t compare_func, + request_process_func_t process, + unsigned *counter, + request_netlink_handler_t netlink_handler, + Request **ret); + int link_requeue_request(Link *link, Request *req, void *userdata, Request **ret); static inline int link_queue_request( |