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