diff --git a/Makefile b/Makefile index 8d4da630d5a9471c617e6ae67d6ae6e77a39902c..0e994ea96dacce08136737ef69c1e24576ab55d6 100644 --- a/Makefile +++ b/Makefile @@ -24,12 +24,12 @@ objs_lib += econet/econet.o econet/ecnt_prvt.o LIBS += -lapi_lib_switchmgr endif -ifeq ($(PLATFORM),IPQ95XX) -objs_lib += ipq95xx/ipq95xx.o +ifeq ($(PLATFORM),LINUX) +objs_lib += linux/common/common_eth.o linux/linux/linux_eth.o endif -ifeq ($(PLATFORM),LINUX) -objs_lib += linux/linux_eth.o +ifeq ($(PLATFORM),MEDIATEK) +objs_lib += linux/common/common_eth.o linux/mtk/mtk_eth.o endif all: libethernet.so diff --git a/ethernet.c b/ethernet.c index fb73ec3260042bfc26e0ea8a4f0e43fdb4b972a1..8c81568fd9ab3fd778f4f205f125e2d21a93cb69 100644 --- a/ethernet.c +++ b/ethernet.c @@ -47,8 +47,8 @@ extern const struct eth_ops test_eth_ops; extern const struct eth_ops econet_gen_eth_ops; extern const struct eth_ops econet_nas_wan_eth_ops; extern const struct eth_ops econet_ae_wan_eth_ops; -#elif defined(IPQ95XX) -extern const struct eth_ops ipq95xx_eth_ops; +#elif defined(IOPSYS_MEDIATEK) +extern const struct eth_ops mtk_eth_ops; #elif defined(IOPSYS_LINUX) extern const struct eth_ops linux_eth_ops; #else @@ -64,8 +64,8 @@ const struct eth_ops *eth_ops[] = { &econet_gen_eth_ops, &econet_nas_wan_eth_ops, &econet_ae_wan_eth_ops, -#elif defined(IPQ95XX) - &ipq95xx_eth_ops, +#elif defined(IOPSYS_MEDIATEK) + &mtk_eth_ops #elif defined(IOPSYS_LINUX) &linux_eth_ops, #else diff --git a/ipq95xx/ipq95xx.c b/ipq95xx/ipq95xx.c deleted file mode 100644 index a6b6c1c69cb699d38cef769bc24a5c7bc81552b9..0000000000000000000000000000000000000000 --- a/ipq95xx/ipq95xx.c +++ /dev/null @@ -1,139 +0,0 @@ -/* - * ipq95xx.c - */ - -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <stdint.h> -#include <errno.h> -#include <ctype.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <net/if.h> -#include <time.h> -#include <syslog.h> -#include <unistd.h> -#include <stdlib.h> -#include <linux/mii.h> -#include <linux/ethtool.h> -#include <linux/sockios.h> -#include <easy/easy.h> - -#include "../ethernet.h" - -#include "ipq95xx.h" - -int ipq95xx_eth_set_link_settings(const char *ifname, struct eth_link link) -{ - struct { - struct ethtool_link_settings req; - __u32 link_mode_data[3 * 32 * 127]; - } ecmd; - - memset(&ecmd, 0, sizeof(struct ethtool_link_settings)); - - if (ipq95xx_eth_get_link_settings(ifname, &link)) - return -1; - - ecmd.req.cmd = ETHTOOL_SLINKSETTINGS; - - ecmd.req.port = link.portid; - ecmd.req.speed = link.speed; - ecmd.req.autoneg = (link.autoneg == 0 ? false : true); - ecmd.req.duplex = (link.fullduplex == 1 ? false : true); - - if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings))) - return -1; - return 0; -} - -int ipq95xx_eth_get_link_settings(const char *ifname, struct eth_link *link) -{ - struct { - struct ethtool_link_settings req; - __u32 link_mode_data[3 * 32 * 127]; - } ecmd; - - memset(&ecmd, 0, sizeof(struct ethtool_link_settings)); - - ecmd.req.cmd = ETHTOOL_GLINKSETTINGS; - - if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings))) - return -1; - - if (ecmd.req.link_mode_masks_nwords >= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS) - return -1; - - ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords; - - if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings))) - return -1; - - if (ecmd.req.link_mode_masks_nwords <= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS) - return -1; - - link->portid = ecmd.req.port; - link->speed = ecmd.req.speed; - link->autoneg = ecmd.req.autoneg == 0 ? false : true; - link->fullduplex = ecmd.req.duplex == 1 ? false : true; - - return 0; -} - -int ipq95xx_eth_poweron_phy(const char *ifname, struct eth_phy p) -{ - libethernet_err("%s(): TODO\n", __func__); - return 0; -} - -int ipq95xx_eth_poweroff_phy(const char *ifname, struct eth_phy p) -{ - libethernet_err("%s(): TODO\n", __func__); - return 0; -} - -int ipq95xx_eth_reset_phy(const char *ifname, int phy_id) -{ - return eth_mii_reset_phy(ifname, phy_id); -} - -int ipq95xx_eth_get_stats(const char *ifname, struct eth_stats *s) -{ - struct if_stats ifstats; - - memset(&ifstats, 0, sizeof(struct if_stats)); - - if (if_getstats(ifname, &ifstats) < 0) - return -1; - - s->rx_packets = ifstats.rx_packets; - s->tx_packets = ifstats.tx_packets; - s->rx_bytes = ifstats.rx_bytes; - s->tx_bytes = ifstats.tx_bytes; - s->rx_errors = ifstats.rx_errors; - s->tx_errors = ifstats.tx_errors; - s->rx_discard_packets = ifstats.rx_dropped; - s->tx_discard_packets = ifstats.tx_dropped; - - return 0; -} - -int ipq95xx_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon) -{ - libethernet_err("%s(): TODO\n", __func__); - return 0; -} - -const struct eth_ops ipq95xx_eth_ops = { - .ifname = "eth", - .set_link_settings = ipq95xx_eth_set_link_settings, - .get_link_settings = ipq95xx_eth_get_link_settings, - .get_stats = ipq95xx_eth_get_stats, - .get_rmon_stats = ipq95xx_eth_get_rmon_stats, - .poweron_phy = ipq95xx_eth_poweron_phy, - .poweroff_phy = ipq95xx_eth_poweroff_phy, - .reset_phy = ipq95xx_eth_reset_phy, -}; diff --git a/ipq95xx/ipq95xx.h b/ipq95xx/ipq95xx.h deleted file mode 100644 index 6017ae2e22c8d4825f458f9fcf3ed3662781b59b..0000000000000000000000000000000000000000 --- a/ipq95xx/ipq95xx.h +++ /dev/null @@ -1,20 +0,0 @@ -#ifndef IPQ95XX -#define IPQ95XX - -#ifdef __cplusplus -extern "C" { -#endif - -int ipq95xx_eth_set_link_settings(const char *ifname, struct eth_link link); -int ipq95xx_eth_get_link_settings(const char *ifname, struct eth_link *link); -int ipq95xx_eth_poweron_phy(const char *ifname, struct eth_phy p); -int ipq95xx_eth_poweroff_phy(const char *ifname, struct eth_phy p); -int ipq95xx_eth_reset_phy(const char *ifname, int phy_id); -int ipq95xx_eth_get_stats(const char *ifname, struct eth_stats *s); -int ipq95xx_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon); - -#ifdef __cplusplus -} -#endif - -#endif /* IPQ95XX */ diff --git a/linux/common/common_eth.c b/linux/common/common_eth.c new file mode 100644 index 0000000000000000000000000000000000000000..3b1c12a02e233215807e97d193da5f0279d4cebf --- /dev/null +++ b/linux/common/common_eth.c @@ -0,0 +1,62 @@ +/* + * common_eth.c - Linux based statistics collection ubus methods. + * + * Copyright (C) 2023 iopsys Software Solutions AB. All rights reserved. + * + * Author: padmalochan.mohapatra@iopsys.eu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <ctype.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <time.h> +#include <syslog.h> +#include <unistd.h> +#include <stdlib.h> +#include <linux/ethtool.h> +#include <linux/sockios.h> +#include <easy/easy.h> +#include <easy/if_utils.h> +#include "ethernet.h" +#include "../linux/linux_eth.h" +#include "../mtk/mtk_eth.h" + +#if defined(IOPSYS_MEDIATEK) +const struct eth_ops mtk_eth_ops = { + .ifname = "lan", + .get_stats = mtk_eth_get_stats, + .get_rmon_stats = mtk_eth_get_rmon_stats, +#elif defined(IOPSYS_LINUX) +const struct eth_ops linux_eth_ops = { + .ifname = "eth", + .set_link_settings = linux_eth_set_link_settings, + .get_link_settings = linux_eth_get_link_settings, + .poweron_phy = linux_eth_poweron_phy, + .poweroff_phy = linux_eth_poweroff_phy, + .reset_phy = linux_eth_reset_phy, + .get_stats = linux_eth_get_stats, + .get_rmon_stats = linux_eth_get_rmon_stats, +#endif +}; diff --git a/linux/linux/linux_eth.c b/linux/linux/linux_eth.c new file mode 100644 index 0000000000000000000000000000000000000000..e03b7762083cc9a7d6774af004f478c5609b1157 --- /dev/null +++ b/linux/linux/linux_eth.c @@ -0,0 +1,348 @@ +/* + * linux_eth.c + */ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <ctype.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <time.h> +#include <syslog.h> +#include <unistd.h> +#include <stdlib.h> +#include <linux/mii.h> +#include <linux/ethtool.h> +#include <linux/sockios.h> +#include <easy/easy.h> +#include "ethernet.h" +#include "linux_eth.h" + +typedef enum { + iow_rx_byte = 0, + iow_rx_packets, + iow_rx_dropped, + iow_rx_fraglist_packets, + iow_rx_nr_frag_packets, + iow_rx_nr_frag_headroom_err, + iow_tx_byte, + iow_tx_packets, + iow_tx_dropped, + iow_tx_nr_frag_packets, + iow_tx_fraglist_packets, + iow_tx_fraglist_nr_frags_packets, + iow_tx_tso_packets, + iow_tx_tso_drop_packets, + iow_rx_frame, + iow_rx_bytes, + iow_rx_bytes_g, + iow_rx_broadcast, + iow_rx_multicast, + iow_rx_crc_err, + iow_rx_runt_err, + iow_rx_jabber_err, + iow_rx_undersize, + iow_rx_oversize, + iow_rx_pkt64, + iow_rx_pkt65to127, + iow_rx_pkt128to255, + iow_rx_pkt256to511, + iow_rx_pkt512to1023, + iow_rx_pkt1024tomax, + iow_rx_unicast, + iow_rx_len_err, + iow_rx_outofrange_err_ctr, + iow_rx_pause, + iow_rx_fifo_overflow, + iow_rx_vlan, + iow_rx_wdog, + iow_rx_lpi_usec_ctr, + iow_rx_lpi_tran_ctr, + iow_rx_drop_frame_ctr, + iow_rx_drop_byte_ctr, + iow_tx_bytes, + iow_tx_frame, + iow_tx_broadcast, + iow_tx_broadcast_gb, + iow_tx_multicast, + iow_tx_multicast_gb, + iow_tx_pkt64, + iow_tx_pkt65to127, + iow_tx_pkt128to255, + iow_tx_pkt256to511, + iow_tx_pkt512to1023, + iow_tx_pkt1024tomax, + iow_tx_unicast, + iow_tx_underflow_err, + iow_tx_bytes_g, + iow_tx_frame_g, + iow_tx_pause, + iow_tx_vlan, + iow_tx_lpi_usec_ctr, + iow_tx_lpi_tran_ctr, + iow_STAT_END, +} g_linux_indx; + +static struct ethtool_stats *g_linux_stats = NULL; +static struct eth_stats g_linux_ifstats; + +int linux_eth_get_link_settings(const char*, struct eth_link*); + +int linux_eth_set_link_settings(const char *ifname, struct eth_link link) +{ + struct { + struct ethtool_link_settings req; + __u32 link_mode_data[3 * 32 * 127]; + } ecmd; + + memset(&ecmd, 0, sizeof(struct ethtool_link_settings)); + + if (linux_eth_get_link_settings(ifname, &link)) + return -1; + + ecmd.req.cmd = ETHTOOL_SLINKSETTINGS; + + ecmd.req.port = link.portid; + ecmd.req.speed = link.speed; + ecmd.req.autoneg = (link.autoneg == 0 ? false : true); + ecmd.req.duplex = (link.fullduplex == 1 ? false : true); + + if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings))) + return -1; + return 0; +} + +int linux_eth_get_link_settings(const char *ifname, struct eth_link *link) +{ + struct { + struct ethtool_link_settings req; + __u32 link_mode_data[3 * 32 * 127]; + } ecmd; + + memset(&ecmd, 0, sizeof(struct ethtool_link_settings)); + + ecmd.req.cmd = ETHTOOL_GLINKSETTINGS; + + if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings))) + return -1; + + if (ecmd.req.link_mode_masks_nwords >= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS) + return -1; + + ecmd.req.link_mode_masks_nwords = -ecmd.req.link_mode_masks_nwords; + + if (0 != eth_ioctl(ifname, SIOCETHTOOL, &ecmd, sizeof(struct ethtool_link_settings))) + return -1; + + if (ecmd.req.link_mode_masks_nwords <= 0 || ecmd.req.cmd != ETHTOOL_GLINKSETTINGS) + return -1; + + link->portid = ecmd.req.port; + link->speed = ecmd.req.speed; + link->autoneg = ecmd.req.autoneg == 0 ? false : true; + link->fullduplex = ecmd.req.duplex == 1 ? false : true; + + return 0; +} + +int linux_eth_poweron_phy(const char *ifname, struct eth_phy p) +{ + libethernet_err("%s(): TODO\n", __func__); + return 0; +} + +int linux_eth_poweroff_phy(const char *ifname, struct eth_phy p) +{ + libethernet_err("%s(): TODO\n", __func__); + return 0; +} + +int linux_eth_reset_phy(const char *ifname, int phy_id) +{ + return eth_mii_reset_phy(ifname, phy_id); +} + +static int linux_get_ifstats(const char *ifname, struct eth_stats *s) +{ + struct if_stats easy_ifstat; + + if (!s) + return -1; + + memset(&easy_ifstat, 0, sizeof(struct if_stats)); + if (if_getstats(ifname, &easy_ifstat) < 0) { + return -1; + } + + s->tx_bytes = easy_ifstat.tx_bytes; + s->tx_packets = easy_ifstat.tx_packets; + s->tx_errors = easy_ifstat.tx_errors; +/* Some counters set to zero, and will be populated cross referring + * the rmon stats structure. + */ + s->tx_ucast_packets = 0; + s->tx_mcast_packets = 0; + s->tx_bcast_packets = 0; + s->tx_discard_packets = 0; + s->rx_bytes = easy_ifstat.rx_bytes; + s->rx_packets = 0; + s->rx_errors = easy_ifstat.rx_errors; + s->rx_ucast_packets = 0; + s->rx_mcast_packets = 0; + s->rx_bcast_packets = 0; + s->rx_discard_packets = 0; + s->rx_unknown_packets = 0; + + return 0; +} + +static int linux_get_ethtool_stats(const char *ifname) +{ + int fd; + size_t n_stats; + size_t stats_size; + int status; + + fd = socket(AF_INET, SOCK_DGRAM, /* protocol = */ 0); + if (fd < 0) { + syslog(LOG_ERR, "%s(%d): Failed" + " to open control socket.\n", __FUNCTION__, __LINE__); + return -1; + } + + struct ethtool_drvinfo drvinfo = {.cmd = ETHTOOL_GDRVINFO}; + + struct ifreq req = {.ifr_data = (void *)&drvinfo}; + + strncpy(req.ifr_name, ifname, sizeof(req.ifr_name)); + + status = ioctl(fd, SIOCETHTOOL, &req); + + if (status < 0) { + close(fd); + syslog(LOG_ERR, "%s(%d): Failed to get" + "driver information from %s:", __FUNCTION__, __LINE__, ifname); + return -1; + } + + n_stats = (size_t)drvinfo.n_stats; + if (n_stats < 1) { + close(fd); + syslog(LOG_ERR, "%s(%d): No stats" + " available for %s", __FUNCTION__, __LINE__, ifname); + return -1; + } + stats_size = sizeof(struct ethtool_stats) + (n_stats * sizeof(uint64_t)); + + g_linux_stats = malloc(stats_size); + if (!g_linux_stats) { + close(fd); + syslog(LOG_ERR, "%s(%d): malloc failed.", + __FUNCTION__, __LINE__); + return -1; + } + + g_linux_stats->cmd = ETHTOOL_GSTATS; + g_linux_stats->n_stats = n_stats; + req.ifr_data = (void *)g_linux_stats; + + status = ioctl(fd, SIOCETHTOOL, &req); + if (status < 0) { + close(fd); + if (g_linux_stats) + free(g_linux_stats); + syslog(LOG_ERR, "%s(%d): Reading statistics" + " from %s failed:", __FUNCTION__, __LINE__, ifname); + return -1; + } + + close(fd); + return 0; +} + +int linux_get_if_stats(const char *ifname) +{ + memset(&g_linux_ifstats, 0, sizeof(struct eth_stats)); + + syslog(LOG_INFO, "%s(%d): ifname is %s", __FUNCTION__, __LINE__, ifname); + + if (linux_get_ifstats(ifname, &g_linux_ifstats) < 0) + return -1; + if (linux_get_ethtool_stats(ifname) < 0) + return -1; + + return 0; +} + +int linux_eth_get_stats(const char *ifname, struct eth_stats *s) +{ + if (!s) + return -1; + + if (linux_get_if_stats(ifname) < 0) + return -1; + + s->tx_bytes = g_linux_ifstats.tx_bytes; + s->tx_packets = g_linux_ifstats.tx_packets; + s->tx_errors = g_linux_ifstats.tx_errors; + s->tx_ucast_packets = (uint64_t)g_linux_stats->data[iow_tx_unicast]; + s->tx_mcast_packets = (uint64_t)g_linux_stats->data[iow_tx_multicast]; + s->tx_bcast_packets = (uint64_t)g_linux_stats->data[iow_tx_broadcast]; + s->tx_discard_packets = (uint64_t)g_linux_stats->data[iow_tx_dropped]; + s->rx_bytes = g_linux_ifstats.rx_bytes; + s->rx_packets = (uint64_t)g_linux_stats->data[iow_rx_packets]; + s->rx_errors = g_linux_ifstats.rx_errors; + s->rx_ucast_packets = (uint64_t)g_linux_stats->data[iow_rx_unicast]; + s->rx_mcast_packets = (uint64_t)g_linux_stats->data[iow_rx_multicast]; + s->rx_bcast_packets = (uint64_t)g_linux_stats->data[iow_rx_broadcast]; + s->rx_discard_packets = (uint64_t)g_linux_stats->data[iow_rx_dropped]; +/*FIXME: Doesn't exist a way to get the counter rx_unknown_packets.*/ + s->rx_unknown_packets = 0; + + free(g_linux_stats); + + return 0; +} + +int linux_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon) +{ + int ret = 0; + + if (linux_get_if_stats(ifname) < 0) + ret = -1; + + rmon->tx.packets = (uint64_t)g_linux_stats->data[iow_tx_packets]; + rmon->tx.bytes = (uint64_t)g_linux_stats->data[iow_tx_bytes]; + rmon->tx.crc_err_packets = 0; +/* These two counters are marked zero because they dont + * hold much relevancy to Customer + */ + rmon->tx.under_sz_packets = 0; + rmon->tx.over_sz_packets = 0; + rmon->tx.packets_64bytes = (uint64_t)g_linux_stats->data[iow_tx_pkt64]; + rmon->tx.packets_65to127bytes = (uint64_t)g_linux_stats->data[iow_tx_pkt65to127]; + rmon->tx.packets_128to255bytes = (uint64_t)g_linux_stats->data[iow_tx_pkt128to255]; + rmon->tx.packets_256to511bytes = (uint64_t)g_linux_stats->data[iow_tx_pkt256to511]; + rmon->tx.packets_512to1023bytes = (uint64_t)g_linux_stats->data[iow_tx_pkt512to1023]; + rmon->tx.packets_1024to1518bytes = (uint64_t)g_linux_stats->data[iow_tx_pkt1024tomax]; + + rmon->rx.bytes = (uint64_t)g_linux_stats->data[iow_rx_byte]; + rmon->rx.packets = (uint64_t)g_linux_stats->data[iow_rx_packets]; + rmon->rx.bcast_packets = (uint64_t)g_linux_stats->data[iow_rx_broadcast]; + rmon->rx.mcast_packets = (uint64_t)g_linux_stats->data[iow_rx_multicast]; + rmon->rx.crc_err_packets = (uint64_t)g_linux_stats->data[iow_rx_crc_err]; + rmon->rx.under_sz_packets = (uint64_t)g_linux_stats->data[iow_rx_undersize]; + rmon->rx.over_sz_packets = (uint64_t)g_linux_stats->data[iow_rx_oversize]; + rmon->rx.packets_64bytes = (uint64_t)g_linux_stats->data[iow_rx_pkt64]; + rmon->rx.packets_65to127bytes = (uint64_t)g_linux_stats->data[iow_rx_pkt65to127]; + + free(g_linux_stats); + + return ret; +} diff --git a/linux/linux/linux_eth.h b/linux/linux/linux_eth.h new file mode 100644 index 0000000000000000000000000000000000000000..f9aee2528deee2b2ad11ee09c4c6df99d97e7bdf --- /dev/null +++ b/linux/linux/linux_eth.h @@ -0,0 +1,20 @@ +#ifndef LINUX_ETH_H +#define LINUX_ETH_H + +#ifdef __cplusplus +extern "C" { +#endif + +int linux_eth_set_link_settings(const char *ifname, struct eth_link link); +int linux_eth_get_link_settings(const char *ifname, struct eth_link *link); +int linux_eth_poweron_phy(const char *ifname, struct eth_phy p); +int linux_eth_poweroff_phy(const char *ifname, struct eth_phy p); +int linux_eth_reset_phy(const char *ifname, int phy_id); +int linux_eth_get_stats(const char *ifname, struct eth_stats *s); +int linux_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon); + +#ifdef __cplusplus +} +#endif + +#endif /* LINUX_ETH_H */ diff --git a/linux/linux_eth.c b/linux/linux_eth.c deleted file mode 100644 index 6ea972d57ceac4bba67ce150b7da020c9899e5ff..0000000000000000000000000000000000000000 --- a/linux/linux_eth.c +++ /dev/null @@ -1,238 +0,0 @@ -/* - * linux_eth.c - Linux based statistics collection ubus methods. - * - * Copyright (C) 2023 iopsys Software Solutions AB. All rights reserved. - * - * Author: padmalochan.mohapatra@iopsys.eu - * - * This program is free software; you can redistribute it and/or - * modify it under the terms of the GNU General Public License - * version 2 as published by the Free Software Foundation. - * - * This program is distributed in the hope that it will be useful, but - * WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA - * 02110-1301 USA - */ - -#include <stdio.h> -#include <stdarg.h> -#include <string.h> -#include <stdint.h> -#include <errno.h> -#include <ctype.h> -#include <sys/types.h> -#include <fcntl.h> -#include <sys/ioctl.h> -#include <sys/socket.h> -#include <net/if.h> -#include <time.h> -#include <syslog.h> -#include <unistd.h> -#include <stdlib.h> -#include <linux/ethtool.h> -#include <linux/sockios.h> -#include <easy/easy.h> -#include <easy/if_utils.h> - -#include "../ethernet.h" - -#include "linux_eth.h" - -typedef enum { - tx_packets = 0, - tx_bytes, - rx_packets, - rx_bytes, - TxDrop, - TxCrcErr, - TxUnicast, - TxMulticast, - TxBroadcast, - TxCollision, - TxSingleCollision, - TxMultipleCollision, - TxDeferred, - TxLateCollision, - TxExcessiveCollistion, - TxPause, - TxPktSz64, - TxPktSz65To127, - TxPktSz128To255, - TxPktSz256To511, - TxPktSz512To1023, - Tx1024ToMax, - TxBytes, - RxDrop, - RxFiltering, - RxUnicast, - RxMulticast, - RxBroadcast, - RxAlignErr, - RxCrcErr, - RxUnderSizeErr, - RxFragErr, - RxOverSzErr, - RxJabberErr, - RxPause, - RxPktSz64, - RxPktSz65To127, - RxPktSz128To255, - RxPktSz256To511, - RxPktSz512To1023, - RxPktSz1024ToMax, - RxBytes, - RxCtrlDrop, - RxIngressDrop, - RxArlDrop, - STATS_END, -} idx; - -struct ethnic_stats { - uint32_t cmd; - uint32_t n_stats; - uint64_t data[STATS_END]; -} stat; - -static struct eth_stats ifstats; - -static int get_ifstats(const char *ifname, struct eth_stats *s) -{ - struct if_stats easy_ifstat; - - if (!s) - return -1; - - memset(&easy_ifstat, 0, sizeof(struct if_stats)); - if (if_getstats(ifname, &easy_ifstat) < 0) { - return -1; - } - - s->tx_bytes = easy_ifstat.tx_bytes; - s->tx_packets = easy_ifstat.tx_packets; - s->tx_errors = easy_ifstat.tx_errors; -/* Some counters set to zero, and will be populated cross referring - * the rmon stats structure. - */ - s->tx_ucast_packets = 0; - s->tx_mcast_packets = 0; - s->tx_bcast_packets = 0; - s->tx_discard_packets = 0; - s->rx_bytes = easy_ifstat.rx_bytes; - s->rx_packets = 0; - s->rx_errors = easy_ifstat.rx_errors; - s->rx_ucast_packets = 0; - s->rx_mcast_packets = 0; - s->rx_bcast_packets = 0; - s->rx_discard_packets = 0; - s->rx_unknown_packets = 0; - - return 0; -} - -int get_ethtool_stats(const char *ifname) -{ - int ret = 0; - - stat.cmd = ETHTOOL_GSTATS; - if (0 != eth_ioctl(ifname, SIOCETHTOOL, &stat, sizeof(struct ethnic_stats))) - ret = -1; - - if (ret) - syslog(LOG_ERR, "%s(%d) nic_stats collection failed.", __FUNCTION__, __LINE__); - - return ret; -} - -int get_stats(const char *ifname) -{ - memset(&ifstats, 0, sizeof(struct eth_stats)); - memset(&stat, 0, sizeof(struct ethnic_stats)); - - syslog(LOG_INFO, "%s(%d): ifname is %s", __FUNCTION__, __LINE__, ifname); - - if (get_ifstats(ifname, &ifstats) < 0) - return -1; - if (get_ethtool_stats(ifname) < 0) - return -1; - - return 0; -} - - -int linux_eth_get_stats(const char *ifname, struct eth_stats *s) -{ - if (!s) - return -1; - - if (get_stats(ifname) < 0) - return -1; - - s->tx_bytes = ifstats.tx_bytes; - s->tx_packets = ifstats.tx_packets; - s->tx_errors = ifstats.tx_errors; - s->tx_ucast_packets = stat.data[TxUnicast]; - s->tx_mcast_packets = stat.data[TxMulticast]; - s->tx_bcast_packets = stat.data[TxBroadcast]; - s->tx_discard_packets = stat.data[TxDrop]; - s->rx_bytes = ifstats.rx_bytes; - s->rx_packets = stat.data[rx_packets]; - s->rx_errors = ifstats.rx_errors; - s->rx_ucast_packets = stat.data[RxUnicast]; - s->rx_mcast_packets = stat.data[RxMulticast]; - s->rx_bcast_packets = stat.data[RxBroadcast]; - s->rx_discard_packets = stat.data[RxDrop]; -/*FIXME: Doesn't exist a way to get the counter rx_unknown_packets.*/ - s->rx_unknown_packets = 0; - - return 0; -} - -int linux_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon) -{ - int ret = 0; - - if (get_stats(ifname) < 0) - ret = -1; - rmon->tx.packets = stat.data[tx_packets]; - rmon->tx.bytes = stat.data[tx_bytes]; - rmon->tx.crc_err_packets = stat.data[TxCrcErr]; -/* These two counters are marked zero because they dont - * hold much relevancy to Customer - */ - rmon->tx.under_sz_packets = 0; - rmon->tx.over_sz_packets = 0; - rmon->tx.packets_64bytes = stat.data[TxPktSz64]; - rmon->tx.packets_65to127bytes = stat.data[TxPktSz65To127]; - rmon->tx.packets_128to255bytes = stat.data[TxPktSz128To255]; - rmon->tx.packets_256to511bytes = stat.data[TxPktSz256To511]; - rmon->tx.packets_512to1023bytes = stat.data[TxPktSz512To1023]; - rmon->tx.packets_1024to1518bytes = stat.data[Tx1024ToMax]; - - rmon->rx.bytes = stat.data[RxBytes]; - rmon->rx.packets = stat.data[rx_packets]; - rmon->rx.bcast_packets = stat.data[RxBroadcast]; - rmon->rx.mcast_packets = stat.data[RxMulticast]; - rmon->rx.crc_err_packets = stat.data[RxCrcErr]; - rmon->rx.under_sz_packets = stat.data[RxUnderSizeErr]; - rmon->rx.over_sz_packets = stat.data[RxOverSzErr]; - rmon->rx.packets_64bytes = stat.data[RxPktSz64]; - rmon->rx.packets_65to127bytes = stat.data[RxPktSz65To127]; - rmon->rx.packets_128to255bytes = stat.data[RxPktSz128To255]; - rmon->rx.packets_256to511bytes = stat.data[RxPktSz256To511]; - rmon->rx.packets_512to1023bytes = stat.data[RxPktSz512To1023]; - rmon->rx.packets_1024to1518bytes = stat.data[RxPktSz1024ToMax]; - - return ret; -} - -const struct eth_ops linux_eth_ops = { - .ifname = "lan", - .get_stats = linux_eth_get_stats, - .get_rmon_stats = linux_eth_get_rmon_stats, -}; diff --git a/linux/linux_eth.h b/linux/linux_eth.h deleted file mode 100644 index 68befa703799c8fb3c136bcabc94a9b781559431..0000000000000000000000000000000000000000 --- a/linux/linux_eth.h +++ /dev/null @@ -1,15 +0,0 @@ -#ifndef LINUX_ETH_H -#define LINUX_ETH_H - -#ifdef __cplusplus -extern "C" { -#endif - -int linux_eth_get_stats(const char *ifname, struct eth_stats *s); -int linux_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon); - -#ifdef __cplusplus -} -#endif - -#endif /* LINUX_ETH_H */ diff --git a/linux/mtk/mtk_eth.c b/linux/mtk/mtk_eth.c new file mode 100644 index 0000000000000000000000000000000000000000..0f32fad6b7ab3ccc41baec9ba9bbad6a16aeeb2b --- /dev/null +++ b/linux/mtk/mtk_eth.c @@ -0,0 +1,233 @@ +/* + * mtk_eth.c - Linux based statistics collection ubus methods. + * + * Copyright (C) 2023 iopsys Software Solutions AB. All rights reserved. + * + * Author: padmalochan.mohapatra@iopsys.eu + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * version 2 as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA + * 02110-1301 USA + */ + +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include <stdint.h> +#include <errno.h> +#include <ctype.h> +#include <sys/types.h> +#include <fcntl.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <net/if.h> +#include <time.h> +#include <syslog.h> +#include <unistd.h> +#include <stdlib.h> +#include <linux/ethtool.h> +#include <linux/sockios.h> +#include <easy/easy.h> +#include <easy/if_utils.h> +#include "ethernet.h" +#include "mtk_eth.h" + +typedef enum { + iow_tx_packets = 0, + iow_tx_bytes, + iow_rx_packets, + iow_rx_bytes, + iow_TxDrop, + iow_TxCrcErr, + iow_TxUnicast, + iow_TxMulticast, + iow_TxBroadcast, + iow_TxCollision, + iow_TxSingleCollision, + iow_TxMultipleCollision, + iow_TxDeferred, + iow_TxLateCollision, + iow_TxExcessiveCollistion, + iow_TxPause, + iow_TxPktSz64, + iow_TxPktSz65To127, + iow_TxPktSz128To255, + iow_TxPktSz256To511, + iow_TxPktSz512To1023, + iow_Tx1024ToMax, + iow_TxBytes, + iow_RxDrop, + iow_RxFiltering, + iow_RxUnicast, + iow_RxMulticast, + iow_RxBroadcast, + iow_RxAlignErr, + iow_RxCrcErr, + iow_RxUnderSizeErr, + iow_RxFragErr, + iow_RxOverSzErr, + iow_RxJabberErr, + iow_RxPause, + iow_RxPktSz64, + iow_RxPktSz65To127, + iow_RxPktSz128To255, + iow_RxPktSz256To511, + iow_RxPktSz512To1023, + iow_RxPktSz1024ToMax, + iow_RxBytes, + iow_RxCtrlDrop, + iow_RxIngressDrop, + iow_RxArlDrop, + iow_STATS_END, +} g_indx; + +struct mtk_ethnic_stats { + uint32_t cmd; + uint32_t n_stats; + uint64_t data[iow_STATS_END]; +} g_mtk_stat; + +static struct eth_stats g_mtk_ifstats; + +static int mtk_get_ifstats(const char *ifname, struct eth_stats *s) +{ + + struct if_stats easy_ifstat; + + if (!s) + return -1; + + memset(&easy_ifstat, 0, sizeof(struct if_stats)); + if (if_getstats(ifname, &easy_ifstat) < 0) { + return -1; + } + + s->tx_bytes = easy_ifstat.tx_bytes; + s->tx_packets = easy_ifstat.tx_packets; + s->tx_errors = easy_ifstat.tx_errors; +/* Some counters set to zero, and will be populated cross referring + * the rmon stats structure. + */ + s->tx_ucast_packets = 0; + s->tx_mcast_packets = 0; + s->tx_bcast_packets = 0; + s->tx_discard_packets = 0; + s->rx_bytes = easy_ifstat.rx_bytes; + s->rx_packets = 0; + s->rx_errors = easy_ifstat.rx_errors; + s->rx_ucast_packets = 0; + s->rx_mcast_packets = 0; + s->rx_bcast_packets = 0; + s->rx_discard_packets = 0; + s->rx_unknown_packets = 0; + + return 0; +} + + +int mtk_get_ethtool_stats(const char *ifname) +{ + int ret = 0; + + g_mtk_stat.cmd = ETHTOOL_GSTATS; + if (0 != eth_ioctl(ifname, SIOCETHTOOL, &g_mtk_stat, sizeof(struct mtk_ethnic_stats))) + ret = -1; + + if (ret) + syslog(LOG_ERR, "%s(%d) nic_stats collection failed.", __FUNCTION__, __LINE__); + + return ret; +} + + +int mtk_get_if_stats(const char *ifname) +{ + + memset(&g_mtk_ifstats, 0, sizeof(struct eth_stats)); + memset(&g_mtk_stat, 0, sizeof(struct mtk_ethnic_stats)); + + syslog(LOG_INFO, "%s(%d): ifname is %s", __FUNCTION__, __LINE__, ifname); + + if (mtk_get_ifstats(ifname, &g_mtk_ifstats) < 0) + return -1; + if (mtk_get_ethtool_stats(ifname) < 0) + return -1; + + return 0; +} + +int mtk_eth_get_stats(const char *ifname, struct eth_stats *s) +{ + if (!s) + return -1; + if (mtk_get_if_stats(ifname) < 0) + return -1; + + s->tx_bytes = g_mtk_ifstats.tx_bytes; + s->tx_packets = g_mtk_ifstats.tx_packets; + s->tx_errors = g_mtk_ifstats.tx_errors; + s->tx_ucast_packets = g_mtk_stat.data[iow_TxUnicast]; + s->tx_mcast_packets = g_mtk_stat.data[iow_TxMulticast]; + s->tx_bcast_packets = g_mtk_stat.data[iow_TxBroadcast]; + s->tx_discard_packets = g_mtk_stat.data[iow_TxDrop]; + s->rx_bytes = g_mtk_ifstats.rx_bytes; + s->rx_packets = g_mtk_stat.data[iow_rx_packets]; + s->rx_errors = g_mtk_ifstats.rx_errors; + s->rx_ucast_packets = g_mtk_stat.data[iow_RxUnicast]; + s->rx_mcast_packets = g_mtk_stat.data[iow_RxMulticast]; + s->rx_bcast_packets = g_mtk_stat.data[iow_RxBroadcast]; + s->rx_discard_packets = g_mtk_stat.data[iow_RxDrop]; +/*FIXME: Doesn't exist a way to get the counter rx_unknown_packets.*/ + s->rx_unknown_packets = 0; + + return 0; +} + +int mtk_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon) +{ + int ret = 0; + + if (mtk_get_if_stats(ifname) < 0) + ret = -1; + + rmon->tx.packets = g_mtk_stat.data[iow_tx_packets]; + rmon->tx.bytes = g_mtk_stat.data[iow_tx_bytes]; + rmon->tx.crc_err_packets = g_mtk_stat.data[iow_TxCrcErr]; +/* These two counters are marked zero because they dont + * hold much relevancy to Customer + */ + rmon->tx.under_sz_packets = 0; + rmon->tx.over_sz_packets = 0; + rmon->tx.packets_64bytes = g_mtk_stat.data[iow_TxPktSz64]; + rmon->tx.packets_65to127bytes = g_mtk_stat.data[iow_TxPktSz65To127]; + rmon->tx.packets_128to255bytes = g_mtk_stat.data[iow_TxPktSz128To255]; + rmon->tx.packets_256to511bytes = g_mtk_stat.data[iow_TxPktSz256To511]; + rmon->tx.packets_512to1023bytes = g_mtk_stat.data[iow_TxPktSz512To1023]; + rmon->tx.packets_1024to1518bytes = g_mtk_stat.data[iow_Tx1024ToMax]; + + rmon->rx.bytes = g_mtk_stat.data[iow_RxBytes]; + rmon->rx.packets = g_mtk_stat.data[iow_rx_packets]; + rmon->rx.bcast_packets = g_mtk_stat.data[iow_RxBroadcast]; + rmon->rx.mcast_packets = g_mtk_stat.data[iow_RxMulticast]; + rmon->rx.crc_err_packets = g_mtk_stat.data[iow_RxCrcErr]; + rmon->rx.under_sz_packets = g_mtk_stat.data[iow_RxUnderSizeErr]; + rmon->rx.over_sz_packets = g_mtk_stat.data[iow_RxOverSzErr]; + rmon->rx.packets_64bytes = g_mtk_stat.data[iow_RxPktSz64]; + rmon->rx.packets_65to127bytes = g_mtk_stat.data[iow_RxPktSz65To127]; + rmon->rx.packets_128to255bytes = g_mtk_stat.data[iow_RxPktSz128To255]; + rmon->rx.packets_256to511bytes = g_mtk_stat.data[iow_RxPktSz256To511]; + rmon->rx.packets_512to1023bytes = g_mtk_stat.data[iow_RxPktSz512To1023]; + rmon->rx.packets_1024to1518bytes = g_mtk_stat.data[iow_RxPktSz1024ToMax]; + + return ret; +} diff --git a/linux/mtk/mtk_eth.h b/linux/mtk/mtk_eth.h new file mode 100644 index 0000000000000000000000000000000000000000..2e5df783df8549e651e064620186d8456ad6809f --- /dev/null +++ b/linux/mtk/mtk_eth.h @@ -0,0 +1,15 @@ +#ifndef MTK_ETH_H +#define MTK_ETH_H + +#ifdef __cplusplus +extern "C" { +#endif + +int mtk_eth_get_stats(const char *ifname, struct eth_stats *s); +int mtk_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon); + +#ifdef __cplusplus +} +#endif + +#endif /* MTK_ETH_H */