From patchwork Fri Sep 11 09:33:36 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Baffo X-Patchwork-Id: 5329 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6446:b0:8a0:ea1f:253a with SMTP id n6csp133370mag; Fri, 11 Sep 2026 02:34:02 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBzxOkLIpTgnqDZy2lMTHyKIQ15gaUbgTCj4QQNa2dpXaG5tEJg+FjX6UYlopUBMgzTJBUsAG/dPZ+c=@openvpn.net X-Received: by 2002:a05:6820:2910:b0:6c0:5d5a:e0e5 with SMTP id 006d021491bc7-6c0bae0b28dmr1995790eaf.29.1789119242407; Fri, 11 Sep 2026 02:34:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1789119242; cv=none; d=google.com; s=arc-20260327; b=ZnKq+7RaYCXPctUig1y8Jqga3zfBshfQTuo4CRBSzlFUHGgvKTivhHE5PKIqmeYtt/ RTdPayhxiuxb9uYsdzM4svtF0ls+JOydInznfp/lkRqicv4Gl5DxLGjfqtZ9bm/piIkP 0fPniXR3DF8AWR2mKbsyiji1HSZOeE+kz73lb3FW63XnDUe6bkEVhzGhZ4dk+XsFCMCi XUeUpR/doEomdRh8kjHDb6tkTfpNZr+Xzj5enxdalLx5mp/ulnwYxbWiBHsl1CS2xwtj r65lkmlwrdq9GzcdTVFO9HiU6mQdAu7CtOtE1UeFUwCl+xB1lE+pgSGOJx8AUXLopyPG orWQ== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=errors-to:content-transfer-encoding:cc:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:message-id:date:to:from:dkim-signature:dkim-signature :dkim-signature:dkim-signature; bh=kJtfo5Bgz+qw7kCo16ttV746DBVnzmWTqIf192W45Nw=; fh=BsMg/B0Yb/hS/rzP5Npz4luh0IleZm8REk1XWiWRt2A=; b=NmMOiezQ0I/9VcXnIyxsf+8qZvJMObaUzDUmExXhPtHFV3xhEhmZY4CFjVyhhSTs8a Vj5mkTqg0ahuHVsUwablNjTjglvSWMA/xVhbibPGnYK7Mhac7iXVDUrDk81navQk2lAY USn3oSbve7uX8Pu2t6AqXllSfdASmuToYEPbfhzu5itx0sCJF2VlY/YmZL1cPzM25foj lPxzHoyEGnrtyRE34z1cH7vvQR7ReabNlvi64tkcUDNVFHFs69PitR6Je3Ys9ttccnav B/JZ+ruMF9eYL1Y5o9ROK+lLnogY7SgNAB7Nr1zbjTL5ZmBPQ/Yel8ww+rJPWF/UodGf 4emA==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=fgjFXp9K; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=le2XEFWE; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Jzrld4w5; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=u8xz7a3e; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 006d021491bc7-6c09b51bb40si2502106eaf.83.2026.09.11.02.34.02 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 11 Sep 2026 02:34:02 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=fgjFXp9K; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=le2XEFWE; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Jzrld4w5; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=u8xz7a3e; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type:Cc: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Subject:MIME-Version:Message-ID:Date:To:From:Sender:Reply-To:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Owner; bh=kJtfo5Bgz+qw7kCo16ttV746DBVnzmWTqIf192W45Nw=; b=fgjFXp9K548KDUmJymjuy/65r4 Sf6H1V5xulQi1OVziLy9WtaUw/LpTBz7GCDo8u1PAzgIb/KcVOFBfk3NUqLwlHn+k4kz/UgXrNNf1 4noaIH1L4IwcaKLHfHjVt16AuxzP1QaaCHPL22rz7zkSwjpFgBLh6fvPD+cU8z94vd3c=; Received: from [127.0.0.1] (helo=sfs-ml-4.v29.lw.sourceforge.com) by sfs-ml-4.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1x4xds-0007Eq-RS; Fri, 11 Sep 2026 09:33:56 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-4.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1x4xdp-0007Ej-7T for openvpn-devel@lists.sourceforge.net; Fri, 11 Sep 2026 09:33:54 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:Message-ID: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:In-Reply-To:References:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=krU+JQT2YQcKNCRQ2GKEJ/fyL+I2IRMgqKDpMNQygig=; b=le2XEFWEa8bdPtOEcf1xUB6UtJ jcOxyoVG78GvezI0aU8m/zxltoKtkHWBrP9Kv69dqvbWWFrtBI3BlJ1ayjUSlSUyDuB9tI0mSLhq3 l4Dm/wbBpn9mE0JJ4L82WFnGp3mx13lFQeEHC/sxWFDqiTpRgvsy5X9H6hvhczeNroVM=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:Message-ID:Date:Subject:Cc:To:From :Sender:Reply-To:Content-Type:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Id:List-Help:List-Unsubscribe:List-Subscribe:List-Post: List-Owner:List-Archive; bh=krU+JQT2YQcKNCRQ2GKEJ/fyL+I2IRMgqKDpMNQygig=; b=J zrld4w5kaQZ2Diq6EGuIdcfsdoLYOIGmYSzGtoO8fy+E/77GPrletMqx61oe8ycc+3uNsClsCR+dM Td7MI6/OZiQr+QOSBuRmCFJgwUCSDKFvBlihLZhhtVDcFPivNAWF5t10MNYRTArZZRRl+N0ooqEQA 1g4uasmI6N+NUV1Y=; Received: from mout-b-112.mailbox.org ([195.10.208.42]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1x4xdn-0007IF-7j for openvpn-devel@lists.sourceforge.net; Fri, 11 Sep 2026 09:33:53 +0000 Received: from smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:b231:465::102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-b-112.mailbox.org (Postfix) with ESMTPS id 4hh8Vv6bHRz5wsy; Fri, 11 Sep 2026 11:33:43 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1789119223; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding; bh=krU+JQT2YQcKNCRQ2GKEJ/fyL+I2IRMgqKDpMNQygig=; b=u8xz7a3eiKSfuJ5u8IJp1N+KclnyvT0SFfRIQR1tIVUrt1/OxsgLwdGEQg0JiKw1pNPAx4 8STLPvHKZhzzzRyfFKKqsL2N4e12EJIswBWof7HvhDrpdM9roU5Kf7MWhEd6HLX/n7RrQJ 8nLp/lDPb/VGldlwF9QvJ2Ovp5UHsjxBD3V2WnPOPtCzTupQvfDcF+Y4+AlYVbIQisyXaN ap2YFd36f03LC/HFZTYHBZfGtEMw/mSTAgro0BsE4/UaU6dgCrZLDBeUJYfaIjkRdZqHoo ffJk3/6IbIAwxiM8jkHKUekdaJ3cN5QZl7zU1CNWgBRT9u6Dd0/70C6aU+uw/g== Authentication-Results: outgoing_mbo_mout; dkim=none; spf=pass (outgoing_mbo_mout: domain of marco@mandelbit.com designates 2001:67c:2050:b231:465::102 as permitted sender) smtp.mailfrom=marco@mandelbit.com From: Marco Baffo To: openvpn-devel@lists.sourceforge.net Date: Fri, 11 Sep 2026 11:33:36 +0200 Message-ID: <20260911093338.1065898-1-marco@mandelbit.com> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4hh8Vv6bHRz5wsy X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-2.hosts.colo.sdot.me", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Drops are currently accounted only via the undifferentiated netdev rx/tx_dropped counters, hiding the actual drop reason. Add per-peer atomic64_t counters (struct ovpn_peer_estats) for the significant [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1x4xdn-0007IF-7j Subject: [Openvpn-devel] [RFC ovpn net-next v3 1/3] ovpn: extend statistics with per-peer drop and event counters X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: 1876027498749756953 X-GMAIL-MSGID: 1876027498749756953 Drops are currently accounted only via the undifferentiated netdev rx/tx_dropped counters, hiding the actual drop reason. Add per-peer atomic64_t counters (struct ovpn_peer_estats) for the significant drop reasons and events in the data path: * RX: decrypt errors, replay errors, unknown key-id, unsupported inner protocol, RPF check failures * TX: encrypt errors, IV exhaustion, missing primary key, missing transport, GSO segmentation errors * events: keepalives received/sent, endpoint floats Only ovpn-specific drop reasons are covered. Generic ENOMEM failures and teardown races are not accounted. Export the counters in a new OVPN_A_PEER_ESTATS nest in the OVPN_CMD_PEER_GET reply and teach ovpn-cli to print them. Signed-off-by: Marco Baffo --- Changes in v3: none. Changes in v2: rebased. Documentation/netlink/specs/ovpn.yaml | 62 +++++++++++++++++++++ drivers/net/ovpn/io.c | 25 +++++++-- drivers/net/ovpn/netlink-gen.c | 19 ++++++- drivers/net/ovpn/netlink-gen.h | 3 +- drivers/net/ovpn/netlink.c | 37 +++++++++++- drivers/net/ovpn/peer.c | 5 ++ drivers/net/ovpn/peer.h | 2 + drivers/net/ovpn/stats.h | 33 +++++++++++ include/uapi/linux/ovpn.h | 20 +++++++ tools/testing/selftests/net/ovpn/ovpn-cli.c | 60 ++++++++++++++++++++ 10 files changed, 259 insertions(+), 7 deletions(-) diff --git a/Documentation/netlink/specs/ovpn.yaml b/Documentation/netlink/specs/ovpn.yaml index ac50d1d7c00a6..dd1bb96c312dd 100644 --- a/Documentation/netlink/specs/ovpn.yaml +++ b/Documentation/netlink/specs/ovpn.yaml @@ -175,6 +175,68 @@ attribute-sets: will advertise the tx-id to be used on the link. checks: max: 0xFFFFFF + - + name: estats + type: nest + doc: Extended statistics, per-peer drop/event counters + nested-attributes: peer-estats + - + name: peer-estats + attributes: + - + name: rx-decrypt-errors + type: uint + doc: Number of packets dropped due to decryption failure + - + name: rx-replay-errors + type: uint + doc: Number of packets dropped by the replay protection check + - + name: rx-unknown-keyid + type: uint + doc: Number of packets dropped due to unknown key ID + - + name: rx-unsupported-proto + type: uint + doc: >- + Number of packets dropped due to unsupported or malformed inner + protocol + - + name: rx-rpf-errors + type: uint + doc: Number of packets dropped by the reverse path filtering check + - + name: tx-encrypt-errors + type: uint + doc: Number of packets dropped due to encryption failure + - + name: tx-iv-exhausted + type: uint + doc: Number of packets dropped due to packet ID (IV) exhaustion + - + name: tx-no-key + type: uint + doc: Number of packets dropped due to missing primary key + - + name: tx-no-transport + type: uint + doc: Number of packets dropped due to missing transport socket + - + name: tx-gso-errors + type: uint + doc: Number of packets dropped due to GSO segmentation failure + - + name: keepalive-rx + type: uint + doc: Number of keepalive packets received from this peer + - + name: keepalive-tx + type: uint + doc: Number of keepalive packets sent to this peer + - + name: float-count + type: uint + doc: Number of times the peer endpoint floated - name: peer-new-input subset-of: peer diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index 9526f8096da60..37547f6117e9c 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -128,8 +128,10 @@ void ovpn_decrypt_post(void *data, int ret) /* crypto is done, cleanup skb CB and its members */ kfree(ovpn_skb_cb(skb)->crypto_tmp); - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + atomic64_inc(&peer->estats.rx_decrypt_errors); goto drop; + } /* PID sits after the op */ pid = (__force __be32 *)(skb->data + OVPN_OPCODE_SIZE); @@ -138,6 +140,7 @@ void ovpn_decrypt_post(void *data, int ret) net_err_ratelimited("%s: PKT ID RX error for peer %u: %d\n", netdev_name(peer->ovpn->dev), peer->id, ret); + atomic64_inc(&peer->estats.rx_replay_errors); goto drop; } @@ -165,6 +168,7 @@ void ovpn_decrypt_post(void *data, int ret) net_info_ratelimited("%s: NULL packet received from peer %u\n", netdev_name(peer->ovpn->dev), peer->id); + atomic64_inc(&peer->estats.rx_unsupported_proto); goto drop; } @@ -172,6 +176,7 @@ void ovpn_decrypt_post(void *data, int ret) net_dbg_ratelimited("%s: ping received from peer %u\n", netdev_name(peer->ovpn->dev), peer->id); + atomic64_inc(&peer->estats.keepalive_rx); /* we drop the packet, but this is not a failure */ consume_skb(skb); goto drop_nocount; @@ -179,6 +184,7 @@ void ovpn_decrypt_post(void *data, int ret) net_info_ratelimited("%s: unsupported protocol received from peer %u\n", netdev_name(peer->ovpn->dev), peer->id); + atomic64_inc(&peer->estats.rx_unsupported_proto); goto drop; } skb->protocol = proto; @@ -193,6 +199,7 @@ void ovpn_decrypt_post(void *data, int ret) net_dbg_ratelimited("%s: RPF dropped packet from peer %u, src: %pI4\n", netdev_name(peer->ovpn->dev), peer->id, &ip_hdr(skb)->saddr); + atomic64_inc(&peer->estats.rx_rpf_errors); goto drop; } @@ -225,6 +232,7 @@ void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb) net_info_ratelimited("%s: no available key for peer %u, key-id: %u\n", netdev_name(peer->ovpn->dev), peer->id, key_id); + atomic64_inc(&peer->estats.rx_unknown_keyid); ovpn_dev_dstats_rx_dropped(peer->ovpn->dev); kfree_skb(skb); ovpn_peer_put(peer); @@ -266,19 +274,24 @@ void ovpn_encrypt_post(void *data, int ret) /* let userspace know so that a new key must be negotiated */ ovpn_nl_key_swap_notify(peer, ks->key_id); + atomic64_inc(&peer->estats.tx_iv_exhausted); goto err; } - if (unlikely(ret < 0)) + if (unlikely(ret < 0)) { + atomic64_inc(&peer->estats.tx_encrypt_errors); goto err; + } skb_mark_not_on_list(skb); orig_len = skb->len; rcu_read_lock(); sock = rcu_dereference(peer->sock); - if (unlikely(!sock)) + if (unlikely(!sock)) { + atomic64_inc(&peer->estats.tx_no_transport); goto err_unlock; + } switch (sock->sk->sk_protocol) { case IPPROTO_UDP: @@ -289,6 +302,7 @@ void ovpn_encrypt_post(void *data, int ret) break; default: /* no transport configured yet */ + atomic64_inc(&peer->estats.tx_no_transport); goto err_unlock; } @@ -315,8 +329,10 @@ static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb) /* get primary key to be used for encrypting data */ ks = ovpn_crypto_key_slot_primary(&peer->crypto); - if (unlikely(!ks)) + if (unlikely(!ks)) { + atomic64_inc(&peer->estats.tx_no_key); return false; + } /* take a reference to the peer because the crypto code may run async. * ovpn_encrypt_post() will release it upon completion @@ -397,6 +413,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) ret = PTR_ERR(segments); net_err_ratelimited("%s: cannot segment payload packet: %d\n", netdev_name(dev), ret); + atomic64_inc(&peer->estats.tx_gso_errors); goto drop; } diff --git a/drivers/net/ovpn/netlink-gen.c b/drivers/net/ovpn/netlink-gen.c index 92d2fdc17c2e8..d427db6c563fe 100644 --- a/drivers/net/ovpn/netlink-gen.c +++ b/drivers/net/ovpn/netlink-gen.c @@ -63,7 +63,7 @@ const struct nla_policy ovpn_keydir_nl_policy[OVPN_A_KEYDIR_NONCE_TAIL + 1] = { [OVPN_A_KEYDIR_NONCE_TAIL] = NLA_POLICY_EXACT_LEN(OVPN_NONCE_TAIL_SIZE), }; -const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_TX_ID + 1] = { +const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_ESTATS + 1] = { [OVPN_A_PEER_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_id_range), [OVPN_A_PEER_REMOTE_IPV4] = { .type = NLA_BE32, }, [OVPN_A_PEER_REMOTE_IPV6] = NLA_POLICY_EXACT_LEN(16), @@ -88,12 +88,29 @@ const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_TX_ID + 1] = { [OVPN_A_PEER_LINK_RX_PACKETS] = { .type = NLA_UINT, }, [OVPN_A_PEER_LINK_TX_PACKETS] = { .type = NLA_UINT, }, [OVPN_A_PEER_TX_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_tx_id_range), + [OVPN_A_PEER_ESTATS] = NLA_POLICY_NESTED(ovpn_peer_estats_nl_policy), }; const struct nla_policy ovpn_peer_del_input_nl_policy[OVPN_A_PEER_ID + 1] = { [OVPN_A_PEER_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_id_range), }; +const struct nla_policy ovpn_peer_estats_nl_policy[OVPN_A_PEER_ESTATS_FLOAT_COUNT + 1] = { + [OVPN_A_PEER_ESTATS_RX_DECRYPT_ERRORS] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_RX_REPLAY_ERRORS] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_RX_UNKNOWN_KEYID] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_RX_UNSUPPORTED_PROTO] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_RX_RPF_ERRORS] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_TX_ENCRYPT_ERRORS] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_TX_IV_EXHAUSTED] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_TX_NO_KEY] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_TX_NO_TRANSPORT] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_TX_GSO_ERRORS] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_KEEPALIVE_RX] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_KEEPALIVE_TX] = { .type = NLA_UINT, }, + [OVPN_A_PEER_ESTATS_FLOAT_COUNT] = { .type = NLA_UINT, }, +}; + const struct nla_policy ovpn_peer_new_input_nl_policy[OVPN_A_PEER_TX_ID + 1] = { [OVPN_A_PEER_ID] = NLA_POLICY_FULL_RANGE(NLA_U32, &ovpn_a_peer_id_range), [OVPN_A_PEER_REMOTE_IPV4] = { .type = NLA_BE32, }, diff --git a/drivers/net/ovpn/netlink-gen.h b/drivers/net/ovpn/netlink-gen.h index 67cd85f86173f..197e4a992d692 100644 --- a/drivers/net/ovpn/netlink-gen.h +++ b/drivers/net/ovpn/netlink-gen.h @@ -18,8 +18,9 @@ extern const struct nla_policy ovpn_keyconf_del_input_nl_policy[OVPN_A_KEYCONF_S extern const struct nla_policy ovpn_keyconf_get_nl_policy[OVPN_A_KEYCONF_CIPHER_ALG + 1]; extern const struct nla_policy ovpn_keyconf_swap_input_nl_policy[OVPN_A_KEYCONF_PEER_ID + 1]; extern const struct nla_policy ovpn_keydir_nl_policy[OVPN_A_KEYDIR_NONCE_TAIL + 1]; -extern const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_TX_ID + 1]; +extern const struct nla_policy ovpn_peer_nl_policy[OVPN_A_PEER_ESTATS + 1]; extern const struct nla_policy ovpn_peer_del_input_nl_policy[OVPN_A_PEER_ID + 1]; +extern const struct nla_policy ovpn_peer_estats_nl_policy[OVPN_A_PEER_ESTATS_FLOAT_COUNT + 1]; extern const struct nla_policy ovpn_peer_new_input_nl_policy[OVPN_A_PEER_TX_ID + 1]; extern const struct nla_policy ovpn_peer_set_input_nl_policy[OVPN_A_PEER_TX_ID + 1]; diff --git a/drivers/net/ovpn/netlink.c b/drivers/net/ovpn/netlink.c index 4dad852941982..9e03b4cefceec 100644 --- a/drivers/net/ovpn/netlink.c +++ b/drivers/net/ovpn/netlink.c @@ -551,9 +551,9 @@ static int ovpn_nl_send_peer(struct sk_buff *skb, const struct genl_info *info, int flags) { const struct ovpn_bind *bind; + struct nlattr *attr, *estats; struct ovpn_socket *sock; int ret = -EMSGSIZE; - struct nlattr *attr; __be16 local_port; void *hdr; int id; @@ -654,6 +654,41 @@ static int ovpn_nl_send_peer(struct sk_buff *skb, const struct genl_info *info, atomic64_read(&peer->link_stats.tx.packets))) goto err; + estats = nla_nest_start(skb, OVPN_A_PEER_ESTATS); + if (!estats) + goto err; + + if (/* drop/event counters */ + nla_put_uint(skb, OVPN_A_PEER_ESTATS_RX_DECRYPT_ERRORS, + atomic64_read(&peer->estats.rx_decrypt_errors)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_RX_REPLAY_ERRORS, + atomic64_read(&peer->estats.rx_replay_errors)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_RX_UNKNOWN_KEYID, + atomic64_read(&peer->estats.rx_unknown_keyid)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_RX_UNSUPPORTED_PROTO, + atomic64_read(&peer->estats.rx_unsupported_proto)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_RX_RPF_ERRORS, + atomic64_read(&peer->estats.rx_rpf_errors)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_TX_ENCRYPT_ERRORS, + atomic64_read(&peer->estats.tx_encrypt_errors)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_TX_IV_EXHAUSTED, + atomic64_read(&peer->estats.tx_iv_exhausted)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_TX_NO_KEY, + atomic64_read(&peer->estats.tx_no_key)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_TX_NO_TRANSPORT, + atomic64_read(&peer->estats.tx_no_transport)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_TX_GSO_ERRORS, + atomic64_read(&peer->estats.tx_gso_errors)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_KEEPALIVE_RX, + atomic64_read(&peer->estats.keepalive_rx)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_KEEPALIVE_TX, + atomic64_read(&peer->estats.keepalive_tx)) || + nla_put_uint(skb, OVPN_A_PEER_ESTATS_FLOAT_COUNT, + atomic64_read(&peer->estats.floats))) + goto err; + + nla_nest_end(skb, estats); + nla_nest_end(skb, attr); genlmsg_end(skb, hdr); diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index c95656ca7c357..08cdd179de320 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -77,6 +77,10 @@ static void ovpn_peer_keepalive_send(struct work_struct *work) struct ovpn_peer *peer = container_of(work, struct ovpn_peer, keepalive_work); + /* count attempted keepalives: if the TX path fails afterwards, + * keepalive_tx will include a transmission that was not sent + */ + atomic64_inc(&peer->estats.keepalive_tx); local_bh_disable(); ovpn_xmit_special(peer, ovpn_keepalive_message, sizeof(ovpn_keepalive_message)); @@ -309,6 +313,7 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) spin_unlock_bh(&peer->lock); + atomic64_inc(&peer->estats.floats); ovpn_nl_peer_float_notify(peer, &ss); /* rehashing is required only in MP mode as P2P has one peer diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index dfa5c0037e02b..5667bad91c31f 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -60,6 +60,7 @@ * @rcu: used to free peer in an RCU safe way * @release_entry: entry for the socket release list * @keepalive_work: used to schedule keepalive sending + * @estats: per-peer drop/event counters */ struct ovpn_peer { struct ovpn_priv *ovpn; @@ -114,6 +115,7 @@ struct ovpn_peer { struct rcu_head rcu; struct llist_node release_entry; struct work_struct keepalive_work; + struct ovpn_peer_estats estats; }; /** diff --git a/drivers/net/ovpn/stats.h b/drivers/net/ovpn/stats.h index 3a45b97c00568..8b900e0c11210 100644 --- a/drivers/net/ovpn/stats.h +++ b/drivers/net/ovpn/stats.h @@ -25,6 +25,39 @@ struct ovpn_peer_stats { struct ovpn_peer_stat tx; }; +/** + * struct ovpn_peer_estats - per-peer drop/event counters + * @rx_decrypt_errors: packets dropped due to decryption/auth failure + * @rx_replay_errors: packets dropped by the replay protection check + * @rx_unknown_keyid: packets dropped due to unknown key ID + * @rx_unsupported_proto: packets dropped due to unsupported or malformed + * inner protocol + * @rx_rpf_errors: packets dropped by the reverse path filtering check + * @tx_encrypt_errors: packets dropped due to encryption failure + * @tx_iv_exhausted: packets dropped due to packet ID (IV) exhaustion + * @tx_no_key: packets dropped due to missing primary key + * @tx_no_transport: packets dropped due to missing transport socket + * @tx_gso_errors: packets dropped due to GSO segmentation failure + * @keepalive_rx: keepalive packets received from this peer + * @keepalive_tx: keepalive packets sent to this peer + * @floats: number of times the peer endpoint floated + */ +struct ovpn_peer_estats { + atomic64_t rx_decrypt_errors; + atomic64_t rx_replay_errors; + atomic64_t rx_unknown_keyid; + atomic64_t rx_unsupported_proto; + atomic64_t rx_rpf_errors; + atomic64_t tx_encrypt_errors; + atomic64_t tx_iv_exhausted; + atomic64_t tx_no_key; + atomic64_t tx_no_transport; + atomic64_t tx_gso_errors; + atomic64_t keepalive_rx; + atomic64_t keepalive_tx; + atomic64_t floats; +}; + void ovpn_peer_stats_init(struct ovpn_peer_stats *ps); static inline void ovpn_peer_stats_increment(struct ovpn_peer_stat *stat, diff --git a/include/uapi/linux/ovpn.h b/include/uapi/linux/ovpn.h index 06690090a1a95..e5ed635c03732 100644 --- a/include/uapi/linux/ovpn.h +++ b/include/uapi/linux/ovpn.h @@ -56,11 +56,31 @@ enum { OVPN_A_PEER_LINK_RX_PACKETS, OVPN_A_PEER_LINK_TX_PACKETS, OVPN_A_PEER_TX_ID, + OVPN_A_PEER_ESTATS, __OVPN_A_PEER_MAX, OVPN_A_PEER_MAX = (__OVPN_A_PEER_MAX - 1) }; +enum { + OVPN_A_PEER_ESTATS_RX_DECRYPT_ERRORS = 1, + OVPN_A_PEER_ESTATS_RX_REPLAY_ERRORS, + OVPN_A_PEER_ESTATS_RX_UNKNOWN_KEYID, + OVPN_A_PEER_ESTATS_RX_UNSUPPORTED_PROTO, + OVPN_A_PEER_ESTATS_RX_RPF_ERRORS, + OVPN_A_PEER_ESTATS_TX_ENCRYPT_ERRORS, + OVPN_A_PEER_ESTATS_TX_IV_EXHAUSTED, + OVPN_A_PEER_ESTATS_TX_NO_KEY, + OVPN_A_PEER_ESTATS_TX_NO_TRANSPORT, + OVPN_A_PEER_ESTATS_TX_GSO_ERRORS, + OVPN_A_PEER_ESTATS_KEEPALIVE_RX, + OVPN_A_PEER_ESTATS_KEEPALIVE_TX, + OVPN_A_PEER_ESTATS_FLOAT_COUNT, + + __OVPN_A_PEER_ESTATS_MAX, + OVPN_A_PEER_ESTATS_MAX = (__OVPN_A_PEER_ESTATS_MAX - 1) +}; + enum { OVPN_A_KEYCONF_PEER_ID = 1, OVPN_A_KEYCONF_SLOT, diff --git a/tools/testing/selftests/net/ovpn/ovpn-cli.c b/tools/testing/selftests/net/ovpn/ovpn-cli.c index f4effa7580c0f..ecac71db769ae 100644 --- a/tools/testing/selftests/net/ovpn/ovpn-cli.c +++ b/tools/testing/selftests/net/ovpn/ovpn-cli.c @@ -893,6 +893,66 @@ static int ovpn_handle_peer(struct nl_msg *msg, void (*arg)__always_unused) fprintf(stderr, "\tLINK TX packets: %" PRIu64 "\n", ovpn_nla_get_uint(pattrs[OVPN_A_PEER_LINK_TX_PACKETS])); + if (pattrs[OVPN_A_PEER_ESTATS]) { + struct nlattr *eattrs[OVPN_A_PEER_ESTATS_MAX + 1]; + + nla_parse(eattrs, OVPN_A_PEER_ESTATS_MAX, + nla_data(pattrs[OVPN_A_PEER_ESTATS]), + nla_len(pattrs[OVPN_A_PEER_ESTATS]), NULL); + + if (eattrs[OVPN_A_PEER_ESTATS_RX_DECRYPT_ERRORS]) + fprintf(stderr, "\tRX decrypt errors: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_RX_DECRYPT_ERRORS])); + + if (eattrs[OVPN_A_PEER_ESTATS_RX_REPLAY_ERRORS]) + fprintf(stderr, "\tRX replay errors: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_RX_REPLAY_ERRORS])); + + if (eattrs[OVPN_A_PEER_ESTATS_RX_UNKNOWN_KEYID]) + fprintf(stderr, "\tRX unknown key-id: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_RX_UNKNOWN_KEYID])); + + if (eattrs[OVPN_A_PEER_ESTATS_RX_UNSUPPORTED_PROTO]) + fprintf(stderr, "\tRX unsupported/malformed proto: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_RX_UNSUPPORTED_PROTO])); + + if (eattrs[OVPN_A_PEER_ESTATS_RX_RPF_ERRORS]) + fprintf(stderr, "\tRX RPF errors: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_RX_RPF_ERRORS])); + + if (eattrs[OVPN_A_PEER_ESTATS_TX_ENCRYPT_ERRORS]) + fprintf(stderr, "\tTX encrypt errors: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_TX_ENCRYPT_ERRORS])); + + if (eattrs[OVPN_A_PEER_ESTATS_TX_IV_EXHAUSTED]) + fprintf(stderr, "\tTX IV exhausted: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_TX_IV_EXHAUSTED])); + + if (eattrs[OVPN_A_PEER_ESTATS_TX_NO_KEY]) + fprintf(stderr, "\tTX no key: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_TX_NO_KEY])); + + if (eattrs[OVPN_A_PEER_ESTATS_TX_NO_TRANSPORT]) + fprintf(stderr, "\tTX no transport: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_TX_NO_TRANSPORT])); + + if (eattrs[OVPN_A_PEER_ESTATS_TX_GSO_ERRORS]) + fprintf(stderr, "\tTX GSO errors: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_TX_GSO_ERRORS])); + + if (eattrs[OVPN_A_PEER_ESTATS_KEEPALIVE_RX]) + fprintf(stderr, "\tKeepalive RX: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_KEEPALIVE_RX])); + + if (eattrs[OVPN_A_PEER_ESTATS_KEEPALIVE_TX]) + fprintf(stderr, "\tKeepalive TX: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_KEEPALIVE_TX])); + + if (eattrs[OVPN_A_PEER_ESTATS_FLOAT_COUNT]) + fprintf(stderr, "\tFloat count: %" PRIu64 "\n", + ovpn_nla_get_uint(eattrs[OVPN_A_PEER_ESTATS_FLOAT_COUNT])); + } + return NL_SKIP; } From patchwork Fri Sep 11 09:33:37 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Baffo X-Patchwork-Id: 5328 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6446:b0:8a0:ea1f:253a with SMTP id n6csp133368mag; Fri, 11 Sep 2026 02:34:02 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBzUIzc5vHIO33ArbOzt5EONtdmw4Zm1sPuEZc6Pwf+i62ujOxD3YW18M7FY4PN0ExxLIa/rHSMlJMk=@openvpn.net X-Received: by 2002:a05:6820:c0d9:20b0:6b1:a667:f0d4 with SMTP id 006d021491bc7-6c0ba537e15mr1642083eaf.20.1789119242378; Fri, 11 Sep 2026 02:34:02 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1789119242; cv=none; d=google.com; s=arc-20260327; b=jeEIL8bqVMI3COWN8JR7h+eI7GB5Aw4HiFqOXFkPtuQUG2+oz7chD2156pLQtCmrki OYhTgLlV+hdsqzruDxnbpT08h6/dRC1p6MP1O/YQ4+M7H759aQtODCWs6+5zRAtRX+sX W5zCB1A7n+e1Wt7xHadGp/P6JJJyQ7CEqJrRkrTSEdezWghyL5+Rtbszhw/FCSprICTX Yndjm0YG4FlVx218uh9CgMzJh8d54t/CvBUBl5jlutEAWGdLpHCJbADZxE+U9AlIht1i CzOCXAHfFIuEFdu76ipaQDny20wxgirfHnugqj0VUV9TkHtw6gVl20km5mFhVPoWbiz6 Xu7A== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=errors-to:content-transfer-encoding:cc:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature:dkim-signature:dkim-signature; bh=lzyYwlNaesCeU3Qc+IbQIloq6RyRmwZcLDZNQZVUxbA=; fh=BsMg/B0Yb/hS/rzP5Npz4luh0IleZm8REk1XWiWRt2A=; b=lmHnm5+q0K5uCsZmd0+46DpCKvu5naL7xRmGAK/NiT+MLzk6RNl2TOUMDy0//G2ynE HBwIJL7P+etoYBBPyvX6aGMZ5ElCvxgwG4bqZD9vTbklt4x4p1Hgd0uTKJq285MOKGwr zbdyLvK7C+FDNP2vv725BU3gIxTQ8PhQvdgwwkgRm0GJ384oakrYuUSB9U/ZvLPgz65+ RfVHebK3Pdo0y+okXWR5Gle/Pn494J+osUAh/SkCEuiZg3aUCMdiXlYZehj5oUi/mqKM Rv0DNZHBhjo5iu7bE5hXENKA3YSKlUxvPCRzKYfug0ACAAhyxC7FQtf6LzkEN6pTB+Yl LSpw==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=W6kMVvH9; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=WKbDvZvs; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Ae4ZGRlp; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=dH9HusZ7; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 006d021491bc7-6c09582a2b5si2709522eaf.10.2026.09.11.02.34.01 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 11 Sep 2026 02:34:02 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=W6kMVvH9; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=WKbDvZvs; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=Ae4ZGRlp; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=dH9HusZ7; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type:Cc: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Subject:MIME-Version:References:In-Reply-To:Message-ID:Date:To:From:Sender: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=lzyYwlNaesCeU3Qc+IbQIloq6RyRmwZcLDZNQZVUxbA=; b=W6kMVvH9JJQrchNRBw7JieF0g8 xtK5AOhGb+kjGpWuzF995LujVQ0HQFP2n5+l65bFZPpZ5YAG3rgpoTj9b1QH7LmZ36gWyuphPdGTf pjPPEBssKM1Ym9K7dLJuynljYj55gJFXScRoSLa3+zISUuM66+e0+9RzZD47whWGSMRo=; Received: from [127.0.0.1] (helo=sfs-ml-1.v29.lw.sourceforge.com) by sfs-ml-1.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1x4xdw-0005qz-Mq; Fri, 11 Sep 2026 09:33:58 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-1.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1x4xdv-0005qs-BP for openvpn-devel@lists.sourceforge.net; Fri, 11 Sep 2026 09:33:56 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=i4j4liymu05fyTdbD/GFBNC2NgT3OXgUGZ6zXQ1oCZU=; b=WKbDvZvsFgEqtnKkM5UdlhZrOu 0Xr7QSn5NSpSHACJlXVKZta+WoIQIX0P1GbqTxsFa90bu4XFYi5g3Heg5AJOZ10dEqii2vcvgFV4D t5tC/+YwqE0WOd8cKccv+/Ti29fAxbOme2LvWZWz6+82pd/u/+biUEFH0197qbBpRooU=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=i4j4liymu05fyTdbD/GFBNC2NgT3OXgUGZ6zXQ1oCZU=; b=Ae4ZGRlpxbI5KDgSEIbfntX1Yi vWWdpsIikiB/UDJnp2c1U5ds5XN0tO9nv7AQ/6gCoNAxHw+pVGif4OwgjZRa4qL8JA5ALK0eIZ8tR 7YhNGfK/FdYBUmR8U8tP44EcboeMo1+PhInhgPpLZbTpyyZxFN1NMeQCUuNAivEs56fM=; Received: from mout-b-201.mailbox.org ([195.10.208.61]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1x4xdq-0007IK-1S for openvpn-devel@lists.sourceforge.net; Fri, 11 Sep 2026 09:33:56 +0000 Received: from smtp102.mailbox.org (smtp102.mailbox.org [IPv6:2001:67c:2050:b231:465::102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-b-201.mailbox.org (Postfix) with ESMTPS id 4hh8Vy0M6zzLm6m; Fri, 11 Sep 2026 11:33:46 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1789119226; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=i4j4liymu05fyTdbD/GFBNC2NgT3OXgUGZ6zXQ1oCZU=; b=dH9HusZ790kre2EIQ6MDDMcmSasSLD8fqoSkLL1wEWDO83lo7dnOUTX9AzMp1XHJb2Capm mW1PJ7dorqg3HZojbrmdL6k86fT+wxR/uCKHk4KaTEUBphKHRJ54Dld/Mgplnm+w1CTWtQ wHPWoXPXfjU3sNQIIKV6Zw6wLjt2SMOz+fqzakoXDMBpXW79HW+Ys1IOX1mbbGYmppi1j/ Ggmlowimh2wWmBd4V6iWJOzK6+UvaA8q/9kG2D4DWf3W5iWiO6nbJtuueNMDdxgCcjYnMF pHnJ6XIXtrt9BItpeJxZf6wcMVkW26BwnDPwqw7zS2z4C0WejzwZy9y4CP1VXA== Authentication-Results: outgoing_mbo_mout; dkim=none; spf=pass (outgoing_mbo_mout: domain of marco@mandelbit.com designates 2001:67c:2050:b231:465::102 as permitted sender) smtp.mailfrom=marco@mandelbit.com From: Marco Baffo To: openvpn-devel@lists.sourceforge.net Date: Fri, 11 Sep 2026 11:33:37 +0200 Message-ID: <20260911093338.1065898-2-marco@mandelbit.com> In-Reply-To: <20260911093338.1065898-1-marco@mandelbit.com> References: <20260911093338.1065898-1-marco@mandelbit.com> MIME-Version: 1.0 X-Rspamd-Queue-Id: 4hh8Vy0M6zzLm6m X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-2.hosts.colo.sdot.me", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Detailed per-peer counters are currently available only through netlink. Maintain device-wide copies of the same counters, incremented together with the per-peer ones, and expose them through ethtool. Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1x4xdq-0007IK-1S Subject: [Openvpn-devel] [RFC ovpn net-next v3 2/3] ovpn: export detailed statistics via ethtool X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: 1876027498561646125 X-GMAIL-MSGID: 1876027498561646125 Detailed per-peer counters are currently available only through netlink. Maintain device-wide copies of the same counters, incremented together with the per-peer ones, and expose them through ethtool. Store the device-wide counters in per-CPU storage and aggregate them when queried, avoiding an additional device-wide atomic update in packet processing paths. The totals remain monotonic across peer deletion and interface down/up. Also count packets dropped because no peer matched the source (RX) or destination (TX) address, and locally generated packets with an invalid protocol. These cannot be attributed to an individual peer and are therefore exported via ethtool only. Signed-off-by: Marco Baffo --- Changes in v3: - Define shared macro lists for peer drop, peer event and device-only drop counters, allowing the drop lists to be reused by patch 3. - Generate counter indices and ethtool names from these lists, replacing the name/index descriptor table with an array indexed by counter ID. - Add a compile-time check that the peer counter count matches struct ovpn_peer_estats. Changes in v2: rebased. drivers/net/ovpn/io.c | 33 ++++++++++------- drivers/net/ovpn/main.c | 73 +++++++++++++++++++++++++++++++++++-- drivers/net/ovpn/ovpnpriv.h | 2 + drivers/net/ovpn/peer.c | 4 +- drivers/net/ovpn/peer.h | 16 ++++++++ drivers/net/ovpn/stats.h | 65 +++++++++++++++++++++++++++++++++ drivers/net/ovpn/udp.c | 5 ++- 7 files changed, 178 insertions(+), 20 deletions(-) diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index 37547f6117e9c..ca3e8a9680694 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -129,7 +129,7 @@ void ovpn_decrypt_post(void *data, int ret) kfree(ovpn_skb_cb(skb)->crypto_tmp); if (unlikely(ret < 0)) { - atomic64_inc(&peer->estats.rx_decrypt_errors); + ovpn_estats_inc(peer, rx_decrypt_errors); goto drop; } @@ -140,7 +140,7 @@ void ovpn_decrypt_post(void *data, int ret) net_err_ratelimited("%s: PKT ID RX error for peer %u: %d\n", netdev_name(peer->ovpn->dev), peer->id, ret); - atomic64_inc(&peer->estats.rx_replay_errors); + ovpn_estats_inc(peer, rx_replay_errors); goto drop; } @@ -168,7 +168,7 @@ void ovpn_decrypt_post(void *data, int ret) net_info_ratelimited("%s: NULL packet received from peer %u\n", netdev_name(peer->ovpn->dev), peer->id); - atomic64_inc(&peer->estats.rx_unsupported_proto); + ovpn_estats_inc(peer, rx_unsupported_proto); goto drop; } @@ -176,7 +176,7 @@ void ovpn_decrypt_post(void *data, int ret) net_dbg_ratelimited("%s: ping received from peer %u\n", netdev_name(peer->ovpn->dev), peer->id); - atomic64_inc(&peer->estats.keepalive_rx); + ovpn_estats_inc(peer, keepalive_rx); /* we drop the packet, but this is not a failure */ consume_skb(skb); goto drop_nocount; @@ -184,7 +184,7 @@ void ovpn_decrypt_post(void *data, int ret) net_info_ratelimited("%s: unsupported protocol received from peer %u\n", netdev_name(peer->ovpn->dev), peer->id); - atomic64_inc(&peer->estats.rx_unsupported_proto); + ovpn_estats_inc(peer, rx_unsupported_proto); goto drop; } skb->protocol = proto; @@ -199,7 +199,7 @@ void ovpn_decrypt_post(void *data, int ret) net_dbg_ratelimited("%s: RPF dropped packet from peer %u, src: %pI4\n", netdev_name(peer->ovpn->dev), peer->id, &ip_hdr(skb)->saddr); - atomic64_inc(&peer->estats.rx_rpf_errors); + ovpn_estats_inc(peer, rx_rpf_errors); goto drop; } @@ -232,7 +232,7 @@ void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb) net_info_ratelimited("%s: no available key for peer %u, key-id: %u\n", netdev_name(peer->ovpn->dev), peer->id, key_id); - atomic64_inc(&peer->estats.rx_unknown_keyid); + ovpn_estats_inc(peer, rx_unknown_keyid); ovpn_dev_dstats_rx_dropped(peer->ovpn->dev); kfree_skb(skb); ovpn_peer_put(peer); @@ -274,12 +274,12 @@ void ovpn_encrypt_post(void *data, int ret) /* let userspace know so that a new key must be negotiated */ ovpn_nl_key_swap_notify(peer, ks->key_id); - atomic64_inc(&peer->estats.tx_iv_exhausted); + ovpn_estats_inc(peer, tx_iv_exhausted); goto err; } if (unlikely(ret < 0)) { - atomic64_inc(&peer->estats.tx_encrypt_errors); + ovpn_estats_inc(peer, tx_encrypt_errors); goto err; } @@ -289,7 +289,7 @@ void ovpn_encrypt_post(void *data, int ret) rcu_read_lock(); sock = rcu_dereference(peer->sock); if (unlikely(!sock)) { - atomic64_inc(&peer->estats.tx_no_transport); + ovpn_estats_inc(peer, tx_no_transport); goto err_unlock; } @@ -302,7 +302,7 @@ void ovpn_encrypt_post(void *data, int ret) break; default: /* no transport configured yet */ - atomic64_inc(&peer->estats.tx_no_transport); + ovpn_estats_inc(peer, tx_no_transport); goto err_unlock; } @@ -330,7 +330,7 @@ static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb) /* get primary key to be used for encrypting data */ ks = ovpn_crypto_key_slot_primary(&peer->crypto); if (unlikely(!ks)) { - atomic64_inc(&peer->estats.tx_no_key); + ovpn_estats_inc(peer, tx_no_key); return false; } @@ -384,8 +384,11 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) /* verify IP header size in network packet */ proto = ovpn_ip_check_protocol(skb); - if (unlikely(!proto || skb->protocol != proto)) + if (unlikely(!proto || skb->protocol != proto)) { + ovpn_dev_estats_inc(ovpn->estats, + OVPN_DEV_ESTAT_TX_BAD_PROTO); goto drop_no_peer; + } /* retrieve peer serving the destination IP of this packet */ peer = ovpn_peer_get_by_dst(ovpn, skb); @@ -402,6 +405,8 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) &ipv6_hdr(skb)->daddr); break; } + ovpn_dev_estats_inc(ovpn->estats, + OVPN_DEV_ESTAT_TX_NO_PEER); goto drop_no_peer; } /* dst was needed for peer selection - it can now be dropped */ @@ -413,7 +418,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) ret = PTR_ERR(segments); net_err_ratelimited("%s: cannot segment payload packet: %d\n", netdev_name(dev), ret); - atomic64_inc(&peer->estats.tx_gso_errors); + ovpn_estats_inc(peer, tx_gso_errors); goto drop; } diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 0708249e9607c..6a34557e89561 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -34,6 +34,7 @@ static void ovpn_priv_free(struct net_device *net) { struct ovpn_priv *ovpn = netdev_priv(net); + free_percpu(ovpn->estats); kfree(ovpn->peers); } @@ -64,18 +65,29 @@ static int ovpn_mp_alloc(struct ovpn_priv *ovpn) static int ovpn_net_init(struct net_device *dev) { struct ovpn_priv *ovpn = netdev_priv(dev); - int err = gro_cells_init(&ovpn->gro_cells, dev); + int err; + + ovpn->estats = netdev_alloc_pcpu_stats(struct ovpn_dev_estats); + if (!ovpn->estats) + return -ENOMEM; + + err = gro_cells_init(&ovpn->gro_cells, dev); if (err < 0) - return err; + goto err_free_estats; err = ovpn_mp_alloc(ovpn); if (err < 0) { gro_cells_destroy(&ovpn->gro_cells); - return err; + goto err_free_estats; } return 0; + +err_free_estats: + free_percpu(ovpn->estats); + ovpn->estats = NULL; + return err; } static void ovpn_net_uninit(struct net_device *dev) @@ -149,10 +161,65 @@ static void ovpn_get_drvinfo(struct net_device *dev, strscpy(info->bus_info, "ovpn", sizeof(info->bus_info)); } +static const char * const ovpn_ethtool_stats[] = { +#define OVPN_ETHTOOL_ESTAT(_counter, _name) \ + [OVPN_DEV_ESTAT_##_name] = #_counter, + OVPN_PEER_DROP_ESTATS(OVPN_ETHTOOL_ESTAT) + OVPN_PEER_EVENT_ESTATS(OVPN_ETHTOOL_ESTAT) + OVPN_DEV_DROP_ESTATS(OVPN_ETHTOOL_ESTAT) +#undef OVPN_ETHTOOL_ESTAT +}; + +static void ovpn_get_strings(struct net_device *dev, u32 stringset, u8 *data) +{ + unsigned int i; + + if (stringset != ETH_SS_STATS) + return; + + for (i = 0; i < ARRAY_SIZE(ovpn_ethtool_stats); i++) + ethtool_puts(&data, ovpn_ethtool_stats[i]); +} + +static int ovpn_get_sset_count(struct net_device *dev, int sset) +{ + if (sset == ETH_SS_STATS) + return ARRAY_SIZE(ovpn_ethtool_stats); + + return -EOPNOTSUPP; +} + +static void ovpn_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct ovpn_priv *ovpn = netdev_priv(dev); + struct ovpn_dev_estats *estats; + const u64_stats_t *counter; + unsigned int start, i; + u64 value; + int cpu; + + for (i = 0; i < ARRAY_SIZE(ovpn_ethtool_stats); i++) { + data[i] = 0; + for_each_possible_cpu(cpu) { + estats = per_cpu_ptr(ovpn->estats, cpu); + counter = &estats->counters[i]; + do { + start = u64_stats_fetch_begin(&estats->syncp); + value = u64_stats_read(counter); + } while (u64_stats_fetch_retry(&estats->syncp, start)); + data[i] += value; + } + } +} + static const struct ethtool_ops ovpn_ethtool_ops = { .get_drvinfo = ovpn_get_drvinfo, .get_link = ethtool_op_get_link, .get_ts_info = ethtool_op_get_ts_info, + .get_strings = ovpn_get_strings, + .get_sset_count = ovpn_get_sset_count, + .get_ethtool_stats = ovpn_get_ethtool_stats, }; static void ovpn_setup(struct net_device *dev) diff --git a/drivers/net/ovpn/ovpnpriv.h b/drivers/net/ovpn/ovpnpriv.h index 84499140e4bd9..56aec8d403e00 100644 --- a/drivers/net/ovpn/ovpnpriv.h +++ b/drivers/net/ovpn/ovpnpriv.h @@ -45,6 +45,7 @@ struct ovpn_peer_collection { * @peer: in P2P mode, this is the only remote peer * @gro_cells: pointer to the Generic Receive Offload cell * @keepalive_work: struct used to schedule keepalive periodic job + * @estats: monotonic per-CPU device-wide drop/event counters */ struct ovpn_priv { struct net_device *dev; @@ -54,6 +55,7 @@ struct ovpn_priv { struct ovpn_peer __rcu *peer; struct gro_cells gro_cells; struct delayed_work keepalive_work; + struct ovpn_dev_estats __percpu *estats; }; #endif /* _NET_OVPN_OVPNSTRUCT_H_ */ diff --git a/drivers/net/ovpn/peer.c b/drivers/net/ovpn/peer.c index 08cdd179de320..37bb57d7ff704 100644 --- a/drivers/net/ovpn/peer.c +++ b/drivers/net/ovpn/peer.c @@ -80,7 +80,7 @@ static void ovpn_peer_keepalive_send(struct work_struct *work) /* count attempted keepalives: if the TX path fails afterwards, * keepalive_tx will include a transmission that was not sent */ - atomic64_inc(&peer->estats.keepalive_tx); + ovpn_estats_inc(peer, keepalive_tx); local_bh_disable(); ovpn_xmit_special(peer, ovpn_keepalive_message, sizeof(ovpn_keepalive_message)); @@ -313,7 +313,7 @@ void ovpn_peer_endpoints_update(struct ovpn_peer *peer, struct sk_buff *skb) spin_unlock_bh(&peer->lock); - atomic64_inc(&peer->estats.floats); + ovpn_estats_inc(peer, floats); ovpn_nl_peer_float_notify(peer, &ss); /* rehashing is required only in MP mode as P2P has one peer diff --git a/drivers/net/ovpn/peer.h b/drivers/net/ovpn/peer.h index 5667bad91c31f..0279580011741 100644 --- a/drivers/net/ovpn/peer.h +++ b/drivers/net/ovpn/peer.h @@ -118,6 +118,22 @@ struct ovpn_peer { struct ovpn_peer_estats estats; }; +/** + * ovpn_estats_inc - increment a counter in both the per-peer and the + * device-wide extended statistics + * @peer: peer whose counter should be incremented + * @counter: name of the counter member in struct ovpn_peer_estats + * + * Device-wide counters are monotonic, they do not decrease when a peer + * is deleted. For device only counters use ovpn_dev_estats_inc() instead. + */ +#define ovpn_estats_inc(peer, counter) \ + do { \ + atomic64_inc(&(peer)->estats.counter); \ + ovpn_dev_estats_inc((peer)->ovpn->estats, \ + OVPN_PEER_ESTAT_IDX(counter)); \ + } while (0) + /** * ovpn_peer_hold - increase reference counter * @peer: the peer whose counter should be increased diff --git a/drivers/net/ovpn/stats.h b/drivers/net/ovpn/stats.h index 8b900e0c11210..40eb63e37700a 100644 --- a/drivers/net/ovpn/stats.h +++ b/drivers/net/ovpn/stats.h @@ -58,6 +58,71 @@ struct ovpn_peer_estats { atomic64_t floats; }; +#define OVPN_PEER_DROP_ESTATS(R) \ + R(rx_decrypt_errors, RX_DECRYPT_ERRORS) \ + R(rx_replay_errors, RX_REPLAY_ERRORS) \ + R(rx_unknown_keyid, RX_UNKNOWN_KEYID) \ + R(rx_unsupported_proto, RX_UNSUPPORTED_PROTO) \ + R(rx_rpf_errors, RX_RPF_ERRORS) \ + R(tx_encrypt_errors, TX_ENCRYPT_ERRORS) \ + R(tx_iv_exhausted, TX_IV_EXHAUSTED) \ + R(tx_no_key, TX_NO_KEY) \ + R(tx_no_transport, TX_NO_TRANSPORT) \ + R(tx_gso_errors, TX_GSO_ERRORS) + +#define OVPN_PEER_EVENT_ESTATS(R) \ + R(keepalive_rx, KEEPALIVE_RX) \ + R(keepalive_tx, KEEPALIVE_TX) \ + R(floats, FLOATS) + +#define OVPN_DEV_DROP_ESTATS(R) \ + R(rx_no_peer, RX_NO_PEER) \ + R(tx_no_peer, TX_NO_PEER) \ + R(tx_bad_proto, TX_BAD_PROTO) + +#define OVPN_PEER_ESTAT_IDX(_counter) \ + (offsetof(struct ovpn_peer_estats, _counter) / sizeof(atomic64_t)) + +enum ovpn_dev_estat { +#define OVPN_ESTAT_COUNT_ONE(_counter, _name) + 1 + OVPN_PEER_ESTAT_COUNT = 0 + OVPN_PEER_DROP_ESTATS(OVPN_ESTAT_COUNT_ONE) + OVPN_PEER_EVENT_ESTATS(OVPN_ESTAT_COUNT_ONE), +#undef OVPN_ESTAT_COUNT_ONE +#define OVPN_PEER_ESTAT_ENUM(_counter, _name) \ + OVPN_DEV_ESTAT_##_name = OVPN_PEER_ESTAT_IDX(_counter), + OVPN_PEER_DROP_ESTATS(OVPN_PEER_ESTAT_ENUM) + OVPN_PEER_EVENT_ESTATS(OVPN_PEER_ESTAT_ENUM) +#undef OVPN_PEER_ESTAT_ENUM + __OVPN_DEV_ESTAT_PEER_LAST = OVPN_PEER_ESTAT_COUNT - 1, +#define OVPN_DEV_ESTAT_ENUM(_counter, _name) OVPN_DEV_ESTAT_##_name, + OVPN_DEV_DROP_ESTATS(OVPN_DEV_ESTAT_ENUM) +#undef OVPN_DEV_ESTAT_ENUM + OVPN_DEV_ESTAT_COUNT, +}; + +static_assert(OVPN_PEER_ESTAT_COUNT == + sizeof(struct ovpn_peer_estats) / sizeof(atomic64_t)); + +struct ovpn_dev_estats { + u64_stats_t counters[OVPN_DEV_ESTAT_COUNT]; + struct u64_stats_sync syncp; +}; + +static inline void +ovpn_dev_estats_inc(struct ovpn_dev_estats __percpu *estats, + unsigned int index) +{ + struct ovpn_dev_estats *stats; + + local_bh_disable(); + stats = this_cpu_ptr(estats); + u64_stats_update_begin(&stats->syncp); + u64_stats_inc(&stats->counters[index]); + u64_stats_update_end(&stats->syncp); + local_bh_enable(); +} + void ovpn_peer_stats_init(struct ovpn_peer_stats *ps); static inline void ovpn_peer_stats_increment(struct ovpn_peer_stat *stat, diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index 7f69e8890b5b5..5ee196a8d4309 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -116,8 +116,11 @@ static int ovpn_udp_encap_recv(struct sock *sk, struct sk_buff *skb) else peer = ovpn_peer_get_by_id(ovpn, peer_id); - if (unlikely(!peer)) + if (unlikely(!peer)) { + ovpn_dev_estats_inc(ovpn->estats, + OVPN_DEV_ESTAT_RX_NO_PEER); goto drop; + } /* pop off outer UDP header */ __skb_pull(skb, sizeof(struct udphdr)); From patchwork Fri Sep 11 09:33:38 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marco Baffo X-Patchwork-Id: 5330 Return-Path: Delivered-To: patchwork@openvpn.net Received: by 2002:a05:7000:6446:b0:8a0:ea1f:253a with SMTP id n6csp133400mag; Fri, 11 Sep 2026 02:34:05 -0700 (PDT) X-Forwarded-Encrypted: i=2; AKwUvBzUunh0oA3EaiTteeR0Rsflyk/8dMcvBKOxVYX/3DLT0lSH+spmSTjWdTSZd2Q3LN5+nehbQO7yyto=@openvpn.net X-Received: by 2002:a05:6870:e122:b0:475:a153:2dcc with SMTP id 586e51a60fabf-47deb5a028bmr2048486fac.34.1789119244858; Fri, 11 Sep 2026 02:34:04 -0700 (PDT) ARC-Seal: i=1; a=rsa-sha256; t=1789119244; cv=none; d=google.com; s=arc-20260327; b=iLlEU9CEILdKV5jins9htwhplj5bJC50bXRbv4qoFURKwQJKizPZDyTTBDaM81DH3J /CRL1nigaaeoXxMSEiTCVqUEX5fqQLtn6GQNRSPkxNuccPU/hx6Hw+6hhhtx3rGIc/te 9Wu1+/EGMYHWPMnfLukvvKcAXOUMcwJOEBSzRKiTBOHCcoYlWI3L9tqE565KiUb5r8c0 3+5OEgu4PTtx+PwW4WMXYU1EQm/YVpT3KSfxSFjlsp3SWYke2gfMfatXft0v/aucoahO 2vx48n8Dgl03n8RImxmRe6lm2UCkJrIQazc8hvo3FXz0mz6eoNCQmaWNzNZxAAoiGry7 FbzA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20260327; h=errors-to:content-transfer-encoding:cc:list-subscribe:list-help :list-post:list-archive:list-unsubscribe:list-id:precedence:subject :mime-version:references:in-reply-to:message-id:date:to:from :dkim-signature:dkim-signature:dkim-signature:dkim-signature; bh=xPCCzsXXsp/qkPR7CjEa84t9SPBEbJIt1827eQpCJEQ=; fh=BsMg/B0Yb/hS/rzP5Npz4luh0IleZm8REk1XWiWRt2A=; b=Y/O6wLmDqkpDmzVXoMaBAPhT/JajRYw2/D1bp0ZgPwghkE12tOJi/kxzVdK1SEWDZB X6FqRP6e+WzO341Etkjl2hlznlcmrpomAq9DiRdzxDr5+yuzql+oWGbr6hmJHhfmkXwI olK8zAowHMpYyJZiD8SZaHfTOYiu1ANLEyaUBH4Z16DaLCjathGNIDF5pAr3yUZ16Xej cRmdutfuhSImYVSVAzTDdCVctlICc7jxRsDnazvgxNuf3AL/86L6Ud0J+6QVr3hUyJs/ qaNbmUUrbpI9Nase9JLxsVkNliTVaE12zOzUW9IrdEn5ZzP62gIsnYCvIvknNXgsbTha 8k2A==; dara=google.com ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=BpecutfG; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=FGmtApU+; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=hMOrF9lm; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=EhILcB0G; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net Received: from lists.sourceforge.net (lists.sourceforge.net. [216.105.38.7]) by mx.google.com with ESMTPS id 586e51a60fabf-47df89c56a9si2194548fac.111.2026.09.11.02.34.04 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 11 Sep 2026 02:34:04 -0700 (PDT) Received-SPF: pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) client-ip=216.105.38.7; Authentication-Results: mx.google.com; dkim=pass header.i=@lists.sourceforge.net header.s=beta header.b=BpecutfG; dkim=neutral (body hash did not verify) header.i=@sourceforge.net header.s=x header.b=FGmtApU+; dkim=neutral (body hash did not verify) header.i=@sf.net header.s=x header.b=hMOrF9lm; dkim=neutral (body hash did not verify) header.i=@mandelbit.com header.s=MBO0001 header.b=EhILcB0G; spf=pass (google.com: domain of openvpn-devel-bounces@lists.sourceforge.net designates 216.105.38.7 as permitted sender) smtp.mailfrom=openvpn-devel-bounces@lists.sourceforge.net DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.sourceforge.net; s=beta; h=Content-Transfer-Encoding:Content-Type:Cc: List-Subscribe:List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id: Subject:MIME-Version:References:In-Reply-To:Message-ID:Date:To:From:Sender: Reply-To:Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender :Resent-To:Resent-Cc:Resent-Message-ID:List-Owner; bh=xPCCzsXXsp/qkPR7CjEa84t9SPBEbJIt1827eQpCJEQ=; b=BpecutfGF0UaRpakKMaYwzhsGU 4VfqikBISkIo5KCXNmSzSVM+DwSsDzooKexm8NMUEyKBm0cM+w8tinPg5LOajlri19eIM4k5hMgvz kiWr7cbxbAXEoPrgRv5igsy2KtrzCw/xdQmaDQg3I468ABDdL1cjMKTR3x2IMP3nQ0q0=; Received: from [127.0.0.1] (helo=sfs-ml-3.v29.lw.sourceforge.com) by sfs-ml-3.v29.lw.sourceforge.com with esmtp (Exim 4.95) (envelope-from ) id 1x4xdw-0000Z7-Ml; Fri, 11 Sep 2026 09:34:01 +0000 Received: from [172.30.29.66] (helo=mx.sourceforge.net) by sfs-ml-3.v29.lw.sourceforge.com with esmtps (TLS1.2) tls TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 (Exim 4.95) (envelope-from ) id 1x4xdv-0000Yw-9i for openvpn-devel@lists.sourceforge.net; Fri, 11 Sep 2026 09:34:00 +0000 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sourceforge.net; s=x; h=Content-Transfer-Encoding:MIME-Version:References: In-Reply-To:Message-ID:Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type: Content-ID:Content-Description:Resent-Date:Resent-From:Resent-Sender: Resent-To:Resent-Cc:Resent-Message-ID:List-Id:List-Help:List-Unsubscribe: List-Subscribe:List-Post:List-Owner:List-Archive; bh=Xv6GdYREw41diB1phyB0iQT6CqYh+v7FN9eCRDelqnw=; b=FGmtApU+MhskE3pmOuDEIui2mM LwO6Wy2GUP8XdJRzigCn6HMgbbthAiYPgk6OmDtlc11ObLbAEX07yn5ZIv5j5cdXbgrmvDZIVvOUx dqQ9mT+J7wuXLeuUF/K7lcm7IoBM2mdCA1KLQvg6pOj4k8Et+K+bK2IVlTQl5ax1Ojkg=; DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=sf.net; s=x ; h=Content-Transfer-Encoding:MIME-Version:References:In-Reply-To:Message-ID: Date:Subject:Cc:To:From:Sender:Reply-To:Content-Type:Content-ID: Content-Description:Resent-Date:Resent-From:Resent-Sender:Resent-To:Resent-Cc :Resent-Message-ID:List-Id:List-Help:List-Unsubscribe:List-Subscribe: List-Post:List-Owner:List-Archive; bh=Xv6GdYREw41diB1phyB0iQT6CqYh+v7FN9eCRDelqnw=; b=hMOrF9lmZASjDgI6dabCa6eHly 0p46xQOi0Iqbo8Zb2835glZ8V5LtQa4LLB2szFPOD/TFm80ezquggbDn5EzBprbrWnoxUX6MAkHwQ jtVDB4Ed6CLYSnfqWH6yC7wQpnJqzlJAnxQz8sDsqrzQ3DMKa0WuNCAbYBfcEwwyc3xI=; Received: from mout-b-107.mailbox.org ([195.10.208.47]) by sfi-mx-1.v28.lw.sourceforge.com with esmtps (TLS1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.95) id 1x4xdr-0007IM-Ur for openvpn-devel@lists.sourceforge.net; Fri, 11 Sep 2026 09:33:59 +0000 Received: from smtp102.mailbox.org (smtp102.mailbox.org [10.196.197.102]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by mout-b-107.mailbox.org (Postfix) with ESMTPS id 4hh8W01H9nz3xx9; Fri, 11 Sep 2026 11:33:48 +0200 (CEST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=mandelbit.com; s=MBO0001; t=1789119228; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:cc:mime-version:mime-version: content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references; bh=Xv6GdYREw41diB1phyB0iQT6CqYh+v7FN9eCRDelqnw=; b=EhILcB0G05W6QhOXPXVsAZOxVm85pIsTIEp6tvvGe5tIswRbh+LhUN0FwaaBRrXHwDkdxf +Y0KM5I7YbTEhKYw4XZfaMylBBEhBMqGvaUTpTFJyrxNBlxOhFPMY2s+5VhGSYMMZpBZ/Y 4/UpkP8+/cycgoByDOxz0mqK66/1NhYBDq8m7fhM0qZNv6GGKgNlugAB+sCfUWYe/CDtFb L4HW4rAJsfpVllPzP8Mec8iwCZUR1SimRbQIiOunb55IjfeHNORRbc3MAhe3OjF/J1E6tr eRpCWZn7kNWax4YzrReKDrtBDlAniMMXh113FOdJ9SeqgMV+Cj+p9lb7NQxvww== From: Marco Baffo To: openvpn-devel@lists.sourceforge.net Date: Fri, 11 Sep 2026 11:33:38 +0200 Message-ID: <20260911093338.1065898-3-marco@mandelbit.com> In-Reply-To: <20260911093338.1065898-1-marco@mandelbit.com> References: <20260911093338.1065898-1-marco@mandelbit.com> MIME-Version: 1.0 X-Spam-Score: -0.2 (/) X-Spam-Report: Spam detection software, running on the system "sfi-spamd-2.hosts.colo.sdot.me", has NOT identified this incoming email as spam. The original message has been attached to this so you can view it or label similar future email. If you have any questions, see the administrator of that system for details. Content preview: Register an OVPN drop reason subsystem and pass explicit reasons to the skb free helpers in RX and TX error paths. Generate reason codes and strings from the existing drop counter lists. Use core reas [...] Content analysis details: (-0.2 points, 5.0 required) pts rule name description ---- ---------------------- -------------------------------------------------- -0.1 DKIM_VALID_AU Message has a valid DKIM or DK signature from author's domain -0.1 DKIM_VALID_EF Message has a valid DKIM or DK signature from envelope-from domain 0.1 DKIM_SIGNED Message has a DKIM or DK signature, not necessarily valid -0.1 DKIM_VALID Message has at least one valid DKIM or DK signature X-Headers-End: 1x4xdr-0007IM-Ur Subject: [Openvpn-devel] [RFC ovpn net-next v3 3/3] ovpn: report packet drop reasons X-BeenThere: openvpn-devel@lists.sourceforge.net X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Antonio Quartulli Errors-To: openvpn-devel-bounces@lists.sourceforge.net X-getmail-retrieved-from-mailbox: Inbox X-GMAIL-THRID: 1876027501471124311 X-GMAIL-MSGID: 1876027501471124311 Register an OVPN drop reason subsystem and pass explicit reasons to the skb free helpers in RX and TX error paths. Generate reason codes and strings from the existing drop counter lists. Use core reasons for short UDP packets and unsupported DATA_V1 packets. Signed-off-by: Marco Baffo --- Changes: this patch was introduced in v3. drivers/net/ovpn/drop.h | 39 ++++++++++++++++++++++++++++++++++ drivers/net/ovpn/io.c | 45 +++++++++++++++++++++++++++++----------- drivers/net/ovpn/main.c | 19 +++++++++++++++++ drivers/net/ovpn/udp.c | 19 +++++++++++------ include/net/dropreason.h | 6 ++++++ 5 files changed, 110 insertions(+), 18 deletions(-) create mode 100644 drivers/net/ovpn/drop.h diff --git a/drivers/net/ovpn/drop.h b/drivers/net/ovpn/drop.h new file mode 100644 index 0000000000000..75e04ba57a778 --- /dev/null +++ b/drivers/net/ovpn/drop.h @@ -0,0 +1,39 @@ +/* SPDX-License-Identifier: GPL-2.0-only */ +/* OpenVPN data channel offload + * + * Copyright (C) 2026 OpenVPN, Inc. + * Author: Marco Baffo + * Antonio Quartulli + */ + +#ifndef _NET_OVPN_DROP_H_ +#define _NET_OVPN_DROP_H_ + +#include +#include + +#include "stats.h" + +enum ovpn_drop_reason { + __OVPN_DROP_REASON = SKB_DROP_REASON_SUBSYS_OVPN << + SKB_DROP_REASON_SUBSYS_SHIFT, +#define OVPN_DROP_REASON_ENUM(_counter, _name) OVPN_DROP_##_name, + OVPN_PEER_DROP_ESTATS(OVPN_DROP_REASON_ENUM) + OVPN_DEV_DROP_ESTATS(OVPN_DROP_REASON_ENUM) +#undef OVPN_DROP_REASON_ENUM + OVPN_DROP_MAX, +}; + +static inline void ovpn_kfree_skb_reason(struct sk_buff *skb, + enum ovpn_drop_reason reason) +{ + kfree_skb_reason(skb, (u32)reason); +} + +static inline void ovpn_kfree_skb_list_reason(struct sk_buff *skb, + enum ovpn_drop_reason reason) +{ + kfree_skb_list_reason(skb, (u32)reason); +} + +#endif /* _NET_OVPN_DROP_H_ */ diff --git a/drivers/net/ovpn/io.c b/drivers/net/ovpn/io.c index ca3e8a9680694..134747d7e08ef 100644 --- a/drivers/net/ovpn/io.c +++ b/drivers/net/ovpn/io.c @@ -20,6 +20,7 @@ #include "bind.h" #include "crypto.h" #include "crypto_aead.h" +#include "drop.h" #include "netlink.h" #include "proto.h" #include "tcp.h" @@ -109,6 +110,7 @@ void ovpn_decrypt_post(void *data, int ret) { struct ovpn_crypto_key_slot *ks; unsigned int payload_offset = 0; + enum ovpn_drop_reason reason; struct sk_buff *skb = data; struct ovpn_socket *sock; struct ovpn_peer *peer; @@ -130,6 +132,7 @@ void ovpn_decrypt_post(void *data, int ret) if (unlikely(ret < 0)) { ovpn_estats_inc(peer, rx_decrypt_errors); + reason = OVPN_DROP_RX_DECRYPT_ERRORS; goto drop; } @@ -141,6 +144,7 @@ void ovpn_decrypt_post(void *data, int ret) netdev_name(peer->ovpn->dev), peer->id, ret); ovpn_estats_inc(peer, rx_replay_errors); + reason = OVPN_DROP_RX_REPLAY_ERRORS; goto drop; } @@ -169,6 +173,7 @@ void ovpn_decrypt_post(void *data, int ret) netdev_name(peer->ovpn->dev), peer->id); ovpn_estats_inc(peer, rx_unsupported_proto); + reason = OVPN_DROP_RX_UNSUPPORTED_PROTO; goto drop; } @@ -185,6 +190,7 @@ void ovpn_decrypt_post(void *data, int ret) net_info_ratelimited("%s: unsupported protocol received from peer %u\n", netdev_name(peer->ovpn->dev), peer->id); ovpn_estats_inc(peer, rx_unsupported_proto); + reason = OVPN_DROP_RX_UNSUPPORTED_PROTO; goto drop; } skb->protocol = proto; @@ -200,6 +206,7 @@ void ovpn_decrypt_post(void *data, int ret) netdev_name(peer->ovpn->dev), peer->id, &ip_hdr(skb)->saddr); ovpn_estats_inc(peer, rx_rpf_errors); + reason = OVPN_DROP_RX_RPF_ERRORS; goto drop; } @@ -207,9 +214,10 @@ void ovpn_decrypt_post(void *data, int ret) /* skb is passed to upper layer - don't free it */ skb = NULL; drop: - if (unlikely(skb)) + if (unlikely(skb)) { ovpn_dev_dstats_rx_dropped(peer->ovpn->dev); - kfree_skb(skb); + ovpn_kfree_skb_reason(skb, reason); + } drop_nocount: if (likely(ks)) ovpn_crypto_key_slot_put(ks); @@ -234,7 +242,7 @@ void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb) key_id); ovpn_estats_inc(peer, rx_unknown_keyid); ovpn_dev_dstats_rx_dropped(peer->ovpn->dev); - kfree_skb(skb); + ovpn_kfree_skb_reason(skb, OVPN_DROP_RX_UNKNOWN_KEYID); ovpn_peer_put(peer); return; } @@ -246,6 +254,7 @@ void ovpn_recv(struct ovpn_peer *peer, struct sk_buff *skb) void ovpn_encrypt_post(void *data, int ret) { struct ovpn_crypto_key_slot *ks; + enum ovpn_drop_reason reason; struct sk_buff *skb = data; struct ovpn_socket *sock; struct ovpn_peer *peer; @@ -275,11 +284,13 @@ void ovpn_encrypt_post(void *data, int ret) ovpn_nl_key_swap_notify(peer, ks->key_id); ovpn_estats_inc(peer, tx_iv_exhausted); + reason = OVPN_DROP_TX_IV_EXHAUSTED; goto err; } if (unlikely(ret < 0)) { ovpn_estats_inc(peer, tx_encrypt_errors); + reason = OVPN_DROP_TX_ENCRYPT_ERRORS; goto err; } @@ -290,6 +301,7 @@ void ovpn_encrypt_post(void *data, int ret) sock = rcu_dereference(peer->sock); if (unlikely(!sock)) { ovpn_estats_inc(peer, tx_no_transport); + reason = OVPN_DROP_TX_NO_TRANSPORT; goto err_unlock; } @@ -303,6 +315,7 @@ void ovpn_encrypt_post(void *data, int ret) default: /* no transport configured yet */ ovpn_estats_inc(peer, tx_no_transport); + reason = OVPN_DROP_TX_NO_TRANSPORT; goto err_unlock; } @@ -314,16 +327,18 @@ void ovpn_encrypt_post(void *data, int ret) err_unlock: rcu_read_unlock(); err: - if (unlikely(skb)) + if (unlikely(skb)) { ovpn_dev_dstats_tx_dropped(peer->ovpn->dev); - kfree_skb(skb); + ovpn_kfree_skb_reason(skb, reason); + } if (likely(ks)) ovpn_crypto_key_slot_put(ks); if (likely(peer)) ovpn_peer_put(peer); } -static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb) +static enum skb_drop_reason ovpn_encrypt_one(struct ovpn_peer *peer, + struct sk_buff *skb) { struct ovpn_crypto_key_slot *ks; @@ -331,7 +346,7 @@ static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb) ks = ovpn_crypto_key_slot_primary(&peer->crypto); if (unlikely(!ks)) { ovpn_estats_inc(peer, tx_no_key); - return false; + return (enum skb_drop_reason)OVPN_DROP_TX_NO_KEY; } /* take a reference to the peer because the crypto code may run async. @@ -340,12 +355,12 @@ static bool ovpn_encrypt_one(struct ovpn_peer *peer, struct sk_buff *skb) if (unlikely(!ovpn_peer_hold(peer))) { DEBUG_NET_WARN_ON_ONCE(1); ovpn_crypto_key_slot_put(ks); - return false; + return SKB_DROP_REASON_NOT_SPECIFIED; } memset(ovpn_skb_cb(skb), 0, sizeof(struct ovpn_cb)); ovpn_encrypt_post(skb, ovpn_aead_encrypt(peer, ks, skb)); - return true; + return SKB_NOT_DROPPED_YET; } /* send skb to connected peer, if any */ @@ -353,14 +368,16 @@ static void ovpn_send(struct ovpn_priv *ovpn, struct sk_buff *skb, struct ovpn_peer *peer) { struct sk_buff *curr, *next; + enum skb_drop_reason reason; /* this might be a GSO-segmented skb list: process each skb * independently */ skb_list_walk_safe(skb, curr, next) { - if (unlikely(!ovpn_encrypt_one(peer, curr))) { + reason = ovpn_encrypt_one(peer, curr); + if (unlikely(reason != SKB_NOT_DROPPED_YET)) { ovpn_dev_dstats_tx_dropped(ovpn->dev); - kfree_skb(curr); + kfree_skb_reason(curr, reason); } } @@ -374,6 +391,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) struct ovpn_priv *ovpn = netdev_priv(dev); struct sk_buff *segments, *curr, *next; struct sk_buff_head skb_list; + enum ovpn_drop_reason reason; unsigned int tx_bytes = 0; struct ovpn_peer *peer; __be16 proto; @@ -387,6 +405,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) if (unlikely(!proto || skb->protocol != proto)) { ovpn_dev_estats_inc(ovpn->estats, OVPN_DEV_ESTAT_TX_BAD_PROTO); + reason = OVPN_DROP_TX_BAD_PROTO; goto drop_no_peer; } @@ -407,6 +426,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) } ovpn_dev_estats_inc(ovpn->estats, OVPN_DEV_ESTAT_TX_NO_PEER); + reason = OVPN_DROP_TX_NO_PEER; goto drop_no_peer; } /* dst was needed for peer selection - it can now be dropped */ @@ -419,6 +439,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) net_err_ratelimited("%s: cannot segment payload packet: %d\n", netdev_name(dev), ret); ovpn_estats_inc(peer, tx_gso_errors); + reason = OVPN_DROP_TX_GSO_ERRORS; goto drop; } @@ -464,7 +485,7 @@ netdev_tx_t ovpn_net_xmit(struct sk_buff *skb, struct net_device *dev) drop_no_peer: ovpn_dev_dstats_tx_dropped(ovpn->dev); skb_tx_error(skb); - kfree_skb_list(skb); + ovpn_kfree_skb_list_reason(skb, reason); return NETDEV_TX_OK; } diff --git a/drivers/net/ovpn/main.c b/drivers/net/ovpn/main.c index 6a34557e89561..8cbb88282e742 100644 --- a/drivers/net/ovpn/main.c +++ b/drivers/net/ovpn/main.c @@ -19,6 +19,7 @@ #include #include "ovpnpriv.h" +#include "drop.h" #include "main.h" #include "netlink.h" #include "io.h" @@ -170,6 +171,20 @@ static const char * const ovpn_ethtool_stats[] = { #undef OVPN_ETHTOOL_ESTAT }; +static const char * const ovpn_drop_reasons[] = { +#define OVPN_DROP_REASON_STRING(_counter, _name) \ + [(OVPN_DROP_##_name) & ~SKB_DROP_REASON_SUBSYS_MASK] = \ + "OVPN_DROP_" #_name, + OVPN_PEER_DROP_ESTATS(OVPN_DROP_REASON_STRING) + OVPN_DEV_DROP_ESTATS(OVPN_DROP_REASON_STRING) +#undef OVPN_DROP_REASON_STRING +}; + +static const struct drop_reason_list ovpn_drop_reason_list = { + .reasons = ovpn_drop_reasons, + .n_reasons = ARRAY_SIZE(ovpn_drop_reasons), +}; + static void ovpn_get_strings(struct net_device *dev, u32 stringset, u8 *data) { unsigned int i; @@ -353,6 +368,9 @@ static int __init ovpn_init(void) goto unreg_rtnl; } + drop_reasons_register_subsys(SKB_DROP_REASON_SUBSYS_OVPN, + &ovpn_drop_reason_list); + return 0; unreg_rtnl: @@ -369,6 +387,7 @@ static __exit void ovpn_cleanup(void) rtnl_link_unregister(&ovpn_link_ops); flush_workqueue(ovpn_wq); + drop_reasons_unregister_subsys(SKB_DROP_REASON_SUBSYS_OVPN); rcu_barrier(); destroy_workqueue(ovpn_wq); diff --git a/drivers/net/ovpn/udp.c b/drivers/net/ovpn/udp.c index 5ee196a8d4309..882c9672acfe0 100644 --- a/drivers/net/ovpn/udp.c +++ b/drivers/net/ovpn/udp.c @@ -21,6 +21,7 @@ #include "ovpnpriv.h" #include "main.h" #include "bind.h" +#include "drop.h" #include "io.h" #include "peer.h" #include "proto.h" @@ -66,6 +67,7 @@ static struct ovpn_socket *ovpn_socket_from_udp_sock(struct sock *sk) */ static int ovpn_udp_encap_recv(struct sock *sk, struct sk_buff *skb) { + enum skb_drop_reason reason = SKB_DROP_REASON_NOT_SPECIFIED; struct ovpn_socket *ovpn_sock; struct ovpn_priv *ovpn; struct ovpn_peer *peer; @@ -89,18 +91,22 @@ static int ovpn_udp_encap_recv(struct sock *sk, struct sk_buff *skb) * header are accessible. * They are required to fetch the OP code, the key ID and the peer ID. */ - if (unlikely(!pskb_may_pull(skb, sizeof(struct udphdr) + - OVPN_OPCODE_SIZE))) { - net_dbg_ratelimited("%s: packet too small from UDP socket\n", - netdev_name(ovpn->dev)); + reason = pskb_may_pull_reason(skb, sizeof(struct udphdr) + + OVPN_OPCODE_SIZE); + if (unlikely(reason != SKB_NOT_DROPPED_YET)) { + if (reason == SKB_DROP_REASON_PKT_TOO_SMALL) + net_dbg_ratelimited("%s: packet too small from UDP socket\n", + netdev_name(ovpn->dev)); goto drop; } opcode = ovpn_opcode_from_skb(skb, sizeof(struct udphdr)); if (unlikely(opcode != OVPN_DATA_V2)) { /* DATA_V1 is not supported */ - if (opcode == OVPN_DATA_V1) + if (opcode == OVPN_DATA_V1) { + reason = SKB_DROP_REASON_UNHANDLED_PROTO; goto drop; + } /* unknown or control packet: let it bubble up to userspace */ return 1; @@ -119,6 +125,7 @@ static int ovpn_udp_encap_recv(struct sock *sk, struct sk_buff *skb) if (unlikely(!peer)) { ovpn_dev_estats_inc(ovpn->estats, OVPN_DEV_ESTAT_RX_NO_PEER); + reason = (enum skb_drop_reason)OVPN_DROP_RX_NO_PEER; goto drop; } @@ -130,7 +137,7 @@ static int ovpn_udp_encap_recv(struct sock *sk, struct sk_buff *skb) drop: ovpn_dev_dstats_rx_dropped(ovpn->dev); drop_noovpn: - kfree_skb(skb); + kfree_skb_reason(skb, reason); return 0; } diff --git a/include/net/dropreason.h b/include/net/dropreason.h index 1df60645fb278..d520f5996b85a 100644 --- a/include/net/dropreason.h +++ b/include/net/dropreason.h @@ -29,6 +29,12 @@ enum skb_drop_reason_subsys { */ SKB_DROP_REASON_SUBSYS_QDISC, + /** + * @SKB_DROP_REASON_SUBSYS_OVPN: OpenVPN data channel drop reasons, + * see drivers/net/ovpn/drop.h + */ + SKB_DROP_REASON_SUBSYS_OVPN, + /** @SKB_DROP_REASON_SUBSYS_NUM: number of subsystems defined */ SKB_DROP_REASON_SUBSYS_NUM };