Resending this - saw no response. 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 [EMAIL PROTECTED] 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
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 <[EMAIL PROTECTED]> --- 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; } _
--- 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
signature.asc
Description: OpenPGP digital signature