2 * Copyright (c) 2011 Gaetano Catalli.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
7 * 1. Redistributions of source code must retain the above copyright notice,
8 * this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED ``AS IS'' WITHOUT ANY WARRANTIES OF ANY KIND.
21 #include <sys/socket.h>
23 #include <net/route.h>
27 #include "socket-util.h"
28 #include "poll-loop.h"
32 VLOG_DEFINE_THIS_MODULE(rtbsd);
34 /* PF_ROUTE socket. */
35 static int notify_sock = -1;
37 /* All registered notifiers. */
38 static struct list all_notifiers = LIST_INITIALIZER(&all_notifiers);
40 static void rtbsd_report_change(const struct if_msghdr *);
41 static void rtbsd_report_notify_error(void);
43 /* Registers 'cb' to be called with auxiliary data 'aux' with network device
44 * change notifications. The notifier is stored in 'notifier', which the
45 * caller must not modify or free.
47 * Returns 0 if successful, otherwise a positive errno value. */
49 rtbsd_notifier_register(struct rtbsd_notifier *notifier,
50 rtbsd_notify_func *cb, void *aux)
52 if (notify_sock < 0) {
54 notify_sock = socket(PF_ROUTE, SOCK_RAW, 0);
55 if (notify_sock < 0) {
56 VLOG_WARN("could not create PF_ROUTE socket: %s",
60 error = set_nonblocking(notify_sock);
62 VLOG_WARN("error set_nonblocking PF_ROUTE socket: %s",
67 /* Catch up on notification work so that the new notifier won't
68 * receive any stale notifications. XXX*/
72 list_push_back(&all_notifiers, ¬ifier->node);
78 /* Cancels notification on 'notifier', which must have previously been
79 * registered with rtbsd_notifier_register(). */
81 rtbsd_notifier_unregister(struct rtbsd_notifier *notifier)
83 list_remove(¬ifier->node);
84 if (list_is_empty(&all_notifiers)) {
90 /* Calls all of the registered notifiers, passing along any as-yet-unreported
91 * netdev change events. */
93 rtbsd_notifier_run(void)
95 static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
97 if (notify_sock < 0) {
104 msg.ifm_type = RTM_IFINFO;
105 msg.ifm_version = RTM_VERSION; //XXX check if necessary
107 /* read from PF_ROUTE socket */
108 retval = read(notify_sock, (char *)&msg, sizeof(msg));
110 /* received packet from PF_ROUTE socket
111 * XXX check for bad packets */
112 if (msg.ifm_type == RTM_IFINFO) {
113 rtbsd_report_change(&msg);
115 } else if (errno == EAGAIN) {
118 if (errno == ENOBUFS) {
119 VLOG_WARN_RL(&rl, "PF_ROUTE receive buffer overflowed");
121 VLOG_WARN_RL(&rl, "error reading PF_ROUTE socket: %s",
124 rtbsd_report_notify_error();
129 /* Causes poll_block() to wake up when network device change notifications are
132 rtbsd_notifier_wait(void)
134 if (notify_sock >= 0) {
135 poll_fd_wait(notify_sock, POLLIN);
140 rtbsd_report_change(const struct if_msghdr *msg)
142 struct rtbsd_notifier *notifier;
143 struct rtbsd_change change;
145 /*COVERAGE_INC(rtbsd_changed);*/ /* XXX update coverage-counters.c */
147 change.msg_type = msg->ifm_type; //XXX
148 change.if_index = msg->ifm_index;
149 if_indextoname(msg->ifm_index, change.if_name);
150 change.master_ifindex = 0; //XXX
152 LIST_FOR_EACH (notifier, node, &all_notifiers) {
153 notifier->cb(&change, notifier->aux);
157 /* If an error occurs the notifiers' callbacks are called with NULL changes */
159 rtbsd_report_notify_error(void)
161 struct rtbsd_notifier *notifier;
163 LIST_FOR_EACH (notifier, node, &all_notifiers) {
164 notifier->cb(NULL, notifier->aux);