1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
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#define DRV_NAME "dummy"
42#define DRV_VERSION "1.0"
43
44static int numdummies = 1;
45
46
47static void set_multicast_list(struct net_device *dev)
48{
49}
50
51struct pcpu_dstats {
52 u64 tx_packets;
53 u64 tx_bytes;
54 struct u64_stats_sync syncp;
55};
56
57static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev,
58 struct rtnl_link_stats64 *stats)
59{
60 int i;
61
62 for_each_possible_cpu(i) {
63 const struct pcpu_dstats *dstats;
64 u64 tbytes, tpackets;
65 unsigned int start;
66
67 dstats = per_cpu_ptr(dev->dstats, i);
68 do {
69 start = u64_stats_fetch_begin_irq(&dstats->syncp);
70 tbytes = dstats->tx_bytes;
71 tpackets = dstats->tx_packets;
72 } while (u64_stats_fetch_retry_irq(&dstats->syncp, start));
73 stats->tx_bytes += tbytes;
74 stats->tx_packets += tpackets;
75 }
76 return stats;
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 dev_kfree_skb(skb);
89 return NETDEV_TX_OK;
90}
91
92static int dummy_dev_init(struct net_device *dev)
93{
94 dev->dstats = netdev_alloc_pcpu_stats(struct pcpu_dstats);
95 if (!dev->dstats)
96 return -ENOMEM;
97
98 return 0;
99}
100
101static void dummy_dev_uninit(struct net_device *dev)
102{
103 free_percpu(dev->dstats);
104}
105
106static int dummy_change_carrier(struct net_device *dev, bool new_carrier)
107{
108 if (new_carrier)
109 netif_carrier_on(dev);
110 else
111 netif_carrier_off(dev);
112 return 0;
113}
114
115static const struct net_device_ops dummy_netdev_ops = {
116 .ndo_init = dummy_dev_init,
117 .ndo_uninit = dummy_dev_uninit,
118 .ndo_start_xmit = dummy_xmit,
119 .ndo_validate_addr = eth_validate_addr,
120 .ndo_set_rx_mode = set_multicast_list,
121 .ndo_set_mac_address = eth_mac_addr,
122 .ndo_get_stats64 = dummy_get_stats64,
123 .ndo_change_carrier = dummy_change_carrier,
124};
125
126static void dummy_get_drvinfo(struct net_device *dev,
127 struct ethtool_drvinfo *info)
128{
129 strlcpy(info->driver, DRV_NAME, sizeof(info->driver));
130 strlcpy(info->version, DRV_VERSION, sizeof(info->version));
131}
132
133static const struct ethtool_ops dummy_ethtool_ops = {
134 .get_drvinfo = dummy_get_drvinfo,
135};
136
137static void dummy_setup(struct net_device *dev)
138{
139 ether_setup(dev);
140
141
142 dev->netdev_ops = &dummy_netdev_ops;
143 dev->ethtool_ops = &dummy_ethtool_ops;
144 dev->destructor = free_netdev;
145
146
147 dev->tx_queue_len = 0;
148 dev->flags |= IFF_NOARP;
149 dev->flags &= ~IFF_MULTICAST;
150 dev->priv_flags |= IFF_LIVE_ADDR_CHANGE;
151 dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO;
152 dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
153 eth_hw_addr_random(dev);
154}
155
156static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
157{
158 if (tb[IFLA_ADDRESS]) {
159 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
160 return -EINVAL;
161 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
162 return -EADDRNOTAVAIL;
163 }
164 return 0;
165}
166
167static struct rtnl_link_ops dummy_link_ops __read_mostly = {
168 .kind = DRV_NAME,
169 .setup = dummy_setup,
170 .validate = dummy_validate,
171};
172
173
174module_param(numdummies, int, 0);
175MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
176
177static int __init dummy_init_one(void)
178{
179 struct net_device *dev_dummy;
180 int err;
181
182 dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_UNKNOWN, dummy_setup);
183 if (!dev_dummy)
184 return -ENOMEM;
185
186 dev_dummy->rtnl_link_ops = &dummy_link_ops;
187 err = register_netdevice(dev_dummy);
188 if (err < 0)
189 goto err;
190 return 0;
191
192err:
193 free_netdev(dev_dummy);
194 return err;
195}
196
197static int __init dummy_init_module(void)
198{
199 int i, err = 0;
200
201 rtnl_lock();
202 err = __rtnl_link_register(&dummy_link_ops);
203 if (err < 0)
204 goto out;
205
206 for (i = 0; i < numdummies && !err; i++) {
207 err = dummy_init_one();
208 cond_resched();
209 }
210 if (err < 0)
211 __rtnl_link_unregister(&dummy_link_ops);
212
213out:
214 rtnl_unlock();
215
216 return err;
217}
218
219static void __exit dummy_cleanup_module(void)
220{
221 rtnl_link_unregister(&dummy_link_ops);
222}
223
224module_init(dummy_init_module);
225module_exit(dummy_cleanup_module);
226MODULE_LICENSE("GPL");
227MODULE_ALIAS_RTNL_LINK(DRV_NAME);
228MODULE_VERSION(DRV_VERSION);
229