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) {
34 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
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 if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
63 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
66 /* We don't support people creating an rtnl connection and
67 * keeping it around over a fork(). Let's complain. */
69 return rtnl->original_pid != getpid();
72 int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) {
73 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
77 assert_return(ret, -EINVAL);
79 r = sd_rtnl_new(&rtnl);
83 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
87 rtnl->sockaddr.nl.nl_groups = groups;
89 addrlen = sizeof(rtnl->sockaddr);
91 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
95 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
105 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
106 assert_return(rtnl, NULL);
107 assert_return(!rtnl_pid_changed(rtnl), NULL);
110 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
115 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
119 assert_return(!rtnl_pid_changed(rtnl), NULL);
121 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
122 struct match_callback *f;
125 for (i = 0; i < rtnl->rqueue_size; i++)
126 sd_rtnl_message_unref(rtnl->rqueue[i]);
129 for (i = 0; i < rtnl->wqueue_size; i++)
130 sd_rtnl_message_unref(rtnl->wqueue[i]);
133 hashmap_free_free(rtnl->reply_callbacks);
134 prioq_free(rtnl->reply_callbacks_prioq);
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);
141 while ((f = rtnl->match_callbacks)) {
142 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
146 safe_close(rtnl->fd);
153 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
155 assert(!rtnl_pid_changed(rtnl));
159 m->hdr->nlmsg_seq = rtnl->serial++;
161 rtnl_message_seal(m);
166 int sd_rtnl_send(sd_rtnl *nl,
167 sd_rtnl_message *message,
171 assert_return(nl, -EINVAL);
172 assert_return(!rtnl_pid_changed(nl), -ECHILD);
173 assert_return(message, -EINVAL);
174 assert_return(!message->sealed, -EPERM);
176 rtnl_seal_message(nl, message);
178 if (nl->wqueue_size <= 0) {
180 r = socket_write_message(nl, message);
184 /* nothing was sent, so let's put it on
186 nl->wqueue[0] = sd_rtnl_message_ref(message);
190 /* append to queue */
191 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
194 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
197 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
201 *serial = rtnl_message_get_serial(message);
206 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
209 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX)
212 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
218 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
224 if (rtnl->rqueue_size <= 0) {
225 /* Try to read a new message */
226 r = socket_read_message(rtnl);
231 /* Dispatch a queued message */
232 *message = rtnl->rqueue[0];
233 rtnl->rqueue_size --;
234 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
239 static int dispatch_wqueue(sd_rtnl *rtnl) {
244 while (rtnl->wqueue_size > 0) {
245 r = socket_write_message(rtnl, rtnl->wqueue[0]);
249 /* Didn't do anything this time */
252 /* see equivalent in sd-bus.c */
253 sd_rtnl_message_unref(rtnl->wqueue[0]);
254 rtnl->wqueue_size --;
255 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
264 static int process_timeout(sd_rtnl *rtnl) {
265 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
266 struct reply_callback *c;
272 c = prioq_peek(rtnl->reply_callbacks_prioq);
276 n = now(CLOCK_MONOTONIC);
280 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
284 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
285 hashmap_remove(rtnl->reply_callbacks, &c->serial);
287 r = c->callback(rtnl, m, c->userdata);
290 return r < 0 ? r : 1;
293 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
294 struct reply_callback *c;
301 if (sd_rtnl_message_is_broadcast(m))
304 serial = rtnl_message_get_serial(m);
305 c = hashmap_remove(rtnl->reply_callbacks, &serial);
310 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
312 r = c->callback(rtnl, m, c->userdata);
318 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
319 struct match_callback *c;
326 r = sd_rtnl_message_get_type(m, &type);
330 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
331 if (type == c->type) {
332 r = c->callback(rtnl, m, c->userdata);
341 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
342 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
347 r = process_timeout(rtnl);
351 r = dispatch_wqueue(rtnl);
355 r = dispatch_rqueue(rtnl, &m);
361 r = process_reply(rtnl, m);
365 r = process_match(rtnl, m);
385 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
386 RTNL_DONT_DESTROY(rtnl);
389 assert_return(rtnl, -EINVAL);
390 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
391 assert_return(!rtnl->processing, -EBUSY);
393 rtnl->processing = true;
394 r = process_running(rtnl, ret);
395 rtnl->processing = false;
400 static usec_t calc_elapse(uint64_t usec) {
401 if (usec == (uint64_t) -1)
405 usec = RTNL_DEFAULT_TIMEOUT;
407 return now(CLOCK_MONOTONIC) + usec;
410 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
411 struct pollfd p[1] = {};
413 usec_t m = (usec_t) -1;
418 e = sd_rtnl_get_events(rtnl);
423 /* Caller wants more data, and doesn't care about
424 * what's been read or any other timeouts. */
428 /* Caller wants to process if there is something to
429 * process, but doesn't care otherwise */
431 r = sd_rtnl_get_timeout(rtnl, &until);
436 nw = now(CLOCK_MONOTONIC);
437 m = until > nw ? until - nw : 0;
441 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
447 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
451 return r > 0 ? 1 : 0;
454 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
455 assert_return(nl, -EINVAL);
456 assert_return(!rtnl_pid_changed(nl), -ECHILD);
458 if (nl->rqueue_size > 0)
461 return rtnl_poll(nl, false, timeout_usec);
464 static int timeout_compare(const void *a, const void *b) {
465 const struct reply_callback *x = a, *y = b;
467 if (x->timeout != 0 && y->timeout == 0)
470 if (x->timeout == 0 && y->timeout != 0)
473 if (x->timeout < y->timeout)
476 if (x->timeout > y->timeout)
482 int sd_rtnl_call_async(sd_rtnl *nl,
484 sd_rtnl_message_handler_t callback,
488 struct reply_callback *c;
492 assert_return(nl, -EINVAL);
493 assert_return(m, -EINVAL);
494 assert_return(callback, -EINVAL);
495 assert_return(!rtnl_pid_changed(nl), -ECHILD);
497 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
501 if (usec != (uint64_t) -1) {
502 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
507 c = new0(struct reply_callback, 1);
511 c->callback = callback;
512 c->userdata = userdata;
513 c->timeout = calc_elapse(usec);
515 k = sd_rtnl_send(nl, m, &s);
523 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
529 if (c->timeout != 0) {
530 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
533 sd_rtnl_call_async_cancel(nl, c->serial);
544 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
545 struct reply_callback *c;
548 assert_return(nl, -EINVAL);
549 assert_return(serial != 0, -EINVAL);
550 assert_return(!rtnl_pid_changed(nl), -ECHILD);
552 c = hashmap_remove(nl->reply_callbacks, &s);
557 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
563 int sd_rtnl_call(sd_rtnl *rtnl,
564 sd_rtnl_message *message,
566 sd_rtnl_message **ret) {
572 assert_return(rtnl, -EINVAL);
573 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
574 assert_return(message, -EINVAL);
576 r = sd_rtnl_send(rtnl, message, &serial);
580 timeout = calc_elapse(usec);
585 while (i < rtnl->rqueue_size) {
586 sd_rtnl_message *incoming;
587 uint32_t received_serial;
589 incoming = rtnl->rqueue[i];
590 received_serial = rtnl_message_get_serial(incoming);
592 if (received_serial == serial) {
593 /* found a match, remove from rqueue and return it */
594 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
595 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
598 r = sd_rtnl_message_get_errno(incoming);
600 sd_rtnl_message_unref(incoming);
607 sd_rtnl_message_unref(incoming);
612 /* Try to read more, right away */
616 r = socket_read_message(rtnl);
620 /* receieved message, so try to process straight away */
626 n = now(CLOCK_MONOTONIC);
632 left = (uint64_t) -1;
634 r = rtnl_poll(rtnl, true, left);
638 r = dispatch_wqueue(rtnl);
644 int sd_rtnl_flush(sd_rtnl *rtnl) {
647 assert_return(rtnl, -EINVAL);
648 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
650 if (rtnl->wqueue_size <= 0)
654 r = dispatch_wqueue(rtnl);
658 if (rtnl->wqueue_size <= 0)
661 r = rtnl_poll(rtnl, false, (uint64_t) -1);
667 int sd_rtnl_get_events(sd_rtnl *rtnl) {
670 assert_return(rtnl, -EINVAL);
671 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
673 if (rtnl->rqueue_size <= 0)
675 if (rtnl->wqueue_size > 0)
681 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
682 struct reply_callback *c;
684 assert_return(rtnl, -EINVAL);
685 assert_return(timeout_usec, -EINVAL);
686 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
688 if (rtnl->rqueue_size > 0) {
693 c = prioq_peek(rtnl->reply_callbacks_prioq);
695 *timeout_usec = (uint64_t) -1;
699 *timeout_usec = c->timeout;
704 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
705 sd_rtnl *rtnl = userdata;
710 r = sd_rtnl_process(rtnl, NULL);
717 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
718 sd_rtnl *rtnl = userdata;
723 r = sd_rtnl_process(rtnl, NULL);
730 static int prepare_callback(sd_event_source *s, void *userdata) {
731 sd_rtnl *rtnl = userdata;
738 e = sd_rtnl_get_events(rtnl);
742 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
746 r = sd_rtnl_get_timeout(rtnl, &until);
752 j = sd_event_source_set_time(rtnl->time_event_source, until);
757 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
764 static int exit_callback(sd_event_source *event, void *userdata) {
765 sd_rtnl *rtnl = userdata;
774 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
777 assert_return(rtnl, -EINVAL);
778 assert_return(!rtnl->event, -EBUSY);
780 assert(!rtnl->io_event_source);
781 assert(!rtnl->time_event_source);
784 rtnl->event = sd_event_ref(event);
786 r = sd_event_default(&rtnl->event);
791 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
795 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
799 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
803 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
807 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
811 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
818 sd_rtnl_detach_event(rtnl);
822 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
823 assert_return(rtnl, -EINVAL);
824 assert_return(rtnl->event, -ENXIO);
826 if (rtnl->io_event_source)
827 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
829 if (rtnl->time_event_source)
830 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
832 if (rtnl->exit_event_source)
833 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
836 rtnl->event = sd_event_unref(rtnl->event);
841 int sd_rtnl_add_match(sd_rtnl *rtnl,
843 sd_rtnl_message_handler_t callback,
845 struct match_callback *c;
847 assert_return(rtnl, -EINVAL);
848 assert_return(callback, -EINVAL);
849 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
850 assert_return(rtnl_message_type_is_link(type) ||
851 rtnl_message_type_is_addr(type) ||
852 rtnl_message_type_is_route(type), -ENOTSUP);
854 c = new0(struct match_callback, 1);
858 c->callback = callback;
860 c->userdata = userdata;
862 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
867 int sd_rtnl_remove_match(sd_rtnl *rtnl,
869 sd_rtnl_message_handler_t callback,
871 struct match_callback *c;
873 assert_return(rtnl, -EINVAL);
874 assert_return(callback, -EINVAL);
875 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
877 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
878 if (c->callback == callback && c->type == type && c->userdata == userdata) {
879 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);