xref: /openbmc/linux/drivers/net/dummy.c (revision f9a82c48)
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 
45 static int numdummies = 1;
46 
47 /* fake multicast ability */
48 static void set_multicast_list(struct net_device *dev)
49 {
50 }
51 
52 struct pcpu_dstats {
53 	u64			tx_packets;
54 	u64			tx_bytes;
55 	struct u64_stats_sync	syncp;
56 };
57 
58 static 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 
79 static 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 
93 static 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 
102 static void dummy_dev_uninit(struct net_device *dev)
103 {
104 	free_percpu(dev->dstats);
105 }
106 
107 static 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 
116 static 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 
127 static 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 
134 static 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 
146 static const struct ethtool_ops dummy_ethtool_ops = {
147 	.get_drvinfo            = dummy_get_drvinfo,
148 	.get_ts_info		= dummy_get_ts_info,
149 };
150 
151 static 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 
176 static 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 
188 static 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. */
195 module_param(numdummies, int, 0);
196 MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
197 
198 static 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 
213 err:
214 	free_netdev(dev_dummy);
215 	return err;
216 }
217 
218 static 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 
235 out:
236 	rtnl_unlock();
237 	up_write(&pernet_ops_rwsem);
238 
239 	return err;
240 }
241 
242 static void __exit dummy_cleanup_module(void)
243 {
244 	rtnl_link_unregister(&dummy_link_ops);
245 }
246 
247 module_init(dummy_init_module);
248 module_exit(dummy_cleanup_module);
249 MODULE_LICENSE("GPL");
250 MODULE_ALIAS_RTNL_LINK(DRV_NAME);
251 MODULE_VERSION(DRV_VERSION);
252