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);
705 r = dispatch_wqueue(rtnl);
711 int sd_rtnl_flush(sd_rtnl *rtnl) {
714 assert_return(rtnl, -EINVAL);
715 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
717 if (rtnl->wqueue_size <= 0)
721 r = dispatch_wqueue(rtnl);
725 if (rtnl->wqueue_size <= 0)
728 r = rtnl_poll(rtnl, false, (uint64_t) -1);
734 int sd_rtnl_get_events(sd_rtnl *rtnl) {
737 assert_return(rtnl, -EINVAL);
738 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
740 if (rtnl->rqueue_size <= 0)
742 if (rtnl->wqueue_size > 0)
748 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
749 struct reply_callback *c;
751 assert_return(rtnl, -EINVAL);
752 assert_return(timeout_usec, -EINVAL);
753 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
755 if (rtnl->rqueue_size > 0) {
760 c = prioq_peek(rtnl->reply_callbacks_prioq);
762 *timeout_usec = (uint64_t) -1;
766 *timeout_usec = c->timeout;
771 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
772 sd_rtnl *rtnl = userdata;
777 r = sd_rtnl_process(rtnl, NULL);
784 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
785 sd_rtnl *rtnl = userdata;
790 r = sd_rtnl_process(rtnl, NULL);
797 static int prepare_callback(sd_event_source *s, void *userdata) {
798 sd_rtnl *rtnl = userdata;
805 e = sd_rtnl_get_events(rtnl);
809 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
813 r = sd_rtnl_get_timeout(rtnl, &until);
819 j = sd_event_source_set_time(rtnl->time_event_source, until);
824 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
831 static int exit_callback(sd_event_source *event, void *userdata) {
832 sd_rtnl *rtnl = userdata;
841 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
844 assert_return(rtnl, -EINVAL);
845 assert_return(!rtnl->event, -EBUSY);
847 assert(!rtnl->io_event_source);
848 assert(!rtnl->time_event_source);
851 rtnl->event = sd_event_ref(event);
853 r = sd_event_default(&rtnl->event);
858 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
862 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
866 r = sd_event_source_set_description(rtnl->io_event_source, "rtnl-receive-message");
870 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
874 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
878 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
882 r = sd_event_source_set_description(rtnl->time_event_source, "rtnl-timer");
886 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
890 r = sd_event_source_set_description(rtnl->exit_event_source, "rtnl-exit");
897 sd_rtnl_detach_event(rtnl);
901 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
902 assert_return(rtnl, -EINVAL);
903 assert_return(rtnl->event, -ENXIO);
905 if (rtnl->io_event_source)
906 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
908 if (rtnl->time_event_source)
909 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
911 if (rtnl->exit_event_source)
912 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
915 rtnl->event = sd_event_unref(rtnl->event);
920 int sd_rtnl_add_match(sd_rtnl *rtnl,
922 sd_rtnl_message_handler_t callback,
924 struct match_callback *c;
926 assert_return(rtnl, -EINVAL);
927 assert_return(callback, -EINVAL);
928 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
929 assert_return(rtnl_message_type_is_link(type) ||
930 rtnl_message_type_is_addr(type) ||
931 rtnl_message_type_is_route(type), -ENOTSUP);
933 c = new0(struct match_callback, 1);
937 c->callback = callback;
939 c->userdata = userdata;
941 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
946 int sd_rtnl_remove_match(sd_rtnl *rtnl,
948 sd_rtnl_message_handler_t callback,
950 struct match_callback *c;
952 assert_return(rtnl, -EINVAL);
953 assert_return(callback, -EINVAL);
954 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
956 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
957 if (c->callback == callback && c->type == type && c->userdata == userdata) {
958 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);