Skip to content

Commit

Permalink
net: rocker: Add support for retrieving port level statistics
Browse files Browse the repository at this point in the history
Add support for retrieving port level statistics from device.
Hook is added for ethtool's stats functionality. For example,

$ ethtool -S eth3
NIC statistics:
     rx_packets: 12
     rx_bytes: 2790
     rx_dropped: 0
     rx_errors: 0
     tx_packets: 8
     tx_bytes: 728
     tx_dropped: 0
     tx_errors: 0

Signed-off-by: David Ahern <dsahern@gmail.com>
Acked-by: Scott Feldman <sfeldma@gmail.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David Ahern authored and David S. Miller committed Feb 2, 2015
1 parent fe3ef61 commit 9766e97
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 0 deletions.
134 changes: 134 additions & 0 deletions drivers/net/ethernet/rocker/rocker.c
Original file line number Diff line number Diff line change
Expand Up @@ -3833,11 +3833,145 @@ static void rocker_port_get_drvinfo(struct net_device *dev,
strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version));
}

static struct rocker_port_stats {
char str[ETH_GSTRING_LEN];
int type;
} rocker_port_stats[] = {
{ "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, },
{ "rx_bytes", ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, },
{ "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, },
{ "rx_errors", ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, },

{ "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, },
{ "tx_bytes", ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, },
{ "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, },
{ "tx_errors", ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, },
};

#define ROCKER_PORT_STATS_LEN ARRAY_SIZE(rocker_port_stats)

static void rocker_port_get_strings(struct net_device *netdev, u32 stringset,
u8 *data)
{
u8 *p = data;
int i;

switch (stringset) {
case ETH_SS_STATS:
for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN);
p += ETH_GSTRING_LEN;
}
break;
}
}

static int
rocker_cmd_get_port_stats_prep(struct rocker *rocker,
struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
struct rocker_tlv *cmd_stats;

if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE,
ROCKER_TLV_CMD_TYPE_GET_PORT_STATS))
return -EMSGSIZE;

cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO);
if (!cmd_stats)
return -EMSGSIZE;

if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_LPORT,
rocker_port->lport))
return -EMSGSIZE;

rocker_tlv_nest_end(desc_info, cmd_stats);

return 0;
}

static int
rocker_cmd_get_port_stats_ethtool_proc(struct rocker *rocker,
struct rocker_port *rocker_port,
struct rocker_desc_info *desc_info,
void *priv)
{
struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1];
struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1];
struct rocker_tlv *pattr;
u32 lport;
u64 *data = priv;
int i;

rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info);

if (!attrs[ROCKER_TLV_CMD_INFO])
return -EIO;

rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX,
attrs[ROCKER_TLV_CMD_INFO]);

if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT])
return -EIO;

lport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]);
if (lport != rocker_port->lport)
return -EIO;

for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) {
pattr = stats_attrs[rocker_port_stats[i].type];
if (!pattr)
continue;

data[i] = rocker_tlv_get_u64(pattr);
}

return 0;
}

static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port,
void *priv)
{
return rocker_cmd_exec(rocker_port->rocker, rocker_port,
rocker_cmd_get_port_stats_prep, NULL,
rocker_cmd_get_port_stats_ethtool_proc,
priv, false);
}

static void rocker_port_get_stats(struct net_device *dev,
struct ethtool_stats *stats, u64 *data)
{
struct rocker_port *rocker_port = netdev_priv(dev);

if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) {
int i;

for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i)
data[i] = 0;
}

return;
}

static int rocker_port_get_sset_count(struct net_device *netdev, int sset)
{
switch (sset) {
case ETH_SS_STATS:
return ROCKER_PORT_STATS_LEN;
default:
return -EOPNOTSUPP;
}
}

static const struct ethtool_ops rocker_port_ethtool_ops = {
.get_settings = rocker_port_get_settings,
.set_settings = rocker_port_set_settings,
.get_drvinfo = rocker_port_get_drvinfo,
.get_link = ethtool_op_get_link,
.get_strings = rocker_port_get_strings,
.get_ethtool_stats = rocker_port_get_stats,
.get_sset_count = rocker_port_get_sset_count,
};

/*****************
Expand Down
21 changes: 21 additions & 0 deletions drivers/net/ethernet/rocker/rocker.h
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,9 @@ enum {
ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL,
ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS,

ROCKER_TLV_CMD_TYPE_CLEAR_PORT_STATS,
ROCKER_TLV_CMD_TYPE_GET_PORT_STATS,

__ROCKER_TLV_CMD_TYPE_MAX,
ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1,
};
Expand All @@ -146,6 +149,24 @@ enum {
__ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1,
};

enum {
ROCKER_TLV_CMD_PORT_STATS_UNSPEC,
ROCKER_TLV_CMD_PORT_STATS_LPORT, /* u32 */

ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, /* u64 */
ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, /* u64 */
ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, /* u64 */
ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, /* u64 */

ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, /* u64 */
ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, /* u64 */
ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, /* u64 */
ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, /* u64 */

__ROCKER_TLV_CMD_PORT_STATS_MAX,
ROCKER_TLV_CMD_PORT_STATS_MAX = __ROCKER_TLV_CMD_PORT_STATS_MAX - 1,
};

enum rocker_port_mode {
ROCKER_PORT_MODE_OF_DPA,
};
Expand Down

0 comments on commit 9766e97

Please sign in to comment.