linux/drivers/net/dummy.c
<<
>>
Prefs
   1/* dummy.c: a dummy net driver
   2
   3        The purpose of this driver is to provide a device to point a
   4        route through, but not to actually transmit packets.
   5
   6        Why?  If you have a machine whose only connection is an occasional
   7        PPP/SLIP/PLIP link, you can only connect to your own hostname
   8        when the link is up.  Otherwise you have to use localhost.
   9        This isn't very consistent.
  10
  11        One solution is to set up a dummy link using PPP/SLIP/PLIP,
  12        but this seems (to me) too much overhead for too little gain.
  13        This driver provides a small alternative. Thus you can do
  14
  15        [when not running slip]
  16                ifconfig dummy slip.addr.ess.here up
  17        [to go to slip]
  18                ifconfig dummy down
  19                dip whatever
  20
  21        This was written by looking at Donald Becker's skeleton driver
  22        and the loopback driver.  I then threw away anything that didn't
  23        apply!  Thanks to Alan Cox for the key clue on what to do with
  24        misguided packets.
  25
  26                        Nick Holloway, 27th May 1994
  27        [I tweaked this explanation a little but that's all]
  28                        Alan Cox, 30th May 1994
  29*/
  30
  31#include <linux/module.h>
  32#include <linux/kernel.h>
  33#include <linux/netdevice.h>
  34#include <linux/etherdevice.h>
  35#include <linux/init.h>
  36#include <linux/moduleparam.h>
  37#include <linux/rtnetlink.h>
  38#include <linux/net_tstamp.h>
  39#include <net/rtnetlink.h>
  40#include <linux/u64_stats_sync.h>
  41
  42#define DRV_NAME        "dummy"
  43#define DRV_VERSION     "1.0"
  44
  45static int numdummies = 1;
  46
  47/* fake multicast ability */
  48static void set_multicast_list(struct net_device *dev)
  49{
  50}
  51
  52struct pcpu_dstats {
  53        u64                     tx_packets;
  54        u64                     tx_bytes;
  55        struct u64_stats_sync   syncp;
  56};
  57
  58static void dummy_get_stats64(struct net_device *dev,
  59                              struct rtnl_link_stats64 *stats)
  60{
  61        int i;
  62
  63        for_each_possible_cpu(i) {
  64                const struct pcpu_dstats *dstats;
  65                u64 tbytes, tpackets;
  66                unsigned int start;
  67
  68                dstats = per_cpu_ptr(dev->dstats, i);
  69                do {
  70                        start = u64_stats_fetch_begin_irq(&dstats->syncp);
  71                        tbytes = dstats->tx_bytes;
  72                        tpackets = dstats->tx_packets;
  73                } while (u64_stats_fetch_retry_irq(&dstats->syncp, start));
  74                stats->tx_bytes += tbytes;
  75                stats->tx_packets += tpackets;
  76        }
  77}
  78
  79static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
  80{
  81        struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
  82
  83        u64_stats_update_begin(&dstats->syncp);
  84        dstats->tx_packets++;
  85        dstats->tx_bytes += skb->len;
  86        u64_stats_update_end(&dstats->syncp);
  87
  88        skb_tx_timestamp(skb);
  89        dev_kfree_skb(skb);
  90        return NETDEV_TX_OK;
  91}
  92
  93static int dummy_dev_init(struct net_device *dev)
  94{
  95        dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
  96        if (!dev->dstats)
  97                return -ENOMEM;
  98
  99        return 0;
 100}
 101
 102static void dummy_dev_uninit(struct net_device *dev)
 103{
 104        free_percpu(dev->dstats);
 105}
 106
 107static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
 108{
 109        if (new_carrier)
 110                netif_carrier_on(dev);
 111        else
 112                netif_carrier_off(dev);
 113        return 0;
 114}
 115
 116static const struct net_device_ops dummy_netdev_ops = {
 117        .ndo_init               = dummy_dev_init,
 118        .ndo_uninit             = dummy_dev_uninit,
 119        .ndo_start_xmit         = dummy_xmit,
 120        .ndo_validate_addr      = eth_validate_addr,
 121        .ndo_set_rx_mode        = set_multicast_list,
 122        .ndo_set_mac_address    = eth_mac_addr,
 123        .ndo_get_stats64        = dummy_get_stats64,
 124        .ndo_change_carrier     = dummy_change_carrier,
 125};
 126
 127static void dummy_get_drvinfo(struct net_device *dev,
 128                              struct ethtool_drvinfo *info)
 129{
 130        strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
 131        strlcpy(info->version, DRV_VERSION, sizeof(info->version));
 132}
 133
 134static int dummy_get_ts_info(struct net_device *dev,
 135                              struct ethtool_ts_info *ts_info)
 136{
 137        ts_info->so_timestamping = SOF_TIMESTAMPING_TX_SOFTWARE |
 138                                   SOF_TIMESTAMPING_RX_SOFTWARE |
 139                                   SOF_TIMESTAMPING_SOFTWARE;
 140
 141        ts_info->phc_index = -1;
 142
 143        return 0;
 144};
 145
 146static const struct ethtool_ops dummy_ethtool_ops = {
 147        .get_drvinfo            = dummy_get_drvinfo,
 148        .get_ts_info            = dummy_get_ts_info,
 149};
 150
 151static void dummy_setup(struct net_device *dev)
 152{
 153        ether_setup(dev);
 154
 155        /* Initialize the device structure. */
 156        dev->netdev_ops = &dummy_netdev_ops;
 157        dev->ethtool_ops = &dummy_ethtool_ops;
 158        dev->needs_free_netdev = true;
 159
 160        /* Fill in device structure with ethernet-generic values. */
 161        dev->flags |= IFF_NOARP;
 162        dev->flags &= ~IFF_MULTICAST;
 163        dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
 164        dev->features   |= NETIF_F_SG | NETIF_F_FRAGLIST;
 165        dev->features   |= NETIF_F_ALL_TSO;
 166        dev->features   |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
 167        dev->features   |= NETIF_F_GSO_ENCAP_ALL;
 168        dev->hw_features |= dev->features;
 169        dev->hw_enc_features |= dev->features;
 170        eth_hw_addr_random(dev);
 171
 172        dev->min_mtu = 0;
 173        dev->max_mtu = 0;
 174}
 175
 176static int dummy_validate(struct nlattr *tb[], struct nlattr *data[],
 177                          struct netlink_ext_ack *extack)
 178{
 179        if (tb[IFLA_ADDRESS]) {
 180                if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
 181                        return -EINVAL;
 182                if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
 183                        return -EADDRNOTAVAIL;
 184        }
 185        return 0;
 186}
 187
 188static struct rtnl_link_ops dummy_link_ops __read_mostly = {
 189        .kind           = DRV_NAME,
 190        .setup          = dummy_setup,
 191        .validate       = dummy_validate,
 192};
 193
 194/* Number of dummy devices to be set up by this module. */
 195module_param(numdummies, int, 0);
 196MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
 197
 198static int __init dummy_init_one(void)
 199{
 200        struct net_device *dev_dummy;
 201        int err;
 202
 203        dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_ENUM, dummy_setup);
 204        if (!dev_dummy)
 205                return -ENOMEM;
 206
 207        dev_dummy->rtnl_link_ops = &dummy_link_ops;
 208        err = register_netdevice(dev_dummy);
 209        if (err < 0)
 210                goto err;
 211        return 0;
 212
 213err:
 214        free_netdev(dev_dummy);
 215        return err;
 216}
 217
 218static int __init dummy_init_module(void)
 219{
 220        int i, err = 0;
 221
 222        down_write(&pernet_ops_rwsem);
 223        rtnl_lock();
 224        err = __rtnl_link_register(&dummy_link_ops);
 225        if (err < 0)
 226                goto out;
 227
 228        for (i = 0; i < numdummies && !err; i++) {
 229                err = dummy_init_one();
 230                cond_resched();
 231        }
 232        if (err < 0)
 233                __rtnl_link_unregister(&dummy_link_ops);
 234
 235out:
 236        rtnl_unlock();
 237        up_write(&pernet_ops_rwsem);
 238
 239        return err;
 240}
 241
 242static void __exit dummy_cleanup_module(void)
 243{
 244        rtnl_link_unregister(&dummy_link_ops);
 245}
 246
 247module_init(dummy_init_module);
 248module_exit(dummy_cleanup_module);
 249MODULE_LICENSE("GPL");
 250MODULE_ALIAS_RTNL_LINK(DRV_NAME);
 251MODULE_VERSION(DRV_VERSION);
 252