Blame view

drivers/net/dummy.c 4.85 KB
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
1
2
3
4
5
6
7
8
9
10
11
12
13
  /* dummy.c: a dummy net driver
  
  	The purpose of this driver is to provide a device to point a
  	route through, but not to actually transmit packets.
  
  	Why?  If you have a machine whose only connection is an occasional
  	PPP/SLIP/PLIP link, you can only connect to your own hostname
  	when the link is up.  Otherwise you have to use localhost.
  	This isn't very consistent.
  
  	One solution is to set up a dummy link using PPP/SLIP/PLIP,
  	but this seems (to me) too much overhead for too little gain.
  	This driver provides a small alternative. Thus you can do
6aa20a223   Jeff Garzik   drivers/net: Trim...
14

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
  	[when not running slip]
  		ifconfig dummy slip.addr.ess.here up
  	[to go to slip]
  		ifconfig dummy down
  		dip whatever
  
  	This was written by looking at Donald Becker's skeleton driver
  	and the loopback driver.  I then threw away anything that didn't
  	apply!	Thanks to Alan Cox for the key clue on what to do with
  	misguided packets.
  
  			Nick Holloway, 27th May 1994
  	[I tweaked this explanation a little but that's all]
  			Alan Cox, 30th May 1994
  */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
30
31
32
33
34
35
  #include <linux/module.h>
  #include <linux/kernel.h>
  #include <linux/netdevice.h>
  #include <linux/etherdevice.h>
  #include <linux/init.h>
  #include <linux/moduleparam.h>
206c9fb26   Patrick McHardy   [DUMMY]: Keep dum...
36
  #include <linux/rtnetlink.h>
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
37
  #include <net/rtnetlink.h>
6d81f41c5   Eric Dumazet   dummy: percpu sta...
38
  #include <linux/u64_stats_sync.h>
206c9fb26   Patrick McHardy   [DUMMY]: Keep dum...
39

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
40
  static int numdummies = 1;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
41
42
43
  static int dummy_set_address(struct net_device *dev, void *p)
  {
  	struct sockaddr *sa = p;
6aa20a223   Jeff Garzik   drivers/net: Trim...
44
  	if (!is_valid_ether_addr(sa->sa_data))
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
45
  		return -EADDRNOTAVAIL;
6aa20a223   Jeff Garzik   drivers/net: Trim...
46

1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
47
48
49
50
51
52
53
54
  	memcpy(dev->dev_addr, sa->sa_data, ETH_ALEN);
  	return 0;
  }
  
  /* fake multicast ability */
  static void set_multicast_list(struct net_device *dev)
  {
  }
6d81f41c5   Eric Dumazet   dummy: percpu sta...
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
  struct pcpu_dstats {
  	u64			tx_packets;
  	u64			tx_bytes;
  	struct u64_stats_sync	syncp;
  };
  
  static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev,
  						   struct rtnl_link_stats64 *stats)
  {
  	int i;
  
  	for_each_possible_cpu(i) {
  		const struct pcpu_dstats *dstats;
  		u64 tbytes, tpackets;
  		unsigned int start;
  
  		dstats = per_cpu_ptr(dev->dstats, i);
  		do {
  			start = u64_stats_fetch_begin(&dstats->syncp);
  			tbytes = dstats->tx_bytes;
  			tpackets = dstats->tx_packets;
  		} while (u64_stats_fetch_retry(&dstats->syncp, start));
  		stats->tx_bytes += tbytes;
  		stats->tx_packets += tpackets;
  	}
  	return stats;
  }
424efe9ca   Stephen Hemminger   netdev: convert p...
82
83
84
  
  static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
  {
6d81f41c5   Eric Dumazet   dummy: percpu sta...
85
86
87
88
89
90
  	struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
  
  	u64_stats_update_begin(&dstats->syncp);
  	dstats->tx_packets++;
  	dstats->tx_bytes += skb->len;
  	u64_stats_update_end(&dstats->syncp);
424efe9ca   Stephen Hemminger   netdev: convert p...
91
92
93
94
  
  	dev_kfree_skb(skb);
  	return NETDEV_TX_OK;
  }
6d81f41c5   Eric Dumazet   dummy: percpu sta...
95
96
97
98
99
100
101
102
103
104
105
106
107
108
  static int dummy_dev_init(struct net_device *dev)
  {
  	dev->dstats = alloc_percpu(struct pcpu_dstats);
  	if (!dev->dstats)
  		return -ENOMEM;
  
  	return 0;
  }
  
  static void dummy_dev_free(struct net_device *dev)
  {
  	free_percpu(dev->dstats);
  	free_netdev(dev);
  }
