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>
This commit is contained in:
Antonio Quartulli
2025-04-15 13:17:27 +02:00
committed by Paolo Abeni
parent 8534731dbf
commit 04ca14955f
6 changed files with 87 additions and 1 deletions

View File

@@ -17,4 +17,5 @@ ovpn-y += netlink-gen.o
ovpn-y += peer.o
ovpn-y += pktid.o
ovpn-y += socket.o
ovpn-y += stats.o
ovpn-y += udp.o

View File

@@ -12,6 +12,7 @@
#include <linux/skbuff.h>
#include <net/gro_cells.h>
#include <net/gso.h>
#include <net/ip.h>
#include "ovpnpriv.h"
#include "peer.h"
@@ -55,9 +56,11 @@ static void ovpn_netdev_write(struct ovpn_peer *peer, struct sk_buff *skb)
/* cause packet to be "received" by the interface */
pkt_len = skb->len;
ret = gro_cells_receive(&peer->ovpn->gro_cells, skb);
if (likely(ret == NET_RX_SUCCESS))
if (likely(ret == NET_RX_SUCCESS)) {
/* update RX stats with the size of decrypted packet */
ovpn_peer_stats_increment_rx(&peer->vpn_stats, pkt_len);
dev_dstats_rx_add(peer->ovpn->dev, pkt_len);
}
}
void ovpn_decrypt_post(void *data, int ret)
@@ -152,6 +155,8 @@ void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb)
struct ovpn_crypto_key_slot *ks;
u8 key_id;
ovpn_peer_stats_increment_rx(&peer->link_stats, skb->len);
/* get the key slot matching the key ID in the received packet */
key_id = ovpn_key_id_from_skb(skb);
ks = ovpn_crypto_key_id_to_slot(&peer->crypto, key_id);
@@ -175,6 +180,7 @@ void ovpn_encrypt_post(void *data, int ret)
struct sk_buff *skb = data;
struct ovpn_socket *sock;
struct ovpn_peer *peer;
unsigned int orig_len;
/* encryption is happening asynchronously. This function will be
* called later by the crypto callback with a proper return value
@@ -194,6 +200,7 @@ void ovpn_encrypt_post(void *data, int ret)
goto err;
skb_mark_not_on_list(skb);
orig_len = skb->len;
rcu_read_lock();
sock = rcu_dereference(peer->sock);
@@ -208,6 +215,8 @@ void ovpn_encrypt_post(void *data, int ret)
/* no transport configured yet */
goto err_unlock;
}
ovpn_peer_stats_increment_tx(&peer->link_stats, orig_len);
/* skb passed down the stack - don't free it */
skb = NULL;
err_unlock:
@@ -322,6 +331,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev)
goto drop;
}
ovpn_peer_stats_increment_tx(&peer->vpn_stats, skb->len);
ovpn_send(ovpn, skb_list.next, peer);
return NETDEV_TX_OK;

View File

@@ -61,6 +61,8 @@ struct ovpn_peer *ovpn_peer_new(struct ovpn_priv *ovpn, u32 id)
ovpn_crypto_state_init(&peer->crypto);
spin_lock_init(&peer->lock);
kref_init(&peer->refcount);
ovpn_peer_stats_init(&peer->vpn_stats);
ovpn_peer_stats_init(&peer->link_stats);
ret = dst_cache_init(&peer->dst_cache, GFP_KERNEL);
if (ret < 0) {

View File

@@ -14,6 +14,7 @@
#include "crypto.h"
#include "socket.h"
#include "stats.h"
/**
* struct ovpn_peer - the main remote peer object
@@ -27,6 +28,8 @@
* @crypto: the crypto configuration (ciphers, keys, etc..)
* @dst_cache: cache for dst_entry used to send to peer
* @bind: remote peer binding
* @vpn_stats: per-peer in-VPN TX/RX stats
* @link_stats: per-peer link/transport TX/RX stats
* @delete_reason: why peer was deleted (i.e. timeout, transport error, ..)
* @lock: protects binding to peer (bind)
* @refcount: reference counter
@@ -45,6 +48,8 @@ struct ovpn_peer {
struct ovpn_crypto_state crypto;
struct dst_cache dst_cache;
struct ovpn_bind __rcu *bind;
struct ovpn_peer_stats vpn_stats;
struct ovpn_peer_stats link_stats;
enum ovpn_del_peer_reason delete_reason;
spinlock_t lock; /* protects bind */
struct kref refcount;

21
drivers/net/ovpn/stats.c Normal file
View File

@@ -0,0 +1,21 @@
// SPDX-License-Identifier: GPL-2.0
/* OpenVPN data channel offload
*
* Copyright (C) 2020-2025 OpenVPN, Inc.
*
* Author: James Yonan <james@openvpn.net>
* Antonio Quartulli <antonio@openvpn.net>
*/
#include <linux/atomic.h>
#include "stats.h"
void ovpn_peer_stats_init(struct ovpn_peer_stats *ps)
{
atomic64_set(&ps->rx.bytes, 0);
atomic64_set(&ps->rx.packets, 0);
atomic64_set(&ps->tx.bytes, 0);
atomic64_set(&ps->tx.packets, 0);
}

47
drivers/net/ovpn/stats.h Normal file
View File

@@ -0,0 +1,47 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/* OpenVPN data channel offload
*
* Copyright (C) 2020-2025 OpenVPN, Inc.
*
* Author: James Yonan <james@openvpn.net>
* Antonio Quartulli <antonio@openvpn.net>
* Lev Stipakov <lev@openvpn.net>
*/
#ifndef _NET_OVPN_OVPNSTATS_H_
#define _NET_OVPN_OVPNSTATS_H_
/* one stat */
struct ovpn_peer_stat {
atomic64_t bytes;
atomic64_t packets;
};
/* rx and tx stats combined */
struct ovpn_peer_stats {
struct ovpn_peer_stat rx;
struct ovpn_peer_stat tx;
};
void ovpn_peer_stats_init(struct ovpn_peer_stats *ps);
static inline void ovpn_peer_stats_increment(struct ovpn_peer_stat *stat,
const unsigned int n)
{
atomic64_add(n, &stat->bytes);
atomic64_inc(&stat->packets);
}
static inline void ovpn_peer_stats_increment_rx(struct ovpn_peer_stats *stats,
const unsigned int n)
{
ovpn_peer_stats_increment(&stats->rx, n);
}
static inline void ovpn_peer_stats_increment_tx(struct ovpn_peer_stats *stats,
const unsigned int n)
{
ovpn_peer_stats_increment(&stats->tx, n);
}
#endif /* _NET_OVPN_OVPNSTATS_H_ */