brintos

brintos / linux-shallow public Read only

0
0
Text · 5.9 KiB · 1afc4c4 Raw
242 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#include <linux/etherdevice.h>3#include "ipvlan.h"4#include <linux/if_vlan.h>5#include <linux/if_tap.h>6#include <linux/interrupt.h>7#include <linux/nsproxy.h>8#include <linux/compat.h>9#include <linux/if_tun.h>10#include <linux/module.h>11#include <linux/skbuff.h>12#include <linux/cache.h>13#include <linux/sched.h>14#include <linux/types.h>15#include <linux/slab.h>16#include <linux/wait.h>17#include <linux/cdev.h>18#include <linux/idr.h>19#include <linux/fs.h>20#include <linux/uio.h>21 22#include <net/net_namespace.h>23#include <net/rtnetlink.h>24#include <net/sock.h>25#include <linux/virtio_net.h>26 27#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \28		      NETIF_F_TSO6)29 30static dev_t ipvtap_major;31static struct cdev ipvtap_cdev;32 33static const void *ipvtap_net_namespace(const struct device *d)34{35	const struct net_device *dev = to_net_dev(d->parent);36	return dev_net(dev);37}38 39static struct class ipvtap_class = {40	 .name = "ipvtap",41	 .ns_type = &net_ns_type_operations,42	 .namespace = ipvtap_net_namespace,43};44 45struct ipvtap_dev {46	struct ipvl_dev vlan;47	struct tap_dev	  tap;48};49 50static void ipvtap_count_tx_dropped(struct tap_dev *tap)51{52	struct ipvtap_dev *vlantap = container_of(tap, struct ipvtap_dev, tap);53	struct ipvl_dev *vlan = &vlantap->vlan;54 55	this_cpu_inc(vlan->pcpu_stats->tx_drps);56}57 58static void ipvtap_count_rx_dropped(struct tap_dev *tap)59{60	struct ipvtap_dev *vlantap = container_of(tap, struct ipvtap_dev, tap);61	struct ipvl_dev *vlan = &vlantap->vlan;62 63	ipvlan_count_rx(vlan, 0, 0, 0);64}65 66static void ipvtap_update_features(struct tap_dev *tap,67				   netdev_features_t features)68{69	struct ipvtap_dev *vlantap = container_of(tap, struct ipvtap_dev, tap);70	struct ipvl_dev *vlan = &vlantap->vlan;71 72	vlan->sfeatures = features;73	netdev_update_features(vlan->dev);74}75 76static int ipvtap_newlink(struct net *src_net, struct net_device *dev,77			  struct nlattr *tb[], struct nlattr *data[],78			  struct netlink_ext_ack *extack)79{80	struct ipvtap_dev *vlantap = netdev_priv(dev);81	int err;82 83	INIT_LIST_HEAD(&vlantap->tap.queue_list);84 85	/* Since macvlan supports all offloads by default, make86	 * tap support all offloads also.87	 */88	vlantap->tap.tap_features = TUN_OFFLOADS;89	vlantap->tap.count_tx_dropped = ipvtap_count_tx_dropped;90	vlantap->tap.update_features =	ipvtap_update_features;91	vlantap->tap.count_rx_dropped = ipvtap_count_rx_dropped;92 93	err = netdev_rx_handler_register(dev, tap_handle_frame, &vlantap->tap);94	if (err)95		return err;96 97	/* Don't put anything that may fail after macvlan_common_newlink98	 * because we can't undo what it does.99	 */100	err =  ipvlan_link_new(src_net, dev, tb, data, extack);101	if (err) {102		netdev_rx_handler_unregister(dev);103		return err;104	}105 106	vlantap->tap.dev = vlantap->vlan.dev;107 108	return err;109}110 111static void ipvtap_dellink(struct net_device *dev,112			   struct list_head *head)113{114	struct ipvtap_dev *vlan = netdev_priv(dev);115 116	netdev_rx_handler_unregister(dev);117	tap_del_queues(&vlan->tap);118	ipvlan_link_delete(dev, head);119}120 121static void ipvtap_setup(struct net_device *dev)122{123	ipvlan_link_setup(dev);124	dev->tx_queue_len = TUN_READQ_SIZE;125	dev->priv_flags &= ~IFF_NO_QUEUE;126}127 128static struct rtnl_link_ops ipvtap_link_ops __read_mostly = {129	.kind		= "ipvtap",130	.setup		= ipvtap_setup,131	.newlink	= ipvtap_newlink,132	.dellink	= ipvtap_dellink,133	.priv_size	= sizeof(struct ipvtap_dev),134};135 136static int ipvtap_device_event(struct notifier_block *unused,137			       unsigned long event, void *ptr)138{139	struct net_device *dev = netdev_notifier_info_to_dev(ptr);140	struct ipvtap_dev *vlantap;141	struct device *classdev;142	dev_t devt;143	int err;144	char tap_name[IFNAMSIZ];145 146	if (dev->rtnl_link_ops != &ipvtap_link_ops)147		return NOTIFY_DONE;148 149	snprintf(tap_name, IFNAMSIZ, "tap%d", dev->ifindex);150	vlantap = netdev_priv(dev);151 152	switch (event) {153	case NETDEV_REGISTER:154		/* Create the device node here after the network device has155		 * been registered but before register_netdevice has156		 * finished running.157		 */158		err = tap_get_minor(ipvtap_major, &vlantap->tap);159		if (err)160			return notifier_from_errno(err);161 162		devt = MKDEV(MAJOR(ipvtap_major), vlantap->tap.minor);163		classdev = device_create(&ipvtap_class, &dev->dev, devt,164					 dev, "%s", tap_name);165		if (IS_ERR(classdev)) {166			tap_free_minor(ipvtap_major, &vlantap->tap);167			return notifier_from_errno(PTR_ERR(classdev));168		}169		err = sysfs_create_link(&dev->dev.kobj, &classdev->kobj,170					tap_name);171		if (err)172			return notifier_from_errno(err);173		break;174	case NETDEV_UNREGISTER:175		/* vlan->minor == 0 if NETDEV_REGISTER above failed */176		if (vlantap->tap.minor == 0)177			break;178		sysfs_remove_link(&dev->dev.kobj, tap_name);179		devt = MKDEV(MAJOR(ipvtap_major), vlantap->tap.minor);180		device_destroy(&ipvtap_class, devt);181		tap_free_minor(ipvtap_major, &vlantap->tap);182		break;183	case NETDEV_CHANGE_TX_QUEUE_LEN:184		if (tap_queue_resize(&vlantap->tap))185			return NOTIFY_BAD;186		break;187	}188 189	return NOTIFY_DONE;190}191 192static struct notifier_block ipvtap_notifier_block __read_mostly = {193	.notifier_call	= ipvtap_device_event,194};195 196static int __init ipvtap_init(void)197{198	int err;199 200	err = tap_create_cdev(&ipvtap_cdev, &ipvtap_major, "ipvtap",201			      THIS_MODULE);202	if (err)203		goto out1;204 205	err = class_register(&ipvtap_class);206	if (err)207		goto out2;208 209	err = register_netdevice_notifier(&ipvtap_notifier_block);210	if (err)211		goto out3;212 213	err = ipvlan_link_register(&ipvtap_link_ops);214	if (err)215		goto out4;216 217	return 0;218 219out4:220	unregister_netdevice_notifier(&ipvtap_notifier_block);221out3:222	class_unregister(&ipvtap_class);223out2:224	tap_destroy_cdev(ipvtap_major, &ipvtap_cdev);225out1:226	return err;227}228module_init(ipvtap_init);229 230static void __exit ipvtap_exit(void)231{232	rtnl_link_unregister(&ipvtap_link_ops);233	unregister_netdevice_notifier(&ipvtap_notifier_block);234	class_unregister(&ipvtap_class);235	tap_destroy_cdev(ipvtap_major, &ipvtap_cdev);236}237module_exit(ipvtap_exit);238MODULE_ALIAS_RTNL_LINK("ipvtap");239MODULE_AUTHOR("Sainath Grandhi <sainath.grandhi@intel.com>");240MODULE_DESCRIPTION("IP-VLAN based tap driver");241MODULE_LICENSE("GPL");242