lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1504744467-79590-4-git-send-email-sainath.grandhi@intel.com>
Date:   Wed,  6 Sep 2017 17:34:27 -0700
From:   sainath.grandhi@...el.com
To:     netdev@...r.kernel.org
Cc:     davem@...emloft.net, Sainath Grandhi <sainath.grandhi@...el.com>
Subject: [PATCH RFC v1 3/3] vethtap: veth based tap driver

From: Sainath Grandhi <sainath.grandhi@...el.com>

This patch adds a tap character device driver that is based on the
veth network interface, called vethtap. This patchset allows vethtap device
to be created ONLY as a peer interface to a veth network interface. It can
be created in the following way,
ip link add veth1 type veth peer name veth2 type vethtap
With this packets on veth2 can be accessed using tap user space interface.

Signed-off-by: Sainath Grandhi <sainath.grandhi@...el.com>
---
 drivers/net/Kconfig                 |   1 +
 drivers/net/Makefile                |   2 +
 drivers/net/{veth.c => veth_main.c} |  33 +++++-
 drivers/net/vethtap.c               | 216 ++++++++++++++++++++++++++++++++++++
 include/linux/if_veth.h             |   4 +
 5 files changed, 255 insertions(+), 1 deletion(-)
 rename drivers/net/{veth.c => veth_main.c} (94%)
 create mode 100644 drivers/net/vethtap.c

diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig
index aba0d65..265853e 100644
--- a/drivers/net/Kconfig
+++ b/drivers/net/Kconfig
@@ -323,6 +323,7 @@ config TUN_VNET_CROSS_LE
 
 config VETH
 	tristate "Virtual ethernet pair device"
+	select TAP
 	---help---
 	  This device is a local ethernet tunnel. Devices are created in pairs.
 	  When one end receives the packet it appears on its pair and vice
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
index 8dff900..7c63e69 100644
--- a/drivers/net/Makefile
+++ b/drivers/net/Makefile
@@ -32,6 +32,8 @@ obj-$(CONFIG_NLMON) += nlmon.o
 obj-$(CONFIG_NET_VRF) += vrf.o
 obj-$(CONFIG_VSOCKMON) += vsockmon.o
 
+veth-objs := veth_main.o vethtap.o
+
 #
 # Networking Drivers
 #
diff --git a/drivers/net/veth.c b/drivers/net/veth_main.c
similarity index 94%
rename from drivers/net/veth.c
rename to drivers/net/veth_main.c
index a1b370d..fc91dd7 100644
--- a/drivers/net/veth.c
+++ b/drivers/net/veth_main.c
@@ -359,6 +359,9 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
 	unsigned char name_assign_type;
 	struct ifinfomsg *ifmp;
 	struct net *net;
