diff options
Diffstat (limited to 'drivers/net/ifb.c')
| -rw-r--r-- | drivers/net/ifb.c | 57 | 
1 files changed, 48 insertions, 9 deletions
diff --git a/drivers/net/ifb.c b/drivers/net/ifb.c index 4fecaed67fc..6e82dd32e80 100644 --- a/drivers/net/ifb.c +++ b/drivers/net/ifb.c @@ -32,6 +32,7 @@  #include <linux/netdevice.h>  #include <linux/etherdevice.h>  #include <linux/init.h> +#include <linux/interrupt.h>  #include <linux/moduleparam.h>  #include <net/pkt_sched.h>  #include <net/net_namespace.h> @@ -40,8 +41,16 @@  struct ifb_private {  	struct tasklet_struct   ifb_tasklet;  	int     tasklet_pending; + +	struct u64_stats_sync	rsync;  	struct sk_buff_head     rq; +	u64 rx_packets; +	u64 rx_bytes; + +	struct u64_stats_sync	tsync;  	struct sk_buff_head     tq; +	u64 tx_packets; +	u64 tx_bytes;  };  static int numifbs = 2; @@ -53,10 +62,8 @@ static int ifb_close(struct net_device *dev);  static void ri_tasklet(unsigned long dev)  { -  	struct net_device *_dev = (struct net_device *)dev;  	struct ifb_private *dp = netdev_priv(_dev); -	struct net_device_stats *stats = &_dev->stats;  	struct netdev_queue *txq;  	struct sk_buff *skb; @@ -76,15 +83,18 @@ static void ri_tasklet(unsigned long dev)  		skb->tc_verd = 0;  		skb->tc_verd = SET_TC_NCLS(skb->tc_verd); -		stats->tx_packets++; -		stats->tx_bytes +=skb->len; + +		u64_stats_update_begin(&dp->tsync); +		dp->tx_packets++; +		dp->tx_bytes += skb->len; +		u64_stats_update_end(&dp->tsync);  		rcu_read_lock();  		skb->dev = dev_get_by_index_rcu(&init_net, skb->skb_iif);  		if (!skb->dev) {  			rcu_read_unlock();  			dev_kfree_skb(skb); -			stats->tx_dropped++; +			_dev->stats.tx_dropped++;  			if (skb_queue_len(&dp->tq) != 0)  				goto resched;  			break; @@ -119,9 +129,37 @@ resched:  } +static struct rtnl_link_stats64 *ifb_stats64(struct net_device *dev, +					     struct rtnl_link_stats64 *stats) +{ +	struct ifb_private *dp = netdev_priv(dev); +	unsigned int start; + +	do { +		start = u64_stats_fetch_begin_bh(&dp->rsync); +		stats->rx_packets = dp->rx_packets; +		stats->rx_bytes = dp->rx_bytes; +	} while (u64_stats_fetch_retry_bh(&dp->rsync, start)); + +	do { +		start = u64_stats_fetch_begin_bh(&dp->tsync); + +		stats->tx_packets = dp->tx_packets; +		stats->tx_bytes = dp->tx_bytes; + +	} while (u64_stats_fetch_retry_bh(&dp->tsync, start)); + +	stats->rx_dropped = dev->stats.rx_dropped; +	stats->tx_dropped = dev->stats.tx_dropped; + +	return stats; +} + +  static const struct net_device_ops ifb_netdev_ops = {  	.ndo_open	= ifb_open,  	.ndo_stop	= ifb_close, +	.ndo_get_stats64 = ifb_stats64,  	.ndo_start_xmit	= ifb_xmit,  	.ndo_validate_addr = eth_validate_addr,  }; @@ -152,15 +190,16 @@ static void ifb_setup(struct net_device *dev)  static netdev_tx_t ifb_xmit(struct sk_buff *skb, struct net_device *dev)  {  	struct ifb_private *dp = netdev_priv(dev); -	struct net_device_stats *stats = &dev->stats;  	u32 from = G_TC_FROM(skb->tc_verd); -	stats->rx_packets++; -	stats->rx_bytes+=skb->len; +	u64_stats_update_begin(&dp->rsync); +	dp->rx_packets++; +	dp->rx_bytes += skb->len; +	u64_stats_update_end(&dp->rsync);  	if (!(from & (AT_INGRESS|AT_EGRESS)) || !skb->skb_iif) {  		dev_kfree_skb(skb); -		stats->rx_dropped++; +		dev->stats.rx_dropped++;  		return NETDEV_TX_OK;  	}  | 
