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 = {