aa18e9e88   Stephen Hemminger   dummy: convert to...
109
  static const struct net_device_ops dummy_netdev_ops = {
6d81f41c5   Eric Dumazet   dummy: percpu sta...
110
  	.ndo_init		= dummy_dev_init,
aa18e9e88   Stephen Hemminger   dummy: convert to...
111
112
  	.ndo_start_xmit		= dummy_xmit,
  	.ndo_validate_addr	= eth_validate_addr,
afc4b13df   Jiri Pirko   net: remove use o...
113
  	.ndo_set_rx_mode	= set_multicast_list,
aa18e9e88   Stephen Hemminger   dummy: convert to...
114
  	.ndo_set_mac_address	= dummy_set_address,
6d81f41c5   Eric Dumazet   dummy: percpu sta...
115
  	.ndo_get_stats64	= dummy_get_stats64,
aa18e9e88   Stephen Hemminger   dummy: convert to...
116
  };
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
117
  static void dummy_setup(struct net_device *dev)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
118
  {
aa18e9e88   Stephen Hemminger   dummy: convert to...
119
  	ether_setup(dev);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
120
  	/* Initialize the device structure. */
aa18e9e88   Stephen Hemminger   dummy: convert to...
121
  	dev->netdev_ops = &dummy_netdev_ops;
6d81f41c5   Eric Dumazet   dummy: percpu sta...
122
  	dev->destructor = dummy_dev_free;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
123
124
  
  	/* Fill in device structure with ethernet-generic values. */
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
125
  	dev->tx_queue_len = 0;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
126
127
  	dev->flags |= IFF_NOARP;
  	dev->flags &= ~IFF_MULTICAST;
6d81f41c5   Eric Dumazet   dummy: percpu sta...
128
  	dev->features	|= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO;
34324dc2b   Michał Mirosław   net: remove NETIF...
129
  	dev->features	|= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
130
131
  	random_ether_addr(dev->dev_addr);
  }
6d81f41c5   Eric Dumazet   dummy: percpu sta...
132

0e06877c6   Patrick McHardy   [RTNETLINK]: rtnl...
133
134
135
136
137
138
139
140
141
142
  static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
  {
  	if (tb[IFLA_ADDRESS]) {
  		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
  			return -EINVAL;
  		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
  			return -EADDRNOTAVAIL;
  	}
  	return 0;
  }
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
143
144
  static struct rtnl_link_ops dummy_link_ops __read_mostly = {
  	.kind		= "dummy",
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
145
  	.setup		= dummy_setup,
0e06877c6   Patrick McHardy   [RTNETLINK]: rtnl...
146
  	.validate	= dummy_validate,
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
147
  };
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
148
149
150
  /* Number of dummy devices to be set up by this module. */
  module_param(numdummies, int, 0);
  MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
206c9fb26   Patrick McHardy   [DUMMY]: Keep dum...
151
  static int __init dummy_init_one(void)
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
152
153
154
  {
  	struct net_device *dev_dummy;
  	int err;
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
155
  	dev_dummy = alloc_netdev(0, "dummy%d", dummy_setup);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
156
157
  	if (!dev_dummy)
  		return -ENOMEM;
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
158
159
160
161
  	dev_dummy->rtnl_link_ops = &dummy_link_ops;
  	err = register_netdevice(dev_dummy);
  	if (err < 0)
  		goto err;
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
162
  	return 0;
206c9fb26   Patrick McHardy   [DUMMY]: Keep dum...
163

5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
164
165
166
  err:
  	free_netdev(dev_dummy);
  	return err;
6aa20a223   Jeff Garzik   drivers/net: Trim...
167
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
168
169
  
  static int __init dummy_init_module(void)
6aa20a223   Jeff Garzik   drivers/net: Trim...
170
  {
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
171
  	int i, err = 0;
206c9fb26   Patrick McHardy   [DUMMY]: Keep dum...
172

5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
173
174
  	rtnl_lock();
  	err = __rtnl_link_register(&dummy_link_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
175
  	for (i = 0; i < numdummies && !err; i++)
206c9fb26   Patrick McHardy   [DUMMY]: Keep dum...
176
  		err = dummy_init_one();
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
177
  	if (err < 0)
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
178
  		__rtnl_link_unregister(&dummy_link_ops);
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
179
  	rtnl_unlock();
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
180
  	return err;
6aa20a223   Jeff Garzik   drivers/net: Trim...
181
  }
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
182
183
184
  
  static void __exit dummy_cleanup_module(void)
  {
2d85cba2b   Patrick McHardy   [RTNETLINK]: rtnl...
185
  	rtnl_link_unregister(&dummy_link_ops);
1da177e4c   Linus Torvalds   Linux-2.6.12-rc2
186
187
188
189
190
  }
  
  module_init(dummy_init_module);
  module_exit(dummy_cleanup_module);
  MODULE_LICENSE("GPL");
5d5cb173d   Patrick McHardy   [DUMMY]: Use rtnl...
191
  MODULE_ALIAS_RTNL_LINK("dummy");