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) {
115 if (rtnl && REFCNT_DEC(rtnl->n_ref) <= 0) {
116 struct match_callback *f;
119 for (i = 0; i < rtnl->rqueue_size; i++)
120 sd_rtnl_message_unref(rtnl->rqueue[i]);
123 for (i = 0; i < rtnl->wqueue_size; i++)
124 sd_rtnl_message_unref(rtnl->wqueue[i]);
127 hashmap_free_free(rtnl->reply_callbacks);
128 prioq_free(rtnl->reply_callbacks_prioq);
130 while ((f = rtnl->match_callbacks)) {
131 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
136 close_nointr_nofail(rtnl->fd);
144 int sd_rtnl_send(sd_rtnl *nl,
145 sd_rtnl_message *message,
149 assert_return(nl, -EINVAL);
150 assert_return(!rtnl_pid_changed(nl), -ECHILD);
151 assert_return(message, -EINVAL);
153 r = rtnl_message_seal(nl, message);
157 if (nl->wqueue_size <= 0) {
159 r = socket_write_message(nl, message);
163 /* nothing was sent, so let's put it on
165 nl->wqueue[0] = sd_rtnl_message_ref(message);
171 /* append to queue */
172 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
175 q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
180 q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
184 *serial = rtnl_message_get_serial(message);
189 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
190 sd_rtnl_message *z = NULL;
196 if (rtnl->rqueue_size > 0) {
197 /* Dispatch a queued message */
199 *message = rtnl->rqueue[0];
200 rtnl->rqueue_size --;
201 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
206 /* Try to read a new message */
207 r = socket_read_message(rtnl, &z);
218 static int dispatch_wqueue(sd_rtnl *rtnl) {
223 while (rtnl->wqueue_size > 0) {
224 r = socket_write_message(rtnl, rtnl->wqueue[0]);
228 /* Didn't do anything this time */
231 /* see equivalent in sd-bus.c */
232 sd_rtnl_message_unref(rtnl->wqueue[0]);
233 rtnl->wqueue_size --;
234 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
243 static int process_timeout(sd_rtnl *rtnl) {
244 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
245 struct reply_callback *c;
251 c = prioq_peek(rtnl->reply_callbacks_prioq);
255 n = now(CLOCK_MONOTONIC);
259 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
263 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
264 hashmap_remove(rtnl->reply_callbacks, &c->serial);
266 r = c->callback(rtnl, m, c->userdata);
269 return r < 0 ? r : 1;
272 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
273 struct reply_callback *c;
280 serial = rtnl_message_get_serial(m);
281 c = hashmap_remove(rtnl->reply_callbacks, &serial);
286 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
288 r = c->callback(rtnl, m, c->userdata);
294 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
295 struct match_callback *c;
302 r = sd_rtnl_message_get_type(m, &type);
306 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
307 if (type == c->type) {
308 r = c->callback(rtnl, m, c->userdata);
317 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
318 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
323 r = process_timeout(rtnl);
327 r = dispatch_wqueue(rtnl);
331 r = dispatch_rqueue(rtnl, &m);
337 r = process_reply(rtnl, m);
341 r = process_match(rtnl, m);
361 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
362 RTNL_DONT_DESTROY(rtnl);
365 assert_return(rtnl, -EINVAL);
366 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
367 assert_return(!rtnl->processing, -EBUSY);
369 rtnl->processing = true;
370 r = process_running(rtnl, ret);
371 rtnl->processing = false;
376 static usec_t calc_elapse(uint64_t usec) {
377 if (usec == (uint64_t) -1)
381 usec = RTNL_DEFAULT_TIMEOUT;
383 return now(CLOCK_MONOTONIC) + usec;
386 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
387 struct pollfd p[1] = {};
389 usec_t m = (usec_t) -1;
394 e = sd_rtnl_get_events(rtnl);
399 /* Caller wants more data, and doesn't care about
400 * what's been read or any other timeouts. */
404 /* Caller wants to process if there is something to
405 * process, but doesn't care otherwise */
407 r = sd_rtnl_get_timeout(rtnl, &until);
412 nw = now(CLOCK_MONOTONIC);
413 m = until > nw ? until - nw : 0;
417 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
423 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
427 return r > 0 ? 1 : 0;
430 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
431 assert_return(nl, -EINVAL);
432 assert_return(!rtnl_pid_changed(nl), -ECHILD);
434 if (nl->rqueue_size > 0)
437 return rtnl_poll(nl, false, timeout_usec);
440 static int timeout_compare(const void *a, const void *b) {
441 const struct reply_callback *x = a, *y = b;
443 if (x->timeout != 0 && y->timeout == 0)
446 if (x->timeout == 0 && y->timeout != 0)
449 if (x->timeout < y->timeout)
452 if (x->timeout > y->timeout)
458 int sd_rtnl_call_async(sd_rtnl *nl,
460 sd_rtnl_message_handler_t callback,
464 struct reply_callback *c;
468 assert_return(nl, -EINVAL);
469 assert_return(m, -EINVAL);
470 assert_return(callback, -EINVAL);
471 assert_return(!rtnl_pid_changed(nl), -ECHILD);
473 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
477 if (usec != (uint64_t) -1) {
478 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
483 c = new0(struct reply_callback, 1);
487 c->callback = callback;
488 c->userdata = userdata;
489 c->timeout = calc_elapse(usec);
491 k = sd_rtnl_send(nl, m, &s);
499 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
505 if (c->timeout != 0) {
506 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
509 sd_rtnl_call_async_cancel(nl, c->serial);
520 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
521 struct reply_callback *c;
524 assert_return(nl, -EINVAL);
525 assert_return(serial != 0, -EINVAL);
526 assert_return(!rtnl_pid_changed(nl), -ECHILD);
528 c = hashmap_remove(nl->reply_callbacks, &s);
533 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
539 int sd_rtnl_call(sd_rtnl *nl,
540 sd_rtnl_message *message,
542 sd_rtnl_message **ret) {
548 assert_return(nl, -EINVAL);
549 assert_return(!rtnl_pid_changed(nl), -ECHILD);
550 assert_return(message, -EINVAL);
552 r = sd_rtnl_send(nl, message, &serial);
556 timeout = calc_elapse(usec);
560 _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
565 if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
568 /* Make sure there's room for queueing this
569 * locally, before we read the message */
571 q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
579 r = socket_read_message(nl, &incoming);
583 uint32_t received_serial = rtnl_message_get_serial(incoming);
585 if (received_serial == serial) {
586 r = sd_rtnl_message_get_errno(incoming);
598 /* Room was allocated on the queue above */
599 nl->rqueue[nl->rqueue_size ++] = incoming;
603 /* Try to read more, right away */
612 n = now(CLOCK_MONOTONIC);
618 left = (uint64_t) -1;
620 r = rtnl_poll(nl, true, left);
624 r = dispatch_wqueue(nl);
630 int sd_rtnl_flush(sd_rtnl *rtnl) {
633 assert_return(rtnl, -EINVAL);
634 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
636 if (rtnl->wqueue_size <= 0)
640 r = dispatch_wqueue(rtnl);
644 if (rtnl->wqueue_size <= 0)
647 r = rtnl_poll(rtnl, false, (uint64_t) -1);
653 int sd_rtnl_get_events(sd_rtnl *rtnl) {
656 assert_return(rtnl, -EINVAL);
657 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
659 if (rtnl->rqueue_size <= 0)
661 if (rtnl->wqueue_size > 0)
667 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
668 struct reply_callback *c;
670 assert_return(rtnl, -EINVAL);
671 assert_return(timeout_usec, -EINVAL);
672 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
674 if (rtnl->rqueue_size > 0) {
679 c = prioq_peek(rtnl->reply_callbacks_prioq);
681 *timeout_usec = (uint64_t) -1;
685 *timeout_usec = c->timeout;
690 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
691 sd_rtnl *rtnl = userdata;
696 r = sd_rtnl_process(rtnl, NULL);
703 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
704 sd_rtnl *rtnl = userdata;
709 r = sd_rtnl_process(rtnl, NULL);
716 static int prepare_callback(sd_event_source *s, void *userdata) {
717 sd_rtnl *rtnl = userdata;
724 e = sd_rtnl_get_events(rtnl);
728 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
732 r = sd_rtnl_get_timeout(rtnl, &until);
738 j = sd_event_source_set_time(rtnl->time_event_source, until);
743 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
750 static int exit_callback(sd_event_source *event, void *userdata) {
751 sd_rtnl *rtnl = userdata;
760 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
763 assert_return(rtnl, -EINVAL);
764 assert_return(!rtnl->event, -EBUSY);
766 assert(!rtnl->io_event_source);
767 assert(!rtnl->time_event_source);
770 rtnl->event = sd_event_ref(event);
772 r = sd_event_default(&rtnl->event);
777 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
781 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
785 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
789 r = sd_event_add_monotonic(rtnl->event, &rtnl->time_event_source, 0, 0, time_callback, rtnl);
793 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
797 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
804 sd_rtnl_detach_event(rtnl);
808 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
809 assert_return(rtnl, -EINVAL);
810 assert_return(rtnl->event, -ENXIO);
812 if (rtnl->io_event_source)
813 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
815 if (rtnl->time_event_source)
816 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
818 if (rtnl->exit_event_source)
819 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
822 rtnl->event = sd_event_unref(rtnl->event);
827 int sd_rtnl_add_match(sd_rtnl *rtnl,
829 sd_rtnl_message_handler_t callback,
831 struct match_callback *c;
833 assert_return(rtnl, -EINVAL);
834 assert_return(callback, -EINVAL);
835 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
836 assert_return(rtnl_message_type_is_link(type) ||
837 rtnl_message_type_is_addr(type) ||
838 rtnl_message_type_is_route(type), -ENOTSUP);
840 c = new0(struct match_callback, 1);
844 c->callback = callback;
846 c->userdata = userdata;
848 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
853 int sd_rtnl_remove_match(sd_rtnl *rtnl,
855 sd_rtnl_message_handler_t callback,
857 struct match_callback *c;
859 assert_return(rtnl, -EINVAL);
860 assert_return(callback, -EINVAL);
861 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
863 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
864 if (c->callback == callback && c->type == type && c->userdata == userdata) {
865 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);