netdev.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Eric Dumazet <eric.dumazet@gmail.com>
To: "David S. Miller" <davem@davemloft.net>
Cc: Linux Netdev List <netdev@vger.kernel.org>,
	Patrick McHardy <kaber@trash.net>
Subject: [PATCH net-next-2.6] macvlan: Precise RX stats accounting
Date: Tue, 17 Nov 2009 19:53:49 +0100	[thread overview]
Message-ID: <4B02F13D.1060903@gmail.com> (raw)

David, here is the macvlan part as well, it also depends on 
dev_txq_stats_fold() being added first.

Thanks

[PATCH net-next-2.6] macvlan: Precise RX stats accounting

With multi queue devices, its possible that several cpus call
macvlan RX routines simultaneously for the same macvlan device.

We update RX stats counter without any locking, so we can
get slightly wrong counters.

One possible fix is to use percpu counters, to get precise
accounting and also get guarantee of no cache line ping pongs
between cpus.

Note: this adds 16 bytes (32 bytes on 64bit arches) of percpu
data per macvlan device.

Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
---
 drivers/net/macvlan.c |   76 ++++++++++++++++++++++++++++++++++------
 1 files changed, 66 insertions(+), 10 deletions(-)

diff --git a/drivers/net/macvlan.c b/drivers/net/macvlan.c
index 271aa7e..f2389a2 100644
--- a/drivers/net/macvlan.c
+++ b/drivers/net/macvlan.c
@@ -38,12 +38,27 @@ struct macvlan_port {
 	struct list_head	vlans;
 };
 
+/**
+ *	struct macvlan_rx_stats - MACVLAN percpu rx stats
+ *	@rx_packets: number of received packets
+ *	@rx_bytes: number of received bytes
+ *	@multicast: number of received multicast packets
+ *	@rx_errors: number of errors
+ */
+struct macvlan_rx_stats {
+	unsigned long rx_packets;
+	unsigned long rx_bytes;
+	unsigned long multicast;
+	unsigned long rx_errors;
+};
+
 struct macvlan_dev {
 	struct net_device	*dev;
 	struct list_head	list;
 	struct hlist_node	hlist;
 	struct macvlan_port	*port;
 	struct net_device	*lowerdev;
+	struct macvlan_rx_stats *rx_stats;
 };
 
 
