chiark / gitweb /
60426576422cc9ed25319ca774415b7d1a03e6d3
[elogind.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 int sd_rtnl_send(sd_rtnl *nl,
194                  sd_rtnl_message *message,
195                  uint32_t *serial) {
196         int r;
197
198         assert_return(nl, -EINVAL);
199         assert_return(!rtnl_pid_changed(nl), -ECHILD);
200         assert_return(message, -EINVAL);
201
202         r = rtnl_message_seal(nl, message);
203         if (r < 0)
204                 return r;
205
206         if (nl->wqueue_size <= 0) {
207                 /* send directly */
208                 r = socket_write_message(nl, message);
209                 if (r < 0)
210                         return r;
211                 else if (r == 0) {
212                         /* nothing was sent, so let's put it on
213                          * the queue */
214                         nl->wqueue[0] = sd_rtnl_message_ref(message);
215                         nl->wqueue_size = 1;
216                 }
217         } else {
218                 sd_rtnl_message **q;
219
220                 /* append to queue */
221                 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
222                         return -ENOBUFS;
223
224                 q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
225                 if (!q)
226                         return -ENOMEM;
227
228                 nl->wqueue = q;
229                 q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
230         }
231
232         if (serial)
233                 *serial = rtnl_message_get_serial(message);
234
235         return 1;
236 }
237
238 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
239         sd_rtnl_message *z = NULL;
240         int r;
241
242         assert(rtnl);
243         assert(message);
244
245         if (rtnl->rqueue_size > 0) {
246                 /* Dispatch a queued message */
247
248                 *message = rtnl->rqueue[0];
249                 rtnl->rqueue_size --;
250                 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
251
252                 return 1;
253         }
254
255         /* Try to read a new message */
256         r = socket_read_message(rtnl, &z);
257         if (r < 0)
258                 return r;
259         if (r == 0)
260                 return 0;
261
262         *message = z;
263
264         return 1;
265 }
266
267 static int dispatch_wqueue(sd_rtnl *rtnl) {
268         int r, ret = 0;
269
270         assert(rtnl);
271
272         while (rtnl->wqueue_size > 0) {
273                 r = socket_write_message(rtnl, rtnl->wqueue[0]);
274                 if (r < 0)
275                         return r;
276                 else if (r == 0)
277                         /* Didn't do anything this time */
278                         return ret;
279                 else {
280                         /* see equivalent in sd-bus.c */
281                         sd_rtnl_message_unref(rtnl->wqueue[0]);
282                         rtnl->wqueue_size --;
283                         memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
284
285                         ret = 1;
286                 }
287         }
288
289         return ret;
290 }
291
292 static int process_timeout(sd_rtnl *rtnl) {
293         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
294         struct reply_callback *c;
295         usec_t n;
296         int r;
297
298         assert(rtnl);
299
300         c = prioq_peek(rtnl->reply_callbacks_prioq);
301         if (!c)
302                 return 0;
303
304         n = now(CLOCK_MONOTONIC);
305         if (c->timeout > n)
306                 return 0;
307
308         r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
309         if (r < 0)
310                 return r;
311
312         assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
313         hashmap_remove(rtnl->reply_callbacks, &c->serial);
314
315         r = c->callback(rtnl, m, c->userdata);
316         free(c);
317
318         return r < 0 ? r : 1;
319 }
320
321 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
322         struct reply_callback *c;
323         uint64_t serial;
324         int r;
325
326         assert(rtnl);
327         assert(m);
328
329         if (sd_rtnl_message_is_broadcast(m))
330                 return 0;
331
332         serial = rtnl_message_get_serial(m);
333         c = hashmap_remove(rtnl->reply_callbacks, &serial);
334         if (!c)
335                 return 0;
336
337         if (c->timeout != 0)
338                 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
339
340         r = c->callback(rtnl, m, c->userdata);
341         free(c);
342
343         return r;
344 }
345
346 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
347         struct match_callback *c;
348         uint16_t type;
349         int r;
350
351         assert(rtnl);
352         assert(m);
353
354         r = sd_rtnl_message_get_type(m, &type);
355         if (r < 0)
356                 return r;
357
358         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
359                 if (type == c->type) {
360                         r = c->callback(rtnl, m, c->userdata);
361                         if (r != 0)
362                                 return r;
363                 }
364         }
365
366         return 0;
367 }
368
369 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
370         _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
371         int r;
372
373         assert(rtnl);
374
375         r = process_timeout(rtnl);
376         if (r != 0)
377                 goto null_message;
378
379         r = dispatch_wqueue(rtnl);
380         if (r != 0)
381                 goto null_message;
382
383         r = dispatch_rqueue(rtnl, &m);
384         if (r < 0)
385                 return r;
386         if (!m)
387                 goto null_message;
388
389         r = process_reply(rtnl, m);
390         if (r != 0)
391                 goto null_message;
392
393         r = process_match(rtnl, m);
394         if (r != 0)
395                 goto null_message;
396
397         if (ret) {
398                 *ret = m;
399                 m = NULL;
400
401                 return 1;
402         }
403
404         return 1;
405
406 null_message:
407         if (r >= 0 && ret)
408                 *ret = NULL;
409
410         return r;
411 }
412
413 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
414         RTNL_DONT_DESTROY(rtnl);
415         int r;
416
417         assert_return(rtnl, -EINVAL);
418         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
419         assert_return(!rtnl->processing, -EBUSY);
420
421         rtnl->processing = true;
422         r = process_running(rtnl, ret);
423         rtnl->processing = false;
424
425         return r;
426 }
427
428 static usec_t calc_elapse(uint64_t usec) {
429         if (usec == (uint64_t) -1)
430                 return 0;
431
432         if (usec == 0)
433                 usec = RTNL_DEFAULT_TIMEOUT;
434
435         return now(CLOCK_MONOTONIC) + usec;
436 }
437
438 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
439         struct pollfd p[1] = {};
440         struct timespec ts;
441         usec_t m = (usec_t) -1;
442         int r, e;
443
444         assert(rtnl);
445
446         e = sd_rtnl_get_events(rtnl);
447         if (e < 0)
448                 return e;
449
450         if (need_more)
451                 /* Caller wants more data, and doesn't care about
452                  * what's been read or any other timeouts. */
453                 return e |= POLLIN;
454         else {
455                 usec_t until;
456                 /* Caller wants to process if there is something to
457                  * process, but doesn't care otherwise */
458
459                 r = sd_rtnl_get_timeout(rtnl, &until);
460                 if (r < 0)
461                         return r;
462                 if (r > 0) {
463                         usec_t nw;
464                         nw = now(CLOCK_MONOTONIC);
465                         m = until > nw ? until - nw : 0;
466                 }
467         }
468
469         if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
470                 m = timeout_usec;
471
472         p[0].fd = rtnl->fd;
473         p[0].events = e;
474
475         r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
476         if (r < 0)
477                 return -errno;
478
479         return r > 0 ? 1 : 0;
480 }
481
482 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
483         assert_return(nl, -EINVAL);
484         assert_return(!rtnl_pid_changed(nl), -ECHILD);
485
486         if (nl->rqueue_size > 0)
487                 return 0;
488
489         return rtnl_poll(nl, false, timeout_usec);
490 }
491
492 static int timeout_compare(const void *a, const void *b) {
493         const struct reply_callback *x = a, *y = b;
494
495         if (x->timeout != 0 && y->timeout == 0)
496                 return -1;
497
498         if (x->timeout == 0 && y->timeout != 0)
499                 return 1;
500
501         if (x->timeout < y->timeout)
502                 return -1;
503
504         if (x->timeout > y->timeout)
505                 return 1;
506
507         return 0;
508 }
509
510 int sd_rtnl_call_async(sd_rtnl *nl,
511                        sd_rtnl_message *m,
512                        sd_rtnl_message_handler_t callback,
513                        void *userdata,
514                        uint64_t usec,
515                        uint32_t *serial) {
516         struct reply_callback *c;
517         uint32_t s;
518         int r, k;
519
520         assert_return(nl, -EINVAL);
521         assert_return(m, -EINVAL);
522         assert_return(callback, -EINVAL);
523         assert_return(!rtnl_pid_changed(nl), -ECHILD);
524
525         r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
526         if (r < 0)
527                 return r;
528
529         if (usec != (uint64_t) -1) {
530                 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
531                 if (r < 0)
532                         return r;
533         }
534
535         c = new0(struct reply_callback, 1);
536         if (!c)
537                 return -ENOMEM;
538
539         c->callback = callback;
540         c->userdata = userdata;
541         c->timeout = calc_elapse(usec);
542
543         k = sd_rtnl_send(nl, m, &s);
544         if (k < 0) {
545                 free(c);
546                 return k;
547         }
548
549         c->serial = s;
550
551         r = hashmap_put(nl->reply_callbacks, &c->serial, c);
552         if (r < 0) {
553                 free(c);
554                 return r;
555         }
556
557         if (c->timeout != 0) {
558                 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
559                 if (r > 0) {
560                         c->timeout = 0;
561                         sd_rtnl_call_async_cancel(nl, c->serial);
562                         return r;
563                 }
564         }
565
566         if (serial)
567                 *serial = s;
568
569         return k;
570 }
571
572 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
573         struct reply_callback *c;
574         uint64_t s = serial;
575
576         assert_return(nl, -EINVAL);
577         assert_return(serial != 0, -EINVAL);
578         assert_return(!rtnl_pid_changed(nl), -ECHILD);
579
580         c = hashmap_remove(nl->reply_callbacks, &s);
581         if (!c)
582                 return 0;
583
584         if (c->timeout != 0)
585                 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
586
587         free(c);
588         return 1;
589 }
590
591 int sd_rtnl_call(sd_rtnl *nl,
592                 sd_rtnl_message *message,
593                 uint64_t usec,
594                 sd_rtnl_message **ret) {
595         usec_t timeout;
596         uint32_t serial;
597         bool room = false;
598         int r;
599
600         assert_return(nl, -EINVAL);
601         assert_return(!rtnl_pid_changed(nl), -ECHILD);
602         assert_return(message, -EINVAL);
603
604         r = sd_rtnl_send(nl, message, &serial);
605         if (r < 0)
606                 return r;
607
608         timeout = calc_elapse(usec);
609
610         for (;;) {
611                 usec_t left;
612                 _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
613
614                 if (!room) {
615                         sd_rtnl_message **q;
616
617                         if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
618                                 return -ENOBUFS;
619
620                         /* Make sure there's room for queueing this
621                          * locally, before we read the message */
622
623                         q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
624                         if (!q)
625                                 return -ENOMEM;
626
627                         nl->rqueue = q;
628                         room = true;
629                 }
630
631                 r = socket_read_message(nl, &incoming);
632                 if (r < 0)
633                         return r;
634                 if (incoming) {
635                         uint32_t received_serial = rtnl_message_get_serial(incoming);
636
637                         if (received_serial == serial) {
638                                 r = sd_rtnl_message_get_errno(incoming);
639                                 if (r < 0)
640                                         return r;
641
642                                 if (ret) {
643                                         *ret = incoming;
644                                         incoming = NULL;
645                                 }
646
647                                 return 1;
648                         }
649
650                         /* Room was allocated on the queue above */
651                         nl->rqueue[nl->rqueue_size ++] = incoming;
652                         incoming = NULL;
653                         room = false;
654
655                         /* Try to read more, right away */
656                         continue;
657                 }
658                 if (r != 0)
659                         continue;
660
661                 if (timeout > 0) {
662                         usec_t n;
663
664                         n = now(CLOCK_MONOTONIC);
665                         if (n >= timeout)
666                                 return -ETIMEDOUT;
667
668                         left = timeout - n;
669                 } else
670                         left = (uint64_t) -1;
671
672                 r = rtnl_poll(nl, true, left);
673                 if (r < 0)
674                         return r;
675
676                 r = dispatch_wqueue(nl);
677                 if (r < 0)
678                         return r;
679         }
680 }
681
682 int sd_rtnl_flush(sd_rtnl *rtnl) {
683         int r;
684
685         assert_return(rtnl, -EINVAL);
686         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
687
688         if (rtnl->wqueue_size <= 0)
689                 return 0;
690
691         for (;;) {
692                 r = dispatch_wqueue(rtnl);
693                 if (r < 0)
694                         return r;
695
696                 if (rtnl->wqueue_size <= 0)
697                         return 0;
698
699                 r = rtnl_poll(rtnl, false, (uint64_t) -1);
700                 if (r < 0)
701                         return r;
702         }
703 }
704
705 int sd_rtnl_get_events(sd_rtnl *rtnl) {
706         int flags = 0;
707
708         assert_return(rtnl, -EINVAL);
709         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
710
711         if (rtnl->rqueue_size <= 0)
712                 flags |= POLLIN;
713         if (rtnl->wqueue_size > 0)
714                 flags |= POLLOUT;
715
716         return flags;
717 }
718
719 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
720         struct reply_callback *c;
721
722         assert_return(rtnl, -EINVAL);
723         assert_return(timeout_usec, -EINVAL);
724         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
725
726         if (rtnl->rqueue_size > 0) {
727                 *timeout_usec = 0;
728                 return 1;
729         }
730
731         c = prioq_peek(rtnl->reply_callbacks_prioq);
732         if (!c) {
733                 *timeout_usec = (uint64_t) -1;
734                 return 0;
735         }
736
737         *timeout_usec = c->timeout;
738
739         return 1;
740 }
741
742 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
743         sd_rtnl *rtnl = userdata;
744         int r;
745
746         assert(rtnl);
747
748         r = sd_rtnl_process(rtnl, NULL);
749         if (r < 0)
750                 return r;
751
752         return 1;
753 }
754
755 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
756         sd_rtnl *rtnl = userdata;
757         int r;
758
759         assert(rtnl);
760
761         r = sd_rtnl_process(rtnl, NULL);
762         if (r < 0)
763                 return r;
764
765         return 1;
766 }
767
768 static int prepare_callback(sd_event_source *s, void *userdata) {
769         sd_rtnl *rtnl = userdata;
770         int r, e;
771         usec_t until;
772
773         assert(s);
774         assert(rtnl);
775
776         e = sd_rtnl_get_events(rtnl);
777         if (e < 0)
778                 return e;
779
780         r = sd_event_source_set_io_events(rtnl->io_event_source, e);
781         if (r < 0)
782                 return r;
783
784         r = sd_rtnl_get_timeout(rtnl, &until);
785         if (r < 0)
786                 return r;
787         if (r > 0) {
788                 int j;
789
790                 j = sd_event_source_set_time(rtnl->time_event_source, until);
791                 if (j < 0)
792                         return j;
793         }
794
795         r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
796         if (r < 0)
797                 return r;
798
799         return 1;
800 }
801
802 static int exit_callback(sd_event_source *event, void *userdata) {
803         sd_rtnl *rtnl = userdata;
804
805         assert(event);
806
807         sd_rtnl_flush(rtnl);
808
809         return 1;
810 }
811
812 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
813         int r;
814
815         assert_return(rtnl, -EINVAL);
816         assert_return(!rtnl->event, -EBUSY);
817
818         assert(!rtnl->io_event_source);
819         assert(!rtnl->time_event_source);
820
821         if (event)
822                 rtnl->event = sd_event_ref(event);
823         else {
824                 r = sd_event_default(&rtnl->event);
825                 if (r < 0)
826                         return r;
827         }
828
829         r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
830         if (r < 0)
831                 goto fail;
832
833         r = sd_event_source_set_priority(rtnl->io_event_source, priority);
834         if (r < 0)
835                 goto fail;
836
837         r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
838         if (r < 0)
839                 goto fail;
840
841         r = sd_event_add_monotonic(rtnl->event, &rtnl->time_event_source, 0, 0, time_callback, rtnl);
842         if (r < 0)
843                 goto fail;
844
845         r = sd_event_source_set_priority(rtnl->time_event_source, priority);
846         if (r < 0)
847                 goto fail;
848
849         r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
850         if (r < 0)
851                 goto fail;
852
853         return 0;
854
855 fail:
856         sd_rtnl_detach_event(rtnl);
857         return r;
858 }
859
860 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
861         assert_return(rtnl, -EINVAL);
862         assert_return(rtnl->event, -ENXIO);
863
864         if (rtnl->io_event_source)
865                 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
866
867         if (rtnl->time_event_source)
868                 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
869
870         if (rtnl->exit_event_source)
871                 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
872
873         if (rtnl->event)
874                 rtnl->event = sd_event_unref(rtnl->event);
875
876         return 0;
877 }
878
879 int sd_rtnl_add_match(sd_rtnl *rtnl,
880                       uint16_t type,
881                       sd_rtnl_message_handler_t callback,
882                       void *userdata) {
883         struct match_callback *c;
884
885         assert_return(rtnl, -EINVAL);
886         assert_return(callback, -EINVAL);
887         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
888         assert_return(rtnl_message_type_is_link(type) ||
889                       rtnl_message_type_is_addr(type) ||
890                       rtnl_message_type_is_route(type), -ENOTSUP);
891
892         c = new0(struct match_callback, 1);
893         if (!c)
894                 return -ENOMEM;
895
896         c->callback = callback;
897         c->type = type;
898         c->userdata = userdata;
899
900         LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
901
902         return 0;
903 }
904
905 int sd_rtnl_remove_match(sd_rtnl *rtnl,
906                          uint16_t type,
907                          sd_rtnl_message_handler_t callback,
908                          void *userdata) {
909         struct match_callback *c;
910
911         assert_return(rtnl, -EINVAL);
912         assert_return(callback, -EINVAL);
913         assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
914
915         LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
916                 if (c->callback == callback && c->type == type && c->userdata == userdata) {
917                         LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);
918                         free(c);
919
920                         return 1;
921                 }
922
923         return 0;
924 }