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 if (setsockopt(rtnl->fd, SOL_SOCKET, SO_PASSCRED, &one, sizeof(one)) < 0)
90 rtnl->sockaddr.nl.nl_groups = groups;
92 addrlen = sizeof(rtnl->sockaddr);
94 r = bind(rtnl->fd, &rtnl->sockaddr.sa, addrlen);
98 r = getsockname(rtnl->fd, &rtnl->sockaddr.sa, &addrlen);
108 sd_rtnl *sd_rtnl_ref(sd_rtnl *rtnl) {
109 assert_return(rtnl, NULL);
110 assert_return(!rtnl_pid_changed(rtnl), NULL);
113 assert_se(REFCNT_INC(rtnl->n_ref) >= 2);
118 sd_rtnl *sd_rtnl_unref(sd_rtnl *rtnl) {
122 assert_return(!rtnl_pid_changed(rtnl), NULL);
124 if (REFCNT_DEC(rtnl->n_ref) <= 0) {
125 struct match_callback *f;
128 for (i = 0; i < rtnl->rqueue_size; i++)
129 sd_rtnl_message_unref(rtnl->rqueue[i]);
132 for (i = 0; i < rtnl->wqueue_size; i++)
133 sd_rtnl_message_unref(rtnl->wqueue[i]);
136 hashmap_free_free(rtnl->reply_callbacks);
137 prioq_free(rtnl->reply_callbacks_prioq);
139 sd_event_source_unref(rtnl->io_event_source);
140 sd_event_source_unref(rtnl->time_event_source);
141 sd_event_source_unref(rtnl->exit_event_source);
142 sd_event_unref(rtnl->event);
144 while ((f = rtnl->match_callbacks)) {
145 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, f);
149 safe_close(rtnl->fd);
156 static void rtnl_seal_message(sd_rtnl *rtnl, sd_rtnl_message *m) {
158 assert(!rtnl_pid_changed(rtnl));
162 m->hdr->nlmsg_seq = rtnl->serial++;
164 rtnl_message_seal(m);
169 int sd_rtnl_send(sd_rtnl *nl,
170 sd_rtnl_message *message,
174 assert_return(nl, -EINVAL);
175 assert_return(!rtnl_pid_changed(nl), -ECHILD);
176 assert_return(message, -EINVAL);
177 assert_return(!message->sealed, -EPERM);
179 rtnl_seal_message(nl, message);
181 if (nl->wqueue_size <= 0) {
183 r = socket_write_message(nl, message);
187 /* nothing was sent, so let's put it on
189 nl->wqueue[0] = sd_rtnl_message_ref(message);
193 /* append to queue */
194 if (nl->wqueue_size >= RTNL_WQUEUE_MAX)
197 if (!GREEDY_REALLOC(nl->wqueue, nl->wqueue_allocated, nl->wqueue_size + 1))
200 nl->wqueue[nl->wqueue_size ++] = sd_rtnl_message_ref(message);
204 *serial = rtnl_message_get_serial(message);
209 int rtnl_rqueue_make_room(sd_rtnl *rtnl) {
212 if (rtnl->rqueue_size >= RTNL_RQUEUE_MAX)
215 if (!GREEDY_REALLOC(rtnl->rqueue, rtnl->rqueue_allocated, rtnl->rqueue_size + 1))
221 static int dispatch_rqueue(sd_rtnl *rtnl, sd_rtnl_message **message) {
227 if (rtnl->rqueue_size <= 0) {
228 /* Try to read a new message */
229 r = socket_read_message(rtnl);
234 /* Dispatch a queued message */
235 *message = rtnl->rqueue[0];
236 rtnl->rqueue_size --;
237 memmove(rtnl->rqueue, rtnl->rqueue + 1, sizeof(sd_rtnl_message*) * rtnl->rqueue_size);
242 static int dispatch_wqueue(sd_rtnl *rtnl) {
247 while (rtnl->wqueue_size > 0) {
248 r = socket_write_message(rtnl, rtnl->wqueue[0]);
252 /* Didn't do anything this time */
255 /* see equivalent in sd-bus.c */
256 sd_rtnl_message_unref(rtnl->wqueue[0]);
257 rtnl->wqueue_size --;
258 memmove(rtnl->wqueue, rtnl->wqueue + 1, sizeof(sd_rtnl_message*) * rtnl->wqueue_size);
267 static int process_timeout(sd_rtnl *rtnl) {
268 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
269 struct reply_callback *c;
275 c = prioq_peek(rtnl->reply_callbacks_prioq);
279 n = now(CLOCK_MONOTONIC);
283 r = rtnl_message_new_synthetic_error(-ETIMEDOUT, c->serial, &m);
287 assert_se(prioq_pop(rtnl->reply_callbacks_prioq) == c);
288 hashmap_remove(rtnl->reply_callbacks, &c->serial);
290 r = c->callback(rtnl, m, c->userdata);
293 return r < 0 ? r : 1;
296 static int process_reply(sd_rtnl *rtnl, sd_rtnl_message *m) {
297 struct reply_callback *c;
304 if (sd_rtnl_message_is_broadcast(m))
307 serial = rtnl_message_get_serial(m);
308 c = hashmap_remove(rtnl->reply_callbacks, &serial);
313 prioq_remove(rtnl->reply_callbacks_prioq, c, &c->prioq_idx);
315 r = c->callback(rtnl, m, c->userdata);
321 static int process_match(sd_rtnl *rtnl, sd_rtnl_message *m) {
322 struct match_callback *c;
329 r = sd_rtnl_message_get_type(m, &type);
333 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks) {
334 if (type == c->type) {
335 r = c->callback(rtnl, m, c->userdata);
344 static int process_running(sd_rtnl *rtnl, sd_rtnl_message **ret) {
345 _cleanup_rtnl_message_unref_ sd_rtnl_message *m = NULL;
350 r = process_timeout(rtnl);
354 r = dispatch_wqueue(rtnl);
358 r = dispatch_rqueue(rtnl, &m);
364 r = process_reply(rtnl, m);
368 r = process_match(rtnl, m);
388 int sd_rtnl_process(sd_rtnl *rtnl, sd_rtnl_message **ret) {
389 RTNL_DONT_DESTROY(rtnl);
392 assert_return(rtnl, -EINVAL);
393 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
394 assert_return(!rtnl->processing, -EBUSY);
396 rtnl->processing = true;
397 r = process_running(rtnl, ret);
398 rtnl->processing = false;
403 static usec_t calc_elapse(uint64_t usec) {
404 if (usec == (uint64_t) -1)
408 usec = RTNL_DEFAULT_TIMEOUT;
410 return now(CLOCK_MONOTONIC) + usec;
413 static int rtnl_poll(sd_rtnl *rtnl, bool need_more, uint64_t timeout_usec) {
414 struct pollfd p[1] = {};
416 usec_t m = (usec_t) -1;
421 e = sd_rtnl_get_events(rtnl);
426 /* Caller wants more data, and doesn't care about
427 * what's been read or any other timeouts. */
431 /* Caller wants to process if there is something to
432 * process, but doesn't care otherwise */
434 r = sd_rtnl_get_timeout(rtnl, &until);
439 nw = now(CLOCK_MONOTONIC);
440 m = until > nw ? until - nw : 0;
444 if (timeout_usec != (uint64_t) -1 && (m == (uint64_t) -1 || timeout_usec < m))
450 r = ppoll(p, 1, m == (uint64_t) -1 ? NULL : timespec_store(&ts, m), NULL);
454 return r > 0 ? 1 : 0;
457 int sd_rtnl_wait(sd_rtnl *nl, uint64_t timeout_usec) {
458 assert_return(nl, -EINVAL);
459 assert_return(!rtnl_pid_changed(nl), -ECHILD);
461 if (nl->rqueue_size > 0)
464 return rtnl_poll(nl, false, timeout_usec);
467 static int timeout_compare(const void *a, const void *b) {
468 const struct reply_callback *x = a, *y = b;
470 if (x->timeout != 0 && y->timeout == 0)
473 if (x->timeout == 0 && y->timeout != 0)
476 if (x->timeout < y->timeout)
479 if (x->timeout > y->timeout)
485 int sd_rtnl_call_async(sd_rtnl *nl,
487 sd_rtnl_message_handler_t callback,
491 struct reply_callback *c;
495 assert_return(nl, -EINVAL);
496 assert_return(m, -EINVAL);
497 assert_return(callback, -EINVAL);
498 assert_return(!rtnl_pid_changed(nl), -ECHILD);
500 r = hashmap_ensure_allocated(&nl->reply_callbacks, uint64_hash_func, uint64_compare_func);
504 if (usec != (uint64_t) -1) {
505 r = prioq_ensure_allocated(&nl->reply_callbacks_prioq, timeout_compare);
510 c = new0(struct reply_callback, 1);
514 c->callback = callback;
515 c->userdata = userdata;
516 c->timeout = calc_elapse(usec);
518 k = sd_rtnl_send(nl, m, &s);
526 r = hashmap_put(nl->reply_callbacks, &c->serial, c);
532 if (c->timeout != 0) {
533 r = prioq_put(nl->reply_callbacks_prioq, c, &c->prioq_idx);
536 sd_rtnl_call_async_cancel(nl, c->serial);
547 int sd_rtnl_call_async_cancel(sd_rtnl *nl, uint32_t serial) {
548 struct reply_callback *c;
551 assert_return(nl, -EINVAL);
552 assert_return(serial != 0, -EINVAL);
553 assert_return(!rtnl_pid_changed(nl), -ECHILD);
555 c = hashmap_remove(nl->reply_callbacks, &s);
560 prioq_remove(nl->reply_callbacks_prioq, c, &c->prioq_idx);
566 int sd_rtnl_call(sd_rtnl *rtnl,
567 sd_rtnl_message *message,
569 sd_rtnl_message **ret) {
575 assert_return(rtnl, -EINVAL);
576 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
577 assert_return(message, -EINVAL);
579 r = sd_rtnl_send(rtnl, message, &serial);
583 timeout = calc_elapse(usec);
588 while (i < rtnl->rqueue_size) {
589 sd_rtnl_message *incoming;
590 uint32_t received_serial;
592 incoming = rtnl->rqueue[i];
593 received_serial = rtnl_message_get_serial(incoming);
595 if (received_serial == serial) {
596 /* found a match, remove from rqueue and return it */
597 memmove(rtnl->rqueue + i,rtnl->rqueue + i + 1,
598 sizeof(sd_rtnl_message*) * (rtnl->rqueue_size - i - 1));
601 r = sd_rtnl_message_get_errno(incoming);
603 sd_rtnl_message_unref(incoming);
610 sd_rtnl_message_unref(incoming);
615 /* Try to read more, right away */
619 r = socket_read_message(rtnl);
623 /* receieved message, so try to process straight away */
629 n = now(CLOCK_MONOTONIC);
635 left = (uint64_t) -1;
637 r = rtnl_poll(rtnl, true, left);
641 r = dispatch_wqueue(rtnl);
647 int sd_rtnl_flush(sd_rtnl *rtnl) {
650 assert_return(rtnl, -EINVAL);
651 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
653 if (rtnl->wqueue_size <= 0)
657 r = dispatch_wqueue(rtnl);
661 if (rtnl->wqueue_size <= 0)
664 r = rtnl_poll(rtnl, false, (uint64_t) -1);
670 int sd_rtnl_get_events(sd_rtnl *rtnl) {
673 assert_return(rtnl, -EINVAL);
674 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
676 if (rtnl->rqueue_size <= 0)
678 if (rtnl->wqueue_size > 0)
684 int sd_rtnl_get_timeout(sd_rtnl *rtnl, uint64_t *timeout_usec) {
685 struct reply_callback *c;
687 assert_return(rtnl, -EINVAL);
688 assert_return(timeout_usec, -EINVAL);
689 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
691 if (rtnl->rqueue_size > 0) {
696 c = prioq_peek(rtnl->reply_callbacks_prioq);
698 *timeout_usec = (uint64_t) -1;
702 *timeout_usec = c->timeout;
707 static int io_callback(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
708 sd_rtnl *rtnl = userdata;
713 r = sd_rtnl_process(rtnl, NULL);
720 static int time_callback(sd_event_source *s, uint64_t usec, void *userdata) {
721 sd_rtnl *rtnl = userdata;
726 r = sd_rtnl_process(rtnl, NULL);
733 static int prepare_callback(sd_event_source *s, void *userdata) {
734 sd_rtnl *rtnl = userdata;
741 e = sd_rtnl_get_events(rtnl);
745 r = sd_event_source_set_io_events(rtnl->io_event_source, e);
749 r = sd_rtnl_get_timeout(rtnl, &until);
755 j = sd_event_source_set_time(rtnl->time_event_source, until);
760 r = sd_event_source_set_enabled(rtnl->time_event_source, r > 0);
767 static int exit_callback(sd_event_source *event, void *userdata) {
768 sd_rtnl *rtnl = userdata;
777 int sd_rtnl_attach_event(sd_rtnl *rtnl, sd_event *event, int priority) {
780 assert_return(rtnl, -EINVAL);
781 assert_return(!rtnl->event, -EBUSY);
783 assert(!rtnl->io_event_source);
784 assert(!rtnl->time_event_source);
787 rtnl->event = sd_event_ref(event);
789 r = sd_event_default(&rtnl->event);
794 r = sd_event_add_io(rtnl->event, &rtnl->io_event_source, rtnl->fd, 0, io_callback, rtnl);
798 r = sd_event_source_set_priority(rtnl->io_event_source, priority);
802 r = sd_event_source_set_prepare(rtnl->io_event_source, prepare_callback);
806 r = sd_event_add_time(rtnl->event, &rtnl->time_event_source, CLOCK_MONOTONIC, 0, 0, time_callback, rtnl);
810 r = sd_event_source_set_priority(rtnl->time_event_source, priority);
814 r = sd_event_add_exit(rtnl->event, &rtnl->exit_event_source, exit_callback, rtnl);
821 sd_rtnl_detach_event(rtnl);
825 int sd_rtnl_detach_event(sd_rtnl *rtnl) {
826 assert_return(rtnl, -EINVAL);
827 assert_return(rtnl->event, -ENXIO);
829 if (rtnl->io_event_source)
830 rtnl->io_event_source = sd_event_source_unref(rtnl->io_event_source);
832 if (rtnl->time_event_source)
833 rtnl->time_event_source = sd_event_source_unref(rtnl->time_event_source);
835 if (rtnl->exit_event_source)
836 rtnl->exit_event_source = sd_event_source_unref(rtnl->exit_event_source);
839 rtnl->event = sd_event_unref(rtnl->event);
844 int sd_rtnl_add_match(sd_rtnl *rtnl,
846 sd_rtnl_message_handler_t callback,
848 struct match_callback *c;
850 assert_return(rtnl, -EINVAL);
851 assert_return(callback, -EINVAL);
852 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
853 assert_return(rtnl_message_type_is_link(type) ||
854 rtnl_message_type_is_addr(type) ||
855 rtnl_message_type_is_route(type), -ENOTSUP);
857 c = new0(struct match_callback, 1);
861 c->callback = callback;
863 c->userdata = userdata;
865 LIST_PREPEND(match_callbacks, rtnl->match_callbacks, c);
870 int sd_rtnl_remove_match(sd_rtnl *rtnl,
872 sd_rtnl_message_handler_t callback,
874 struct match_callback *c;
876 assert_return(rtnl, -EINVAL);
877 assert_return(callback, -EINVAL);
878 assert_return(!rtnl_pid_changed(rtnl), -ECHILD);
880 LIST_FOREACH(match_callbacks, c, rtnl->match_callbacks)
881 if (c->callback == callback && c->type == type && c->userdata == userdata) {
882 LIST_REMOVE(match_callbacks, rtnl->match_callbacks, c);