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