Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net: rocker: Add support for retrieving port level statistics

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>

authored by

David Ahern and committed by
David S. Miller
9766e97a fe3ef616

+155
+134
drivers/net/ethernet/rocker/rocker.c
··· 3833 3833 strlcpy(drvinfo->version, UTS_RELEASE, sizeof(drvinfo->version)); 3834 3834 } 3835 3835 3836 + static struct rocker_port_stats { 3837 + char str[ETH_GSTRING_LEN]; 3838 + int type; 3839 + } rocker_port_stats[] = { 3840 + { "rx_packets", ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, }, 3841 + { "rx_bytes", ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, }, 3842 + { "rx_dropped", ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, }, 3843 + { "rx_errors", ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, }, 3844 + 3845 + { "tx_packets", ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, }, 3846 + { "tx_bytes", ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, }, 3847 + { "tx_dropped", ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, }, 3848 + { "tx_errors", ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, }, 3849 + }; 3850 + 3851 + #define ROCKER_PORT_STATS_LEN ARRAY_SIZE(rocker_port_stats) 3852 + 3853 + static void rocker_port_get_strings(struct net_device *netdev, u32 stringset, 3854 + u8 *data) 3855 + { 3856 + u8 *p = data; 3857 + int i; 3858 + 3859 + switch (stringset) { 3860 + case ETH_SS_STATS: 3861 + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) { 3862 + memcpy(p, rocker_port_stats[i].str, ETH_GSTRING_LEN); 3863 + p += ETH_GSTRING_LEN; 3864 + } 3865 + break; 3866 + } 3867 + } 3868 + 3869 + static int 3870 + rocker_cmd_get_port_stats_prep(struct rocker *rocker, 3871 + struct rocker_port *rocker_port, 3872 + struct rocker_desc_info *desc_info, 3873 + void *priv) 3874 + { 3875 + struct rocker_tlv *cmd_stats; 3876 + 3877 + if (rocker_tlv_put_u16(desc_info, ROCKER_TLV_CMD_TYPE, 3878 + ROCKER_TLV_CMD_TYPE_GET_PORT_STATS)) 3879 + return -EMSGSIZE; 3880 + 3881 + cmd_stats = rocker_tlv_nest_start(desc_info, ROCKER_TLV_CMD_INFO); 3882 + if (!cmd_stats) 3883 + return -EMSGSIZE; 3884 + 3885 + if (rocker_tlv_put_u32(desc_info, ROCKER_TLV_CMD_PORT_STATS_LPORT, 3886 + rocker_port->lport)) 3887 + return -EMSGSIZE; 3888 + 3889 + rocker_tlv_nest_end(desc_info, cmd_stats); 3890 + 3891 + return 0; 3892 + } 3893 + 3894 + static int 3895 + rocker_cmd_get_port_stats_ethtool_proc(struct rocker *rocker, 3896 + struct rocker_port *rocker_port, 3897 + struct rocker_desc_info *desc_info, 3898 + void *priv) 3899 + { 3900 + struct rocker_tlv *attrs[ROCKER_TLV_CMD_MAX + 1]; 3901 + struct rocker_tlv *stats_attrs[ROCKER_TLV_CMD_PORT_STATS_MAX + 1]; 3902 + struct rocker_tlv *pattr; 3903 + u32 lport; 3904 + u64 *data = priv; 3905 + int i; 3906 + 3907 + rocker_tlv_parse_desc(attrs, ROCKER_TLV_CMD_MAX, desc_info); 3908 + 3909 + if (!attrs[ROCKER_TLV_CMD_INFO]) 3910 + return -EIO; 3911 + 3912 + rocker_tlv_parse_nested(stats_attrs, ROCKER_TLV_CMD_PORT_STATS_MAX, 3913 + attrs[ROCKER_TLV_CMD_INFO]); 3914 + 3915 + if (!stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]) 3916 + return -EIO; 3917 + 3918 + lport = rocker_tlv_get_u32(stats_attrs[ROCKER_TLV_CMD_PORT_STATS_LPORT]); 3919 + if (lport != rocker_port->lport) 3920 + return -EIO; 3921 + 3922 + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); i++) { 3923 + pattr = stats_attrs[rocker_port_stats[i].type]; 3924 + if (!pattr) 3925 + continue; 3926 + 3927 + data[i] = rocker_tlv_get_u64(pattr); 3928 + } 3929 + 3930 + return 0; 3931 + } 3932 + 3933 + static int rocker_cmd_get_port_stats_ethtool(struct rocker_port *rocker_port, 3934 + void *priv) 3935 + { 3936 + return rocker_cmd_exec(rocker_port->rocker, rocker_port, 3937 + rocker_cmd_get_port_stats_prep, NULL, 3938 + rocker_cmd_get_port_stats_ethtool_proc, 3939 + priv, false); 3940 + } 3941 + 3942 + static void rocker_port_get_stats(struct net_device *dev, 3943 + struct ethtool_stats *stats, u64 *data) 3944 + { 3945 + struct rocker_port *rocker_port = netdev_priv(dev); 3946 + 3947 + if (rocker_cmd_get_port_stats_ethtool(rocker_port, data) != 0) { 3948 + int i; 3949 + 3950 + for (i = 0; i < ARRAY_SIZE(rocker_port_stats); ++i) 3951 + data[i] = 0; 3952 + } 3953 + 3954 + return; 3955 + } 3956 + 3957 + static int rocker_port_get_sset_count(struct net_device *netdev, int sset) 3958 + { 3959 + switch (sset) { 3960 + case ETH_SS_STATS: 3961 + return ROCKER_PORT_STATS_LEN; 3962 + default: 3963 + return -EOPNOTSUPP; 3964 + } 3965 + } 3966 + 3836 3967 static const struct ethtool_ops rocker_port_ethtool_ops = { 3837 3968 .get_settings = rocker_port_get_settings, 3838 3969 .set_settings = rocker_port_set_settings, 3839 3970 .get_drvinfo = rocker_port_get_drvinfo, 3840 3971 .get_link = ethtool_op_get_link, 3972 + .get_strings = rocker_port_get_strings, 3973 + .get_ethtool_stats = rocker_port_get_stats, 3974 + .get_sset_count = rocker_port_get_sset_count, 3841 3975 }; 3842 3976 3843 3977 /*****************
+21
drivers/net/ethernet/rocker/rocker.h
··· 127 127 ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_DEL, 128 128 ROCKER_TLV_CMD_TYPE_OF_DPA_GROUP_GET_STATS, 129 129 130 + ROCKER_TLV_CMD_TYPE_CLEAR_PORT_STATS, 131 + ROCKER_TLV_CMD_TYPE_GET_PORT_STATS, 132 + 130 133 __ROCKER_TLV_CMD_TYPE_MAX, 131 134 ROCKER_TLV_CMD_TYPE_MAX = __ROCKER_TLV_CMD_TYPE_MAX - 1, 132 135 }; ··· 147 144 __ROCKER_TLV_CMD_PORT_SETTINGS_MAX, 148 145 ROCKER_TLV_CMD_PORT_SETTINGS_MAX = 149 146 __ROCKER_TLV_CMD_PORT_SETTINGS_MAX - 1, 147 + }; 148 + 149 + enum { 150 + ROCKER_TLV_CMD_PORT_STATS_UNSPEC, 151 + ROCKER_TLV_CMD_PORT_STATS_LPORT, /* u32 */ 152 + 153 + ROCKER_TLV_CMD_PORT_STATS_RX_PKTS, /* u64 */ 154 + ROCKER_TLV_CMD_PORT_STATS_RX_BYTES, /* u64 */ 155 + ROCKER_TLV_CMD_PORT_STATS_RX_DROPPED, /* u64 */ 156 + ROCKER_TLV_CMD_PORT_STATS_RX_ERRORS, /* u64 */ 157 + 158 + ROCKER_TLV_CMD_PORT_STATS_TX_PKTS, /* u64 */ 159 + ROCKER_TLV_CMD_PORT_STATS_TX_BYTES, /* u64 */ 160 + ROCKER_TLV_CMD_PORT_STATS_TX_DROPPED, /* u64 */ 161 + ROCKER_TLV_CMD_PORT_STATS_TX_ERRORS, /* u64 */ 162 + 163 + __ROCKER_TLV_CMD_PORT_STATS_MAX, 164 + ROCKER_TLV_CMD_PORT_STATS_MAX = __ROCKER_TLV_CMD_PORT_STATS_MAX - 1, 150 165 }; 151 166 152 167 enum rocker_port_mode {