mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2025-01-06 05:06:29 +00:00
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: 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>
This commit is contained in:
parent
0a3a809089
commit
af09a341dc
@ -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 (
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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, ...) */
|
||||
|
@ -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
|
||||
};
|
||||
|
||||
|
@ -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 @@ tcp_inbound_ao_hash(struct sock *sk, const struct sk_buff *skb,
|
||||
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)
|
||||
|
@ -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,
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user