Instead of using 32 bit enum values for event numbers, convert the code to use 64 bit long bit fields. This means that the user API is changed to use 64 bit event values instead of 32 bit event values. Signed-off-by: Jukka Rissanen <jukka.rissanen@nordicsemi.no>
574 lines
15 KiB
C
574 lines
15 KiB
C
/*
|
|
* Copyright (c) 2016 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_PERIODIC_OUTPUT)
|
|
#define NET_LOG_LEVEL LOG_LEVEL_INF
|
|
#else
|
|
#define NET_LOG_LEVEL CONFIG_NET_STATISTICS_LOG_LEVEL
|
|
#endif
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_REGISTER(net_stats, NET_LOG_LEVEL);
|
|
|
|
#include <zephyr/kernel.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <errno.h>
|
|
#include <zephyr/net/net_core.h>
|
|
#include <zephyr/net/prometheus/collector.h>
|
|
#include <zephyr/net/prometheus/counter.h>
|
|
#include <zephyr/net/prometheus/gauge.h>
|
|
#include <zephyr/net/prometheus/histogram.h>
|
|
#include <zephyr/net/prometheus/summary.h>
|
|
|
|
#include "net_stats.h"
|
|
#include "net_private.h"
|
|
|
|
/* Global network statistics.
|
|
*
|
|
* The variable needs to be global so that the GET_STAT() macro can access it
|
|
* from net_shell.c
|
|
*/
|
|
struct net_stats net_stats = { 0 };
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_PERIODIC_OUTPUT)
|
|
|
|
#define PRINT_STATISTICS_INTERVAL (30 * MSEC_PER_SEC)
|
|
|
|
#if NET_TC_COUNT > 1
|
|
static const char *priority2str(enum net_priority priority)
|
|
{
|
|
switch (priority) {
|
|
case NET_PRIORITY_BK:
|
|
return "BK"; /* Background */
|
|
case NET_PRIORITY_BE:
|
|
return "BE"; /* Best effort */
|
|
case NET_PRIORITY_EE:
|
|
return "EE"; /* Excellent effort */
|
|
case NET_PRIORITY_CA:
|
|
return "CA"; /* Critical applications */
|
|
case NET_PRIORITY_VI:
|
|
return "VI"; /* Video, < 100 ms latency and jitter */
|
|
case NET_PRIORITY_VO:
|
|
return "VO"; /* Voice, < 10 ms latency and jitter */
|
|
case NET_PRIORITY_IC:
|
|
return "IC"; /* Internetwork control */
|
|
case NET_PRIORITY_NC:
|
|
return "NC"; /* Network control */
|
|
}
|
|
|
|
return "??";
|
|
}
|
|
#endif
|
|
|
|
static inline int64_t cmp_val(uint64_t val1, uint64_t val2)
|
|
{
|
|
return (int64_t)(val1 - val2);
|
|
}
|
|
|
|
static inline void stats(struct net_if *iface)
|
|
{
|
|
static uint64_t next_print;
|
|
uint64_t curr = k_uptime_get();
|
|
int64_t cmp = cmp_val(curr, next_print);
|
|
int i;
|
|
|
|
if (!next_print || (abs(cmp) > PRINT_STATISTICS_INTERVAL)) {
|
|
if (iface) {
|
|
NET_INFO("Interface %p [%d]", iface,
|
|
net_if_get_by_iface(iface));
|
|
} else {
|
|
NET_INFO("Global statistics:");
|
|
}
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6)
|
|
NET_INFO("IPv6 recv %u\tsent\t%u\tdrop\t%u\tforwarded\t%u",
|
|
GET_STAT(iface, ipv6.recv),
|
|
GET_STAT(iface, ipv6.sent),
|
|
GET_STAT(iface, ipv6.drop),
|
|
GET_STAT(iface, ipv6.forwarded));
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6_ND)
|
|
NET_INFO("IPv6 ND recv %u\tsent\t%u\tdrop\t%u",
|
|
GET_STAT(iface, ipv6_nd.recv),
|
|
GET_STAT(iface, ipv6_nd.sent),
|
|
GET_STAT(iface, ipv6_nd.drop));
|
|
#endif /* CONFIG_NET_STATISTICS_IPV6_ND */
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6_PMTU)
|
|
NET_INFO("IPv6 PMTU recv %u\tsent\t%u\tdrop\t%u",
|
|
GET_STAT(iface, ipv6_pmtu.recv),
|
|
GET_STAT(iface, ipv6_pmtu.sent),
|
|
GET_STAT(iface, ipv6_pmtu.drop));
|
|
#endif /* CONFIG_NET_STATISTICS_IPV6_PMTU */
|
|
#if defined(CONFIG_NET_STATISTICS_MLD)
|
|
NET_INFO("IPv6 MLD recv %u\tsent\t%u\tdrop\t%u",
|
|
GET_STAT(iface, ipv6_mld.recv),
|
|
GET_STAT(iface, ipv6_mld.sent),
|
|
GET_STAT(iface, ipv6_mld.drop));
|
|
#endif /* CONFIG_NET_STATISTICS_MLD */
|
|
#endif /* CONFIG_NET_STATISTICS_IPV6 */
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV4)
|
|
NET_INFO("IPv4 recv %u\tsent\t%u\tdrop\t%u\tforwarded\t%u",
|
|
GET_STAT(iface, ipv4.recv),
|
|
GET_STAT(iface, ipv4.sent),
|
|
GET_STAT(iface, ipv4.drop),
|
|
GET_STAT(iface, ipv4.forwarded));
|
|
#endif /* CONFIG_NET_STATISTICS_IPV4 */
|
|
|
|
NET_INFO("IP vhlerr %u\thblener\t%u\tlblener\t%u",
|
|
GET_STAT(iface, ip_errors.vhlerr),
|
|
GET_STAT(iface, ip_errors.hblenerr),
|
|
GET_STAT(iface, ip_errors.lblenerr));
|
|
NET_INFO("IP fragerr %u\tchkerr\t%u\tprotoer\t%u",
|
|
GET_STAT(iface, ip_errors.fragerr),
|
|
GET_STAT(iface, ip_errors.chkerr),
|
|
GET_STAT(iface, ip_errors.protoerr));
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV4_PMTU)
|
|
NET_INFO("IPv4 PMTU recv %u\tsent\t%u\tdrop\t%u",
|
|
GET_STAT(iface, ipv4_pmtu.recv),
|
|
GET_STAT(iface, ipv4_pmtu.sent),
|
|
GET_STAT(iface, ipv4_pmtu.drop));
|
|
#endif /* CONFIG_NET_STATISTICS_IPV4_PMTU */
|
|
|
|
NET_INFO("ICMP recv %u\tsent\t%u\tdrop\t%u",
|
|
GET_STAT(iface, icmp.recv),
|
|
GET_STAT(iface, icmp.sent),
|
|
GET_STAT(iface, icmp.drop));
|
|
NET_INFO("ICMP typeer %u\tchkerr\t%u",
|
|
GET_STAT(iface, icmp.typeerr),
|
|
GET_STAT(iface, icmp.chkerr));
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_UDP)
|
|
NET_INFO("UDP recv %u\tsent\t%u\tdrop\t%u",
|
|
GET_STAT(iface, udp.recv),
|
|
GET_STAT(iface, udp.sent),
|
|
GET_STAT(iface, udp.drop));
|
|
NET_INFO("UDP chkerr %u",
|
|
GET_STAT(iface, udp.chkerr));
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_TCP)
|
|
NET_INFO("TCP bytes recv %llu\tsent\t%llu",
|
|
GET_STAT(iface, tcp.bytes.received),
|
|
GET_STAT(iface, tcp.bytes.sent));
|
|
NET_INFO("TCP seg recv %u\tsent\t%u\tdrop\t%u",
|
|
GET_STAT(iface, tcp.recv),
|
|
GET_STAT(iface, tcp.sent),
|
|
GET_STAT(iface, tcp.drop));
|
|
NET_INFO("TCP seg resent %u\tchkerr\t%u\tackerr\t%u",
|
|
GET_STAT(iface, tcp.resent),
|
|
GET_STAT(iface, tcp.chkerr),
|
|
GET_STAT(iface, tcp.ackerr));
|
|
NET_INFO("TCP seg rsterr %u\trst\t%u\tre-xmit\t%u",
|
|
GET_STAT(iface, tcp.rsterr),
|
|
GET_STAT(iface, tcp.rst),
|
|
GET_STAT(iface, tcp.rexmit));
|
|
NET_INFO("TCP conn drop %u\tconnrst\t%u",
|
|
GET_STAT(iface, tcp.conndrop),
|
|
GET_STAT(iface, tcp.connrst));
|
|
#endif
|
|
|
|
NET_INFO("Bytes received %llu", GET_STAT(iface, bytes.received));
|
|
NET_INFO("Bytes sent %llu", GET_STAT(iface, bytes.sent));
|
|
NET_INFO("Processing err %u",
|
|
GET_STAT(iface, processing_error));
|
|
|
|
#if NET_TC_COUNT > 1
|
|
#if NET_TC_TX_COUNT > 1
|
|
NET_INFO("TX traffic class statistics:");
|
|
NET_INFO("TC Priority\tSent pkts\tbytes");
|
|
|
|
for (i = 0; i < NET_TC_TX_COUNT; i++) {
|
|
NET_INFO("[%d] %s (%u)\t%u\t\t%llu", i,
|
|
priority2str(GET_STAT(iface,
|
|
tc.sent[i].priority)),
|
|
GET_STAT(iface, tc.sent[i].priority),
|
|
GET_STAT(iface, tc.sent[i].pkts),
|
|
GET_STAT(iface, tc.sent[i].bytes));
|
|
}
|
|
#endif
|
|
|
|
#if NET_TC_RX_COUNT > 1
|
|
NET_INFO("RX traffic class statistics:");
|
|
NET_INFO("TC Priority\tRecv pkts\tbytes");
|
|
|
|
for (i = 0; i < NET_TC_RX_COUNT; i++) {
|
|
NET_INFO("[%d] %s (%u)\t%u\t\t%llu", i,
|
|
priority2str(GET_STAT(iface,
|
|
tc.recv[i].priority)),
|
|
GET_STAT(iface, tc.recv[i].priority),
|
|
GET_STAT(iface, tc.recv[i].pkts),
|
|
GET_STAT(iface, tc.recv[i].bytes));
|
|
}
|
|
#endif
|
|
#else /* NET_TC_COUNT > 1 */
|
|
ARG_UNUSED(i);
|
|
#endif /* NET_TC_COUNT > 1 */
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_POWER_MANAGEMENT)
|
|
NET_INFO("Power management statistics:");
|
|
NET_INFO("Last suspend time: %u ms",
|
|
GET_STAT(iface, pm.last_suspend_time));
|
|
NET_INFO("Got suspended %u times",
|
|
GET_STAT(iface, pm.suspend_count));
|
|
NET_INFO("Average suspend time: %u ms",
|
|
(uint32_t)(GET_STAT(iface, pm.overall_suspend_time) /
|
|
GET_STAT(iface, pm.suspend_count)));
|
|
NET_INFO("Total suspended time: %llu ms",
|
|
GET_STAT(iface, pm.overall_suspend_time));
|
|
#endif
|
|
next_print = curr + PRINT_STATISTICS_INTERVAL;
|
|
}
|
|
}
|
|
|
|
void net_print_statistics_iface(struct net_if *iface)
|
|
{
|
|
/* In order to make the info print lines shorter, use shorter
|
|
* function name.
|
|
*/
|
|
stats(iface);
|
|
}
|
|
|
|
static void iface_cb(struct net_if *iface, void *user_data)
|
|
{
|
|
net_print_statistics_iface(iface);
|
|
}
|
|
|
|
void net_print_statistics_all(void)
|
|
{
|
|
net_if_foreach(iface_cb, NULL);
|
|
}
|
|
|
|
void net_print_statistics(void)
|
|
{
|
|
net_print_statistics_iface(NULL);
|
|
}
|
|
|
|
#endif /* CONFIG_NET_STATISTICS_PERIODIC_OUTPUT */
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_USER_API)
|
|
|
|
static int net_stats_get(uint64_t mgmt_request, struct net_if *iface,
|
|
void *data, size_t len)
|
|
{
|
|
size_t len_chk = 0;
|
|
void *src = NULL;
|
|
|
|
switch (NET_MGMT_GET_COMMAND(mgmt_request)) {
|
|
case NET_REQUEST_STATS_CMD_GET_ALL:
|
|
len_chk = sizeof(struct net_stats);
|
|
#if defined(CONFIG_NET_STATISTICS_PER_INTERFACE)
|
|
src = iface ? &iface->stats : &net_stats;
|
|
#else
|
|
src = &net_stats;
|
|
#endif
|
|
break;
|
|
case NET_REQUEST_STATS_CMD_GET_PROCESSING_ERROR:
|
|
len_chk = sizeof(net_stats_t);
|
|
src = GET_STAT_ADDR(iface, processing_error);
|
|
break;
|
|
case NET_REQUEST_STATS_CMD_GET_BYTES:
|
|
len_chk = sizeof(struct net_stats_bytes);
|
|
src = GET_STAT_ADDR(iface, bytes);
|
|
break;
|
|
case NET_REQUEST_STATS_CMD_GET_IP_ERRORS:
|
|
len_chk = sizeof(struct net_stats_ip_errors);
|
|
src = GET_STAT_ADDR(iface, ip_errors);
|
|
break;
|
|
#if defined(CONFIG_NET_STATISTICS_IPV4)
|
|
case NET_REQUEST_STATS_CMD_GET_IPV4:
|
|
len_chk = sizeof(struct net_stats_ip);
|
|
src = GET_STAT_ADDR(iface, ipv4);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6)
|
|
case NET_REQUEST_STATS_CMD_GET_IPV6:
|
|
len_chk = sizeof(struct net_stats_ip);
|
|
src = GET_STAT_ADDR(iface, ipv6);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6_ND)
|
|
case NET_REQUEST_STATS_CMD_GET_IPV6_ND:
|
|
len_chk = sizeof(struct net_stats_ipv6_nd);
|
|
src = GET_STAT_ADDR(iface, ipv6_nd);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6_PMTU)
|
|
case NET_REQUEST_STATS_CMD_GET_IPV6_PMTU:
|
|
len_chk = sizeof(struct net_stats_ipv6_pmtu);
|
|
src = GET_STAT_ADDR(iface, ipv6_pmtu);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_IPV4_PMTU)
|
|
case NET_REQUEST_STATS_CMD_GET_IPV4_PMTU:
|
|
len_chk = sizeof(struct net_stats_ipv4_pmtu);
|
|
src = GET_STAT_ADDR(iface, ipv4_pmtu);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_ICMP)
|
|
case NET_REQUEST_STATS_CMD_GET_ICMP:
|
|
len_chk = sizeof(struct net_stats_icmp);
|
|
src = GET_STAT_ADDR(iface, icmp);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_UDP)
|
|
case NET_REQUEST_STATS_CMD_GET_UDP:
|
|
len_chk = sizeof(struct net_stats_udp);
|
|
src = GET_STAT_ADDR(iface, udp);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_TCP)
|
|
case NET_REQUEST_STATS_CMD_GET_TCP:
|
|
len_chk = sizeof(struct net_stats_tcp);
|
|
src = GET_STAT_ADDR(iface, tcp);
|
|
break;
|
|
#endif
|
|
#if defined(CONFIG_NET_STATISTICS_POWER_MANAGEMENT)
|
|
case NET_REQUEST_STATS_GET_PM:
|
|
len_chk = sizeof(struct net_stats_pm);
|
|
src = GET_STAT_ADDR(iface, pm);
|
|
break;
|
|
#endif
|
|
}
|
|
|
|
if (len != len_chk || !src) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
memcpy(data, src, len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_ALL,
|
|
net_stats_get);
|
|
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PROCESSING_ERROR,
|
|
net_stats_get);
|
|
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_BYTES,
|
|
net_stats_get);
|
|
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IP_ERRORS,
|
|
net_stats_get);
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV4)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IPV4,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IPV6,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6_ND)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IPV6_ND,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV6_PMTU)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IPV6_PMTU,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_IPV4_PMTU)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IPV4_PMTU,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_ICMP)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_ICMP,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_UDP)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_UDP,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_TCP)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_TCP,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_POWER_MANAGEMENT)
|
|
NET_MGMT_REGISTER_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PM,
|
|
net_stats_get);
|
|
#endif
|
|
|
|
#endif /* CONFIG_NET_STATISTICS_USER_API */
|
|
|
|
void net_stats_reset(struct net_if *iface)
|
|
{
|
|
if (iface) {
|
|
net_if_stats_reset(iface);
|
|
return;
|
|
}
|
|
|
|
net_if_stats_reset_all();
|
|
memset(&net_stats, 0, sizeof(net_stats));
|
|
}
|
|
|
|
#if defined(CONFIG_NET_STATISTICS_VIA_PROMETHEUS)
|
|
static void register_prometheus_metrics(struct net_if *iface)
|
|
{
|
|
int total_count = 0;
|
|
|
|
/* Find the correct collector for this interface */
|
|
STRUCT_SECTION_FOREACH(prometheus_collector, entry) {
|
|
if (entry->user_data == (void *)iface) {
|
|
iface->collector = entry;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (iface->collector == NULL) {
|
|
NET_DBG("No collector found for interface %d",
|
|
net_if_get_by_iface(iface));
|
|
return;
|
|
}
|
|
|
|
STRUCT_SECTION_FOREACH(prometheus_counter, entry) {
|
|
if (entry->base.collector != iface->collector) {
|
|
continue;
|
|
}
|
|
|
|
prometheus_collector_register_metric(iface->collector,
|
|
&entry->base);
|
|
total_count++;
|
|
}
|
|
|
|
STRUCT_SECTION_FOREACH(prometheus_gauge, entry) {
|
|
if (entry->base.collector != iface->collector) {
|
|
continue;
|
|
}
|
|
|
|
prometheus_collector_register_metric(iface->collector,
|
|
&entry->base);
|
|
total_count++;
|
|
}
|
|
|
|
STRUCT_SECTION_FOREACH(prometheus_summary, entry) {
|
|
if (entry->base.collector != iface->collector) {
|
|
continue;
|
|
}
|
|
|
|
prometheus_collector_register_metric(iface->collector,
|
|
&entry->base);
|
|
total_count++;
|
|
}
|
|
|
|
STRUCT_SECTION_FOREACH(prometheus_histogram, entry) {
|
|
if (entry->base.collector != iface->collector) {
|
|
continue;
|
|
}
|
|
|
|
prometheus_collector_register_metric(iface->collector,
|
|
&entry->base);
|
|
total_count++;
|
|
}
|
|
|
|
NET_DBG("Registered %d metrics for interface %d", total_count,
|
|
net_if_get_by_iface(iface));
|
|
}
|
|
|
|
/* Do not update metrics one by one as that would require searching
|
|
* each individual metric from the collector. Instead, let the
|
|
* Prometheus API scrape the data from net_stats stored in net_if when
|
|
* needed.
|
|
*/
|
|
int net_stats_prometheus_scrape(struct prometheus_collector *collector,
|
|
struct prometheus_metric *metric,
|
|
void *user_data)
|
|
{
|
|
struct net_if *iface = user_data;
|
|
net_stats_t value;
|
|
|
|
if (!iface) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
if (iface->collector != collector) {
|
|
return -EINVAL;
|
|
}
|
|
|
|
/* Update the metrics */
|
|
if (metric->type == PROMETHEUS_COUNTER) {
|
|
struct prometheus_counter *counter =
|
|
CONTAINER_OF(metric, struct prometheus_counter, base);
|
|
|
|
if (counter->user_data == NULL) {
|
|
return -EAGAIN;
|
|
}
|
|
|
|
value = *((net_stats_t *)counter->user_data);
|
|
|
|
prometheus_counter_set(counter, (uint64_t)value);
|
|
|
|
} else if (metric->type == PROMETHEUS_GAUGE) {
|
|
struct prometheus_gauge *gauge =
|
|
CONTAINER_OF(metric, struct prometheus_gauge, base);
|
|
|
|
if (gauge->user_data == NULL) {
|
|
return -EAGAIN;
|
|
}
|
|
|
|
value = *((net_stats_t *)gauge->user_data);
|
|
|
|
prometheus_gauge_set(gauge, (double)value);
|
|
|
|
} else if (metric->type == PROMETHEUS_HISTOGRAM) {
|
|
struct prometheus_histogram *histogram =
|
|
CONTAINER_OF(metric, struct prometheus_histogram, base);
|
|
|
|
if (histogram->user_data == NULL) {
|
|
return -EAGAIN;
|
|
}
|
|
|
|
} else if (metric->type == PROMETHEUS_SUMMARY) {
|
|
struct prometheus_summary *summary =
|
|
CONTAINER_OF(metric, struct prometheus_summary, base);
|
|
|
|
if (summary->user_data == NULL) {
|
|
return -EAGAIN;
|
|
}
|
|
|
|
if (IS_ENABLED(CONFIG_NET_PKT_TXTIME_STATS) &&
|
|
strstr(metric->name, "_tx_time_summary") == 0) {
|
|
IF_ENABLED(CONFIG_NET_PKT_TXTIME_STATS,
|
|
(struct net_stats_tx_time *tx_time =
|
|
(struct net_stats_tx_time *)summary->user_data;
|
|
|
|
prometheus_summary_observe_set(
|
|
summary,
|
|
(double)tx_time->sum,
|
|
(unsigned long)tx_time->count)));
|
|
} else if (IS_ENABLED(CONFIG_NET_PKT_RXTIME_STATS) &&
|
|
strstr(metric->name, "_rx_time_summary") == 0) {
|
|
IF_ENABLED(CONFIG_NET_PKT_RXTIME_STATS,
|
|
(struct net_stats_rx_time *rx_time =
|
|
(struct net_stats_rx_time *)summary->user_data;
|
|
|
|
prometheus_summary_observe_set(
|
|
summary,
|
|
(double)rx_time->sum,
|
|
(unsigned long)rx_time->count)));
|
|
}
|
|
} else {
|
|
NET_DBG("Unknown metric type %d", metric->type);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void net_stats_prometheus_init(struct net_if *iface)
|
|
{
|
|
register_prometheus_metrics(iface);
|
|
}
|
|
#endif /* CONFIG_NET_STATISTICS_VIA_PROMETHEUS */
|