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);
383 log_debug_errno(r, "sd-rtnl: timedout callback failed: %m");
390 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
391 struct reply_callback *c;
398 if (sd_rtnl_message_is_broadcast(m))
401 serial = rtnl_message_get_serial(m);
402 c = hashmap_remove(rtnl->reply_callbacks, &serial);
407 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
409 r = c->callback(rtnl, m, c->userdata);
411 log_debug_errno(r, "sd-rtnl: callback failed: %m");
418 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
419 struct match_callback *c;
426 r = sd_rtnl_message_get_type(m, &type);
430 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
431 if (type == c->type) {
432 r = c->callback(rtnl, m, c->userdata);
435 log_debug_errno(r, "sd-rtnl: match callback failed: %m");
445 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
446 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
451 r = process_timeout(rtnl);
455 r = dispatch_wqueue(rtnl);
459 r = dispatch_rqueue(rtnl, &m);
465 r = process_reply(rtnl, m);
469 r = process_match(rtnl, m);
489 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
490 RTNL_DONT_DESTROY(rtnl);
493 assert_return(rtnl, -EINVAL);
494 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
495 assert_return(!rtnl->processing, -EBUSY);
497 rtnl->processing = true;
498 r = process_running(rtnl, ret);
499 rtnl->processing = false;
504 static usec_t calc_elapse(uint64_t usec) {
505 if (usec == (uint64_t) -1)
509 usec = RTNL_DEFAULT_TIMEOUT;
511 return now(CLOCK_MONOTONIC) + usec;
514 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
515 struct pollfd p[1] = {};
517 usec_t m = USEC_INFINITY;
522 e = sd_rtnl_get_events(rtnl);
527 /* Caller wants more data, and doesn't care about
528 * what's been read or any other timeouts. */
532 /* Caller wants to process if there is something to
533 * process, but doesn't care otherwise */
535 r = sd_rtnl_get_timeout(rtnl, &until);
540 nw = now(CLOCK_MONOTONIC);
541 m = until > nw ? until - nw : 0;
545 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
551 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
555 return r > 0 ? 1 : 0;
558 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
559 assert_return(nl, -EINVAL);
560 assert_return(!rtnl_pid_changed(nl), -ECHILD);
562 if (nl->rqueue_size > 0)
565 return rtnl_poll(nl, false, timeout_usec);
568 static int timeout_compare(const void *a, const void *b) {
569 const struct reply_callback *x = a, *y = b;
571 if (x->timeout != 0 && y->timeout == 0)
574 if (x->timeout == 0 && y->timeout != 0)
577 if (x->timeout < y->timeout)
580 if (x->timeout > y->timeout)
586 int sd_rtnl_call_async(sd_rtnl *nl,
588 sd_rtnl_message_handler_t callback,
592 struct reply_callback *c;
596 assert_return(nl, -EINVAL);
597 assert_return(m, -EINVAL);
598 assert_return(callback, -EINVAL);
599 assert_return(!rtnl_pid_changed(nl), -ECHILD);
601 r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
605 if (usec != (uint64_t) -1) {
606 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
611 c = new0(struct reply_callback, 1);
615 c->callback = callback;
616 c->userdata = userdata;
617 c->timeout = calc_elapse(usec);
619 k = sd_rtnl_send(nl, m, &s);
627 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
633 if (c->timeout != 0) {
634 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
637 sd_rtnl_call_async_cancel(nl, c->serial);
648 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
649 struct reply_callback *c;
652 assert_return(nl, -EINVAL);
653 assert_return(serial != 0, -EINVAL);
654 assert_return(!rtnl_pid_changed(nl), -ECHILD);
656 c = hashmap_remove(nl->reply_callbacks, &s);
661 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
667 int sd_rtnl_call(sd_rtnl *rtnl,
668 sd_rtnl_message *message,
670 sd_rtnl_message **ret) {
676 assert_return(rtnl, -EINVAL);
677 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
678 assert_return(message, -EINVAL);
680 r = sd_rtnl_send(rtnl, message, &serial);
684 timeout = calc_elapse(usec);
689 while (i < rtnl->rqueue_size) {
690 sd_rtnl_message *incoming;
691 uint32_t received_serial;
693 incoming = rtnl->rqueue[i];
694 received_serial = rtnl_message_get_serial(incoming);
696 if (received_serial == serial) {
697 /* found a match, remove from rqueue and return it */
698 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
699 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
702 r = sd_rtnl_message_get_errno(incoming);
704 sd_rtnl_message_unref(incoming);
711 sd_rtnl_message_unref(incoming);
716 /* Try to read more, right away */
720 r = socket_read_message(rtnl);
724 /* received message, so try to process straight away */
730 n = now(CLOCK_MONOTONIC);
736 left = (uint64_t) -1;
738 r = rtnl_poll(rtnl, true, left);
744 r = dispatch_wqueue(rtnl);
750 int sd_rtnl_flush(sd_rtnl *rtnl) {
753 assert_return(rtnl, -EINVAL);
754 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
756 if (rtnl->wqueue_size <= 0)
760 r = dispatch_wqueue(rtnl);
764 if (rtnl->wqueue_size <= 0)
767 r = rtnl_poll(rtnl, false, (uint64_t) -1);
773 int sd_rtnl_get_events(sd_rtnl *rtnl) {
776 assert_return(rtnl, -EINVAL);
777 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
779 if (rtnl->rqueue_size <= 0)
781 if (rtnl->wqueue_size > 0)
787 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
788 struct reply_callback *c;
790 assert_return(rtnl, -EINVAL);
791 assert_return(timeout_usec, -EINVAL);
792 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
794 if (rtnl->rqueue_size > 0) {
799 c = prioq_peek(rtnl->reply_callbacks_prioq);
801 *timeout_usec = (uint64_t) -1;
805 *timeout_usec = c->timeout;
810 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
811 sd_rtnl *rtnl = userdata;
816 r = sd_rtnl_process(rtnl, NULL);
823 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
824 sd_rtnl *rtnl = userdata;
829 r = sd_rtnl_process(rtnl, NULL);
836 static int prepare_callback(sd_event_source *s, void *userdata) {
837 sd_rtnl *rtnl = userdata;
844 e = sd_rtnl_get_events(rtnl);
848 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
852 r = sd_rtnl_get_timeout(rtnl, &until);
858 j = sd_event_source_set_time(rtnl->time_event_source, until);
863 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
870 static int exit_callback(sd_event_source *event, void *userdata) {
871 sd_rtnl *rtnl = userdata;
880 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
883 assert_return(rtnl, -EINVAL);
884 assert_return(!rtnl->event, -EBUSY);
886 assert(!rtnl->io_event_source);
887 assert(!rtnl->time_event_source);
890 rtnl->event = sd_event_ref(event);
892 r = sd_event_default(&rtnl->event);
897 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
901 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
905 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
909 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
913 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
917 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
921 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
925 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
929 r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
936 sd_rtnl_detach_event(rtnl);
940 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
941 assert_return(rtnl, -EINVAL);
942 assert_return(rtnl->event, -ENXIO);
944 if (rtnl->io_event_source)
945 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
947 if (rtnl->time_event_source)
948 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
950 if (rtnl->exit_event_source)
951 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
954 rtnl->event = sd_event_unref(rtnl->event);
959 int sd_rtnl_add_match(sd_rtnl *rtnl,
961 sd_rtnl_message_handler_t callback,
963 struct match_callback *c;
965 assert_return(rtnl, -EINVAL);
966 assert_return(callback, -EINVAL);
967 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
968 assert_return(rtnl_message_type_is_link(type) ||
969 rtnl_message_type_is_addr(type) ||
970 rtnl_message_type_is_route(type), -ENOTSUP);
972 c = new0(struct match_callback, 1);
976 c->callback = callback;
978 c->userdata = userdata;
980 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
985 int sd_rtnl_remove_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);
995 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
996 if (c->callback == callback && c->type == type && c->userdata == userdata) {
997 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);