cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

macvtap.c (6425B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2#include <linux/etherdevice.h>
      3#include <linux/if_macvlan.h>
      4#include <linux/if_tap.h>
      5#include <linux/if_vlan.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/signal.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#include <linux/skb_array.h>
     27
     28struct macvtap_dev {
     29	struct macvlan_dev vlan;
     30	struct tap_dev    tap;
     31};
     32
     33/*
     34 * Variables for dealing with macvtaps device numbers.
     35 */
     36static dev_t macvtap_major;
     37
     38static const void *macvtap_net_namespace(struct device *d)
     39{
     40	struct net_device *dev = to_net_dev(d->parent);
     41	return dev_net(dev);
     42}
     43
     44static struct class macvtap_class = {
     45	.name = "macvtap",
     46	.owner = THIS_MODULE,
     47	.ns_type = &net_ns_type_operations,
     48	.namespace = macvtap_net_namespace,
     49};
     50static struct cdev macvtap_cdev;
     51
     52#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
     53		      NETIF_F_TSO6)
     54
     55static void macvtap_count_tx_dropped(struct tap_dev *tap)
     56{
     57	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
     58	struct macvlan_dev *vlan = &vlantap->vlan;
     59
     60	this_cpu_inc(vlan->pcpu_stats->tx_dropped);
     61}
     62
     63static void macvtap_count_rx_dropped(struct tap_dev *tap)
     64{
     65	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
     66	struct macvlan_dev *vlan = &vlantap->vlan;
     67
     68	macvlan_count_rx(vlan, 0, 0, 0);
     69}
     70
     71static void macvtap_update_features(struct tap_dev *tap,
     72				    netdev_features_t features)
     73{
     74	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
     75	struct macvlan_dev *vlan = &vlantap->vlan;
     76
     77	vlan->set_features = features;
     78	netdev_update_features(vlan->dev);
     79}
     80
     81static int macvtap_newlink(struct net *src_net, struct net_device *dev,
     82			   struct nlattr *tb[], struct nlattr *data[],
     83			   struct netlink_ext_ack *extack)
     84{
     85	struct macvtap_dev *vlantap = netdev_priv(dev);
     86	int err;
     87
     88	INIT_LIST_HEAD(&vlantap->tap.queue_list);
     89
     90	/* Since macvlan supports all offloads by default, make
     91	 * tap support all offloads also.
     92	 */
     93	vlantap->tap.tap_features = TUN_OFFLOADS;
     94
     95	/* Register callbacks for rx/tx drops accounting and updating
     96	 * net_device features
     97	 */
     98	vlantap->tap.count_tx_dropped = macvtap_count_tx_dropped;
     99	vlantap->tap.count_rx_dropped = macvtap_count_rx_dropped;
    100	vlantap->tap.update_features  = macvtap_update_features;
    101
    102	err = netdev_rx_handler_register(dev, tap_handle_frame, &vlantap->tap);
    103	if (err)
    104		return err;
    105
    106	/* Don't put anything that may fail after macvlan_common_newlink
    107	 * because we can't undo what it does.
    108	 */
    109	err = macvlan_common_newlink(src_net, dev, tb, data, extack);
    110	if (err) {
    111		netdev_rx_handler_unregister(dev);
    112		return err;
    113	}
    114
    115	vlantap->tap.dev = vlantap->vlan.dev;
    116
    117	return 0;
    118}
    119
    120static void macvtap_dellink(struct net_device *dev,
    121			    struct list_head *head)
    122{
    123	struct macvtap_dev *vlantap = netdev_priv(dev);
    124
    125	netdev_rx_handler_unregister(dev);
    126	tap_del_queues(&vlantap->tap);
    127	macvlan_dellink(dev, head);
    128}
    129
    130static void macvtap_setup(struct net_device *dev)
    131{
    132	macvlan_common_setup(dev);
    133	dev->tx_queue_len = TUN_READQ_SIZE;
    134}
    135
    136static struct net *macvtap_link_net(const struct net_device *dev)
    137{
    138	return dev_net(macvlan_dev_real_dev(dev));
    139}
    140
    141static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
    142	.kind		= "macvtap",
    143	.setup		= macvtap_setup,
    144	.newlink	= macvtap_newlink,
    145	.dellink	= macvtap_dellink,
    146	.get_link_net	= macvtap_link_net,
    147	.priv_size      = sizeof(struct macvtap_dev),
    148};
    149
    150static int macvtap_device_event(struct notifier_block *unused,
    151				unsigned long event, void *ptr)
    152{
    153	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
    154	struct macvtap_dev *vlantap;
    155	struct device *classdev;
    156	dev_t devt;
    157	int err;
    158	char tap_name[IFNAMSIZ];
    159
    160	if (dev->rtnl_link_ops != &macvtap_link_ops)
    161		return NOTIFY_DONE;
    162
    163	snprintf(tap_name, IFNAMSIZ, "tap%d", dev->ifindex);
    164	vlantap = netdev_priv(dev);
    165
    166	switch (event) {
    167	case NETDEV_REGISTER:
    168		/* Create the device node here after the network device has
    169		 * been registered but before register_netdevice has
    170		 * finished running.
    171		 */
    172		err = tap_get_minor(macvtap_major, &vlantap->tap);
    173		if (err)
    174			return notifier_from_errno(err);
    175
    176		devt = MKDEV(MAJOR(macvtap_major), vlantap->tap.minor);
    177		classdev = device_create(&macvtap_class, &dev->dev, devt,
    178					 dev, "%s", tap_name);
    179		if (IS_ERR(classdev)) {
    180			tap_free_minor(macvtap_major, &vlantap->tap);
    181			return notifier_from_errno(PTR_ERR(classdev));
    182		}
    183		err = sysfs_create_link(&dev->dev.kobj, &classdev->kobj,
    184					tap_name);
    185		if (err)
    186			return notifier_from_errno(err);
    187		break;
    188	case NETDEV_UNREGISTER:
    189		/* vlan->minor == 0 if NETDEV_REGISTER above failed */
    190		if (vlantap->tap.minor == 0)
    191			break;
    192		sysfs_remove_link(&dev->dev.kobj, tap_name);
    193		devt = MKDEV(MAJOR(macvtap_major), vlantap->tap.minor);
    194		device_destroy(&macvtap_class, devt);
    195		tap_free_minor(macvtap_major, &vlantap->tap);
    196		break;
    197	case NETDEV_CHANGE_TX_QUEUE_LEN:
    198		if (tap_queue_resize(&vlantap->tap))
    199			return NOTIFY_BAD;
    200		break;
    201	}
    202
    203	return NOTIFY_DONE;
    204}
    205
    206static struct notifier_block macvtap_notifier_block __read_mostly = {
    207	.notifier_call	= macvtap_device_event,
    208};
    209
    210static int macvtap_init(void)
    211{
    212	int err;
    213
    214	err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap",
    215			      THIS_MODULE);
    216	if (err)
    217		goto out1;
    218
    219	err = class_register(&macvtap_class);
    220	if (err)
    221		goto out2;
    222
    223	err = register_netdevice_notifier(&macvtap_notifier_block);
    224	if (err)
    225		goto out3;
    226
    227	err = macvlan_link_register(&macvtap_link_ops);
    228	if (err)
    229		goto out4;
    230
    231	return 0;
    232
    233out4:
    234	unregister_netdevice_notifier(&macvtap_notifier_block);
    235out3:
    236	class_unregister(&macvtap_class);
    237out2:
    238	tap_destroy_cdev(macvtap_major, &macvtap_cdev);
    239out1:
    240	return err;
    241}
    242module_init(macvtap_init);
    243
    244static void macvtap_exit(void)
    245{
    246	rtnl_link_unregister(&macvtap_link_ops);
    247	unregister_netdevice_notifier(&macvtap_notifier_block);
    248	class_unregister(&macvtap_class);
    249	tap_destroy_cdev(macvtap_major, &macvtap_cdev);
    250}
    251module_exit(macvtap_exit);
    252
    253MODULE_ALIAS_RTNL_LINK("macvtap");
    254MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
    255MODULE_LICENSE("GPL");