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