]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-address-label.c
Merge pull request #21838 from lnussel/logind-refactor
[thirdparty/systemd.git] / src / network / networkd-address-label.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if.h>
4 #include <linux/if_addrlabel.h>
5
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"
14
15 AddressLabel *address_label_free(AddressLabel *label) {
16 if (!label)
17 return NULL;
18
19 if (label->network) {
20 assert(label->section);
21 hashmap_remove(label->network->address_labels_by_section, label->section);
22 }
23
24 config_section_free(label->section);
25 return mfree(label);
26 }
27
28 DEFINE_SECTION_CLEANUP_FUNCTIONS(AddressLabel, address_label_free);
29
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;
33 int r;
34
35 assert(network);
36 assert(ret);
37 assert(filename);
38 assert(section_line > 0);
39
40 r = config_section_new(filename, section_line, &n);
41 if (r < 0)
42 return r;
43
44 label = hashmap_get(network->address_labels_by_section, n);
45 if (label) {
46 *ret = TAKE_PTR(label);
47 return 0;
48 }
49
50 label = new(AddressLabel, 1);
51 if (!label)
52 return -ENOMEM;
53
54 *label = (AddressLabel) {
55 .network = network,
56 .section = TAKE_PTR(n),
57 .label = UINT32_MAX,
58 };
59
60 r = hashmap_ensure_put(&network->address_labels_by_section, &config_section_hash_ops, label->section, label);
61 if (r < 0)
62 return r;
63
64 *ret = TAKE_PTR(label);
65 return 0;
66 }
67
68 static int address_label_configure_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
69 int r;
70
71 assert(rtnl);
72 assert(m);
73 assert(link);
74 assert(link->ifname);
75 assert(link->static_address_label_messages > 0);
76
77 link->static_address_label_messages--;
78
79 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
80 return 1;
81
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);
86 return 1;
87 }
88
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);
93 }
94
95 return 1;
96 }
97
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;
100 int r;
101
102 assert(label);
103 assert(link);
104 assert(link->ifindex > 0);
105 assert(link->manager);
106 assert(link->manager->rtnl);
107 assert(callback);
108
109 r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL,
110 link->ifindex, AF_INET6);
111 if (r < 0)
112 return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m");
113
114 r = sd_rtnl_message_addrlabel_set_prefixlen(req, label->prefixlen);
115 if (r < 0)
116 return log_link_error_errno(link, r, "Could not set prefixlen: %m");
117
118 r = sd_netlink_message_append_u32(req, IFAL_LABEL, label->label);
119 if (r < 0)
120 return log_link_error_errno(link, r, "Could not append IFAL_LABEL attribute: %m");
121
122 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->prefix);
123 if (r < 0)
124 return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
125
126 r = netlink_call_async(link->manager->rtnl, NULL, req, callback,
127 link_netlink_destroy_callback, link);
128 if (r < 0)
129 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
130
131 link_ref(link);
132
133 return 1;
134 }
135
136 int link_request_static_address_labels(Link *link) {
137 AddressLabel *label;
138 int r;
139
140 assert(link);
141 assert(link->network);
142
143 link->static_address_labels_configured = false;
144
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);
148 if (r < 0)
149 return log_link_warning_errno(link, r, "Failed to request address label: %m");
150 }
151
152 if (link->static_address_label_messages == 0) {
153 link->static_address_labels_configured = true;
154 link_check_ready(link);
155 } else {
156 log_link_debug(link, "Setting address labels.");
157 link_set_state(link, LINK_STATE_CONFIGURING);
158 }
159
160 return 0;
161 }
162
163 int request_process_address_label(Request *req) {
164 assert(req);
165 assert(req->link);
166 assert(req->label);
167 assert(req->type == REQUEST_TYPE_ADDRESS_LABEL);
168
169 if (!link_is_ready_to_configure(req->link, false))
170 return 0;
171
172 return address_label_configure(req->label, req->link, req->netlink_handler);
173 }
174
175 static int address_label_section_verify(AddressLabel *label) {
176 assert(label);
177 assert(label->section);
178
179 if (section_is_invalid(label->section))
180 return -EINVAL;
181
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);
187
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);
193
194 return 0;
195 }
196
197 void network_drop_invalid_address_labels(Network *network) {
198 AddressLabel *label;
199
200 assert(network);
201
202 HASHMAP_FOREACH(label, network->address_labels_by_section)
203 if (address_label_section_verify(label) < 0)
204 address_label_free(label);
205 }
206
207 int config_parse_address_label_prefix(
208 const char *unit,
209 const char *filename,
210 unsigned line,
211 const char *section,
212 unsigned section_line,
213 const char *lvalue,
214 int ltype,
215 const char *rvalue,
216 void *data,
217 void *userdata) {
218
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;
223 int r;
224
225 assert(filename);
226 assert(section);
227 assert(lvalue);
228 assert(rvalue);
229 assert(data);
230
231 r = address_label_new_static(network, filename, section_line, &n);
232 if (r < 0)
233 return log_oom();
234
235 r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen);
236 if (r < 0) {
237 log_syntax(unit, LOG_WARNING, filename, line, r,
238 "Invalid prefix for address label, ignoring assignment: %s", rvalue);
239 return 0;
240 }
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);
246 return 0;
247 }
248
249 n->prefix = a.in6;
250 n->prefixlen = prefixlen;
251 n->prefix_set = true;
252
253 TAKE_PTR(n);
254 return 0;
255 }
256
257 int config_parse_address_label(
258 const char *unit,
259 const char *filename,
260 unsigned line,
261 const char *section,
262 unsigned section_line,
263 const char *lvalue,
264 int ltype,
265 const char *rvalue,
266 void *data,
267 void *userdata) {
268
269 _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
270 Network *network = userdata;
271 uint32_t k;
272 int r;
273
274 assert(filename);
275 assert(section);
276 assert(lvalue);
277 assert(rvalue);
278 assert(data);
279
280 r = address_label_new_static(network, filename, section_line, &n);
281 if (r < 0)
282 return log_oom();
283
284 r = safe_atou32(rvalue, &k);
285 if (r < 0) {
286 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse address label, ignoring: %s", rvalue);
287 return 0;
288 }
289
290 if (k == UINT_MAX) {
291 log_syntax(unit, LOG_WARNING, filename, line, 0, "Address label is invalid, ignoring: %s", rvalue);
292 return 0;
293 }
294
295 n->label = k;
296 TAKE_PTR(n);
297
298 return 0;
299 }