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