1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Tom Gundersen <teg@jklm.no>
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.
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.
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/>.
22 #include <sys/socket.h>
30 #include "rtnl-internal.h"
31 #include "rtnl-util.h"
33 static int sd_rtnl_new(sd_rtnl **ret) {
36 assert_return(ret, -EINVAL);
38 rtnl = new0(sd_rtnl, 1);
42 rtnl->n_ref = REFCNT_INIT;
46 rtnl->sockaddr.nl.nl_family = AF_NETLINK;
48 rtnl->original_pid = getpid();
50 LIST_HEAD_INIT(rtnl->match_callbacks);
52 /* We guarantee that wqueue always has space for at least
54 rtnl->wqueue = new(sd_rtnl_message*, 1);
64 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
67 /* We don't support people creating an rtnl connection and
68 * keeping it around over a fork(). Let's complain. */
70 return rtnl->original_pid != getpid();
73 int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) {
74 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
78 assert_return(ret, -EINVAL);
80 r = sd_rtnl_new(&rtnl);
84 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
88 rtnl->sockaddr.nl.nl_groups = groups;
90 addrlen = sizeof(rtnl->sockaddr);
92 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
96 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
106 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
108 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
113 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
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..
129 refs = rtnl->rqueue_size + rtnl->wqueue_size + 1;
131 if (REFCNT_GET(rtnl->n_ref) <= refs) {
132 struct match_callback *f;
136 for (i = 0; i < rtnl->rqueue_size; i++) {
137 if (REFCNT_GET(rtnl->rqueue[i]->n_ref) > 1) {
140 } else if (rtnl->rqueue[i]->rtnl != rtnl)
145 for (i = 0; i < rtnl->wqueue_size; i++) {
146 if (REFCNT_GET(rtnl->wqueue[i]->n_ref) > 1) {
149 } else if (rtnl->wqueue[i]->rtnl != rtnl)
154 if (q && REFCNT_GET(rtnl->n_ref) == refs) {
155 /* Drop our own ref early to avoid recursion from:
156 * sd_rtnl_message_unref()
158 * These must enter sd_rtnl_unref() with a ref-cnt
159 * smaller than us. */
160 REFCNT_DEC(rtnl->n_ref);
162 for (i = 0; i < rtnl->rqueue_size; i++)
163 sd_rtnl_message_unref(rtnl->rqueue[i]);
166 for (i = 0; i < rtnl->wqueue_size; i++)
167 sd_rtnl_message_unref(rtnl->wqueue[i]);
170 assert_se(REFCNT_GET(rtnl->n_ref) == 0);
172 hashmap_free_free(rtnl->reply_callbacks);
173 prioq_free(rtnl->reply_callbacks_prioq);
175 while ((f = rtnl->match_callbacks)) {
176 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
180 safe_close(rtnl->fd);
187 assert_se(REFCNT_GET(rtnl->n_ref) > 0);
188 REFCNT_DEC(rtnl->n_ref);
193 int sd_rtnl_send(sd_rtnl *nl,
194 sd_rtnl_message *message,
198 assert_return(nl, -EINVAL);
199 assert_return(!rtnl_pid_changed(nl), -ECHILD);
200 assert_return(message, -EINVAL);
202 r = rtnl_message_seal(nl, message);
206 if (nl->wqueue_size <= 0) {
208 r = socket_write_message(nl, message);
212 /* nothing was sent, so let's put it on
214 nl->wqueue[0] = sd_rtnl_message_ref(message);
220 /* append to queue */
221 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
224 q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
229 q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
233 *serial = rtnl_message_get_serial(message);
238 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
239 sd_rtnl_message *z = NULL;
245 if (rtnl->rqueue_size > 0) {
246 /* Dispatch a queued message */
248 *message = rtnl->rqueue[0];
249 rtnl->rqueue_size --;
250 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
255 /* Try to read a new message */
256 r = socket_read_message(rtnl, &z);
267 static int dispatch_wqueue(sd_rtnl *rtnl) {
272 while (rtnl->wqueue_size > 0) {
273 r = socket_write_message(rtnl, rtnl->wqueue[0]);
277 /* Didn't do anything this time */
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);
292 static int process_timeout(sd_rtnl *rtnl) {
293 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
294 struct reply_callback *c;
300 c = prioq_peek(rtnl->reply_callbacks_prioq);
304 n = now(CLOCK_MONOTONIC);
308 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
312 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
313 hashmap_remove(rtnl->reply_callbacks, &c->serial);
315 r = c->callback(rtnl, m, c->userdata);
318 return r < 0 ? r : 1;
321 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
322 struct reply_callback *c;
329 if (sd_rtnl_message_is_broadcast(m))
332 serial = rtnl_message_get_serial(m);
333 c = hashmap_remove(rtnl->reply_callbacks, &serial);
338 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
340 r = c->callback(rtnl, m, c->userdata);
346 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
347 struct match_callback *c;
354 r = sd_rtnl_message_get_type(m, &type);
358 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
359 if (type == c->type) {
360 r = c->callback(rtnl, m, c->userdata);
369 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
370 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
375 r = process_timeout(rtnl);
379 r = dispatch_wqueue(rtnl);
383 r = dispatch_rqueue(rtnl, &m);
389 r = process_reply(rtnl, m);
393 r = process_match(rtnl, m);
413 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
414 RTNL_DONT_DESTROY(rtnl);
417 assert_return(rtnl, -EINVAL);
418 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
419 assert_return(!rtnl->processing, -EBUSY);
421 rtnl->processing = true;
422 r = process_running(rtnl, ret);
423 rtnl->processing = false;
428 static usec_t calc_elapse(uint64_t usec) {
429 if (usec == (uint64_t) -1)
433 usec = RTNL_DEFAULT_TIMEOUT;
435 return now(CLOCK_MONOTONIC) + usec;
438 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
439 struct pollfd p[1] = {};
441 usec_t m = (usec_t) -1;
446 e = sd_rtnl_get_events(rtnl);
451 /* Caller wants more data, and doesn't care about
452 * what's been read or any other timeouts. */
456 /* Caller wants to process if there is something to
457 * process, but doesn't care otherwise */
459 r = sd_rtnl_get_timeout(rtnl, &until);
464 nw = now(CLOCK_MONOTONIC);
465 m = until > nw ? until - nw : 0;
469 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
475 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
479 return r > 0 ? 1 : 0;
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);
486 if (nl->rqueue_size > 0)
489 return rtnl_poll(nl, false, timeout_usec);
492 static int timeout_compare(const void *a, const void *b) {
493 const struct reply_callback *x = a, *y = b;
495 if (x->timeout != 0 && y->timeout == 0)
498 if (x->timeout == 0 && y->timeout != 0)
501 if (x->timeout < y->timeout)
504 if (x->timeout > y->timeout)
510 int sd_rtnl_call_async(sd_rtnl *nl,
512 sd_rtnl_message_handler_t callback,
516 struct reply_callback *c;
520 assert_return(nl, -EINVAL);
521 assert_return(m, -EINVAL);
522 assert_return(callback, -EINVAL);
523 assert_return(!rtnl_pid_changed(nl), -ECHILD);
525 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
529 if (usec != (uint64_t) -1) {
530 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
535 c = new0(struct reply_callback, 1);
539 c->callback = callback;
540 c->userdata = userdata;
541 c->timeout = calc_elapse(usec);
543 k = sd_rtnl_send(nl, m, &s);
551 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
557 if (c->timeout != 0) {
558 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
561 sd_rtnl_call_async_cancel(nl, c->serial);
572 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
573 struct reply_callback *c;
576 assert_return(nl, -EINVAL);
577 assert_return(serial != 0, -EINVAL);
578 assert_return(!rtnl_pid_changed(nl), -ECHILD);
580 c = hashmap_remove(nl->reply_callbacks, &s);
585 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
591 int sd_rtnl_call(sd_rtnl *nl,
592 sd_rtnl_message *message,
594 sd_rtnl_message **ret) {
600 assert_return(nl, -EINVAL);
601 assert_return(!rtnl_pid_changed(nl), -ECHILD);
602 assert_return(message, -EINVAL);
604 r = sd_rtnl_send(nl, message, &serial);
608 timeout = calc_elapse(usec);
612 _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
617 if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
620 /* Make sure there's room for queueing this
621 * locally, before we read the message */
623 q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
631 r = socket_read_message(nl, &incoming);
635 uint32_t received_serial = rtnl_message_get_serial(incoming);
637 if (received_serial == serial) {
638 r = sd_rtnl_message_get_errno(incoming);
650 /* Room was allocated on the queue above */
651 nl->rqueue[nl->rqueue_size ++] = incoming;
655 /* Try to read more, right away */
664 n = now(CLOCK_MONOTONIC);
670 left = (uint64_t) -1;
672 r = rtnl_poll(nl, true, left);
676 r = dispatch_wqueue(nl);
682 int sd_rtnl_flush(sd_rtnl *rtnl) {
685 assert_return(rtnl, -EINVAL);
686 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
688 if (rtnl->wqueue_size <= 0)
692 r = dispatch_wqueue(rtnl);
696 if (rtnl->wqueue_size <= 0)
699 r = rtnl_poll(rtnl, false, (uint64_t) -1);
705 int sd_rtnl_get_events(sd_rtnl *rtnl) {
708 assert_return(rtnl, -EINVAL);
709 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
711 if (rtnl->rqueue_size <= 0)
713 if (rtnl->wqueue_size > 0)
719 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
720 struct reply_callback *c;
722 assert_return(rtnl, -EINVAL);
723 assert_return(timeout_usec, -EINVAL);
724 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
726 if (rtnl->rqueue_size > 0) {
731 c = prioq_peek(rtnl->reply_callbacks_prioq);
733 *timeout_usec = (uint64_t) -1;
737 *timeout_usec = c->timeout;
742 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
743 sd_rtnl *rtnl = userdata;
748 r = sd_rtnl_process(rtnl, NULL);
755 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
756 sd_rtnl *rtnl = userdata;
761 r = sd_rtnl_process(rtnl, NULL);
768 static int prepare_callback(sd_event_source *s, void *userdata) {
769 sd_rtnl *rtnl = userdata;
776 e = sd_rtnl_get_events(rtnl);
780 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
784 r = sd_rtnl_get_timeout(rtnl, &until);
790 j = sd_event_source_set_time(rtnl->time_event_source, until);
795 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
802 static int exit_callback(sd_event_source *event, void *userdata) {
803 sd_rtnl *rtnl = userdata;
812 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
815 assert_return(rtnl, -EINVAL);
816 assert_return(!rtnl->event, -EBUSY);
818 assert(!rtnl->io_event_source);
819 assert(!rtnl->time_event_source);
822 rtnl->event = sd_event_ref(event);
824 r = sd_event_default(&rtnl->event);
829 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
833 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
837 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
841 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
845 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
849 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
856 sd_rtnl_detach_event(rtnl);
860 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
861 assert_return(rtnl, -EINVAL);
862 assert_return(rtnl->event, -ENXIO);
864 if (rtnl->io_event_source)
865 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
867 if (rtnl->time_event_source)
868 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
870 if (rtnl->exit_event_source)
871 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
874 rtnl->event = sd_event_unref(rtnl->event);
879 int sd_rtnl_add_match(sd_rtnl *rtnl,
881 sd_rtnl_message_handler_t callback,
883 struct match_callback *c;
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);
892 c = new0(struct match_callback, 1);
896 c->callback = callback;
898 c->userdata = userdata;
900 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
905 int sd_rtnl_remove_match(sd_rtnl *rtnl,
907 sd_rtnl_message_handler_t callback,
909 struct match_callback *c;
911 assert_return(rtnl, -EINVAL);
912 assert_return(callback, -EINVAL);
913 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
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);