]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-queue.c
network: netdev: increment reference counter on request
[thirdparty/systemd.git] / src / network / networkd-queue.c
CommitLineData
19d9a5ad
YW
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "networkd-address.h"
354bc760 4#include "networkd-address-label.h"
e5b35bf6 5#include "networkd-bridge-fdb.h"
9a038aac 6#include "networkd-bridge-mdb.h"
1d28a3cf 7#include "networkd-dhcp-server.h"
ccffa166
YW
8#include "networkd-dhcp4.h"
9#include "networkd-dhcp6.h"
fdeba3f5 10#include "networkd-ipv6-proxy-ndp.h"
19d9a5ad 11#include "networkd-manager.h"
ba4c7184 12#include "networkd-ndisc.h"
19d9a5ad
YW
13#include "networkd-neighbor.h"
14#include "networkd-nexthop.h"
15#include "networkd-route.h"
16#include "networkd-routing-policy-rule.h"
17#include "networkd-queue.h"
9b682672 18#include "networkd-setlink.h"
1dec9d81 19#include "tc.h"
19d9a5ad
YW
20
21static void request_free_object(RequestType type, void *object) {
89346ac6 22 switch (type) {
112a0972
YW
23 case REQUEST_TYPE_ACTIVATE_LINK:
24 break;
76c5a0f2
YW
25 case REQUEST_TYPE_ADDRESS:
26 address_free(object);
27 break;
354bc760
YW
28 case REQUEST_TYPE_ADDRESS_LABEL:
29 address_label_free(object);
30 break;
e5b35bf6
YW
31 case REQUEST_TYPE_BRIDGE_FDB:
32 bridge_fdb_free(object);
33 break;
9a038aac
YW
34 case REQUEST_TYPE_BRIDGE_MDB:
35 bridge_mdb_free(object);
36 break;
1d28a3cf 37 case REQUEST_TYPE_DHCP_SERVER:
ccffa166
YW
38 case REQUEST_TYPE_DHCP4_CLIENT:
39 case REQUEST_TYPE_DHCP6_CLIENT:
1d28a3cf 40 break;
fdeba3f5
YW
41 case REQUEST_TYPE_IPV6_PROXY_NDP:
42 free(object);
43 break;
ba4c7184
YW
44 case REQUEST_TYPE_NDISC:
45 break;
40ca350e
YW
46 case REQUEST_TYPE_NEIGHBOR:
47 neighbor_free(object);
48 break;
709055da 49 case REQUEST_TYPE_NETDEV_STACKED:
efa7b8ad 50 netdev_unref(object);
709055da 51 break;
76c5a0f2
YW
52 case REQUEST_TYPE_NEXTHOP:
53 nexthop_free(object);
54 break;
a254fab2
YW
55 case REQUEST_TYPE_RADV:
56 break;
76c5a0f2
YW
57 case REQUEST_TYPE_ROUTE:
58 route_free(object);
59 break;
0e5ef6be
YW
60 case REQUEST_TYPE_ROUTING_POLICY_RULE:
61 routing_policy_rule_free(object);
62 break;
0fa8ee6c 63 case REQUEST_TYPE_SET_LINK:
1dec9d81
YW
64 break;
65 case REQUEST_TYPE_TRAFFIC_CONTROL:
66 traffic_control_free(object);
67 break;
68f52063 68 case REQUEST_TYPE_UP_DOWN:
0fa8ee6c 69 break;
19d9a5ad 70 default:
04499a70 71 assert_not_reached();
19d9a5ad
YW
72 }
73}
74
40b12fa2 75static Request *request_free(Request *req) {
19d9a5ad
YW
76 if (!req)
77 return NULL;
78
40b12fa2
YW
79 if (req->link && req->link->manager)
80 /* To prevent from triggering assertions in hash functions, remove this request before
81 * freeing object below. */
82 ordered_set_remove(req->link->manager->request_queue, req);
19d9a5ad
YW
83 if (req->consume_object)
84 request_free_object(req->type, req->object);
19d9a5ad
YW
85 link_unref(req->link);
86
87 return mfree(req);
88}
89
90DEFINE_TRIVIAL_CLEANUP_FUNC(Request*, request_free);
91
92void request_drop(Request *req) {
475ec334
YW
93 if (!req)
94 return;
95
19d9a5ad
YW
96 if (req->message_counter)
97 (*req->message_counter)--;
98
99 request_free(req);
100}
101
40b12fa2
YW
102static void request_hash_func(const Request *req, struct siphash *state) {
103 assert(req);
104 assert(req->link);
105 assert(state);
106
107 siphash24_compress(&req->link->ifindex, sizeof(req->link->ifindex), state);
108 siphash24_compress(&req->type, sizeof(req->type), state);
109
89346ac6 110 switch (req->type) {
112a0972
YW
111 case REQUEST_TYPE_ACTIVATE_LINK:
112 break;
40b12fa2
YW
113 case REQUEST_TYPE_ADDRESS:
114 address_hash_func(req->address, state);
115 break;
116 case REQUEST_TYPE_ADDRESS_LABEL:
117 case REQUEST_TYPE_BRIDGE_FDB:
118 case REQUEST_TYPE_BRIDGE_MDB:
709055da 119 case REQUEST_TYPE_NETDEV_STACKED:
40b12fa2
YW
120 /* TODO: Currently, these types do not have any specific hash and compare functions.
121 * Fortunately, all these objects are 'static', thus we can use the trivial functions. */
122 trivial_hash_func(req->object, state);
123 break;
124 case REQUEST_TYPE_DHCP_SERVER:
ccffa166
YW
125 case REQUEST_TYPE_DHCP4_CLIENT:
126 case REQUEST_TYPE_DHCP6_CLIENT:
127 /* These types do not have an object. */
40b12fa2
YW
128 break;
129 case REQUEST_TYPE_IPV6_PROXY_NDP:
130 in6_addr_hash_func(req->ipv6_proxy_ndp, state);
131 break;
ba4c7184
YW
132 case REQUEST_TYPE_NDISC:
133 /* This type does not have an object. */
134 break;
40b12fa2
YW
135 case REQUEST_TYPE_NEIGHBOR:
136 neighbor_hash_func(req->neighbor, state);
137 break;
138 case REQUEST_TYPE_NEXTHOP:
139 nexthop_hash_func(req->nexthop, state);
140 break;
a254fab2
YW
141 case REQUEST_TYPE_RADV:
142 /* This type does not have an object. */
143 break;
40b12fa2
YW
144 case REQUEST_TYPE_ROUTE:
145 route_hash_func(req->route, state);
146 break;
147 case REQUEST_TYPE_ROUTING_POLICY_RULE:
148 routing_policy_rule_hash_func(req->rule, state);
149 break;
89346ac6 150 case REQUEST_TYPE_SET_LINK:
9b682672 151 trivial_hash_func(req->set_link_operation_ptr, state);
0fa8ee6c 152 break;
1dec9d81
YW
153 case REQUEST_TYPE_TRAFFIC_CONTROL:
154 traffic_control_hash_func(req->traffic_control, state);
155 break;
68f52063
YW
156 case REQUEST_TYPE_UP_DOWN:
157 break;
40b12fa2 158 default:
04499a70 159 assert_not_reached();
40b12fa2
YW
160 }
161}
162
163static int request_compare_func(const struct Request *a, const struct Request *b) {
164 int r;
165
166 assert(a);
167 assert(b);
168 assert(a->link);
169 assert(b->link);
170
171 r = CMP(a->link->ifindex, b->link->ifindex);
172 if (r != 0)
173 return r;
174
175 r = CMP(a->type, b->type);
176 if (r != 0)
177 return r;
178
179 switch (a->type) {
112a0972
YW
180 case REQUEST_TYPE_ACTIVATE_LINK:
181 return 0;
40b12fa2
YW
182 case REQUEST_TYPE_ADDRESS:
183 return address_compare_func(a->address, b->address);
184 case REQUEST_TYPE_ADDRESS_LABEL:
185 case REQUEST_TYPE_BRIDGE_FDB:
186 case REQUEST_TYPE_BRIDGE_MDB:
709055da 187 case REQUEST_TYPE_NETDEV_STACKED:
40b12fa2
YW
188 return trivial_compare_func(a->object, b->object);
189 case REQUEST_TYPE_DHCP_SERVER:
ccffa166
YW
190 case REQUEST_TYPE_DHCP4_CLIENT:
191 case REQUEST_TYPE_DHCP6_CLIENT:
40b12fa2
YW
192 return 0;
193 case REQUEST_TYPE_IPV6_PROXY_NDP:
194 return in6_addr_compare_func(a->ipv6_proxy_ndp, b->ipv6_proxy_ndp);
ba4c7184
YW
195 case REQUEST_TYPE_NDISC:
196 return 0;
40b12fa2
YW
197 case REQUEST_TYPE_NEIGHBOR:
198 return neighbor_compare_func(a->neighbor, b->neighbor);
199 case REQUEST_TYPE_NEXTHOP:
200 return nexthop_compare_func(a->nexthop, b->nexthop);
201 case REQUEST_TYPE_ROUTE:
202 return route_compare_func(a->route, b->route);
a254fab2
YW
203 case REQUEST_TYPE_RADV:
204 return 0;
40b12fa2
YW
205 case REQUEST_TYPE_ROUTING_POLICY_RULE:
206 return routing_policy_rule_compare_func(a->rule, b->rule);
0fa8ee6c 207 case REQUEST_TYPE_SET_LINK:
9b682672 208 return trivial_compare_func(a->set_link_operation_ptr, b->set_link_operation_ptr);
1dec9d81
YW
209 case REQUEST_TYPE_TRAFFIC_CONTROL:
210 return traffic_control_compare_func(a->traffic_control, b->traffic_control);
68f52063
YW
211 case REQUEST_TYPE_UP_DOWN:
212 return 0;
40b12fa2 213 default:
04499a70 214 assert_not_reached();
40b12fa2
YW
215 }
216}
217
218DEFINE_PRIVATE_HASH_OPS_WITH_KEY_DESTRUCTOR(
219 request_hash_ops,
220 Request,
221 request_hash_func,
222 request_compare_func,
223 request_free);
224
19d9a5ad
YW
225int link_queue_request(
226 Link *link,
227 RequestType type,
228 void *object,
229 bool consume_object,
230 unsigned *message_counter,
231 link_netlink_message_handler_t netlink_handler,
232 Request **ret) {
233
234 _cleanup_(request_freep) Request *req = NULL;
0fa8ee6c 235 Request *existing;
19d9a5ad
YW
236 int r;
237
238 assert(link);
239 assert(link->manager);
240 assert(type >= 0 && type < _REQUEST_TYPE_MAX);
112a0972
YW
241 assert(IN_SET(type,
242 REQUEST_TYPE_ACTIVATE_LINK,
243 REQUEST_TYPE_DHCP_SERVER,
ccffa166
YW
244 REQUEST_TYPE_DHCP4_CLIENT,
245 REQUEST_TYPE_DHCP6_CLIENT,
ba4c7184 246 REQUEST_TYPE_NDISC,
a254fab2 247 REQUEST_TYPE_RADV,
68f52063
YW
248 REQUEST_TYPE_SET_LINK,
249 REQUEST_TYPE_UP_DOWN) ||
112a0972 250 object);
a254fab2
YW
251 assert(IN_SET(type,
252 REQUEST_TYPE_DHCP_SERVER,
ccffa166
YW
253 REQUEST_TYPE_DHCP4_CLIENT,
254 REQUEST_TYPE_DHCP6_CLIENT,
ba4c7184 255 REQUEST_TYPE_NDISC,
1dec9d81
YW
256 REQUEST_TYPE_RADV,
257 REQUEST_TYPE_TRAFFIC_CONTROL) ||
a254fab2 258 netlink_handler);
19d9a5ad
YW
259
260 req = new(Request, 1);
261 if (!req) {
262 if (consume_object)
263 request_free_object(type, object);
264 return -ENOMEM;
265 }
266
267 *req = (Request) {
40b12fa2 268 .link = link_ref(link),
19d9a5ad
YW
269 .type = type,
270 .object = object,
271 .consume_object = consume_object,
272 .message_counter = message_counter,
273 .netlink_handler = netlink_handler,
274 };
275
0fa8ee6c
YW
276 existing = ordered_set_get(link->manager->request_queue, req);
277 if (existing) {
278 /* To prevent from removing the existing request. */
40b12fa2 279 req->link = link_unref(req->link);
19d9a5ad 280
0fa8ee6c
YW
281 if (ret)
282 *ret = existing;
283 return 0;
40b12fa2 284 }
19d9a5ad 285
0fa8ee6c
YW
286 r = ordered_set_ensure_put(&link->manager->request_queue, &request_hash_ops, req);
287 if (r < 0)
288 return r;
289
19d9a5ad
YW
290 if (req->message_counter)
291 (*req->message_counter)++;
292
293 if (ret)
294 *ret = req;
295
296 TAKE_PTR(req);
40b12fa2 297 return 1;
19d9a5ad
YW
298}
299
300int manager_process_requests(sd_event_source *s, void *userdata) {
301 Manager *manager = userdata;
302 int r;
303
304 assert(manager);
305
306 for (;;) {
307 bool processed = false;
308 Request *req;
309
310 ORDERED_SET_FOREACH(req, manager->request_queue) {
89346ac6 311 switch (req->type) {
112a0972
YW
312 case REQUEST_TYPE_ACTIVATE_LINK:
313 r = request_process_activation(req);
314 break;
76c5a0f2
YW
315 case REQUEST_TYPE_ADDRESS:
316 r = request_process_address(req);
317 break;
354bc760
YW
318 case REQUEST_TYPE_ADDRESS_LABEL:
319 r = request_process_address_label(req);
320 break;
e5b35bf6
YW
321 case REQUEST_TYPE_BRIDGE_FDB:
322 r = request_process_bridge_fdb(req);
323 break;
9a038aac
YW
324 case REQUEST_TYPE_BRIDGE_MDB:
325 r = request_process_bridge_mdb(req);
326 break;
1d28a3cf
YW
327 case REQUEST_TYPE_DHCP_SERVER:
328 r = request_process_dhcp_server(req);
329 break;
ccffa166
YW
330 case REQUEST_TYPE_DHCP4_CLIENT:
331 r = request_process_dhcp4_client(req);
332 break;
333 case REQUEST_TYPE_DHCP6_CLIENT:
334 r = request_process_dhcp6_client(req);
335 break;
fdeba3f5
YW
336 case REQUEST_TYPE_IPV6_PROXY_NDP:
337 r = request_process_ipv6_proxy_ndp_address(req);
338 break;
ba4c7184
YW
339 case REQUEST_TYPE_NDISC:
340 r = request_process_ndisc(req);
341 break;
40ca350e
YW
342 case REQUEST_TYPE_NEIGHBOR:
343 r = request_process_neighbor(req);
344 break;
709055da
YW
345 case REQUEST_TYPE_NETDEV_STACKED:
346 r = request_process_stacked_netdev(req);
347 break;
76c5a0f2
YW
348 case REQUEST_TYPE_NEXTHOP:
349 r = request_process_nexthop(req);
350 break;
a254fab2
YW
351 case REQUEST_TYPE_RADV:
352 r = request_process_radv(req);
353 break;
76c5a0f2
YW
354 case REQUEST_TYPE_ROUTE:
355 r = request_process_route(req);
356 break;
0e5ef6be
YW
357 case REQUEST_TYPE_ROUTING_POLICY_RULE:
358 r = request_process_routing_policy_rule(req);
359 break;
0fa8ee6c
YW
360 case REQUEST_TYPE_SET_LINK:
361 r = request_process_set_link(req);
362 break;
1dec9d81
YW
363 case REQUEST_TYPE_TRAFFIC_CONTROL:
364 r = request_process_traffic_control(req);
365 break;
68f52063
YW
366 case REQUEST_TYPE_UP_DOWN:
367 r = request_process_link_up_or_down(req);
368 break;
19d9a5ad
YW
369 default:
370 return -EINVAL;
371 }
372 if (r < 0)
373 link_enter_failed(req->link);
374 if (r > 0) {
375 ordered_set_remove(manager->request_queue, req);
376 request_free(req);
377 processed = true;
378 }
379 }
380
381 if (!processed)
382 break;
383 }
384
385 return 0;
386}