Commit df03288b authored by David S. Miller's avatar David S. Miller

Merge branch 'rx_nohandler'

Jarod Wilson says:

====================
net: add and use rx_nohandler stat counter

The network core tries to keep track of dropped packets, but some packets
you wouldn't really call dropped, so much as intentionally ignored, under
certain circumstances. One such case is that of bonding and team device
slaves that are currently inactive. Their respective rx_handler functions
return RX_HANDLER_EXACT (the only places in the kernel that return that),
which ends up tracking into the network core's __netif_receive_skb_core()
function's drop path, with no pt_prev set. On a noisy network, this can
result in a very rapidly incrementing rx_dropped counter, not only on the
inactive slave(s), but also on the master device, such as the following:

$ cat /proc/net/dev
Inter-|   Receive                                                |  Transmit
 face |bytes    packets errs drop fifo frame compressed multicast|bytes    packets errs drop fifo colls carrier compressed
  p7p1: 14783346  140430    0 140428    0     0          0      2040      680       8    0    0    0     0       0          0
  p7p2: 14805198  140648    0    0    0     0          0      2034        0       0    0    0    0     0       0          0
 bond0: 53365248  532798    0 421160    0     0          0    115151     2040      24    0    0    0     0       0          0
    lo:    5420      54    0    0    0     0          0         0     5420      54    0    0    0     0       0          0
  p5p1: 19292195  196197    0 140368    0     0          0     56564      680       8    0    0    0     0       0          0
  p5p2: 19289707  196171    0 140364    0     0          0     56547      680       8    0    0    0     0       0          0
   em3: 20996626  158214    0    0    0     0          0       383        0       0    0    0    0     0       0          0
   em2: 14065122  138462    0    0    0     0          0       310        0       0    0    0    0     0       0          0
   em1: 14063162  138440    0    0    0     0          0       308        0       0    0    0    0     0       0          0
   em4: 21050830  158729    0    0    0     0          0       385    71662     469    0    0    0     0       0          0
   ib0:       0       0    0    0    0     0          0         0        0       0    0    0    0     0       0          0

In this scenario, p5p1, p5p2 and p7p1 are all inactive slaves in an
active-backup bond0, and you can see that all three have high drop counts,
with the master bond0 showing a tally of all three.

I know that this was previously discussed some here:

    http://www.spinics.net/lists/netdev/msg226341.html

It seems additional counters never came to fruition, so this is a first
attempt at creating one of them, so that we stop calling these drops,
which for users monitoring rx_dropped, causes great alarm, and renders the
counter much less useful for them.

This adds a sysfs statistics node and makes the counter available via
netlink.

Additionally, I'm not certain if this set qualifies for net, or if it
should be put aside and resubmitted for net-next after 4.5 is put to
bed, but I do have users who consider this an important bugfix.

