+ static unsigned int n = 0;
+ struct netdev_tunnel *netdev;
+ int error;
+
+ netdev = xzalloc(sizeof *netdev);
+ netdev_init(&netdev->up, name, class);
+ 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) {
+ error = netdev->sockfd;
+ goto error;
+ }
+
+
+ shash_add(&tunnel_netdevs, name, netdev);
+
+ n++;
+
+ *netdevp = &netdev->up;
+
+ VLOG_DBG("tunnel_create: name=%s, fd=%d, port=%d", name, netdev->sockfd, netdev->local_addr.sin_port);
+
+ return 0;
+
+error:
+ free(netdev);
+ return error;
+}
+
+static void
+netdev_tunnel_destroy(struct netdev *netdev_)
+{
+ struct netdev_tunnel *netdev = netdev_tunnel_cast(netdev_);
+
+ if (netdev->sockfd != -1)
+ close(netdev->sockfd);
+
+ shash_find_and_delete(&tunnel_netdevs,
+ netdev_get_name(netdev_));
+ free(netdev);
+}
+
+static int
+netdev_tunnel_get_config(const struct netdev *dev_, struct smap *args)
+{
+ struct netdev_tunnel *netdev = netdev_tunnel_cast(dev_);
+
+ 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));
+ return 0;
+}
+
+static int
+netdev_tunnel_connect(struct netdev_tunnel *dev)
+{
+ char buf[1024];
+ if (dev->sockfd < 0)
+ return EBADF;
+ if (!dev->valid_remote_ip || !dev->valid_remote_port)
+ return 0;
+ dev->remote_addr.sin_family = AF_INET;
+ if (connect(dev->sockfd, (struct sockaddr*) &dev->remote_addr, sizeof(dev->remote_addr)) < 0) {
+ return errno;
+ }
+ dev->connected = true;
+ netdev_tunnel_update_seq(dev);
+ VLOG_DBG("%s: connected to (%s, %d)", netdev_get_name(&dev->up),
+ inet_ntop(AF_INET, &dev->remote_addr.sin_addr, buf, 1024), ntohs(dev->remote_addr.sin_port));
+ return 0;
+}
+
+static int
+netdev_tunnel_set_config(struct netdev *dev_, const struct smap *args)
+{
+ struct netdev_tunnel *netdev = netdev_tunnel_cast(dev_);