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->flags |= IFF_NOARP;
148 dev->flags &= ~IFF_MULTICAST;
149 dev->priv_flags |= IFF_LIVE_ADDR_CHANGE | IFF_NO_QUEUE;
150 dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST;
151 dev->features |= NETIF_F_ALL_TSO | NETIF_F_UFO;
152 dev->features |= NETIF_F_HW_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
153 dev->features |= NETIF_F_GSO_ENCAP_ALL;
154 dev->hw_features |= dev->features;
155 dev->hw_enc_features |= dev->features;
156 eth_hw_addr_random(dev);
157
158 dev->min_mtu = 0;
159 dev->max_mtu = ETH_MAX_MTU;
160}
161
162static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
163{
164 if (tb[IFLA_ADDRESS]) {
165 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
166 return -EINVAL;
167 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
168 return -EADDRNOTAVAIL;
169 }
170 return 0;
171}
172
173static struct rtnl_link_ops dummy_link_ops __read_mostly = {
174 .kind = DRV_NAME,
175 .setup = dummy_setup,
176 .validate = dummy_validate,
177};
178
179
180module_param(numdummies, int, 0);
181MODULE_PARM_DESC(numdummies, "Number of dummy pseudo devices");
182
183static int __init dummy_init_one(void)
184{
185 struct net_device *dev_dummy;
186 int err;
187
188 dev_dummy = alloc_netdev(0, "dummy%d", NET_NAME_UNKNOWN, dummy_setup);
189 if (!dev_dummy)
190 return -ENOMEM;
191
192 dev_dummy->rtnl_link_ops = &dummy_link_ops;
193 err = register_netdevice(dev_dummy);
194 if (err < 0)
195 goto err;
196 return 0;
197
198err:
199 free_netdev(dev_dummy);
200 return err;
201}
202
203static int __init dummy_init_module(void)
204{
205 int i, err = 0;
206
207 rtnl_lock();
208 err = __rtnl_link_register(&dummy_link_ops);
209 if (err < 0)
210 goto out;
211
212 for (i = 0; i < numdummies && !err; i++) {
213 err = dummy_init_one();
214 cond_resched();
215 }
216 if (err < 0)
217 __rtnl_link_unregister(&dummy_link_ops);
218
219out:
220 rtnl_unlock();
221
222 return err;
223}
224
225static void __exit dummy_cleanup_module(void)
226{
227 rtnl_link_unregister(&dummy_link_ops);
228}
229
230module_init(dummy_init_module);
231module_exit(dummy_cleanup_module);
232MODULE_LICENSE("GPL");
233MODULE_ALIAS_RTNL_LINK(DRV_NAME);
234MODULE_VERSION(DRV_VERSION);
235