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: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
745e20f1b6
commit
6d81f41c58
|
@ -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)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
/* 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 {
|
||||||
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;
|
||||||
|
|
Reference in New Issue