+/* Creates the netdev object of 'type' with 'name'. */
+static int
+netdev_linux_create(const char *name, const char *type,
+ const struct shash *args, bool created)
+{
+ struct netdev_obj_linux *netdev_obj;
+ static const char tap_dev[] = "/dev/net/tun";
+ struct ifreq ifr;
+ int error;
+
+ if (!shash_is_empty(args)) {
+ VLOG_WARN("arguments for %s devices should be empty", type);
+ }
+
+ /* Create the name binding in the netdev library for this object. */
+ netdev_obj = xcalloc(1, sizeof *netdev_obj);
+ netdev_obj_init(&netdev_obj->netdev_obj, name, &netdev_linux_class,
+ created);
+ netdev_obj->tap_fd = -1;
+
+ if (strcmp(type, "tap")) {
+ return 0;
+ }
+
+ /* Open tap device. */
+ netdev_obj->tap_fd = open(tap_dev, O_RDWR);
+ if (netdev_obj->tap_fd < 0) {
+ error = errno;
+ VLOG_WARN("opening \"%s\" failed: %s", tap_dev, strerror(error));
+ goto error;
+ }
+
+ /* Create tap device. */
+ ifr.ifr_flags = IFF_TAP | IFF_NO_PI;
+ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+ if (ioctl(netdev_obj->tap_fd, TUNSETIFF, &ifr) == -1) {
+ VLOG_WARN("%s: creating tap device failed: %s", name,
+ strerror(errno));
+ error = errno;
+ goto error;
+ }
+
+ /* Make non-blocking. */
+ error = set_nonblocking(netdev_obj->tap_fd);
+ if (error) {
+ goto error;
+ }
+
+ return 0;
+
+error:
+ netdev_destroy(name);
+ return error;
+}
+
+/* Destroys the netdev object 'netdev_obj_'. */
+static void
+netdev_linux_destroy(struct netdev_obj *netdev_obj_)
+{
+ struct netdev_obj_linux *netdev_obj = netdev_obj_linux_cast(netdev_obj_);
+
+ if (netdev_obj->tap_fd >= 0) {
+ close(netdev_obj->tap_fd);
+ }
+ free(netdev_obj);
+
+ return;
+}
+