18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci#include <linux/etherdevice.h>
38c2ecf20Sopenharmony_ci#include <linux/if_macvlan.h>
48c2ecf20Sopenharmony_ci#include <linux/if_tap.h>
58c2ecf20Sopenharmony_ci#include <linux/if_vlan.h>
68c2ecf20Sopenharmony_ci#include <linux/interrupt.h>
78c2ecf20Sopenharmony_ci#include <linux/nsproxy.h>
88c2ecf20Sopenharmony_ci#include <linux/compat.h>
98c2ecf20Sopenharmony_ci#include <linux/if_tun.h>
108c2ecf20Sopenharmony_ci#include <linux/module.h>
118c2ecf20Sopenharmony_ci#include <linux/skbuff.h>
128c2ecf20Sopenharmony_ci#include <linux/cache.h>
138c2ecf20Sopenharmony_ci#include <linux/sched/signal.h>
148c2ecf20Sopenharmony_ci#include <linux/types.h>
158c2ecf20Sopenharmony_ci#include <linux/slab.h>
168c2ecf20Sopenharmony_ci#include <linux/wait.h>
178c2ecf20Sopenharmony_ci#include <linux/cdev.h>
188c2ecf20Sopenharmony_ci#include <linux/idr.h>
198c2ecf20Sopenharmony_ci#include <linux/fs.h>
208c2ecf20Sopenharmony_ci#include <linux/uio.h>
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ci#include <net/net_namespace.h>
238c2ecf20Sopenharmony_ci#include <net/rtnetlink.h>
248c2ecf20Sopenharmony_ci#include <net/sock.h>
258c2ecf20Sopenharmony_ci#include <linux/virtio_net.h>
268c2ecf20Sopenharmony_ci#include <linux/skb_array.h>
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cistruct macvtap_dev {
298c2ecf20Sopenharmony_ci	struct macvlan_dev vlan;
308c2ecf20Sopenharmony_ci	struct tap_dev    tap;
318c2ecf20Sopenharmony_ci};
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ci/*
348c2ecf20Sopenharmony_ci * Variables for dealing with macvtaps device numbers.
358c2ecf20Sopenharmony_ci */
368c2ecf20Sopenharmony_cistatic dev_t macvtap_major;
378c2ecf20Sopenharmony_ci
388c2ecf20Sopenharmony_cistatic const void *macvtap_net_namespace(struct device *d)
398c2ecf20Sopenharmony_ci{
408c2ecf20Sopenharmony_ci	struct net_device *dev = to_net_dev(d->parent);
418c2ecf20Sopenharmony_ci	return dev_net(dev);
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_cistatic struct class macvtap_class = {
458c2ecf20Sopenharmony_ci	.name = "macvtap",
468c2ecf20Sopenharmony_ci	.owner = THIS_MODULE,
478c2ecf20Sopenharmony_ci	.ns_type = &net_ns_type_operations,
488c2ecf20Sopenharmony_ci	.namespace = macvtap_net_namespace,
498c2ecf20Sopenharmony_ci};
508c2ecf20Sopenharmony_cistatic struct cdev macvtap_cdev;
518c2ecf20Sopenharmony_ci
528c2ecf20Sopenharmony_ci#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
538c2ecf20Sopenharmony_ci		      NETIF_F_TSO6)
548c2ecf20Sopenharmony_ci
558c2ecf20Sopenharmony_cistatic void macvtap_count_tx_dropped(struct tap_dev *tap)
568c2ecf20Sopenharmony_ci{
578c2ecf20Sopenharmony_ci	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
588c2ecf20Sopenharmony_ci	struct macvlan_dev *vlan = &vlantap->vlan;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	this_cpu_inc(vlan->pcpu_stats->tx_dropped);
618c2ecf20Sopenharmony_ci}
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_cistatic void macvtap_count_rx_dropped(struct tap_dev *tap)
648c2ecf20Sopenharmony_ci{
658c2ecf20Sopenharmony_ci	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
668c2ecf20Sopenharmony_ci	struct macvlan_dev *vlan = &vlantap->vlan;
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_ci	macvlan_count_rx(vlan, 0, 0, 0);
698c2ecf20Sopenharmony_ci}
708c2ecf20Sopenharmony_ci
718c2ecf20Sopenharmony_cistatic void macvtap_update_features(struct tap_dev *tap,
728c2ecf20Sopenharmony_ci				    netdev_features_t features)
738c2ecf20Sopenharmony_ci{
748c2ecf20Sopenharmony_ci	struct macvtap_dev *vlantap = container_of(tap, struct macvtap_dev, tap);
758c2ecf20Sopenharmony_ci	struct macvlan_dev *vlan = &vlantap->vlan;
768c2ecf20Sopenharmony_ci
778c2ecf20Sopenharmony_ci	vlan->set_features = features;
788c2ecf20Sopenharmony_ci	netdev_update_features(vlan->dev);
798c2ecf20Sopenharmony_ci}
808c2ecf20Sopenharmony_ci
818c2ecf20Sopenharmony_cistatic int macvtap_newlink(struct net *src_net, struct net_device *dev,
828c2ecf20Sopenharmony_ci			   struct nlattr *tb[], struct nlattr *data[],
838c2ecf20Sopenharmony_ci			   struct netlink_ext_ack *extack)
848c2ecf20Sopenharmony_ci{
858c2ecf20Sopenharmony_ci	struct macvtap_dev *vlantap = netdev_priv(dev);
868c2ecf20Sopenharmony_ci	int err;
878c2ecf20Sopenharmony_ci
888c2ecf20Sopenharmony_ci	INIT_LIST_HEAD(&vlantap->tap.queue_list);
898c2ecf20Sopenharmony_ci
908c2ecf20Sopenharmony_ci	/* Since macvlan supports all offloads by default, make
918c2ecf20Sopenharmony_ci	 * tap support all offloads also.
928c2ecf20Sopenharmony_ci	 */
938c2ecf20Sopenharmony_ci	vlantap->tap.tap_features = TUN_OFFLOADS;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	/* Register callbacks for rx/tx drops accounting and updating
968c2ecf20Sopenharmony_ci	 * net_device features
978c2ecf20Sopenharmony_ci	 */
988c2ecf20Sopenharmony_ci	vlantap->tap.count_tx_dropped = macvtap_count_tx_dropped;
998c2ecf20Sopenharmony_ci	vlantap->tap.count_rx_dropped = macvtap_count_rx_dropped;
1008c2ecf20Sopenharmony_ci	vlantap->tap.update_features  = macvtap_update_features;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	err = netdev_rx_handler_register(dev, tap_handle_frame, &vlantap->tap);
1038c2ecf20Sopenharmony_ci	if (err)
1048c2ecf20Sopenharmony_ci		return err;
1058c2ecf20Sopenharmony_ci
1068c2ecf20Sopenharmony_ci	/* Don't put anything that may fail after macvlan_common_newlink
1078c2ecf20Sopenharmony_ci	 * because we can't undo what it does.
1088c2ecf20Sopenharmony_ci	 */
1098c2ecf20Sopenharmony_ci	err = macvlan_common_newlink(src_net, dev, tb, data, extack);
1108c2ecf20Sopenharmony_ci	if (err) {
1118c2ecf20Sopenharmony_ci		netdev_rx_handler_unregister(dev);
1128c2ecf20Sopenharmony_ci		return err;
1138c2ecf20Sopenharmony_ci	}
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_ci	vlantap->tap.dev = vlantap->vlan.dev;
1168c2ecf20Sopenharmony_ci
1178c2ecf20Sopenharmony_ci	return 0;
1188c2ecf20Sopenharmony_ci}
1198c2ecf20Sopenharmony_ci
1208c2ecf20Sopenharmony_cistatic void macvtap_dellink(struct net_device *dev,
1218c2ecf20Sopenharmony_ci			    struct list_head *head)
1228c2ecf20Sopenharmony_ci{
1238c2ecf20Sopenharmony_ci	struct macvtap_dev *vlantap = netdev_priv(dev);
1248c2ecf20Sopenharmony_ci
1258c2ecf20Sopenharmony_ci	netdev_rx_handler_unregister(dev);
1268c2ecf20Sopenharmony_ci	tap_del_queues(&vlantap->tap);
1278c2ecf20Sopenharmony_ci	macvlan_dellink(dev, head);
1288c2ecf20Sopenharmony_ci}
1298c2ecf20Sopenharmony_ci
1308c2ecf20Sopenharmony_cistatic void macvtap_setup(struct net_device *dev)
1318c2ecf20Sopenharmony_ci{
1328c2ecf20Sopenharmony_ci	macvlan_common_setup(dev);
1338c2ecf20Sopenharmony_ci	dev->tx_queue_len = TUN_READQ_SIZE;
1348c2ecf20Sopenharmony_ci}
1358c2ecf20Sopenharmony_ci
1368c2ecf20Sopenharmony_cistatic struct net *macvtap_link_net(const struct net_device *dev)
1378c2ecf20Sopenharmony_ci{
1388c2ecf20Sopenharmony_ci	return dev_net(macvlan_dev_real_dev(dev));
1398c2ecf20Sopenharmony_ci}
1408c2ecf20Sopenharmony_ci
1418c2ecf20Sopenharmony_cistatic struct rtnl_link_ops macvtap_link_ops __read_mostly = {
1428c2ecf20Sopenharmony_ci	.kind		= "macvtap",
1438c2ecf20Sopenharmony_ci	.setup		= macvtap_setup,
1448c2ecf20Sopenharmony_ci	.newlink	= macvtap_newlink,
1458c2ecf20Sopenharmony_ci	.dellink	= macvtap_dellink,
1468c2ecf20Sopenharmony_ci	.get_link_net	= macvtap_link_net,
1478c2ecf20Sopenharmony_ci	.priv_size      = sizeof(struct macvtap_dev),
1488c2ecf20Sopenharmony_ci};
1498c2ecf20Sopenharmony_ci
1508c2ecf20Sopenharmony_cistatic int macvtap_device_event(struct notifier_block *unused,
1518c2ecf20Sopenharmony_ci				unsigned long event, void *ptr)
1528c2ecf20Sopenharmony_ci{
1538c2ecf20Sopenharmony_ci	struct net_device *dev = netdev_notifier_info_to_dev(ptr);
1548c2ecf20Sopenharmony_ci	struct macvtap_dev *vlantap;
1558c2ecf20Sopenharmony_ci	struct device *classdev;
1568c2ecf20Sopenharmony_ci	dev_t devt;
1578c2ecf20Sopenharmony_ci	int err;
1588c2ecf20Sopenharmony_ci	char tap_name[IFNAMSIZ];
1598c2ecf20Sopenharmony_ci
1608c2ecf20Sopenharmony_ci	if (dev->rtnl_link_ops != &macvtap_link_ops)
1618c2ecf20Sopenharmony_ci		return NOTIFY_DONE;
1628c2ecf20Sopenharmony_ci
1638c2ecf20Sopenharmony_ci	snprintf(tap_name, IFNAMSIZ, "tap%d", dev->ifindex);
1648c2ecf20Sopenharmony_ci	vlantap = netdev_priv(dev);
1658c2ecf20Sopenharmony_ci
1668c2ecf20Sopenharmony_ci	switch (event) {
1678c2ecf20Sopenharmony_ci	case NETDEV_REGISTER:
1688c2ecf20Sopenharmony_ci		/* Create the device node here after the network device has
1698c2ecf20Sopenharmony_ci		 * been registered but before register_netdevice has
1708c2ecf20Sopenharmony_ci		 * finished running.
1718c2ecf20Sopenharmony_ci		 */
1728c2ecf20Sopenharmony_ci		err = tap_get_minor(macvtap_major, &vlantap->tap);
1738c2ecf20Sopenharmony_ci		if (err)
1748c2ecf20Sopenharmony_ci			return notifier_from_errno(err);
1758c2ecf20Sopenharmony_ci
1768c2ecf20Sopenharmony_ci		devt = MKDEV(MAJOR(macvtap_major), vlantap->tap.minor);
1778c2ecf20Sopenharmony_ci		classdev = device_create(&macvtap_class, &dev->dev, devt,
1788c2ecf20Sopenharmony_ci					 dev, tap_name);
1798c2ecf20Sopenharmony_ci		if (IS_ERR(classdev)) {
1808c2ecf20Sopenharmony_ci			tap_free_minor(macvtap_major, &vlantap->tap);
1818c2ecf20Sopenharmony_ci			return notifier_from_errno(PTR_ERR(classdev));
1828c2ecf20Sopenharmony_ci		}
1838c2ecf20Sopenharmony_ci		err = sysfs_create_link(&dev->dev.kobj, &classdev->kobj,
1848c2ecf20Sopenharmony_ci					tap_name);
1858c2ecf20Sopenharmony_ci		if (err)
1868c2ecf20Sopenharmony_ci			return notifier_from_errno(err);
1878c2ecf20Sopenharmony_ci		break;
1888c2ecf20Sopenharmony_ci	case NETDEV_UNREGISTER:
1898c2ecf20Sopenharmony_ci		/* vlan->minor == 0 if NETDEV_REGISTER above failed */
1908c2ecf20Sopenharmony_ci		if (vlantap->tap.minor == 0)
1918c2ecf20Sopenharmony_ci			break;
1928c2ecf20Sopenharmony_ci		sysfs_remove_link(&dev->dev.kobj, tap_name);
1938c2ecf20Sopenharmony_ci		devt = MKDEV(MAJOR(macvtap_major), vlantap->tap.minor);
1948c2ecf20Sopenharmony_ci		device_destroy(&macvtap_class, devt);
1958c2ecf20Sopenharmony_ci		tap_free_minor(macvtap_major, &vlantap->tap);
1968c2ecf20Sopenharmony_ci		break;
1978c2ecf20Sopenharmony_ci	case NETDEV_CHANGE_TX_QUEUE_LEN:
1988c2ecf20Sopenharmony_ci		if (tap_queue_resize(&vlantap->tap))
1998c2ecf20Sopenharmony_ci			return NOTIFY_BAD;
2008c2ecf20Sopenharmony_ci		break;
2018c2ecf20Sopenharmony_ci	}
2028c2ecf20Sopenharmony_ci
2038c2ecf20Sopenharmony_ci	return NOTIFY_DONE;
2048c2ecf20Sopenharmony_ci}
2058c2ecf20Sopenharmony_ci
2068c2ecf20Sopenharmony_cistatic struct notifier_block macvtap_notifier_block __read_mostly = {
2078c2ecf20Sopenharmony_ci	.notifier_call	= macvtap_device_event,
2088c2ecf20Sopenharmony_ci};
2098c2ecf20Sopenharmony_ci
2108c2ecf20Sopenharmony_cistatic int macvtap_init(void)
2118c2ecf20Sopenharmony_ci{
2128c2ecf20Sopenharmony_ci	int err;
2138c2ecf20Sopenharmony_ci
2148c2ecf20Sopenharmony_ci	err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap",
2158c2ecf20Sopenharmony_ci			      THIS_MODULE);
2168c2ecf20Sopenharmony_ci	if (err)
2178c2ecf20Sopenharmony_ci		goto out1;
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci	err = class_register(&macvtap_class);
2208c2ecf20Sopenharmony_ci	if (err)
2218c2ecf20Sopenharmony_ci		goto out2;
2228c2ecf20Sopenharmony_ci
2238c2ecf20Sopenharmony_ci	err = register_netdevice_notifier(&macvtap_notifier_block);
2248c2ecf20Sopenharmony_ci	if (err)
2258c2ecf20Sopenharmony_ci		goto out3;
2268c2ecf20Sopenharmony_ci
2278c2ecf20Sopenharmony_ci	err = macvlan_link_register(&macvtap_link_ops);
2288c2ecf20Sopenharmony_ci	if (err)
2298c2ecf20Sopenharmony_ci		goto out4;
2308c2ecf20Sopenharmony_ci
2318c2ecf20Sopenharmony_ci	return 0;
2328c2ecf20Sopenharmony_ci
2338c2ecf20Sopenharmony_ciout4:
2348c2ecf20Sopenharmony_ci	unregister_netdevice_notifier(&macvtap_notifier_block);
2358c2ecf20Sopenharmony_ciout3:
2368c2ecf20Sopenharmony_ci	class_unregister(&macvtap_class);
2378c2ecf20Sopenharmony_ciout2:
2388c2ecf20Sopenharmony_ci	tap_destroy_cdev(macvtap_major, &macvtap_cdev);
2398c2ecf20Sopenharmony_ciout1:
2408c2ecf20Sopenharmony_ci	return err;
2418c2ecf20Sopenharmony_ci}
2428c2ecf20Sopenharmony_cimodule_init(macvtap_init);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_cistatic void macvtap_exit(void)
2458c2ecf20Sopenharmony_ci{
2468c2ecf20Sopenharmony_ci	rtnl_link_unregister(&macvtap_link_ops);
2478c2ecf20Sopenharmony_ci	unregister_netdevice_notifier(&macvtap_notifier_block);
2488c2ecf20Sopenharmony_ci	class_unregister(&macvtap_class);
2498c2ecf20Sopenharmony_ci	tap_destroy_cdev(macvtap_major, &macvtap_cdev);
2508c2ecf20Sopenharmony_ci}
2518c2ecf20Sopenharmony_cimodule_exit(macvtap_exit);
2528c2ecf20Sopenharmony_ci
2538c2ecf20Sopenharmony_ciMODULE_ALIAS_RTNL_LINK("macvtap");
2548c2ecf20Sopenharmony_ciMODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
2558c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL");
256