Linux Kernel  3.7.1
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
dummy.c
Go to the documentation of this file.
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 <net/rtnetlink.h>
39 #include <linux/u64_stats_sync.h>
40 
41 static int numdummies = 1;
42 
43 /* fake multicast ability */
44 static void set_multicast_list(struct net_device *dev)
45 {
46 }
47 
48 struct pcpu_dstats {
52 };
53 
54 static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev,
55  struct rtnl_link_stats64 *stats)
56 {
57  int i;
58 
60  const struct pcpu_dstats *dstats;
61  u64 tbytes, tpackets;
62  unsigned int start;
63 
64  dstats = per_cpu_ptr(dev->dstats, i);
65  do {
66  start = u64_stats_fetch_begin_bh(&dstats->syncp);
67  tbytes = dstats->tx_bytes;
68  tpackets = dstats->tx_packets;
69  } while (u64_stats_fetch_retry_bh(&dstats->syncp, start));
70  stats->tx_bytes += tbytes;
71  stats->tx_packets += tpackets;
72  }
73  return stats;
74 }
75 
76 static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
77 {
78  struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
79 
80  u64_stats_update_begin(&dstats->syncp);
81  dstats->tx_packets++;
82  dstats->tx_bytes += skb->len;
83  u64_stats_update_end(&dstats->syncp);
84 
85  dev_kfree_skb(skb);
86  return NETDEV_TX_OK;
87 }
88 
89 static int dummy_dev_init(struct net_device *dev)
90 {
91  dev->dstats = alloc_percpu(struct pcpu_dstats);
92  if (!dev->dstats)
93  return -ENOMEM;
94 
95  return 0;
96 }
97 
98 static void dummy_dev_uninit(struct net_device *dev)
99 {
100  free_percpu(dev->dstats);
101 }
102 
103 static const struct net_device_ops dummy_netdev_ops = {
104  .ndo_init = dummy_dev_init,
105  .ndo_uninit = dummy_dev_uninit,
106  .ndo_start_xmit = dummy_xmit,
107  .ndo_validate_addr = eth_validate_addr,
108  .ndo_set_rx_mode = set_multicast_list,
109  .ndo_set_mac_address = eth_mac_addr,
110  .ndo_get_stats64 = dummy_get_stats64,
111 };
112 
113 static void dummy_setup(struct net_device *dev)
114 {
115  ether_setup(dev);
116 
117  /* Initialize the device structure. */
118  dev->netdev_ops = &dummy_netdev_ops;
119  dev->destructor = free_netdev;
120 
121  /* Fill in device structure with ethernet-generic values. */
122  dev->tx_queue_len = 0;
123  dev->flags |= IFF_NOARP;
124  dev->flags &= ~IFF_MULTICAST;
128  eth_hw_addr_random(dev);
129 }
130 
131 static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
132 {
133  if (tb[IFLA_ADDRESS]) {
134  if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
135  return -EINVAL;
136  if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
137  return -EADDRNOTAVAIL;
138  }
139  return 0;
140 }
141 
142 static struct rtnl_link_ops dummy_link_ops __read_mostly = {
143  .kind = "dummy",
144  .setup = dummy_setup,
145  .validate = dummy_validate,
146 };
147 
148 /* Number of dummy devices to be set up by this module. */
149 module_param(numdummies, int, 0);
150 MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
151 
152 static int __init dummy_init_one(void)
153 {
154  struct net_device *dev_dummy;
155  int err;
156 
157  dev_dummy = alloc_netdev(0, "dummy%d", dummy_setup);
158  if (!dev_dummy)
159  return -ENOMEM;
160 
161  dev_dummy->rtnl_link_ops = &dummy_link_ops;
162  err = register_netdevice(dev_dummy);
163  if (err < 0)
164  goto err;
165  return 0;
166 
167 err:
168  free_netdev(dev_dummy);
169  return err;
170 }
171 
172 static int __init dummy_init_module(void)
173 {
174  int i, err = 0;
175 
176  rtnl_lock();
177  err = __rtnl_link_register(&dummy_link_ops);
178 
179  for (i = 0; i < numdummies && !err; i++) {
180  err = dummy_init_one();
181  cond_resched();
182  }
183  if (err < 0)
184  __rtnl_link_unregister(&dummy_link_ops);
185  rtnl_unlock();
186 
187  return err;
188 }
189 
190 static void __exit dummy_cleanup_module(void)
191 {
192  rtnl_link_unregister(&dummy_link_ops);
193 }
194 
195 module_init(dummy_init_module);
196 module_exit(dummy_cleanup_module);
197 MODULE_LICENSE("GPL");
198 MODULE_ALIAS_RTNL_LINK("dummy");