1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
4 #include <linux/if_addrlabel.h>
6 #include "alloc-util.h"
7 #include "netlink-util.h"
8 #include "networkd-address-label.h"
9 #include "networkd-link.h"
10 #include "networkd-manager.h"
11 #include "networkd-network.h"
12 #include "networkd-queue.h"
13 #include "parse-util.h"
15 AddressLabel
*address_label_free(AddressLabel
*label
) {
20 assert(label
->section
);
21 hashmap_remove(label
->network
->address_labels_by_section
, label
->section
);
24 config_section_free(label
->section
);
28 DEFINE_SECTION_CLEANUP_FUNCTIONS(AddressLabel
, address_label_free
);
30 static int address_label_new_static(Network
*network
, const char *filename
, unsigned section_line
, AddressLabel
**ret
) {
31 _cleanup_(config_section_freep
) ConfigSection
*n
= NULL
;
32 _cleanup_(address_label_freep
) AddressLabel
*label
= NULL
;
38 assert(section_line
> 0);
40 r
= config_section_new(filename
, section_line
, &n
);
44 label
= hashmap_get(network
->address_labels_by_section
, n
);
46 *ret
= TAKE_PTR(label
);
50 label
= new(AddressLabel
, 1);
54 *label
= (AddressLabel
) {
56 .section
= TAKE_PTR(n
),
60 r
= hashmap_ensure_put(&network
->address_labels_by_section
, &config_section_hash_ops
, label
->section
, label
);
64 *ret
= TAKE_PTR(label
);
68 static int address_label_configure_handler(sd_netlink
*rtnl
, sd_netlink_message
*m
, Link
*link
) {
75 assert(link
->static_address_label_messages
> 0);
77 link
->static_address_label_messages
--;
79 if (IN_SET(link
->state
, LINK_STATE_FAILED
, LINK_STATE_LINGER
))
82 r
= sd_netlink_message_get_errno(m
);
83 if (r
< 0 && r
!= -EEXIST
) {
84 log_link_message_warning_errno(link
, m
, r
, "Could not set address label");
85 link_enter_failed(link
);
89 if (link
->static_address_label_messages
== 0) {
90 log_link_debug(link
, "Addresses label set");
91 link
->static_address_labels_configured
= true;
92 link_check_ready(link
);
98 static int address_label_configure(AddressLabel
*label
, Link
*link
, link_netlink_message_handler_t callback
) {
99 _cleanup_(sd_netlink_message_unrefp
) sd_netlink_message
*req
= NULL
;
104 assert(link
->ifindex
> 0);
105 assert(link
->manager
);
106 assert(link
->manager
->rtnl
);
109 r
= sd_rtnl_message_new_addrlabel(link
->manager
->rtnl
, &req
, RTM_NEWADDRLABEL
,
110 link
->ifindex
, AF_INET6
);
112 return log_link_error_errno(link
, r
, "Could not allocate RTM_NEWADDR message: %m");
114 r
= sd_rtnl_message_addrlabel_set_prefixlen(req
, label
->prefixlen
);
116 return log_link_error_errno(link
, r
, "Could not set prefixlen: %m");
118 r
= sd_netlink_message_append_u32(req
, IFAL_LABEL
, label
->label
);
120 return log_link_error_errno(link
, r
, "Could not append IFAL_LABEL attribute: %m");
122 r
= sd_netlink_message_append_in6_addr(req
, IFA_ADDRESS
, &label
->prefix
);
124 return log_link_error_errno(link
, r
, "Could not append IFA_ADDRESS attribute: %m");
126 r
= netlink_call_async(link
->manager
->rtnl
, NULL
, req
, callback
,
127 link_netlink_destroy_callback
, link
);
129 return log_link_error_errno(link
, r
, "Could not send rtnetlink message: %m");
136 int link_request_static_address_labels(Link
*link
) {
141 assert(link
->network
);
143 link
->static_address_labels_configured
= false;
145 HASHMAP_FOREACH(label
, link
->network
->address_labels_by_section
) {
146 r
= link_queue_request(link
, REQUEST_TYPE_ADDRESS_LABEL
, label
, false,
147 &link
->static_address_label_messages
, address_label_configure_handler
, NULL
);
149 return log_link_warning_errno(link
, r
, "Failed to request address label: %m");
152 if (link
->static_address_label_messages
== 0) {
153 link
->static_address_labels_configured
= true;
154 link_check_ready(link
);
156 log_link_debug(link
, "Setting address labels.");
157 link_set_state(link
, LINK_STATE_CONFIGURING
);
163 int request_process_address_label(Request
*req
) {
167 assert(req
->type
== REQUEST_TYPE_ADDRESS_LABEL
);
169 if (!link_is_ready_to_configure(req
->link
, false))
172 return address_label_configure(req
->label
, req
->link
, req
->netlink_handler
);
175 static int address_label_section_verify(AddressLabel
*label
) {
177 assert(label
->section
);
179 if (section_is_invalid(label
->section
))
182 if (!label
->prefix_set
)
183 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
184 "%s: [IPv6AddressLabel] section without Prefix= setting specified. "
185 "Ignoring [IPv6AddressLabel] section from line %u.",
186 label
->section
->filename
, label
->section
->line
);
188 if (label
->label
== UINT32_MAX
)
189 return log_warning_errno(SYNTHETIC_ERRNO(EINVAL
),
190 "%s: [IPv6AddressLabel] section without Label= setting specified. "
191 "Ignoring [IPv6AddressLabel] section from line %u.",
192 label
->section
->filename
, label
->section
->line
);
197 void network_drop_invalid_address_labels(Network
*network
) {
202 HASHMAP_FOREACH(label
, network
->address_labels_by_section
)
203 if (address_label_section_verify(label
) < 0)
204 address_label_free(label
);
207 int config_parse_address_label_prefix(
209 const char *filename
,
212 unsigned section_line
,
219 _cleanup_(address_label_free_or_set_invalidp
) AddressLabel
*n
= NULL
;
220 Network
*network
= userdata
;
221 unsigned char prefixlen
;
222 union in_addr_union a
;
231 r
= address_label_new_static(network
, filename
, section_line
, &n
);
235 r
= in_addr_prefix_from_string(rvalue
, AF_INET6
, &a
, &prefixlen
);
237 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
238 "Invalid prefix for address label, ignoring assignment: %s", rvalue
);
241 if (in6_addr_is_ipv4_mapped_address(&a
.in6
) && prefixlen
> 96) {
242 /* See ip6addrlbl_alloc() in net/ipv6/addrlabel.c of kernel. */
243 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
244 "The prefix length of IPv4 mapped address for address label must be equal to or smaller than 96, "
245 "ignoring assignment: %s", rvalue
);
250 n
->prefixlen
= prefixlen
;
251 n
->prefix_set
= true;
257 int config_parse_address_label(
259 const char *filename
,
262 unsigned section_line
,
269 _cleanup_(address_label_free_or_set_invalidp
) AddressLabel
*n
= NULL
;
270 Network
*network
= userdata
;
280 r
= address_label_new_static(network
, filename
, section_line
, &n
);
284 r
= safe_atou32(rvalue
, &k
);
286 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
, "Failed to parse address label, ignoring: %s", rvalue
);
291 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0, "Address label is invalid, ignoring: %s", rvalue
);