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 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
73 /* We don't support people creating an rtnl connection and
74 * keeping it around over a fork(). Let's complain. */
76 return rtnl->original_pid != getpid();
79 static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
83 for (i = 0; i < n_groups; i++) {
86 group = va_arg(ap, unsigned);
87 assert_return(group < 32, -EINVAL);
89 groups |= group ? (1 << (group - 1)) : 0;
97 static int rtnl_open_fd_ap(sd_rtnl **ret, int fd, unsigned n_groups, va_list ap) {
98 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
102 assert_return(ret, -EINVAL);
103 assert_return(fd >= 0, -EINVAL);
105 r = sd_rtnl_new(&rtnl);
109 r = setsockopt(fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
113 r = setsockopt(fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
117 r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
121 addrlen = sizeof(rtnl->sockaddr);
123 r = bind(fd, &rtnl->sockaddr.sa, addrlen);
127 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
139 int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) {
143 va_start(ap, n_groups);
144 r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
150 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
154 fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
158 va_start(ap, n_groups);
159 r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
170 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
171 return fd_inc_rcvbuf(rtnl->fd, size);
174 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
175 assert_return(rtnl, NULL);
176 assert_return(!rtnl_pid_changed(rtnl), NULL);
179 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
184 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
188 assert_return(!rtnl_pid_changed(rtnl), NULL);
190 if (REFCNT_DEC(rtnl->n_ref) == 0) {
191 struct match_callback *f;
194 for (i = 0; i < rtnl->rqueue_size; i++)
195 sd_rtnl_message_unref(rtnl->rqueue[i]);
198 for (i = 0; i < rtnl->rqueue_partial_size; i++)
199 sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
200 free(rtnl->rqueue_partial);
202 for (i = 0; i < rtnl->wqueue_size; i++)
203 sd_rtnl_message_unref(rtnl->wqueue[i]);
208 hashmap_free_free(rtnl->reply_callbacks);
209 prioq_free(rtnl->reply_callbacks_prioq);
211 sd_event_source_unref(rtnl->io_event_source);
212 sd_event_source_unref(rtnl->time_event_source);
213 sd_event_source_unref(rtnl->exit_event_source);
214 sd_event_unref(rtnl->event);
216 while ((f = rtnl->match_callbacks)) {
217 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
221 safe_close(rtnl->fd);
228 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
230 assert(!rtnl_pid_changed(rtnl));
234 m->hdr->nlmsg_seq = rtnl->serial++;
236 rtnl_message_seal(m);
241 int sd_rtnl_send(sd_rtnl *nl,
242 sd_rtnl_message *message,
246 assert_return(nl, -EINVAL);
247 assert_return(!rtnl_pid_changed(nl), -ECHILD);
248 assert_return(message, -EINVAL);
249 assert_return(!message->sealed, -EPERM);
251 rtnl_seal_message(nl, message);
253 if (nl->wqueue_size <= 0) {
255 r = socket_write_message(nl, message);
259 /* nothing was sent, so let's put it on
261 nl->wqueue[0] = sd_rtnl_message_ref(message);
265 /* append to queue */
266 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
267 log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
271 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
274 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
278 *serial = rtnl_message_get_serial(message);
283 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
286 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
287 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
291 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
297 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
300 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
301 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
305 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
306 rtnl->rqueue_partial_size + 1))
312 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
318 if (rtnl->rqueue_size <= 0) {
319 /* Try to read a new message */
320 r = socket_read_message(rtnl);
325 /* Dispatch a queued message */
326 *message = rtnl->rqueue[0];
327 rtnl->rqueue_size --;
328 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
333 static int dispatch_wqueue(sd_rtnl *rtnl) {
338 while (rtnl->wqueue_size > 0) {
339 r = socket_write_message(rtnl, rtnl->wqueue[0]);
343 /* Didn't do anything this time */
346 /* see equivalent in sd-bus.c */
347 sd_rtnl_message_unref(rtnl->wqueue[0]);
348 rtnl->wqueue_size --;
349 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
358 static int process_timeout(sd_rtnl *rtnl) {
359 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
360 struct reply_callback *c;
366 c = prioq_peek(rtnl->reply_callbacks_prioq);
370 n = now(CLOCK_MONOTONIC);
374 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
378 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
379 hashmap_remove(rtnl->reply_callbacks, &c->serial);
381 r = c->callback(rtnl, m, c->userdata);
384 return r < 0 ? r : 1;
387 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
388 struct reply_callback *c;
395 if (sd_rtnl_message_is_broadcast(m))
398 serial = rtnl_message_get_serial(m);
399 c = hashmap_remove(rtnl->reply_callbacks, &serial);
404 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
406 r = c->callback(rtnl, m, c->userdata);
412 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
413 struct match_callback *c;
420 r = sd_rtnl_message_get_type(m, &type);
424 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
425 if (type == c->type) {
426 r = c->callback(rtnl, m, c->userdata);
435 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
436 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
441 r = process_timeout(rtnl);
445 r = dispatch_wqueue(rtnl);
449 r = dispatch_rqueue(rtnl, &m);
455 r = process_reply(rtnl, m);
459 r = process_match(rtnl, m);
479 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
480 RTNL_DONT_DESTROY(rtnl);
483 assert_return(rtnl, -EINVAL);
484 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
485 assert_return(!rtnl->processing, -EBUSY);
487 rtnl->processing = true;
488 r = process_running(rtnl, ret);
489 rtnl->processing = false;
494 static usec_t calc_elapse(uint64_t usec) {
495 if (usec == (uint64_t) -1)
499 usec = RTNL_DEFAULT_TIMEOUT;
501 return now(CLOCK_MONOTONIC) + usec;
504 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
505 struct pollfd p[1] = {};
507 usec_t m = USEC_INFINITY;
512 e = sd_rtnl_get_events(rtnl);
517 /* Caller wants more data, and doesn't care about
518 * what's been read or any other timeouts. */
522 /* Caller wants to process if there is something to
523 * process, but doesn't care otherwise */
525 r = sd_rtnl_get_timeout(rtnl, &until);
530 nw = now(CLOCK_MONOTONIC);
531 m = until > nw ? until - nw : 0;
535 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
541 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
545 return r > 0 ? 1 : 0;
548 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
549 assert_return(nl, -EINVAL);
550 assert_return(!rtnl_pid_changed(nl), -ECHILD);
552 if (nl->rqueue_size > 0)
555 return rtnl_poll(nl, false, timeout_usec);
558 static int timeout_compare(const void *a, const void *b) {
559 const struct reply_callback *x = a, *y = b;
561 if (x->timeout != 0 && y->timeout == 0)
564 if (x->timeout == 0 && y->timeout != 0)
567 if (x->timeout < y->timeout)
570 if (x->timeout > y->timeout)
576 int sd_rtnl_call_async(sd_rtnl *nl,
578 sd_rtnl_message_handler_t callback,
582 struct reply_callback *c;
586 assert_return(nl, -EINVAL);
587 assert_return(m, -EINVAL);
588 assert_return(callback, -EINVAL);
589 assert_return(!rtnl_pid_changed(nl), -ECHILD);
591 r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
595 if (usec != (uint64_t) -1) {
596 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
601 c = new0(struct reply_callback, 1);
605 c->callback = callback;
606 c->userdata = userdata;
607 c->timeout = calc_elapse(usec);
609 k = sd_rtnl_send(nl, m, &s);
617 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
623 if (c->timeout != 0) {
624 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
627 sd_rtnl_call_async_cancel(nl, c->serial);
638 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
639 struct reply_callback *c;
642 assert_return(nl, -EINVAL);
643 assert_return(serial != 0, -EINVAL);
644 assert_return(!rtnl_pid_changed(nl), -ECHILD);
646 c = hashmap_remove(nl->reply_callbacks, &s);
651 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
657 int sd_rtnl_call(sd_rtnl *rtnl,
658 sd_rtnl_message *message,
660 sd_rtnl_message **ret) {
666 assert_return(rtnl, -EINVAL);
667 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
668 assert_return(message, -EINVAL);
670 r = sd_rtnl_send(rtnl, message, &serial);
674 timeout = calc_elapse(usec);
679 while (i < rtnl->rqueue_size) {
680 sd_rtnl_message *incoming;
681 uint32_t received_serial;
683 incoming = rtnl->rqueue[i];
684 received_serial = rtnl_message_get_serial(incoming);
686 if (received_serial == serial) {
687 /* found a match, remove from rqueue and return it */
688 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
689 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
692 r = sd_rtnl_message_get_errno(incoming);
694 sd_rtnl_message_unref(incoming);
701 sd_rtnl_message_unref(incoming);
706 /* Try to read more, right away */
710 r = socket_read_message(rtnl);
714 /* received message, so try to process straight away */
720 n = now(CLOCK_MONOTONIC);
726 left = (uint64_t) -1;
728 r = rtnl_poll(rtnl, true, left);
734 r = dispatch_wqueue(rtnl);
740 int sd_rtnl_flush(sd_rtnl *rtnl) {
743 assert_return(rtnl, -EINVAL);
744 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
746 if (rtnl->wqueue_size <= 0)
750 r = dispatch_wqueue(rtnl);
754 if (rtnl->wqueue_size <= 0)
757 r = rtnl_poll(rtnl, false, (uint64_t) -1);
763 int sd_rtnl_get_events(sd_rtnl *rtnl) {
766 assert_return(rtnl, -EINVAL);
767 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
769 if (rtnl->rqueue_size <= 0)
771 if (rtnl->wqueue_size > 0)
777 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
778 struct reply_callback *c;
780 assert_return(rtnl, -EINVAL);
781 assert_return(timeout_usec, -EINVAL);
782 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
784 if (rtnl->rqueue_size > 0) {
789 c = prioq_peek(rtnl->reply_callbacks_prioq);
791 *timeout_usec = (uint64_t) -1;
795 *timeout_usec = c->timeout;
800 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
801 sd_rtnl *rtnl = userdata;
806 r = sd_rtnl_process(rtnl, NULL);
813 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
814 sd_rtnl *rtnl = userdata;
819 r = sd_rtnl_process(rtnl, NULL);
826 static int prepare_callback(sd_event_source *s, void *userdata) {
827 sd_rtnl *rtnl = userdata;
834 e = sd_rtnl_get_events(rtnl);
838 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
842 r = sd_rtnl_get_timeout(rtnl, &until);
848 j = sd_event_source_set_time(rtnl->time_event_source, until);
853 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
860 static int exit_callback(sd_event_source *event, void *userdata) {
861 sd_rtnl *rtnl = userdata;
870 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
873 assert_return(rtnl, -EINVAL);
874 assert_return(!rtnl->event, -EBUSY);
876 assert(!rtnl->io_event_source);
877 assert(!rtnl->time_event_source);
880 rtnl->event = sd_event_ref(event);
882 r = sd_event_default(&rtnl->event);
887 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
891 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
895 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
899 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
903 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
907 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
911 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
915 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
919 r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
926 sd_rtnl_detach_event(rtnl);
930 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
931 assert_return(rtnl, -EINVAL);
932 assert_return(rtnl->event, -ENXIO);
934 if (rtnl->io_event_source)
935 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
937 if (rtnl->time_event_source)
938 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
940 if (rtnl->exit_event_source)
941 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
944 rtnl->event = sd_event_unref(rtnl->event);
949 int sd_rtnl_add_match(sd_rtnl *rtnl,
951 sd_rtnl_message_handler_t callback,
953 struct match_callback *c;
955 assert_return(rtnl, -EINVAL);
956 assert_return(callback, -EINVAL);
957 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
958 assert_return(rtnl_message_type_is_link(type) ||
959 rtnl_message_type_is_addr(type) ||
960 rtnl_message_type_is_route(type), -ENOTSUP);
962 c = new0(struct match_callback, 1);
966 c->callback = callback;
968 c->userdata = userdata;
970 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
975 int sd_rtnl_remove_match(sd_rtnl *rtnl,
977 sd_rtnl_message_handler_t callback,
979 struct match_callback *c;
981 assert_return(rtnl, -EINVAL);
982 assert_return(callback, -EINVAL);
983 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
985 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
986 if (c->callback == callback && c->type == type && c->userdata == userdata) {
987 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);