diff --git a/include/zephyr/net/net_stats.h b/include/zephyr/net/net_stats.h index 211f2dffd30..588121f5be1 100644 --- a/include/zephyr/net/net_stats.h +++ b/include/zephyr/net/net_stats.h @@ -371,6 +371,34 @@ struct net_stats_pm { uint32_t start_time; }; +/** + * @brief Network packet filter statistics + */ +struct net_stats_pkt_filter { + /** Network packet filter RX statistics */ + struct { + /** Network packets dropped at network interface level */ + net_stats_t drop; +#if defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) + /** IPv4 packets dropped at network interface level */ + net_stats_t ipv4_drop; +#endif +#if defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK) + /** IPv6 packets dropped at network interface level */ + net_stats_t ipv6_drop; +#endif +#if defined(CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK) + /** Packets dropped at connection input */ + net_stats_t local_drop; +#endif + } rx; + + /** Network packet filter TX statistics */ + struct { + /** Network packets dropped at network interface level */ + net_stats_t drop; + } tx; +}; /** * @brief All network statistics in one struct. @@ -388,6 +416,10 @@ struct net_stats { /** IP layer errors */ struct net_stats_ip_errors ip_errors; +#if defined(CONFIG_NET_STATISTICS_PKT_FILTER) + struct net_stats_pkt_filter pkt_filter; +#endif + #if defined(CONFIG_NET_STATISTICS_IPV6) /** IPv6 statistics */ struct net_stats_ip ipv6; @@ -709,6 +741,7 @@ struct net_stats_wifi { enum net_request_stats_cmd { NET_REQUEST_STATS_CMD_GET_ALL = 1, NET_REQUEST_STATS_CMD_GET_PROCESSING_ERROR, + NET_REQUEST_STATS_CMD_GET_PKT_FILTER_DROP, NET_REQUEST_STATS_CMD_GET_BYTES, NET_REQUEST_STATS_CMD_GET_IP_ERRORS, NET_REQUEST_STATS_CMD_GET_IPV4, @@ -737,6 +770,10 @@ enum net_request_stats_cmd { #define NET_REQUEST_STATS_GET_PROCESSING_ERROR \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_PROCESSING_ERROR) +/** Request all pkt_filter drop statistics */ +#define NET_REQUEST_STATS_GET_PKT_FILTER_DROP \ + (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_PKT_FILTER_DROP) + /** Request number of received and sent bytes */ #define NET_REQUEST_STATS_GET_BYTES \ (_NET_STATS_BASE | NET_REQUEST_STATS_CMD_GET_BYTES) @@ -752,6 +789,10 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PROCESSING_ERROR); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_BYTES); NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_IP_ERRORS); +#if defined(CONFIG_NET_STATISTICS_PKT_FILTER) +NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_GET_PKT_FILTER_DROP); +#endif /* CONFIG_NET_STATISTICS_PKT_FILTER */ + /** @endcond */ #if defined(CONFIG_NET_STATISTICS_IPV4) @@ -1373,6 +1414,55 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_RESET_WIFI); #define NET_STATS_PROMETHEUS_RX_TIME(iface, dev_id, sfx) #endif +#define NET_STATS_PROMETHEUS_PKT_FILTER_IPV4(iface, dev_id, sfx) \ + NET_STATS_PROMETHEUS_COUNTER_DEFINE( \ + "Packet filter RX IPv4 drop", \ + NET_STATS_GET_INSTANCE(dev_id, sfx, pkt_filter_rx_ipv4_drop), \ + "packet_count", \ + NET_STATS_GET_COLLECTOR_NAME(dev_id, sfx), \ + NET_STATS_GET_VAR(dev_id, sfx, pkt_filter_rx_ipv4_drop),\ + &(iface)->stats.pkt_filter.rx.ipv4_drop); + +#define NET_STATS_PROMETHEUS_PKT_FILTER_IPV6(iface, dev_id, sfx) \ + NET_STATS_PROMETHEUS_COUNTER_DEFINE( \ + "Packet filter RX IPv6 drop", \ + NET_STATS_GET_INSTANCE(dev_id, sfx, pkt_filter_rx_ipv6_drop), \ + "packet_count", \ + NET_STATS_GET_COLLECTOR_NAME(dev_id, sfx), \ + NET_STATS_GET_VAR(dev_id, sfx, pkt_filter_rx_ipv6_drop),\ + &(iface)->stats.pkt_filter.rx.ipv6_drop); + +#define NET_STATS_PROMETHEUS_PKT_FILTER_LOCAL(iface, dev_id, sfx) \ + NET_STATS_PROMETHEUS_COUNTER_DEFINE( \ + "Packet filter RX local drop", \ + NET_STATS_GET_INSTANCE(dev_id, sfx, pkt_filter_rx_local_drop), \ + "packet_count", \ + NET_STATS_GET_COLLECTOR_NAME(dev_id, sfx), \ + NET_STATS_GET_VAR(dev_id, sfx, pkt_filter_rx_local_drop),\ + &(iface)->stats.pkt_filter.rx.local_drop); + +#define NET_STATS_PROMETHEUS_PKT_FILTER(iface, dev_id, sfx) \ + NET_STATS_PROMETHEUS_COUNTER_DEFINE( \ + "Packet filter RX drop", \ + NET_STATS_GET_INSTANCE(dev_id, sfx, pkt_filter_rx_drop),\ + "packet_count", \ + NET_STATS_GET_COLLECTOR_NAME(dev_id, sfx), \ + NET_STATS_GET_VAR(dev_id, sfx, pkt_filter_rx_drop), \ + &(iface)->stats.pkt_filter.rx.drop); \ + NET_STATS_PROMETHEUS_COUNTER_DEFINE( \ + "Packet filter TX drop", \ + NET_STATS_GET_INSTANCE(dev_id, sfx, pkt_filter_tx_drop),\ + "packet_count", \ + NET_STATS_GET_COLLECTOR_NAME(dev_id, sfx), \ + NET_STATS_GET_VAR(dev_id, sfx, pkt_filter_tx_drop), \ + &(iface)->stats.pkt_filter.tx.drop); \ + IF_ENABLED(CONFIG_NET_PKT_FILTER_IPV4_HOOK, \ + (NET_STATS_PROMETHEUS_PKT_FILTER_IPV4(iface, dev_id, sfx))) \ + IF_ENABLED(CONFIG_NET_PKT_FILTER_IPV6_HOOK, \ + (NET_STATS_PROMETHEUS_PKT_FILTER_IPV6(iface, dev_id, sfx))) \ + IF_ENABLED(CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK, \ + (NET_STATS_PROMETHEUS_PKT_FILTER_LOCAL(iface, dev_id, sfx))) + /* Per network interface statistics via Prometheus */ #define NET_STATS_PROMETHEUS(iface, dev_id, sfx) \ NET_STATS_PROMETHEUS_COUNTER_DEFINE( \ @@ -1382,6 +1472,8 @@ NET_MGMT_DEFINE_REQUEST_HANDLER(NET_REQUEST_STATS_RESET_WIFI); NET_STATS_GET_COLLECTOR_NAME(dev_id, sfx), \ NET_STATS_GET_VAR(dev_id, sfx, processing_error), \ &(iface)->stats.processing_error); \ + IF_ENABLED(CONFIG_NET_STATISTICS_PKT_FILTER, \ + (NET_STATS_PROMETHEUS_PKT_FILTER(iface, dev_id, sfx))) \ /* IP layer error statistics */ \ NET_STATS_PROMETHEUS_COUNTER_DEFINE( \ "IP proto error", \ diff --git a/subsys/net/ip/Kconfig.stats b/subsys/net/ip/Kconfig.stats index 68f2c0a92d6..e7ed8dfaa28 100644 --- a/subsys/net/ip/Kconfig.stats +++ b/subsys/net/ip/Kconfig.stats @@ -114,6 +114,13 @@ config NET_STATISTICS_DNS help Keep track of DNS related statistics +config NET_STATISTICS_PKT_FILTER + bool "Network packet filter statistics" + depends on NET_PKT_FILTER + default y + help + Keep track of network packet filter related statistics + config NET_STATISTICS_PPP bool "Point-to-point (PPP) statistics" depends on NET_L2_PPP diff --git a/subsys/net/ip/connection.c b/subsys/net/ip/connection.c index c03b7f9b8ca..8dd431fea33 100644 --- a/subsys/net/ip/connection.c +++ b/subsys/net/ip/connection.c @@ -676,6 +676,7 @@ enum net_verdict net_conn_input(struct net_pkt *pkt, if (!net_pkt_filter_local_in_recv_ok(pkt)) { /* drop the packet */ + net_stats_update_filter_rx_local_drop(net_pkt_iface(pkt)); return NET_DROP; } diff --git a/subsys/net/ip/ipv4.c b/subsys/net/ip/ipv4.c index 64749cb64e9..0add73288bb 100644 --- a/subsys/net/ip/ipv4.c +++ b/subsys/net/ip/ipv4.c @@ -343,6 +343,7 @@ enum net_verdict net_ipv4_input(struct net_pkt *pkt, bool is_loopback) if (!net_pkt_filter_ip_recv_ok(pkt)) { /* drop the packet */ + net_stats_update_filter_rx_ipv4_drop(net_pkt_iface(pkt)); return NET_DROP; } diff --git a/subsys/net/ip/ipv6.c b/subsys/net/ip/ipv6.c index 24cc3d12871..7690ce38884 100644 --- a/subsys/net/ip/ipv6.c +++ b/subsys/net/ip/ipv6.c @@ -584,6 +584,7 @@ enum net_verdict net_ipv6_input(struct net_pkt *pkt, bool is_loopback) if (!net_pkt_filter_ip_recv_ok(pkt)) { /* drop the packet */ NET_DBG("DROP: pkt filter"); + net_stats_update_filter_rx_ipv6_drop(net_pkt_iface(pkt)); return NET_DROP; } diff --git a/subsys/net/ip/net_core.c b/subsys/net/ip/net_core.c index 0f3d5d7418a..97b6bd95f17 100644 --- a/subsys/net/ip/net_core.c +++ b/subsys/net/ip/net_core.c @@ -583,7 +583,10 @@ int net_recv_data(struct net_if *iface, struct net_pkt *pkt) net_pkt_set_iface(pkt, iface); if (!net_pkt_filter_recv_ok(pkt)) { - /* silently drop the packet */ + /* Silently drop the packet, but update the statistics in order + * to be able to monitor filter activity. + */ + net_stats_update_filter_rx_drop(net_pkt_iface(pkt)); net_pkt_unref(pkt); } else { net_queue_rx(iface, pkt); diff --git a/subsys/net/ip/net_if.c b/subsys/net/ip/net_if.c index e03d290044f..4c91f7b1721 100644 --- a/subsys/net/ip/net_if.c +++ b/subsys/net/ip/net_if.c @@ -340,7 +340,10 @@ void net_process_tx_packet(struct net_pkt *pkt) void net_if_try_queue_tx(struct net_if *iface, struct net_pkt *pkt, k_timeout_t timeout) { if (!net_pkt_filter_send_ok(pkt)) { - /* silently drop the packet */ + /* Silently drop the packet, but update the statistics in order + * to be able to monitor filter activity. + */ + net_stats_update_filter_tx_drop(net_pkt_iface(pkt)); net_pkt_unref(pkt); return; } diff --git a/subsys/net/ip/net_stats.h b/subsys/net/ip/net_stats.h index 6a7a3cdbd93..17b3f0d8c7f 100644 --- a/subsys/net/ip/net_stats.h +++ b/subsys/net/ip/net_stats.h @@ -59,12 +59,56 @@ static inline void net_stats_update_bytes_sent(struct net_if *iface, { UPDATE_STAT(iface, stats.bytes.sent += bytes); } + +#if defined(CONFIG_NET_STATISTICS_PKT_FILTER) +static inline void net_stats_update_filter_rx_drop(struct net_if *iface) +{ + UPDATE_STAT(iface, stats.pkt_filter.rx.drop++); +} + +static inline void net_stats_update_filter_tx_drop(struct net_if *iface) +{ + UPDATE_STAT(iface, stats.pkt_filter.tx.drop++); +} + +static inline void net_stats_update_filter_rx_ipv4_drop(struct net_if *iface) +{ +#if defined(CONFIG_NET_PKT_FILTER_IPV4_HOOK) + UPDATE_STAT(iface, stats.pkt_filter.rx.ipv4_drop++); +#endif +} + +static inline void net_stats_update_filter_rx_ipv6_drop(struct net_if *iface) +{ +#if defined(CONFIG_NET_PKT_FILTER_IPV6_HOOK) + UPDATE_STAT(iface, stats.pkt_filter.rx.ipv6_drop++); +#endif +} + +static inline void net_stats_update_filter_rx_local_drop(struct net_if *iface) +{ +#if defined(CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK) + UPDATE_STAT(iface, stats.pkt_filter.rx.local_drop++); +#endif +} +#else /* CONFIG_NET_STATISTICS_PKT_FILTER */ +#define net_stats_update_filter_rx_drop(iface) +#define net_stats_update_filter_tx_drop(iface) +#define net_stats_update_filter_rx_ipv4_drop(iface) +#define net_stats_update_filter_rx_ipv6_drop(iface) +#define net_stats_update_filter_rx_local_drop(iface) +#endif /* CONFIG_NET_STATISTICS_PKT_FILTER */ #else #define net_stats_update_processing_error(iface) #define net_stats_update_ip_errors_protoerr(iface) #define net_stats_update_ip_errors_vhlerr(iface) #define net_stats_update_bytes_recv(iface, bytes) #define net_stats_update_bytes_sent(iface, bytes) +#define net_stats_update_filter_rx_drop(iface) +#define net_stats_update_filter_tx_drop(iface) +#define net_stats_update_filter_rx_ipv4_drop(iface) +#define net_stats_update_filter_rx_ipv6_drop(iface) +#define net_stats_update_filter_rx_local_drop(iface) #endif /* CONFIG_NET_STATISTICS */ #if defined(CONFIG_NET_STATISTICS_IPV6) && defined(CONFIG_NET_NATIVE_IPV6) diff --git a/subsys/net/lib/shell/stats.c b/subsys/net/lib/shell/stats.c index cda7d9401e9..64256bc7473 100644 --- a/subsys/net/lib/shell/stats.c +++ b/subsys/net/lib/shell/stats.c @@ -559,6 +559,21 @@ static void net_shell_print_statistics(struct net_if *iface, void *user_data) GET_STAT(iface, dns.sent), GET_STAT(iface, dns.drop)); #endif /* CONFIG_NET_STATISTICS_DNS */ +#if defined(CONFIG_NET_STATISTICS_PKT_FILTER) + PR("Filter drop rx %d" + IF_ENABLED(CONFIG_NET_PKT_FILTER_IPV4_HOOK, ("\tIPv4\t%d")) + IF_ENABLED(CONFIG_NET_PKT_FILTER_IPV6_HOOK, ("\tIPv6\t%d")) + IF_ENABLED(CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK, ("\tlocal\t%d")) + "\ttx\t%d\n", + GET_STAT(iface, pkt_filter.rx.drop), + IF_ENABLED(CONFIG_NET_PKT_FILTER_IPV4_HOOK, + (GET_STAT(iface, pkt_filter.rx.ipv4_drop),)) + IF_ENABLED(CONFIG_NET_PKT_FILTER_IPV6_HOOK, + (GET_STAT(iface, pkt_filter.rx.ipv6_drop),)) + IF_ENABLED(CONFIG_NET_PKT_FILTER_LOCAL_IN_HOOK, + (GET_STAT(iface, pkt_filter.rx.local_drop),)) + GET_STAT(iface, pkt_filter.tx.drop)); +#endif /* CONFIG_NET_STATISTICS_DNS */ PR("Bytes received %u\n", GET_STAT(iface, bytes.received)); PR("Bytes sent %u\n", GET_STAT(iface, bytes.sent));