net/tcp: Add TCP-AO segments counters
authorDmitry Safonov <dima@arista.com>
Mon, 23 Oct 2023 19:22:05 +0000 (20:22 +0100)
committerDavid S. Miller <davem@davemloft.net>
Fri, 27 Oct 2023 09:35:45 +0000 (10:35 +0100)
Introduce segment counters that are useful for troubleshooting/debugging
as well as for writing tests.
Now there are global snmp counters as well as per-socket and per-key.

Co-developed-by: Francesco Ruggeri <fruggeri@arista.com>
Signed-off-by: Francesco Ruggeri <fruggeri@arista.com>
Co-developed-by: Salam Noureddine <noureddine@arista.com>
Signed-off-by: Salam Noureddine <noureddine@arista.com>
Signed-off-by: Dmitry Safonov <dima@arista.com>
Acked-by: David Ahern <dsahern@kernel.org>
Signed-off-by: David S. Miller <davem@davemloft.net>
include/net/dropreason-core.h
include/net/tcp.h
include/net/tcp_ao.h
include/uapi/linux/snmp.h
include/uapi/linux/tcp.h
net/ipv4/proc.c
net/ipv4/tcp_ao.c
net/ipv4/tcp_ipv4.c
net/ipv6/tcp_ipv6.c

index 7637137ae33ee2bbe6204f9ccab0181fdbcc27e2..3c70ad53a49cb6d5749388236422a1e6471b473f 100644 (file)
@@ -168,17 +168,24 @@ enum skb_drop_reason {
         */
        SKB_DROP_REASON_TCP_MD5FAILURE,
        /**
-        * @SKB_DROP_REASON_TCP_AONOTFOUND: no TCP-AO hash and one was expected
+        * @SKB_DROP_REASON_TCP_AONOTFOUND: no TCP-AO hash and one was expected,
+        * corresponding to LINUX_MIB_TCPAOREQUIRED
         */
        SKB_DROP_REASON_TCP_AONOTFOUND,
        /**
         * @SKB_DROP_REASON_TCP_AOUNEXPECTED: TCP-AO hash is present and it
-        * was not expected.
+        * was not expected, corresponding to LINUX_MIB_TCPAOKEYNOTFOUND
         */
        SKB_DROP_REASON_TCP_AOUNEXPECTED,
-       /** @SKB_DROP_REASON_TCP_AOKEYNOTFOUND: TCP-AO key is unknown */
+       /**
+        * @SKB_DROP_REASON_TCP_AOKEYNOTFOUND: TCP-AO key is unknown,
+        * corresponding to LINUX_MIB_TCPAOKEYNOTFOUND
+        */
        SKB_DROP_REASON_TCP_AOKEYNOTFOUND,
-       /** @SKB_DROP_REASON_TCP_AOFAILURE: TCP-AO hash is wrong */
+       /**
+        * @SKB_DROP_REASON_TCP_AOFAILURE: TCP-AO hash is wrong,
+        * corresponding to LINUX_MIB_TCPAOBAD
+        */
        SKB_DROP_REASON_TCP_AOFAILURE,
        /**
         * @SKB_DROP_REASON_SOCKET_BACKLOG: failed to add skb to socket backlog (
index 8e1f835bad227e5f95b85aa2dcddcc29b3b18ffb..50ae1ed244e5ae10a7921e7d199a7680a2b23f20 100644 (file)
@@ -2712,7 +2712,7 @@ static inline int tcp_parse_auth_options(const struct tcphdr *th,
 }
 
 static inline bool tcp_ao_required(struct sock *sk, const void *saddr,
-                                  int family)
+                                  int family, bool stat_inc)
 {
 #ifdef CONFIG_TCP_AO
        struct tcp_ao_info *ao_info;
@@ -2724,8 +2724,13 @@ static inline bool tcp_ao_required(struct sock *sk, const void *saddr,
                return false;
 
        ao_key = tcp_ao_do_lookup(sk, saddr, family, -1, -1);
-       if (ao_info->ao_required || ao_key)
+       if (ao_info->ao_required || ao_key) {
+               if (stat_inc) {
+                       NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOREQUIRED);
+                       atomic64_inc(&ao_info->counters.ao_required);
+               }
                return true;
+       }
 #endif
        return false;
 }
@@ -2747,8 +2752,10 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req,
                return SKB_DROP_REASON_TCP_AUTH_HDR;
 
        if (req) {
-               if (tcp_rsk_used_ao(req) != !!aoh)
+               if (tcp_rsk_used_ao(req) != !!aoh) {
+                       NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOBAD);
                        return SKB_DROP_REASON_TCP_AOFAILURE;
+               }
        }
 
        /* sdif set, means packet ingressed via a device
@@ -2763,7 +2770,7 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req,
                 * the last key is impossible to remove, so there's
                 * always at least one current_key.
                 */
-               if (tcp_ao_required(sk, saddr, family))
+               if (tcp_ao_required(sk, saddr, family, true))
                        return SKB_DROP_REASON_TCP_AONOTFOUND;
                if (unlikely(tcp_md5_do_lookup(sk, l3index, saddr, family))) {
                        NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
index 1c7c0a5d187711f8d5390f436d2e3d28cfd6f357..cfb55bd9411bcda78d53a4a39a6e687afdb34f31 100644 (file)
@@ -19,6 +19,13 @@ struct tcp_ao_hdr {
        u8      rnext_keyid;
 };
 
+struct tcp_ao_counters {
+       atomic64_t      pkt_good;
+       atomic64_t      pkt_bad;
+       atomic64_t      key_not_found;
+       atomic64_t      ao_required;
+};
+
 struct tcp_ao_key {
        struct hlist_node       node;
        union tcp_ao_addr       addr;
@@ -33,6 +40,8 @@ struct tcp_ao_key {
        u8                      rcvid;
        u8                      maclen;
        struct rcu_head         rcu;
+       atomic64_t              pkt_good;
+       atomic64_t              pkt_bad;
        u8                      traffic_keys[];
 };
 
@@ -81,6 +90,7 @@ struct tcp_ao_info {
         */
        struct tcp_ao_key       *current_key;
        struct tcp_ao_key       *rnext_key;
+       struct tcp_ao_counters  counters;
        u32                     ao_required     :1,
                                __unused        :31;
        __be32                  lisn;
index b2b72886cb6d1db1a99e69a8dad8612ef85cfb42..3d5ea841bffe56d1ab9d441aee9a5e0767c40c35 100644 (file)
@@ -297,6 +297,10 @@ enum
        LINUX_MIB_TCPMIGRATEREQSUCCESS,         /* TCPMigrateReqSuccess */
        LINUX_MIB_TCPMIGRATEREQFAILURE,         /* TCPMigrateReqFailure */
        LINUX_MIB_TCPPLBREHASH,                 /* TCPPLBRehash */
+       LINUX_MIB_TCPAOREQUIRED,                /* TCPAORequired */
+       LINUX_MIB_TCPAOBAD,                     /* TCPAOBad */
+       LINUX_MIB_TCPAOKEYNOTFOUND,             /* TCPAOKeyNotFound */
+       LINUX_MIB_TCPAOGOOD,                    /* TCPAOGood */
        __LINUX_MIB_MAX
 };
 
index fa49f03e62fe7c0bd8f70f417b2fc52a986ab027..9c48964849d1b34655a6446c637cf6d6ad302e2f 100644 (file)
@@ -404,9 +404,15 @@ struct tcp_ao_info_opt { /* setsockopt(TCP_AO_INFO) */
        __u32   set_current     :1,     /* corresponding ::current_key */
                set_rnext       :1,     /* corresponding ::rnext */
                ao_required     :1,     /* don't accept non-AO connects */
-               reserved        :29;    /* must be 0 */
+               set_counters    :1,     /* set/clear ::pkt_* counters */
+               reserved        :28;    /* must be 0 */
+       __u16   reserved2;              /* padding, must be 0 */
        __u8    current_key;            /* KeyID to set as Current_key */
        __u8    rnext;                  /* KeyID to set as Rnext_key */
+       __u64   pkt_good;               /* verified segments */
+       __u64   pkt_bad;                /* failed verification */
+       __u64   pkt_key_not_found;      /* could not find a key to verify */
+       __u64   pkt_ao_required;        /* segments missing TCP-AO sign */
 } __attribute__((aligned(8)));
 
 /* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */
index a85b0aba36462d15aca6f594e3be37354e582e86..f5b37ebc18c031a873f21601c4701fe42a7d0b34 100644 (file)
@@ -299,6 +299,10 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TCPMigrateReqSuccess", LINUX_MIB_TCPMIGRATEREQSUCCESS),
        SNMP_MIB_ITEM("TCPMigrateReqFailure", LINUX_MIB_TCPMIGRATEREQFAILURE),
        SNMP_MIB_ITEM("TCPPLBRehash", LINUX_MIB_TCPPLBREHASH),
+       SNMP_MIB_ITEM("TCPAORequired", LINUX_MIB_TCPAOREQUIRED),
+       SNMP_MIB_ITEM("TCPAOBad", LINUX_MIB_TCPAOBAD),
+       SNMP_MIB_ITEM("TCPAOKeyNotFound", LINUX_MIB_TCPAOKEYNOTFOUND),
+       SNMP_MIB_ITEM("TCPAOGood", LINUX_MIB_TCPAOGOOD),
        SNMP_MIB_SENTINEL
 };
 
index 6c5815713b7351c983aa0debb05935fa8748e2ae..1097e99a9ad64b83dd1f315a9f91efb612a7204d 100644 (file)
@@ -182,6 +182,8 @@ static struct tcp_ao_key *tcp_ao_copy_key(struct sock *sk,
        *new_key = *key;
        INIT_HLIST_NODE(&new_key->node);
        tcp_sigpool_get(new_key->tcp_sigpool_id);
+       atomic64_set(&new_key->pkt_good, 0);
+       atomic64_set(&new_key->pkt_bad, 0);
 
        return new_key;
 }
@@ -771,8 +773,12 @@ tcp_ao_verify_hash(const struct sock *sk, const struct sk_buff *skb,
        const struct tcphdr *th = tcp_hdr(skb);
        void *hash_buf = NULL;
 
-       if (maclen != tcp_ao_maclen(key))
+       if (maclen != tcp_ao_maclen(key)) {
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOBAD);
+               atomic64_inc(&info->counters.pkt_bad);
+               atomic64_inc(&key->pkt_bad);
                return SKB_DROP_REASON_TCP_AOFAILURE;
+       }
 
        hash_buf = kmalloc(tcp_ao_digest_size(key), GFP_ATOMIC);
        if (!hash_buf)
@@ -782,9 +788,15 @@ tcp_ao_verify_hash(const struct sock *sk, const struct sk_buff *skb,
        tcp_ao_hash_skb(family, hash_buf, key, sk, skb, traffic_key,
                        (phash - (u8 *)th), sne);
        if (memcmp(phash, hash_buf, maclen)) {
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOBAD);
+               atomic64_inc(&info->counters.pkt_bad);
+               atomic64_inc(&key->pkt_bad);
                kfree(hash_buf);
                return SKB_DROP_REASON_TCP_AOFAILURE;
        }
+       NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOGOOD);
+       atomic64_inc(&info->counters.pkt_good);
+       atomic64_inc(&key->pkt_good);
        kfree(hash_buf);
        return SKB_NOT_DROPPED_YET;
 }
