diff --git a/bcm/bcm.c b/bcm/bcm.c index ef96e6443011dbe9e078868320b8549c91a300e3..589bfc357442361a0730b6aaa8713a4c8201ba4c 100644 --- a/bcm/bcm.c +++ b/bcm/bcm.c @@ -276,12 +276,13 @@ static int bcm_eth_get_stats_from_proc(const char *ifname, struct eth_stats *s) return 0; } -int bcm_eth_get_stats(const char *ifname, struct eth_stats *s) + +static int read_eth_stats(const char *ifname, struct eth_stats *s) { + int ret_proc; struct ethswctl_data data; int unit = -1; int port = -1; - int ret_proc; int ret; /* get from proc first */ @@ -331,6 +332,79 @@ int bcm_eth_get_stats(const char *ifname, struct eth_stats *s) return 0; } + +static void reinit_extended_stats_for_bridge(struct eth_stats *to) +{ + // In case of bridge, function to read all stats has already + // been called once, which might have stored garbage in the + // extended stats, so important to reinit here. + to->tx_ucast_packets = 0; + to->rx_ucast_packets = 0; + to->tx_mcast_packets = 0; + to->rx_mcast_packets = 0; + to->tx_bcast_packets = 0; + to->rx_bcast_packets = 0; + to->rx_unknown_packets = 0; +} + + +// This function adds up the extended stats to get cumulative stats +// for the bridge type interfaces. +static void add_to_stats(struct eth_stats *to, struct eth_stats *from) +{ + to->tx_ucast_packets += from->tx_ucast_packets; + to->rx_ucast_packets += from->rx_ucast_packets; + to->tx_mcast_packets += from->tx_mcast_packets; + to->rx_mcast_packets += from->rx_mcast_packets; + to->tx_bcast_packets += from->tx_bcast_packets; + to->rx_bcast_packets += from->rx_bcast_packets; + to->rx_unknown_packets += from->rx_unknown_packets; +} + + +int bcm_eth_get_stats(const char *ifname, struct eth_stats *s) +{ + + if (read_eth_stats(ifname, s)) { + libethernet_err("error in reading stats for interface %s\n", ifname); + return -1; + } + + if (if_isbridge(ifname)) { + // read stats for each interface in bridge and add them to get + // bridge stats + struct eth_stats temp; + int ret = 0; + char ifnames[32][16] = {0}; + int count, i; + + ret = br_get_iflist(ifname, &count, ifnames); + if ((count <= 0) || (ret < 0)) // empty bridge + return 0; + + // only extended stats are not available for bridge interfaces, + // we have already read the available stats above and now loop + // on the member ports to get the extended stats for each port + // and add those up to get the extended stats for the bridge + reinit_extended_stats_for_bridge(s); + for (i = 0; i < count; i++) { + memset(&temp, 0, sizeof(struct eth_stats)); + + if (strncmp("eth", ifnames[i], 3) != 0) + continue; + + if (read_eth_stats(ifnames[i], &temp)) { + libethernet_err("error in reading stats for interface %s\n", ifnames[i]); + continue; // no need to add this to bridge stats + } + + add_to_stats(s, &temp); + } + } + + return 0; +} + int bcm_eth_get_rmon_stats(const char *ifname, struct eth_rmon_stats *rmon) { struct ethswctl_data data; diff --git a/ethernet.c b/ethernet.c index 9fb105b2ba8c936bbbf7005be0e44bc882b02f4d..a159365c1f8ad0cbc20ee29aea247cb747131145 100644 --- a/ethernet.c +++ b/ethernet.c @@ -66,6 +66,14 @@ const struct eth_ops *get_eth_driver(const char *ifname) return eth_ops[i]; } + // The plan is to have this support in broadcom only for now, that is, + // we will present bridge level stats for broadcom only for now, hence, + // this, in the long term, we should add this support for all platforms. +#ifdef IOPSYS_BROADCOM + if (if_isbridge(ifname)) { + return eth_ops[0]; + } +#endif return NULL; }