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))
57 /* We guarantee that the read buffer has at least space for
59 if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
60 sizeof(struct nlmsghdr), sizeof(uint8_t)))
69 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
72 /* We don't support people creating an rtnl connection and
73 * keeping it around over a fork(). Let's complain. */
75 return rtnl->original_pid != getpid();
78 int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) {
79 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
83 assert_return(ret, -EINVAL);
85 r = sd_rtnl_new(&rtnl);
89 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
93 if (setsockopt(rtnl->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
96 rtnl->sockaddr.nl.nl_groups = groups;
98 addrlen = sizeof(rtnl->sockaddr);
100 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
104 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
114 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
115 assert_return(rtnl, NULL);
116 assert_return(!rtnl_pid_changed(rtnl), NULL);
119 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
124 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
128 assert_return(!rtnl_pid_changed(rtnl), NULL);
130 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
131 struct match_callback *f;
134 for (i = 0; i < rtnl->rqueue_size; i++)
135 sd_rtnl_message_unref(rtnl->rqueue[i]);
138 for (i = 0; i < rtnl->wqueue_size; i++)
139 sd_rtnl_message_unref(rtnl->wqueue[i]);
144 hashmap_free_free(rtnl->reply_callbacks);
145 prioq_free(rtnl->reply_callbacks_prioq);
147 sd_event_source_unref(rtnl->io_event_source);
148 sd_event_source_unref(rtnl->time_event_source);
149 sd_event_source_unref(rtnl->exit_event_source);
150 sd_event_unref(rtnl->event);
152 while ((f = rtnl->match_callbacks)) {
153 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
157 safe_close(rtnl->fd);
164 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
166 assert(!rtnl_pid_changed(rtnl));
170 m->hdr->nlmsg_seq = rtnl->serial++;
172 rtnl_message_seal(m);
177 int sd_rtnl_send(sd_rtnl *nl,
178 sd_rtnl_message *message,
182 assert_return(nl, -EINVAL);
183 assert_return(!rtnl_pid_changed(nl), -ECHILD);
184 assert_return(message, -EINVAL);
185 assert_return(!message->sealed, -EPERM);
187 rtnl_seal_message(nl, message);
189 if (nl->wqueue_size <= 0) {
191 r = socket_write_message(nl, message);
195 /* nothing was sent, so let's put it on
197 nl->wqueue[0] = sd_rtnl_message_ref(message);
201 /* append to queue */
202 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
205 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
208 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
212 *serial = rtnl_message_get_serial(message);
217 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
220 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX)
223 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
229 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
235 if (rtnl->rqueue_size <= 0) {
236 /* Try to read a new message */
237 r = socket_read_message(rtnl);
242 /* Dispatch a queued message */
243 *message = rtnl->rqueue[0];
244 rtnl->rqueue_size --;
245 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
250 static int dispatch_wqueue(sd_rtnl *rtnl) {
255 while (rtnl->wqueue_size > 0) {
256 r = socket_write_message(rtnl, rtnl->wqueue[0]);
260 /* Didn't do anything this time */
263 /* see equivalent in sd-bus.c */
264 sd_rtnl_message_unref(rtnl->wqueue[0]);
265 rtnl->wqueue_size --;
266 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
275 static int process_timeout(sd_rtnl *rtnl) {
276 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
277 struct reply_callback *c;
283 c = prioq_peek(rtnl->reply_callbacks_prioq);
287 n = now(CLOCK_MONOTONIC);
291 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
295 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
296 hashmap_remove(rtnl->reply_callbacks, &c->serial);
298 r = c->callback(rtnl, m, c->userdata);
301 return r < 0 ? r : 1;
304 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
305 struct reply_callback *c;
312 if (sd_rtnl_message_is_broadcast(m))
315 serial = rtnl_message_get_serial(m);
316 c = hashmap_remove(rtnl->reply_callbacks, &serial);
321 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
323 r = c->callback(rtnl, m, c->userdata);
329 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
330 struct match_callback *c;
337 r = sd_rtnl_message_get_type(m, &type);
341 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
342 if (type == c->type) {
343 r = c->callback(rtnl, m, c->userdata);
352 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
353 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
358 r = process_timeout(rtnl);
362 r = dispatch_wqueue(rtnl);
366 r = dispatch_rqueue(rtnl, &m);
372 r = process_reply(rtnl, m);
376 r = process_match(rtnl, m);
396 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
397 RTNL_DONT_DESTROY(rtnl);
400 assert_return(rtnl, -EINVAL);
401 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
402 assert_return(!rtnl->processing, -EBUSY);
404 rtnl->processing = true;
405 r = process_running(rtnl, ret);
406 rtnl->processing = false;
411 static usec_t calc_elapse(uint64_t usec) {
412 if (usec == (uint64_t) -1)
416 usec = RTNL_DEFAULT_TIMEOUT;
418 return now(CLOCK_MONOTONIC) + usec;
421 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
422 struct pollfd p[1] = {};
424 usec_t m = (usec_t) -1;
429 e = sd_rtnl_get_events(rtnl);
434 /* Caller wants more data, and doesn't care about
435 * what's been read or any other timeouts. */
439 /* Caller wants to process if there is something to
440 * process, but doesn't care otherwise */
442 r = sd_rtnl_get_timeout(rtnl, &until);
447 nw = now(CLOCK_MONOTONIC);
448 m = until > nw ? until - nw : 0;
452 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
458 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
462 return r > 0 ? 1 : 0;
465 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
466 assert_return(nl, -EINVAL);
467 assert_return(!rtnl_pid_changed(nl), -ECHILD);
469 if (nl->rqueue_size > 0)
472 return rtnl_poll(nl, false, timeout_usec);
475 static int timeout_compare(const void *a, const void *b) {
476 const struct reply_callback *x = a, *y = b;
478 if (x->timeout != 0 && y->timeout == 0)
481 if (x->timeout == 0 && y->timeout != 0)
484 if (x->timeout < y->timeout)
487 if (x->timeout > y->timeout)
493 int sd_rtnl_call_async(sd_rtnl *nl,
495 sd_rtnl_message_handler_t callback,
499 struct reply_callback *c;
503 assert_return(nl, -EINVAL);
504 assert_return(m, -EINVAL);
505 assert_return(callback, -EINVAL);
506 assert_return(!rtnl_pid_changed(nl), -ECHILD);
508 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
512 if (usec != (uint64_t) -1) {
513 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
518 c = new0(struct reply_callback, 1);
522 c->callback = callback;
523 c->userdata = userdata;
524 c->timeout = calc_elapse(usec);
526 k = sd_rtnl_send(nl, m, &s);
534 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
540 if (c->timeout != 0) {
541 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
544 sd_rtnl_call_async_cancel(nl, c->serial);
555 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
556 struct reply_callback *c;
559 assert_return(nl, -EINVAL);
560 assert_return(serial != 0, -EINVAL);
561 assert_return(!rtnl_pid_changed(nl), -ECHILD);
563 c = hashmap_remove(nl->reply_callbacks, &s);
568 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
574 int sd_rtnl_call(sd_rtnl *rtnl,
575 sd_rtnl_message *message,
577 sd_rtnl_message **ret) {
583 assert_return(rtnl, -EINVAL);
584 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
585 assert_return(message, -EINVAL);
587 r = sd_rtnl_send(rtnl, message, &serial);
591 timeout = calc_elapse(usec);
596 while (i < rtnl->rqueue_size) {
597 sd_rtnl_message *incoming;
598 uint32_t received_serial;
600 incoming = rtnl->rqueue[i];
601 received_serial = rtnl_message_get_serial(incoming);
603 if (received_serial == serial) {
604 /* found a match, remove from rqueue and return it */
605 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
606 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
609 r = sd_rtnl_message_get_errno(incoming);
611 sd_rtnl_message_unref(incoming);
618 sd_rtnl_message_unref(incoming);
623 /* Try to read more, right away */
627 r = socket_read_message(rtnl);
631 /* receieved message, so try to process straight away */
637 n = now(CLOCK_MONOTONIC);
643 left = (uint64_t) -1;
645 r = rtnl_poll(rtnl, true, left);
649 r = dispatch_wqueue(rtnl);
655 int sd_rtnl_flush(sd_rtnl *rtnl) {
658 assert_return(rtnl, -EINVAL);
659 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
661 if (rtnl->wqueue_size <= 0)
665 r = dispatch_wqueue(rtnl);
669 if (rtnl->wqueue_size <= 0)
672 r = rtnl_poll(rtnl, false, (uint64_t) -1);
678 int sd_rtnl_get_events(sd_rtnl *rtnl) {
681 assert_return(rtnl, -EINVAL);
682 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
684 if (rtnl->rqueue_size <= 0)
686 if (rtnl->wqueue_size > 0)
692 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
693 struct reply_callback *c;
695 assert_return(rtnl, -EINVAL);
696 assert_return(timeout_usec, -EINVAL);
697 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
699 if (rtnl->rqueue_size > 0) {
704 c = prioq_peek(rtnl->reply_callbacks_prioq);
706 *timeout_usec = (uint64_t) -1;
710 *timeout_usec = c->timeout;
715 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
716 sd_rtnl *rtnl = userdata;
721 r = sd_rtnl_process(rtnl, NULL);
728 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
729 sd_rtnl *rtnl = userdata;
734 r = sd_rtnl_process(rtnl, NULL);
741 static int prepare_callback(sd_event_source *s, void *userdata) {
742 sd_rtnl *rtnl = userdata;
749 e = sd_rtnl_get_events(rtnl);
753 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
757 r = sd_rtnl_get_timeout(rtnl, &until);
763 j = sd_event_source_set_time(rtnl->time_event_source, until);
768 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
775 static int exit_callback(sd_event_source *event, void *userdata) {
776 sd_rtnl *rtnl = userdata;
785 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
788 assert_return(rtnl, -EINVAL);
789 assert_return(!rtnl->event, -EBUSY);
791 assert(!rtnl->io_event_source);
792 assert(!rtnl->time_event_source);
795 rtnl->event = sd_event_ref(event);
797 r = sd_event_default(&rtnl->event);
802 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
806 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
810 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
814 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
818 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
822 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
829 sd_rtnl_detach_event(rtnl);
833 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
834 assert_return(rtnl, -EINVAL);
835 assert_return(rtnl->event, -ENXIO);
837 if (rtnl->io_event_source)
838 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
840 if (rtnl->time_event_source)
841 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
843 if (rtnl->exit_event_source)
844 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
847 rtnl->event = sd_event_unref(rtnl->event);
852 int sd_rtnl_add_match(sd_rtnl *rtnl,
854 sd_rtnl_message_handler_t callback,
856 struct match_callback *c;
858 assert_return(rtnl, -EINVAL);
859 assert_return(callback, -EINVAL);
860 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
861 assert_return(rtnl_message_type_is_link(type) ||
862 rtnl_message_type_is_addr(type) ||
863 rtnl_message_type_is_route(type), -ENOTSUP);
865 c = new0(struct match_callback, 1);
869 c->callback = callback;
871 c->userdata = userdata;
873 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
878 int sd_rtnl_remove_match(sd_rtnl *rtnl,
880 sd_rtnl_message_handler_t callback,
882 struct match_callback *c;
884 assert_return(rtnl, -EINVAL);
885 assert_return(callback, -EINVAL);
886 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
888 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
889 if (c->callback == callback && c->type == type && c->userdata == userdata) {
890 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);