diff -uprN aa/drivers/net/tun.c bb/drivers/net/tun.c
--- aa/drivers/net/tun.c	2007-11-06 16:18:25.000000000 +0300
+++ bb/drivers/net/tun.c	2007-11-06 16:20:50.000000000 +0300
@@ -69,15 +69,18 @@ static int debug;
 
 /* Network device part of the driver */
 
-static LIST_HEAD(tun_dev_list);
+LIST_HEAD(tun_dev_list);
+EXPORT_SYMBOL(tun_dev_list);
+
 static struct ethtool_ops tun_ethtool_ops;
 
 /* Net device open. */
-static int tun_net_open(struct net_device *dev)
+int tun_net_open(struct net_device *dev)
 {
 	netif_start_queue(dev);
 	return 0;
 }
+EXPORT_SYMBOL(tun_net_open);
 
 /* Net device close. */
 static int tun_net_close(struct net_device *dev)
@@ -196,7 +199,7 @@ static struct net_device_stats *tun_net_
 }
 
 /* Initialize net device. */
-static void tun_net_init(struct net_device *dev)
+void tun_net_init(struct net_device *dev)
 {
 	struct tun_struct *tun = netdev_priv(dev);
    
@@ -223,6 +226,7 @@ static void tun_net_init(struct net_devi
 		break;
 	}
 }
+EXPORT_SYMBOL(tun_net_init);
 
 /* Character device part */
 
@@ -458,7 +462,7 @@ static ssize_t tun_chr_read(struct file 
 	return tun_chr_readv(file, &iv, 1, pos);
 }
 
