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)))
70 int sd_rtnl_new_from_netlink(sd_rtnl **ret, int fd) {
71 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
75 assert_return(ret, -EINVAL);
77 r = sd_rtnl_new(&rtnl);
81 addrlen = sizeof(rtnl->sockaddr);
83 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
95 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
98 /* We don't support people creating an rtnl connection and
99 * keeping it around over a fork(). Let's complain. */
101 return rtnl->original_pid != getpid();
104 static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
108 for (i = 0; i < n_groups; i++) {
111 group = va_arg(ap, unsigned);
112 assert_return(group < 32, -EINVAL);
114 groups |= group ? (1 << (group - 1)) : 0;
122 static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) {
123 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
127 assert_return(ret, -EINVAL);
128 assert_return(fd >= 0, -EINVAL);
130 r = sd_rtnl_new(&rtnl);
134 r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
138 r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
142 r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
146 addrlen = sizeof(rtnl->sockaddr);
148 r = bind(fd, &rtnl->sockaddr.sa, addrlen);
149 /* ignore EINVAL to allow opening an already bound socket */
150 if (r < 0 && errno != EINVAL)
153 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
165 int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) {
169 va_start(ap, n_groups);
170 r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
176 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
180 fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
184 va_start(ap, n_groups);
185 r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
196 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
197 return fd_inc_rcvbuf(rtnl->fd, size);
200 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
201 assert_return(rtnl, NULL);
202 assert_return(!rtnl_pid_changed(rtnl), NULL);
205 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
210 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
214 assert_return(!rtnl_pid_changed(rtnl), NULL);
216 if (REFCNT_DEC(rtnl->n_ref) == 0) {
217 struct match_callback *f;
220 for (i = 0; i < rtnl->rqueue_size; i++)
221 sd_rtnl_message_unref(rtnl->rqueue[i]);
224 for (i = 0; i < rtnl->rqueue_partial_size; i++)
225 sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
226 free(rtnl->rqueue_partial);
228 for (i = 0; i < rtnl->wqueue_size; i++)
229 sd_rtnl_message_unref(rtnl->wqueue[i]);
234 hashmap_free_free(rtnl->reply_callbacks);
235 prioq_free(rtnl->reply_callbacks_prioq);
237 sd_event_source_unref(rtnl->io_event_source);
238 sd_event_source_unref(rtnl->time_event_source);
239 sd_event_source_unref(rtnl->exit_event_source);
240 sd_event_unref(rtnl->event);
242 while ((f = rtnl->match_callbacks)) {
243 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
247 safe_close(rtnl->fd);
254 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
256 assert(!rtnl_pid_changed(rtnl));
260 m->hdr->nlmsg_seq = rtnl->serial++;
262 rtnl_message_seal(m);
267 int sd_rtnl_send(sd_rtnl *nl,
268 sd_rtnl_message *message,
272 assert_return(nl, -EINVAL);
273 assert_return(!rtnl_pid_changed(nl), -ECHILD);
274 assert_return(message, -EINVAL);
275 assert_return(!message->sealed, -EPERM);
277 rtnl_seal_message(nl, message);
279 if (nl->wqueue_size <= 0) {
281 r = socket_write_message(nl, message);
285 /* nothing was sent, so let's put it on
287 nl->wqueue[0] = sd_rtnl_message_ref(message);
291 /* append to queue */
292 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
293 log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
297 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
300 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
304 *serial = rtnl_message_get_serial(message);
309 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
312 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
313 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
317 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
323 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
326 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
327 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
331 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
332 rtnl->rqueue_partial_size + 1))
338 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
344 if (rtnl->rqueue_size <= 0) {
345 /* Try to read a new message */
346 r = socket_read_message(rtnl);
351 /* Dispatch a queued message */
352 *message = rtnl->rqueue[0];
353 rtnl->rqueue_size --;
354 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
359 static int dispatch_wqueue(sd_rtnl *rtnl) {
364 while (rtnl->wqueue_size > 0) {
365 r = socket_write_message(rtnl, rtnl->wqueue[0]);
369 /* Didn't do anything this time */
372 /* see equivalent in sd-bus.c */
373 sd_rtnl_message_unref(rtnl->wqueue[0]);
374 rtnl->wqueue_size --;
375 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
384 static int process_timeout(sd_rtnl *rtnl) {
385 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
386 struct reply_callback *c;
392 c = prioq_peek(rtnl->reply_callbacks_prioq);
396 n = now(CLOCK_MONOTONIC);
400 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
404 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
405 hashmap_remove(rtnl->reply_callbacks, &c->serial);
407 r = c->callback(rtnl, m, c->userdata);
409 log_debug_errno(r, "sd-rtnl: timedout callback failed: %m");
416 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
417 struct reply_callback *c;
424 if (sd_rtnl_message_is_broadcast(m))
427 serial = rtnl_message_get_serial(m);
428 c = hashmap_remove(rtnl->reply_callbacks, &serial);
433 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
435 r = c->callback(rtnl, m, c->userdata);
437 log_debug_errno(r, "sd-rtnl: callback failed: %m");
444 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
445 struct match_callback *c;
452 r = sd_rtnl_message_get_type(m, &type);
456 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
457 if (type == c->type) {
458 r = c->callback(rtnl, m, c->userdata);
461 log_debug_errno(r, "sd-rtnl: match callback failed: %m");
471 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
472 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
477 r = process_timeout(rtnl);
481 r = dispatch_wqueue(rtnl);
485 r = dispatch_rqueue(rtnl, &m);
491 r = process_reply(rtnl, m);
495 r = process_match(rtnl, m);
515 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
516 RTNL_DONT_DESTROY(rtnl);
519 assert_return(rtnl, -EINVAL);
520 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
521 assert_return(!rtnl->processing, -EBUSY);
523 rtnl->processing = true;
524 r = process_running(rtnl, ret);
525 rtnl->processing = false;
530 static usec_t calc_elapse(uint64_t usec) {
531 if (usec == (uint64_t) -1)
535 usec = RTNL_DEFAULT_TIMEOUT;
537 return now(CLOCK_MONOTONIC) + usec;
540 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
541 struct pollfd p[1] = {};
543 usec_t m = USEC_INFINITY;
548 e = sd_rtnl_get_events(rtnl);
553 /* Caller wants more data, and doesn't care about
554 * what's been read or any other timeouts. */
558 /* Caller wants to process if there is something to
559 * process, but doesn't care otherwise */
561 r = sd_rtnl_get_timeout(rtnl, &until);
566 nw = now(CLOCK_MONOTONIC);
567 m = until > nw ? until - nw : 0;
571 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
577 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
581 return r > 0 ? 1 : 0;
584 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
585 assert_return(nl, -EINVAL);
586 assert_return(!rtnl_pid_changed(nl), -ECHILD);
588 if (nl->rqueue_size > 0)
591 return rtnl_poll(nl, false, timeout_usec);
594 static int timeout_compare(const void *a, const void *b) {
595 const struct reply_callback *x = a, *y = b;
597 if (x->timeout != 0 && y->timeout == 0)
600 if (x->timeout == 0 && y->timeout != 0)
603 if (x->timeout < y->timeout)
606 if (x->timeout > y->timeout)
612 int sd_rtnl_call_async(sd_rtnl *nl,
614 sd_rtnl_message_handler_t callback,
618 struct reply_callback *c;
622 assert_return(nl, -EINVAL);
623 assert_return(m, -EINVAL);
624 assert_return(callback, -EINVAL);
625 assert_return(!rtnl_pid_changed(nl), -ECHILD);
627 r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
631 if (usec != (uint64_t) -1) {
632 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
637 c = new0(struct reply_callback, 1);
641 c->callback = callback;
642 c->userdata = userdata;
643 c->timeout = calc_elapse(usec);
645 k = sd_rtnl_send(nl, m, &s);
653 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
659 if (c->timeout != 0) {
660 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
663 sd_rtnl_call_async_cancel(nl, c->serial);
674 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
675 struct reply_callback *c;
678 assert_return(nl, -EINVAL);
679 assert_return(serial != 0, -EINVAL);
680 assert_return(!rtnl_pid_changed(nl), -ECHILD);
682 c = hashmap_remove(nl->reply_callbacks, &s);
687 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
693 int sd_rtnl_call(sd_rtnl *rtnl,
694 sd_rtnl_message *message,
696 sd_rtnl_message **ret) {
702 assert_return(rtnl, -EINVAL);
703 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
704 assert_return(message, -EINVAL);
706 r = sd_rtnl_send(rtnl, message, &serial);
710 timeout = calc_elapse(usec);
715 while (i < rtnl->rqueue_size) {
716 sd_rtnl_message *incoming;
717 uint32_t received_serial;
719 incoming = rtnl->rqueue[i];
720 received_serial = rtnl_message_get_serial(incoming);
722 if (received_serial == serial) {
723 /* found a match, remove from rqueue and return it */
724 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
725 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
728 r = sd_rtnl_message_get_errno(incoming);
730 sd_rtnl_message_unref(incoming);
737 sd_rtnl_message_unref(incoming);
742 /* Try to read more, right away */
746 r = socket_read_message(rtnl);
750 /* received message, so try to process straight away */
756 n = now(CLOCK_MONOTONIC);
762 left = (uint64_t) -1;
764 r = rtnl_poll(rtnl, true, left);
770 r = dispatch_wqueue(rtnl);
776 int sd_rtnl_flush(sd_rtnl *rtnl) {
779 assert_return(rtnl, -EINVAL);
780 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
782 if (rtnl->wqueue_size <= 0)
786 r = dispatch_wqueue(rtnl);
790 if (rtnl->wqueue_size <= 0)
793 r = rtnl_poll(rtnl, false, (uint64_t) -1);
799 int sd_rtnl_get_events(sd_rtnl *rtnl) {
802 assert_return(rtnl, -EINVAL);
803 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
805 if (rtnl->rqueue_size <= 0)
807 if (rtnl->wqueue_size > 0)
813 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
814 struct reply_callback *c;
816 assert_return(rtnl, -EINVAL);
817 assert_return(timeout_usec, -EINVAL);
818 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
820 if (rtnl->rqueue_size > 0) {
825 c = prioq_peek(rtnl->reply_callbacks_prioq);
827 *timeout_usec = (uint64_t) -1;
831 *timeout_usec = c->timeout;
836 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
837 sd_rtnl *rtnl = userdata;
842 r = sd_rtnl_process(rtnl, NULL);
849 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
850 sd_rtnl *rtnl = userdata;
855 r = sd_rtnl_process(rtnl, NULL);
862 static int prepare_callback(sd_event_source *s, void *userdata) {
863 sd_rtnl *rtnl = userdata;
870 e = sd_rtnl_get_events(rtnl);
874 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
878 r = sd_rtnl_get_timeout(rtnl, &until);
884 j = sd_event_source_set_time(rtnl->time_event_source, until);
889 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
896 static int exit_callback(sd_event_source *event, void *userdata) {
897 sd_rtnl *rtnl = userdata;
906 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
909 assert_return(rtnl, -EINVAL);
910 assert_return(!rtnl->event, -EBUSY);
912 assert(!rtnl->io_event_source);
913 assert(!rtnl->time_event_source);
916 rtnl->event = sd_event_ref(event);
918 r = sd_event_default(&rtnl->event);
923 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
927 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
931 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
935 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
939 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
943 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
947 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
951 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
955 r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
962 sd_rtnl_detach_event(rtnl);
966 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
967 assert_return(rtnl, -EINVAL);
968 assert_return(rtnl->event, -ENXIO);
970 if (rtnl->io_event_source)
971 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
973 if (rtnl->time_event_source)
974 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
976 if (rtnl->exit_event_source)
977 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
980 rtnl->event = sd_event_unref(rtnl->event);
985 int sd_rtnl_add_match(sd_rtnl *rtnl,
987 sd_rtnl_message_handler_t callback,
989 struct match_callback *c;
991 assert_return(rtnl, -EINVAL);
992 assert_return(callback, -EINVAL);
993 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
994 assert_return(rtnl_message_type_is_link(type) ||
995 rtnl_message_type_is_addr(type) ||
996 rtnl_message_type_is_route(type), -ENOTSUP);
998 c = new0(struct match_callback, 1);
1002 c->callback = callback;
1004 c->userdata = userdata;
1006 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
1011 int sd_rtnl_remove_match(sd_rtnl *rtnl,
1013 sd_rtnl_message_handler_t callback,
1015 struct match_callback *c;
1017 assert_return(rtnl, -EINVAL);
1018 assert_return(callback, -EINVAL);
1019 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
1021 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
1022 if (c->callback == callback && c->type == type && c->userdata == userdata) {
1023 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);