summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid S. Miller <davem@davemloft.net>2016-02-06 02:59:58 -0500
committerDavid S. Miller <davem@davemloft.net>2016-02-06 02:59:58 -0500
commitdf03288bb49a7da9023de5d9e4dabd882db3abd7 (patch)
tree4536c2f822bead6d91e90c5a7ad7c2d828f6e5c7
parent817298102b0bc936b08dfcc5fbcc2213157050f2 (diff)
parentf344b0d940d2da88c23b864f818da43081ce300f (diff)
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: Jarod Wilson <jarod@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--drivers/net/bonding/bond_main.c1
-rw-r--r--drivers/net/team/team.c10
-rw-r--r--include/linux/if_team.h1
-rw-r--r--include/linux/netdevice.h3
-rw-r--r--include/uapi/linux/if_link.h4
-rw-r--r--net/core/dev.c25
-rw-r--r--net/core/net-sysfs.c2
-rw-r--r--net/core/rtnetlink.c2
8 files changed, 38 insertions, 10 deletions
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index 56b560558884..6587929b040a 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -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_errors += sstats->rx_errors - pstats->rx_errors;
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_bytes += sstats->tx_bytes - pstats->tx_bytes;
diff --git a/drivers/net/team/team.c b/drivers/net/team/team.c
index 718ceeab4dbc..00558e139584 100644
--- a/drivers/net/team/team.c
+++ b/drivers/net/team/team.c
@@ -758,6 +758,8 @@ static rx_handler_result_t team_handle_frame(struct sk_buff **pskb)
u64_stats_update_end(&pcpu_stats->syncp);
skb->dev = team->dev;
+ } else if (res == RX_HANDLER_EXACT) {
+ this_cpu_inc(team->pcpu_stats->rx_nohandler);
} else {
this_cpu_inc(team->pcpu_stats->rx_dropped);
}
@@ -1807,7 +1809,7 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
struct team *team = netdev_priv(dev);
struct team_pcpu_stats *p;
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;
int i;
@@ -1828,14 +1830,16 @@ team_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats)
stats->tx_packets += tx_packets;
stats->tx_bytes += tx_bytes;
/*
- * rx_dropped & tx_dropped are u32, updated
- * without syncp protection.
+ * rx_dropped, tx_dropped & rx_nohandler are u32,
+ * updated without syncp protection.
*/
rx_dropped += p->rx_dropped;
tx_dropped += p->tx_dropped;
+ rx_nohandler += p->rx_nohandler;
}
stats->rx_dropped = rx_dropped;
stats->tx_dropped = tx_dropped;
+ stats->rx_nohandler = rx_nohandler;
return stats;
}
diff --git a/include/linux/if_team.h b/include/linux/if_team.h
index b84e49c3a738..174f43f43aff 100644
--- a/include/linux/if_team.h
+++ b/include/linux/if_team.h
@@ -24,6 +24,7 @@ struct team_pcpu_stats {
struct u64_stats_sync syncp;
u32 rx_dropped;
u32 tx_dropped;
+ u32 rx_nohandler;
};
struct team;
diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h
index 289c2314d766..78a20cec2a0a 100644
--- a/include/linux/netdevice.h
+++ b/include/linux/netdevice.h
@@ -1397,6 +1397,8 @@ enum netdev_priv_flags {
* do not use this in drivers
* @tx_dropped: Dropped packets by core network,
* 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,
* instead of ioctl,
@@ -1611,6 +1613,7 @@ struct net_device {
atomic_long_t rx_dropped;
atomic_long_t tx_dropped;
+ atomic_long_t rx_nohandler;
#ifdef CONFIG_WIRELESS_EXT
const struct iw_handler_def * wireless_handlers;
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index a30b78090594..d3e90b91e07e 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -35,6 +35,8 @@ struct rtnl_link_stats {
/* for cslip etc */
__u32 rx_compressed;
__u32 tx_compressed;
+
+ __u32 rx_nohandler; /* dropped, no handler found */
};
/* The main device statistics structure */
@@ -68,6 +70,8 @@ struct rtnl_link_stats64 {
/* for cslip etc */
__u64 rx_compressed;
__u64 tx_compressed;
+
+ __u64 rx_nohandler; /* dropped, no handler found */
};
/* The struct should be in sync with struct ifmap */
diff --git a/net/core/dev.c b/net/core/dev.c
index 8cba3d852f25..f1284835b8c9 100644
--- a/net/core/dev.c
+++ b/net/core/dev.c
@@ -4154,7 +4154,10 @@ ncls:
ret = pt_prev->func(skb, skb->dev, pt_prev, orig_dev);
} else {
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);
/* Jamal, now you will not able to escape explaining
* me how you were going to use this. :-)
@@ -7253,24 +7256,31 @@ void netdev_run_todo(void)
}
}
-/* Convert net_device_stats to rtnl_link_stats64. They have the same
- * fields in the same order, with only the type differing.
+/* Convert net_device_stats to rtnl_link_stats64. rtnl_link_stats64 has
+ * 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,
const struct net_device_stats *netdev_stats)
{
#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));
+ /* zero out counters that only exist in rtnl_link_stats64 */
+ memset((char *)stats64 + sizeof(*netdev_stats), 0,
+ sizeof(*stats64) - sizeof(*netdev_stats));
#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;
u64 *dst = (u64 *)stats64;
- BUILD_BUG_ON(sizeof(*netdev_stats) / sizeof(unsigned long) !=
- sizeof(*stats64) / sizeof(u64));
+ BUILD_BUG_ON(n > sizeof(*stats64) / sizeof(u64));
for (i = 0; i < n; 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
}
EXPORT_SYMBOL(netdev_stats_to_stats64);
@@ -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->tx_dropped += atomic_long_read(&dev->tx_dropped);
+ storage->rx_nohandler += atomic_long_read(&dev->rx_nohandler);
return storage;
}
EXPORT_SYMBOL(dev_get_stats);
diff --git a/net/core/net-sysfs.c b/net/core/net-sysfs.c
index b6c8a6629b39..da7dbc237a5f 100644
--- a/net/core/net-sysfs.c
+++ b/net/core/net-sysfs.c
@@ -574,6 +574,7 @@ NETSTAT_ENTRY(tx_heartbeat_errors);
NETSTAT_ENTRY(tx_window_errors);
NETSTAT_ENTRY(rx_compressed);
NETSTAT_ENTRY(tx_compressed);
+NETSTAT_ENTRY(rx_nohandler);
static struct attribute *netstat_attrs[] = {
&dev_attr_rx_packets.attr,
@@ -599,6 +600,7 @@ static struct attribute *netstat_attrs[] = {
&dev_attr_tx_window_errors.attr,
&dev_attr_rx_compressed.attr,
&dev_attr_tx_compressed.attr,
+ &dev_attr_rx_nohandler.attr,
NULL
};
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c
index d735e854f916..20d71358c143 100644
--- a/net/core/rtnetlink.c
+++ b/net/core/rtnetlink.c
@@ -804,6 +804,8 @@ static void copy_rtnl_link_stats(struct rtnl_link_stats *a,
a->rx_compressed = b->rx_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)