From 56d2bbe173b41913cf4b701d812ce2d39a86612c Mon Sep 17 00:00:00 2001 From: Holger Eitzenberger Date: Fri, 30 Aug 2013 10:50:22 +0200 Subject: [PATCH] netfilter/ct: support optional CTA_TIMESTAMP attribute Recent kernels support conntrack time stamping, which is a helpful feature to determine the duration of a flow without building a flow cache in your user space application, just to keep the 'start' time of your flow. Timestamps are recorded with nanosecond resolution once this feature is enabled. This patch adds optional support for the CTA_TIMESTAMP, then modifies the dump routine to write that info in a format similar to /proc/net/nf_conntrack. This is an example output when using NL_DUMP_LINE: udp 10.128.128.28:56836 <-> 10.128.129.255:8612 delta-time 30 Signed-off-by: Holger Eitzenberger Signed-off-by: Thomas Graf --- include/netlink-private/netlink.h | 2 ++ include/netlink-private/types.h | 3 +++ include/netlink/netfilter/ct.h | 9 +++++++++ lib/netfilter/ct.c | 29 +++++++++++++++++++++++++++++ lib/netfilter/ct_obj.c | 29 +++++++++++++++++++++++++++++ 5 files changed, 72 insertions(+) diff --git a/include/netlink-private/netlink.h b/include/netlink-private/netlink.h index 2e511bf..2315e71 100644 --- a/include/netlink-private/netlink.h +++ b/include/netlink-private/netlink.h @@ -67,6 +67,8 @@ #include #include +#define NSEC_PER_SEC 1000000000L + struct trans_tbl { int i; const char *a; diff --git a/include/netlink-private/types.h b/include/netlink-private/types.h index 05a6a45..ab5eea4 100644 --- a/include/netlink-private/types.h +++ b/include/netlink-private/types.h @@ -19,6 +19,7 @@ #include #include #include +#include #include #define NL_SOCK_BUFSIZE_SET (1<<0) @@ -794,6 +795,8 @@ struct nfnl_ct { struct nfnl_ct_dir ct_orig; struct nfnl_ct_dir ct_repl; + + struct nfnl_ct_timestamp ct_tstamp; }; union nfnl_exp_protodata { diff --git a/include/netlink/netfilter/ct.h b/include/netlink/netfilter/ct.h index 57fbe53..776e3b3 100644 --- a/include/netlink/netfilter/ct.h +++ b/include/netlink/netfilter/ct.h @@ -25,6 +25,11 @@ extern "C" { struct nfnl_ct; +struct nfnl_ct_timestamp { + uint64_t start; + uint64_t stop; +}; + extern struct nl_object_ops ct_obj_ops; extern struct nfnl_ct * nfnl_ct_alloc(void); @@ -119,6 +124,10 @@ extern void nfnl_ct_set_bytes(struct nfnl_ct *, int, uint64_t); extern int nfnl_ct_test_bytes(const struct nfnl_ct *, int); extern uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *, int); +extern void nfnl_ct_set_timestamp(struct nfnl_ct *, uint64_t, uint64_t); +extern int nfnl_ct_test_timestamp(const struct nfnl_ct *); +extern const struct nfnl_ct_timestamp *nfnl_ct_get_timestamp(const struct nfnl_ct *); + #ifdef __cplusplus } #endif diff --git a/lib/netfilter/ct.c b/lib/netfilter/ct.c index 794932f..362cd28 100644 --- a/lib/netfilter/ct.c +++ b/lib/netfilter/ct.c @@ -102,6 +102,11 @@ static struct nla_policy ct_counters_policy[CTA_COUNTERS_MAX+1] = { [CTA_COUNTERS32_BYTES] = { .type = NLA_U32 }, }; +static struct nla_policy ct_timestamp_policy[CTA_TIMESTAMP_MAX + 1] = { + [CTA_TIMESTAMP_START] = { .type = NLA_U64 }, + [CTA_TIMESTAMP_STOP] = { .type = NLA_U64 }, +}; + static int ct_parse_ip(struct nfnl_ct *ct, int repl, struct nlattr *attr) { struct nlattr *tb[CTA_IP_MAX+1]; @@ -300,6 +305,24 @@ int nfnlmsg_ct_group(struct nlmsghdr *nlh) } } +static int ct_parse_timestamp(struct nfnl_ct *ct, struct nlattr *attr) +{ + struct nlattr *tb[CTA_TIMESTAMP_MAX + 1]; + int err; + + err = nla_parse_nested(tb, CTA_TIMESTAMP_MAX, attr, + ct_timestamp_policy); + if (err < 0) + return err; + + if (tb[CTA_TIMESTAMP_START] && tb[CTA_TIMESTAMP_STOP]) + nfnl_ct_set_timestamp(ct, + ntohll(nla_get_u64(tb[CTA_TIMESTAMP_START])), + ntohll(nla_get_u64(tb[CTA_TIMESTAMP_STOP]))); + + return 0; +} + int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result) { struct nfnl_ct *ct; @@ -359,6 +382,12 @@ int nfnlmsg_ct_parse(struct nlmsghdr *nlh, struct nfnl_ct **result) goto errout; } + if (tb[CTA_TIMESTAMP]) { + err = ct_parse_timestamp(ct, tb[CTA_TIMESTAMP]); + if (err < 0) + goto errout; + } + *result = ct; return 0; diff --git a/lib/netfilter/ct_obj.c b/lib/netfilter/ct_obj.c index bac775b..685879b 100644 --- a/lib/netfilter/ct_obj.c +++ b/lib/netfilter/ct_obj.c @@ -51,6 +51,7 @@ #define CT_ATTR_REPL_ICMP_CODE (1UL << 23) #define CT_ATTR_REPL_PACKETS (1UL << 24) #define CT_ATTR_REPL_BYTES (1UL << 25) +#define CT_ATTR_TIMESTAMP (1UL << 26) /** @endcond */ static void ct_free_data(struct nl_object *c) @@ -192,6 +193,17 @@ static void ct_dump_line(struct nl_object *a, struct nl_dump_params *p) if (nfnl_ct_test_mark(ct) && nfnl_ct_get_mark(ct)) nl_dump(p, "mark %u ", nfnl_ct_get_mark(ct)); + if (nfnl_ct_test_timestamp(ct)) { + const struct nfnl_ct_timestamp *tstamp = nfnl_ct_get_timestamp(ct); + int64_t delta_time = tstamp->stop - tstamp->start; + + if (delta_time > 0) + delta_time /= NSEC_PER_SEC; + else + delta_time = 0; + nl_dump(p, "delta-time %llu ", delta_time); + } + nl_dump(p, "\n"); } @@ -777,6 +789,23 @@ uint64_t nfnl_ct_get_bytes(const struct nfnl_ct *ct, int repl) return dir->bytes; } +void nfnl_ct_set_timestamp(struct nfnl_ct *ct, uint64_t start, uint64_t stop) +{ + ct->ct_tstamp.start = start; + ct->ct_tstamp.stop = stop; + ct->ce_mask |= CT_ATTR_TIMESTAMP; +} + +int nfnl_ct_test_timestamp(const struct nfnl_ct *ct) +{ + return !!(ct->ce_mask & CT_ATTR_TIMESTAMP); +} + +const struct nfnl_ct_timestamp *nfnl_ct_get_timestamp(const struct nfnl_ct *ct) +{ + return &ct->ct_tstamp; +} + /** @} */ struct nl_object_ops ct_obj_ops = { -- 2.40.0