Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

ovpn: store tunnel and transport statistics

Byte/packet counters for in-tunnel and transport streams
are now initialized and updated as needed.

To be exported via netlink.

Signed-off-by: Antonio Quartulli <antonio@openvpn.net>
Link: https://patch.msgid.link/20250415-b4-ovpn-v26-10-577f6097b964@openvpn.net
Reviewed-by: Sabrina Dubroca <sd@queasysnail.net>
Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Signed-off-by: Paolo Abeni <pabeni@redhat.com>

authored by

Antonio Quartulli and committed by
Paolo Abeni
04ca1495 8534731d

+87 -1
+1
drivers/net/ovpn/Makefile
··· 17 17 ovpn-y += peer.o 18 18 ovpn-y += pktid.o 19 19 ovpn-y += socket.o 20 + ovpn-y += stats.o 20 21 ovpn-y += udp.o
+11 -1
drivers/net/ovpn/io.c
··· 12 12 #include <linux/skbuff.h> 13 13 #include <net/gro_cells.h> 14 14 #include <net/gso.h> 15 + #include <net/ip.h> 15 16 16 17 #include "ovpnpriv.h" 17 18 #include "peer.h" ··· 56 55 /* cause packet to be "received" by the interface */ 57 56 pkt_len = skb->len; 58 57 ret = gro_cells_receive(&peer->ovpn->gro_cells, skb); 59 - if (likely(ret == NET_RX_SUCCESS)) 58 + if (likely(ret == NET_RX_SUCCESS)) { 60 59 /* update RX stats with the size of decrypted packet */ 60 + ovpn_peer_stats_increment_rx(&peer->vpn_stats, pkt_len); 61 61 dev_dstats_rx_add(peer->ovpn->dev, pkt_len); 62 + } 62 63 } 63 64 64 65 void ovpn_decrypt_post(void *data, int ret) ··· 155 152 struct ovpn_crypto_key_slot *ks; 156 153 u8 key_id; 157 154 155 + ovpn_peer_stats_increment_rx(&peer->link_stats, skb->len); 156 + 158 157 /* get the key slot matching the key ID in the received packet */ 159 158 key_id = ovpn_key_id_from_skb(skb); 160 159 ks = ovpn_crypto_key_id_to_slot(&peer->crypto, key_id); ··· 180 175 struct sk_buff *skb = data; 181 176 struct ovpn_socket *sock; 182 177 struct ovpn_peer *peer; 178 + unsigned int orig_len; 183 179 184 180 /* encryption is happening asynchronously. This function will be 185 181 * called later by the crypto callback with a proper return value ··· 200 194 goto err; 201 195 202 196 skb_mark_not_on_list(skb); 197 + orig_len = skb->len; 203 198 204 199 rcu_read_lock(); 205 200 sock = rcu_dereference(peer->sock); ··· 215 208 /* no transport configured yet */ 216 209 goto err_unlock; 217 210 } 211 + 212 + ovpn_peer_stats_increment_tx(&peer->link_stats, orig_len); 218 213 /* skb passed down the stack - don't free it */ 219 214 skb = NULL; 220 215 err_unlock: ··· 331 322 goto drop; 332 323 } 333 324 325 + ovpn_peer_stats_increment_tx(&peer->vpn_stats, skb->len); 334 326 ovpn_send(ovpn, skb_list.next, peer); 335 327 336 328 return NETDEV_TX_OK;
+2
drivers/net/ovpn/peer.c
··· 61 61 ovpn_crypto_state_init(&peer->crypto); 62 62 spin_lock_init(&peer->lock); 63 63 kref_init(&peer->refcount); 64 + ovpn_peer_stats_init(&peer->vpn_stats); 65 + ovpn_peer_stats_init(&peer->link_stats); 64 66 65 67 ret = dst_cache_init(&peer->dst_cache, GFP_KERNEL); 66 68 if (ret < 0) {
+5
drivers/net/ovpn/peer.h
··· 14 14 15 15 #include "crypto.h" 16 16 #include "socket.h" 17 + #include "stats.h" 17 18 18 19 /** 19 20 * struct ovpn_peer - the main remote peer object ··· 28 27 * @crypto: the crypto configuration (ciphers, keys, etc..) 29 28 * @dst_cache: cache for dst_entry used to send to peer 30 29 * @bind: remote peer binding 30 + * @vpn_stats: per-peer in-VPN TX/RX stats 31 + * @link_stats: per-peer link/transport TX/RX stats 31 32 * @delete_reason: why peer was deleted (i.e. timeout, transport error, ..) 32 33 * @lock: protects binding to peer (bind) 33 34 * @refcount: reference counter ··· 48 45 struct ovpn_crypto_state crypto; 49 46 struct dst_cache dst_cache; 50 47 struct ovpn_bind __rcu *bind; 48 + struct ovpn_peer_stats vpn_stats; 49 + struct ovpn_peer_stats link_stats; 51 50 enum ovpn_del_peer_reason delete_reason; 52 51 spinlock_t lock; /* protects bind */ 53 52 struct kref refcount;
+21
drivers/net/ovpn/stats.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* OpenVPN data channel offload 3 + * 4 + * Copyright (C) 2020-2025 OpenVPN, Inc. 5 + * 6 + * Author: James Yonan <james@openvpn.net> 7 + * Antonio Quartulli <antonio@openvpn.net> 8 + */ 9 + 10 + #include <linux/atomic.h> 11 + 12 + #include "stats.h" 13 + 14 + void ovpn_peer_stats_init(struct ovpn_peer_stats *ps) 15 + { 16 + atomic64_set(&ps->rx.bytes, 0); 17 + atomic64_set(&ps->rx.packets, 0); 18 + 19 + atomic64_set(&ps->tx.bytes, 0); 20 + atomic64_set(&ps->tx.packets, 0); 21 + }
+47
drivers/net/ovpn/stats.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* OpenVPN data channel offload 3 + * 4 + * Copyright (C) 2020-2025 OpenVPN, Inc. 5 + * 6 + * Author: James Yonan <james@openvpn.net> 7 + * Antonio Quartulli <antonio@openvpn.net> 8 + * Lev Stipakov <lev@openvpn.net> 9 + */ 10 + 11 + #ifndef _NET_OVPN_OVPNSTATS_H_ 12 + #define _NET_OVPN_OVPNSTATS_H_ 13 + 14 + /* one stat */ 15 + struct ovpn_peer_stat { 16 + atomic64_t bytes; 17 + atomic64_t packets; 18 + }; 19 + 20 + /* rx and tx stats combined */ 21 + struct ovpn_peer_stats { 22 + struct ovpn_peer_stat rx; 23 + struct ovpn_peer_stat tx; 24 + }; 25 + 26 + void ovpn_peer_stats_init(struct ovpn_peer_stats *ps); 27 + 28 + static inline void ovpn_peer_stats_increment(struct ovpn_peer_stat *stat, 29 + const unsigned int n) 30 + { 31 + atomic64_add(n, &stat->bytes); 32 + atomic64_inc(&stat->packets); 33 + } 34 + 35 + static inline void ovpn_peer_stats_increment_rx(struct ovpn_peer_stats *stats, 36 + const unsigned int n) 37 + { 38 + ovpn_peer_stats_increment(&stats->rx, n); 39 + } 40 + 41 + static inline void ovpn_peer_stats_increment_tx(struct ovpn_peer_stats *stats, 42 + const unsigned int n) 43 + { 44 + ovpn_peer_stats_increment(&stats->tx, n); 45 + } 46 + 47 + #endif /* _NET_OVPN_OVPNSTATS_H_ */