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))
63 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
66 /* We don't support people creating an rtnl connection and
67 * keeping it around over a fork(). Let's complain. */
69 return rtnl->original_pid != getpid();
72 int sd_rtnl_open(sd_rtnl **ret, uint32_t groups) {
73 _cleanup_rtnl_unref_ sd_rtnl *rtnl = NULL;
77 assert_return(ret, -EINVAL);
79 r = sd_rtnl_new(&rtnl);
83 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
87 rtnl->sockaddr.nl.nl_groups = groups;
89 addrlen = sizeof(rtnl->sockaddr);
91 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
95 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
105 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
106 assert_return(rtnl, NULL);
107 assert_return(!rtnl_pid_changed(rtnl), NULL);
110 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
115 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
119 assert_return(!rtnl_pid_changed(rtnl), NULL);
121 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
122 struct match_callback *f;
125 for (i = 0; i < rtnl->rqueue_size; i++)
126 sd_rtnl_message_unref(rtnl->rqueue[i]);
129 for (i = 0; i < rtnl->wqueue_size; i++)
130 sd_rtnl_message_unref(rtnl->wqueue[i]);
133 hashmap_free_free(rtnl->reply_callbacks);
134 prioq_free(rtnl->reply_callbacks_prioq);
136 sd_event_source_unref(rtnl->io_event_source);
137 sd_event_source_unref(rtnl->time_event_source);
138 sd_event_source_unref(rtnl->exit_event_source);
139 sd_event_unref(rtnl->event);
141 while ((f = rtnl->match_callbacks)) {
142 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
146 safe_close(rtnl->fd);
153 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
155 assert(!rtnl_pid_changed(rtnl));
159 m->hdr->nlmsg_seq = rtnl->serial++;
161 rtnl_message_seal(m);
166 int sd_rtnl_send(sd_rtnl *nl,
167 sd_rtnl_message *message,
171 assert_return(nl, -EINVAL);
172 assert_return(!rtnl_pid_changed(nl), -ECHILD);
173 assert_return(message, -EINVAL);
174 assert_return(!message->sealed, -EPERM);
176 rtnl_seal_message(nl, message);
178 if (nl->wqueue_size <= 0) {
180 r = socket_write_message(nl, message);
184 /* nothing was sent, so let's put it on
186 nl->wqueue[0] = sd_rtnl_message_ref(message);
190 /* append to queue */
191 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
194 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
197 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
201 *serial = rtnl_message_get_serial(message);
206 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
207 sd_rtnl_message *z = NULL;
213 if (rtnl->rqueue_size > 0) {
214 /* Dispatch a queued message */
216 *message = rtnl->rqueue[0];
217 rtnl->rqueue_size --;
218 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
223 /* Try to read a new message */
224 r = socket_read_message(rtnl, &z);
233 static int dispatch_wqueue(sd_rtnl *rtnl) {
238 while (rtnl->wqueue_size > 0) {
239 r = socket_write_message(rtnl, rtnl->wqueue[0]);
243 /* Didn't do anything this time */
246 /* see equivalent in sd-bus.c */
247 sd_rtnl_message_unref(rtnl->wqueue[0]);
248 rtnl->wqueue_size --;
249 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
258 static int process_timeout(sd_rtnl *rtnl) {
259 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
260 struct reply_callback *c;
266 c = prioq_peek(rtnl->reply_callbacks_prioq);
270 n = now(CLOCK_MONOTONIC);
274 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
278 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
279 hashmap_remove(rtnl->reply_callbacks, &c->serial);
281 r = c->callback(rtnl, m, c->userdata);
284 return r < 0 ? r : 1;
287 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
288 struct reply_callback *c;
295 if (sd_rtnl_message_is_broadcast(m))
298 serial = rtnl_message_get_serial(m);
299 c = hashmap_remove(rtnl->reply_callbacks, &serial);
304 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
306 r = c->callback(rtnl, m, c->userdata);
312 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
313 struct match_callback *c;
320 r = sd_rtnl_message_get_type(m, &type);
324 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
325 if (type == c->type) {
326 r = c->callback(rtnl, m, c->userdata);
335 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
336 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
341 r = process_timeout(rtnl);
345 r = dispatch_wqueue(rtnl);
349 r = dispatch_rqueue(rtnl, &m);
355 r = process_reply(rtnl, m);
359 r = process_match(rtnl, m);
379 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
380 RTNL_DONT_DESTROY(rtnl);
383 assert_return(rtnl, -EINVAL);
384 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
385 assert_return(!rtnl->processing, -EBUSY);
387 rtnl->processing = true;
388 r = process_running(rtnl, ret);
389 rtnl->processing = false;
394 static usec_t calc_elapse(uint64_t usec) {
395 if (usec == (uint64_t) -1)
399 usec = RTNL_DEFAULT_TIMEOUT;
401 return now(CLOCK_MONOTONIC) + usec;
404 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
405 struct pollfd p[1] = {};
407 usec_t m = (usec_t) -1;
412 e = sd_rtnl_get_events(rtnl);
417 /* Caller wants more data, and doesn't care about
418 * what's been read or any other timeouts. */
422 /* Caller wants to process if there is something to
423 * process, but doesn't care otherwise */
425 r = sd_rtnl_get_timeout(rtnl, &until);
430 nw = now(CLOCK_MONOTONIC);
431 m = until > nw ? until - nw : 0;
435 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
441 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
445 return r > 0 ? 1 : 0;
448 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
449 assert_return(nl, -EINVAL);
450 assert_return(!rtnl_pid_changed(nl), -ECHILD);
452 if (nl->rqueue_size > 0)
455 return rtnl_poll(nl, false, timeout_usec);
458 static int timeout_compare(const void *a, const void *b) {
459 const struct reply_callback *x = a, *y = b;
461 if (x->timeout != 0 && y->timeout == 0)
464 if (x->timeout == 0 && y->timeout != 0)
467 if (x->timeout < y->timeout)
470 if (x->timeout > y->timeout)
476 int sd_rtnl_call_async(sd_rtnl *nl,
478 sd_rtnl_message_handler_t callback,
482 struct reply_callback *c;
486 assert_return(nl, -EINVAL);
487 assert_return(m, -EINVAL);
488 assert_return(callback, -EINVAL);
489 assert_return(!rtnl_pid_changed(nl), -ECHILD);
491 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
495 if (usec != (uint64_t) -1) {
496 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
501 c = new0(struct reply_callback, 1);
505 c->callback = callback;
506 c->userdata = userdata;
507 c->timeout = calc_elapse(usec);
509 k = sd_rtnl_send(nl, m, &s);
517 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
523 if (c->timeout != 0) {
524 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
527 sd_rtnl_call_async_cancel(nl, c->serial);
538 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
539 struct reply_callback *c;
542 assert_return(nl, -EINVAL);
543 assert_return(serial != 0, -EINVAL);
544 assert_return(!rtnl_pid_changed(nl), -ECHILD);
546 c = hashmap_remove(nl->reply_callbacks, &s);
551 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
557 int sd_rtnl_call(sd_rtnl *nl,
558 sd_rtnl_message *message,
560 sd_rtnl_message **ret) {
566 assert_return(nl, -EINVAL);
567 assert_return(!rtnl_pid_changed(nl), -ECHILD);
568 assert_return(message, -EINVAL);
570 r = sd_rtnl_send(nl, message, &serial);
574 timeout = calc_elapse(usec);
578 _cleanup_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
583 if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
586 /* Make sure there's room for queueing this
587 * locally, before we read the message */
589 q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
597 r = socket_read_message(nl, &incoming);
601 uint32_t received_serial = rtnl_message_get_serial(incoming);
603 if (received_serial == serial) {
604 r = sd_rtnl_message_get_errno(incoming);
616 /* Room was allocated on the queue above */
617 nl->rqueue[nl->rqueue_size ++] = incoming;
621 /* Try to read more, right away */
630 n = now(CLOCK_MONOTONIC);
636 left = (uint64_t) -1;
638 r = rtnl_poll(nl, true, left);
642 r = dispatch_wqueue(nl);
648 int sd_rtnl_flush(sd_rtnl *rtnl) {
651 assert_return(rtnl, -EINVAL);
652 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
654 if (rtnl->wqueue_size <= 0)
658 r = dispatch_wqueue(rtnl);
662 if (rtnl->wqueue_size <= 0)
665 r = rtnl_poll(rtnl, false, (uint64_t) -1);
671 int sd_rtnl_get_events(sd_rtnl *rtnl) {
674 assert_return(rtnl, -EINVAL);
675 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
677 if (rtnl->rqueue_size <= 0)
679 if (rtnl->wqueue_size > 0)
685 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
686 struct reply_callback *c;
688 assert_return(rtnl, -EINVAL);
689 assert_return(timeout_usec, -EINVAL);
690 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
692 if (rtnl->rqueue_size > 0) {
697 c = prioq_peek(rtnl->reply_callbacks_prioq);
699 *timeout_usec = (uint64_t) -1;
703 *timeout_usec = c->timeout;
708 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
709 sd_rtnl *rtnl = userdata;
714 r = sd_rtnl_process(rtnl, NULL);
721 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
722 sd_rtnl *rtnl = userdata;
727 r = sd_rtnl_process(rtnl, NULL);
734 static int prepare_callback(sd_event_source *s, void *userdata) {
735 sd_rtnl *rtnl = userdata;
742 e = sd_rtnl_get_events(rtnl);
746 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
750 r = sd_rtnl_get_timeout(rtnl, &until);
756 j = sd_event_source_set_time(rtnl->time_event_source, until);
761 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
768 static int exit_callback(sd_event_source *event, void *userdata) {
769 sd_rtnl *rtnl = userdata;
778 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
781 assert_return(rtnl, -EINVAL);
782 assert_return(!rtnl->event, -EBUSY);
784 assert(!rtnl->io_event_source);
785 assert(!rtnl->time_event_source);
788 rtnl->event = sd_event_ref(event);
790 r = sd_event_default(&rtnl->event);
795 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
799 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
803 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
807 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
811 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
815 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
822 sd_rtnl_detach_event(rtnl);
826 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
827 assert_return(rtnl, -EINVAL);
828 assert_return(rtnl->event, -ENXIO);
830 if (rtnl->io_event_source)
831 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
833 if (rtnl->time_event_source)
834 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
836 if (rtnl->exit_event_source)
837 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
840 rtnl->event = sd_event_unref(rtnl->event);
845 int sd_rtnl_add_match(sd_rtnl *rtnl,
847 sd_rtnl_message_handler_t callback,
849 struct match_callback *c;
851 assert_return(rtnl, -EINVAL);
852 assert_return(callback, -EINVAL);
853 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
854 assert_return(rtnl_message_type_is_link(type) ||
855 rtnl_message_type_is_addr(type) ||
856 rtnl_message_type_is_route(type), -ENOTSUP);
858 c = new0(struct match_callback, 1);
862 c->callback = callback;
864 c->userdata = userdata;
866 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
871 int sd_rtnl_remove_match(sd_rtnl *rtnl,
873 sd_rtnl_message_handler_t callback,
875 struct match_callback *c;
877 assert_return(rtnl, -EINVAL);
878 assert_return(callback, -EINVAL);
879 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
881 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
882 if (c->callback == callback && c->type == type && c->userdata == userdata) {
883 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);