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) {
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 /* We guarantee that wqueue always has space for at least
52 rtnl->wqueue = new(sd_rtnl_message*, 1);
62 static bool rtnl_pid_changed(sd_rtnl *rtnl) {
65 /* We don't support people creating an rtnl connection and
66 * keeping it around over a fork(). Let's complain. */
68 return rtnl->original_pid != getpid();
71 int sd_rtnl_open(uint32_t groups, sd_rtnl **ret) {
72 _cleanup_sd_rtnl_unref_ sd_rtnl *rtnl = NULL;
76 r = sd_rtnl_new(&rtnl);
80 rtnl->fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC|SOCK_NONBLOCK, NETLINK_ROUTE);
84 rtnl->sockaddr.nl.nl_groups = groups;
86 addrlen = sizeof(rtnl->sockaddr);
88 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
92 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
102 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
104 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
109 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
111 if (rtnl && REFCNT_DEC(rtnl->n_ref) <= 0) {
114 for (i = 0; i < rtnl->rqueue_size; i++)
115 sd_rtnl_message_unref(rtnl->rqueue[i]);
118 for (i = 0; i < rtnl->wqueue_size; i++)
119 sd_rtnl_message_unref(rtnl->wqueue[i]);
122 hashmap_free_free(rtnl->reply_callbacks);
123 prioq_free(rtnl->reply_callbacks_prioq);
126 close_nointr_nofail(rtnl->fd);
134 int sd_rtnl_send(sd_rtnl *nl,
135 sd_rtnl_message *message,
139 assert_return(nl, -EINVAL);
140 assert_return(!rtnl_pid_changed(nl), -ECHILD);
141 assert_return(message, -EINVAL);
143 r = message_seal(nl, message);
147 if (nl->wqueue_size <= 0) {
149 r = socket_write_message(nl, message);
153 /* nothing was sent, so let's put it on
155 nl->wqueue[0] = sd_rtnl_message_ref(message);
161 /* append to queue */
162 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
165 q = realloc(nl->wqueue, sizeof(sd_rtnl_message*) * (nl->wqueue_size + 1));
170 q[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
174 *serial = message_get_serial(message);
179 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
180 sd_rtnl_message *z = NULL;
186 if (rtnl->rqueue_size > 0) {
187 /* Dispatch a queued message */
189 *message = rtnl->rqueue[0];
190 rtnl->rqueue_size --;
191 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
196 /* Try to read a new message */
197 r = socket_read_message(rtnl, &z);
208 static int dispatch_wqueue(sd_rtnl *rtnl) {
213 while (rtnl->wqueue_size > 0) {
214 r = socket_write_message(rtnl, rtnl->wqueue[0]);
218 /* Didn't do anything this time */
221 /* see equivalent in sd-bus.c */
222 sd_rtnl_message_unref(rtnl->wqueue[0]);
223 rtnl->wqueue_size --;
224 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
233 static int process_timeout(sd_rtnl *rtnl) {
234 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
235 struct reply_callback *c;
241 c = prioq_peek(rtnl->reply_callbacks_prioq);
245 n = now(CLOCK_MONOTONIC);
249 r = message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
253 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
254 hashmap_remove(rtnl->reply_callbacks, &c->serial);
256 r = c->callback(rtnl, m, c->userdata);
259 return r < 0 ? r : 1;
262 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
263 struct reply_callback *c;
270 serial = message_get_serial(m);
271 c = hashmap_remove(rtnl->reply_callbacks, &serial);
276 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
278 r = c->callback(rtnl, m, c->userdata);
284 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
285 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *m = NULL;
288 r = process_timeout(rtnl);
292 r = dispatch_wqueue(rtnl);
296 r = dispatch_rqueue(rtnl, &m);
302 r = process_reply(rtnl, m);
322 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
323 RTNL_DONT_DESTROY(rtnl);
326 assert_return(rtnl, -EINVAL);
327 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
328 assert_return(!rtnl->processing, -EBUSY);
330 rtnl->processing = true;
331 r = process_running(rtnl, ret);
332 rtnl->processing = false;
337 static usec_t calc_elapse(uint64_t usec) {
338 if (usec == (uint64_t) -1)
342 usec = RTNL_DEFAULT_TIMEOUT;
344 return now(CLOCK_MONOTONIC) + usec;
347 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
348 struct pollfd p[1] = {};
350 usec_t m = (usec_t) -1;
355 e = sd_rtnl_get_events(rtnl);
360 /* Caller wants more data, and doesn't care about
361 * what's been read or any other timeouts. */
365 /* Caller wants to process if there is something to
366 * process, but doesn't care otherwise */
368 r = sd_rtnl_get_timeout(rtnl, &until);
373 nw = now(CLOCK_MONOTONIC);
374 m = until > nw ? until - nw : 0;
378 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
384 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
388 return r > 0 ? 1 : 0;
391 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
392 assert_return(nl, -EINVAL);
393 assert_return(!rtnl_pid_changed(nl), -ECHILD);
395 if (nl->rqueue_size > 0)
398 return rtnl_poll(nl, false, timeout_usec);
401 static int timeout_compare(const void *a, const void *b) {
402 const struct reply_callback *x = a, *y = b;
404 if (x->timeout != 0 && y->timeout == 0)
407 if (x->timeout == 0 && y->timeout != 0)
410 if (x->timeout < y->timeout)
413 if (x->timeout > y->timeout)
419 int sd_rtnl_call_async(sd_rtnl *nl,
421 sd_rtnl_message_handler_t callback,
425 struct reply_callback *c;
429 assert_return(nl, -EINVAL);
430 assert_return(m, -EINVAL);
431 assert_return(callback, -EINVAL);
432 assert_return(!rtnl_pid_changed(nl), -ECHILD);
434 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
438 if (usec != (uint64_t) -1) {
439 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
444 c = new0(struct reply_callback, 1);
448 c->callback = callback;
449 c->userdata = userdata;
450 c->timeout = calc_elapse(usec);
452 k = sd_rtnl_send(nl, m, &s);
460 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
466 if (c->timeout != 0) {
467 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
470 sd_rtnl_call_async_cancel(nl, c->serial);
481 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
482 struct reply_callback *c;
485 assert_return(nl, -EINVAL);
486 assert_return(serial != 0, -EINVAL);
487 assert_return(!rtnl_pid_changed(nl), -ECHILD);
489 c = hashmap_remove(nl->reply_callbacks, &s);
494 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
500 int sd_rtnl_call(sd_rtnl *nl,
501 sd_rtnl_message *message,
503 sd_rtnl_message **ret) {
509 assert_return(nl, -EINVAL);
510 assert_return(!rtnl_pid_changed(nl), -ECHILD);
511 assert_return(message, -EINVAL);
513 r = sd_rtnl_send(nl, message, &serial);
517 timeout = calc_elapse(usec);
521 _cleanup_sd_rtnl_message_unref_ sd_rtnl_message *incoming = NULL;
526 if (nl->rqueue_size >= RTNL_RQUEUE_MAX)
529 /* Make sure there's room for queueing this
530 * locally, before we read the message */
532 q = realloc(nl->rqueue, (nl->rqueue_size + 1) * sizeof(sd_rtnl_message*));
540 r = socket_read_message(nl, &incoming);
544 uint32_t received_serial = message_get_serial(incoming);
546 if (received_serial == serial) {
547 r = sd_rtnl_message_get_errno(incoming);
559 /* Room was allocated on the queue above */
560 nl->rqueue[nl->rqueue_size ++] = incoming;
564 /* Try to read more, right away */
573 n = now(CLOCK_MONOTONIC);
579 left = (uint64_t) -1;
581 r = rtnl_poll(nl, true, left);
585 r = dispatch_wqueue(nl);
591 int sd_rtnl_flush(sd_rtnl *rtnl) {
594 assert_return(rtnl, -EINVAL);
595 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
597 if (rtnl->wqueue_size <= 0)
601 r = dispatch_wqueue(rtnl);
605 if (rtnl->wqueue_size <= 0)
608 r = rtnl_poll(rtnl, false, (uint64_t) -1);
614 int sd_rtnl_get_events(sd_rtnl *rtnl) {
617 assert_return(rtnl, -EINVAL);
618 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
620 if (rtnl->rqueue_size <= 0)
622 if (rtnl->wqueue_size > 0)
628 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
629 struct reply_callback *c;
631 assert_return(rtnl, -EINVAL);
632 assert_return(timeout_usec, -EINVAL);
633 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
635 if (rtnl->rqueue_size > 0) {
640 c = prioq_peek(rtnl->reply_callbacks_prioq);
642 *timeout_usec = (uint64_t) -1;
646 *timeout_usec = c->timeout;
651 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
652 sd_rtnl *rtnl = userdata;
657 r = sd_rtnl_process(rtnl, NULL);
664 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
665 sd_rtnl *rtnl = userdata;
670 r = sd_rtnl_process(rtnl, NULL);
677 static int prepare_callback(sd_event_source *s, void *userdata) {
678 sd_rtnl *rtnl = userdata;
685 e = sd_rtnl_get_events(rtnl);
689 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
693 r = sd_rtnl_get_timeout(rtnl, &until);
699 j = sd_event_source_set_time(rtnl->time_event_source, until);
704 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
711 static int quit_callback(sd_event_source *event, void *userdata) {
712 sd_rtnl *rtnl = userdata;
721 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
724 assert_return(rtnl, -EINVAL);
725 assert_return(!rtnl->event, -EBUSY);
727 assert(!rtnl->io_event_source);
728 assert(!rtnl->time_event_source);
731 rtnl->event = sd_event_ref(event);
733 r = sd_event_default(&rtnl->event);
738 r = sd_event_add_io(rtnl->event, rtnl->fd, 0, io_callback, rtnl, &rtnl->io_event_source);
742 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
746 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
750 r = sd_event_add_monotonic(rtnl->event, 0, 0, time_callback, rtnl, &rtnl->time_event_source);
754 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
758 r = sd_event_add_quit(rtnl->event, quit_callback, rtnl, &rtnl->quit_event_source);
765 sd_rtnl_detach_event(rtnl);
769 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
770 assert_return(rtnl, -EINVAL);
771 assert_return(rtnl->event, -ENXIO);
773 if (rtnl->io_event_source)
774 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
776 if (rtnl->time_event_source)
777 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
779 if (rtnl->quit_event_source)
780 rtnl->quit_event_source = sd_event_source_unref(rtnl->quit_event_source);
783 rtnl->event = sd_event_unref(rtnl->event);