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 int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) {
79 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
83 assert_return(ret, -EINVAL);
85 r = sd_rtnl_new(&rtnl);
89 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
93 if (setsockopt(rtnl->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
96 rtnl->sockaddr.nl.nl_groups = groups;
98 addrlen = sizeof(rtnl->sockaddr);
100 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
104 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
114 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
115 assert_return(rtnl, NULL);
116 assert_return(!rtnl_pid_changed(rtnl), NULL);
119 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
124 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
128 assert_return(!rtnl_pid_changed(rtnl), NULL);
130 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
131 struct match_callback *f;
134 for (i = 0; i < rtnl->rqueue_size; i++)
135 sd_rtnl_message_unref(rtnl->rqueue[i]);
138 for (i = 0; i < rtnl->rqueue_partial_size; i++)
139 sd_rtnl_message_unref(rtnl->rqueue_partial[i]);
140 free(rtnl->rqueue_partial);
142 for (i = 0; i < rtnl->wqueue_size; i++)
143 sd_rtnl_message_unref(rtnl->wqueue[i]);
148 hashmap_free_free(rtnl->reply_callbacks);
149 prioq_free(rtnl->reply_callbacks_prioq);
151 sd_event_source_unref(rtnl->io_event_source);
152 sd_event_source_unref(rtnl->time_event_source);
153 sd_event_source_unref(rtnl->exit_event_source);
154 sd_event_unref(rtnl->event);
156 while ((f = rtnl->match_callbacks)) {
157 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
161 safe_close(rtnl->fd);
168 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
170 assert(!rtnl_pid_changed(rtnl));
174 m->hdr->nlmsg_seq = rtnl->serial++;
176 rtnl_message_seal(m);
181 int sd_rtnl_send(sd_rtnl *nl,
182 sd_rtnl_message *message,
186 assert_return(nl, -EINVAL);
187 assert_return(!rtnl_pid_changed(nl), -ECHILD);
188 assert_return(message, -EINVAL);
189 assert_return(!message->sealed, -EPERM);
191 rtnl_seal_message(nl, message);
193 if (nl->wqueue_size <= 0) {
195 r = socket_write_message(nl, message);
199 /* nothing was sent, so let's put it on
201 nl->wqueue[0] = sd_rtnl_message_ref(message);
205 /* append to queue */
206 if (nl->wqueue_size >= RTNL_WQUEUE_MAX) {
207 log_debug("rtnl: exhausted the write queue size (%d)", RTNL_WQUEUE_MAX);
211 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
214 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
218 *serial = rtnl_message_get_serial(message);
223 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
226 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX) {
227 log_debug("rtnl: exhausted the read queue size (%d)", RTNL_RQUEUE_MAX);
231 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
237 int rtnl_rqueue_partial_make_room(sd_rtnl *rtnl) {
240 if (rtnl->rqueue_partial_size >= RTNL_RQUEUE_MAX) {
241 log_debug("rtnl: exhausted the partial read queue size (%d)", RTNL_RQUEUE_MAX);
245 if (!GREEDY_REALLOC(rtnl->rqueue_partial, rtnl->rqueue_partial_allocated,
246 rtnl->rqueue_partial_size + 1))
252 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
258 if (rtnl->rqueue_size <= 0) {
259 /* Try to read a new message */
260 r = socket_read_message(rtnl);
265 /* Dispatch a queued message */
266 *message = rtnl->rqueue[0];
267 rtnl->rqueue_size --;
268 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
273 static int dispatch_wqueue(sd_rtnl *rtnl) {
278 while (rtnl->wqueue_size > 0) {
279 r = socket_write_message(rtnl, rtnl->wqueue[0]);
283 /* Didn't do anything this time */
286 /* see equivalent in sd-bus.c */
287 sd_rtnl_message_unref(rtnl->wqueue[0]);
288 rtnl->wqueue_size --;
289 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
298 static int process_timeout(sd_rtnl *rtnl) {
299 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
300 struct reply_callback *c;
306 c = prioq_peek(rtnl->reply_callbacks_prioq);
310 n = now(CLOCK_MONOTONIC);
314 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
318 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
319 hashmap_remove(rtnl->reply_callbacks, &c->serial);
321 r = c->callback(rtnl, m, c->userdata);
324 return r < 0 ? r : 1;
327 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
328 struct reply_callback *c;
335 if (sd_rtnl_message_is_broadcast(m))
338 serial = rtnl_message_get_serial(m);
339 c = hashmap_remove(rtnl->reply_callbacks, &serial);
344 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
346 r = c->callback(rtnl, m, c->userdata);
352 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
353 struct match_callback *c;
360 r = sd_rtnl_message_get_type(m, &type);
364 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
365 if (type == c->type) {
366 r = c->callback(rtnl, m, c->userdata);
375 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
376 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
381 r = process_timeout(rtnl);
385 r = dispatch_wqueue(rtnl);
389 r = dispatch_rqueue(rtnl, &m);
395 r = process_reply(rtnl, m);
399 r = process_match(rtnl, m);
419 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
420 RTNL_DONT_DESTROY(rtnl);
423 assert_return(rtnl, -EINVAL);
424 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
425 assert_return(!rtnl->processing, -EBUSY);
427 rtnl->processing = true;
428 r = process_running(rtnl, ret);
429 rtnl->processing = false;
434 static usec_t calc_elapse(uint64_t usec) {
435 if (usec == (uint64_t) -1)
439 usec = RTNL_DEFAULT_TIMEOUT;
441 return now(CLOCK_MONOTONIC) + usec;
444 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
445 struct pollfd p[1] = {};
447 usec_t m = (usec_t) -1;
452 e = sd_rtnl_get_events(rtnl);
457 /* Caller wants more data, and doesn't care about
458 * what's been read or any other timeouts. */
462 /* Caller wants to process if there is something to
463 * process, but doesn't care otherwise */
465 r = sd_rtnl_get_timeout(rtnl, &until);
470 nw = now(CLOCK_MONOTONIC);
471 m = until > nw ? until - nw : 0;
475 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
481 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
485 return r > 0 ? 1 : 0;
488 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
489 assert_return(nl, -EINVAL);
490 assert_return(!rtnl_pid_changed(nl), -ECHILD);
492 if (nl->rqueue_size > 0)
495 return rtnl_poll(nl, false, timeout_usec);
498 static int timeout_compare(const void *a, const void *b) {
499 const struct reply_callback *x = a, *y = b;
501 if (x->timeout != 0 && y->timeout == 0)
504 if (x->timeout == 0 && y->timeout != 0)
507 if (x->timeout < y->timeout)
510 if (x->timeout > y->timeout)
516 int sd_rtnl_call_async(sd_rtnl *nl,
518 sd_rtnl_message_handler_t callback,
522 struct reply_callback *c;
526 assert_return(nl, -EINVAL);
527 assert_return(m, -EINVAL);
528 assert_return(callback, -EINVAL);
529 assert_return(!rtnl_pid_changed(nl), -ECHILD);
531 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
535 if (usec != (uint64_t) -1) {
536 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
541 c = new0(struct reply_callback, 1);
545 c->callback = callback;
546 c->userdata = userdata;
547 c->timeout = calc_elapse(usec);
549 k = sd_rtnl_send(nl, m, &s);
557 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
563 if (c->timeout != 0) {
564 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
567 sd_rtnl_call_async_cancel(nl, c->serial);
578 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
579 struct reply_callback *c;
582 assert_return(nl, -EINVAL);
583 assert_return(serial != 0, -EINVAL);
584 assert_return(!rtnl_pid_changed(nl), -ECHILD);
586 c = hashmap_remove(nl->reply_callbacks, &s);
591 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
597 int sd_rtnl_call(sd_rtnl *rtnl,
598 sd_rtnl_message *message,
600 sd_rtnl_message **ret) {
606 assert_return(rtnl, -EINVAL);
607 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
608 assert_return(message, -EINVAL);
610 r = sd_rtnl_send(rtnl, message, &serial);
614 timeout = calc_elapse(usec);
619 while (i < rtnl->rqueue_size) {
620 sd_rtnl_message *incoming;
621 uint32_t received_serial;
623 incoming = rtnl->rqueue[i];
624 received_serial = rtnl_message_get_serial(incoming);
626 if (received_serial == serial) {
627 /* found a match, remove from rqueue and return it */
628 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
629 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
632 r = sd_rtnl_message_get_errno(incoming);
634 sd_rtnl_message_unref(incoming);
641 sd_rtnl_message_unref(incoming);
646 /* Try to read more, right away */
650 r = socket_read_message(rtnl);
654 /* receieved message, so try to process straight away */
660 n = now(CLOCK_MONOTONIC);
666 left = (uint64_t) -1;
668 r = rtnl_poll(rtnl, true, left);
672 r = dispatch_wqueue(rtnl);
678 int sd_rtnl_flush(sd_rtnl *rtnl) {
681 assert_return(rtnl, -EINVAL);
682 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
684 if (rtnl->wqueue_size <= 0)
688 r = dispatch_wqueue(rtnl);
692 if (rtnl->wqueue_size <= 0)
695 r = rtnl_poll(rtnl, false, (uint64_t) -1);
701 int sd_rtnl_get_events(sd_rtnl *rtnl) {
704 assert_return(rtnl, -EINVAL);
705 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
707 if (rtnl->rqueue_size <= 0)
709 if (rtnl->wqueue_size > 0)
715 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
716 struct reply_callback *c;
718 assert_return(rtnl, -EINVAL);
719 assert_return(timeout_usec, -EINVAL);
720 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
722 if (rtnl->rqueue_size > 0) {
727 c = prioq_peek(rtnl->reply_callbacks_prioq);
729 *timeout_usec = (uint64_t) -1;
733 *timeout_usec = c->timeout;
738 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
739 sd_rtnl *rtnl = userdata;
744 r = sd_rtnl_process(rtnl, NULL);
751 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
752 sd_rtnl *rtnl = userdata;
757 r = sd_rtnl_process(rtnl, NULL);
764 static int prepare_callback(sd_event_source *s, void *userdata) {
765 sd_rtnl *rtnl = userdata;
772 e = sd_rtnl_get_events(rtnl);
776 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
780 r = sd_rtnl_get_timeout(rtnl, &until);
786 j = sd_event_source_set_time(rtnl->time_event_source, until);
791 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
798 static int exit_callback(sd_event_source *event, void *userdata) {
799 sd_rtnl *rtnl = userdata;
808 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
811 assert_return(rtnl, -EINVAL);
812 assert_return(!rtnl->event, -EBUSY);
814 assert(!rtnl->io_event_source);
815 assert(!rtnl->time_event_source);
818 rtnl->event = sd_event_ref(event);
820 r = sd_event_default(&rtnl->event);
825 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
829 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
833 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
837 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
841 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
845 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
852 sd_rtnl_detach_event(rtnl);
856 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
857 assert_return(rtnl, -EINVAL);
858 assert_return(rtnl->event, -ENXIO);
860 if (rtnl->io_event_source)
861 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
863 if (rtnl->time_event_source)
864 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
866 if (rtnl->exit_event_source)
867 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
870 rtnl->event = sd_event_unref(rtnl->event);
875 int sd_rtnl_add_match(sd_rtnl *rtnl,
877 sd_rtnl_message_handler_t callback,
879 struct match_callback *c;
881 assert_return(rtnl, -EINVAL);
882 assert_return(callback, -EINVAL);
883 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
884 assert_return(rtnl_message_type_is_link(type) ||
885 rtnl_message_type_is_addr(type) ||
886 rtnl_message_type_is_route(type), -ENOTSUP);
888 c = new0(struct match_callback, 1);
892 c->callback = callback;
894 c->userdata = userdata;
896 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
901 int sd_rtnl_remove_match(sd_rtnl *rtnl,
903 sd_rtnl_message_handler_t callback,
905 struct match_callback *c;
907 assert_return(rtnl, -EINVAL);
908 assert_return(callback, -EINVAL);
909 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
911 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
912 if (c->callback == callback && c->type == type && c->userdata == userdata) {
913 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);