linux/drivers/net/ipvlan/ipvtap.c
<<
>>
Prefs
   1#include <linux/etherdevice.h>
   2#include "ipvlan.h"
   3#include <linux/if_vlan.h>
   4#include <linux/if_tap.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.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
  26#define TUN_OFFLOADS (NETIF_F_HW_CSUM | NETIF_F_TSO_ECN | NETIF_F_TSO | \
  27                      NETIF_F_TSO6)
  28
  29static dev_t ipvtap_major;
  30static struct cdev ipvtap_cdev;
  31
  32static const void *ipvtap_net_namespace(struct device *d)
  33{
  34        struct net_device *dev = to_net_dev(d->parent);
  35        return dev_net(dev);
  36}
  37
  38static struct class ipvtap_class = {
  39         .name = "ipvtap",
  40         .owner = THIS_MODULE,
  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, make
  86         * 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_newlink
  98         * 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 has
 155                 * been registered but before register_netdevice has
 156                 * 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, 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 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 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_LICENSE("GPL");
 241