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>
31 #include "rtnl-internal.h"
32 #include "rtnl-util.h"
34 static int sd_rtnl_new(sd_rtnl **ret) {
35 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
37 assert_return(ret, -EINVAL);
39 rtnl = new0(sd_rtnl, 1);
43 rtnl->n_ref = REFCNT_INIT;
47 rtnl->sockaddr.nl.nl_family = AF_NETLINK;
49 rtnl->original_pid = getpid();
51 LIST_HEAD_INIT(rtnl->match_callbacks);
53 /* We guarantee that wqueue always has space for at least
55 if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
58 /* We guarantee that the read buffer has at least space for
60 if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
61 sizeof(struct nlmsghdr), sizeof(uint8_t)))
64 /* Change notification responses have sequence 0, so we must
65 * start our request sequence numbers at 1, or we may confuse our
66 * responses with notifications from the kernel */
75 int sd_rtnl_new_from_netlink(sd_rtnl **ret, int fd) {
76 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
80 assert_return(ret, -EINVAL);
82 r = sd_rtnl_new(&rtnl);
86 addrlen = sizeof(rtnl->sockaddr);
88 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
100 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
103 /* We don't support people creating an rtnl connection and
104 * keeping it around over a fork(). Let's complain. */
106 return rtnl->original_pid != getpid();
109 static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
113 for (i = 0; i < n_groups; i++) {
116 group = va_arg(ap, unsigned);
117 assert_return(group < 32, -EINVAL);
119 groups |= group ? (1 << (group - 1)) : 0;
127 static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) {
128 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
132 assert_return(ret, -EINVAL);
133 assert_return(fd >= 0, -EINVAL);
135 r = sd_rtnl_new(&rtnl);
139 r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
143 r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
147 r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
151 addrlen = sizeof(rtnl->sockaddr);
153 r = bind(fd, &rtnl->sockaddr.sa, addrlen);
154 /* ignore EINVAL to allow opening an already bound socket */
155 if (r < 0 && errno != EINVAL)
158 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
170 int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) {
174 va_start(ap, n_groups);
175 r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
181 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
185 fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
189 va_start(ap, n_groups);
190 r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
201 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
202 return fd_inc_rcvbuf(rtnl->fd, size);
205 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
206 assert_return(rtnl, NULL);
207 assert_return(!rtnl_pid_changed(rtnl), NULL);
210 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
215 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
219 assert_return(!rtnl_pid_changed(rtnl), NULL);
221 if (REFCNT_DEC(rtnl->n_ref) == 0) {
222 struct match_callback *f;
225 for (i = 0; i < rtnl->rqueue_size; i++)
226 sd_rtnl_message_unref(rtnl->rqueue[i]);
229 for (i = 0; i < rtnl->rqueue_partial_size; i++)
230 sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
231 free(rtnl->rqueue_partial);
233 for (i = 0; i < rtnl->wqueue_size; i++)
234 sd_rtnl_message_unref(rtnl->wqueue[i]);
239 hashmap_free_free(rtnl->reply_callbacks);
240 prioq_free(rtnl->reply_callbacks_prioq);
242 sd_event_source_unref(rtnl->io_event_source);
243 sd_event_source_unref(rtnl->time_event_source);
244 sd_event_source_unref(rtnl->exit_event_source);
245 sd_event_unref(rtnl->event);
247 while ((f = rtnl->match_callbacks)) {
248 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
252 safe_close(rtnl->fd);
259 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
261 assert(!rtnl_pid_changed(rtnl));
265 /* don't use seq == 0, as that is used for broadcasts, so we
266 would get confused by replies to such messages */
267 m->hdr->nlmsg_seq = rtnl->serial++ ? : rtnl->serial++;
269 rtnl_message_seal(m);
274 int sd_rtnl_send(sd_rtnl *nl,
275 sd_rtnl_message *message,
279 assert_return(nl, -EINVAL);
280 assert_return(!rtnl_pid_changed(nl), -ECHILD);
281 assert_return(message, -EINVAL);
282 assert_return(!message->sealed, -EPERM);
284 rtnl_seal_message(nl, message);
286 if (nl->wqueue_size <= 0) {
288 r = socket_write_message(nl, message);
292 /* nothing was sent, so let's put it on
294 nl->wqueue[0] = sd_rtnl_message_ref(message);
298 /* append to queue */
299 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
300 log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
304 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
307 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
311 *serial = rtnl_message_get_serial(message);
316 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
319 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
320 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
324 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
330 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
333 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
334 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
338 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
339 rtnl->rqueue_partial_size + 1))
345 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
351 if (rtnl->rqueue_size <= 0) {
352 /* Try to read a new message */
353 r = socket_read_message(rtnl);
358 /* Dispatch a queued message */
359 *message = rtnl->rqueue[0];
360 rtnl->rqueue_size --;
361 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
366 static int dispatch_wqueue(sd_rtnl *rtnl) {
371 while (rtnl->wqueue_size > 0) {
372 r = socket_write_message(rtnl, rtnl->wqueue[0]);
376 /* Didn't do anything this time */
379 /* see equivalent in sd-bus.c */
380 sd_rtnl_message_unref(rtnl->wqueue[0]);
381 rtnl->wqueue_size --;
382 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
391 static int process_timeout(sd_rtnl *rtnl) {
392 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
393 struct reply_callback *c;
399 c = prioq_peek(rtnl->reply_callbacks_prioq);
403 n = now(CLOCK_MONOTONIC);
407 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
411 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
412 hashmap_remove(rtnl->reply_callbacks, &c->serial);
414 r = c->callback(rtnl, m, c->userdata);
416 log_debug_errno(r, "sd-rtnl: timedout callback failed: %m");
423 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
424 _cleanup_free_ struct reply_callback *c = NULL;
432 serial = rtnl_message_get_serial(m);
433 c = hashmap_remove(rtnl->reply_callbacks, &serial);
438 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
440 r = sd_rtnl_message_get_type(m, &type);
444 if (type == NLMSG_DONE)
447 r = c->callback(rtnl, m, c->userdata);
449 log_debug_errno(r, "sd-rtnl: callback failed: %m");
454 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
455 struct match_callback *c;
462 r = sd_rtnl_message_get_type(m, &type);
466 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
467 if (type == c->type) {
468 r = c->callback(rtnl, m, c->userdata);
471 log_debug_errno(r, "sd-rtnl: match callback failed: %m");
481 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
482 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
487 r = process_timeout(rtnl);
491 r = dispatch_wqueue(rtnl);
495 r = dispatch_rqueue(rtnl, &m);
501 if (sd_rtnl_message_is_broadcast(m)) {
502 r = process_match(rtnl, m);
506 r = process_reply(rtnl, m);
527 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
528 RTNL_DONT_DESTROY(rtnl);
531 assert_return(rtnl, -EINVAL);
532 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
533 assert_return(!rtnl->processing, -EBUSY);
535 rtnl->processing = true;
536 r = process_running(rtnl, ret);
537 rtnl->processing = false;
542 static usec_t calc_elapse(uint64_t usec) {
543 if (usec == (uint64_t) -1)
547 usec = RTNL_DEFAULT_TIMEOUT;
549 return now(CLOCK_MONOTONIC) + usec;
552 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
553 struct pollfd p[1] = {};
555 usec_t m = USEC_INFINITY;
560 e = sd_rtnl_get_events(rtnl);
565 /* Caller wants more data, and doesn't care about
566 * what's been read or any other timeouts. */
570 /* Caller wants to process if there is something to
571 * process, but doesn't care otherwise */
573 r = sd_rtnl_get_timeout(rtnl, &until);
578 nw = now(CLOCK_MONOTONIC);
579 m = until > nw ? until - nw : 0;
583 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
589 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
593 return r > 0 ? 1 : 0;
596 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
597 assert_return(nl, -EINVAL);
598 assert_return(!rtnl_pid_changed(nl), -ECHILD);
600 if (nl->rqueue_size > 0)
603 return rtnl_poll(nl, false, timeout_usec);
606 static int timeout_compare(const void *a, const void *b) {
607 const struct reply_callback *x = a, *y = b;
609 if (x->timeout != 0 && y->timeout == 0)
612 if (x->timeout == 0 && y->timeout != 0)
615 if (x->timeout < y->timeout)
618 if (x->timeout > y->timeout)
624 int sd_rtnl_call_async(sd_rtnl *nl,
626 sd_rtnl_message_handler_t callback,
630 struct reply_callback *c;
634 assert_return(nl, -EINVAL);
635 assert_return(m, -EINVAL);
636 assert_return(callback, -EINVAL);
637 assert_return(!rtnl_pid_changed(nl), -ECHILD);
639 r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
643 if (usec != (uint64_t) -1) {
644 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
649 c = new0(struct reply_callback, 1);
653 c->callback = callback;
654 c->userdata = userdata;
655 c->timeout = calc_elapse(usec);
657 k = sd_rtnl_send(nl, m, &s);
665 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
671 if (c->timeout != 0) {
672 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
675 sd_rtnl_call_async_cancel(nl, c->serial);
686 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
687 struct reply_callback *c;
690 assert_return(nl, -EINVAL);
691 assert_return(serial != 0, -EINVAL);
692 assert_return(!rtnl_pid_changed(nl), -ECHILD);
694 c = hashmap_remove(nl->reply_callbacks, &s);
699 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
705 int sd_rtnl_call(sd_rtnl *rtnl,
706 sd_rtnl_message *message,
708 sd_rtnl_message **ret) {
713 assert_return(rtnl, -EINVAL);
714 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
715 assert_return(message, -EINVAL);
717 r = sd_rtnl_send(rtnl, message, &serial);
721 timeout = calc_elapse(usec);
727 for (i = 0; i < rtnl->rqueue_size; i++) {
728 uint32_t received_serial;
730 received_serial = rtnl_message_get_serial(rtnl->rqueue[i]);
732 if (received_serial == serial) {
733 _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
736 incoming = rtnl->rqueue[i];
738 /* found a match, remove from rqueue and return it */
739 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
740 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
743 r = sd_rtnl_message_get_errno(incoming);
747 r = sd_rtnl_message_get_type(incoming, &type);
751 if (type == NLMSG_DONE) {
765 r = socket_read_message(rtnl);
769 /* received message, so try to process straight away */
775 n = now(CLOCK_MONOTONIC);
781 left = (uint64_t) -1;
783 r = rtnl_poll(rtnl, true, left);
789 r = dispatch_wqueue(rtnl);
795 int sd_rtnl_flush(sd_rtnl *rtnl) {
798 assert_return(rtnl, -EINVAL);
799 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
801 if (rtnl->wqueue_size <= 0)
805 r = dispatch_wqueue(rtnl);
809 if (rtnl->wqueue_size <= 0)
812 r = rtnl_poll(rtnl, false, (uint64_t) -1);
818 int sd_rtnl_get_events(sd_rtnl *rtnl) {
821 assert_return(rtnl, -EINVAL);
822 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
824 if (rtnl->rqueue_size <= 0)
826 if (rtnl->wqueue_size > 0)
832 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
833 struct reply_callback *c;
835 assert_return(rtnl, -EINVAL);
836 assert_return(timeout_usec, -EINVAL);
837 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
839 if (rtnl->rqueue_size > 0) {
844 c = prioq_peek(rtnl->reply_callbacks_prioq);
846 *timeout_usec = (uint64_t) -1;
850 *timeout_usec = c->timeout;
855 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
856 sd_rtnl *rtnl = userdata;
861 r = sd_rtnl_process(rtnl, NULL);
868 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
869 sd_rtnl *rtnl = userdata;
874 r = sd_rtnl_process(rtnl, NULL);
881 static int prepare_callback(sd_event_source *s, void *userdata) {
882 sd_rtnl *rtnl = userdata;
889 e = sd_rtnl_get_events(rtnl);
893 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
897 r = sd_rtnl_get_timeout(rtnl, &until);
903 j = sd_event_source_set_time(rtnl->time_event_source, until);
908 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
915 static int exit_callback(sd_event_source *event, void *userdata) {
916 sd_rtnl *rtnl = userdata;
925 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
928 assert_return(rtnl, -EINVAL);
929 assert_return(!rtnl->event, -EBUSY);
931 assert(!rtnl->io_event_source);
932 assert(!rtnl->time_event_source);
935 rtnl->event = sd_event_ref(event);
937 r = sd_event_default(&rtnl->event);
942 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
946 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
950 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
954 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
958 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
962 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
966 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
970 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
974 r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
981 sd_rtnl_detach_event(rtnl);
985 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
986 assert_return(rtnl, -EINVAL);
987 assert_return(rtnl->event, -ENXIO);
989 if (rtnl->io_event_source)
990 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
992 if (rtnl->time_event_source)
993 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
995 if (rtnl->exit_event_source)
996 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
999 rtnl->event = sd_event_unref(rtnl->event);
1004 int sd_rtnl_add_match(sd_rtnl *rtnl,
1006 sd_rtnl_message_handler_t callback,
1008 struct match_callback *c;
1010 assert_return(rtnl, -EINVAL);
1011 assert_return(callback, -EINVAL);
1012 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
1013 assert_return(rtnl_message_type_is_link(type) ||
1014 rtnl_message_type_is_addr(type) ||
1015 rtnl_message_type_is_route(type), -EOPNOTSUPP);
1017 c = new0(struct match_callback, 1);
1021 c->callback = callback;
1023 c->userdata = userdata;
1025 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
1030 int sd_rtnl_remove_match(sd_rtnl *rtnl,
1032 sd_rtnl_message_handler_t callback,
1034 struct match_callback *c;
1036 assert_return(rtnl, -EINVAL);
1037 assert_return(callback, -EINVAL);
1038 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
1040 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
1041 if (c->callback == callback && c->type == type && c->userdata == userdata) {
1042 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);