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 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) {
107 assert_return(rtnl, NULL);
108 assert_return(!rtnl_pid_changed(rtnl), NULL);
111 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
116 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
120 assert_return(!rtnl_pid_changed(rtnl), NULL);
122 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
123 struct match_callback *f;
126 for (i = 0; i < rtnl->rqueue_size; i++)
127 sd_rtnl_message_unref(rtnl->rqueue[i]);
130 for (i = 0; i < rtnl->wqueue_size; i++)
131 sd_rtnl_message_unref(rtnl->wqueue[i]);
134 hashmap_free_free(rtnl->reply_callbacks);
135 prioq_free(rtnl->reply_callbacks_prioq);
137 sd_event_source_unref(rtnl->io_event_source);
138 sd_event_source_unref(rtnl->time_event_source);
139 sd_event_source_unref(rtnl->exit_event_source);
140 sd_event_unref(rtnl->event);
142 while ((f = rtnl->match_callbacks)) {
143 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
147 safe_close(rtnl->fd);
154 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
156 assert(!rtnl_pid_changed(rtnl));
160 m->hdr->nlmsg_seq = rtnl->serial++;
162 rtnl_message_seal(m);
167 int sd_rtnl_send(sd_rtnl *nl,
168 sd_rtnl_message *message,
172 assert_return(nl, -EINVAL);
173 assert_return(!rtnl_pid_changed(nl), -ECHILD);
174 assert_return(message, -EINVAL);
175 assert_return(!message->sealed, -EPERM);
177 rtnl_seal_message(nl, message);
179 if (nl->wqueue_size <= 0) {
181 r = socket_write_message(nl, message);
185 /* nothing was sent, so let's put it on
187 nl->wqueue[0] = sd_rtnl_message_ref(message);
193 /* append to queue */
194 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
197 q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
202 q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
206 *serial = rtnl_message_get_serial(message);
211 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
212 sd_rtnl_message *z = NULL;
218 if (rtnl->rqueue_size > 0) {
219 /* Dispatch a queued message */
221 *message = rtnl->rqueue[0];
222 rtnl->rqueue_size --;
223 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
228 /* Try to read a new message */
229 r = socket_read_message(rtnl, &z);
238 static int dispatch_wqueue(sd_rtnl *rtnl) {
243 while (rtnl->wqueue_size > 0) {
244 r = socket_write_message(rtnl, rtnl->wqueue[0]);
248 /* Didn't do anything this time */
251 /* see equivalent in sd-bus.c */
252 sd_rtnl_message_unref(rtnl->wqueue[0]);
253 rtnl->wqueue_size --;
254 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
263 static int process_timeout(sd_rtnl *rtnl) {
264 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
265 struct reply_callback *c;
271 c = prioq_peek(rtnl->reply_callbacks_prioq);
275 n = now(CLOCK_MONOTONIC);
279 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
283 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
284 hashmap_remove(rtnl->reply_callbacks, &c->serial);
286 r = c->callback(rtnl, m, c->userdata);
289 return r < 0 ? r : 1;
292 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
293 struct reply_callback *c;
300 if (sd_rtnl_message_is_broadcast(m))
303 serial = rtnl_message_get_serial(m);
304 c = hashmap_remove(rtnl->reply_callbacks, &serial);
309 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
311 r = c->callback(rtnl, m, c->userdata);
317 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
318 struct match_callback *c;
325 r = sd_rtnl_message_get_type(m, &type);
329 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
330 if (type == c->type) {
331 r = c->callback(rtnl, m, c->userdata);
340 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
341 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
346 r = process_timeout(rtnl);
350 r = dispatch_wqueue(rtnl);
354 r = dispatch_rqueue(rtnl, &m);
360 r = process_reply(rtnl, m);
364 r = process_match(rtnl, m);
384 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
385 RTNL_DONT_DESTROY(rtnl);
388 assert_return(rtnl, -EINVAL);
389 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
390 assert_return(!rtnl->processing, -EBUSY);
392 rtnl->processing = true;
393 r = process_running(rtnl, ret);
394 rtnl->processing = false;
399 static usec_t calc_elapse(uint64_t usec) {
400 if (usec == (uint64_t) -1)
404 usec = RTNL_DEFAULT_TIMEOUT;
406 return now(CLOCK_MONOTONIC) + usec;
409 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
410 struct pollfd p[1] = {};
412 usec_t m = (usec_t) -1;
417 e = sd_rtnl_get_events(rtnl);
422 /* Caller wants more data, and doesn't care about
423 * what's been read or any other timeouts. */
427 /* Caller wants to process if there is something to
428 * process, but doesn't care otherwise */
430 r = sd_rtnl_get_timeout(rtnl, &until);
435 nw = now(CLOCK_MONOTONIC);
436 m = until > nw ? until - nw : 0;
440 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
446 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
450 return r > 0 ? 1 : 0;
453 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
454 assert_return(nl, -EINVAL);
455 assert_return(!rtnl_pid_changed(nl), -ECHILD);
457 if (nl->rqueue_size > 0)
460 return rtnl_poll(nl, false, timeout_usec);
463 static int timeout_compare(const void *a, const void *b) {
464 const struct reply_callback *x = a, *y = b;
466 if (x->timeout != 0 && y->timeout == 0)
469 if (x->timeout == 0 && y->timeout != 0)
472 if (x->timeout < y->timeout)
475 if (x->timeout > y->timeout)
481 int sd_rtnl_call_async(sd_rtnl *nl,
483 sd_rtnl_message_handler_t callback,
487 struct reply_callback *c;
491 assert_return(nl, -EINVAL);
492 assert_return(m, -EINVAL);
493 assert_return(callback, -EINVAL);
494 assert_return(!rtnl_pid_changed(nl), -ECHILD);
496 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
500 if (usec != (uint64_t) -1) {
501 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
506 c = new0(struct reply_callback, 1);
510 c->callback = callback;
511 c->userdata = userdata;
512 c->timeout = calc_elapse(usec);
514 k = sd_rtnl_send(nl, m, &s);
522 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
528 if (c->timeout != 0) {
529 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
532 sd_rtnl_call_async_cancel(nl, c->serial);
543 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
544 struct reply_callback *c;
547 assert_return(nl, -EINVAL);
548 assert_return(serial != 0, -EINVAL);
549 assert_return(!rtnl_pid_changed(nl), -ECHILD);
551 c = hashmap_remove(nl->reply_callbacks, &s);
556 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
562 int sd_rtnl_call(sd_rtnl *nl,
563 sd_rtnl_message *message,
565 sd_rtnl_message **ret) {
571 assert_return(nl, -EINVAL);
572 assert_return(!rtnl_pid_changed(nl), -ECHILD);
573 assert_return(message, -EINVAL);
575 r = sd_rtnl_send(nl, message, &serial);
579 timeout = calc_elapse(usec);
583 _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
588 if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
591 /* Make sure there's room for queueing this
592 * locally, before we read the message */
594 q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
602 r = socket_read_message(nl, &incoming);
606 uint32_t received_serial = rtnl_message_get_serial(incoming);
608 if (received_serial == serial) {
609 r = sd_rtnl_message_get_errno(incoming);
621 /* Room was allocated on the queue above */
622 nl->rqueue[nl->rqueue_size ++] = incoming;
626 /* Try to read more, right away */
635 n = now(CLOCK_MONOTONIC);
641 left = (uint64_t) -1;
643 r = rtnl_poll(nl, true, left);
647 r = dispatch_wqueue(nl);
653 int sd_rtnl_flush(sd_rtnl *rtnl) {
656 assert_return(rtnl, -EINVAL);
657 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
659 if (rtnl->wqueue_size <= 0)
663 r = dispatch_wqueue(rtnl);
667 if (rtnl->wqueue_size <= 0)
670 r = rtnl_poll(rtnl, false, (uint64_t) -1);
676 int sd_rtnl_get_events(sd_rtnl *rtnl) {
679 assert_return(rtnl, -EINVAL);
680 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
682 if (rtnl->rqueue_size <= 0)
684 if (rtnl->wqueue_size > 0)
690 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
691 struct reply_callback *c;
693 assert_return(rtnl, -EINVAL);
694 assert_return(timeout_usec, -EINVAL);
695 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
697 if (rtnl->rqueue_size > 0) {
702 c = prioq_peek(rtnl->reply_callbacks_prioq);
704 *timeout_usec = (uint64_t) -1;
708 *timeout_usec = c->timeout;
713 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
714 sd_rtnl *rtnl = userdata;
719 r = sd_rtnl_process(rtnl, NULL);
726 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
727 sd_rtnl *rtnl = userdata;
732 r = sd_rtnl_process(rtnl, NULL);
739 static int prepare_callback(sd_event_source *s, void *userdata) {
740 sd_rtnl *rtnl = userdata;
747 e = sd_rtnl_get_events(rtnl);
751 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
755 r = sd_rtnl_get_timeout(rtnl, &until);
761 j = sd_event_source_set_time(rtnl->time_event_source, until);
766 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
773 static int exit_callback(sd_event_source *event, void *userdata) {
774 sd_rtnl *rtnl = userdata;
783 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
786 assert_return(rtnl, -EINVAL);
787 assert_return(!rtnl->event, -EBUSY);
789 assert(!rtnl->io_event_source);
790 assert(!rtnl->time_event_source);
793 rtnl->event = sd_event_ref(event);
795 r = sd_event_default(&rtnl->event);
800 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
804 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
808 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
812 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
816 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
820 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
827 sd_rtnl_detach_event(rtnl);
831 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
832 assert_return(rtnl, -EINVAL);
833 assert_return(rtnl->event, -ENXIO);
835 if (rtnl->io_event_source)
836 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
838 if (rtnl->time_event_source)
839 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
841 if (rtnl->exit_event_source)
842 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
845 rtnl->event = sd_event_unref(rtnl->event);
850 int sd_rtnl_add_match(sd_rtnl *rtnl,
852 sd_rtnl_message_handler_t callback,
854 struct match_callback *c;
856 assert_return(rtnl, -EINVAL);
857 assert_return(callback, -EINVAL);
858 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
859 assert_return(rtnl_message_type_is_link(type) ||
860 rtnl_message_type_is_addr(type) ||
861 rtnl_message_type_is_route(type), -ENOTSUP);
863 c = new0(struct match_callback, 1);
867 c->callback = callback;
869 c->userdata = userdata;
871 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
876 int sd_rtnl_remove_match(sd_rtnl *rtnl,
878 sd_rtnl_message_handler_t callback,
880 struct match_callback *c;
882 assert_return(rtnl, -EINVAL);
883 assert_return(callback, -EINVAL);
884 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
886 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
887 if (c->callback == callback && c->type == type && c->userdata == userdata) {
888 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);