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 | NETIF_F_UFO)
  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,
  81                           struct net_device *dev,
  82                           struct nlattr *tb[],
  83                           struct nlattr *data[])
  84{
  85        struct macvtap_dev *vlantap = netdev_priv(dev);
  86        int err;
  87
  88        INIT_LIST_HEAD(&vlantap->tap.queue_list);
  89
  90        /* Since macvlan supports all offloads by default, make
  91         * tap support all offloads also.
  92         */
  93        vlantap->tap.tap_features = TUN_OFFLOADS;
  94
  95        /* Register callbacks for rx/tx drops accounting and updating
  96         * net_device features
  97         */
  98        vlantap->tap.count_tx_dropped = macvtap_count_tx_dropped;
  99        vlantap->tap.count_rx_dropped = macvtap_count_rx_dropped;
 100        vlantap->tap.update_features  = macvtap_update_features;
 101
 102        err = netdev_rx_handler_register(dev, tap_handle_frame, &vlantap->tap);
 103        if (err)
 104                return err;
 105
 106        /* Don't put anything that may fail after macvlan_common_newlink
 107         * because we can't undo what it does.
 108         */
 109        err = macvlan_common_newlink(src_net, dev, tb, data);
 110        if (err) {
 111                netdev_rx_handler_unregister(dev);
 112                return err;
 113        }
 114
 115        vlantap->tap.dev = vlantap->vlan.dev;
 116
 117        return 0;
 118}
 119
 120static void macvtap_dellink(struct net_device *dev,
 121                            struct list_head *head)
 122{
 123        struct macvtap_dev *vlantap = netdev_priv(dev);
 124
 125        netdev_rx_handler_unregister(dev);
 126        tap_del_queues(&vlantap->tap);
 127        macvlan_dellink(dev, head);
 128}
 129
 130static void macvtap_setup(struct net_device *dev)
 131{
 132        macvlan_common_setup(dev);
 133        dev->tx_queue_len = TUN_READQ_SIZE;
 134}
 135
 136static struct rtnl_link_ops macvtap_link_ops __read_mostly = {
 137        .kind           = "macvtap",
 138        .setup          = macvtap_setup,
 139        .newlink        = macvtap_newlink,
 140        .dellink        = macvtap_dellink,
 141        .priv_size      = sizeof(struct macvtap_dev),
 142};
 143
 144static int macvtap_device_event(struct notifier_block *unused,
 145                                unsigned long event, void *ptr)
 146{
 147        struct net_device *dev = netdev_notifier_info_to_dev(ptr);
 148        struct macvtap_dev *vlantap;
 149        struct device *classdev;
 150        dev_t devt;
 151        int err;
 152        char tap_name[IFNAMSIZ];
 153
 154        if (dev->rtnl_link_ops != &macvtap_link_ops)
 155                return NOTIFY_DONE;
 156
 157        snprintf(tap_name, IFNAMSIZ, "tap%d", dev->ifindex);
 158        vlantap = netdev_priv(dev);
 159
 160        switch (event) {
 161        case NETDEV_REGISTER:
 162                /* Create the device node here after the network device has
 163                 * been registered but before register_netdevice has
 164                 * finished running.
 165                 */
 166                err = tap_get_minor(macvtap_major, &vlantap->tap);
 167                if (err)
 168                        return notifier_from_errno(err);
 169
 170                devt = MKDEV(MAJOR(macvtap_major), vlantap->tap.minor);
 171                classdev = device_create(&macvtap_class, &dev->dev, devt,
 172                                         dev, tap_name);
 173                if (IS_ERR(classdev)) {
 174                        tap_free_minor(macvtap_major, &vlantap->tap);
 175                        return notifier_from_errno(PTR_ERR(classdev));
 176                }
 177                err = sysfs_create_link(&dev->dev.kobj, &classdev->kobj,
 178                                        tap_name);
 179                if (err)
 180                        return notifier_from_errno(err);
 181                break;
 182        case NETDEV_UNREGISTER:
 183                /* vlan->minor == 0 if NETDEV_REGISTER above failed */
 184                if (vlantap->tap.minor == 0)
 185                        break;
 186                sysfs_remove_link(&dev->dev.kobj, tap_name);
 187                devt = MKDEV(MAJOR(macvtap_major), vlantap->tap.minor);
 188                device_destroy(&macvtap_class, devt);
 189                tap_free_minor(macvtap_major, &vlantap->tap);
 190                break;
 191        case NETDEV_CHANGE_TX_QUEUE_LEN:
 192                if (tap_queue_resize(&vlantap->tap))
 193                        return NOTIFY_BAD;
 194                break;
 195        }
 196
 197        return NOTIFY_DONE;
 198}
 199
 200static struct notifier_block macvtap_notifier_block __read_mostly = {
 201        .notifier_call  = macvtap_device_event,
 202};
 203
 204static int macvtap_init(void)
 205{
 206        int err;
 207
 208        err = tap_create_cdev(&macvtap_cdev, &macvtap_major, "macvtap");
 209
 210        if (err)
 211                goto out1;
 212
 213        err = class_register(&macvtap_class);
 214        if (err)
 215                goto out2;
 216
 217        err = register_netdevice_notifier(&macvtap_notifier_block);
 218        if (err)
 219                goto out3;
 220
 221        err = macvlan_link_register(&macvtap_link_ops);
 222        if (err)
 223                goto out4;
 224
 225        return 0;
 226
 227out4:
 228        unregister_netdevice_notifier(&macvtap_notifier_block);
 229out3:
 230        class_unregister(&macvtap_class);
 231out2:
 232        tap_destroy_cdev(macvtap_major, &macvtap_cdev);
 233out1:
 234        return err;
 235}
 236module_init(macvtap_init);
 237
 238static void macvtap_exit(void)
 239{
 240        rtnl_link_unregister(&macvtap_link_ops);
 241        unregister_netdevice_notifier(&macvtap_notifier_block);
 242        class_unregister(&macvtap_class);
 243        tap_destroy_cdev(macvtap_major, &macvtap_cdev);
 244}
 245module_exit(macvtap_exit);
 246
 247MODULE_ALIAS_RTNL_LINK("macvtap");
 248MODULE_AUTHOR("Arnd Bergmann <arnd@arndb.de>");
 249MODULE_LICENSE("GPL");
 250