+ ovs_assert(is_netdev_tunnel_class(netdev_get_class(netdev)));
+ return CONTAINER_OF(netdev, struct netdev_tunnel, up);
+}
+
+static struct netdev_rx_tunnel *
+netdev_rx_tunnel_cast(const struct netdev_rx *rx)
+{
+ ovs_assert(is_netdev_tunnel_class(netdev_get_class(rx->netdev)));
+ return CONTAINER_OF(rx, struct netdev_rx_tunnel, up);
+}
+
+static struct netdev *
+netdev_tunnel_alloc(void)
+{
+ struct netdev_tunnel *netdev = xzalloc(sizeof *netdev);
+ return &netdev->up;
+}
+
+static int
+netdev_tunnel_construct(struct netdev *netdev_)
+{
+ static atomic_uint next_n = ATOMIC_VAR_INIT(0);
+ struct netdev_tunnel *netdev = netdev_tunnel_cast(netdev_);
+ unsigned int n;
+
+ atomic_add(&next_n, 1, &n);
+
+ ovs_mutex_init(&netdev->mutex, PTHREAD_MUTEX_NORMAL);
+ netdev->hwaddr[0] = 0xfe;
+ netdev->hwaddr[1] = 0xff;
+ netdev->hwaddr[2] = 0xff;
+ netdev->hwaddr[3] = n >> 16;
+ netdev->hwaddr[4] = n >> 8;
+ netdev->hwaddr[5] = n;
+ netdev->flags = 0;
+ netdev->change_seq = 1;
+ memset(&netdev->remote_addr, 0, sizeof(netdev->remote_addr));
+ netdev->valid_remote_ip = false;
+ netdev->valid_remote_port = false;
+ netdev->connected = false;
+
+
+ netdev->sockfd = inet_open_passive(SOCK_DGRAM, "", 0, &netdev->local_addr, 0);
+ if (netdev->sockfd < 0) {
+ return netdev->sockfd;
+ }
+
+
+ shash_add(&tunnel_netdevs, netdev_get_name(netdev_), netdev);
+
+ n++;
+
+ VLOG_DBG("tunnel_create: name=%s, fd=%d, port=%d",
+ netdev_get_name(netdev_), netdev->sockfd, netdev->local_addr.sin_port);
+
+ return 0;
+
+}
+
+static void
+netdev_tunnel_destruct(struct netdev *netdev_)
+{
+ struct netdev_tunnel *netdev = netdev_tunnel_cast(netdev_);
+
+ ovs_mutex_lock(&tunnel_netdevs_mutex);
+
+ if (netdev->sockfd != -1)
+ close(netdev->sockfd);
+
+ shash_find_and_delete(&tunnel_netdevs,
+ netdev_get_name(netdev_));
+
+ ovs_mutex_destroy(&netdev->mutex);
+ ovs_mutex_unlock(&tunnel_netdevs_mutex);
+}
+
+static void
+netdev_tunnel_dealloc(struct netdev *netdev_)
+{
+ struct netdev_tunnel *netdev = netdev_tunnel_cast(netdev_);
+ free(netdev);
+}
+
+static int
+netdev_tunnel_get_config(const struct netdev *dev_, struct smap *args)
+{
+ struct netdev_tunnel *netdev = netdev_tunnel_cast(dev_);
+
+ ovs_mutex_lock(&netdev->mutex);
+ if (netdev->valid_remote_ip)
+ smap_add_format(args, "remote_ip", IP_FMT,
+ IP_ARGS(netdev->remote_addr.sin_addr.s_addr));
+ if (netdev->valid_remote_port)
+ smap_add_format(args, "remote_port", "%"PRIu16,
+ ntohs(netdev->remote_addr.sin_port));
+ ovs_mutex_unlock(&netdev->mutex);
+ return 0;