Commit 6d81f41c authored by Eric Dumazet's avatar Eric Dumazet Committed by David S. Miller

dummy: percpu stats and lockless xmit

Converts dummy network device driver to :

- percpu stats

- 64bit stats

- lockless xmit (NETIF_F_LLTX)

- performance features added (NETIF_F_SG | NETIF_F_FRAGLIST |
NETIF_F_TSO | NETIF_F_NO_CSUM | NETIF_F_HIGHDMA)
Signed-off-by: default avatarEric Dumazet <eric.dumazet@gmail.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 745e20f1
...@@ -36,6 +36,7 @@ ...@@ -36,6 +36,7 @@
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <net/rtnetlink.h> #include <net/rtnetlink.h>
#include <linux/u64_stats_sync.h>
static int numdummies = 1; static int numdummies = 1;
...@@ -55,21 +56,69 @@ static void set_multicast_list(struct net_device *dev) ...@@ -55,21 +56,69 @@ static void set_multicast_list(struct net_device *dev)
{ {
} }
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;
}
static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev)
{ {
dev->stats.tx_packets++; struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats);
dev->stats.tx_bytes += skb->len;
u64_stats_update_begin(&dstats->syncp);
dstats->tx_packets++;
dstats->tx_bytes += skb->len;
u64_stats_update_end(&dstats->syncp);
dev_kfree_skb(skb); dev_kfree_skb(skb);
return NETDEV_TX_OK; return NETDEV_TX_OK;
} }
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);
}
static const struct net_device_ops dummy_netdev_ops = { static const struct net_device_ops dummy_netdev_ops = {
.ndo_init = dummy_dev_init,
.ndo_start_xmit = dummy_xmit, .ndo_start_xmit = dummy_xmit,
.ndo_validate_addr = eth_validate_addr, .ndo_validate_addr = eth_validate_addr,
.ndo_set_multicast_list = set_multicast_list, .ndo_set_multicast_list = set_multicast_list,
.ndo_set_mac_address = dummy_set_address, .ndo_set_mac_address = dummy_set_address,
.ndo_get_stats64 = dummy_get_stats64,
}; };
static void dummy_setup(struct net_device *dev) static void dummy_setup(struct net_device *dev)
...@@ -78,14 +127,17 @@ static void dummy_setup(struct net_device *dev) ...@@ -78,14 +127,17 @@ static void dummy_setup(struct net_device *dev)
/* Initialize the device structure. */ /* Initialize the device structure. */
dev->netdev_ops = &dummy_netdev_ops; dev->netdev_ops = &dummy_netdev_ops;
dev->destructor = free_netdev; dev->destructor = dummy_dev_free;
/* Fill in device structure with ethernet-generic values. */ /* Fill in device structure with ethernet-generic values. */
dev->tx_queue_len = 0; dev->tx_queue_len = 0;
dev->flags |= IFF_NOARP; dev->flags |= IFF_NOARP;
dev->flags &= ~IFF_MULTICAST; dev->flags &= ~IFF_MULTICAST;
dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO;
dev->features |= NETIF_F_NO_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX;
random_ether_addr(dev->dev_addr); random_ether_addr(dev->dev_addr);
} }
static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) static int dummy_validate(struct nlattr *tb[], struct nlattr *data[])
{ {
if (tb[IFLA_ADDRESS]) { if (tb[IFLA_ADDRESS]) {
......
...@@ -1057,6 +1057,7 @@ struct net_device { ...@@ -1057,6 +1057,7 @@ struct net_device {
void *ml_priv; void *ml_priv;
struct pcpu_lstats __percpu *lstats; /* loopback stats */ struct pcpu_lstats __percpu *lstats; /* loopback stats */
struct pcpu_tstats __percpu *tstats; /* tunnel stats */ struct pcpu_tstats __percpu *tstats; /* tunnel stats */
struct pcpu_dstats __percpu *dstats; /* dummy stats */
}; };
/* GARP */ /* GARP */
struct garp_port *garp_port; struct garp_port *garp_port;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment