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 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
144 assert_return(rtnl, NULL);
145 assert_return(!rtnl_pid_changed(rtnl), NULL);
148 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
153 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
157 assert_return(!rtnl_pid_changed(rtnl), NULL);
159 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
160 struct match_callback *f;
163 for (i = 0; i < rtnl->rqueue_size; i++)
164 sd_rtnl_message_unref(rtnl->rqueue[i]);
167 for (i = 0; i < rtnl->rqueue_partial_size; i++)
168 sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
169 free(rtnl->rqueue_partial);
171 for (i = 0; i < rtnl->wqueue_size; i++)
172 sd_rtnl_message_unref(rtnl->wqueue[i]);
177 hashmap_free_free(rtnl->reply_callbacks);
178 prioq_free(rtnl->reply_callbacks_prioq);
180 sd_event_source_unref(rtnl->io_event_source);
181 sd_event_source_unref(rtnl->time_event_source);
182 sd_event_source_unref(rtnl->exit_event_source);
183 sd_event_unref(rtnl->event);
185 while ((f = rtnl->match_callbacks)) {
186 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
190 safe_close(rtnl->fd);
197 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
199 assert(!rtnl_pid_changed(rtnl));
203 m->hdr->nlmsg_seq = rtnl->serial++;
205 rtnl_message_seal(m);
210 int sd_rtnl_send(sd_rtnl *nl,
211 sd_rtnl_message *message,
215 assert_return(nl, -EINVAL);
216 assert_return(!rtnl_pid_changed(nl), -ECHILD);
217 assert_return(message, -EINVAL);
218 assert_return(!message->sealed, -EPERM);
220 rtnl_seal_message(nl, message);
222 if (nl->wqueue_size <= 0) {
224 r = socket_write_message(nl, message);
228 /* nothing was sent, so let's put it on
230 nl->wqueue[0] = sd_rtnl_message_ref(message);
234 /* append to queue */
235 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
236 log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
240 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
243 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
247 *serial = rtnl_message_get_serial(message);
252 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
255 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
256 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
260 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
266 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
269 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
270 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
274 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
275 rtnl->rqueue_partial_size + 1))
281 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
287 if (rtnl->rqueue_size <= 0) {
288 /* Try to read a new message */
289 r = socket_read_message(rtnl);
294 /* Dispatch a queued message */
295 *message = rtnl->rqueue[0];
296 rtnl->rqueue_size --;
297 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
302 static int dispatch_wqueue(sd_rtnl *rtnl) {
307 while (rtnl->wqueue_size > 0) {
308 r = socket_write_message(rtnl, rtnl->wqueue[0]);
312 /* Didn't do anything this time */
315 /* see equivalent in sd-bus.c */
316 sd_rtnl_message_unref(rtnl->wqueue[0]);
317 rtnl->wqueue_size --;
318 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
327 static int process_timeout(sd_rtnl *rtnl) {
328 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
329 struct reply_callback *c;
335 c = prioq_peek(rtnl->reply_callbacks_prioq);
339 n = now(CLOCK_MONOTONIC);
343 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
347 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
348 hashmap_remove(rtnl->reply_callbacks, &c->serial);
350 r = c->callback(rtnl, m, c->userdata);
353 return r < 0 ? r : 1;
356 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
357 struct reply_callback *c;
364 if (sd_rtnl_message_is_broadcast(m))
367 serial = rtnl_message_get_serial(m);
368 c = hashmap_remove(rtnl->reply_callbacks, &serial);
373 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
375 r = c->callback(rtnl, m, c->userdata);
381 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
382 struct match_callback *c;
389 r = sd_rtnl_message_get_type(m, &type);
393 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
394 if (type == c->type) {
395 r = c->callback(rtnl, m, c->userdata);
404 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
405 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
410 r = process_timeout(rtnl);
414 r = dispatch_wqueue(rtnl);
418 r = dispatch_rqueue(rtnl, &m);
424 r = process_reply(rtnl, m);
428 r = process_match(rtnl, m);
448 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
449 RTNL_DONT_DESTROY(rtnl);
452 assert_return(rtnl, -EINVAL);
453 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
454 assert_return(!rtnl->processing, -EBUSY);
456 rtnl->processing = true;
457 r = process_running(rtnl, ret);
458 rtnl->processing = false;
463 static usec_t calc_elapse(uint64_t usec) {
464 if (usec == (uint64_t) -1)
468 usec = RTNL_DEFAULT_TIMEOUT;
470 return now(CLOCK_MONOTONIC) + usec;
473 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
474 struct pollfd p[1] = {};
476 usec_t m = USEC_INFINITY;
481 e = sd_rtnl_get_events(rtnl);
486 /* Caller wants more data, and doesn't care about
487 * what's been read or any other timeouts. */
491 /* Caller wants to process if there is something to
492 * process, but doesn't care otherwise */
494 r = sd_rtnl_get_timeout(rtnl, &until);
499 nw = now(CLOCK_MONOTONIC);
500 m = until > nw ? until - nw : 0;
504 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
510 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
514 return r > 0 ? 1 : 0;
517 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
518 assert_return(nl, -EINVAL);
519 assert_return(!rtnl_pid_changed(nl), -ECHILD);
521 if (nl->rqueue_size > 0)
524 return rtnl_poll(nl, false, timeout_usec);
527 static int timeout_compare(const void *a, const void *b) {
528 const struct reply_callback *x = a, *y = b;
530 if (x->timeout != 0 && y->timeout == 0)
533 if (x->timeout == 0 && y->timeout != 0)
536 if (x->timeout < y->timeout)
539 if (x->timeout > y->timeout)
545 int sd_rtnl_call_async(sd_rtnl *nl,
547 sd_rtnl_message_handler_t callback,
551 struct reply_callback *c;
555 assert_return(nl, -EINVAL);
556 assert_return(m, -EINVAL);
557 assert_return(callback, -EINVAL);
558 assert_return(!rtnl_pid_changed(nl), -ECHILD);
560 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
564 if (usec != (uint64_t) -1) {
565 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
570 c = new0(struct reply_callback, 1);
574 c->callback = callback;
575 c->userdata = userdata;
576 c->timeout = calc_elapse(usec);
578 k = sd_rtnl_send(nl, m, &s);
586 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
592 if (c->timeout != 0) {
593 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
596 sd_rtnl_call_async_cancel(nl, c->serial);
607 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
608 struct reply_callback *c;
611 assert_return(nl, -EINVAL);
612 assert_return(serial != 0, -EINVAL);
613 assert_return(!rtnl_pid_changed(nl), -ECHILD);
615 c = hashmap_remove(nl->reply_callbacks, &s);
620 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
626 int sd_rtnl_call(sd_rtnl *rtnl,
627 sd_rtnl_message *message,
629 sd_rtnl_message **ret) {
635 assert_return(rtnl, -EINVAL);
636 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
637 assert_return(message, -EINVAL);
639 r = sd_rtnl_send(rtnl, message, &serial);
643 timeout = calc_elapse(usec);
648 while (i < rtnl->rqueue_size) {
649 sd_rtnl_message *incoming;
650 uint32_t received_serial;
652 incoming = rtnl->rqueue[i];
653 received_serial = rtnl_message_get_serial(incoming);
655 if (received_serial == serial) {
656 /* found a match, remove from rqueue and return it */
657 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
658 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
661 r = sd_rtnl_message_get_errno(incoming);
663 sd_rtnl_message_unref(incoming);
670 sd_rtnl_message_unref(incoming);
675 /* Try to read more, right away */
679 r = socket_read_message(rtnl);
683 /* receieved message, so try to process straight away */
689 n = now(CLOCK_MONOTONIC);
695 left = (uint64_t) -1;
697 r = rtnl_poll(rtnl, true, left);
701 r = dispatch_wqueue(rtnl);
707 int sd_rtnl_flush(sd_rtnl *rtnl) {
710 assert_return(rtnl, -EINVAL);
711 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
713 if (rtnl->wqueue_size <= 0)
717 r = dispatch_wqueue(rtnl);
721 if (rtnl->wqueue_size <= 0)
724 r = rtnl_poll(rtnl, false, (uint64_t) -1);
730 int sd_rtnl_get_events(sd_rtnl *rtnl) {
733 assert_return(rtnl, -EINVAL);
734 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
736 if (rtnl->rqueue_size <= 0)
738 if (rtnl->wqueue_size > 0)
744 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
745 struct reply_callback *c;
747 assert_return(rtnl, -EINVAL);
748 assert_return(timeout_usec, -EINVAL);
749 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
751 if (rtnl->rqueue_size > 0) {
756 c = prioq_peek(rtnl->reply_callbacks_prioq);
758 *timeout_usec = (uint64_t) -1;
762 *timeout_usec = c->timeout;
767 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
768 sd_rtnl *rtnl = userdata;
773 r = sd_rtnl_process(rtnl, NULL);
780 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
781 sd_rtnl *rtnl = userdata;
786 r = sd_rtnl_process(rtnl, NULL);
793 static int prepare_callback(sd_event_source *s, void *userdata) {
794 sd_rtnl *rtnl = userdata;
801 e = sd_rtnl_get_events(rtnl);
805 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
809 r = sd_rtnl_get_timeout(rtnl, &until);
815 j = sd_event_source_set_time(rtnl->time_event_source, until);
820 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
827 static int exit_callback(sd_event_source *event, void *userdata) {
828 sd_rtnl *rtnl = userdata;
837 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
840 assert_return(rtnl, -EINVAL);
841 assert_return(!rtnl->event, -EBUSY);
843 assert(!rtnl->io_event_source);
844 assert(!rtnl->time_event_source);
847 rtnl->event = sd_event_ref(event);
849 r = sd_event_default(&rtnl->event);
854 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
858 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
862 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
866 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
870 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
874 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
881 sd_rtnl_detach_event(rtnl);
885 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
886 assert_return(rtnl, -EINVAL);
887 assert_return(rtnl->event, -ENXIO);
889 if (rtnl->io_event_source)
890 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
892 if (rtnl->time_event_source)
893 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
895 if (rtnl->exit_event_source)
896 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
899 rtnl->event = sd_event_unref(rtnl->event);
904 int sd_rtnl_add_match(sd_rtnl *rtnl,
906 sd_rtnl_message_handler_t callback,
908 struct match_callback *c;
910 assert_return(rtnl, -EINVAL);
911 assert_return(callback, -EINVAL);
912 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
913 assert_return(rtnl_message_type_is_link(type) ||
914 rtnl_message_type_is_addr(type) ||
915 rtnl_message_type_is_route(type), -ENOTSUP);
917 c = new0(struct match_callback, 1);
921 c->callback = callback;
923 c->userdata = userdata;
925 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
930 int sd_rtnl_remove_match(sd_rtnl *rtnl,
932 sd_rtnl_message_handler_t callback,
934 struct match_callback *c;
936 assert_return(rtnl, -EINVAL);
937 assert_return(callback, -EINVAL);
938 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
940 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
941 if (c->callback == callback && c->type == type && c->userdata == userdata) {
942 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);