return get_etheraddr(netdev_name, mac, NULL);
}
\f
-struct netdev_monitor {
- struct nl_sock *sock;
- struct svec netdevs;
- struct svec changed;
-};
-
-static const char *lookup_netdev(const struct netdev_monitor *, const char *);
-static const char *pop_changed(struct netdev_monitor *);
-static const char *all_netdevs_changed(struct netdev_monitor *);
-
-/* Creates a new network device monitor that initially monitors no
- * devices. On success, sets '*monp' to the new network monitor and returns
- * 0; on failure, sets '*monp' to a null pointer and returns a positive errno
- * value. */
-int
-netdev_monitor_create(struct netdev_monitor **monp)
-{
- struct netdev_monitor *mon;
- struct nl_sock *sock;
- int error;
-
- *monp = NULL;
- error = nl_sock_create(NETLINK_ROUTE, RTNLGRP_LINK, 0, 0, &sock);
- if (error) {
- /* XXX Fall back to polling? Non-root is not allowed to subscribe to
- * multicast groups but can still poll network device state. */
- VLOG_WARN("could not create rtnetlink socket: %s", strerror(error));
- return error;
- }
-
- mon = *monp = xmalloc(sizeof *mon);
- mon->sock = sock;
- svec_init(&mon->netdevs);
- svec_init(&mon->changed);
- return 0;
-}
-
-void
-netdev_monitor_destroy(struct netdev_monitor *mon)
-{
- if (mon) {
- nl_sock_destroy(mon->sock);
- svec_destroy(&mon->netdevs);
- svec_destroy(&mon->changed);
- free(mon);
- }
-}
-
-/* Sets the set of network devices monitored by 'mon' to the 'n_netdevs'
- * network devices named in 'netdevs'. The caller retains ownership of
- * 'netdevs'. */
-void
-netdev_monitor_set_devices(struct netdev_monitor *mon,
- char **netdevs, size_t n_netdevs)
-{
- size_t i;
-
- svec_clear(&mon->netdevs);
- for (i = 0; i < n_netdevs; i++) {
- svec_add(&mon->netdevs, netdevs[i]);
- }
- svec_sort(&mon->netdevs);
-}
-
-/* If the state of any network device has changed, returns its name. The
- * caller must not modify or free the name.
- *
- * This function can return "false positives". The caller is responsible for
- * verifying that the network device's state actually changed, if necessary.
- *
- * If no network device's state has changed, returns a null pointer. */
-const char *
-netdev_monitor_poll(struct netdev_monitor *mon)
-{
- static struct vlog_rate_limit slow_rl = VLOG_RATE_LIMIT_INIT(1, 5);
- const char *changed_name;
-
- changed_name = pop_changed(mon);
- if (changed_name) {
- return changed_name;
- }
-
- for (;;) {
- struct ofpbuf *buf;
- int retval;
-
- retval = nl_sock_recv(mon->sock, &buf, false);
- if (retval == EAGAIN) {
- return NULL;
- } else if (retval == ENOBUFS) {
- VLOG_WARN_RL(&slow_rl, "network monitor socket overflowed");
- return all_netdevs_changed(mon);
- } else if (retval) {
- VLOG_WARN_RL(&slow_rl, "error on network monitor socket: %s",
- strerror(retval));
- return NULL;
- } else {
- struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)];
- const char *name;
-
- if (!nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
- rtnlgrp_link_policy,
- attrs, ARRAY_SIZE(rtnlgrp_link_policy))) {
- VLOG_WARN_RL(&slow_rl, "received bad rtnl message");
- return all_netdevs_changed(mon);
- }
- name = lookup_netdev(mon, nl_attr_get_string(attrs[IFLA_IFNAME]));
- ofpbuf_delete(buf);
- if (name) {
- /* Return the looked-up string instead of the attribute string,
- * because we freed the buffer that contains the attribute. */
- return name;
- }
- }
- }
-}
-
-void
-netdev_monitor_run(struct netdev_monitor *mon UNUSED)
-{
- /* Nothing to do in this implementation. */
-}
-
-void
-netdev_monitor_wait(struct netdev_monitor *mon)
-{
- nl_sock_wait(mon->sock, POLLIN);
-}
-
-static const char *
-lookup_netdev(const struct netdev_monitor *mon, const char *name)
-{
- size_t idx = svec_find(&mon->netdevs, name);
- return idx != SIZE_MAX ? mon->netdevs.names[idx] : NULL;
-}
-
-static const char *
-pop_changed(struct netdev_monitor *mon)
-{
- while (mon->changed.n) {
- const char *name = lookup_netdev(mon, svec_back(&mon->changed));
- svec_pop_back(&mon->changed);
- if (name) {
- return name;
- }
- }
- return NULL;
-}
-
-static const char *
-all_netdevs_changed(struct netdev_monitor *mon)
-{
- svec_clear(&mon->changed);
- svec_append(&mon->changed, &mon->netdevs);
- return pop_changed(mon);
-}
-\f
static void restore_all_flags(void *aux);
/* Set up a signal hook to restore network device flags on program