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);
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);
152 r = getsockname(fd, &rtnl->sockaddr.sa, &addrlen);
164 int sd_rtnl_open_fd(sd_rtnl **ret, int fd, unsigned n_groups, ...) {
168 va_start(ap, n_groups);
169 r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
175 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
179 fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
183 va_start(ap, n_groups);
184 r = rtnl_open_fd_ap(ret, fd, n_groups, ap);
195 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
196 return fd_inc_rcvbuf(rtnl->fd, size);
199 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
200 assert_return(rtnl, NULL);
201 assert_return(!rtnl_pid_changed(rtnl), NULL);
204 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
209 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
213 assert_return(!rtnl_pid_changed(rtnl), NULL);
215 if (REFCNT_DEC(rtnl->n_ref) == 0) {
216 struct match_callback *f;
219 for (i = 0; i < rtnl->rqueue_size; i++)
220 sd_rtnl_message_unref(rtnl->rqueue[i]);
223 for (i = 0; i < rtnl->rqueue_partial_size; i++)
224 sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
225 free(rtnl->rqueue_partial);
227 for (i = 0; i < rtnl->wqueue_size; i++)
228 sd_rtnl_message_unref(rtnl->wqueue[i]);
233 hashmap_free_free(rtnl->reply_callbacks);
234 prioq_free(rtnl->reply_callbacks_prioq);
236 sd_event_source_unref(rtnl->io_event_source);
237 sd_event_source_unref(rtnl->time_event_source);
238 sd_event_source_unref(rtnl->exit_event_source);
239 sd_event_unref(rtnl->event);
241 while ((f = rtnl->match_callbacks)) {
242 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
246 safe_close(rtnl->fd);
253 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
255 assert(!rtnl_pid_changed(rtnl));
259 m->hdr->nlmsg_seq = rtnl->serial++;
261 rtnl_message_seal(m);
266 int sd_rtnl_send(sd_rtnl *nl,
267 sd_rtnl_message *message,
271 assert_return(nl, -EINVAL);
272 assert_return(!rtnl_pid_changed(nl), -ECHILD);
273 assert_return(message, -EINVAL);
274 assert_return(!message->sealed, -EPERM);
276 rtnl_seal_message(nl, message);
278 if (nl->wqueue_size <= 0) {
280 r = socket_write_message(nl, message);
284 /* nothing was sent, so let's put it on
286 nl->wqueue[0] = sd_rtnl_message_ref(message);
290 /* append to queue */
291 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
292 log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
296 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
299 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
303 *serial = rtnl_message_get_serial(message);
308 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
311 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
312 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
316 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
322 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
325 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
326 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
330 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
331 rtnl->rqueue_partial_size + 1))
337 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
343 if (rtnl->rqueue_size <= 0) {
344 /* Try to read a new message */
345 r = socket_read_message(rtnl);
350 /* Dispatch a queued message */
351 *message = rtnl->rqueue[0];
352 rtnl->rqueue_size --;
353 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
358 static int dispatch_wqueue(sd_rtnl *rtnl) {
363 while (rtnl->wqueue_size > 0) {
364 r = socket_write_message(rtnl, rtnl->wqueue[0]);
368 /* Didn't do anything this time */
371 /* see equivalent in sd-bus.c */
372 sd_rtnl_message_unref(rtnl->wqueue[0]);
373 rtnl->wqueue_size --;
374 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
383 static int process_timeout(sd_rtnl *rtnl) {
384 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
385 struct reply_callback *c;
391 c = prioq_peek(rtnl->reply_callbacks_prioq);
395 n = now(CLOCK_MONOTONIC);
399 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
403 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
404 hashmap_remove(rtnl->reply_callbacks, &c->serial);
406 r = c->callback(rtnl, m, c->userdata);
408 log_debug_errno(r, "sd-rtnl: timedout callback failed: %m");
415 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
416 struct reply_callback *c;
423 if (sd_rtnl_message_is_broadcast(m))
426 serial = rtnl_message_get_serial(m);
427 c = hashmap_remove(rtnl->reply_callbacks, &serial);
432 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
434 r = c->callback(rtnl, m, c->userdata);
436 log_debug_errno(r, "sd-rtnl: callback failed: %m");
443 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
444 struct match_callback *c;
451 r = sd_rtnl_message_get_type(m, &type);
455 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
456 if (type == c->type) {
457 r = c->callback(rtnl, m, c->userdata);
460 log_debug_errno(r, "sd-rtnl: match callback failed: %m");
470 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
471 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
476 r = process_timeout(rtnl);
480 r = dispatch_wqueue(rtnl);
484 r = dispatch_rqueue(rtnl, &m);
490 r = process_reply(rtnl, m);
494 r = process_match(rtnl, m);
514 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
515 RTNL_DONT_DESTROY(rtnl);
518 assert_return(rtnl, -EINVAL);
519 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
520 assert_return(!rtnl->processing, -EBUSY);
522 rtnl->processing = true;
523 r = process_running(rtnl, ret);
524 rtnl->processing = false;
529 static usec_t calc_elapse(uint64_t usec) {
530 if (usec == (uint64_t) -1)
534 usec = RTNL_DEFAULT_TIMEOUT;
536 return now(CLOCK_MONOTONIC) + usec;
539 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
540 struct pollfd p[1] = {};
542 usec_t m = USEC_INFINITY;
547 e = sd_rtnl_get_events(rtnl);
552 /* Caller wants more data, and doesn't care about
553 * what's been read or any other timeouts. */
557 /* Caller wants to process if there is something to
558 * process, but doesn't care otherwise */
560 r = sd_rtnl_get_timeout(rtnl, &until);
565 nw = now(CLOCK_MONOTONIC);
566 m = until > nw ? until - nw : 0;
570 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
576 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
580 return r > 0 ? 1 : 0;
583 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
584 assert_return(nl, -EINVAL);
585 assert_return(!rtnl_pid_changed(nl), -ECHILD);
587 if (nl->rqueue_size > 0)
590 return rtnl_poll(nl, false, timeout_usec);
593 static int timeout_compare(const void *a, const void *b) {
594 const struct reply_callback *x = a, *y = b;
596 if (x->timeout != 0 && y->timeout == 0)
599 if (x->timeout == 0 && y->timeout != 0)
602 if (x->timeout < y->timeout)
605 if (x->timeout > y->timeout)
611 int sd_rtnl_call_async(sd_rtnl *nl,
613 sd_rtnl_message_handler_t callback,
617 struct reply_callback *c;
621 assert_return(nl, -EINVAL);
622 assert_return(m, -EINVAL);
623 assert_return(callback, -EINVAL);
624 assert_return(!rtnl_pid_changed(nl), -ECHILD);
626 r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
630 if (usec != (uint64_t) -1) {
631 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
636 c = new0(struct reply_callback, 1);
640 c->callback = callback;
641 c->userdata = userdata;
642 c->timeout = calc_elapse(usec);
644 k = sd_rtnl_send(nl, m, &s);
652 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
658 if (c->timeout != 0) {
659 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
662 sd_rtnl_call_async_cancel(nl, c->serial);
673 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
674 struct reply_callback *c;
677 assert_return(nl, -EINVAL);
678 assert_return(serial != 0, -EINVAL);
679 assert_return(!rtnl_pid_changed(nl), -ECHILD);
681 c = hashmap_remove(nl->reply_callbacks, &s);
686 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
692 int sd_rtnl_call(sd_rtnl *rtnl,
693 sd_rtnl_message *message,
695 sd_rtnl_message **ret) {
701 assert_return(rtnl, -EINVAL);
702 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
703 assert_return(message, -EINVAL);
705 r = sd_rtnl_send(rtnl, message, &serial);
709 timeout = calc_elapse(usec);
714 while (i < rtnl->rqueue_size) {
715 sd_rtnl_message *incoming;
716 uint32_t received_serial;
718 incoming = rtnl->rqueue[i];
719 received_serial = rtnl_message_get_serial(incoming);
721 if (received_serial == serial) {
722 /* found a match, remove from rqueue and return it */
723 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
724 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
727 r = sd_rtnl_message_get_errno(incoming);
729 sd_rtnl_message_unref(incoming);
736 sd_rtnl_message_unref(incoming);
741 /* Try to read more, right away */
745 r = socket_read_message(rtnl);
749 /* received message, so try to process straight away */
755 n = now(CLOCK_MONOTONIC);
761 left = (uint64_t) -1;
763 r = rtnl_poll(rtnl, true, left);
769 r = dispatch_wqueue(rtnl);
775 int sd_rtnl_flush(sd_rtnl *rtnl) {
778 assert_return(rtnl, -EINVAL);
779 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
781 if (rtnl->wqueue_size <= 0)
785 r = dispatch_wqueue(rtnl);
789 if (rtnl->wqueue_size <= 0)
792 r = rtnl_poll(rtnl, false, (uint64_t) -1);
798 int sd_rtnl_get_events(sd_rtnl *rtnl) {
801 assert_return(rtnl, -EINVAL);
802 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
804 if (rtnl->rqueue_size <= 0)
806 if (rtnl->wqueue_size > 0)
812 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
813 struct reply_callback *c;
815 assert_return(rtnl, -EINVAL);
816 assert_return(timeout_usec, -EINVAL);
817 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
819 if (rtnl->rqueue_size > 0) {
824 c = prioq_peek(rtnl->reply_callbacks_prioq);
826 *timeout_usec = (uint64_t) -1;
830 *timeout_usec = c->timeout;
835 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
836 sd_rtnl *rtnl = userdata;
841 r = sd_rtnl_process(rtnl, NULL);
848 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
849 sd_rtnl *rtnl = userdata;
854 r = sd_rtnl_process(rtnl, NULL);
861 static int prepare_callback(sd_event_source *s, void *userdata) {
862 sd_rtnl *rtnl = userdata;
869 e = sd_rtnl_get_events(rtnl);
873 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
877 r = sd_rtnl_get_timeout(rtnl, &until);
883 j = sd_event_source_set_time(rtnl->time_event_source, until);
888 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
895 static int exit_callback(sd_event_source *event, void *userdata) {
896 sd_rtnl *rtnl = userdata;
905 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
908 assert_return(rtnl, -EINVAL);
909 assert_return(!rtnl->event, -EBUSY);
911 assert(!rtnl->io_event_source);
912 assert(!rtnl->time_event_source);
915 rtnl->event = sd_event_ref(event);
917 r = sd_event_default(&rtnl->event);
922 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
926 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
930 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
934 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
938 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
942 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
946 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
950 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
954 r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
961 sd_rtnl_detach_event(rtnl);
965 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
966 assert_return(rtnl, -EINVAL);
967 assert_return(rtnl->event, -ENXIO);
969 if (rtnl->io_event_source)
970 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
972 if (rtnl->time_event_source)
973 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
975 if (rtnl->exit_event_source)
976 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
979 rtnl->event = sd_event_unref(rtnl->event);
984 int sd_rtnl_add_match(sd_rtnl *rtnl,
986 sd_rtnl_message_handler_t callback,
988 struct match_callback *c;
990 assert_return(rtnl, -EINVAL);
991 assert_return(callback, -EINVAL);
992 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
993 assert_return(rtnl_message_type_is_link(type) ||
994 rtnl_message_type_is_addr(type) ||
995 rtnl_message_type_is_route(type), -ENOTSUP);
997 c = new0(struct match_callback, 1);
1001 c->callback = callback;
1003 c->userdata = userdata;
1005 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
1010 int sd_rtnl_remove_match(sd_rtnl *rtnl,
1012 sd_rtnl_message_handler_t callback,
1014 struct match_callback *c;
1016 assert_return(rtnl, -EINVAL);
1017 assert_return(callback, -EINVAL);
1018 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
1020 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
1021 if (c->callback == callback && c->type == type && c->userdata == userdata) {
1022 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);