@@ -110,6 +125,7 @@ static void macvlan_broadcast(struct sk_buff *skb,
 	struct net_device *dev;
 	struct sk_buff *nskb;
 	unsigned int i;
+	struct macvlan_rx_stats *rx_stats;
 
 	if (skb->protocol == htons(ETH_P_PAUSE))
 		return;
@@ -117,17 +133,17 @@ static void macvlan_broadcast(struct sk_buff *skb,
 	for (i = 0; i < MACVLAN_HASH_SIZE; i++) {
 		hlist_for_each_entry_rcu(vlan, n, &port->vlan_hash[i], hlist) {
 			dev = vlan->dev;
+			rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
 
 			nskb = skb_clone(skb, GFP_ATOMIC);
 			if (nskb == NULL) {
-				dev->stats.rx_errors++;
-				dev->stats.rx_dropped++;
+				rx_stats->rx_errors++;
 				continue;
 			}
 
-			dev->stats.rx_bytes += skb->len + ETH_HLEN;
-			dev->stats.rx_packets++;
-			dev->stats.multicast++;
+			rx_stats->rx_bytes += skb->len + ETH_HLEN;
+			rx_stats->rx_packets++;
+			rx_stats->multicast++;
 
 			nskb->dev = dev;
 			if (!compare_ether_addr_64bits(eth->h_dest, dev->broadcast))
@@ -147,6 +163,7 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
 	const struct macvlan_port *port;
 	const struct macvlan_dev *vlan;
 	struct net_device *dev;
+	struct macvlan_rx_stats *rx_stats;
 
 	port = rcu_dereference(skb->dev->macvlan_port);
 	if (port == NULL)
@@ -166,16 +183,15 @@ static struct sk_buff *macvlan_handle_frame(struct sk_buff *skb)
 		kfree_skb(skb);
 		return NULL;
 	}
-
+	rx_stats = per_cpu_ptr(vlan->rx_stats, smp_processor_id());
 	skb = skb_share_check(skb, GFP_ATOMIC);
 	if (skb == NULL) {
-		dev->stats.rx_errors++;
-		dev->stats.rx_dropped++;
+		rx_stats->rx_errors++;
 		return NULL;
 	}
 
-	dev->stats.rx_bytes += skb->len + ETH_HLEN;
-	dev->stats.rx_packets++;
+	rx_stats->rx_bytes += skb->len + ETH_HLEN;
+	rx_stats->rx_packets++;
 
 	skb->dev = dev;
 	skb->pkt_type = PACKET_HOST;
@@ -365,9 +381,47 @@ static int macvlan_init(struct net_device *dev)
 
 	macvlan_set_lockdep_class(dev);
 
+	vlan->rx_stats = alloc_percpu(struct macvlan_rx_stats);
+	if (!vlan->rx_stats)
+		return -ENOMEM;
+
 	return 0;
 }
 
+static void macvlan_uninit(struct net_device *dev)
+{
+	struct macvlan_dev *vlan = netdev_priv(dev);
+
+	free_percpu(vlan->rx_stats);
+}
+
+static struct net_device_stats *macvlan_dev_get_stats(struct net_device *dev)
+{
+	struct net_device_stats *stats = &dev->stats;
+	struct macvlan_dev *vlan = netdev_priv(dev);
+
+	dev_txq_stats_fold(dev, stats);
+
+	if (vlan->rx_stats) {
+		struct macvlan_rx_stats *p, rx = {0};
+		int i;
+
+		for_each_possible_cpu(i) {
+			p = per_cpu_ptr(vlan->rx_stats, i);
+			rx.rx_packets += p->rx_packets;
+			rx.rx_bytes   += p->rx_bytes;
+			rx.rx_errors  += p->rx_errors;
+			rx.multicast  += p->multicast;
+		}
+		stats->rx_packets = rx.rx_packets;
+		stats->rx_bytes   = rx.rx_bytes;
+		stats->rx_errors  = rx.rx_errors;
+		stats->rx_dropped = rx.rx_errors;
+		stats->multicast  = rx.multicast;
+	}
+	return stats;
+}
+
 static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
 					struct ethtool_drvinfo *drvinfo)
 {
@@ -404,6 +458,7 @@ static const struct ethtool_ops macvlan_ethtool_ops = {
 
 static const struct net_device_ops macvlan_netdev_ops = {
 	.ndo_init		= macvlan_init,
+	.ndo_uninit		= macvlan_uninit,
 	.ndo_open		= macvlan_open,
 	.ndo_stop		= macvlan_stop,
 	.ndo_start_xmit		= macvlan_start_xmit,
@@ -411,6 +466,7 @@ static const struct net_device_ops macvlan_netdev_ops = {
 	.ndo_change_rx_flags	= macvlan_change_rx_flags,
 	.ndo_set_mac_address	= macvlan_set_mac_address,
 	.ndo_set_multicast_list	= macvlan_set_multicast_list,
+	.ndo_get_stats		= macvlan_dev_get_stats,
 	.ndo_validate_addr	= eth_validate_addr,
 };
 

             reply	other threads:[~2009-11-17 18:53 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-11-17 18:53 Eric Dumazet [this message]
2009-11-18  7:53 ` [PATCH net-next-2.6] macvlan: Precise RX stats accounting David Miller

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=4B02F13D.1060903@gmail.com \
    --to=eric.dumazet@gmail.com \
    --cc=davem@davemloft.net \
    --cc=kaber@trash.net \
    --cc=netdev@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).