]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
95b74ef6 SS |
2 | |
3 | #include <net/if.h> | |
4 | #include <linux/if_addrlabel.h> | |
5 | ||
6 | #include "alloc-util.h" | |
7 | #include "conf-parser.h" | |
8 | #include "networkd-address-label.h" | |
9 | #include "netlink-util.h" | |
10 | #include "networkd-manager.h" | |
11 | #include "parse-util.h" | |
12 | #include "socket-util.h" | |
13 | ||
95b74ef6 SS |
14 | void address_label_free(AddressLabel *label) { |
15 | if (!label) | |
16 | return; | |
17 | ||
18 | if (label->network) { | |
19 | LIST_REMOVE(labels, label->network->address_labels, label); | |
20 | assert(label->network->n_address_labels > 0); | |
21 | label->network->n_address_labels--; | |
22 | ||
23 | if (label->section) { | |
24 | hashmap_remove(label->network->address_labels_by_section, label->section); | |
25 | network_config_section_free(label->section); | |
26 | } | |
27 | } | |
28 | ||
29 | free(label); | |
30 | } | |
31 | ||
32 | static int address_label_new_static(Network *network, const char *filename, unsigned section_line, AddressLabel **ret) { | |
8e766630 LP |
33 | _cleanup_(network_config_section_freep) NetworkConfigSection *n = NULL; |
34 | _cleanup_(address_label_freep) AddressLabel *label = NULL; | |
95b74ef6 SS |
35 | int r; |
36 | ||
37 | assert(network); | |
38 | assert(ret); | |
39 | assert(!!filename == (section_line > 0)); | |
40 | ||
0f7f2769 YW |
41 | if (filename) { |
42 | r = network_config_section_new(filename, section_line, &n); | |
43 | if (r < 0) | |
44 | return r; | |
95b74ef6 | 45 | |
0f7f2769 YW |
46 | label = hashmap_get(network->address_labels_by_section, n); |
47 | if (label) { | |
48 | *ret = TAKE_PTR(label); | |
95b74ef6 | 49 | |
0f7f2769 YW |
50 | return 0; |
51 | } | |
95b74ef6 SS |
52 | } |
53 | ||
0f7f2769 YW |
54 | label = new(AddressLabel, 1); |
55 | if (!label) | |
56 | return -ENOMEM; | |
95b74ef6 | 57 | |
0f7f2769 YW |
58 | *label = (AddressLabel) { |
59 | .network = network, | |
60 | }; | |
95b74ef6 | 61 | |
95b74ef6 SS |
62 | LIST_APPEND(labels, network->address_labels, label); |
63 | network->n_address_labels++; | |
64 | ||
0f7f2769 YW |
65 | if (filename) { |
66 | label->section = TAKE_PTR(n); | |
67 | ||
3e570042 YW |
68 | r = hashmap_ensure_allocated(&network->address_labels_by_section, &network_config_hash_ops); |
69 | if (r < 0) | |
70 | return r; | |
71 | ||
0f7f2769 YW |
72 | r = hashmap_put(network->address_labels_by_section, label->section, label); |
73 | if (r < 0) | |
74 | return r; | |
75 | } | |
76 | ||
1cc6c93a | 77 | *ret = TAKE_PTR(label); |
95b74ef6 SS |
78 | |
79 | return 0; | |
80 | } | |
81 | ||
302a796f | 82 | static int address_label_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) { |
cccf9517 YW |
83 | int r; |
84 | ||
85 | assert(rtnl); | |
86 | assert(m); | |
87 | assert(link); | |
88 | assert(link->ifname); | |
89 | assert(link->address_label_messages > 0); | |
90 | ||
91 | link->address_label_messages--; | |
92 | ||
93 | if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER)) | |
94 | return 1; | |
95 | ||
96 | r = sd_netlink_message_get_errno(m); | |
97 | if (r < 0 && r != -EEXIST) | |
98 | log_link_warning_errno(link, r, "could not set address label: %m"); | |
99 | else if (r >= 0) | |
100 | manager_rtnl_process_address(rtnl, m, link->manager); | |
101 | ||
102 | if (link->address_label_messages == 0) | |
103 | log_link_debug(link, "Addresses label set"); | |
104 | ||
105 | return 1; | |
106 | } | |
107 | ||
95b74ef6 SS |
108 | int address_label_configure( |
109 | AddressLabel *label, | |
110 | Link *link, | |
302a796f | 111 | link_netlink_message_handler_t callback, |
95b74ef6 SS |
112 | bool update) { |
113 | ||
114 | _cleanup_(sd_netlink_message_unrefp) sd_netlink_message *req = NULL; | |
115 | int r; | |
116 | ||
117 | assert(label); | |
118 | assert(link); | |
119 | assert(link->ifindex > 0); | |
120 | assert(link->manager); | |
121 | assert(link->manager->rtnl); | |
122 | ||
123 | r = sd_rtnl_message_new_addrlabel(link->manager->rtnl, &req, RTM_NEWADDRLABEL, | |
f7bf1abe | 124 | link->ifindex, AF_INET6); |
95b74ef6 SS |
125 | if (r < 0) |
126 | return log_error_errno(r, "Could not allocate RTM_NEWADDR message: %m"); | |
127 | ||
128 | r = sd_rtnl_message_addrlabel_set_prefixlen(req, label->prefixlen); | |
129 | if (r < 0) | |
130 | return log_error_errno(r, "Could not set prefixlen: %m"); | |
131 | ||
132 | r = sd_netlink_message_append_u32(req, IFAL_LABEL, label->label); | |
133 | if (r < 0) | |
134 | return log_error_errno(r, "Could not append IFAL_LABEL attribute: %m"); | |
135 | ||
136 | r = sd_netlink_message_append_in6_addr(req, IFA_ADDRESS, &label->in_addr.in6); | |
137 | if (r < 0) | |
138 | return log_error_errno(r, "Could not append IFA_ADDRESS attribute: %m"); | |
139 | ||
302a796f YW |
140 | r = netlink_call_async(link->manager->rtnl, NULL, req, |
141 | callback ?: address_label_handler, | |
142 | link_netlink_destroy_callback, link); | |
95b74ef6 SS |
143 | if (r < 0) |
144 | return log_error_errno(r, "Could not send rtnetlink message: %m"); | |
145 | ||
146 | link_ref(link); | |
147 | ||
148 | return 0; | |
149 | } | |
150 | ||
151 | int config_parse_address_label_prefix(const char *unit, | |
152 | const char *filename, | |
153 | unsigned line, | |
154 | const char *section, | |
155 | unsigned section_line, | |
156 | const char *lvalue, | |
157 | int ltype, | |
158 | const char *rvalue, | |
159 | void *data, | |
160 | void *userdata) { | |
161 | ||
8e766630 | 162 | _cleanup_(address_label_freep) AddressLabel *n = NULL; |
95b74ef6 | 163 | Network *network = userdata; |
f7bf1abe | 164 | int r; |
95b74ef6 SS |
165 | |
166 | assert(filename); | |
167 | assert(section); | |
168 | assert(lvalue); | |
169 | assert(rvalue); | |
170 | assert(data); | |
171 | ||
172 | r = address_label_new_static(network, filename, section_line, &n); | |
173 | if (r < 0) | |
174 | return r; | |
175 | ||
f7bf1abe | 176 | r = in_addr_prefix_from_string(rvalue, AF_INET6, &n->in_addr, &n->prefixlen); |
95b74ef6 | 177 | if (r < 0) { |
f7bf1abe | 178 | log_syntax(unit, LOG_ERR, filename, line, r, "Address label is invalid, ignoring assignment: %s", rvalue); |
95b74ef6 SS |
179 | return 0; |
180 | } | |
181 | ||
95b74ef6 SS |
182 | n = NULL; |
183 | ||
184 | return 0; | |
185 | } | |
186 | ||
187 | int config_parse_address_label( | |
188 | const char *unit, | |
189 | const char *filename, | |
190 | unsigned line, | |
191 | const char *section, | |
192 | unsigned section_line, | |
193 | const char *lvalue, | |
194 | int ltype, | |
195 | const char *rvalue, | |
196 | void *data, | |
197 | void *userdata) { | |
198 | ||
8e766630 | 199 | _cleanup_(address_label_freep) AddressLabel *n = NULL; |
95b74ef6 SS |
200 | Network *network = userdata; |
201 | uint32_t k; | |
202 | int r; | |
203 | ||
204 | assert(filename); | |
205 | assert(section); | |
206 | assert(lvalue); | |
207 | assert(rvalue); | |
208 | assert(data); | |
209 | ||
210 | r = address_label_new_static(network, filename, section_line, &n); | |
211 | if (r < 0) | |
212 | return r; | |
213 | ||
214 | r = safe_atou32(rvalue, &k); | |
215 | if (r < 0) { | |
216 | log_syntax(unit, LOG_ERR, filename, line, r, "Failed to parse address label, ignoring: %s", rvalue); | |
217 | return 0; | |
218 | } | |
219 | ||
220 | if (k == 0xffffffffUL) { | |
3fe91079 | 221 | log_syntax(unit, LOG_ERR, filename, line, r, "Address label is invalid, ignoring: %s", rvalue); |
95b74ef6 SS |
222 | return 0; |
223 | } | |
224 | ||
225 | n->label = k; | |
226 | n = NULL; | |
227 | ||
228 | return 0; | |
229 | } |