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);
135 safe_close(rtnl->fd);
142 int sd_rtnl_send(sd_rtnl *nl,
143 sd_rtnl_message *message,
147 assert_return(nl, -EINVAL);
148 assert_return(!rtnl_pid_changed(nl), -ECHILD);
149 assert_return(message, -EINVAL);
151 r = rtnl_message_seal(nl, message);
155 if (nl->wqueue_size <= 0) {
157 r = socket_write_message(nl, message);
161 /* nothing was sent, so let's put it on
163 nl->wqueue[0] = sd_rtnl_message_ref(message);
169 /* append to queue */
170 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
173 q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
178 q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
182 *serial = rtnl_message_get_serial(message);
187 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
188 sd_rtnl_message *z = NULL;
194 if (rtnl->rqueue_size > 0) {
195 /* Dispatch a queued message */
197 *message = rtnl->rqueue[0];
198 rtnl->rqueue_size --;
199 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
204 /* Try to read a new message */
205 r = socket_read_message(rtnl, &z);
216 static int dispatch_wqueue(sd_rtnl *rtnl) {
221 while (rtnl->wqueue_size > 0) {
222 r = socket_write_message(rtnl, rtnl->wqueue[0]);
226 /* Didn't do anything this time */
229 /* see equivalent in sd-bus.c */
230 sd_rtnl_message_unref(rtnl->wqueue[0]);
231 rtnl->wqueue_size --;
232 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
241 static int process_timeout(sd_rtnl *rtnl) {
242 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
243 struct reply_callback *c;
249 c = prioq_peek(rtnl->reply_callbacks_prioq);
253 n = now(CLOCK_MONOTONIC);
257 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
261 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
262 hashmap_remove(rtnl->reply_callbacks, &c->serial);
264 r = c->callback(rtnl, m, c->userdata);
267 return r < 0 ? r : 1;
270 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
271 struct reply_callback *c;
278 if (sd_rtnl_message_is_broadcast(m))
281 serial = rtnl_message_get_serial(m);
282 c = hashmap_remove(rtnl->reply_callbacks, &serial);
287 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
289 r = c->callback(rtnl, m, c->userdata);
295 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
296 struct match_callback *c;
303 r = sd_rtnl_message_get_type(m, &type);
307 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
308 if (type == c->type) {
309 r = c->callback(rtnl, m, c->userdata);
318 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
319 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
324 r = process_timeout(rtnl);
328 r = dispatch_wqueue(rtnl);
332 r = dispatch_rqueue(rtnl, &m);
338 r = process_reply(rtnl, m);
342 r = process_match(rtnl, m);
362 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
363 RTNL_DONT_DESTROY(rtnl);
366 assert_return(rtnl, -EINVAL);
367 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
368 assert_return(!rtnl->processing, -EBUSY);
370 rtnl->processing = true;
371 r = process_running(rtnl, ret);
372 rtnl->processing = false;
377 static usec_t calc_elapse(uint64_t usec) {
378 if (usec == (uint64_t) -1)
382 usec = RTNL_DEFAULT_TIMEOUT;
384 return now(CLOCK_MONOTONIC) + usec;
387 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
388 struct pollfd p[1] = {};
390 usec_t m = (usec_t) -1;
395 e = sd_rtnl_get_events(rtnl);
400 /* Caller wants more data, and doesn't care about
401 * what's been read or any other timeouts. */
405 /* Caller wants to process if there is something to
406 * process, but doesn't care otherwise */
408 r = sd_rtnl_get_timeout(rtnl, &until);
413 nw = now(CLOCK_MONOTONIC);
414 m = until > nw ? until - nw : 0;
418 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
424 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
428 return r > 0 ? 1 : 0;
431 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
432 assert_return(nl, -EINVAL);
433 assert_return(!rtnl_pid_changed(nl), -ECHILD);
435 if (nl->rqueue_size > 0)
438 return rtnl_poll(nl, false, timeout_usec);
441 static int timeout_compare(const void *a, const void *b) {
442 const struct reply_callback *x = a, *y = b;
444 if (x->timeout != 0 && y->timeout == 0)
447 if (x->timeout == 0 && y->timeout != 0)
450 if (x->timeout < y->timeout)
453 if (x->timeout > y->timeout)
459 int sd_rtnl_call_async(sd_rtnl *nl,
461 sd_rtnl_message_handler_t callback,
465 struct reply_callback *c;
469 assert_return(nl, -EINVAL);
470 assert_return(m, -EINVAL);
471 assert_return(callback, -EINVAL);
472 assert_return(!rtnl_pid_changed(nl), -ECHILD);
474 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
478 if (usec != (uint64_t) -1) {
479 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
484 c = new0(struct reply_callback, 1);
488 c->callback = callback;
489 c->userdata = userdata;
490 c->timeout = calc_elapse(usec);
492 k = sd_rtnl_send(nl, m, &s);
500 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
506 if (c->timeout != 0) {
507 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
510 sd_rtnl_call_async_cancel(nl, c->serial);
521 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
522 struct reply_callback *c;
525 assert_return(nl, -EINVAL);
526 assert_return(serial != 0, -EINVAL);
527 assert_return(!rtnl_pid_changed(nl), -ECHILD);
529 c = hashmap_remove(nl->reply_callbacks, &s);
534 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
540 int sd_rtnl_call(sd_rtnl *nl,
541 sd_rtnl_message *message,
543 sd_rtnl_message **ret) {
549 assert_return(nl, -EINVAL);
550 assert_return(!rtnl_pid_changed(nl), -ECHILD);
551 assert_return(message, -EINVAL);
553 r = sd_rtnl_send(nl, message, &serial);
557 timeout = calc_elapse(usec);
561 _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
566 if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
569 /* Make sure there's room for queueing this
570 * locally, before we read the message */
572 q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
580 r = socket_read_message(nl, &incoming);
584 uint32_t received_serial = rtnl_message_get_serial(incoming);
586 if (received_serial == serial) {
587 r = sd_rtnl_message_get_errno(incoming);
599 /* Room was allocated on the queue above */
600 nl->rqueue[nl->rqueue_size ++] = incoming;
604 /* Try to read more, right away */
613 n = now(CLOCK_MONOTONIC);
619 left = (uint64_t) -1;
621 r = rtnl_poll(nl, true, left);
625 r = dispatch_wqueue(nl);
631 int sd_rtnl_flush(sd_rtnl *rtnl) {
634 assert_return(rtnl, -EINVAL);
635 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
637 if (rtnl->wqueue_size <= 0)
641 r = dispatch_wqueue(rtnl);
645 if (rtnl->wqueue_size <= 0)
648 r = rtnl_poll(rtnl, false, (uint64_t) -1);
654 int sd_rtnl_get_events(sd_rtnl *rtnl) {
657 assert_return(rtnl, -EINVAL);
658 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
660 if (rtnl->rqueue_size <= 0)
662 if (rtnl->wqueue_size > 0)
668 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
669 struct reply_callback *c;
671 assert_return(rtnl, -EINVAL);
672 assert_return(timeout_usec, -EINVAL);
673 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
675 if (rtnl->rqueue_size > 0) {
680 c = prioq_peek(rtnl->reply_callbacks_prioq);
682 *timeout_usec = (uint64_t) -1;
686 *timeout_usec = c->timeout;
691 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
692 sd_rtnl *rtnl = userdata;
697 r = sd_rtnl_process(rtnl, NULL);
704 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
705 sd_rtnl *rtnl = userdata;
710 r = sd_rtnl_process(rtnl, NULL);
717 static int prepare_callback(sd_event_source *s, void *userdata) {
718 sd_rtnl *rtnl = userdata;
725 e = sd_rtnl_get_events(rtnl);
729 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
733 r = sd_rtnl_get_timeout(rtnl, &until);
739 j = sd_event_source_set_time(rtnl->time_event_source, until);
744 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
751 static int exit_callback(sd_event_source *event, void *userdata) {
752 sd_rtnl *rtnl = userdata;
761 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
764 assert_return(rtnl, -EINVAL);
765 assert_return(!rtnl->event, -EBUSY);
767 assert(!rtnl->io_event_source);
768 assert(!rtnl->time_event_source);
771 rtnl->event = sd_event_ref(event);
773 r = sd_event_default(&rtnl->event);
778 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
782 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
786 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
790 r = sd_event_add_monotonic(rtnl->event, &rtnl->time_event_source, 0, 0, time_callback, rtnl);
794 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
798 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
805 sd_rtnl_detach_event(rtnl);
809 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
810 assert_return(rtnl, -EINVAL);
811 assert_return(rtnl->event, -ENXIO);
813 if (rtnl->io_event_source)
814 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
816 if (rtnl->time_event_source)
817 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
819 if (rtnl->exit_event_source)
820 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
823 rtnl->event = sd_event_unref(rtnl->event);
828 int sd_rtnl_add_match(sd_rtnl *rtnl,
830 sd_rtnl_message_handler_t callback,
832 struct match_callback *c;
834 assert_return(rtnl, -EINVAL);
835 assert_return(callback, -EINVAL);
836 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
837 assert_return(rtnl_message_type_is_link(type) ||
838 rtnl_message_type_is_addr(type) ||
839 rtnl_message_type_is_route(type), -ENOTSUP);
841 c = new0(struct match_callback, 1);
845 c->callback = callback;
847 c->userdata = userdata;
849 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
854 int sd_rtnl_remove_match(sd_rtnl *rtnl,
856 sd_rtnl_message_handler_t callback,
858 struct match_callback *c;
860 assert_return(rtnl, -EINVAL);
861 assert_return(callback, -EINVAL);
862 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
864 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
865 if (c->callback == callback && c->type == type && c->userdata == userdata) {
866 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);