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