]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-address-label.c
network: address label: use struct in6_addr instead
[thirdparty/systemd.git] / src / network / networkd-address-label.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
95b74ef6
SS
2
3#include <net/if.h>
4#include <linux/if_addrlabel.h>
5
6#include "alloc-util.h"
95b74ef6 7#include "netlink-util.h"
fb486c90
YW
8#include "networkd-address-label.h"
9#include "networkd-link.h"
95b74ef6 10#include "networkd-manager.h"
fb486c90 11#include "networkd-network.h"
95b74ef6 12#include "parse-util.h"
95b74ef6 13
cae418a3 14AddressLabel *address_label_free(AddressLabel *label) {
95b74ef6 15 if (!label)
cae418a3 16 return NULL;
95b74ef6
SS
17
18 if (label->network) {
d6a2a0f9
YW
19 assert(label->section);
20 hashmap_remove(label->network->address_labels_by_section, label->section);
95b74ef6
SS
21 }
22
d6a2a0f9 23 network_config_section_free(label->section);
cae418a3 24 return mfree(label);
95b74ef6
SS
25}
26
fb486c90
YW
27DEFINE_NETWORK_SECTION_FUNCTIONS(AddressLabel, address_label_free);
28
95b74ef6 29static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) {
8e766630
LP
30 _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL;
31 _cleanup_(address_label_freep) AddressLabel *label = NULL;
95b74ef6
SS
32 int r;
33
34 assert(network);
35 assert(ret);
d6a2a0f9
YW
36 assert(filename);
37 assert(section_line > 0);
95b74ef6 38
d6a2a0f9
YW
39 r = network_config_section_new(filename, section_line, &n);
40 if (r < 0)
41 return r;
95b74ef6 42
d6a2a0f9
YW
43 label = hashmap_get(network->address_labels_by_section, n);
44 if (label) {
45 *ret = TAKE_PTR(label);
46 return 0;
95b74ef6
SS
47 }
48
0f7f2769
YW
49 label = new(AddressLabel, 1);
50 if (!label)
51 return -ENOMEM;
95b74ef6 52
0f7f2769
YW
53 *label = (AddressLabel) {
54 .network = network,
d6a2a0f9 55 .section = TAKE_PTR(n),
0f7f2769 56 };
95b74ef6 57
fb8ac4cf 58 r = hashmap_ensure_put(&network->address_labels_by_section, &network_config_hash_ops, label->section, label);
d6a2a0f9
YW
59 if (r < 0)
60 return r;
0f7f2769 61
1cc6c93a 62 *ret = TAKE_PTR(label);
95b74ef6
SS
63 return 0;
64}
65
302a796f 66static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
cccf9517
YW
67 int r;
68
69 assert(rtnl);
70 assert(m);
71 assert(link);
72 assert(link->ifname);
73 assert(link->address_label_messages > 0);
74
75 link->address_label_messages--;
76
77 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
78 return 1;
79
80 r = sd_netlink_message_get_errno(m);
4ff296b0 81 if (r < 0 && r != -EEXIST) {
5ecb131d 82 log_link_message_warning_errno(link, m, r, "Could not set address label");
4ff296b0
YW
83 link_enter_failed(link);
84 return 1;
3a1dfdb4 85 }
cccf9517
YW
86
87 if (link->address_label_messages == 0)
88 log_link_debug(link, "Addresses label set");
89
90 return 1;
91}
92
fe2bc17c 93static int address_label_configure(AddressLabel *label, Link *link) {
95b74ef6
SS
94 _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL;
95 int r;
96
97 assert(label);
98 assert(link);
99 assert(link->ifindex > 0);
100 assert(link->manager);
101 assert(link->manager->rtnl);
102
103 r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL,
f7bf1abe 104 link->ifindex, AF_INET6);
95b74ef6 105 if (r < 0)
98b02994 106 return log_link_error_errno(link, r, "Could not allocate RTM_NEWADDR message: %m");
95b74ef6
SS
107
108 r = sd_rtnl_message_addrlabel_set_prefixlen(req, label->prefixlen);
109 if (r < 0)
98b02994 110 return log_link_error_errno(link, r, "Could not set prefixlen: %m");
95b74ef6
SS
111
112 r = sd_netlink_message_append_u32(req, IFAL_LABEL, label->label);
113 if (r < 0)
98b02994 114 return log_link_error_errno(link, r, "Could not append IFAL_LABEL attribute: %m");
95b74ef6 115
4c0c8d1e 116 r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr);
95b74ef6 117 if (r < 0)
98b02994 118 return log_link_error_errno(link, r, "Could not append IFA_ADDRESS attribute: %m");
95b74ef6 119
302a796f 120 r = netlink_call_async(link->manager->rtnl, NULL, req,
fe2bc17c 121 address_label_handler,
302a796f 122 link_netlink_destroy_callback, link);
95b74ef6 123 if (r < 0)
98b02994 124 return log_link_error_errno(link, r, "Could not send rtnetlink message: %m");
95b74ef6
SS
125
126 link_ref(link);
127
128 return 0;
129}
130
fe2bc17c
YW
131int link_set_address_labels(Link *link) {
132 AddressLabel *label;
133 int r;
134
135 assert(link);
136 assert(link->network);
137
138 HASHMAP_FOREACH(label, link->network->address_labels_by_section) {
139 r = address_label_configure(label, link);
140 if (r < 0)
141 return log_link_warning_errno(link, r, "Could not set address label: %m");
142
143 link->address_label_messages++;
144 }
145
146 return 0;
147}
148
13ffa39f 149void network_drop_invalid_address_labels(Network *network) {
ab316813
YW
150 AddressLabel *label;
151
152 assert(network);
153
154 HASHMAP_FOREACH(label, network->address_labels_by_section)
155 if (section_is_invalid(label->section))
156 address_label_free(label);
157}
158
95b74ef6
SS
159int config_parse_address_label_prefix(const char *unit,
160 const char *filename,
161 unsigned line,
162 const char *section,
163 unsigned section_line,
164 const char *lvalue,
165 int ltype,
166 const char *rvalue,
167 void *data,
168 void *userdata) {
169
fcbf4cb7 170 _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
95b74ef6 171 Network *network = userdata;
2551b422
YW
172 unsigned char prefixlen;
173 union in_addr_union a;
f7bf1abe 174 int r;
95b74ef6
SS
175
176 assert(filename);
177 assert(section);
178 assert(lvalue);
179 assert(rvalue);
180 assert(data);
181
182 r = address_label_new_static(network, filename, section_line, &n);
183 if (r < 0)
d96edb2c 184 return log_oom();
95b74ef6 185
2551b422 186 r = in_addr_prefix_from_string(rvalue, AF_INET6, &a, &prefixlen);
95b74ef6 187 if (r < 0) {
2551b422
YW
188 log_syntax(unit, LOG_WARNING, filename, line, r,
189 "Invalid prefix for address label, ignoring assignment: %s", rvalue);
95b74ef6
SS
190 return 0;
191 }
2551b422
YW
192 if (in6_addr_is_ipv4_mapped_address(&a.in6) && prefixlen > 96) {
193 /* See ip6addrlbl_alloc() in net/ipv6/addrlabel.c of kernel. */
194 log_syntax(unit, LOG_WARNING, filename, line, 0,
195 "The prefix length of IPv4 mapped address for address label must be equal to or smaller than 96, "
196 "ignoring assignment: %s", rvalue);
197 return 0;
198 }
199
4c0c8d1e 200 n->in_addr = a.in6;
2551b422 201 n->prefixlen = prefixlen;
95b74ef6 202
dea161d9 203 TAKE_PTR(n);
95b74ef6
SS
204 return 0;
205}
206
207int config_parse_address_label(
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
fcbf4cb7 219 _cleanup_(address_label_free_or_set_invalidp) AddressLabel *n = NULL;
95b74ef6
SS
220 Network *network = userdata;
221 uint32_t k;
222 int r;
223
224 assert(filename);
225 assert(section);
226 assert(lvalue);
227 assert(rvalue);
228 assert(data);
229
230 r = address_label_new_static(network, filename, section_line, &n);
231 if (r < 0)
d96edb2c 232 return log_oom();
95b74ef6
SS
233
234 r = safe_atou32(rvalue, &k);
235 if (r < 0) {
d96edb2c 236 log_syntax(unit, LOG_WARNING, filename, line, r, "Failed to parse address label, ignoring: %s", rvalue);
95b74ef6
SS
237 return 0;
238 }
239
99b5f4f7 240 if (k == UINT32_C(0xffffffff)) {
d96edb2c 241 log_syntax(unit, LOG_WARNING, filename, line, 0, "Address label is invalid, ignoring: %s", rvalue);
95b74ef6
SS
242 return 0;
243 }
244
245 n->label = k;
dea161d9 246 TAKE_PTR(n);
95b74ef6
SS
247
248 return 0;
249}