162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci#include <linux/etherdevice.h>
362306a36Sopenharmony_ci#include <linux/if_macvlan.h>
462306a36Sopenharmony_ci#include <linux/if_tap.h>
562306a36Sopenharmony_ci#include <linux/if_vlan.h>
662306a36Sopenharmony_ci#include <linux/interrupt.h>
762306a36Sopenharmony_ci#include <linux/nsproxy.h>
862306a36Sopenharmony_ci#include <linux/compat.h>
962306a36Sopenharmony_ci#include <linux/if_tun.h>
1062306a36Sopenharmony_ci#include <linux/module.h>
1162306a36Sopenharmony_ci#include <linux/skbuff.h>
1262306a36Sopenharmony_ci#include <linux/cache.h>
1362306a36Sopenharmony_ci#include <linux/sched/signal.h>
1462306a36Sopenharmony_ci#include <linux/types.h>
1562306a36Sopenharmony_ci#include <linux/slab.h>
1662306a36Sopenharmony_ci#include <linux/wait.h>
1762306a36Sopenharmony_ci#include <linux/cdev.h>
1862306a36Sopenharmony_ci#include <linux/idr.h>
1962306a36Sopenharmony_ci#include <linux/fs.h>
2062306a36Sopenharmony_ci#include <linux/uio.h>
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#include <net/net_namespace.h>
2362306a36Sopenharmony_ci#include <net/rtnetlink.h>
2462306a36Sopenharmony_ci#include <net/sock.h>
2562306a36Sopenharmony_ci#include <linux/virtio_net.h>
2662306a36Sopenharmony_ci#include <linux/skb_array.h>
2762306a36Sopenharmony_ci
2862306a36Sopenharmony_cistruct macvtap_dev {
2962306a36Sopenharmony_ci	struct macvlan_dev vlan;
3062306a36Sopenharmony_ci	struct tap_dev    tap;
3162306a36Sopenharmony_ci};
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci/*
3462306a36Sopenharmony_ci * Variables for dealing with macvtaps device numbers.
3562306a36Sopenharmony_ci */
3662306a36Sopenharmony_cistatic dev_t macvtap_major;
3762306a36Sopenharmony_ci
3862306a36Sopenharmony_cistatic const void *macvtap_net_namespace(const struct device *d)
3962306a36Sopenharmony_ci{
4062306a36Sopenharmony_ci	const struct net_device *dev = to_net_dev(d->parent);
4162306a36Sopenharmony_ci	return dev_net(dev);
4262306a36Sopenharmony_ci}
4362306a36Sopenharmony_ci
4462306a36Sopenharmony_cistatic struct class macvtap_class = {
4562306a36Sopenharmony_ci	.name = "macvtap",
4662306a36Sopenharmony_ci	.ns_type = &net_ns_type_operations,
4762306a36Sopenharmony_ci	.namespace = macvtap_net_namespace,
4862306a36Sopenharmony_ci};
4962306a36Sopenharmony_cistatic struct cdev macvtap_cdev;
5062306a36Sopenharmony_ci
5162306a36Sopenharmony_ci#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
5262306a36Sopenharmony_ci		      NETIF_F_TSO6)
5362306a36Sopenharmony_ci
5462306a36Sopenharmony_cistatic void macvtap_count_tx_dropped(struct tap_dev *tap)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
5762306a36Sopenharmony_ci	struct macvlan_dev *vlan = &vlantap->vlan;
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	this_cpu_inc(vlan->pcpu_stats->tx_dropped);
6062306a36Sopenharmony_ci}
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_cistatic void macvtap_count_rx_dropped(struct tap_dev *tap)
6362306a36Sopenharmony_ci{
6462306a36Sopenharmony_ci	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
6562306a36Sopenharmony_ci	struct macvlan_dev *vlan = &vlantap->vlan;
6662306a36Sopenharmony_ci
6762306a36Sopenharmony_ci	macvlan_count_rx(vlan, 0, 0, 0);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic void macvtap_update_features(struct tap_dev *tap,
7162306a36Sopenharmony_ci				    netdev_features_t features)
7262306a36Sopenharmony_ci{
7362306a36Sopenharmony_ci	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
7462306a36Sopenharmony_ci	struct macvlan_dev *vlan = &vlantap->vlan;
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci	vlan->set_features = features;
7762306a36Sopenharmony_ci	netdev_update_features(vlan->dev);
7862306a36Sopenharmony_ci}
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_cistatic int macvtap_newlink(struct net *src_net, struct net_device *dev,
8162306a36Sopenharmony_ci			   struct nlattr *tb[], struct nlattr *data[],
8262306a36Sopenharmony_ci			   struct netlink_ext_ack *extack)
8362306a36Sopenharmony_ci{
8462306a36Sopenharmony_ci	struct macvtap_dev *vlantap = netdev_priv(dev);
8562306a36Sopenharmony_ci	int err;
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ci	INIT_LIST_HEAD(&vlantap->tap.queue_list);
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci	/* Since macvlan supports all offloads by default, make
9062306a36Sopenharmony_ci	 * tap support all offloads also.
9162306a36Sopenharmony_ci	 */
9262306a36Sopenharmony_ci	vlantap->tap.tap_features = TUN_OFFLOADS;
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	/* Register callbacks for rx/tx drops accounting and updating
9562306a36Sopenharmony_ci	 * net_device features
9662306a36Sopenharmony_ci	 */
9762306a36Sopenharmony_ci	vlantap->tap.count_tx_dropped = macvtap_count_tx_dropped;
9862306a36Sopenharmony_ci	vlantap->tap.count_rx_dropped = macvtap_count_rx_dropped;
9962306a36Sopenharmony_ci	vlantap->tap.update_features  = macvtap_update_features;
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci	err = netdev_rx_handler_register(dev, tap_handle_frame, &vlantap->tap);
10262306a36Sopenharmony_ci	if (err)
10362306a36Sopenharmony_ci		return err;
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci	/* Don't put anything that may fail after macvlan_common_newlink
10662306a36Sopenharmony_ci	 * because we can't undo what it does.
10762306a36Sopenharmony_ci	 */
10862306a36Sopenharmony_ci	err = macvlan_common_newlink(src_net, dev, tb, data, extack);
10962306a36Sopenharmony_ci	if (err) {
11062306a36Sopenharmony_ci		netdev_rx_handler_unregister(dev);
11162306a36Sopenharmony_ci		return err;
11262306a36Sopenharmony_ci	}
11362306a36Sopenharmony_ci
11462306a36Sopenharmony_ci	vlantap->tap.dev = vlantap->vlan.dev;
11562306a36Sopenharmony_ci
11662306a36Sopenharmony_ci	return 0;
11762306a36Sopenharmony_ci}
11862306a36Sopenharmony_ci
11962306a36Sopenharmony_cistatic void macvtap_dellink(struct net_device *dev,
12062306a36Sopenharmony_ci			    struct list_head *head)
12162306a36Sopenharmony_ci{
12262306a36Sopenharmony_ci	struct macvtap_dev *vlantap = netdev_priv(dev);
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_ci	netdev_rx_handler_unregister(dev);
12562306a36Sopenharmony_ci	tap_del_queues(&vlantap->tap);
12662306a36Sopenharmony_ci	macvlan_dellink(dev, head);
12762306a36Sopenharmony_ci}
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_cistatic void macvtap_setup(struct net_device *dev)
13062306a36Sopenharmony_ci{
13162306a36Sopenharmony_ci	macvlan_common_setup(dev);
13262306a36Sopenharmony_ci	dev->tx_queue_len = TUN_READQ_SIZE;
13362306a36Sopenharmony_ci}
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_cistatic struct net *macvtap_link_net(const struct net_device *dev)
13662306a36Sopenharmony_ci{
13762306a36Sopenharmony_ci	return dev_net(macvlan_dev_real_dev(dev));
13862306a36Sopenharmony_ci}
13962306a36Sopenharmony_ci
14062306a36Sopenharmony_cistatic struct rtnl_link_ops macvtap_link_ops __read_mostly = {
14162306a36Sopenharmony_ci	.kind		= "macvtap",
14262306a36Sopenharmony_ci	.setup		= macvtap_setup,
14362306a36Sopenharmony_ci	.newlink	= macvtap_newlink,
14462306a36Sopenharmony_ci	.dellink	= macvtap_dellink,
14562306a36Sopenharmony_ci	.get_link_net	= macvtap_link_net,
14662306a36Sopenharmony_ci	.priv_size      = sizeof(struct macvtap_dev),
14762306a36Sopenharmony_ci};
14862306a36Sopenharmony_ci
14962306a36Sopenharmony_cistatic int macvtap_device_event(struct notifier_block *unused,
15062306a36Sopenharmony_ci				unsigned long event, void *ptr)
15162306a36Sopenharmony_ci{
15262306a36Sopenharmony_ci	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
15362306a36Sopenharmony_ci	struct macvtap_dev *vlantap;
15462306a36Sopenharmony_ci	struct device *classdev;
15562306a36Sopenharmony_ci	dev_t devt;
15662306a36Sopenharmony_ci	int err;
15762306a36Sopenharmony_ci	char tap_name[IFNAMSIZ];
15862306a36Sopenharmony_ci
15962306a36Sopenharmony_ci	if (dev->rtnl_link_ops != &macvtap_link_ops)
16062306a36Sopenharmony_ci		return NOTIFY_DONE;
16162306a36Sopenharmony_ci
16262306a36Sopenharmony_ci	snprintf(tap_name, IFNAMSIZ, "tap%d", dev->ifindex);
16362306a36Sopenharmony_ci	vlantap = netdev_priv(dev);
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_ci	switch (event) {
16662306a36Sopenharmony_ci	case NETDEV_REGISTER:
16762306a36Sopenharmony_ci		/* Create the device node here after the network device has
16862306a36Sopenharmony_ci		 * been registered but before register_netdevice has
16962306a36Sopenharmony_ci		 * finished running.
17062306a36Sopenharmony_ci		 */
17162306a36Sopenharmony_ci		err = tap_get_minor(macvtap_major, &vlantap->tap);
17262306a36Sopenharmony_ci		if (err)
17362306a36Sopenharmony_ci			return notifier_from_errno(err);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci		devt = MKDEV(MAJOR(macvtap_major), vlantap->tap.minor);
17662306a36Sopenharmony_ci		classdev = device_create(&macvtap_class, &dev->dev, devt,
17762306a36Sopenharmony_ci					 dev, "%s", tap_name);
17862306a36Sopenharmony_ci		if (IS_ERR(classdev)) {
17962306a36Sopenharmony_ci			tap_free_minor(macvtap_major, &vlantap->tap);
18062306a36Sopenharmony_ci			return notifier_from_errno(PTR_ERR(classdev));
18162306a36Sopenharmony_ci		}
18262306a36Sopenharmony_ci		err = sysfs_create_link(&dev->dev.kobj, &classdev->kobj,
18362306a36Sopenharmony_ci					tap_name);
18462306a36Sopenharmony_ci		if (err)
18562306a36Sopenharmony_ci			return notifier_from_errno(err);
18662306a36Sopenharmony_ci		break;
18762306a36Sopenharmony_ci	case NETDEV_UNREGISTER:
18862306a36Sopenharmony_ci		/* vlan->minor == 0 if NETDEV_REGISTER above failed */
18962306a36Sopenharmony_ci		if (vlantap->tap.minor == 0)
19062306a36Sopenharmony_ci			break;
19162306a36Sopenharmony_ci		sysfs_remove_link(&dev->dev.kobj, tap_name);
19262306a36Sopenharmony_ci		devt = MKDEV(MAJOR(macvtap_major), vlantap->tap.minor);
19362306a36Sopenharmony_ci		device_destroy(&macvtap_class, devt);
19462306a36Sopenharmony_ci		tap_free_minor(macvtap_major, &vlantap->tap);
19562306a36Sopenharmony_ci		break;
19662306a36Sopenharmony_ci	case NETDEV_CHANGE_TX_QUEUE_LEN:
19762306a36Sopenharmony_ci		if (tap_queue_resize(&vlantap->tap))
19862306a36Sopenharmony_ci			return NOTIFY_BAD;
19962306a36Sopenharmony_ci		break;
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	return NOTIFY_DONE;
20362306a36Sopenharmony_ci}
20462306a36Sopenharmony_ci
20562306a36Sopenharmony_cistatic struct notifier_block macvtap_notifier_block __read_mostly = {
20662306a36Sopenharmony_ci	.notifier_call	= macvtap_device_event,
20762306a36Sopenharmony_ci};
20862306a36Sopenharmony_ci
20962306a36Sopenharmony_cistatic int __init macvtap_init(void)
21062306a36Sopenharmony_ci{
21162306a36Sopenharmony_ci	int err;
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_ci	err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap",
21462306a36Sopenharmony_ci			      THIS_MODULE);
21562306a36Sopenharmony_ci	if (err)
21662306a36Sopenharmony_ci		goto out1;
21762306a36Sopenharmony_ci
21862306a36Sopenharmony_ci	err = class_register(&macvtap_class);
21962306a36Sopenharmony_ci	if (err)
22062306a36Sopenharmony_ci		goto out2;
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_ci	err = register_netdevice_notifier(&macvtap_notifier_block);
22362306a36Sopenharmony_ci	if (err)
22462306a36Sopenharmony_ci		goto out3;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	err = macvlan_link_register(&macvtap_link_ops);
22762306a36Sopenharmony_ci	if (err)
22862306a36Sopenharmony_ci		goto out4;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	return 0;
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ciout4:
23362306a36Sopenharmony_ci	unregister_netdevice_notifier(&macvtap_notifier_block);
23462306a36Sopenharmony_ciout3:
23562306a36Sopenharmony_ci	class_unregister(&macvtap_class);
23662306a36Sopenharmony_ciout2:
23762306a36Sopenharmony_ci	tap_destroy_cdev(macvtap_major, &macvtap_cdev);
23862306a36Sopenharmony_ciout1:
23962306a36Sopenharmony_ci	return err;
24062306a36Sopenharmony_ci}
24162306a36Sopenharmony_cimodule_init(macvtap_init);
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic void __exit macvtap_exit(void)
24462306a36Sopenharmony_ci{
24562306a36Sopenharmony_ci	rtnl_link_unregister(&macvtap_link_ops);
24662306a36Sopenharmony_ci	unregister_netdevice_notifier(&macvtap_notifier_block);
24762306a36Sopenharmony_ci	class_unregister(&macvtap_class);
24862306a36Sopenharmony_ci	tap_destroy_cdev(macvtap_major, &macvtap_cdev);
24962306a36Sopenharmony_ci}
25062306a36Sopenharmony_cimodule_exit(macvtap_exit);
25162306a36Sopenharmony_ci
25262306a36Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("macvtap");
25362306a36Sopenharmony_ciMODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
25462306a36Sopenharmony_ciMODULE_LICENSE("GPL");
255