From 8b630fa9ef6e2eecc8425e62ea31194c4d0e410e Mon Sep 17 00:00:00 2001 From: Kristof Provost Date: Sun, 27 Nov 2022 12:58:40 +0100 Subject: [PATCH] if_ovpn: implement OVPN_GET_PEER_STATS Allow userspace to retrieve per-peer traffic stats. Sponsored by: Rubicon Communications, LLC ("Netgate") Differential Revision: https://reviews.freebsd.org/D37604 --- sys/net/if_ovpn.c | 57 +++++++++++++++++++++++++++++++++++++++++++++++ sys/net/if_ovpn.h | 1 + 2 files changed, 58 insertions(+) diff --git a/sys/net/if_ovpn.c b/sys/net/if_ovpn.c index 6686315fbf01..2cfe55568348 100644 --- a/sys/net/if_ovpn.c +++ b/sys/net/if_ovpn.c @@ -1212,6 +1212,60 @@ ovpn_get_stats(struct ovpn_softc *sc, nvlist_t **onvl) return (ret); } +static int +ovpn_get_peer_stats(struct ovpn_softc *sc, nvlist_t **nvl) +{ + struct ovpn_kpeer *peer; + nvlist_t *nvpeer = NULL; + int ret; + + OVPN_RLOCK_TRACKER; + + *nvl = nvlist_create(0); + if (*nvl == NULL) + return (ENOMEM); + +#define OVPN_PEER_COUNTER_OUT(name, in, out) \ + do { \ + ret = ovpn_add_counters(nvpeer, name, \ + peer->counters[offsetof(struct ovpn_peer_counters, in) / \ + sizeof(uint64_t)], \ + peer->counters[offsetof(struct ovpn_peer_counters, out) / \ + sizeof(uint64_t)]); \ + if (ret != 0) \ + goto error; \ + } while(0) + + OVPN_RLOCK(sc); + RB_FOREACH(peer, ovpn_kpeers, &sc->peers) { + nvpeer = nvlist_create(0); + if (nvpeer == NULL) { + OVPN_RUNLOCK(sc); + nvlist_destroy(*nvl); + *nvl = NULL; + return (ENOMEM); + } + + nvlist_add_number(nvpeer, "peerid", peer->peerid); + + OVPN_PEER_COUNTER_OUT("packets", pkt_in, pkt_out); + OVPN_PEER_COUNTER_OUT("bytes", bytes_in, bytes_out); + + nvlist_append_nvlist_array(*nvl, "peers", nvpeer); + nvlist_destroy(nvpeer); + } +#undef OVPN_PEER_COUNTER_OUT + OVPN_RUNLOCK(sc); + + return (0); + +error: + nvlist_destroy(nvpeer); + nvlist_destroy(*nvl); + *nvl = NULL; + return (ret); +} + static int ovpn_poll_pkt(struct ovpn_softc *sc, nvlist_t **onvl) { @@ -1266,6 +1320,9 @@ ovpn_ioctl_get(struct ifnet *ifp, struct ifdrv *ifd) case OVPN_GET_STATS: error = ovpn_get_stats(sc, &nvl); break; + case OVPN_GET_PEER_STATS: + error = ovpn_get_peer_stats(sc, &nvl); + break; case OVPN_POLL_PKT: error = ovpn_poll_pkt(sc, &nvl); break; diff --git a/sys/net/if_ovpn.h b/sys/net/if_ovpn.h index 5ea2ae6dd2ec..1c0299940c3e 100644 --- a/sys/net/if_ovpn.h +++ b/sys/net/if_ovpn.h @@ -66,5 +66,6 @@ enum ovpn_key_cipher { #define OVPN_POLL_PKT _IO ('D', 10) #define OVPN_GET_PKT _IO ('D', 11) #define OVPN_SET_IFMODE _IO ('D', 12) +#define OVPN_GET_PEER_STATS _IO ('D', 13) #endif