+	struct nlattr *linkinfo[IFLA_INFO_MAX + 1];
+	char peer_type[8];
+	struct rtnl_link_ops *link_ops;
 
 	/*
 	 * create and register peer first
@@ -393,17 +396,38 @@ static int veth_newlink(struct net *src_net, struct net_device *dev,
 		name_assign_type = NET_NAME_ENUM;
 	}
 
+	link_ops = &veth_link_ops;
+	if (tbp[IFLA_LINKINFO]) {
+		err = rtnl_nla_parse_ifla_info(linkinfo,
+					       nla_data(tbp[IFLA_LINKINFO]),
+					       nla_len(tbp[IFLA_LINKINFO]),
+					       NULL);
+
+		if (err < 0)
+			return err;
+
+		if (linkinfo[IFLA_INFO_KIND]) {
+			nla_strlcpy(peer_type, linkinfo[IFLA_INFO_KIND],
+				    sizeof(peer_type));
+			if (!strncmp(peer_type, "vethtap", sizeof(peer_type)))
+				link_ops = &vethtap_link_ops;
+		}
+	}
+
 	net = rtnl_link_get_net(src_net, tbp);
 	if (IS_ERR(net))
 		return PTR_ERR(net);
 
 	peer = rtnl_create_link(net, ifname, name_assign_type,
-				&veth_link_ops, tbp);
+				link_ops, tbp);
 	if (IS_ERR(peer)) {
 		put_net(net);
 		return PTR_ERR(peer);
 	}
 
+	if (!strncmp(peer_type, "vethtap", sizeof(peer_type)))
+		link_ops->newlink(net, peer, tbp, NULL, NULL);
+
 	if (!ifmp || !tbp[IFLA_ADDRESS])
 		eth_hw_addr_random(peer);
 
@@ -536,12 +560,19 @@ static __init int veth_init(void)
 
 	err = veth_link_register(&veth_link_ops);
 
+	if (err)
+		goto out1;
+
+	err = vethtap_init();
+
+out1:
 	return err;
 }
 
 static __exit void veth_exit(void)
 {
 	rtnl_link_unregister(&veth_link_ops);
+	vethtap_exit();
 }
 
 module_init(veth_init);
diff --git a/drivers/net/vethtap.c b/drivers/net/vethtap.c
new file mode 100644
index 0000000..922b3ea
--- /dev/null
+++ b/drivers/net/vethtap.c
@@ -0,0 +1,216 @@
+#include <linux/etherdevice.h>
+#include <linux/if_tap.h>
+#include <linux/if_vlan.h>
+#include <linux/if_veth.h>
+#include <linux/interrupt.h>
+#include <linux/nsproxy.h>
+#include <linux/compat.h>
+#include <linux/if_tun.h>
+#include <linux/module.h>
+#include <linux/skbuff.h>
+#include <linux/cache.h>
+#include <linux/sched/signal.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/wait.h>
+#include <linux/cdev.h>
+#include <linux/idr.h>
+#include <linux/fs.h>
+#include <linux/uio.h>
+
+#include <net/net_namespace.h>
+#include <net/rtnetlink.h>
+#include <net/sock.h>
+#include <linux/virtio_net.h>
+#include <linux/skb_array.h>
+
+struct vethtap_dev {
+	struct veth_priv  veth;
+	struct tap_dev    tap;
+};
+
+/* Variables for dealing with vethtaps device numbers.
+ */
+static dev_t vethtap_major;
+
+static const void *vethtap_net_namespace(struct device *d)
+{
+	struct net_device *dev = to_net_dev(d->parent);
+
+	return dev_net(dev);
+}
+
+static struct class vethtap_class = {
+	.name = "vethtap",
+	.owner = THIS_MODULE,
+	.ns_type = &net_ns_type_operations,
+	.namespace = vethtap_net_namespace,
+};
+
+static struct cdev vethtap_cdev;
+
+#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
+		      NETIF_F_TSO6)
+
+static void vethtap_count_tx_dropped(struct tap_dev *tap)
+{
+	struct vethtap_dev *vethtap = container_of(tap, struct vethtap_dev,
+						   tap);
+	struct veth_priv *veth = &vethtap->veth;
+
+	atomic64_inc(&veth->dropped);
+}
+
+static int vethtap_newlink(struct net *src_net, struct net_device *dev,
+			   struct nlattr *tb[], struct nlattr *data[],
+			   struct netlink_ext_ack *extack)
+{
+	struct vethtap_dev *vethtap = netdev_priv(dev);
+	int err;
+
+	INIT_LIST_HEAD(&vethtap->tap.queue_list);
+
+	/* Since macvlan supports all offloads by default, make
+	 * tap support all offloads also.
+	 */
+	vethtap->tap.tap_features = TUN_OFFLOADS;
+
+	/* Register callbacks for rx/tx drops accounting and updating
+	 * net_device features
+	 */
+	vethtap->tap.count_tx_dropped = vethtap_count_tx_dropped;
+	vethtap->tap.count_rx_dropped = NULL;
+	vethtap->tap.update_features  = NULL;
+
+	err = netdev_rx_handler_register(dev, tap_handle_frame, &vethtap->tap);
+	if (err)
+		return err;
+
+	vethtap->tap.dev = dev;
+
+	return 0;
+}
+
+static void vethtap_dellink(struct net_device *dev,
+			    struct list_head *head)
+{
+	struct vethtap_dev *vethtap = netdev_priv(dev);
+
+	netdev_rx_handler_unregister(dev);
+	tap_del_queues(&vethtap->tap);
+	veth_dellink(dev, head);
+}
+
+static void vethtap_setup(struct net_device *dev)
+{
+	veth_common_setup(dev);
+	dev->tx_queue_len = TUN_READQ_SIZE;
+}
+
+struct rtnl_link_ops vethtap_link_ops __read_mostly = {
+	.kind           = "vethtap",
+	.setup		= vethtap_setup,
+	.newlink	= vethtap_newlink,
+	.dellink	= vethtap_dellink,
+	.priv_size      = sizeof(struct vethtap_dev),
+};
+
+static int vethtap_device_event(struct notifier_block *unused,
+				unsigned long event, void *ptr)
+{
+	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
+	struct vethtap_dev *vethtap;
+	struct device *classdev;
+	dev_t devt;
+	int err;
+	char tap_name[IFNAMSIZ];
+
+	if (dev->rtnl_link_ops != &vethtap_link_ops)
+		return NOTIFY_DONE;
+
+	snprintf(tap_name, IFNAMSIZ, "tap%d", dev->ifindex);
+	vethtap = netdev_priv(dev);
+
+	switch (event) {
+	case NETDEV_REGISTER:
+		/* Create the device node here after the network device has
+		 * been registered but before register_netdevice has
+		 * finished running.
+		 */
+		err = tap_get_minor(vethtap_major, &vethtap->tap);
+		if (err)
+			return notifier_from_errno(err);
+
+		devt = MKDEV(MAJOR(vethtap_major), vethtap->tap.minor);
+		classdev = device_create(&vethtap_class, &dev->dev, devt,
+					 dev, tap_name);
+		if (IS_ERR(classdev)) {
+			tap_free_minor(vethtap_major, &vethtap->tap);
+			return notifier_from_errno(PTR_ERR(classdev));
+		}
+		err = sysfs_create_link(&dev->dev.kobj, &classdev->kobj,
+					tap_name);
+		if (err)
+			return notifier_from_errno(err);
+		break;
+	case NETDEV_UNREGISTER:
+		/* vlan->minor == 0 if NETDEV_REGISTER above failed */
+		if (vethtap->tap.minor == 0)
+			break;
+		sysfs_remove_link(&dev->dev.kobj, tap_name);
+		devt = MKDEV(MAJOR(vethtap_major), vethtap->tap.minor);
+		device_destroy(&vethtap_class, devt);
+		tap_free_minor(vethtap_major, &vethtap->tap);
+		break;
+	case NETDEV_CHANGE_TX_QUEUE_LEN:
+		if (tap_queue_resize(&vethtap->tap))
+			return NOTIFY_BAD;
+		break;
+	}
+
+	return NOTIFY_DONE;
+}
+
+static struct notifier_block vethtap_notifier_block __read_mostly = {
+	.notifier_call	= vethtap_device_event,
+};
+
+int vethtap_init(void)
+{
+	int err;
+
+	err = tap_create_cdev(&vethtap_cdev, &vethtap_major, "vethtap");
+
+	if (err)
+		goto out1;
+
+	err = class_register(&vethtap_class);
+	if (err)
+		goto out2;
+
+	err = register_netdevice_notifier(&vethtap_notifier_block);
+	if (err)
+		goto out3;
+
+	veth_link_ops_init(&vethtap_link_ops);
+	if (err)
+		goto out4;
+
+	return 0;
+
+out4:
+	unregister_netdevice_notifier(&vethtap_notifier_block);
+out3:
+	class_unregister(&vethtap_class);
+out2:
+	tap_destroy_cdev(vethtap_major, &vethtap_cdev);
+out1:
+	return err;
+}
+
+void vethtap_exit(void)
+{
+	unregister_netdevice_notifier(&vethtap_notifier_block);
+	class_unregister(&vethtap_class);
+	tap_destroy_cdev(vethtap_major, &vethtap_cdev);
+}
diff --git a/include/linux/if_veth.h b/include/linux/if_veth.h
index b007891..dbc06c4 100644
--- a/include/linux/if_veth.h
+++ b/include/linux/if_veth.h
@@ -4,6 +4,10 @@ struct veth_priv {
 	unsigned int            requested_headroom;
 };
 
+extern struct rtnl_link_ops vethtap_link_ops;
+
 void veth_common_setup(struct net_device *dev);
 void veth_dellink(struct net_device *dev, struct list_head *head);
 void veth_link_ops_init(struct rtnl_link_ops *ops);
+int vethtap_init(void);
+void vethtap_exit(void);
-- 
2.7.4

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