@@ -804,8 +816,10 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb,
        u32 sne = 0;
 
        info = rcu_dereference(tcp_sk(sk)->ao_info);
-       if (!info)
+       if (!info) {
+               NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOKEYNOTFOUND);
                return SKB_DROP_REASON_TCP_AOUNEXPECTED;
+       }
 
        if (unlikely(th->syn)) {
                sisn = th->seq;
@@ -900,6 +914,8 @@ verify_hash:
        return ret;
 
 key_not_found:
+       NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPAOKEYNOTFOUND);
+       atomic64_inc(&info->counters.key_not_found);
        return SKB_DROP_REASON_TCP_AOKEYNOTFOUND;
 }
 
@@ -1483,6 +1499,8 @@ static int tcp_ao_add_cmd(struct sock *sk, unsigned short int family,
        key->keyflags   = cmd.keyflags;
        key->sndid      = cmd.sndid;
        key->rcvid      = cmd.rcvid;
+       atomic64_set(&key->pkt_good, 0);
+       atomic64_set(&key->pkt_bad, 0);
 
        ret = tcp_ao_parse_crypto(&cmd, key);
        if (ret < 0)
@@ -1699,7 +1717,7 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family,
                        return -EINVAL;
        }
 
-       if (cmd.reserved != 0)
+       if (cmd.reserved != 0 || cmd.reserved2 != 0)
                return -EINVAL;
 
        ao_info = setsockopt_ao_info(sk);
