]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/libsystemd/sd-rtnl/sd-rtnl.c
sd-rtnl: add sd_rtnl_message_enter_container()
[thirdparty/systemd.git] / src / libsystemd / sd-rtnl / sd-rtnl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <poll.h>
24
25 #include "macro.h"
26 #include "util.h"
27 #include "hashmap.h"
28
29 #include "sd-rtnl.h"
30 #include "rtnl-internal.h"
31 #include "rtnl-util.h"
32
33 static int sd_rtnl_new(sd_rtnl **ret) {
34 sd_rtnl *rtnl;
35
36 assert_return(ret, -EINVAL);
37
38 rtnl = new0(sd_rtnl, 1);
39 if (!rtnl)
40 return -ENOMEM;
41
42 rtnl->n_ref = REFCNT_INIT;
43
44 rtnl->fd = -1;
45
46 rtnl->sockaddr.nl.nl_family = AF_NETLINK;
47
48 rtnl->original_pid = getpid();
49
50 LIST_HEAD_INIT(rtnl->match_callbacks);
51
52 /* We guarantee that wqueue always has space for at least
53 * one entry */
54 rtnl->wqueue = new(sd_rtnl_message*, 1);
55 if (!rtnl->wqueue) {
56 free(rtnl);
57 return -ENOMEM;
58 }
59
60 *ret = rtnl;
61 return 0;
62 }
63
64 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
65 assert(rtnl);
66
67 /* We don't support people creating an rtnl connection and
68 * keeping it around over a fork(). Let's complain. */
69
70 return rtnl->original_pid != getpid();
71 }
72
73 int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) {
74 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
75 socklen_t addrlen;
76 int r;
77
78 assert_return(ret, -EINVAL);
79
80 r = sd_rtnl_new(&rtnl);
81 if (r < 0)
82 return r;
83
84 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
85 if (rtnl->fd < 0)
86 return -errno;
87
88 rtnl->sockaddr.nl.nl_groups = groups;
89
90 addrlen = sizeof(rtnl->sockaddr);
91
92 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
93 if (r < 0)
94 return -errno;
95
96 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
97 if (r < 0)
98 return r;
99
100 *ret = rtnl;
101 rtnl = NULL;
102
103 return 0;
104 }
105
106 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
107 if (rtnl)
108 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
109
110 return rtnl;
111 }
112
113 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
114 unsigned long refs;
115
116 if (!rtnl)
117 return NULL;
118
119 /*
120 * If our ref-cnt is exactly the number of internally queued messages
121 * plus the ref-cnt to be dropped, then we know there's no external
122 * reference to us. Hence, we look through all queued messages and if
123 * they also have no external references, we're about to drop the last
124 * ref. Flush the queues so the REFCNT_DEC() below will drop to 0.
125 * We must be careful not to introduce inter-message references or this
126 * logic will fall apart..
127 */
128
129 refs = rtnl->rqueue_size + rtnl->wqueue_size + 1;
130
131 if (REFCNT_GET(rtnl->n_ref) <= refs) {
132 struct match_callback *f;
133 bool q = true;
134 unsigned i;
135
136 for (i = 0; i < rtnl->rqueue_size; i++) {
137 if (REFCNT_GET(rtnl->rqueue[i]->n_ref) > 1) {
138 q = false;
139 break;
140 } else if (rtnl->rqueue[i]->rtnl != rtnl)
141 --refs;
142 }
143
144 if (q) {
145 for (i = 0; i < rtnl->wqueue_size; i++) {
146 if (REFCNT_GET(rtnl->wqueue[i]->n_ref) > 1) {
147 q = false;
148 break;
149 } else if (rtnl->wqueue[i]->rtnl != rtnl)
150 --refs;
151 }
152 }
153
154 if (q && REFCNT_GET(rtnl->n_ref) == refs) {
155 /* Drop our own ref early to avoid recursion from:
156 * sd_rtnl_message_unref()
157 * sd_rtnl_unref()
158 * These must enter sd_rtnl_unref() with a ref-cnt
159 * smaller than us. */
160 REFCNT_DEC(rtnl->n_ref);
161
162 for (i = 0; i < rtnl->rqueue_size; i++)
163 sd_rtnl_message_unref(rtnl->rqueue[i]);
164 free(rtnl->rqueue);
165
166 for (i = 0; i < rtnl->wqueue_size; i++)
167 sd_rtnl_message_unref(rtnl->wqueue[i]);
168 free(rtnl->wqueue);
169
170 assert_se(REFCNT_GET(rtnl->n_ref) == 0);
171
172 hashmap_free_free(rtnl->reply_callbacks);
173 prioq_free(rtnl->reply_callbacks_prioq);
174
175 while ((f = rtnl->match_callbacks)) {
176 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
177 free(f);
178 }
179
180 safe_close(rtnl->fd);
181 free(rtnl);
182
183 return NULL;
184 }
185 }
186
187 assert_se(REFCNT_GET(rtnl->n_ref) > 0);
188 REFCNT_DEC(rtnl->n_ref);
189
190 return NULL;
191 }
192
193 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
194 assert(rtnl);
195 assert(!rtnl_pid_changed(rtnl));
196 assert(m);
197 assert(m->hdr);
198
199 m->hdr->nlmsg_seq = rtnl->serial++;
200
201 rtnl_message_seal(m);
202
203 return;
204 }
205
206 int sd_rtnl_send(sd_rtnl *nl,
207 sd_rtnl_message *message,
208 uint32_t *serial) {
209 int r;
210
211 assert_return(nl, -EINVAL);
212 assert_return(!rtnl_pid_changed(nl), -ECHILD);
213 assert_return(message, -EINVAL);
214 assert_return(!message->sealed, -EPERM);
215
216 rtnl_seal_message(nl, message);
217
218 if (nl->wqueue_size <= 0) {
219 /* send directly */
220 r = socket_write_message(nl, message);
221 if (r < 0)
222 return r;
223 else if (r == 0) {
224 /* nothing was sent, so let's put it on
225 * the queue */
226 nl->wqueue[0] = sd_rtnl_message_ref(message);
227 nl->wqueue_size = 1;
228 }
229 } else {
230 sd_rtnl_message **q;
231
232 /* append to queue */
233 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
234 return -ENOBUFS;
235
236 q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
237 if (!q)
238 return -ENOMEM;
239
240 nl->wqueue = q;
241 q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
242 }
243
244 if (serial)
245 *serial = rtnl_message_get_serial(message);
246
247 return 1;
248 }
249
250 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
251 sd_rtnl_message *z = NULL;
252 int r;
253
254 assert(rtnl);
255 assert(message);
256
257 if (rtnl->rqueue_size > 0) {
258 /* Dispatch a queued message */
259
260 *message = rtnl->rqueue[0];
261 rtnl->rqueue_size --;
262 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
263
264 return 1;
265 }
266
267 /* Try to read a new message */
268 r = socket_read_message(rtnl, &z);
269 if (r <= 0)
270 return r;
271
272 *message = z;
273
274 return 1;
275 }
276
277 static int dispatch_wqueue(sd_rtnl *rtnl) {
278 int r, ret = 0;
279
280 assert(rtnl);
281
282 while (rtnl->wqueue_size > 0) {
283 r = socket_write_message(rtnl, rtnl->wqueue[0]);
284 if (r < 0)
285 return r;
286 else if (r == 0)
287 /* Didn't do anything this time */
288 return ret;
289 else {
290 /* see equivalent in sd-bus.c */
291 sd_rtnl_message_unref(rtnl->wqueue[0]);
292 rtnl->wqueue_size --;
293 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
294
295 ret = 1;
296 }
297 }
298
299 return ret;
300 }
301
302 static int process_timeout(sd_rtnl *rtnl) {
303 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
304 struct reply_callback *c;
305 usec_t n;
306 int r;
307
308 assert(rtnl);
309
310 c = prioq_peek(rtnl->reply_callbacks_prioq);
311 if (!c)
312 return 0;
313
314 n = now(CLOCK_MONOTONIC);
315 if (c->timeout > n)
316 return 0;
317
318 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
319 if (r < 0)
320 return r;
321
322 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
323 hashmap_remove(rtnl->reply_callbacks, &c->serial);
324
325 r = c->callback(rtnl, m, c->userdata);
326 free(c);
327
328 return r < 0 ? r : 1;
329 }
330
331 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
332 struct reply_callback *c;
333 uint64_t serial;
334 int r;
335
336 assert(rtnl);
337 assert(m);
338
339 if (sd_rtnl_message_is_broadcast(m))
340 return 0;
341
342 serial = rtnl_message_get_serial(m);
343 c = hashmap_remove(rtnl->reply_callbacks, &serial);
344 if (!c)
345 return 0;
346
347 if (c->timeout != 0)
348 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
349
350 r = c->callback(rtnl, m, c->userdata);
351 free(c);
352
353 return r;
354 }
355
356 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
357 struct match_callback *c;
358 uint16_t type;
359 int r;
360
361 assert(rtnl);
362 assert(m);
363
364 r = sd_rtnl_message_get_type(m, &type);
365 if (r < 0)
366 return r;
367
368 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
369 if (type == c->type) {
370 r = c->callback(rtnl, m, c->userdata);
371 if (r != 0)
372 return r;
373 }
374 }
375
376 return 0;
377 }
378
379 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
380 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
381 int r;
382
383 assert(rtnl);
384
385 r = process_timeout(rtnl);
386 if (r != 0)
387 goto null_message;
388
389 r = dispatch_wqueue(rtnl);
390 if (r != 0)
391 goto null_message;
392
393 r = dispatch_rqueue(rtnl, &m);
394 if (r < 0)
395 return r;
396 if (!m)
397 goto null_message;
398
399 r = process_reply(rtnl, m);
400 if (r != 0)
401 goto null_message;
402
403 r = process_match(rtnl, m);
404 if (r != 0)
405 goto null_message;
406
407 if (ret) {
408 *ret = m;
409 m = NULL;
410
411 return 1;
412 }
413
414 return 1;
415
416 null_message:
417 if (r >= 0 && ret)
418 *ret = NULL;
419
420 return r;
421 }
422
423 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
424 RTNL_DONT_DESTROY(rtnl);
425 int r;
426
427 assert_return(rtnl, -EINVAL);
428 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
429 assert_return(!rtnl->processing, -EBUSY);
430
431 rtnl->processing = true;
432 r = process_running(rtnl, ret);
433 rtnl->processing = false;
434
435 return r;
436 }
437
438 static usec_t calc_elapse(uint64_t usec) {
439 if (usec == (uint64_t) -1)
440 return 0;
441
442 if (usec == 0)
443 usec = RTNL_DEFAULT_TIMEOUT;
444
445 return now(CLOCK_MONOTONIC) + usec;
446 }
447
448 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
449 struct pollfd p[1] = {};
450 struct timespec ts;
451 usec_t m = (usec_t) -1;
452 int r, e;
453
454 assert(rtnl);
455
456 e = sd_rtnl_get_events(rtnl);
457 if (e < 0)
458 return e;
459
460 if (need_more)
461 /* Caller wants more data, and doesn't care about
462 * what's been read or any other timeouts. */
463 return e |= POLLIN;
464 else {
465 usec_t until;
466 /* Caller wants to process if there is something to
467 * process, but doesn't care otherwise */
468
469 r = sd_rtnl_get_timeout(rtnl, &until);
470 if (r < 0)
471 return r;
472 if (r > 0) {
473 usec_t nw;
474 nw = now(CLOCK_MONOTONIC);
475 m = until > nw ? until - nw : 0;
476 }
477 }
478
479 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
480 m = timeout_usec;
481
482 p[0].fd = rtnl->fd;
483 p[0].events = e;
484
485 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
486 if (r < 0)
487 return -errno;
488
489 return r > 0 ? 1 : 0;
490 }
491
492 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
493 assert_return(nl, -EINVAL);
494 assert_return(!rtnl_pid_changed(nl), -ECHILD);
495
496 if (nl->rqueue_size > 0)
497 return 0;
498
499 return rtnl_poll(nl, false, timeout_usec);
500 }
501
502 static int timeout_compare(const void *a, const void *b) {
503 const struct reply_callback *x = a, *y = b;
504
505 if (x->timeout != 0 && y->timeout == 0)
506 return -1;
507
508 if (x->timeout == 0 && y->timeout != 0)
509 return 1;
510
511 if (x->timeout < y->timeout)
512 return -1;
513
514 if (x->timeout > y->timeout)
515 return 1;
516
517 return 0;
518 }
519
520 int sd_rtnl_call_async(sd_rtnl *nl,
521 sd_rtnl_message *m,
522 sd_rtnl_message_handler_t callback,
523 void *userdata,
524 uint64_t usec,
525 uint32_t *serial) {
526 struct reply_callback *c;
527 uint32_t s;
528 int r, k;
529
530 assert_return(nl, -EINVAL);
531 assert_return(m, -EINVAL);
532 assert_return(callback, -EINVAL);
533 assert_return(!rtnl_pid_changed(nl), -ECHILD);
534
535 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
536 if (r < 0)
537 return r;
538
539 if (usec != (uint64_t) -1) {
540 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
541 if (r < 0)
542 return r;
543 }
544
545 c = new0(struct reply_callback, 1);
546 if (!c)
547 return -ENOMEM;
548
549 c->callback = callback;
550 c->userdata = userdata;
551 c->timeout = calc_elapse(usec);
552
553 k = sd_rtnl_send(nl, m, &s);
554 if (k < 0) {
555 free(c);
556 return k;
557 }
558
559 c->serial = s;
560
561 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
562 if (r < 0) {
563 free(c);
564 return r;
565 }
566
567 if (c->timeout != 0) {
568 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
569 if (r > 0) {
570 c->timeout = 0;
571 sd_rtnl_call_async_cancel(nl, c->serial);
572 return r;
573 }
574 }
575
576 if (serial)
577 *serial = s;
578
579 return k;
580 }
581
582 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
583 struct reply_callback *c;
584 uint64_t s = serial;
585
586 assert_return(nl, -EINVAL);
587 assert_return(serial != 0, -EINVAL);
588 assert_return(!rtnl_pid_changed(nl), -ECHILD);
589
590 c = hashmap_remove(nl->reply_callbacks, &s);
591 if (!c)
592 return 0;
593
594 if (c->timeout != 0)
595 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
596
597 free(c);
598 return 1;
599 }
600
601 int sd_rtnl_call(sd_rtnl *nl,
602 sd_rtnl_message *message,
603 uint64_t usec,
604 sd_rtnl_message **ret) {
605 usec_t timeout;
606 uint32_t serial;
607 bool room = false;
608 int r;
609
610 assert_return(nl, -EINVAL);
611 assert_return(!rtnl_pid_changed(nl), -ECHILD);
612 assert_return(message, -EINVAL);
613
614 r = sd_rtnl_send(nl, message, &serial);
615 if (r < 0)
616 return r;
617
618 timeout = calc_elapse(usec);
619
620 for (;;) {
621 usec_t left;
622 _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
623
624 if (!room) {
625 sd_rtnl_message **q;
626
627 if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
628 return -ENOBUFS;
629
630 /* Make sure there's room for queueing this
631 * locally, before we read the message */
632
633 q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
634 if (!q)
635 return -ENOMEM;
636
637 nl->rqueue = q;
638 room = true;
639 }
640
641 r = socket_read_message(nl, &incoming);
642 if (r < 0)
643 return r;
644 if (incoming) {
645 uint32_t received_serial = rtnl_message_get_serial(incoming);
646
647 if (received_serial == serial) {
648 r = sd_rtnl_message_get_errno(incoming);
649 if (r < 0)
650 return r;
651
652 if (ret) {
653 *ret = incoming;
654 incoming = NULL;
655 }
656
657 return 1;
658 }
659
660 /* Room was allocated on the queue above */
661 nl->rqueue[nl->rqueue_size ++] = incoming;
662 incoming = NULL;
663 room = false;
664
665 /* Try to read more, right away */
666 continue;
667 }
668 if (r != 0)
669 continue;
670
671 if (timeout > 0) {
672 usec_t n;
673
674 n = now(CLOCK_MONOTONIC);
675 if (n >= timeout)
676 return -ETIMEDOUT;
677
678 left = timeout - n;
679 } else
680 left = (uint64_t) -1;
681
682 r = rtnl_poll(nl, true, left);
683 if (r < 0)
684 return r;
685
686 r = dispatch_wqueue(nl);
687 if (r < 0)
688 return r;
689 }
690 }
691
692 int sd_rtnl_flush(sd_rtnl *rtnl) {
693 int r;
694
695 assert_return(rtnl, -EINVAL);
696 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
697
698 if (rtnl->wqueue_size <= 0)
699 return 0;
700
701 for (;;) {
702 r = dispatch_wqueue(rtnl);
703 if (r < 0)
704 return r;
705
706 if (rtnl->wqueue_size <= 0)
707 return 0;
708
709 r = rtnl_poll(rtnl, false, (uint64_t) -1);
710 if (r < 0)
711 return r;
712 }
713 }
714
715 int sd_rtnl_get_events(sd_rtnl *rtnl) {
716 int flags = 0;
717
718 assert_return(rtnl, -EINVAL);
719 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
720
721 if (rtnl->rqueue_size <= 0)
722 flags |= POLLIN;
723 if (rtnl->wqueue_size > 0)
724 flags |= POLLOUT;
725
726 return flags;
727 }
728
729 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
730 struct reply_callback *c;
731
732 assert_return(rtnl, -EINVAL);
733 assert_return(timeout_usec, -EINVAL);
734 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
735
736 if (rtnl->rqueue_size > 0) {
737 *timeout_usec = 0;
738 return 1;
739 }
740
741 c = prioq_peek(rtnl->reply_callbacks_prioq);
742 if (!c) {
743 *timeout_usec = (uint64_t) -1;
744 return 0;
745 }
746
747 *timeout_usec = c->timeout;
748
749 return 1;
750 }
751
752 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
753 sd_rtnl *rtnl = userdata;
754 int r;
755
756 assert(rtnl);
757
758 r = sd_rtnl_process(rtnl, NULL);
759 if (r < 0)
760 return r;
761
762 return 1;
763 }
764
765 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
766 sd_rtnl *rtnl = userdata;
767 int r;
768
769 assert(rtnl);
770
771 r = sd_rtnl_process(rtnl, NULL);
772 if (r < 0)
773 return r;
774
775 return 1;
776 }
777
778 static int prepare_callback(sd_event_source *s, void *userdata) {
779 sd_rtnl *rtnl = userdata;
780 int r, e;
781 usec_t until;
782
783 assert(s);
784 assert(rtnl);
785
786 e = sd_rtnl_get_events(rtnl);
787 if (e < 0)
788 return e;
789
790 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
791 if (r < 0)
792 return r;
793
794 r = sd_rtnl_get_timeout(rtnl, &until);
795 if (r < 0)
796 return r;
797 if (r > 0) {
798 int j;
799
800 j = sd_event_source_set_time(rtnl->time_event_source, until);
801 if (j < 0)
802 return j;
803 }
804
805 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
806 if (r < 0)
807 return r;
808
809 return 1;
810 }
811
812 static int exit_callback(sd_event_source *event, void *userdata) {
813 sd_rtnl *rtnl = userdata;
814
815 assert(event);
816
817 sd_rtnl_flush(rtnl);
818
819 return 1;
820 }
821
822 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
823 int r;
824
825 assert_return(rtnl, -EINVAL);
826 assert_return(!rtnl->event, -EBUSY);
827
828 assert(!rtnl->io_event_source);
829 assert(!rtnl->time_event_source);
830
831 if (event)
832 rtnl->event = sd_event_ref(event);
833 else {
834 r = sd_event_default(&rtnl->event);
835 if (r < 0)
836 return r;
837 }
838
839 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
840 if (r < 0)
841 goto fail;
842
843 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
844 if (r < 0)
845 goto fail;
846
847 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
848 if (r < 0)
849 goto fail;
850
851 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
852 if (r < 0)
853 goto fail;
854
855 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
856 if (r < 0)
857 goto fail;
858
859 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
860 if (r < 0)
861 goto fail;
862
863 return 0;
864
865 fail:
866 sd_rtnl_detach_event(rtnl);
867 return r;
868 }
869
870 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
871 assert_return(rtnl, -EINVAL);
872 assert_return(rtnl->event, -ENXIO);
873
874 if (rtnl->io_event_source)
875 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
876
877 if (rtnl->time_event_source)
878 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
879
880 if (rtnl->exit_event_source)
881 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
882
883 if (rtnl->event)
884 rtnl->event = sd_event_unref(rtnl->event);
885
886 return 0;
887 }
888
889 int sd_rtnl_add_match(sd_rtnl *rtnl,
890 uint16_t type,
891 sd_rtnl_message_handler_t callback,
892 void *userdata) {
893 struct match_callback *c;
894
895 assert_return(rtnl, -EINVAL);
896 assert_return(callback, -EINVAL);
897 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
898 assert_return(rtnl_message_type_is_link(type) ||
899 rtnl_message_type_is_addr(type) ||
900 rtnl_message_type_is_route(type), -ENOTSUP);
901
902 c = new0(struct match_callback, 1);
903 if (!c)
904 return -ENOMEM;
905
906 c->callback = callback;
907 c->type = type;
908 c->userdata = userdata;
909
910 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
911
912 return 0;
913 }
914
915 int sd_rtnl_remove_match(sd_rtnl *rtnl,
916 uint16_t type,
917 sd_rtnl_message_handler_t callback,
918 void *userdata) {
919 struct match_callback *c;
920
921 assert_return(rtnl, -EINVAL);
922 assert_return(callback, -EINVAL);
923 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
924
925 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
926 if (c->callback == callback && c->type == type && c->userdata == userdata) {
927 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
928 free(c);
929
930 return 1;
931 }
932
933 return 0;
934 }