This has been tested quite a bit on x86_64, and now lightly on i686 as
well, to verify functionality of updates to netdev_stats_to_stats64()
on 32-bit arches.
====================
Signed-off-by: default avatarJarod Wilson <jarod@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 81729810 f344b0d9
...@@ -3309,6 +3309,7 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev, ...@@ -3309,6 +3309,7 @@ static struct rtnl_link_stats64 *bond_get_stats(struct net_device *bond_dev,
stats->rx_bytes += sstats->rx_bytes - pstats->rx_bytes; stats->rx_bytes += sstats->rx_bytes - pstats->rx_bytes;
stats->rx_errors += sstats->rx_errors - pstats->rx_errors; stats->rx_errors += sstats->rx_errors - pstats->rx_errors;
stats->rx_dropped += sstats->rx_dropped - pstats->rx_dropped; stats->rx_dropped += sstats->rx_dropped - pstats->rx_dropped;
stats->rx_nohandler += sstats->rx_nohandler - pstats->rx_nohandler;
stats->tx_packets += sstats->tx_packets - pstats->tx_packets;; stats->tx_packets += sstats->tx_packets - pstats->tx_packets;;
stats->tx_bytes += sstats->tx_bytes - pstats->tx_bytes; stats->tx_bytes += sstats->tx_bytes - pstats->tx_bytes;
......
...@@ -758,6 +758,8 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb) ...@@ -758,6 +758,8 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
u64_stats_update_end(&pcpu_stats->syncp); u64_stats_update_end(&pcpu_stats->syncp);
skb->dev = team->dev; skb->dev = team->dev;
} else if (res == RX_HANDLER_EXACT) {
this_cpu_inc(team->pcpu_stats->rx_nohandler);
} else { } else {
this_cpu_inc(team->pcpu_stats->rx_dropped); this_cpu_inc(team->pcpu_stats->rx_dropped);
} }
...@@ -1807,7 +1809,7 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) ...@@ -1807,7 +1809,7 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
struct team *team = netdev_priv(dev); struct team *team = netdev_priv(dev);
struct team_pcpu_stats *p; struct team_pcpu_stats *p;
u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes; u64 rx_packets, rx_bytes, rx_multicast, tx_packets, tx_bytes;
u32 rx_dropped = 0, tx_dropped = 0; u32 rx_dropped = 0, tx_dropped = 0, rx_nohandler = 0;
unsigned int start; unsigned int start;
int i; int i;
...@@ -1828,14 +1830,16 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats) ...@@ -1828,14 +1830,16 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
stats->tx_packets += tx_packets; stats->tx_packets += tx_packets;
stats->tx_bytes += tx_bytes; stats->tx_bytes += tx_bytes;
/* /*
* rx_dropped & tx_dropped are u32, updated * rx_dropped, tx_dropped & rx_nohandler are u32,
* without syncp protection. * updated without syncp protection.
*/ */
rx_dropped += p->rx_dropped; rx_dropped += p->rx_dropped;
tx_dropped += p->tx_dropped; tx_dropped += p->tx_dropped;
rx_nohandler += p->rx_nohandler;
} }
stats->rx_dropped = rx_dropped; stats->rx_dropped = rx_dropped;
stats->tx_dropped = tx_dropped; stats->tx_dropped = tx_dropped;
stats->rx_nohandler = rx_nohandler;
return stats; return stats;
} }
......
...@@ -24,6 +24,7 @@ struct team_pcpu_stats { ...@@ -24,6 +24,7 @@ struct team_pcpu_stats {
struct u64_stats_sync syncp; struct u64_stats_sync syncp;
u32 rx_dropped; u32 rx_dropped;
u32 tx_dropped; u32 tx_dropped;
u32 rx_nohandler;
}; };
struct team; struct team;
......
...@@ -1397,6 +1397,8 @@ enum netdev_priv_flags { ...@@ -1397,6 +1397,8 @@ enum netdev_priv_flags {
* do not use this in drivers * do not use this in drivers
* @tx_dropped: Dropped packets by core network, * @tx_dropped: Dropped packets by core network,
* do not use this in drivers * do not use this in drivers
* @rx_nohandler: nohandler dropped packets by core network on
* inactive devices, do not use this in drivers
* *
* @wireless_handlers: List of functions to handle Wireless Extensions, * @wireless_handlers: List of functions to handle Wireless Extensions,
* instead of ioctl, * instead of ioctl,
...@@ -1611,6 +1613,7 @@ struct net_device { ...@@ -1611,6 +1613,7 @@ struct net_device {
atomic_long_t rx_dropped; atomic_long_t rx_dropped;
atomic_long_t tx_dropped; atomic_long_t tx_dropped;
atomic_long_t rx_nohandler;
#ifdef CONFIG_WIRELESS_EXT #ifdef CONFIG_WIRELESS_EXT
const struct iw_handler_def * wireless_handlers; const struct iw_handler_def * wireless_handlers;
......
...@@ -35,6 +35,8 @@ struct rtnl_link_stats { ...@@ -35,6 +35,8 @@ struct rtnl_link_stats {
/* for cslip etc */ /* for cslip etc */
__u32 rx_compressed; __u32 rx_compressed;
__u32 tx_compressed; __u32 tx_compressed;
__u32 rx_nohandler; /* dropped, no handler found */
}; };
/* The main device statistics structure */ /* The main device statistics structure */
...@@ -68,6 +70,8 @@ struct rtnl_link_stats64 { ...@@ -68,6 +70,8 @@ struct rtnl_link_stats64 {
/* for cslip etc */ /* for cslip etc */
__u64 rx_compressed; __u64 rx_compressed;
__u64 tx_compressed; __u64 tx_compressed;
__u64 rx_nohandler; /* dropped, no handler found */
}; };
/* The struct should be in sync with struct ifmap */ /* The struct should be in sync with struct ifmap */
......
...@@ -4154,7 +4154,10 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc) ...@@ -4154,7 +4154,10 @@ static int __netif_receive_skb_core(struct sk_buff *skb, bool pfmemalloc)
ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev); ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
} else { } else {
drop: drop:
atomic_long_inc(&skb->dev->rx_dropped); if (!deliver_exact)
atomic_long_inc(&skb->dev->rx_dropped);
else
atomic_long_inc(&skb->dev->rx_nohandler);
kfree_skb(skb); kfree_skb(skb);
/* Jamal, now you will not able to escape explaining /* Jamal, now you will not able to escape explaining
* me how you were going to use this. :-) * me how you were going to use this. :-)
...@@ -7253,24 +7256,31 @@ void netdev_run_todo(void) ...@@ -7253,24 +7256,31 @@ void netdev_run_todo(void)
} }
} }
/* Convert net_device_stats to rtnl_link_stats64. They have the same /* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has
* fields in the same order, with only the type differing. * all the same fields in the same order as net_device_stats, with only
* the type differing, but rtnl_link_stats64 may have additional fields
* at the end for newer counters.
*/ */
void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64, void netdev_stats_to_stats64(struct rtnl_link_stats64 *stats64,
const struct net_device_stats *netdev_stats) const struct net_device_stats *netdev_stats)
{ {
#if BITS_PER_LONG == 64 #if BITS_PER_LONG == 64
BUILD_BUG_ON(sizeof(*stats64) != sizeof(*netdev_stats)); BUILD_BUG_ON(sizeof(*stats64) < sizeof(*netdev_stats));
memcpy(stats64, netdev_stats, sizeof(*stats64)); memcpy(stats64, netdev_stats, sizeof(*stats64));
/* zero out counters that only exist in rtnl_link_stats64 */
memset((char *)stats64 + sizeof(*netdev_stats), 0,
sizeof(*stats64) - sizeof(*netdev_stats));
#else #else
size_t i, n = sizeof(*stats64) / sizeof(u64); size_t i, n = sizeof(*netdev_stats) / sizeof(unsigned long);
const unsigned long *src = (const unsigned long *)netdev_stats; const unsigned long *src = (const unsigned long *)netdev_stats;
u64 *dst = (u64 *)stats64; u64 *dst = (u64 *)stats64;
BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) != BUILD_BUG_ON(n > sizeof(*stats64) / sizeof(u64));
sizeof(*stats64) / sizeof(u64));
for (i = 0; i < n; i++) for (i = 0; i < n; i++)
dst[i] = src[i]; dst[i] = src[i];
/* zero out counters that only exist in rtnl_link_stats64 */
memset((char *)stats64 + n * sizeof(u64), 0,
sizeof(*stats64) - n * sizeof(u64));
#endif #endif
} }
EXPORT_SYMBOL(netdev_stats_to_stats64); EXPORT_SYMBOL(netdev_stats_to_stats64);
...@@ -7300,6 +7310,7 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev, ...@@ -7300,6 +7310,7 @@ struct rtnl_link_stats64 *dev_get_stats(struct net_device *dev,
} }
storage->rx_dropped += atomic_long_read(&dev->rx_dropped); storage->rx_dropped += atomic_long_read(&dev->rx_dropped);
storage->tx_dropped += atomic_long_read(&dev->tx_dropped); storage->tx_dropped += atomic_long_read(&dev->tx_dropped);
storage->rx_nohandler += atomic_long_read(&dev->rx_nohandler);
return storage; return storage;
} }
EXPORT_SYMBOL(dev_get_stats); EXPORT_SYMBOL(dev_get_stats);
......
...@@ -574,6 +574,7 @@ NETSTAT_ENTRY(tx_heartbeat_errors); ...@@ -574,6 +574,7 @@ NETSTAT_ENTRY(tx_heartbeat_errors);
NETSTAT_ENTRY(tx_window_errors); NETSTAT_ENTRY(tx_window_errors);
NETSTAT_ENTRY(rx_compressed); NETSTAT_ENTRY(rx_compressed);
NETSTAT_ENTRY(tx_compressed); NETSTAT_ENTRY(tx_compressed);
NETSTAT_ENTRY(rx_nohandler);
static struct attribute *netstat_attrs[] = { static struct attribute *netstat_attrs[] = {
&dev_attr_rx_packets.attr, &dev_attr_rx_packets.attr,
...@@ -599,6 +600,7 @@ static struct attribute *netstat_attrs[] = { ...@@ -599,6 +600,7 @@ static struct attribute *netstat_attrs[] = {
&dev_attr_tx_window_errors.attr, &dev_attr_tx_window_errors.attr,
&dev_attr_rx_compressed.attr, &dev_attr_rx_compressed.attr,
&dev_attr_tx_compressed.attr, &dev_attr_tx_compressed.attr,
&dev_attr_rx_nohandler.attr,
NULL NULL
}; };
......
...@@ -804,6 +804,8 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a, ...@@ -804,6 +804,8 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
a->rx_compressed = b->rx_compressed; a->rx_compressed = b->rx_compressed;
a->tx_compressed = b->tx_compressed; a->tx_compressed = b->tx_compressed;
a->rx_nohandler = b->rx_nohandler;
} }
static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b) static void copy_rtnl_link_stats64(void *v, const struct rtnl_link_stats64 *b)
......
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