Skip to content
Snippets Groups Projects
Commit 0828daf7 authored by Padmalochan Mohapatra's avatar Padmalochan Mohapatra Committed by Rahul Thakur
Browse files

libethernet : Implementation of methods ifstats and rmonstats on Linux.

parent 21f8ec98
No related branches found
No related tags found
No related merge requests found
......@@ -12,20 +12,27 @@ objs_lib = ethernet.o
ifeq ($(PLATFORM),BROADCOM)
objs_lib += bcm/bcm.o
else ifeq ($(PLATFORM),MEDIATEK)
objs_lib += ethsw.o
XXFLAGS += -Wl,-whole-archive -lsw -Wl,-no-whole-archive
else ifeq ($(PLATFORM),ECONET)
endif
ifeq ($(PLATFORM),TEST)
CFLAGS += -DIOPSYS_TEST -I/usr/include/libnl3
LIBETH_CFLAGS += $(DIAG_CFLAGS) -Werror
objs_lib += test_stub/stub.o
endif
ifeq ($(PLATFORM),ECONET)
CFLAGS += -Itest_stub
LIBETH_CFLAGS += $(DIAG_CFLAGS) -Werror
objs_lib += econet/econet.o econet/ecnt_prvt.o
LIBS += -lapi_lib_switchmgr
else ifeq ($(PLATFORM),IPQ95XX)
endif
ifeq ($(PLATFORM),IPQ95XX)
objs_lib += ipq95xx/ipq95xx.o
else ifeq ($(PLATFORM),TEST)
CFLAGS += -DIOPSYS_TEST -I/usr/include/libnl3
LIBETH_CFLAGS += $(DIAG_CFLAGS) -Werror
objs_lib += test_stub/stub.o
endif
ifeq ($(PLATFORM),LINUX)
objs_lib += linux/linux_eth.o
endif
all: libethernet.so
......@@ -38,5 +45,4 @@ libethernet.so: $(objs_lib)
-shared -o $@ $^ $(XXFLAGS) $(LIBS)
clean:
rm -f bcm/*.o
rm -f *.o *.so
......@@ -38,20 +38,6 @@
#include "ethernet.h"
#if defined(IOPSYS_BROADCOM)
extern const struct eth_ops bcm_eth_ops;
#elif defined(IOPSYS_TEST)
extern const struct eth_ops test_eth_ops;
#elif defined(IOPSYS_ECONET)
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;
#else
extern const struct eth_ops ethsw_ops;
#endif
const struct eth_ops *eth_ops[] = {
#if defined(IOPSYS_BROADCOM)
&bcm_eth_ops,
......@@ -63,6 +49,8 @@ const struct eth_ops *eth_ops[] = {
&econet_ae_wan_eth_ops,
#elif defined(IPQ95XX)
&ipq95xx_eth_ops,
#elif defined(IOPSYS_LINUX)
&linux_eth_ops,
#else
&ethsw_ops, /* FIXME */
#endif
......
......@@ -35,6 +35,23 @@ extern "C" {
#define libethernet_info(...) pr_info("libethernet: " __VA_ARGS__)
#define libethernet_dbg(...) pr_debug("libethernet: " __VA_ARGS__)
#if defined(IOPSYS_BROADCOM)
extern const struct eth_ops bcm_eth_ops;
#elif defined(IOPSYS_TEST)
extern const struct eth_ops test_eth_ops;
#elif defined(IOPSYS_ECONET)
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_LINUX)
extern const struct eth_ops linux_eth_ops;
#else
extern const struct eth_ops ethsw_ops;
#endif
/* enum eth_duplex - duplex modes */
enum eth_duplex {
AUTO_DUPLEX,
......
/*
* 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 <netlink/genl/genl.h>
#include <netlink/cache.h>
#include <netlink/utils.h>
#include <netlink/object.h>
#include <netlink/genl/genl.h>
#include <netlink/genl/ctrl.h>
#include <netlink/netlink.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
#include <netlink/genl/ctrl.h>
#include <netlink/netlink.h>
#include <netlink/route/rtnl.h>
#include <netlink/route/link.h>
#include <linux/sockios.h>
#include "easy.h"
#include "if_utils.h"
#include "../ethernet.h"
#include "linux_eth.h"
/************************************************************
* Open a netlink socket connectivity with NETLINK_ROUTE
* to read the stats using designated API.
************************************************************
*/
static int if_openlnk(const char *ifname, struct nl_sock **s,
struct rtnl_link **l)
{
struct rtnl_link *link;
struct nl_sock *sk;
int ret = 0;
sk = nl_socket_alloc();
if (sk == NULL) {
ret = -errno;
return ret;
}
if (nl_connect(sk, NETLINK_ROUTE) < 0) {
syslog(LOG_ERR, "%s(%d) nl socket connection failed.",
__FUNCTION__, __LINE__);
ret = -1;
goto out;
}
if (rtnl_link_get_kernel(sk, 0, ifname, &link) < 0) {
ret = -1;
goto out;
}
*l = link;
*s = sk;
return 0;
out:
nl_socket_free(sk);
return ret;
}
/************************************************************
* Close the socket and free the allocated nl objects.
************************************************************
*/
static int if_closelnk(struct nl_sock *s, struct rtnl_link *l)
{
rtnl_link_put(l);
nl_socket_free(s);
return 0;
}
static int get_ifstats(const char *ifname, struct eth_stats *s)
{
struct rtnl_link *link;
struct nl_sock *sk;
int ret = 0;
if (!s)
return -1;
ret = if_openlnk(ifname, &sk, &link);
if (ret)
return -1;
s->tx_bytes = rtnl_link_get_stat(link, RTNL_LINK_TX_BYTES);
s->tx_packets = rtnl_link_get_stat(link, RTNL_LINK_TX_PACKETS);
s->tx_errors = rtnl_link_get_stat(link, RTNL_LINK_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 = rtnl_link_get_stat(link, RTNL_LINK_RX_BYTES);
s->rx_packets = 0;
s->rx_errors = rtnl_link_get_stat(link, RTNL_LINK_RX_ERRORS);
s->rx_ucast_packets = 0;
s->rx_mcast_packets = rtnl_link_get_stat(link, RTNL_LINK_MULTICAST);
s->rx_bcast_packets = 0;
s->rx_discard_packets = 0;
s->rx_unknown_packets = 0;
if_closelnk(sk, link);
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 = ifstats.tx_mcast_packets;
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,
};
#ifndef LINUX
#define LINUX
#ifdef __cplusplus
extern "C" {
#endif
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;
static struct ethnic_stats {
__u32 cmd;
__u32 n_stats;
__u64 data[STATS_END];
} stat;
static struct eth_stats ifstats;
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 */
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment