diff options
author | Eric Dumazet <eric.dumazet@gmail.com> | 2010-09-27 16:50:33 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2010-09-29 16:23:30 -0400 |
commit | 6d81f41c58c69ddde497e9e640ba5805aa26e78c (patch) | |
tree | 9e4cadd10af9f487fabb99a393f095d185160a13 /drivers/net/dummy.c | |
parent | 745e20f1b626b1be4b100af5d4bf7b3439392f8f (diff) |
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>
Diffstat (limited to 'drivers/net/dummy.c')
-rw-r--r-- | drivers/net/dummy.c | 58 |
1 files changed, 55 insertions, 3 deletions
diff --git a/drivers/net/dummy.c b/drivers/net/dummy.c index 37dcfdc63456..ff2d29b17858 100644 --- a/drivers/net/dummy.c +++ b/drivers/net/dummy.c | |||
@@ -36,6 +36,7 @@ | |||
36 | #include <linux/moduleparam.h> | 36 | #include <linux/moduleparam.h> |
37 | #include <linux/rtnetlink.h> | 37 | #include <linux/rtnetlink.h> |
38 | #include <net/rtnetlink.h> | 38 | #include <net/rtnetlink.h> |
39 | #include <linux/u64_stats_sync.h> | ||
39 | 40 | ||
40 | static int numdummies = 1; | 41 | static int numdummies = 1; |
41 | 42 | ||
@@ -55,21 +56,69 @@ static void set_multicast_list(struct net_device *dev) | |||
55 | { | 56 | { |
56 | } | 57 | } |
57 | 58 | ||
59 | struct pcpu_dstats { | ||
60 | u64 tx_packets; | ||
61 | u64 tx_bytes; | ||
62 | struct u64_stats_sync syncp; | ||
63 | }; | ||
64 | |||
65 | static struct rtnl_link_stats64 *dummy_get_stats64(struct net_device *dev, | ||
66 | struct rtnl_link_stats64 *stats) | ||
67 | { | ||
68 | int i; | ||
69 | |||
70 | for_each_possible_cpu(i) { | ||
71 | const struct pcpu_dstats *dstats; | ||
72 | u64 tbytes, tpackets; | ||
73 | unsigned int start; | ||
74 | |||
75 | dstats = per_cpu_ptr(dev->dstats, i); | ||
76 | do { | ||
77 | start = u64_stats_fetch_begin(&dstats->syncp); | ||
78 | tbytes = dstats->tx_bytes; | ||
79 | tpackets = dstats->tx_packets; | ||
80 | } while (u64_stats_fetch_retry(&dstats->syncp, start)); | ||
81 | stats->tx_bytes += tbytes; | ||
82 | stats->tx_packets += tpackets; | ||
83 | } | ||
84 | return stats; | ||
85 | } | ||
58 | 86 | ||
59 | static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) | 87 | static netdev_tx_t dummy_xmit(struct sk_buff *skb, struct net_device *dev) |
60 | { | 88 | { |
61 | dev->stats.tx_packets++; | 89 | struct pcpu_dstats *dstats = this_cpu_ptr(dev->dstats); |
62 | dev->stats.tx_bytes += skb->len; | 90 | |
91 | u64_stats_update_begin(&dstats->syncp); | ||
92 | dstats->tx_packets++; | ||
93 | dstats->tx_bytes += skb->len; | ||
94 | u64_stats_update_end(&dstats->syncp); | ||
63 | 95 | ||
64 | dev_kfree_skb(skb); | 96 | dev_kfree_skb(skb); |
65 | return NETDEV_TX_OK; | 97 | return NETDEV_TX_OK; |
66 | } | 98 | } |
67 | 99 | ||
100 | static int dummy_dev_init(struct net_device *dev) | ||
101 | { | ||
102 | dev->dstats = alloc_percpu(struct pcpu_dstats); | ||
103 | if (!dev->dstats) | ||
104 | return -ENOMEM; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | static void dummy_dev_free(struct net_device *dev) | ||
110 | { | ||
111 | free_percpu(dev->dstats); | ||
112 | free_netdev(dev); | ||
113 | } | ||
114 | |||
68 | static const struct net_device_ops dummy_netdev_ops = { | 115 | static const struct net_device_ops dummy_netdev_ops = { |
116 | .ndo_init = dummy_dev_init, | ||
69 | .ndo_start_xmit = dummy_xmit, | 117 | .ndo_start_xmit = dummy_xmit, |
70 | .ndo_validate_addr = eth_validate_addr, | 118 | .ndo_validate_addr = eth_validate_addr, |
71 | .ndo_set_multicast_list = set_multicast_list, | 119 | .ndo_set_multicast_list = set_multicast_list, |
72 | .ndo_set_mac_address = dummy_set_address, | 120 | .ndo_set_mac_address = dummy_set_address, |
121 | .ndo_get_stats64 = dummy_get_stats64, | ||
73 | }; | 122 | }; |
74 | 123 | ||
75 | static void dummy_setup(struct net_device *dev) | 124 | static void dummy_setup(struct net_device *dev) |
@@ -78,14 +127,17 @@ static void dummy_setup(struct net_device *dev) | |||
78 | 127 | ||
79 | /* Initialize the device structure. */ | 128 | /* Initialize the device structure. */ |
80 | dev->netdev_ops = &dummy_netdev_ops; | 129 | dev->netdev_ops = &dummy_netdev_ops; |
81 | dev->destructor = free_netdev; | 130 | dev->destructor = dummy_dev_free; |
82 | 131 | ||
83 | /* Fill in device structure with ethernet-generic values. */ | 132 | /* Fill in device structure with ethernet-generic values. */ |
84 | dev->tx_queue_len = 0; | 133 | dev->tx_queue_len = 0; |
85 | dev->flags |= IFF_NOARP; | 134 | dev->flags |= IFF_NOARP; |
86 | dev->flags &= ~IFF_MULTICAST; | 135 | dev->flags &= ~IFF_MULTICAST; |
136 | dev->features |= NETIF_F_SG | NETIF_F_FRAGLIST | NETIF_F_TSO; | ||
137 | dev->features |= NETIF_F_NO_CSUM | NETIF_F_HIGHDMA | NETIF_F_LLTX; | ||
87 | random_ether_addr(dev->dev_addr); | 138 | random_ether_addr(dev->dev_addr); |
88 | } | 139 | } |
140 | |||
89 | static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) | 141 | static int dummy_validate(struct nlattr *tb[], struct nlattr *data[]) |
90 | { | 142 | { |
91 | if (tb[IFLA_ADDRESS]) { | 143 | if (tb[IFLA_ADDRESS]) { |