Commit af09a341 authored by Dmitry Safonov's avatar Dmitry Safonov Committed by David S. Miller

net/tcp: Add TCP-AO segments counters

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: default avatarFrancesco Ruggeri <fruggeri@arista.com>
Signed-off-by: default avatarFrancesco Ruggeri <fruggeri@arista.com>
Co-developed-by: default avatarSalam Noureddine <noureddine@arista.com>
Signed-off-by: default avatarSalam Noureddine <noureddine@arista.com>
Signed-off-by: default avatarDmitry Safonov <dima@arista.com>
Acked-by: default avatarDavid Ahern <dsahern@kernel.org>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 0a3a8090
...@@ -168,17 +168,24 @@ enum skb_drop_reason { ...@@ -168,17 +168,24 @@ enum skb_drop_reason {
*/ */
SKB_DROP_REASON_TCP_MD5FAILURE, 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_AONOTFOUND,
/** /**
* @SKB_DROP_REASON_TCP_AOUNEXPECTED: TCP-AO hash is present and it * @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_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_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_TCP_AOFAILURE,
/** /**
* @SKB_DROP_REASON_SOCKET_BACKLOG: failed to add skb to socket backlog ( * @SKB_DROP_REASON_SOCKET_BACKLOG: failed to add skb to socket backlog (
......
...@@ -2712,7 +2712,7 @@ static inline int tcp_parse_auth_options(const struct tcphdr *th, ...@@ -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, static inline bool tcp_ao_required(struct sock *sk, const void *saddr,
int family) int family, bool stat_inc)
{ {
#ifdef CONFIG_TCP_AO #ifdef CONFIG_TCP_AO
struct tcp_ao_info *ao_info; struct tcp_ao_info *ao_info;
...@@ -2724,8 +2724,13 @@ static inline bool tcp_ao_required(struct sock *sk, const void *saddr, ...@@ -2724,8 +2724,13 @@ static inline bool tcp_ao_required(struct sock *sk, const void *saddr,
return false; return false;
ao_key = tcp_ao_do_lookup(sk, saddr, family, -1, -1); 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; return true;
}
#endif #endif
return false; return false;
} }
...@@ -2747,8 +2752,10 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req, ...@@ -2747,8 +2752,10 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req,
return SKB_DROP_REASON_TCP_AUTH_HDR; return SKB_DROP_REASON_TCP_AUTH_HDR;
if (req) { 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; return SKB_DROP_REASON_TCP_AOFAILURE;
}
} }
/* sdif set, means packet ingressed via a device /* sdif set, means packet ingressed via a device
...@@ -2763,7 +2770,7 @@ tcp_inbound_hash(struct sock *sk, const struct request_sock *req, ...@@ -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 * the last key is impossible to remove, so there's
* always at least one current_key. * 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; return SKB_DROP_REASON_TCP_AONOTFOUND;
if (unlikely(tcp_md5_do_lookup(sk, l3index, saddr, family))) { if (unlikely(tcp_md5_do_lookup(sk, l3index, saddr, family))) {
NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND); NET_INC_STATS(sock_net(sk), LINUX_MIB_TCPMD5NOTFOUND);
......
...@@ -19,6 +19,13 @@ struct tcp_ao_hdr { ...@@ -19,6 +19,13 @@ struct tcp_ao_hdr {
u8 rnext_keyid; 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 tcp_ao_key {
struct hlist_node node; struct hlist_node node;
union tcp_ao_addr addr; union tcp_ao_addr addr;
...@@ -33,6 +40,8 @@ struct tcp_ao_key { ...@@ -33,6 +40,8 @@ struct tcp_ao_key {
u8 rcvid; u8 rcvid;
u8 maclen; u8 maclen;
struct rcu_head rcu; struct rcu_head rcu;
atomic64_t pkt_good;
atomic64_t pkt_bad;
u8 traffic_keys[]; u8 traffic_keys[];
}; };
...@@ -81,6 +90,7 @@ struct tcp_ao_info { ...@@ -81,6 +90,7 @@ struct tcp_ao_info {
*/ */
struct tcp_ao_key *current_key; struct tcp_ao_key *current_key;
struct tcp_ao_key *rnext_key; struct tcp_ao_key *rnext_key;
struct tcp_ao_counters counters;
u32 ao_required :1, u32 ao_required :1,
__unused :31; __unused :31;
__be32 lisn; __be32 lisn;
......
...@@ -297,6 +297,10 @@ enum ...@@ -297,6 +297,10 @@ enum
LINUX_MIB_TCPMIGRATEREQSUCCESS, /* TCPMigrateReqSuccess */ LINUX_MIB_TCPMIGRATEREQSUCCESS, /* TCPMigrateReqSuccess */
LINUX_MIB_TCPMIGRATEREQFAILURE, /* TCPMigrateReqFailure */ LINUX_MIB_TCPMIGRATEREQFAILURE, /* TCPMigrateReqFailure */
LINUX_MIB_TCPPLBREHASH, /* TCPPLBRehash */ LINUX_MIB_TCPPLBREHASH, /* TCPPLBRehash */
LINUX_MIB_TCPAOREQUIRED, /* TCPAORequired */
LINUX_MIB_TCPAOBAD, /* TCPAOBad */
LINUX_MIB_TCPAOKEYNOTFOUND, /* TCPAOKeyNotFound */
LINUX_MIB_TCPAOGOOD, /* TCPAOGood */
__LINUX_MIB_MAX __LINUX_MIB_MAX
}; };
......
...@@ -404,9 +404,15 @@ struct tcp_ao_info_opt { /* setsockopt(TCP_AO_INFO) */ ...@@ -404,9 +404,15 @@ struct tcp_ao_info_opt { /* setsockopt(TCP_AO_INFO) */
__u32 set_current :1, /* corresponding ::current_key */ __u32 set_current :1, /* corresponding ::current_key */
set_rnext :1, /* corresponding ::rnext */ set_rnext :1, /* corresponding ::rnext */
ao_required :1, /* don't accept non-AO connects */ 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 current_key; /* KeyID to set as Current_key */
__u8 rnext; /* KeyID to set as Rnext_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))); } __attribute__((aligned(8)));
/* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */ /* setsockopt(fd, IPPROTO_TCP, TCP_ZEROCOPY_RECEIVE, ...) */
......
...@@ -299,6 +299,10 @@ static const struct snmp_mib snmp4_net_list[] = { ...@@ -299,6 +299,10 @@ static const struct snmp_mib snmp4_net_list[] = {
SNMP_MIB_ITEM("TCPMigrateReqSuccess", LINUX_MIB_TCPMIGRATEREQSUCCESS), SNMP_MIB_ITEM("TCPMigrateReqSuccess", LINUX_MIB_TCPMIGRATEREQSUCCESS),
SNMP_MIB_ITEM("TCPMigrateReqFailure", LINUX_MIB_TCPMIGRATEREQFAILURE), SNMP_MIB_ITEM("TCPMigrateReqFailure", LINUX_MIB_TCPMIGRATEREQFAILURE),
SNMP_MIB_ITEM("TCPPLBRehash", LINUX_MIB_TCPPLBREHASH), 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 SNMP_MIB_SENTINEL
}; };
......
...@@ -182,6 +182,8 @@ static struct tcp_ao_key *tcp_ao_copy_key(struct sock *sk, ...@@ -182,6 +182,8 @@ static struct tcp_ao_key *tcp_ao_copy_key(struct sock *sk,
*new_key = *key; *new_key = *key;
INIT_HLIST_NODE(&new_key->node); INIT_HLIST_NODE(&new_key->node);
tcp_sigpool_get(new_key->tcp_sigpool_id); 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; return new_key;
} }
...@@ -771,8 +773,12 @@ tcp_ao_verify_hash(const struct sock *sk, const struct sk_buff *skb, ...@@ -771,8 +773,12 @@ tcp_ao_verify_hash(const struct sock *sk, const struct sk_buff *skb,
const struct tcphdr *th = tcp_hdr(skb); const struct tcphdr *th = tcp_hdr(skb);
void *hash_buf = NULL; 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; return SKB_DROP_REASON_TCP_AOFAILURE;
}
hash_buf = kmalloc(tcp_ao_digest_size(key), GFP_ATOMIC); hash_buf = kmalloc(tcp_ao_digest_size(key), GFP_ATOMIC);
if (!hash_buf) if (!hash_buf)
...@@ -782,9 +788,15 @@ tcp_ao_verify_hash(const struct sock *sk, const struct sk_buff *skb, ...@@ -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, tcp_ao_hash_skb(family, hash_buf, key, sk, skb, traffic_key,
(phash - (u8 *)th), sne); (phash - (u8 *)th), sne);
if (memcmp(phash, hash_buf, maclen)) { 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); kfree(hash_buf);
return SKB_DROP_REASON_TCP_AOFAILURE; 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); kfree(hash_buf);
return SKB_NOT_DROPPED_YET; return SKB_NOT_DROPPED_YET;
} }
...@@ -804,8 +816,10 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb, ...@@ -804,8 +816,10 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb,
u32 sne = 0; u32 sne = 0;
info = rcu_dereference(tcp_sk(sk)->ao_info); 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; return SKB_DROP_REASON_TCP_AOUNEXPECTED;
}
if (unlikely(th->syn)) { if (unlikely(th->syn)) {
sisn = th->seq; sisn = th->seq;
...@@ -900,6 +914,8 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb, ...@@ -900,6 +914,8 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb,
return ret; return ret;
key_not_found: 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; return SKB_DROP_REASON_TCP_AOKEYNOTFOUND;
} }
...@@ -1483,6 +1499,8 @@ static int tcp_ao_add_cmd(struct sock *sk, unsigned short int family, ...@@ -1483,6 +1499,8 @@ static int tcp_ao_add_cmd(struct sock *sk, unsigned short int family,
key->keyflags = cmd.keyflags; key->keyflags = cmd.keyflags;
key->sndid = cmd.sndid; key->sndid = cmd.sndid;
key->rcvid = cmd.rcvid; key->rcvid = cmd.rcvid;
atomic64_set(&key->pkt_good, 0);
atomic64_set(&key->pkt_bad, 0);
ret = tcp_ao_parse_crypto(&cmd, key); ret = tcp_ao_parse_crypto(&cmd, key);
if (ret < 0) if (ret < 0)
...@@ -1699,7 +1717,7 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family, ...@@ -1699,7 +1717,7 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family,
return -EINVAL; return -EINVAL;
} }
if (cmd.reserved != 0) if (cmd.reserved != 0 || cmd.reserved2 != 0)
return -EINVAL; return -EINVAL;
ao_info = setsockopt_ao_info(sk); ao_info = setsockopt_ao_info(sk);
...@@ -1734,6 +1752,12 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family, ...@@ -1734,6 +1752,12 @@ static int tcp_ao_info_cmd(struct sock *sk, unsigned short int family,
goto out; 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; ao_info->ao_required = cmd.ao_required;
if (new_current) if (new_current)
......
...@@ -1531,7 +1531,7 @@ static int tcp_v4_parse_md5_keys(struct sock *sk, int optname, ...@@ -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. /* Don't allow keys for peers that have a matching TCP-AO key.
* See the comment in tcp_ao_add_cmd() * 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 -EKEYREJECTED;
return tcp_md5_do_add(sk, addr, AF_INET, prefixlen, l3index, flags, return tcp_md5_do_add(sk, addr, AF_INET, prefixlen, l3index, flags,
......
...@@ -661,7 +661,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname, ...@@ -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. /* Don't allow keys for peers that have a matching TCP-AO key.
* See the comment in tcp_ao_add_cmd() * 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 -EKEYREJECTED;
return tcp_md5_do_add(sk, addr, return tcp_md5_do_add(sk, addr,
AF_INET, prefixlen, l3index, flags, AF_INET, prefixlen, l3index, flags,
...@@ -673,7 +673,7 @@ static int tcp_v6_parse_md5_keys(struct sock *sk, int optname, ...@@ -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. /* Don't allow keys for peers that have a matching TCP-AO key.
* See the comment in tcp_ao_add_cmd() * 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 -EKEYREJECTED;
return tcp_md5_do_add(sk, addr, AF_INET6, prefixlen, l3index, flags, return tcp_md5_do_add(sk, addr, AF_INET6, prefixlen, l3index, flags,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment