diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c
index 93271a2632b8..6a4d3d785c65 100644
--- a/net/l2tp/l2tp_core.c
+++ b/net/l2tp/l2tp_core.c
@@ -56,6 +56,7 @@
 #include <net/inet_ecn.h>
 #include <net/ip6_route.h>
 #include <net/ip6_checksum.h>
+#include <net/dst_metadata.h>
 
 #include <asm/byteorder.h>
 #include <linux/atomic.h>
@@ -101,6 +102,10 @@ struct l2tp_skb_cb {
 
 static struct workqueue_struct *l2tp_wq;
 
+struct l2tp_tunl_dev_priv {
+	u32 tunnel_id;
+};
+
 /* per-net private data for this module */
 static unsigned int l2tp_net_id;
 struct l2tp_net {
@@ -1248,6 +1253,27 @@ static void l2tp_tunnel_del_work(struct work_struct *work)
 		}
 	}
 
+	/* If the tunnel has a netdev, release it now.
+	 *
+	 * FIXME: feels like a race condition in the making:
+	 * our alloc_netdev call uses an interface name derived from
+	 * tunnel ID.  Both tunnel ID and interface name must be
+	 * unique, and hence if there's a lag between the tunnel
+	 * removal from the list below and the netdev going away,
+	 * there could be allocation failures.
+	 *
+	 * An alternative scheme might be to let alloc_netdev
+	 * auto-assign the tunnel device name: in this case we would
+	 * need to indicate that name back to userspace using netlink.
+	 *
+	 * Another approach would be to have the netlink tunnel
+	 * create command call out the tunnel device name.
+	 */
+	rtnl_lock();
+	if (tunnel->dev)
+		unregister_netdevice(tunnel->dev);
+	rtnl_unlock();
+
 	/* Remove the tunnel struct from the tunnel list */
 	pn = l2tp_pernet(tunnel->l2tp_net);
 	spin_lock_bh(&pn->l2tp_tunnel_list_lock);
@@ -1452,6 +1478,7 @@ static int l2tp_validate_socket(const struct sock *sk, const struct net *net,
 	return 0;
 }
 
+static struct net_device *l2tp_tunnel_netdev_alloc(struct net *net, u32 tunnel_id);
 int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
 			 struct l2tp_tunnel_cfg *cfg)
 {
@@ -1520,6 +1547,8 @@ int l2tp_tunnel_register(struct l2tp_tunnel *tunnel, struct net *net,
 	if (tunnel->fd >= 0)
 		sockfd_put(sock);
 
+	tunnel->dev = l2tp_tunnel_netdev_alloc(net, tunnel->tunnel_id);
+
 	return 0;
 
 err_sock:
@@ -1632,6 +1661,139 @@ struct l2tp_session *l2tp_session_create(int priv_size, struct l2tp_tunnel *tunn
 }
 EXPORT_SYMBOL_GPL(l2tp_session_create);
 
+/*****************************************************************************
+ * Tunnel virtual netdev
+ *****************************************************************************/
+
+static int l2tp_tunl_dev_init(struct net_device *dev)
+{
+	netdev_lockdep_set_classes(dev);
+	return 0;
+}
+
+static void l2tp_tunl_dev_uninit(struct net_device *dev)
+{
+}
+
+static netdev_tx_t l2tp_tunl_dev_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+	const struct ip_tunnel_info *info;
+	struct l2tp_tunl_dev_priv *priv;
+	struct l2tp_session *session;
+	struct l2tp_tunnel *tunnel;
+	u32 tid, sid;
+
+	info = skb_tunnel_info(skb);
+	if (!info || !(info->mode & IP_TUNNEL_INFO_TX))
+		goto drop;
+
+	priv = netdev_priv(dev);
+	tid = priv->tunnel_id;
+	tunnel = l2tp_tunnel_get(dev_net(dev), tid);
+	if (!tunnel) {
+		pr_err("%s: no tunnel %u in this netns", dev->name, tid);
+		goto drop;
+	}
+
+	sid = be32_to_cpu(tunnel_id_to_key32(info->key.tun_id));
+	session = l2tp_tunnel_get_session(tunnel, sid);
+	if (!session) {
+		pr_err("%s: no session %u in tunnel %u", dev->name, sid, tid);
+		goto drop_unref_tunnel;
+	}
+
+	if (l2tp_xmit_skb(session, skb) != NET_XMIT_SUCCESS)
+		goto drop_unref_tunnel_and_session;
+
+	l2tp_session_dec_refcount(session);
+	l2tp_tunnel_dec_refcount(tunnel);
+
+	return NETDEV_TX_OK;
+
+drop_unref_tunnel_and_session:
+	l2tp_session_dec_refcount(session);
+drop_unref_tunnel:
+	l2tp_tunnel_dec_refcount(tunnel);
+drop:
+	dev_kfree_skb(skb);
+	return NETDEV_TX_OK;
+}
+
+static rx_handler_result_t l2tp_tunl_dev_rx_handler(struct sk_buff **pskb)
+{
+	struct sk_buff *skb = *pskb;
+
+	/* If a packet hasn't been redirected using tc rules we
+	 * don't want it to continue through the network stack,
+	 * so consume it now.
+	 */
+	kfree_skb(skb);
+
+	return RX_HANDLER_CONSUMED;
+}
+
+static const struct net_device_ops l2tp_tunnel_netdev_ops = {
+	.ndo_init		= l2tp_tunl_dev_init,
+	.ndo_uninit		= l2tp_tunl_dev_uninit,
+	.ndo_start_xmit		= l2tp_tunl_dev_xmit,
+};
+
+static struct device_type l2tpvt_type = {
+	.name = "l2tpvt",
+};
+
+static void l2tp_tunnel_netdev_setup(struct net_device *dev)
+{
+	SET_NETDEV_DEVTYPE(dev, &l2tpvt_type);
+	eth_hw_addr_random(dev);
+	ether_setup(dev);
+	eth_hw_addr_random(dev);
+	dev->netdev_ops = &l2tp_tunnel_netdev_ops;
+	dev->features |= NETIF_F_LLTX;
+	dev->min_mtu = ETH_MIN_MTU;
+	dev->max_mtu = ETH_MAX_MTU;
+	dev->priv_flags &= ~IFF_XMIT_DST_RELEASE;
+}
+
+static struct net_device *l2tp_tunnel_netdev_alloc(struct net *net, u32 tunnel_id)
+{
+	struct l2tp_tunl_dev_priv *priv;
+	struct net_device *dev;
+	char name[IFNAMSIZ];
+	int ret;
+
+	snprintf(name, IFNAMSIZ, "l2tpt%d", tunnel_id);
+
+	dev = alloc_netdev(sizeof(*priv), name, NET_NAME_USER, l2tp_tunnel_netdev_setup);
+	dev_net_set(dev, net);
+
+	ret = register_netdev(dev);
+	if (ret < 0) {
+		pr_err("%s: register_netdev said %d\n", __func__, ret);
+		free_netdev(dev);
+		return NULL;
+	}
+
+	/* Add rx handler to prevent packets entering the stack.
+	 * The intention here is to allow packets on the tunnel device to
+	 * be seen by sch_handle_ingress (and hence tc classifiers/actions)
+	 * but prevent them from being passed to protocol code.
+	 */
+	rtnl_lock();
+	ret = netdev_rx_handler_register(dev, l2tp_tunl_dev_rx_handler, NULL);
+	rtnl_unlock();
+	if (ret < 0) {
+		pr_err("%s: netdev_rx_handler_register said %d\n", __func__, ret);
+		free_netdev(dev);
+		return NULL;
+	}
+
+	priv = netdev_priv(dev);
+	priv->tunnel_id = tunnel_id;
+
+	return dev;
+}
+
 /*****************************************************************************
  * Init and cleanup
  *****************************************************************************/
diff --git a/net/l2tp/l2tp_core.h b/net/l2tp/l2tp_core.h
index 98ea98eb9567..4d2aeb852f38 100644
--- a/net/l2tp/l2tp_core.h
+++ b/net/l2tp/l2tp_core.h
@@ -185,6 +185,7 @@ struct l2tp_tunnel {
 						 */
 
 	struct work_struct	del_work;
+	struct net_device	*dev;
 };
 
 /* Pseudowire ops callbacks for use with the l2tp genetlink interface */
