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