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 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
98 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
103 assert_return(ret, -EINVAL);
105 r = sd_rtnl_new(&rtnl);
109 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
113 r = setsockopt(rtnl->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one));
117 r = setsockopt(rtnl->fd, SOL_NETLINK, NETLINK_PKTINFO, &one, sizeof(one));
121 va_start(ap, n_groups);
122 r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
127 addrlen = sizeof(rtnl->sockaddr);
129 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
133 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
143 int sd_rtnl_inc_rcvbuf(const sd_rtnl *const rtnl, const int size) {
144 return fd_inc_rcvbuf(rtnl->fd, size);
147 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
148 assert_return(rtnl, NULL);
149 assert_return(!rtnl_pid_changed(rtnl), NULL);
152 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
157 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
161 assert_return(!rtnl_pid_changed(rtnl), NULL);
163 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
164 struct match_callback *f;
167 for (i = 0; i < rtnl->rqueue_size; i++)
168 sd_rtnl_message_unref(rtnl->rqueue[i]);
171 for (i = 0; i < rtnl->rqueue_partial_size; i++)
172 sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
173 free(rtnl->rqueue_partial);
175 for (i = 0; i < rtnl->wqueue_size; i++)
176 sd_rtnl_message_unref(rtnl->wqueue[i]);
181 hashmap_free_free(rtnl->reply_callbacks);
182 prioq_free(rtnl->reply_callbacks_prioq);
184 sd_event_source_unref(rtnl->io_event_source);
185 sd_event_source_unref(rtnl->time_event_source);
186 sd_event_source_unref(rtnl->exit_event_source);
187 sd_event_unref(rtnl->event);
189 while ((f = rtnl->match_callbacks)) {
190 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
194 safe_close(rtnl->fd);
201 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
203 assert(!rtnl_pid_changed(rtnl));
207 m->hdr->nlmsg_seq = rtnl->serial++;
209 rtnl_message_seal(m);
214 int sd_rtnl_send(sd_rtnl *nl,
215 sd_rtnl_message *message,
219 assert_return(nl, -EINVAL);
220 assert_return(!rtnl_pid_changed(nl), -ECHILD);
221 assert_return(message, -EINVAL);
222 assert_return(!message->sealed, -EPERM);
224 rtnl_seal_message(nl, message);
226 if (nl->wqueue_size <= 0) {
228 r = socket_write_message(nl, message);
232 /* nothing was sent, so let's put it on
234 nl->wqueue[0] = sd_rtnl_message_ref(message);
238 /* append to queue */
239 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
240 log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
244 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
247 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
251 *serial = rtnl_message_get_serial(message);
256 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
259 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
260 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
264 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
270 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
273 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
274 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
278 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
279 rtnl->rqueue_partial_size + 1))
285 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
291 if (rtnl->rqueue_size <= 0) {
292 /* Try to read a new message */
293 r = socket_read_message(rtnl);
298 /* Dispatch a queued message */
299 *message = rtnl->rqueue[0];
300 rtnl->rqueue_size --;
301 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
306 static int dispatch_wqueue(sd_rtnl *rtnl) {
311 while (rtnl->wqueue_size > 0) {
312 r = socket_write_message(rtnl, rtnl->wqueue[0]);
316 /* Didn't do anything this time */
319 /* see equivalent in sd-bus.c */
320 sd_rtnl_message_unref(rtnl->wqueue[0]);
321 rtnl->wqueue_size --;
322 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
331 static int process_timeout(sd_rtnl *rtnl) {
332 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
333 struct reply_callback *c;
339 c = prioq_peek(rtnl->reply_callbacks_prioq);
343 n = now(CLOCK_MONOTONIC);
347 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
351 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
352 hashmap_remove(rtnl->reply_callbacks, &c->serial);
354 r = c->callback(rtnl, m, c->userdata);
357 return r < 0 ? r : 1;
360 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
361 struct reply_callback *c;
368 if (sd_rtnl_message_is_broadcast(m))
371 serial = rtnl_message_get_serial(m);
372 c = hashmap_remove(rtnl->reply_callbacks, &serial);
377 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
379 r = c->callback(rtnl, m, c->userdata);
385 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
386 struct match_callback *c;
393 r = sd_rtnl_message_get_type(m, &type);
397 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
398 if (type == c->type) {
399 r = c->callback(rtnl, m, c->userdata);
408 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
409 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
414 r = process_timeout(rtnl);
418 r = dispatch_wqueue(rtnl);
422 r = dispatch_rqueue(rtnl, &m);
428 r = process_reply(rtnl, m);
432 r = process_match(rtnl, m);
452 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
453 RTNL_DONT_DESTROY(rtnl);
456 assert_return(rtnl, -EINVAL);
457 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
458 assert_return(!rtnl->processing, -EBUSY);
460 rtnl->processing = true;
461 r = process_running(rtnl, ret);
462 rtnl->processing = false;
467 static usec_t calc_elapse(uint64_t usec) {
468 if (usec == (uint64_t) -1)
472 usec = RTNL_DEFAULT_TIMEOUT;
474 return now(CLOCK_MONOTONIC) + usec;
477 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
478 struct pollfd p[1] = {};
480 usec_t m = USEC_INFINITY;
485 e = sd_rtnl_get_events(rtnl);
490 /* Caller wants more data, and doesn't care about
491 * what's been read or any other timeouts. */
495 /* Caller wants to process if there is something to
496 * process, but doesn't care otherwise */
498 r = sd_rtnl_get_timeout(rtnl, &until);
503 nw = now(CLOCK_MONOTONIC);
504 m = until > nw ? until - nw : 0;
508 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
514 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
518 return r > 0 ? 1 : 0;
521 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
522 assert_return(nl, -EINVAL);
523 assert_return(!rtnl_pid_changed(nl), -ECHILD);
525 if (nl->rqueue_size > 0)
528 return rtnl_poll(nl, false, timeout_usec);
531 static int timeout_compare(const void *a, const void *b) {
532 const struct reply_callback *x = a, *y = b;
534 if (x->timeout != 0 && y->timeout == 0)
537 if (x->timeout == 0 && y->timeout != 0)
540 if (x->timeout < y->timeout)
543 if (x->timeout > y->timeout)
549 int sd_rtnl_call_async(sd_rtnl *nl,
551 sd_rtnl_message_handler_t callback,
555 struct reply_callback *c;
559 assert_return(nl, -EINVAL);
560 assert_return(m, -EINVAL);
561 assert_return(callback, -EINVAL);
562 assert_return(!rtnl_pid_changed(nl), -ECHILD);
564 r = hashmap_ensure_allocated(&nl->reply_callbacks, &uint64_hash_ops);
568 if (usec != (uint64_t) -1) {
569 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
574 c = new0(struct reply_callback, 1);
578 c->callback = callback;
579 c->userdata = userdata;
580 c->timeout = calc_elapse(usec);
582 k = sd_rtnl_send(nl, m, &s);
590 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
596 if (c->timeout != 0) {
597 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
600 sd_rtnl_call_async_cancel(nl, c->serial);
611 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
612 struct reply_callback *c;
615 assert_return(nl, -EINVAL);
616 assert_return(serial != 0, -EINVAL);
617 assert_return(!rtnl_pid_changed(nl), -ECHILD);
619 c = hashmap_remove(nl->reply_callbacks, &s);
624 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
630 int sd_rtnl_call(sd_rtnl *rtnl,
631 sd_rtnl_message *message,
633 sd_rtnl_message **ret) {
639 assert_return(rtnl, -EINVAL);
640 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
641 assert_return(message, -EINVAL);
643 r = sd_rtnl_send(rtnl, message, &serial);
647 timeout = calc_elapse(usec);
652 while (i < rtnl->rqueue_size) {
653 sd_rtnl_message *incoming;
654 uint32_t received_serial;
656 incoming = rtnl->rqueue[i];
657 received_serial = rtnl_message_get_serial(incoming);
659 if (received_serial == serial) {
660 /* found a match, remove from rqueue and return it */
661 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
662 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
665 r = sd_rtnl_message_get_errno(incoming);
667 sd_rtnl_message_unref(incoming);
674 sd_rtnl_message_unref(incoming);
679 /* Try to read more, right away */
683 r = socket_read_message(rtnl);
687 /* received message, so try to process straight away */
693 n = now(CLOCK_MONOTONIC);
699 left = (uint64_t) -1;
701 r = rtnl_poll(rtnl, true, left);
707 r = dispatch_wqueue(rtnl);
713 int sd_rtnl_flush(sd_rtnl *rtnl) {
716 assert_return(rtnl, -EINVAL);
717 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
719 if (rtnl->wqueue_size <= 0)
723 r = dispatch_wqueue(rtnl);
727 if (rtnl->wqueue_size <= 0)
730 r = rtnl_poll(rtnl, false, (uint64_t) -1);
736 int sd_rtnl_get_events(sd_rtnl *rtnl) {
739 assert_return(rtnl, -EINVAL);
740 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
742 if (rtnl->rqueue_size <= 0)
744 if (rtnl->wqueue_size > 0)
750 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
751 struct reply_callback *c;
753 assert_return(rtnl, -EINVAL);
754 assert_return(timeout_usec, -EINVAL);
755 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
757 if (rtnl->rqueue_size > 0) {
762 c = prioq_peek(rtnl->reply_callbacks_prioq);
764 *timeout_usec = (uint64_t) -1;
768 *timeout_usec = c->timeout;
773 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
774 sd_rtnl *rtnl = userdata;
779 r = sd_rtnl_process(rtnl, NULL);
786 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
787 sd_rtnl *rtnl = userdata;
792 r = sd_rtnl_process(rtnl, NULL);
799 static int prepare_callback(sd_event_source *s, void *userdata) {
800 sd_rtnl *rtnl = userdata;
807 e = sd_rtnl_get_events(rtnl);
811 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
815 r = sd_rtnl_get_timeout(rtnl, &until);
821 j = sd_event_source_set_time(rtnl->time_event_source, until);
826 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
833 static int exit_callback(sd_event_source *event, void *userdata) {
834 sd_rtnl *rtnl = userdata;
843 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
846 assert_return(rtnl, -EINVAL);
847 assert_return(!rtnl->event, -EBUSY);
849 assert(!rtnl->io_event_source);
850 assert(!rtnl->time_event_source);
853 rtnl->event = sd_event_ref(event);
855 r = sd_event_default(&rtnl->event);
860 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
864 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
868 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
872 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
876 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
880 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
884 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
888 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
892 r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
899 sd_rtnl_detach_event(rtnl);
903 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
904 assert_return(rtnl, -EINVAL);
905 assert_return(rtnl->event, -ENXIO);
907 if (rtnl->io_event_source)
908 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
910 if (rtnl->time_event_source)
911 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
913 if (rtnl->exit_event_source)
914 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
917 rtnl->event = sd_event_unref(rtnl->event);
922 int sd_rtnl_add_match(sd_rtnl *rtnl,
924 sd_rtnl_message_handler_t callback,
926 struct match_callback *c;
928 assert_return(rtnl, -EINVAL);
929 assert_return(callback, -EINVAL);
930 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
931 assert_return(rtnl_message_type_is_link(type) ||
932 rtnl_message_type_is_addr(type) ||
933 rtnl_message_type_is_route(type), -ENOTSUP);
935 c = new0(struct match_callback, 1);
939 c->callback = callback;
941 c->userdata = userdata;
943 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
948 int sd_rtnl_remove_match(sd_rtnl *rtnl,
950 sd_rtnl_message_handler_t callback,
952 struct match_callback *c;
954 assert_return(rtnl, -EINVAL);
955 assert_return(callback, -EINVAL);
956 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
958 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
959 if (c->callback == callback && c->type == type && c->userdata == userdata) {
960 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);