chiark / gitweb /
sd-rtnl: add sd_rtnl_message_enter_container()
[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 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 }