-
-/* Initializes 'notifier' as a netdev notifier for 'netdev', for which
- * notification will consist of calling 'cb', with auxiliary data 'aux'. */
-void
-netdev_notifier_init(struct netdev_notifier *notifier, struct netdev *netdev,
- void (*cb)(struct netdev_notifier *), void *aux)
-{
- notifier->netdev = netdev;
- notifier->cb = cb;
- notifier->aux = aux;
-}
-\f
-/* Tracks changes in the status of a set of network devices. */
-struct netdev_monitor {
- struct shash polled_netdevs;
- struct sset changed_netdevs;
-};
-
-/* Creates and returns a new structure for monitor changes in the status of
- * network devices. */
-struct netdev_monitor *
-netdev_monitor_create(void)
-{
- struct netdev_monitor *monitor = xmalloc(sizeof *monitor);
- shash_init(&monitor->polled_netdevs);
- sset_init(&monitor->changed_netdevs);
- return monitor;
-}
-
-/* Destroys 'monitor'. */
-void
-netdev_monitor_destroy(struct netdev_monitor *monitor)
-{
- if (monitor) {
- struct shash_node *node;
-
- SHASH_FOR_EACH (node, &monitor->polled_netdevs) {
- struct netdev_notifier *notifier = node->data;
- netdev_get_dev(notifier->netdev)->netdev_class->poll_remove(
- notifier);
- }
-
- shash_destroy(&monitor->polled_netdevs);
- sset_destroy(&monitor->changed_netdevs);
- free(monitor);
- }
-}
-
-static void
-netdev_monitor_cb(struct netdev_notifier *notifier)
-{
- struct netdev_monitor *monitor = notifier->aux;
- const char *name = netdev_get_name(notifier->netdev);
- sset_add(&monitor->changed_netdevs, name);
-}
-
-/* Attempts to add 'netdev' as a netdev monitored by 'monitor'. Returns 0 if
- * successful, otherwise a positive errno value.
- *
- * Adding a given 'netdev' to a monitor multiple times is equivalent to adding
- * it once. */
-int
-netdev_monitor_add(struct netdev_monitor *monitor, struct netdev *netdev)
-{
- const char *netdev_name = netdev_get_name(netdev);
- int error = 0;
- if (!shash_find(&monitor->polled_netdevs, netdev_name)
- && netdev_get_dev(netdev)->netdev_class->poll_add)
- {
- struct netdev_notifier *notifier;
- error = netdev_get_dev(netdev)->netdev_class->poll_add(netdev,
- netdev_monitor_cb, monitor, ¬ifier);
- if (!error) {
- assert(notifier->netdev == netdev);
- shash_add(&monitor->polled_netdevs, netdev_name, notifier);
- }
- }
- return error;
-}
-
-/* Removes 'netdev' from the set of netdevs monitored by 'monitor'. (This has
- * no effect if 'netdev' is not in the set of devices monitored by
- * 'monitor'.) */
-void
-netdev_monitor_remove(struct netdev_monitor *monitor, struct netdev *netdev)
-{
- const char *netdev_name = netdev_get_name(netdev);
- struct shash_node *node;
-
- node = shash_find(&monitor->polled_netdevs, netdev_name);
- if (node) {
- /* Cancel future notifications. */
- struct netdev_notifier *notifier = node->data;
- netdev_get_dev(netdev)->netdev_class->poll_remove(notifier);
- shash_delete(&monitor->polled_netdevs, node);
-
- /* Drop any pending notification. */
- sset_find_and_delete(&monitor->changed_netdevs, netdev_name);
- }
-}
-
-/* Checks for changes to netdevs in the set monitored by 'monitor'. If any of
- * the attributes (Ethernet address, carrier status, speed or peer-advertised
- * speed, flags, etc.) of a network device monitored by 'monitor' has changed,
- * sets '*devnamep' to the name of a device that has changed and returns 0.
- * The caller is responsible for freeing '*devnamep' (with free()).
- *
- * If no devices have changed, sets '*devnamep' to NULL and returns EAGAIN. */
-int
-netdev_monitor_poll(struct netdev_monitor *monitor, char **devnamep)
-{
- if (sset_is_empty(&monitor->changed_netdevs)) {
- *devnamep = NULL;
- return EAGAIN;
- } else {
- *devnamep = sset_pop(&monitor->changed_netdevs);
- return 0;
- }
-}
-
-/* Registers with the poll loop to wake up from the next call to poll_block()
- * when netdev_monitor_poll(monitor) would indicate that a device has
- * changed. */
-void
-netdev_monitor_poll_wait(const struct netdev_monitor *monitor)
-{
- if (!sset_is_empty(&monitor->changed_netdevs)) {
- poll_immediate_wake();
- } else {
- /* XXX Nothing needed here for netdev_linux, but maybe other netdev
- * classes need help. */
- }
-}