xref: /openbmc/linux/drivers/net/netdevsim/netdev.c (revision 83c9e13aa39aed5cf9a2f8dd69770b7c35ba1281)
1*83c9e13aSJakub Kicinski /*
2*83c9e13aSJakub Kicinski  * Copyright (C) 2017 Netronome Systems, Inc.
3*83c9e13aSJakub Kicinski  *
4*83c9e13aSJakub Kicinski  * This software is licensed under the GNU General License Version 2,
5*83c9e13aSJakub Kicinski  * June 1991 as shown in the file COPYING in the top-level directory of this
6*83c9e13aSJakub Kicinski  * source tree.
7*83c9e13aSJakub Kicinski  *
8*83c9e13aSJakub Kicinski  * THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS"
9*83c9e13aSJakub Kicinski  * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
10*83c9e13aSJakub Kicinski  * BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
11*83c9e13aSJakub Kicinski  * FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE
12*83c9e13aSJakub Kicinski  * OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME
13*83c9e13aSJakub Kicinski  * THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
14*83c9e13aSJakub Kicinski  */
15*83c9e13aSJakub Kicinski 
16*83c9e13aSJakub Kicinski #include <linux/etherdevice.h>
17*83c9e13aSJakub Kicinski #include <linux/kernel.h>
18*83c9e13aSJakub Kicinski #include <linux/module.h>
19*83c9e13aSJakub Kicinski #include <linux/netdevice.h>
20*83c9e13aSJakub Kicinski #include <linux/slab.h>
21*83c9e13aSJakub Kicinski #include <net/netlink.h>
22*83c9e13aSJakub Kicinski #include <net/rtnetlink.h>
23*83c9e13aSJakub Kicinski 
24*83c9e13aSJakub Kicinski #include "netdevsim.h"
25*83c9e13aSJakub Kicinski 
26*83c9e13aSJakub Kicinski static netdev_tx_t nsim_start_xmit(struct sk_buff *skb, struct net_device *dev)
27*83c9e13aSJakub Kicinski {
28*83c9e13aSJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
29*83c9e13aSJakub Kicinski 
30*83c9e13aSJakub Kicinski 	u64_stats_update_begin(&ns->syncp);
31*83c9e13aSJakub Kicinski 	ns->tx_packets++;
32*83c9e13aSJakub Kicinski 	ns->tx_bytes += skb->len;
33*83c9e13aSJakub Kicinski 	u64_stats_update_end(&ns->syncp);
34*83c9e13aSJakub Kicinski 
35*83c9e13aSJakub Kicinski 	dev_kfree_skb(skb);
36*83c9e13aSJakub Kicinski 
37*83c9e13aSJakub Kicinski 	return NETDEV_TX_OK;
38*83c9e13aSJakub Kicinski }
39*83c9e13aSJakub Kicinski 
40*83c9e13aSJakub Kicinski static void nsim_set_rx_mode(struct net_device *dev)
41*83c9e13aSJakub Kicinski {
42*83c9e13aSJakub Kicinski }
43*83c9e13aSJakub Kicinski 
44*83c9e13aSJakub Kicinski static void
45*83c9e13aSJakub Kicinski nsim_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
46*83c9e13aSJakub Kicinski {
47*83c9e13aSJakub Kicinski 	struct netdevsim *ns = netdev_priv(dev);
48*83c9e13aSJakub Kicinski 	unsigned int start;
49*83c9e13aSJakub Kicinski 
50*83c9e13aSJakub Kicinski 	do {
51*83c9e13aSJakub Kicinski 		start = u64_stats_fetch_begin(&ns->syncp);
52*83c9e13aSJakub Kicinski 		stats->tx_bytes = ns->tx_bytes;
53*83c9e13aSJakub Kicinski 		stats->tx_packets = ns->tx_packets;
54*83c9e13aSJakub Kicinski 	} while (u64_stats_fetch_retry(&ns->syncp, start));
55*83c9e13aSJakub Kicinski }
56*83c9e13aSJakub Kicinski 
57*83c9e13aSJakub Kicinski static const struct net_device_ops nsim_netdev_ops = {
58*83c9e13aSJakub Kicinski 	.ndo_start_xmit		= nsim_start_xmit,
59*83c9e13aSJakub Kicinski 	.ndo_set_rx_mode	= nsim_set_rx_mode,
60*83c9e13aSJakub Kicinski 	.ndo_set_mac_address	= eth_mac_addr,
61*83c9e13aSJakub Kicinski 	.ndo_validate_addr	= eth_validate_addr,
62*83c9e13aSJakub Kicinski 	.ndo_get_stats64	= nsim_get_stats64,
63*83c9e13aSJakub Kicinski };
64*83c9e13aSJakub Kicinski 
65*83c9e13aSJakub Kicinski static void nsim_setup(struct net_device *dev)
66*83c9e13aSJakub Kicinski {
67*83c9e13aSJakub Kicinski 	ether_setup(dev);
68*83c9e13aSJakub Kicinski 	eth_hw_addr_random(dev);
69*83c9e13aSJakub Kicinski 
70*83c9e13aSJakub Kicinski 	dev->netdev_ops = &nsim_netdev_ops;
71*83c9e13aSJakub Kicinski 	dev->needs_free_netdev = true;
72*83c9e13aSJakub Kicinski 
73*83c9e13aSJakub Kicinski 	dev->tx_queue_len = 0;
74*83c9e13aSJakub Kicinski 	dev->flags |= IFF_NOARP;
75*83c9e13aSJakub Kicinski 	dev->flags &= ~IFF_MULTICAST;
76*83c9e13aSJakub Kicinski 	dev->priv_flags |= IFF_LIVE_ADDR_CHANGE |
77*83c9e13aSJakub Kicinski 			   IFF_NO_QUEUE;
78*83c9e13aSJakub Kicinski 	dev->features |= NETIF_F_HIGHDMA |
79*83c9e13aSJakub Kicinski 			 NETIF_F_SG |
80*83c9e13aSJakub Kicinski 			 NETIF_F_FRAGLIST |
81*83c9e13aSJakub Kicinski 			 NETIF_F_HW_CSUM |
82*83c9e13aSJakub Kicinski 			 NETIF_F_TSO;
83*83c9e13aSJakub Kicinski 	dev->max_mtu = ETH_MAX_MTU;
84*83c9e13aSJakub Kicinski }
85*83c9e13aSJakub Kicinski 
86*83c9e13aSJakub Kicinski static int nsim_validate(struct nlattr *tb[], struct nlattr *data[],
87*83c9e13aSJakub Kicinski 			 struct netlink_ext_ack *extack)
88*83c9e13aSJakub Kicinski {
89*83c9e13aSJakub Kicinski 	if (tb[IFLA_ADDRESS]) {
90*83c9e13aSJakub Kicinski 		if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
91*83c9e13aSJakub Kicinski 			return -EINVAL;
92*83c9e13aSJakub Kicinski 		if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
93*83c9e13aSJakub Kicinski 			return -EADDRNOTAVAIL;
94*83c9e13aSJakub Kicinski 	}
95*83c9e13aSJakub Kicinski 	return 0;
96*83c9e13aSJakub Kicinski }
97*83c9e13aSJakub Kicinski 
98*83c9e13aSJakub Kicinski static struct rtnl_link_ops nsim_link_ops __read_mostly = {
99*83c9e13aSJakub Kicinski 	.kind		= DRV_NAME,
100*83c9e13aSJakub Kicinski 	.priv_size	= sizeof(struct netdevsim),
101*83c9e13aSJakub Kicinski 	.setup		= nsim_setup,
102*83c9e13aSJakub Kicinski 	.validate	= nsim_validate,
103*83c9e13aSJakub Kicinski };
104*83c9e13aSJakub Kicinski 
105*83c9e13aSJakub Kicinski static int __init nsim_module_init(void)
106*83c9e13aSJakub Kicinski {
107*83c9e13aSJakub Kicinski 	return rtnl_link_register(&nsim_link_ops);
108*83c9e13aSJakub Kicinski }
109*83c9e13aSJakub Kicinski 
110*83c9e13aSJakub Kicinski static void __exit nsim_module_exit(void)
111*83c9e13aSJakub Kicinski {
112*83c9e13aSJakub Kicinski 	rtnl_link_unregister(&nsim_link_ops);
113*83c9e13aSJakub Kicinski }
114*83c9e13aSJakub Kicinski 
115*83c9e13aSJakub Kicinski module_init(nsim_module_init);
116*83c9e13aSJakub Kicinski module_exit(nsim_module_exit);
117*83c9e13aSJakub Kicinski MODULE_LICENSE("GPL");
118*83c9e13aSJakub Kicinski MODULE_ALIAS_RTNL_LINK(DRV_NAME);
119