* [PATCH] Interface Stat Clearing Framework, skge support, ethtool support
@ 2006-04-30 3:16 Phil Dibowitz
0 siblings, 0 replies; only message in thread
From: Phil Dibowitz @ 2006-04-30 3:16 UTC (permalink / raw)
To: netdev
[-- Attachment #1.1: Type: text/plain, Size: 1305 bytes --]
Hey folks,
A few months back I posted an in-progress patch for adding a clear_stats
framework similar to the get_stats framework and implimenting support
for it in the skge driver (the one NIC I have access to), as well as
adding the ethtool support for it.
While a few people said they didn't see the need for it, other people
did see the need for it, and I know it's a common request on many
sysadmin mailing lists I'm on.
Since no one seemed to have any technical issue with the patch, I've
cleaned up the patch, tested it, and fixed a few minor issues.
Unless someone has an objection, I'd think this would be useful to a lot
of people.
There are two patches attached:
interface_stats_clear.patch - the kernel patch against 2.6.17-rc3-git2
ethtool3-clearstats.patch - the ethtool patch to add the -z flag to
support it.
If the kernel patch gets accepted I'll send a more complete ethtool
patch with documentation updates, etc.
Thanks.
--
Phil Dibowitz phil@ipom.com
Freeware and Technical Pages Insanity Palace of Metallica
http://www.phildev.net/ http://www.ipom.com/
"Be who you are and say what you feel, because those who mind don't
matter and those who matter don't mind."
- Dr. Suess
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.2: interface_stats_clear.patch --]
[-- Type: text/x-patch; name="interface_stats_clear.patch", Size: 6417 bytes --]
This patch adds support for clearing interface statistics using the ethtool interface adding a new 0x23 command. It adds a clear_stats function pointer to the net_device struct, and then impliments local functions in the driver much the say get_stats works. The ethtool funtion pointer points to the same functions. The driver-local functions are currently only implimented in the skge driver.
Signed-off-by: Phil Dibowitz <phil@ipom.com>
---
diff -puN include/linux/netdevice.h~interface_stats_clear include/linux/netdevice.h
--- linux-2.6.17-rc3-git2/include/linux/netdevice.h~interface_stats_clear 2006-04-29 19:44:41.000000000 -0700
+++ linux-2.6.17-rc3-git2-phil/include/linux/netdevice.h 2006-04-29 19:44:41.000000000 -0700
@@ -319,6 +319,7 @@ struct net_device
struct net_device_stats* (*get_stats)(struct net_device *dev);
+ void (*clear_stats)(struct net_device *dev);
struct iw_statistics* (*get_wireless_stats)(struct net_device *dev);
/* List of functions to handle Wireless Extensions (instead of ioctl).
diff -puN drivers/net/skge.c~interface_stats_clear drivers/net/skge.c
--- linux-2.6.17-rc3-git2/drivers/net/skge.c~interface_stats_clear 2006-04-29 19:44:41.000000000 -0700
+++ linux-2.6.17-rc3-git2-phil/drivers/net/skge.c 2006-04-29 19:44:41.000000000 -0700
@@ -44,7 +44,7 @@
#include "skge.h"
#define DRV_NAME "skge"
-#define DRV_VERSION "1.5"
+#define DRV_VERSION "1.6"
#define PFX DRV_NAME " "
#define DEFAULT_TX_RING_SIZE 128
@@ -97,6 +97,8 @@ static int xm_phy_write(struct skge_hw *
static int gm_phy_write(struct skge_hw *hw, int port, u16 reg, u16 val);
static void genesis_get_stats(struct skge_port *skge, u64 *data);
static void yukon_get_stats(struct skge_port *skge, u64 *data);
+static void genesis_clear_stats(struct skge_port *skge);
+static void yukon_clear_stats(struct skge_port *skge);
static void yukon_init(struct skge_hw *hw, int port);
static void genesis_mac_init(struct skge_hw *hw, int port);
static void genesis_link_up(struct skge_port *skge);
@@ -366,6 +368,15 @@ static struct net_device_stats *skge_get
return &skge->net_stats;
}
+static void skge_clear_stats(struct net_device *dev)
+{
+ struct skge_port *skge = netdev_priv(dev);
+ if (skge->hw->chip_id == CHIP_ID_GENESIS)
+ genesis_clear_stats(skge);
+ else
+ yukon_clear_stats(skge);
+}
+
static void skge_get_strings(struct net_device *dev, u32 stringset, u8 *data)
{
int i;
@@ -722,6 +733,7 @@ static struct ethtool_ops skge_ethtool_o
.phys_id = skge_phys_id,
.get_stats_count = skge_get_stats_count,
.get_ethtool_stats = skge_get_ethtool_stats,
+ .clear_ethtool_stats = skge_clear_stats,
.get_perm_addr = ethtool_op_get_perm_addr,
};
@@ -1383,6 +1395,20 @@ static void genesis_get_stats(struct skg
data[i] = xm_read32(hw, port, skge_stats[i].xmac_offset);
}
+static void genesis_clear_stats(struct skge_port *skge)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+
+ /*
+ * This is based on reading other parts of the driver
+ * and is not yet tested.
+ */
+
+ xm_write16(hw, port, XM_STAT_CMD, 0 | XM_SC_CLR_RXC
+ | XM_SC_CLR_TXC);
+}
+
static void genesis_mac_intr(struct skge_hw *hw, int port)
{
struct skge_port *skge = netdev_priv(hw->dev[port]);
@@ -1871,6 +1897,21 @@ static void yukon_get_stats(struct skge_
skge_stats[i].gma_offset);
}
+static void yukon_clear_stats(struct skge_port *skge)
+{
+ struct skge_hw *hw = skge->hw;
+ int port = skge->port;
+ u16 reg;
+ int i;
+
+ reg = gma_read16(hw, port, GM_PHY_ADDR);
+ /* this read is important, or we sometimes get no effect */
+ gma_write16(hw, port, GM_PHY_ADDR, reg | GM_PAR_MIB_CLR);
+ for (i = 0; i < GM_MIB_CNT_SIZE; i++)
+ gma_read16(hw, port, GM_MIB_CNT_BASE + 8*i);
+ gma_write16(hw, port, GM_PHY_ADDR, reg);
+}
+
static void yukon_mac_intr(struct skge_hw *hw, int port)
{
struct net_device *dev = hw->dev[port];
@@ -3183,6 +3224,7 @@ static struct net_device *skge_devinit(s
dev->do_ioctl = skge_ioctl;
dev->hard_start_xmit = skge_xmit_frame;
dev->get_stats = skge_get_stats;
+ dev->clear_stats = skge_clear_stats;
if (hw->chip_id == CHIP_ID_GENESIS)
dev->set_multicast_list = genesis_set_multicast;
else
diff -puN include/linux/ethtool.h~interface_stats_clear include/linux/ethtool.h
--- linux-2.6.17-rc3-git2/include/linux/ethtool.h~interface_stats_clear 2006-04-29 19:44:41.000000000 -0700
+++ linux-2.6.17-rc3-git2-phil/include/linux/ethtool.h 2006-04-29 19:44:41.000000000 -0700
@@ -365,6 +365,7 @@ struct ethtool_ops {
int (*phys_id)(struct net_device *, u32);
int (*get_stats_count)(struct net_device *);
void (*get_ethtool_stats)(struct net_device *, struct ethtool_stats *, u64 *);
+ void (*clear_ethtool_stats)(struct net_device *);
int (*get_perm_addr)(struct net_device *, struct ethtool_perm_addr *, u8 *);
int (*begin)(struct net_device *);
void (*complete)(struct net_device *);
@@ -408,6 +409,7 @@ struct ethtool_ops {
#define ETHTOOL_GPERMADDR 0x00000020 /* Get permanent hardware address */
#define ETHTOOL_GUFO 0x00000021 /* Get UFO enable (ethtool_value) */
#define ETHTOOL_SUFO 0x00000022 /* Set UFO enable (ethtool_value) */
+#define ETHTOOL_CSTATS 0x00000023 /* Clear NIC-specific statistics */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
diff -puN net/core/ethtool.c~interface_stats_clear net/core/ethtool.c
--- linux-2.6.17-rc3-git2/net/core/ethtool.c~interface_stats_clear 2006-04-29 19:44:41.000000000 -0700
+++ linux-2.6.17-rc3-git2-phil/net/core/ethtool.c 2006-04-29 19:44:41.000000000 -0700
@@ -741,6 +741,17 @@ static int ethtool_get_stats(struct net_
return ret;
}
+static int ethtool_clear_stats(struct net_device *dev, void __user *useraddr)
+{
+ struct ethtool_ops *ops = dev->ethtool_ops;
+ if (!ops->clear_ethtool_stats)
+ return -EOPNOTSUPP;
+
+ ops->clear_ethtool_stats(dev);
+
+ return 0;
+}
+
static int ethtool_get_perm_addr(struct net_device *dev, void __user *useraddr)
{
struct ethtool_perm_addr epaddr;
@@ -906,6 +917,9 @@ int dev_ethtool(struct ifreq *ifr)
case ETHTOOL_SUFO:
rc = ethtool_set_ufo(dev, useraddr);
break;
+ case ETHTOOL_CSTATS:
+ rc = ethtool_clear_stats(dev, useraddr);
+ break;
default:
rc = -EOPNOTSUPP;
}
_
[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1.3: ethtool3-clearstats.patch --]
[-- Type: text/x-patch; name="ethtool3-clearstats.patch", Size: 3683 bytes --]
--- ethtool-3/ethtool.c.b4phil 2006-04-29 19:01:18.000000000 -0700
+++ ethtool-3/ethtool.c 2006-04-29 19:01:36.000000000 -0700
@@ -66,6 +66,7 @@
static int do_goffload(int fd, struct ifreq *ifr);
static int do_soffload(int fd, struct ifreq *ifr);
static int do_gstats(int fd, struct ifreq *ifr);
+static int do_cstats(int fd, struct ifreq *ifr);
static int send_ioctl(int fd, struct ifreq *ifr);
static int check_for_pre24_kernel();
@@ -242,6 +243,7 @@
MODE_GOFFLOAD,
MODE_SOFFLOAD,
MODE_GSTATS,
+ MODE_CSTATS,
} mode = MODE_GSET;
static int goffload_changed = 0;
@@ -470,6 +472,8 @@
mode = MODE_TEST;
else if (!strcmp(argp[i], "-S"))
mode = MODE_GSTATS;
+ else if (!strcmp(argp[i], "-z"))
+ mode = MODE_CSTATS;
else if (!strcmp(argp[i], "-h"))
show_usage(0);
else
@@ -492,6 +496,7 @@
(mode == MODE_GOFFLOAD) ||
(mode == MODE_SOFFLOAD) ||
(mode == MODE_GSTATS) ||
+ (mode == MODE_CSTATS) ||
(mode == MODE_PHYS_ID)) {
devname = argp[i];
break;
@@ -1266,6 +1271,8 @@
return do_soffload(fd, &ifr);
} else if (mode == MODE_GSTATS) {
return do_gstats(fd, &ifr);
+ } else if (mode == MODE_CSTATS) {
+ return do_cstats(fd, &ifr);
}
return 69;
@@ -2010,6 +2017,79 @@
return 0;
}
+static int do_cstats(int fd, struct ifreq *ifr)
+{
+ struct ethtool_drvinfo drvinfo;
+ struct ethtool_gstrings *strings;
+ struct ethtool_stats *stats;
+ unsigned int n_stats, sz_str, sz_stats, i;
+ int err;
+
+ drvinfo.cmd = ETHTOOL_GDRVINFO;
+ ifr->ifr_data = (caddr_t)&drvinfo;
+ err = send_ioctl(fd, ifr);
+ if (err < 0) {
+ perror("Cannot get driver information");
+ return 71;
+ }
+
+ n_stats = drvinfo.n_stats;
+ if (n_stats < 1) {
+ fprintf(stderr, "no stats available\n");
+ return 94;
+ }
+
+ sz_str = n_stats * ETH_GSTRING_LEN;
+ sz_stats = n_stats * sizeof(u64);
+
+ strings = calloc(1, sz_str + sizeof(struct ethtool_gstrings));
+ stats = calloc(1, sz_stats + sizeof(struct ethtool_stats));
+ if (!strings || !stats) {
+ fprintf(stderr, "no memory available\n");
+ return 95;
+ }
+
+ strings->cmd = ETHTOOL_GSTRINGS;
+ strings->string_set = ETH_SS_STATS;
+ strings->len = n_stats;
+ ifr->ifr_data = (caddr_t) strings;
+ err = send_ioctl(fd, ifr);
+ if (err < 0) {
+ perror("Cannot get stats strings information");
+ free(strings);
+ free(stats);
+ return 96;
+ }
+
+ stats->cmd = ETHTOOL_CSTATS;
+ stats->n_stats = n_stats;
+ ifr->ifr_data = (caddr_t) stats;
+ err = send_ioctl(fd, ifr);
+ if (err < 0) {
+ perror("Cannot get stats information");
+ free(strings);
+ free(stats);
+ return 97;
+ }
+
+ /* todo - pretty-print the strings per-driver */
+ /*
+ fprintf(stdout, "NIC statistics:\n");
+ for (i = 0; i < n_stats; i++) {
+ char s[ETH_GSTRING_LEN];
+
+ strncpy(s, &strings->data[i * ETH_GSTRING_LEN],
+ ETH_GSTRING_LEN);
+ fprintf(stdout, " %s: %llu\n",
+ s, stats->data[i]);
+ }
+ */
+ free(strings);
+ free(stats);
+
+ return 0;
+}
+
static int send_ioctl(int fd, struct ifreq *ifr)
{
int err;
--- ethtool-3/ethtool-copy.h.b4phil 2006-04-29 19:01:26.000000000 -0700
+++ ethtool-3/ethtool-copy.h 2006-04-29 19:01:36.000000000 -0700
@@ -283,6 +283,7 @@
#define ETHTOOL_GSTATS 0x0000001d /* get NIC-specific statistics */
#define ETHTOOL_GTSO 0x0000001e /* Get TSO enable (ethtool_value) */
#define ETHTOOL_STSO 0x0000001f /* Set TSO enable (ethtool_value) */
+#define ETHTOOL_CSTATS 0x00000023 /* get NIC-specific statistics */
/* compatibility with older code */
#define SPARC_ETH_GSET ETHTOOL_GSET
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 252 bytes --]
^ permalink raw reply [flat|nested] only message in thread
only message in thread, other threads:[~2006-04-30 3:17 UTC | newest]
Thread overview: (only message) (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-04-30 3:16 [PATCH] Interface Stat Clearing Framework, skge support, ethtool support Phil Dibowitz
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.