diff options
-rw-r--r-- | man/networkd.conf.xml | 31 | ||||
-rw-r--r-- | man/systemd.network.xml | 8 | ||||
-rw-r--r-- | src/network/networkd-address-label.c | 157 | ||||
-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-- | test/test-network/conf/networkd-address-label.conf | 5 | ||||
-rwxr-xr-x | test/test-network/systemd-networkd-tests.py | 4 |
10 files changed, 203 insertions, 25 deletions
diff --git a/man/networkd.conf.xml b/man/networkd.conf.xml index 9daa1254b6..4772e82799 100644 --- a/man/networkd.conf.xml +++ b/man/networkd.conf.xml @@ -214,6 +214,37 @@ </refsect1> <refsect1> + <title>[IPv6AddressLabel] Section Options</title> + + <para>An [IPv6AddressLabel] section accepts the following keys. Specify multiple [IPv6AddressLabel] + sections to configure multiple address labels. IPv6 address labels are used for address selection. + See <ulink url="https://tools.ietf.org/html/rfc3484">RFC 3484</ulink>. Precedence is managed by + userspace, and only the label itself is stored in the kernel.</para> + + <variablelist class='network-directives'> + <varlistentry> + <term><varname>Label=</varname></term> + <listitem> + <para>The label for the prefix, an unsigned integer in the range 0…4294967294. 0xffffffff is + reserved. This setting is mandatory.</para> + + <xi:include href="version-info.xml" xpointer="v257"/> + </listitem> + </varlistentry> + + <varlistentry> + <term><varname>Prefix=</varname></term> + <listitem> + <para>IPv6 prefix is an address with a prefix length, separated by a slash + <literal>/</literal> character. This setting is mandatory.</para> + + <xi:include href="version-info.xml" xpointer="v257"/> + </listitem> + </varlistentry> + </variablelist> + </refsect1> + + <refsect1> <title>[DHCPv4] Section Options</title> <para>This section configures the DHCP Unique Identifier (DUID) value used by DHCP protocol. DHCPv4 diff --git a/man/systemd.network.xml b/man/systemd.network.xml index 0374dc7cdc..6f6746b13b 100644 --- a/man/systemd.network.xml +++ b/man/systemd.network.xml @@ -1628,8 +1628,8 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix</programlisting> <varlistentry> <term><varname>Label=</varname></term> <listitem> - <para>The label for the prefix, an unsigned integer in the range 0…4294967294. 0xffffffff is - reserved. This setting is mandatory.</para> + <para>The label for the prefix. Takes an unsigned integer in the range 0…4294967294 (0xfffffffe). + 4294967295 (0xffffffff) is reserved. This setting is mandatory.</para> <xi:include href="version-info.xml" xpointer="v234"/> </listitem> @@ -1638,8 +1638,8 @@ NFTSet=prefix:netdev:filter:eth_ipv4_prefix</programlisting> <varlistentry> <term><varname>Prefix=</varname></term> <listitem> - <para>IPv6 prefix is an address with a prefix length, separated by a slash - <literal>/</literal> character. This setting is mandatory. </para> + <para>Takes an IPv6 address with a prefix length, separated by a slash + <literal>/</literal> character. This setting is mandatory.</para> <xi:include href="version-info.xml" xpointer="v234"/> </listitem> diff --git a/src/network/networkd-address-label.c b/src/network/networkd-address-label.c index eea37acce6..3ac0cca72e 100644 --- a/src/network/networkd-address-label.c +++ b/src/network/networkd-address-label.c @@ -22,6 +22,11 @@ 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); } @@ -36,21 +41,30 @@ DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR( AddressLabel, address_label_free); -static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) { +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; @@ -61,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, &address_label_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; @@ -74,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, @@ -94,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); } @@ -102,6 +117,33 @@ static int address_label_configure_handler( return 1; } +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; @@ -119,7 +161,7 @@ static int address_label_fill_message(AddressLabel *label, sd_netlink_message *m return sd_netlink_message_append_in6_addr(m, IFA_ADDRESS, &label->prefix); } -static int address_label_configure(AddressLabel *label, Link *link, Request *req) { +static int link_address_label_configure(AddressLabel *label, Link *link, Request *req) { _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *m = NULL; int r; @@ -142,23 +184,62 @@ static int address_label_configure(AddressLabel *label, Link *link, Request *req return request_call_netlink_async(link->manager->rtnl, m, req); } -static int address_label_process_request(Request *req, Link *link, void *userdata) { +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 = address_label_fill_message(label, m); + if (r < 0) + return r; + + return request_call_netlink_async(manager->rtnl, m, req); +} + +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, false)) + if (!link_is_ready_to_configure(link, /* allow_unmanaged = */ false)) return 0; - r = address_label_configure(label, link, req); + if (!link->manager->static_address_labels_configured) + return 0; + + 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; @@ -171,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"); } @@ -189,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); @@ -211,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, @@ -234,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; @@ -245,7 +361,7 @@ int config_parse_address_label_prefix( assert(rvalue); 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(); @@ -289,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; @@ -299,7 +416,7 @@ int config_parse_address_label( assert(rvalue); 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(); 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/test/test-network/conf/networkd-address-label.conf b/test/test-network/conf/networkd-address-label.conf new file mode 100644 index 0000000000..253b9f30db --- /dev/null +++ b/test/test-network/conf/networkd-address-label.conf @@ -0,0 +1,5 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later + +[IPv6AddressLabel] +Label=5555 +Prefix=2004:da8:2:0::/64 diff --git a/test/test-network/systemd-networkd-tests.py b/test/test-network/systemd-networkd-tests.py index 3a30c8bfd1..3cf743dec2 100755 --- a/test/test-network/systemd-networkd-tests.py +++ b/test/test-network/systemd-networkd-tests.py @@ -3729,12 +3729,14 @@ class NetworkdNetworkTests(unittest.TestCase, Utilities): def test_ipv6_address_label(self): copy_network_unit('25-ipv6-address-label-section.network', '12-dummy.netdev') + copy_networkd_conf_dropin('networkd-address-label.conf') start_networkd() self.wait_online('dummy98:degraded') output = check_output('ip addrlabel list') print(output) - self.assertRegex(output, '2004:da8:1::/64') + self.assertRegex(output, '2004:da8:1::/64 dev dummy98 label 4444') + self.assertRegex(output, '2004:da8:2::/64 label 5555') def test_ipv6_proxy_ndp(self): copy_network_unit('25-ipv6-proxy-ndp.network', '12-dummy.netdev') |