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>
30 #include "rtnl-internal.h"
31 #include "rtnl-util.h"
33 static int sd_rtnl_new(sd_rtnl **ret) {
34 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
36 assert_return(ret, -EINVAL);
38 rtnl = new0(sd_rtnl, 1);
42 rtnl->n_ref = REFCNT_INIT;
46 rtnl->sockaddr.nl.nl_family = AF_NETLINK;
48 rtnl->original_pid = getpid();
50 LIST_HEAD_INIT(rtnl->match_callbacks);
52 /* We guarantee that wqueue always has space for at least
54 if (!GREEDY_REALLOC(rtnl->wqueue, rtnl->wqueue_allocated, 1))
57 /* We guarantee that the read buffer has at least space for
59 if (!greedy_realloc((void**)&rtnl->rbuffer, &rtnl->rbuffer_allocated,
60 sizeof(struct nlmsghdr), sizeof(uint8_t)))
69 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
72 /* We don't support people creating an rtnl connection and
73 * keeping it around over a fork(). Let's complain. */
75 return rtnl->original_pid != getpid();
78 static int rtnl_compute_groups_ap(uint32_t *_groups, unsigned n_groups, va_list ap) {
82 for (i = 0; i < n_groups; i++) {
85 group = va_arg(ap, unsigned);
86 assert_return(group < 32, -EINVAL);
88 groups |= group ? (1 << (group - 1)) : 0;
96 int sd_rtnl_open(sd_rtnl **ret, unsigned n_groups, ...) {
97 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
102 assert_return(ret, -EINVAL);
104 r = sd_rtnl_new(&rtnl);
108 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
112 if (setsockopt(rtnl->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
115 va_start(ap, n_groups);
116 r = rtnl_compute_groups_ap(&rtnl->sockaddr.nl.nl_groups, n_groups, ap);
121 addrlen = sizeof(rtnl->sockaddr);
123 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
127 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
137 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
138 assert_return(rtnl, NULL);
139 assert_return(!rtnl_pid_changed(rtnl), NULL);
142 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
147 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
151 assert_return(!rtnl_pid_changed(rtnl), NULL);
153 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
154 struct match_callback *f;
157 for (i = 0; i < rtnl->rqueue_size; i++)
158 sd_rtnl_message_unref(rtnl->rqueue[i]);
161 for (i = 0; i < rtnl->rqueue_partial_size; i++)
162 sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
163 free(rtnl->rqueue_partial);
165 for (i = 0; i < rtnl->wqueue_size; i++)
166 sd_rtnl_message_unref(rtnl->wqueue[i]);
171 hashmap_free_free(rtnl->reply_callbacks);
172 prioq_free(rtnl->reply_callbacks_prioq);
174 sd_event_source_unref(rtnl->io_event_source);
175 sd_event_source_unref(rtnl->time_event_source);
176 sd_event_source_unref(rtnl->exit_event_source);
177 sd_event_unref(rtnl->event);
179 while ((f = rtnl->match_callbacks)) {
180 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
184 safe_close(rtnl->fd);
191 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
193 assert(!rtnl_pid_changed(rtnl));
197 m->hdr->nlmsg_seq = rtnl->serial++;
199 rtnl_message_seal(m);
204 int sd_rtnl_send(sd_rtnl *nl,
205 sd_rtnl_message *message,
209 assert_return(nl, -EINVAL);
210 assert_return(!rtnl_pid_changed(nl), -ECHILD);
211 assert_return(message, -EINVAL);
212 assert_return(!message->sealed, -EPERM);
214 rtnl_seal_message(nl, message);
216 if (nl->wqueue_size <= 0) {
218 r = socket_write_message(nl, message);
222 /* nothing was sent, so let's put it on
224 nl->wqueue[0] = sd_rtnl_message_ref(message);
228 /* append to queue */
229 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
230 log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
234 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
237 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
241 *serial = rtnl_message_get_serial(message);
246 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
249 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
250 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
254 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
260 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
263 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
264 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
268 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
269 rtnl->rqueue_partial_size + 1))
275 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
281 if (rtnl->rqueue_size <= 0) {
282 /* Try to read a new message */
283 r = socket_read_message(rtnl);
288 /* Dispatch a queued message */
289 *message = rtnl->rqueue[0];
290 rtnl->rqueue_size --;
291 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
296 static int dispatch_wqueue(sd_rtnl *rtnl) {
301 while (rtnl->wqueue_size > 0) {
302 r = socket_write_message(rtnl, rtnl->wqueue[0]);
306 /* Didn't do anything this time */
309 /* see equivalent in sd-bus.c */
310 sd_rtnl_message_unref(rtnl->wqueue[0]);
311 rtnl->wqueue_size --;
312 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
321 static int process_timeout(sd_rtnl *rtnl) {
322 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
323 struct reply_callback *c;
329 c = prioq_peek(rtnl->reply_callbacks_prioq);
333 n = now(CLOCK_MONOTONIC);
337 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
341 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
342 hashmap_remove(rtnl->reply_callbacks, &c->serial);
344 r = c->callback(rtnl, m, c->userdata);
347 return r < 0 ? r : 1;
350 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
351 struct reply_callback *c;
358 if (sd_rtnl_message_is_broadcast(m))
361 serial = rtnl_message_get_serial(m);
362 c = hashmap_remove(rtnl->reply_callbacks, &serial);
367 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
369 r = c->callback(rtnl, m, c->userdata);
375 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
376 struct match_callback *c;
383 r = sd_rtnl_message_get_type(m, &type);
387 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
388 if (type == c->type) {
389 r = c->callback(rtnl, m, c->userdata);
398 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
399 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
404 r = process_timeout(rtnl);
408 r = dispatch_wqueue(rtnl);
412 r = dispatch_rqueue(rtnl, &m);
418 r = process_reply(rtnl, m);
422 r = process_match(rtnl, m);
442 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
443 RTNL_DONT_DESTROY(rtnl);
446 assert_return(rtnl, -EINVAL);
447 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
448 assert_return(!rtnl->processing, -EBUSY);
450 rtnl->processing = true;
451 r = process_running(rtnl, ret);
452 rtnl->processing = false;
457 static usec_t calc_elapse(uint64_t usec) {
458 if (usec == (uint64_t) -1)
462 usec = RTNL_DEFAULT_TIMEOUT;
464 return now(CLOCK_MONOTONIC) + usec;
467 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
468 struct pollfd p[1] = {};
470 usec_t m = (usec_t) -1;
475 e = sd_rtnl_get_events(rtnl);
480 /* Caller wants more data, and doesn't care about
481 * what's been read or any other timeouts. */
485 /* Caller wants to process if there is something to
486 * process, but doesn't care otherwise */
488 r = sd_rtnl_get_timeout(rtnl, &until);
493 nw = now(CLOCK_MONOTONIC);
494 m = until > nw ? until - nw : 0;
498 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
504 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
508 return r > 0 ? 1 : 0;
511 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
512 assert_return(nl, -EINVAL);
513 assert_return(!rtnl_pid_changed(nl), -ECHILD);
515 if (nl->rqueue_size > 0)
518 return rtnl_poll(nl, false, timeout_usec);
521 static int timeout_compare(const void *a, const void *b) {
522 const struct reply_callback *x = a, *y = b;
524 if (x->timeout != 0 && y->timeout == 0)
527 if (x->timeout == 0 && y->timeout != 0)
530 if (x->timeout < y->timeout)
533 if (x->timeout > y->timeout)
539 int sd_rtnl_call_async(sd_rtnl *nl,
541 sd_rtnl_message_handler_t callback,
545 struct reply_callback *c;
549 assert_return(nl, -EINVAL);
550 assert_return(m, -EINVAL);
551 assert_return(callback, -EINVAL);
552 assert_return(!rtnl_pid_changed(nl), -ECHILD);
554 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
558 if (usec != (uint64_t) -1) {
559 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
564 c = new0(struct reply_callback, 1);
568 c->callback = callback;
569 c->userdata = userdata;
570 c->timeout = calc_elapse(usec);
572 k = sd_rtnl_send(nl, m, &s);
580 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
586 if (c->timeout != 0) {
587 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
590 sd_rtnl_call_async_cancel(nl, c->serial);
601 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
602 struct reply_callback *c;
605 assert_return(nl, -EINVAL);
606 assert_return(serial != 0, -EINVAL);
607 assert_return(!rtnl_pid_changed(nl), -ECHILD);
609 c = hashmap_remove(nl->reply_callbacks, &s);
614 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
620 int sd_rtnl_call(sd_rtnl *rtnl,
621 sd_rtnl_message *message,
623 sd_rtnl_message **ret) {
629 assert_return(rtnl, -EINVAL);
630 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
631 assert_return(message, -EINVAL);
633 r = sd_rtnl_send(rtnl, message, &serial);
637 timeout = calc_elapse(usec);
642 while (i < rtnl->rqueue_size) {
643 sd_rtnl_message *incoming;
644 uint32_t received_serial;
646 incoming = rtnl->rqueue[i];
647 received_serial = rtnl_message_get_serial(incoming);
649 if (received_serial == serial) {
650 /* found a match, remove from rqueue and return it */
651 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
652 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
655 r = sd_rtnl_message_get_errno(incoming);
657 sd_rtnl_message_unref(incoming);
664 sd_rtnl_message_unref(incoming);
669 /* Try to read more, right away */
673 r = socket_read_message(rtnl);
677 /* receieved message, so try to process straight away */
683 n = now(CLOCK_MONOTONIC);
689 left = (uint64_t) -1;
691 r = rtnl_poll(rtnl, true, left);
695 r = dispatch_wqueue(rtnl);
701 int sd_rtnl_flush(sd_rtnl *rtnl) {
704 assert_return(rtnl, -EINVAL);
705 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
707 if (rtnl->wqueue_size <= 0)
711 r = dispatch_wqueue(rtnl);
715 if (rtnl->wqueue_size <= 0)
718 r = rtnl_poll(rtnl, false, (uint64_t) -1);
724 int sd_rtnl_get_events(sd_rtnl *rtnl) {
727 assert_return(rtnl, -EINVAL);
728 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
730 if (rtnl->rqueue_size <= 0)
732 if (rtnl->wqueue_size > 0)
738 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
739 struct reply_callback *c;
741 assert_return(rtnl, -EINVAL);
742 assert_return(timeout_usec, -EINVAL);
743 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
745 if (rtnl->rqueue_size > 0) {
750 c = prioq_peek(rtnl->reply_callbacks_prioq);
752 *timeout_usec = (uint64_t) -1;
756 *timeout_usec = c->timeout;
761 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
762 sd_rtnl *rtnl = userdata;
767 r = sd_rtnl_process(rtnl, NULL);
774 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
775 sd_rtnl *rtnl = userdata;
780 r = sd_rtnl_process(rtnl, NULL);
787 static int prepare_callback(sd_event_source *s, void *userdata) {
788 sd_rtnl *rtnl = userdata;
795 e = sd_rtnl_get_events(rtnl);
799 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
803 r = sd_rtnl_get_timeout(rtnl, &until);
809 j = sd_event_source_set_time(rtnl->time_event_source, until);
814 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
821 static int exit_callback(sd_event_source *event, void *userdata) {
822 sd_rtnl *rtnl = userdata;
831 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
834 assert_return(rtnl, -EINVAL);
835 assert_return(!rtnl->event, -EBUSY);
837 assert(!rtnl->io_event_source);
838 assert(!rtnl->time_event_source);
841 rtnl->event = sd_event_ref(event);
843 r = sd_event_default(&rtnl->event);
848 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
852 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
856 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
860 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
864 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
868 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
875 sd_rtnl_detach_event(rtnl);
879 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
880 assert_return(rtnl, -EINVAL);
881 assert_return(rtnl->event, -ENXIO);
883 if (rtnl->io_event_source)
884 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
886 if (rtnl->time_event_source)
887 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
889 if (rtnl->exit_event_source)
890 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
893 rtnl->event = sd_event_unref(rtnl->event);
898 int sd_rtnl_add_match(sd_rtnl *rtnl,
900 sd_rtnl_message_handler_t callback,
902 struct match_callback *c;
904 assert_return(rtnl, -EINVAL);
905 assert_return(callback, -EINVAL);
906 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
907 assert_return(rtnl_message_type_is_link(type) ||
908 rtnl_message_type_is_addr(type) ||
909 rtnl_message_type_is_route(type), -ENOTSUP);
911 c = new0(struct match_callback, 1);
915 c->callback = callback;
917 c->userdata = userdata;
919 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
924 int sd_rtnl_remove_match(sd_rtnl *rtnl,
926 sd_rtnl_message_handler_t callback,
928 struct match_callback *c;
930 assert_return(rtnl, -EINVAL);
931 assert_return(callback, -EINVAL);
932 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
934 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
935 if (c->callback == callback && c->type == type && c->userdata == userdata) {
936 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);