+
+ do {
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
+ uint64_t buf_stub[4096 / 8];
+ struct ofpbuf buf;
+
+ ofpbuf_use_stub(&buf, buf_stub, sizeof buf_stub);
+ error = nl_sock_recv(sock, &buf, false);
+ if (!error) {
+ struct rtnetlink_link_change change;
+
+ if (rtnetlink_link_parse(&buf, &change)) {
+ struct netdev *netdev_ = netdev_from_name(change.ifname);
+ if (netdev_ && is_netdev_linux_class(netdev_->netdev_class)) {
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+
+ ovs_mutex_lock(&netdev->mutex);
+ netdev_linux_update(netdev, &change);
+ ovs_mutex_unlock(&netdev->mutex);
+ }
+ netdev_close(netdev_);
+ }
+ } else if (error == ENOBUFS) {
+ struct shash device_shash;
+ struct shash_node *node;
+
+ nl_sock_drain(sock);
+
+ shash_init(&device_shash);
+ netdev_get_devices(&netdev_linux_class, &device_shash);
+ SHASH_FOR_EACH (node, &device_shash) {
+ struct netdev *netdev_ = node->data;
+ struct netdev_linux *netdev = netdev_linux_cast(netdev_);
+ unsigned int flags;
+
+ ovs_mutex_lock(&netdev->mutex);
+ get_flags(netdev_, &flags);
+ netdev_linux_changed(netdev, flags, 0);
+ ovs_mutex_unlock(&netdev->mutex);
+
+ netdev_close(netdev_);
+ }
+ shash_destroy(&device_shash);
+ } else if (error != EAGAIN) {
+ VLOG_WARN_RL(&rl, "error reading or parsing netlink (%s)",
+ ovs_strerror(error));
+ }
+ ofpbuf_uninit(&buf);
+ } while (!error);