[ovs-dev] [patch v2 3/3] conntrack: Support global invalid packet stats.
Darrell Ball
dlu998 at gmail.com
Thu Jun 28 06:02:18 UTC 2018
Signed-off-by: Darrell Ball <dlu998 at gmail.com>
---
NEWS | 2 +
lib/conntrack.c | 114 +++++++++++++++++++++++++++++++++++++++++++++++++---
lib/conntrack.h | 13 ++++++
lib/ct-dpif.c | 24 +++++++++++
lib/ct-dpif.h | 13 ++++++
lib/dpctl.c | 62 ++++++++++++++++++++++++++++
lib/dpctl.man | 3 +-
lib/dpif-netdev.c | 26 ++++++++++++
lib/dpif-netlink.c | 1 +
lib/dpif-provider.h | 5 +++
10 files changed, 257 insertions(+), 6 deletions(-)
diff --git a/NEWS b/NEWS
index cd15a33..f39825d 100644
--- a/NEWS
+++ b/NEWS
@@ -40,6 +40,8 @@ Post-v2.9.0
ovs-appctl dpif-netdev/pmd-perf-show
* Supervision of PMD performance metrics and logging of suspicious
iterations
+ * ovs-appctl dpctl/ct-stats-show now prints conntrack global invalid
+ packet statistics.
- ERSPAN:
* Implemented ERSPAN protocol (draft-foschiano-erspan-00.txt) for
both kernel datapath and userspace datapath.
diff --git a/lib/conntrack.c b/lib/conntrack.c
index 825f1ad..997b243 100644
--- a/lib/conntrack.c
+++ b/lib/conntrack.c
@@ -228,6 +228,25 @@ long long ct_timeout_val[] = {
* are accepted; this is for CT_CONN_TYPE_DEFAULT connections. */
#define DEFAULT_N_CONN_LIMIT 3000000
+/* IPv4 sanity invalid packets. */
+static atomic_count min_hdr_err_v4;
+static atomic_count size_err_v4;
+static atomic_count cksum_err_v4;
+
+/* IPv6 sanity invalid packets. */
+static atomic_count min_hdr_err_v6;
+static atomic_count hdr_parse_err_v6;
+
+/* L4 sanity invalid packets. */
+static atomic_count hdr_size_err_tcp;
+static atomic_count size_err_tcp;
+static atomic_count cksum_err_tcp;
+static atomic_count hdr_size_err_udp;
+static atomic_count size_err_udp;
+static atomic_count cksum_err_udp;
+static atomic_count cksum_err_icmp;
+static atomic_count cksum_err_icmp6;
+
/* Does a member by member comparison of two conn_keys; this
* function must be kept in sync with struct conn_key; returns 0
* if the keys are equal or 1 if the keys are not equal. */
@@ -339,6 +358,20 @@ conntrack_init(struct conntrack *ct)
ct->hash_basis = random_uint32();
atomic_count_init(&ct->n_conn, 0);
atomic_init(&ct->n_conn_limit, DEFAULT_N_CONN_LIMIT);
+ atomic_count_init(&min_hdr_err_v4, 0);
+ atomic_count_init(&size_err_v4, 0);
+ atomic_count_init(&cksum_err_v4, 0);
+ atomic_count_init(&min_hdr_err_v6, 0);
+ atomic_count_init(&hdr_parse_err_v6, 0);
+ atomic_count_init(&hdr_size_err_tcp, 0);
+ atomic_count_init(&size_err_tcp, 0);
+ atomic_count_init(&cksum_err_tcp, 0);
+ atomic_count_init(&hdr_size_err_udp, 0);
+ atomic_count_init(&size_err_udp, 0);
+ atomic_count_init(&cksum_err_udp, 0);
+ atomic_count_init(&cksum_err_icmp, 0);
+ atomic_count_init(&cksum_err_icmp6, 0);
+
latch_init(&ct->clean_thread_exit);
ct->clean_thread = ovs_thread_create("ct_clean", clean_thread_main, ct);
}
@@ -1502,6 +1535,7 @@ extract_l3_ipv4(const void *data, size_t size, bool validate_checksum,
struct conn_key *key, const char **new_data)
{
if (OVS_UNLIKELY(size < IP_HEADER_LEN)) {
+ atomic_count_inc(&min_hdr_err_v4);
return false;
}
@@ -1509,14 +1543,17 @@ extract_l3_ipv4(const void *data, size_t size, bool validate_checksum,
size_t ip_len = IP_IHL(ip->ip_ihl_ver) * 4;
if (OVS_UNLIKELY(ip_len < IP_HEADER_LEN)) {
+ atomic_count_inc(&min_hdr_err_v4);
return false;
}
if (OVS_UNLIKELY(size < ip_len)) {
+ atomic_count_inc(&size_err_v4);
return false;
}
if (OVS_UNLIKELY(validate_checksum && csum(data, ip_len) != 0)) {
+ atomic_count_inc(&cksum_err_v4);
return false;
}
@@ -1542,6 +1579,7 @@ extract_l3_ipv6(const void *data, size_t size, struct conn_key *key,
const struct ovs_16aligned_ip6_hdr *ip6 = data;
if (OVS_UNLIKELY(size < sizeof *ip6)) {
+ atomic_count_inc(&min_hdr_err_v6);
return false;
}
@@ -1552,6 +1590,7 @@ extract_l3_ipv6(const void *data, size_t size, struct conn_key *key,
if (OVS_UNLIKELY(!parse_ipv6_ext_hdrs(&data, &size, &nw_proto,
&nw_frag))) {
+ atomic_count_inc(&hdr_parse_err_v6);
return false;
}
@@ -1595,15 +1634,24 @@ check_l4_tcp(const struct conn_key *key, const void *data, size_t size,
{
const struct tcp_header *tcp = data;
if (size < sizeof *tcp) {
+ atomic_count_inc(&hdr_size_err_tcp);
return false;
}
size_t tcp_len = TCP_OFFSET(tcp->tcp_ctl) * 4;
if (OVS_UNLIKELY(tcp_len < TCP_HEADER_LEN || tcp_len > size)) {
+ atomic_count_inc(&size_err_tcp);
return false;
}
- return validate_checksum ? checksum_valid(key, data, size, l3) : true;
+ if (!validate_checksum) {
+ return true;
+ } else if (checksum_valid(key, data, size, l3)) {
+ return true;
+ } else {
+ atomic_count_inc(&cksum_err_tcp);
+ return false;
+ }
}
static inline bool
@@ -1612,30 +1660,53 @@ check_l4_udp(const struct conn_key *key, const void *data, size_t size,
{
const struct udp_header *udp = data;
if (size < sizeof *udp) {
+ atomic_count_inc(&hdr_size_err_udp);
return false;
}
size_t udp_len = ntohs(udp->udp_len);
if (OVS_UNLIKELY(udp_len < UDP_HEADER_LEN || udp_len > size)) {
+ atomic_count_inc(&size_err_udp);
return false;
}
/* Validation must be skipped if checksum is 0 on IPv4 packets */
- return (udp->udp_csum == 0 && key->dl_type == htons(ETH_TYPE_IP))
- || (validate_checksum ? checksum_valid(key, data, size, l3) : true);
+ if (!validate_checksum ||
+ (udp->udp_csum == 0 && key->dl_type == htons(ETH_TYPE_IP))) {
+ return true;
+ } else if (checksum_valid(key, data, size, l3)) {
+ return true;
+ } else {
+ atomic_count_inc(&cksum_err_udp);
+ return false;
+ }
}
static inline bool
check_l4_icmp(const void *data, size_t size, bool validate_checksum)
{
- return validate_checksum ? csum(data, size) == 0 : true;
+ if (!validate_checksum) {
+ return true;
+ } else if (csum(data, size) == 0) {
+ return true;
+ } else {
+ atomic_count_inc(&cksum_err_icmp);
+ return false;
+ }
}
static inline bool
check_l4_icmp6(const struct conn_key *key, const void *data, size_t size,
const void *l3, bool validate_checksum)
{
- return validate_checksum ? checksum_valid(key, data, size, l3) : true;
+ if (!validate_checksum) {
+ return true;
+ } else if (checksum_valid(key, data, size, l3)) {
+ return true;
+ } else {
+ atomic_count_inc(&cksum_err_icmp6);
+ return false;
+ }
}
static inline bool
@@ -1946,6 +2017,7 @@ conn_key_extract(struct conntrack *ct, struct dp_packet *pkt, ovs_be16 dl_type,
bool hwol_bad_l3_csum = dp_packet_ip_checksum_bad(pkt);
if (hwol_bad_l3_csum) {
ok = false;
+ atomic_count_inc(&cksum_err_v4);
} else {
bool hwol_good_l3_csum = dp_packet_ip_checksum_valid(pkt);
/* Validate the checksum only when hwol is not supported. */
@@ -2594,6 +2666,38 @@ conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns)
return 0;
}
+int
+conntrack_get_invl_stats(unsigned int *ct_min_hdr_err_v4,
+ unsigned int *ct_size_err_v4,
+ unsigned int *ct_cksum_err_v4,
+ unsigned int *ct_min_hdr_err_v6,
+ unsigned int *ct_hdr_parse_err_v6,
+ unsigned int *ct_hdr_size_err_tcp,
+ unsigned int *ct_size_err_tcp,
+ unsigned int *ct_cksum_err_tcp,
+ unsigned int *ct_hdr_size_err_udp,
+ unsigned int *ct_size_err_udp,
+ unsigned int *ct_cksum_err_udp,
+ unsigned int *ct_cksum_err_icmp,
+ unsigned int *ct_cksum_err_icmp6)
+{
+ *ct_min_hdr_err_v4 = atomic_count_get(&min_hdr_err_v4);
+ *ct_size_err_v4 = atomic_count_get(&size_err_v4);
+ *ct_cksum_err_v4 = atomic_count_get(&cksum_err_v4);
+ *ct_min_hdr_err_v6 = atomic_count_get(&min_hdr_err_v6);
+ *ct_hdr_parse_err_v6 = atomic_count_get(&hdr_parse_err_v6);
+ *ct_hdr_size_err_tcp = atomic_count_get(&hdr_size_err_tcp);
+ *ct_size_err_tcp = atomic_count_get(&size_err_tcp);
+ *ct_cksum_err_tcp = atomic_count_get(&cksum_err_tcp);
+ *ct_hdr_size_err_udp = atomic_count_get(&hdr_size_err_udp);
+ *ct_size_err_udp = atomic_count_get(&size_err_udp);
+ *ct_cksum_err_udp = atomic_count_get(&cksum_err_udp);
+ *ct_cksum_err_icmp = atomic_count_get(&cksum_err_icmp);
+ *ct_cksum_err_icmp6 = atomic_count_get(&cksum_err_icmp6);
+
+ return 0;
+}
+
/* This function must be called with the ct->resources read lock taken. */
static struct alg_exp_node *
expectation_lookup(struct hmap *alg_expectations, const struct conn_key *key,
diff --git a/lib/conntrack.h b/lib/conntrack.h
index e3a5dcc..b1d477a 100644
--- a/lib/conntrack.h
+++ b/lib/conntrack.h
@@ -122,6 +122,19 @@ int conntrack_flush_tuple(struct conntrack *, const struct ct_dpif_tuple *,
int conntrack_set_maxconns(struct conntrack *ct, uint32_t maxconns);
int conntrack_get_maxconns(struct conntrack *ct, uint32_t *maxconns);
int conntrack_get_nconns(struct conntrack *ct, uint32_t *nconns);
+int conntrack_get_invl_stats(unsigned int *ct_min_hdr_err_v4,
+ unsigned int *ct_size_err_v4,
+ unsigned int *ct_cksum_err_v4,
+ unsigned int *ct_min_hdr_err_v6,
+ unsigned int *ct_hdr_parse_err_v6,
+ unsigned int *ct_hdr_size_err_tcp,
+ unsigned int *ct_size_err_tcp,
+ unsigned int *ct_cksum_err_tcp,
+ unsigned int *ct_hdr_size_err_udp,
+ unsigned int *ct_size_err_udp,
+ unsigned int *ct_cksum_err_udp,
+ unsigned int *ct_cksum_err_icmp,
+ unsigned int *ct_cksum_err_icmp6);
/* 'struct ct_lock' is a wrapper for an adaptive mutex. It's useful to try
* different types of locks (e.g. spinlocks) */
diff --git a/lib/ct-dpif.c b/lib/ct-dpif.c
index 5fa3a97..19224a4 100644
--- a/lib/ct-dpif.c
+++ b/lib/ct-dpif.c
@@ -164,6 +164,30 @@ ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns)
: EOPNOTSUPP);
}
+int
+ct_dpif_get_invl_stats(struct dpif *dpif, unsigned int *min_hdr_err_v4,
+ unsigned int *size_err_v4,
+ unsigned int *cksum_err_v4,
+ unsigned int *min_hdr_err_v6,
+ unsigned int *hdr_parse_err_v6,
+ unsigned int *hdr_size_err_tcp,
+ unsigned int *size_err_tcp,
+ unsigned int *cksum_err_tcp,
+ unsigned int *hdr_size_err_udp,
+ unsigned int *size_err_udp,
+ unsigned int *cksum_err_udp,
+ unsigned int *cksum_err_icmp,
+ unsigned int *cksum_err_icmp6)
+{
+ return (dpif->dpif_class->ct_get_invl_stats
+ ? dpif->dpif_class->ct_get_invl_stats(dpif, min_hdr_err_v4,
+ size_err_v4, cksum_err_v4, min_hdr_err_v6,
+ hdr_parse_err_v6, hdr_size_err_tcp, size_err_tcp,
+ cksum_err_tcp, hdr_size_err_udp, size_err_udp,
+ cksum_err_udp, cksum_err_icmp, cksum_err_icmp6)
+ : EOPNOTSUPP);
+}
+
void
ct_dpif_entry_uninit(struct ct_dpif_entry *entry)
{
diff --git a/lib/ct-dpif.h b/lib/ct-dpif.h
index 09e7698..ffa4b4e 100644
--- a/lib/ct-dpif.h
+++ b/lib/ct-dpif.h
@@ -200,6 +200,19 @@ int ct_dpif_flush(struct dpif *, const uint16_t *zone,
int ct_dpif_set_maxconns(struct dpif *dpif, uint32_t maxconns);
int ct_dpif_get_maxconns(struct dpif *dpif, uint32_t *maxconns);
int ct_dpif_get_nconns(struct dpif *dpif, uint32_t *nconns);
+int ct_dpif_get_invl_stats(struct dpif *dpif, unsigned int *min_hdr_err_v4,
+ unsigned int *size_err_v4,
+ unsigned int *cksum_err_v4,
+ unsigned int *min_hdr_err_v6,
+ unsigned int *hdr_parse_err_v6,
+ unsigned int *hdr_size_err_tcp,
+ unsigned int *size_err_tcp,
+ unsigned int *cksum_err_tcp,
+ unsigned int *hdr_size_err_udp,
+ unsigned int *size_err_udp,
+ unsigned int *cksum_err_udp,
+ unsigned int *cksum_err_icmp,
+ unsigned int *cksum_err_icmp6);
void ct_dpif_entry_uninit(struct ct_dpif_entry *);
void ct_dpif_format_entry(const struct ct_dpif_entry *, struct ds *,
bool verbose, bool print_stats);
diff --git a/lib/dpctl.c b/lib/dpctl.c
index 4f1e443..9be1ab0 100644
--- a/lib/dpctl.c
+++ b/lib/dpctl.c
@@ -1381,6 +1381,67 @@ error:
return error;
}
+static void
+ct_print_invalid_stats(struct dpctl_params *dpctl_p, struct dpif *dpif)
+{
+ if (dpif) {
+ unsigned int min_hdr_err_v4;
+ unsigned int size_err_v4;
+ unsigned int cksum_err_v4;
+ unsigned int min_hdr_err_v6;
+ unsigned int hdr_parse_err_v6;
+ unsigned int hdr_size_err_tcp;
+ unsigned int size_err_tcp;
+ unsigned int cksum_err_tcp;
+ unsigned int hdr_size_err_udp;
+ unsigned int size_err_udp;
+ unsigned int cksum_err_udp;
+ unsigned int cksum_err_icmp;
+ unsigned int cksum_err_icmp6;
+ int error = ct_dpif_get_invl_stats(dpif, &min_hdr_err_v4, &size_err_v4,
+ &cksum_err_v4, &min_hdr_err_v6,
+ &hdr_parse_err_v6,
+ &hdr_size_err_tcp, &size_err_tcp,
+ &cksum_err_tcp,
+ &hdr_size_err_udp, &size_err_udp,
+ &cksum_err_udp, &cksum_err_icmp,
+ &cksum_err_icmp6);
+
+ if (!error) {
+ dpctl_print(dpctl_p, "\nConnTracker Invalid Packet Stats:\n");
+ dpctl_print(dpctl_p, "v4 minimum header errors: %u\n",
+ min_hdr_err_v4);
+ dpctl_print(dpctl_p, "v4 packet size errors: %u\n",
+ size_err_v4);
+ dpctl_print(dpctl_p, "v4 checksum errors: %u\n",
+ cksum_err_v4);
+ dpctl_print(dpctl_p, "v6 minimum header errors: %u\n",
+ min_hdr_err_v6);
+ dpctl_print(dpctl_p, "v6 parse errors: %u\n",
+ hdr_parse_err_v6);
+ dpctl_print(dpctl_p, "tcp header size errors: %u\n",
+ cksum_err_tcp);
+ dpctl_print(dpctl_p, "tcp size errors: %u\n",
+ cksum_err_tcp);
+ dpctl_print(dpctl_p, "tcp checksum errors: %u\n",
+ cksum_err_tcp);
+ dpctl_print(dpctl_p, "udp header size errors: %u\n",
+ cksum_err_tcp);
+ dpctl_print(dpctl_p, "udp size errors: %u\n",
+ cksum_err_tcp);
+ dpctl_print(dpctl_p, "udp checksum errors: %u\n",
+ cksum_err_udp);
+ dpctl_print(dpctl_p, "icmp checksum errors: %u\n",
+ cksum_err_icmp);
+ dpctl_print(dpctl_p, "icmp6 checksum errors: %u\n",
+ cksum_err_icmp6);
+ } else {
+ dpctl_error(dpctl_p, error,
+ "ct drop stats could not be retrieved");
+ }
+ }
+}
+
static int
dpctl_ct_stats_show(int argc, const char *argv[],
struct dpctl_params *dpctl_p)
@@ -1514,6 +1575,7 @@ dpctl_ct_stats_show(int argc, const char *argv[],
}
ct_dpif_dump_done(dump);
+ ct_print_invalid_stats(dpctl_p, dpif);
dpif_close(dpif);
return error;
}
diff --git a/lib/dpctl.man b/lib/dpctl.man
index 5d987e6..4f62397 100644
--- a/lib/dpctl.man
+++ b/lib/dpctl.man
@@ -244,7 +244,8 @@ An example of an IPv6 TCP \fIct-tuple\fR:
Displays the number of connections grouped by protocol used by \fIdp\fR.
If \fBzone=\fIzone\fR is specified, numbers refer to the connections in
\fIzone\fR. With \fB\-\-more\fR, groups by connection state for each
-protocol.
+protocol. Prints global invalid packet stats for the userspace connection
+tracker; typically, a rule is in place to drop invalid flagged packets.
.
.TP
\*(DX\fBct\-bkts\fR [\fIdp\fR] [\fBgt=\fIthreshold\fR]
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 9390fff..b3c67a9 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -6044,6 +6044,31 @@ dpif_netdev_ct_get_nconns(struct dpif *dpif, uint32_t *nconns)
return conntrack_get_nconns(&dp->conntrack, nconns);
}
+static int
+dpif_netdev_ct_get_invl_stats(struct dpif *dpif OVS_UNUSED,
+ unsigned int *ct_min_hdr_err_v4,
+ unsigned int *ct_size_err_v4,
+ unsigned int *ct_cksum_err_v4,
+ unsigned int *ct_min_hdr_err_v6,
+ unsigned int *ct_hdr_parse_err_v6,
+ unsigned int *ct_hdr_size_err_tcp,
+ unsigned int *ct_size_err_tcp,
+ unsigned int *ct_cksum_err_tcp,
+ unsigned int *ct_hdr_size_err_udp,
+ unsigned int *ct_size_err_udp,
+ unsigned int *ct_cksum_err_udp,
+ unsigned int *ct_cksum_err_icmp,
+ unsigned int *ct_cksum_err_icmp6)
+{
+ return conntrack_get_invl_stats(ct_min_hdr_err_v4, ct_size_err_v4,
+ ct_cksum_err_v4, ct_min_hdr_err_v6,
+ ct_hdr_parse_err_v6, ct_hdr_size_err_tcp,
+ ct_size_err_tcp, ct_cksum_err_tcp,
+ ct_hdr_size_err_udp, ct_size_err_udp,
+ ct_cksum_err_udp, ct_cksum_err_icmp,
+ ct_cksum_err_icmp6);
+}
+
const struct dpif_class dpif_netdev_class = {
"netdev",
dpif_netdev_init,
@@ -6092,6 +6117,7 @@ const struct dpif_class dpif_netdev_class = {
dpif_netdev_ct_set_maxconns,
dpif_netdev_ct_get_maxconns,
dpif_netdev_ct_get_nconns,
+ dpif_netdev_ct_get_invl_stats,
dpif_netdev_meter_get_features,
dpif_netdev_meter_set,
dpif_netdev_meter_get,
diff --git a/lib/dpif-netlink.c b/lib/dpif-netlink.c
index aa9bbd9..6d07d15 100644
--- a/lib/dpif-netlink.c
+++ b/lib/dpif-netlink.c
@@ -3006,6 +3006,7 @@ const struct dpif_class dpif_netlink_class = {
NULL, /* ct_set_maxconns */
NULL, /* ct_get_maxconns */
NULL, /* ct_get_nconns */
+ NULL, /* ct_get_invl_stats */
dpif_netlink_meter_get_features,
dpif_netlink_meter_set,
dpif_netlink_meter_get,
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 62b3598..21a8625 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -443,6 +443,11 @@ struct dpif_class {
int (*ct_get_maxconns)(struct dpif *, uint32_t *maxconns);
/* Get number of connections tracked. */
int (*ct_get_nconns)(struct dpif *, uint32_t *nconns);
+ int (*ct_get_invl_stats)(struct dpif *, unsigned int *,
+ unsigned int *, unsigned int *, unsigned int *,
+ unsigned int *, unsigned int *, unsigned int *,
+ unsigned int *, unsigned int *, unsigned int *,
+ unsigned int *, unsigned int *, unsigned int *);
/* Meters */
--
1.9.1
More information about the dev
mailing list