11da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* dummy.c: a dummy net driver 21da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 31da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds The purpose of this driver is to provide a device to point a 41da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds route through, but not to actually transmit packets. 51da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 61da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Why? If you have a machine whose only connection is an occasional 71da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds PPP/SLIP/PLIP link, you can only connect to your own hostname 81da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds when the link is up. Otherwise you have to use localhost. 91da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This isn't very consistent. 101da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 111da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds One solution is to set up a dummy link using PPP/SLIP/PLIP, 121da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds but this seems (to me) too much overhead for too little gain. 131da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This driver provides a small alternative. Thus you can do 146aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 151da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [when not running slip] 161da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifconfig dummy slip.addr.ess.here up 171da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [to go to slip] 181da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds ifconfig dummy down 191da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dip whatever 201da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 211da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds This was written by looking at Donald Becker's skeleton driver 221da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds and the loopback driver. I then threw away anything that didn't 231da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds apply! Thanks to Alan Cox for the key clue on what to do with 241da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds misguided packets. 251da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Nick Holloway, 27th May 1994 271da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds [I tweaked this explanation a little but that's all] 281da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds Alan Cox, 30th May 1994 291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds*/ 301da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 311da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/module.h> 321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/kernel.h> 331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/netdevice.h> 341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/etherdevice.h> 351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/init.h> 361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds#include <linux/moduleparam.h> 37206c9fb26f5df2ea6d440fb64159faf4d8665398Patrick McHardy#include <linux/rtnetlink.h> 385d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy#include <net/rtnetlink.h> 396d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet#include <linux/u64_stats_sync.h> 40206c9fb26f5df2ea6d440fb64159faf4d8665398Patrick McHardy 411da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int numdummies = 1; 421da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 431da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int dummy_set_address(struct net_device *dev, void *p) 441da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 451da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct sockaddr *sa = p; 461da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 476aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik if (!is_valid_ether_addr(sa->sa_data)) 481da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -EADDRNOTAVAIL; 496aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik 507ce5d222190cb3ce3ae88bafde7c4fa52a5103e0Danny Kukawka dev->addr_assign_type &= ~NET_ADDR_RANDOM; 511da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN); 521da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return 0; 531da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 541da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 551da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* fake multicast ability */ 561da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void set_multicast_list(struct net_device *dev) 571da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 581da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 606d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazetstruct pcpu_dstats { 616d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet u64 tx_packets; 626d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet u64 tx_bytes; 636d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet struct u64_stats_sync syncp; 646d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet}; 656d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet 666d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazetstatic struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev, 676d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet struct rtnl_link_stats64 *stats) 686d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet{ 696d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet int i; 706d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet 716d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet for_each_possible_cpu(i) { 726d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet const struct pcpu_dstats *dstats; 736d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet u64 tbytes, tpackets; 746d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet unsigned int start; 756d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet 766d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet dstats = per_cpu_ptr(dev->dstats, i); 776d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet do { 786d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet start = u64_stats_fetch_begin(&dstats->syncp); 796d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet tbytes = dstats->tx_bytes; 806d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet tpackets = dstats->tx_packets; 816d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet } while (u64_stats_fetch_retry(&dstats->syncp, start)); 826d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet stats->tx_bytes += tbytes; 836d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet stats->tx_packets += tpackets; 846d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet } 856d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet return stats; 866d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet} 87424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger 88424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemmingerstatic netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) 89424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger{ 906d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats); 916d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet 926d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet u64_stats_update_begin(&dstats->syncp); 936d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet dstats->tx_packets++; 946d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet dstats->tx_bytes += skb->len; 956d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet u64_stats_update_end(&dstats->syncp); 96424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger 97424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger dev_kfree_skb(skb); 98424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger return NETDEV_TX_OK; 99424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger} 100424efe9caf6047ffbcd6b383ff4d2347254aabf1Stephen Hemminger 1016d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazetstatic int dummy_dev_init(struct net_device *dev) 1026d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet{ 1036d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet dev->dstats = alloc_percpu(struct pcpu_dstats); 1046d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet if (!dev->dstats) 1056d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet return -ENOMEM; 1066d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet 1076d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet return 0; 1086d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet} 1096d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet 110890fdf2a0cb88202d1427589db2cf29c1bdd3c1dHiroaki SHIMODAstatic void dummy_dev_uninit(struct net_device *dev) 1116d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet{ 1126d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet free_percpu(dev->dstats); 1136d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet} 1146d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet 115aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemmingerstatic const struct net_device_ops dummy_netdev_ops = { 1166d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet .ndo_init = dummy_dev_init, 117890fdf2a0cb88202d1427589db2cf29c1bdd3c1dHiroaki SHIMODA .ndo_uninit = dummy_dev_uninit, 118aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemminger .ndo_start_xmit = dummy_xmit, 119aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemminger .ndo_validate_addr = eth_validate_addr, 120afc4b13df143122f99a0eb10bfefb216c2806de0Jiri Pirko .ndo_set_rx_mode = set_multicast_list, 121aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemminger .ndo_set_mac_address = dummy_set_address, 1226d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet .ndo_get_stats64 = dummy_get_stats64, 123aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemminger}; 124aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemminger 1255d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardystatic void dummy_setup(struct net_device *dev) 1261da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 127aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemminger ether_setup(dev); 128aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemminger 1291da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Initialize the device structure. */ 130aa18e9e88c863a58f6ea63eeee0e740be071fdcfStephen Hemminger dev->netdev_ops = &dummy_netdev_ops; 131890fdf2a0cb88202d1427589db2cf29c1bdd3c1dHiroaki SHIMODA dev->destructor = free_netdev; 1321da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1331da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds /* Fill in device structure with ethernet-generic values. */ 1341da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->tx_queue_len = 0; 1351da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->flags |= IFF_NOARP; 1361da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds dev->flags &= ~IFF_MULTICAST; 1376d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO; 13834324dc2bf27c1773045fea63cb11f7e2a6ad2b9Michał Mirosław dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX; 1397ce5d222190cb3ce3ae88bafde7c4fa52a5103e0Danny Kukawka eth_hw_addr_random(dev); 1401da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 1416d81f41c58c69ddde497e9e640ba5805aa26e78cEric Dumazet 1420e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardystatic int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) 1430e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy{ 1440e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy if (tb[IFLA_ADDRESS]) { 1450e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN) 1460e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy return -EINVAL; 1470e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS]))) 1480e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy return -EADDRNOTAVAIL; 1490e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy } 1500e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy return 0; 1510e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy} 1520e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy 1535d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardystatic struct rtnl_link_ops dummy_link_ops __read_mostly = { 1545d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy .kind = "dummy", 1555d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy .setup = dummy_setup, 1560e06877c6fdbc67b1132be895f995acd1ff30135Patrick McHardy .validate = dummy_validate, 1575d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy}; 1585d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy 1591da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds/* Number of dummy devices to be set up by this module. */ 1601da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_param(numdummies, int, 0); 1611da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices"); 1621da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 163206c9fb26f5df2ea6d440fb64159faf4d8665398Patrick McHardystatic int __init dummy_init_one(void) 1641da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 1651da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds struct net_device *dev_dummy; 1661da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int err; 1671da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1682d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardy dev_dummy = alloc_netdev(0, "dummy%d", dummy_setup); 1691da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds if (!dev_dummy) 1701da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return -ENOMEM; 1711da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1725d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy dev_dummy->rtnl_link_ops = &dummy_link_ops; 1735d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy err = register_netdevice(dev_dummy); 1745d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy if (err < 0) 1755d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy goto err; 1765d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy return 0; 177206c9fb26f5df2ea6d440fb64159faf4d8665398Patrick McHardy 1785d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardyerr: 1795d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy free_netdev(dev_dummy); 1805d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy return err; 1816aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik} 1821da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 1831da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic int __init dummy_init_module(void) 1846aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik{ 1851da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds int i, err = 0; 186206c9fb26f5df2ea6d440fb64159faf4d8665398Patrick McHardy 1875d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy rtnl_lock(); 1885d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy err = __rtnl_link_register(&dummy_link_ops); 1895d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy 19009838df9d2ff31252a69a8393ea96a9734eba7e8Eric Dumazet for (i = 0; i < numdummies && !err; i++) { 191206c9fb26f5df2ea6d440fb64159faf4d8665398Patrick McHardy err = dummy_init_one(); 19209838df9d2ff31252a69a8393ea96a9734eba7e8Eric Dumazet cond_resched(); 19309838df9d2ff31252a69a8393ea96a9734eba7e8Eric Dumazet } 1942d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardy if (err < 0) 1955d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy __rtnl_link_unregister(&dummy_link_ops); 1965d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy rtnl_unlock(); 1975d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardy 1981da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds return err; 1996aa20a2235535605db6d6d2bd850298b2fe7f31eJeff Garzik} 2001da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2011da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsstatic void __exit dummy_cleanup_module(void) 2021da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds{ 2032d85cba2b272a5201a60966a65a4f8c0bcc0bb71Patrick McHardy rtnl_link_unregister(&dummy_link_ops); 2041da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds} 2051da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvalds 2061da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_init(dummy_init_module); 2071da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus Torvaldsmodule_exit(dummy_cleanup_module); 2081da177e4c3f41524e886b7f1b8a0c1fc7321cacLinus TorvaldsMODULE_LICENSE("GPL"); 2095d5cb173d85ebf6dfb16f456a8148ecb4b1cecbcPatrick McHardyMODULE_ALIAS_RTNL_LINK("dummy"); 210