-static void tun_setup(struct net_device *dev)
+void tun_setup(struct net_device *dev)
 {
 	struct tun_struct *tun = netdev_priv(dev);
 
@@ -476,6 +480,7 @@ static void tun_setup(struct net_device 
 	dev->destructor = free_netdev;
 	dev->features |= NETIF_F_VIRTUAL;
 }
+EXPORT_SYMBOL(tun_setup);
 
 static struct tun_struct *tun_get_by_name(const char *name)
 {
@@ -574,6 +579,7 @@ static int tun_set_iff(struct file *file
 
 	file->private_data = tun;
 	tun->attached = 1;
+	tun->bind_file = file;
 
 	strcpy(ifr->ifr_name, tun->dev->name);
 	return 0;
@@ -754,12 +760,13 @@ static int tun_chr_fasync(int fd, struct
 	return 0;
 }
 
-static int tun_chr_open(struct inode *inode, struct file * file)
+int tun_chr_open(struct inode *inode, struct file * file)
 {
 	DBG1(KERN_INFO "tunX: tun_chr_open\n");
 	file->private_data = NULL;
 	return 0;
 }
+EXPORT_SYMBOL(tun_chr_open);
 
 static int tun_chr_close(struct inode *inode, struct file *file)
 {
diff -uprN aa/include/linux/cpt_image.h bb/include/linux/cpt_image.h
--- aa/include/linux/cpt_image.h	2007-11-06 16:18:45.000000000 +0300
+++ bb/include/linux/cpt_image.h	2007-11-06 16:21:19.000000000 +0300
@@ -84,6 +84,7 @@ enum _cpt_object_type
 	CPT_OBJ_INOTIFY_WATCH,
 	CPT_OBJ_INOTIFY_EVENT,
 	CPT_OBJ_TASK_AUX,
+	CPT_OBJ_NET_TUNTAP,
 };
 
 #define CPT_ALIGN(n) (((n)+7)&~7)
@@ -303,6 +304,7 @@ struct cpt_file_image
 #define CPT_DENTRY_PROC		8
 #define CPT_DENTRY_EPOLL	0x10
 #define CPT_DENTRY_REPLACED	0x20
+#define CPT_DENTRY_TUNTAP	0x100
 	__u64	cpt_inode;
 	__u64	cpt_priv;
 
@@ -1324,6 +1326,23 @@ struct cpt_netdev_image {
 	__u8	cpt_name[16];
 } __attribute__ ((aligned (8)));
 
+struct cpt_tuntap_image {
+	__u64	cpt_next;
+	__u32	cpt_object;
+	__u16	cpt_hdrlen;
+	__u16	cpt_content;
+
+	__u32	cpt_owner;
+	__u32	cpt_attached;
+	__u64	cpt_flags;
+	__u64	cpt_bindfile;
+	__u64	cpt_if_flags;
+	__u8	cpt_dev_addr[6];
+	__u16	cpt_pad;
+	__u32	cpt_chr_filter[2];
+	__u32	cpt_net_filter[2];
+} __attribute__ ((aligned (8)));
+
 struct cpt_ifaddr_image {
 	__u64	cpt_next;
 	__u32	cpt_object;
diff -uprN aa/include/linux/if_tun.h bb/include/linux/if_tun.h
--- aa/include/linux/if_tun.h	2007-11-06 16:18:56.000000000 +0300
+++ bb/include/linux/if_tun.h	2007-11-06 16:21:32.000000000 +0300
@@ -18,6 +18,10 @@
 #ifndef __IF_TUN_H
 #define __IF_TUN_H
 
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/netdevice.h>
+
 /* Uncomment to enable debugging */
 /* #define TUN_DEBUG 1 */
 
@@ -35,6 +39,7 @@ struct tun_struct {
 	struct list_head        list;
 	unsigned long 		flags;
 	int			attached;
+	void			*bind_file;
 	uid_t			owner;
 
 	wait_queue_head_t	read_wait;
@@ -91,4 +96,10 @@ struct tun_pi {
 };
 #define TUN_PKT_STRIP	0x0001
 
+extern int tun_net_open(struct net_device *dev);
+extern int tun_chr_open(struct inode *inode, struct file * file);
+extern void tun_net_init(struct net_device *dev);
+extern void tun_setup(struct net_device *dev);
+extern struct list_head tun_dev_list;
+
 #endif /* __IF_TUN_H */
diff -uprN aa/kernel/cpt/cpt_dump.c bb/kernel/cpt/cpt_dump.c
--- aa/kernel/cpt/cpt_dump.c	2007-11-06 16:19:19.000000000 +0300
+++ bb/kernel/cpt/cpt_dump.c	2007-11-06 16:51:31.000000000 +0300
@@ -19,6 +19,7 @@
 #include <linux/namespace.h>
 #include <linux/netdevice.h>
 #include <linux/nfcalls.h>
+#include <linux/if_tun.h>
 
 #include "cpt_obj.h"
 #include "cpt_context.h"
@@ -788,13 +789,15 @@ int cpt_dump(struct cpt_context *ctx)
 	if (!err)
 		err = cpt_dump_ubc(ctx);
 	if (!err)
-		err = cpt_dump_ifinfo(ctx);
-	if (!err)
 		err = cpt_dump_files(ctx);
 	if (!err)
 		err = cpt_dump_files_struct(ctx);
 	if (!err)
 		err = cpt_dump_fs_struct(ctx);
+	/* netdevices should be dumped after dumping open files
+	   as we need to restore netdevice binding to /dev/net/tun file */
+	if (!err)
+		err = cpt_dump_ifinfo(ctx);
 	if (!err)
 		err = cpt_dump_namespace(ctx);
 	if (!err)
@@ -920,7 +923,11 @@ static void check_unsupported_netdevices
 #if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE)
 		    !(KSYMREF(veth_open) && dev->open == KSYMREF(veth_open)) &&
 #endif
-		    dev != get_exec_env()->_venet_dev) {
+		    dev != get_exec_env()->_venet_dev
+#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
+		    && dev->open != tun_net_open
+#endif
+							) {
 			eprintk_ctx("unsupported netdevice %s\n", dev->name);
 			*caps |= (1<<CPT_UNSUPPORTED_NETDEV);
 		}
diff -uprN aa/kernel/cpt/cpt_files.c bb/kernel/cpt/cpt_files.c
--- aa/kernel/cpt/cpt_files.c	2007-11-06 16:19:58.000000000 +0300
+++ bb/kernel/cpt/cpt_files.c	2007-11-06 16:22:05.000000000 +0300
@@ -19,6 +19,7 @@
 #include <linux/vzcalluser.h>
 #include <ub/ub_mem.h>
 #include <linux/cpt_image.h>
+#include <linux/if_tun.h>
 
 #include "cpt_obj.h"
 #include "cpt_context.h"
@@ -501,6 +502,10 @@ static int dump_one_file(cpt_object_t *o
 			if (file->f_flags&FASYNC)
 				v->cpt_fown_fd = cpt_tty_fasync(file, ctx);
 		}
+#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
+		if (file->f_op && file->f_op->open == tun_chr_open)
+			v->cpt_lflags |= CPT_DENTRY_TUNTAP;
+#endif
 	}
 	if (S_ISSOCK(v->cpt_i_mode)) {
 		if (obj->o_index < 0) {
@@ -709,6 +714,10 @@ static int dump_content_chrdev(struct fi
 	    maj == TTYAUX_MAJOR) {
 		return cpt_dump_content_tty(file, ctx);
 	}
+#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
+	if (file->f_op && file->f_op->open == tun_chr_open)
+		return 0;
+#endif
 	eprintk_ctx("unsupported chrdev %d/%d\n", maj, iminor(ino));
 	return -EINVAL;
 }
diff -uprN aa/kernel/cpt/cpt_net.c bb/kernel/cpt/cpt_net.c
--- aa/kernel/cpt/cpt_net.c	2007-11-06 16:20:03.000000000 +0300
+++ bb/kernel/cpt/cpt_net.c	2007-11-06 16:22:11.000000000 +0300
@@ -17,12 +17,54 @@
 #include <linux/vzcalluser.h>
 #include <linux/cpt_image.h>
 #include <linux/nfcalls.h>
+#include <linux/if_tun.h>
 
 #include "cpt_obj.h"
 #include "cpt_context.h"
 #include "cpt_kernel.h"
 #include "cpt_syscalls.h"
 
+static void cpt_dump_tuntap(struct net_device *dev, struct cpt_context * ctx)
+{
+#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
+	struct cpt_tuntap_image v;
+	struct tun_struct *tun;
+	cpt_object_t *obj;
+
+	if (dev->open != tun_net_open)
+		return;
+
+	tun = netdev_priv(dev);
+	cpt_open_object(NULL, ctx);
+
+	v.cpt_next = CPT_NULL;
+	v.cpt_object = CPT_OBJ_NET_TUNTAP;
+	v.cpt_hdrlen = sizeof(v);
+	v.cpt_content = CPT_CONTENT_VOID;
+
+	v.cpt_owner = tun->owner;
+	v.cpt_flags = tun->flags;
+	v.cpt_attached = tun->attached;
+
+	if (tun->bind_file) {
+		obj = lookup_cpt_object(CPT_OBJ_FILE, tun->bind_file, ctx);
+		BUG_ON(!obj);
+		v.cpt_bindfile = obj->o_pos;
+	}
+
+	v.cpt_if_flags = tun->if_flags;
+	BUG_ON(sizeof(v.cpt_dev_addr) != sizeof(tun->dev_addr));
+	memcpy(v.cpt_dev_addr, tun->dev_addr, sizeof(v.cpt_dev_addr));
+	BUG_ON(sizeof(v.cpt_chr_filter) != sizeof(tun->chr_filter));
+	memcpy(v.cpt_chr_filter, tun->chr_filter, sizeof(v.cpt_chr_filter));
+	BUG_ON(sizeof(v.cpt_net_filter) != sizeof(tun->net_filter));
+	memcpy(v.cpt_net_filter, tun->net_filter, sizeof(v.cpt_net_filter));
+	ctx->write(&v, sizeof(v), ctx);
+	cpt_close_object(ctx);
+#endif
+	return;
+}
+
 int cpt_dump_link(struct cpt_context * ctx)
 {
 	struct net_device *dev;
@@ -30,25 +72,35 @@ int cpt_dump_link(struct cpt_context * c
 	cpt_open_section(ctx, CPT_SECT_NET_DEVICE);
 	for (dev = dev_base; dev; dev = dev->next) {
 		struct cpt_netdev_image v;
+		loff_t saved_obj;
 
 		cpt_open_object(NULL, ctx);
 
 		v.cpt_next = CPT_NULL;
 		v.cpt_object = CPT_OBJ_NET_DEVICE;
 		v.cpt_hdrlen = sizeof(v);
-		v.cpt_content = CPT_CONTENT_VOID;
+		v.cpt_content = CPT_CONTENT_ARRAY;
 
 		v.cpt_index = dev->ifindex;
 		v.cpt_flags = dev->flags;
 		memcpy(v.cpt_name, dev->name, IFNAMSIZ);
 		ctx->write(&v, sizeof(v), ctx);
+
+		cpt_push_object(&saved_obj, ctx);
+		cpt_dump_tuntap(dev, ctx);
+		cpt_pop_object(&saved_obj, ctx);
+
 		cpt_close_object(ctx);
 
 		if (dev != get_exec_env()->_loopback_dev &&
 #if defined(CONFIG_VE_ETHDEV) || defined(CONFIG_VE_ETHDEV_MODULE)
 		    !(KSYMREF(veth_open) && dev->open == KSYMREF(veth_open)) &&
 #endif
-		    dev != get_exec_env()->_venet_dev) {
+		    dev != get_exec_env()->_venet_dev
+#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
+		    && dev->open != tun_net_open
+#endif
+							) {
 			eprintk_ctx("unsupported netdevice %s\n", dev->name);
 			cpt_close_section(ctx);
 			return -EBUSY;
diff -uprN aa/kernel/cpt/rst_files.c bb/kernel/cpt/rst_files.c
--- aa/kernel/cpt/rst_files.c	2007-11-06 16:20:12.000000000 +0300
+++ bb/kernel/cpt/rst_files.c	2007-11-06 16:22:20.000000000 +0300
@@ -225,6 +225,11 @@ static struct file *open_special(struct 
 		return NULL;
 	}
 
+	/* /dev/net/tun will be opened by caller */
+	if (fi->cpt_lflags & CPT_DENTRY_TUNTAP) {
+		kfree(ii);
+		return NULL;
+	}
 	file = rst_open_tty(fi, ii, flags, ctx);
 	kfree(ii);
 	return file;
diff -uprN aa/kernel/cpt/rst_net.c bb/kernel/cpt/rst_net.c
--- aa/kernel/cpt/rst_net.c	2007-11-06 16:20:21.000000000 +0300
+++ bb/kernel/cpt/rst_net.c	2007-11-06 16:22:29.000000000 +0300
@@ -16,11 +16,13 @@
 #include <linux/ve.h>
 #include <net/route.h>
 #include <net/ip_fib.h>
+#include <linux/if_tun.h>
 
 #include "cpt_obj.h"
 #include "cpt_context.h"
 #include "cpt_kernel.h"
 #include "cpt_net.h"
+#include "cpt_files.h"
 
 #include "cpt_syscalls.h"
 
@@ -237,6 +239,72 @@ int rst_resume_network(struct cpt_contex
 	return 0;
 }
 
+/* We do not restore skb queue, just reinit it */
+static int rst_restore_tuntap(loff_t pos, struct cpt_netdev_image *di,
+			struct cpt_context *ctx)
+{
+	int err = -ENODEV;
+#if defined(CONFIG_TUN) || defined(CONFIG_TUN_MODULE)
+	struct cpt_tuntap_image ti;
+	struct net_device *dev;
+	struct file *bind_file = NULL;
+	struct tun_struct *tun;
+
+	pos += di->cpt_hdrlen;
+	err = rst_get_object(CPT_OBJ_NET_TUNTAP, pos, &ti, ctx);
+	if (err)
+		return err;
+
+	rtnl_lock();
+	err = -ENOMEM;
+	dev = alloc_netdev(sizeof(struct tun_struct), di->cpt_name, tun_setup);
+	if (!dev)
+		goto out;
+
+	tun = netdev_priv(dev);
+
+	tun->dev = dev;
+	tun->owner = ti.cpt_owner;
+	tun->flags = ti.cpt_flags;
+	tun->attached = ti.cpt_attached;
+	tun->if_flags = ti.cpt_if_flags;
+	tun_net_init(dev);
+	BUG_ON(sizeof(ti.cpt_dev_addr) != sizeof(tun->dev_addr));
+	memcpy(tun->dev_addr, ti.cpt_dev_addr, sizeof(ti.cpt_dev_addr));
+	BUG_ON(sizeof(ti.cpt_chr_filter) != sizeof(tun->chr_filter));
+	memcpy(tun->chr_filter, ti.cpt_chr_filter, sizeof(ti.cpt_chr_filter));
+	BUG_ON(sizeof(ti.cpt_net_filter) != sizeof(tun->net_filter));
+	memcpy(tun->net_filter, ti.cpt_net_filter, sizeof(ti.cpt_net_filter));
+
+	dev->flags = di->cpt_flags;
+
+	err = register_netdevice(dev);
+	if (err < 0) {
+		free_netdev(dev);
+		eprintk_ctx("failed to register tun/tap net device\n");
+		goto out;
+	}
+	list_add(&tun->list, &tun_dev_list);
+
+	if (ti.cpt_bindfile) {
+		bind_file = rst_file(ti.cpt_bindfile, -1, ctx);
+		if (IS_ERR(bind_file)) {
+			eprintk_ctx("rst_restore_tuntap:"
+				"rst_file: %Ld\n",
+				(unsigned long long)ti.cpt_bindfile);
+			err = PTR_ERR(bind_file);
+			goto out;
+		}
+	}
+	bind_file->private_data = tun;
+	fput(bind_file);
+
+out:
+	rtnl_unlock();
+#endif
+	return err;
+}
+
 int rst_restore_netdev(struct cpt_context *ctx)
 {
 	int err;
@@ -265,6 +333,13 @@ int rst_restore_netdev(struct cpt_contex
 		err = rst_get_object(CPT_OBJ_NET_DEVICE, sec, &di, ctx);
 		if (err)
 			return err;
+
+		if (di.cpt_next > sizeof(di)) {
+			err = rst_restore_tuntap(sec, &di, ctx);
+			if (err)
+				return err;
+		}
+
 		rtnl_lock();
 		dev = __dev_get_by_name(di.cpt_name);
 		if (dev) {