@@ -1734,6 +1752,12 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family,
                        goto out;
                }
        }
+       if (cmd.set_counters) {
+               atomic64_set(&ao_info->counters.pkt_good, cmd.pkt_good);
+               atomic64_set(&ao_info->counters.pkt_bad, cmd.pkt_bad);
+               atomic64_set(&ao_info->counters.key_not_found, cmd.pkt_key_not_found);
+               atomic64_set(&ao_info->counters.ao_required, cmd.pkt_ao_required);
+       }
 
        ao_info->ao_required = cmd.ao_required;
        if (new_current)
index f39ccefa78dcd3ef7026ec7771e37f6dd09afbdd..ece95d5138e1b367277977afd8d41cc1552dfb9c 100644 (file)
@@ -1531,7 +1531,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname,
        /* Don't allow keys for peers that have a matching TCP-AO key.
         * See the comment in tcp_ao_add_cmd()
         */
-       if (tcp_ao_required(sk, addr, AF_INET))
+       if (tcp_ao_required(sk, addr, AF_INET, false))
                return -EKEYREJECTED;
 
        return tcp_md5_do_add(sk, addr, AF_INET, prefixlen, l3index, flags,
index d2724383d263b2188ee33274810662e2227a7a75..cc899caf348e6d4a96a5a8f7bf30cc5ce4153abf 100644 (file)
@@ -661,7 +661,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
                /* Don't allow keys for peers that have a matching TCP-AO key.
                 * See the comment in tcp_ao_add_cmd()
                 */
-               if (tcp_ao_required(sk, addr, AF_INET))
+               if (tcp_ao_required(sk, addr, AF_INET, false))
                        return -EKEYREJECTED;
                return tcp_md5_do_add(sk, addr,
                                      AF_INET, prefixlen, l3index, flags,
@@ -673,7 +673,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname,
        /* Don't allow keys for peers that have a matching TCP-AO key.
         * See the comment in tcp_ao_add_cmd()
         */
-       if (tcp_ao_required(sk, addr, AF_INET6))
+       if (tcp_ao_required(sk, addr, AF_INET6, false))
                return -EKEYREJECTED;
 
        return tcp_md5_do_add(sk, addr, AF_INET6, prefixlen, l3index, flags,