Skip to contentSkip to conversation

ulogd2 updates for NFCT

PATCH New Pablo Neira Ayuso 1 participant 7 messages Jan 13, 2010 netfilter

lore
Share & tools
lore

Pablo Neira Ayuso

author maintainer
#0 lore raw

cover ulogd2 updates for NFCT

This patchset includes a set of updates for ulogd2's NFCT plugin. I'm posting them here since there are other involved in the ulogd2 development, to let them know.

If nobody complains, I'll push it in some days.

---

Pablo Neira Ayuso (6):
NFCT: cleanup constructor and destructor functions
NFCT: change `pollinterval' behaviour
NFCT: use new hashtable implementation for better performance
NFCT: split event handler if hashtable is used or not
NFCT: fix number of options (missing one)
NFCT: fix reset counters via SIGUSR2 signal

 include/ulogd/hash.h            |   34 +--
 input/flow/ulogd_inpflow_NFCT.c |  430 ++++++++++++++++++++++++++++++---------
 src/hash.c                      |  168 +++++----------
 ulogd.conf.in                   |    1 
 4 files changed, 402 insertions(+), 231 deletions(-)
author maintainer
#1 lore raw

PATCH 1/6 NFCT: cleanup constructor and destructor functions

This patch cleans up the destructor and the destructor functions in the NFCT plugin. I know, this patch isn't easy to review because it includes too many changes in one.

---
 input/flow/ulogd_inpflow_NFCT.c |   97 +++++++++++++++++++++++----------------
 1 files changed, 56 insertions(+), 41 deletions(-)
input/flow/ulogd_inpflow_NFCT.c +56 -41
index 8d6347f..9ef4eae 100644
@@ -3,7 +3,7 @@
  * ulogd input plugin for ctnetlink
  *
  * (C) 2005 by Harald Welte <[email protected]>
- * (C) 2008 by Pablo Neira Ayuso <[email protected]>
+ * (C) 2008-2010 by Pablo Neira Ayuso <[email protected]>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2
@@ -852,7 +852,7 @@ static int constructor_nfct(struct ulogd_pluginstance *upi)
 			     eventmask_ce(upi->config_kset).u.value);
 	if (!cpi->cth) {
 		ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
-		return -1;
+		goto err_cth;
 	}
 
 	nfct_callback_register(cpi->cth, NFCT_T_ALL, &event_handler, upi);
@@ -863,25 +863,6 @@ static int constructor_nfct(struct ulogd_pluginstance *upi)
 					"set to %d\n", cpi->nlbufsiz);
 	}
 
-	if (usehash_ce(upi->config_kset).u.value != 0) {
-		cpi->ovh = nfct_open(NFNL_SUBSYS_CTNETLINK, 0);
-		if (!cpi->ovh) {
-			ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
-			return -1;
-		}
-
-		nfct_callback_register(cpi->ovh, NFCT_T_ALL,
-				       &overrun_handler, upi);
-	}
-
-	cpi->pgh = nfct_open(NFNL_SUBSYS_CTNETLINK, 0);
-	if (!cpi->pgh) {
-		ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
-		return -1;
-	}
-
-	ulogd_init_timer(&cpi->ov_timer, upi, overrun_timeout);
-
 	cpi->nfct_fd.fd = nfct_fd(cpi->cth);
 	cpi->nfct_fd.cb = &read_cb_nfct;
 	cpi->nfct_fd.data = cpi;
@@ -890,13 +871,9 @@ static int constructor_nfct(struct ulogd_pluginstance *upi)
 	ulogd_register_fd(&cpi->nfct_fd);
 
 	if (usehash_ce(upi->config_kset).u.value != 0) {
-		cpi->nfct_ov.fd = nfct_fd(cpi->ovh);
-		cpi->nfct_ov.cb = &read_cb_ovh;
-		cpi->nfct_ov.data = cpi;
-		cpi->nfct_ov.when = ULOGD_FD_READ;
-
-		ulogd_register_fd(&cpi->nfct_ov);
+		int family = AF_UNSPEC;
 
+		/* we use a hashtable to cache entries in userspace. */
 		cpi->ct_active =
 		     hashtable_create(buckets_ce(upi->config_kset).u.value,
 				      maxentries_ce(upi->config_kset).u.value,
@@ -905,14 +882,52 @@ static int constructor_nfct(struct ulogd_pluginstance *upi)
 				      compare);
 		if (!cpi->ct_active) {
 			ulogd_log(ULOGD_FATAL, "error allocating hash\n");
-			nfct_close(cpi->cth);
-			nfct_close(cpi->ovh);
-			nfct_close(cpi->pgh);
-			return -1;
+			goto err_hashtable;
+		}
+
+		/* populate the hashtable. */
+		nfct_query(cpi->cth, NFCT_Q_DUMP, &family);
+
+		/* the overrun handler only make sense with the hashtable,
+		 * if we hit overrun, we resync with ther kernel table. */
+		cpi->ovh = nfct_open(NFNL_SUBSYS_CTNETLINK, 0);
+		if (!cpi->ovh) {
+			ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
+			goto err_ovh;
+		}
+
+		nfct_callback_register(cpi->ovh, NFCT_T_ALL,
+				       &overrun_handler, upi);
+
+		ulogd_init_timer(&cpi->ov_timer, upi, overrun_timeout);
+
+		cpi->nfct_ov.fd = nfct_fd(cpi->ovh);
+		cpi->nfct_ov.cb = &read_cb_ovh;
+		cpi->nfct_ov.data = cpi;
+		cpi->nfct_ov.when = ULOGD_FD_READ;
+
+		ulogd_register_fd(&cpi->nfct_ov);
+
+		/* we use this to purge old entries during overruns.*/
+		cpi->pgh = nfct_open(NFNL_SUBSYS_CTNETLINK, 0);
+		if (!cpi->pgh) {
+			ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
+			goto err_pgh;
 		}
 	}
 
 	return 0;
+
+err_pgh:
+	ulogd_unregister_fd(&cpi->nfct_ov);
+	nfct_close(cpi->ovh);
+err_ovh:
+	hashtable_destroy(cpi->ct_active);
+err_hashtable:
+	ulogd_unregister_fd(&cpi->nfct_fd);
+	nfct_close(cpi->cth);
+err_cth:
+	return -1;
 }
 
 static int destructor_nfct(struct ulogd_pluginstance *pi)
@@ -920,12 +935,7 @@ static int destructor_nfct(struct ulogd_pluginstance *pi)
 	struct nfct_pluginstance *cpi = (void *) pi->private;
 	int rc;
 
-	/* free existent entries */
-	hashtable_iterate(cpi->ct_active, NULL, do_free);
-
-	hashtable_destroy(cpi->ct_active);
-
-	ulogd_del_timer(&cpi->ov_timer);
+	ulogd_unregister_fd(&cpi->nfct_fd);
 
 	rc = nfct_close(cpi->cth);
 	if (rc < 0)
@@ -933,15 +943,20 @@ static int destructor_nfct(struct ulogd_pluginstance *pi)
 
 
 	if (usehash_ce(pi->config_kset).u.value != 0) {
+		ulogd_del_timer(&cpi->ov_timer);
+		ulogd_unregister_fd(&cpi->nfct_ov);
+
 		rc = nfct_close(cpi->ovh);
 		if (rc < 0)
 			return rc;
-	}
 
-	rc = nfct_close(cpi->pgh);
-	if (rc < 0)
-		return rc;
+		rc = nfct_close(cpi->pgh);
+		if (rc < 0)
+			return rc;
 
+		hashtable_iterate(cpi->ct_active, NULL, do_free);
+		hashtable_destroy(cpi->ct_active);
+	}
 	return 0;
 }
 
author maintainer
#2 lore raw

PATCH 2/6 NFCT: change `pollinterval' behaviour

In reply to Pablo Neira Ayuso

This patch adds support for poll-based logging. Basically, ulogd polls from the kernel periodically to log entries. You can use the `pollinterval' option in the configuration file to set the polling period.

This patch changes the current behaviour of `pollinterval' that allowed to mix both the event-driven logging with polling periodically from the kernel. I have tried to look for anyone in google (and asking Eric Leblond) using this feature but I found noone.

---
 input/flow/ulogd_inpflow_NFCT.c |  128 +++++++++++++++++++++++++++++++++++++--
 ulogd.conf.in                   |    1 
 2 files changed, 121 insertions(+), 8 deletions(-)
input/flow/ulogd_inpflow_NFCT.c +120 -8
index 9ef4eae..d76649e 100644
@@ -567,7 +567,6 @@ do_propagate_ct(struct ulogd_pluginstance *upi,
 	propagate_ct(upi, ct, type, ts);
 }
 
-/* XXX: pollinterval needs a different handler */
 static int event_handler(enum nf_conntrack_msg_type type,
 			 struct nf_conntrack *ct,
 			 void *data)
@@ -646,6 +645,40 @@ static int event_handler(enum nf_conntrack_msg_type type,
 	return NFCT_CB_CONTINUE;
 }
 
+static int
+polling_handler(enum nf_conntrack_msg_type type,
+		struct nf_conntrack *ct, void *data)
+{
+	struct ulogd_pluginstance *upi = data;
+	struct nfct_pluginstance *cpi =
+				(struct nfct_pluginstance *) upi->private;
+	struct ct_timestamp *ts = NULL;
+	struct ct_timestamp tmp = {
+		.ct = ct,
+	};
+
+	switch(type) {
+	case NFCT_T_UPDATE:
+		ts = hashtable_get(cpi->ct_active, &tmp);
+		if (ts)
+			nfct_copy(ts->ct, ct, NFCT_CP_META);
+		else {
+			ts = hashtable_add(cpi->ct_active, &tmp);
+			if (ts == NULL)
+				return NFCT_CB_CONTINUE;
+
+			gettimeofday(&ts->time[START], NULL);
+			return NFCT_CB_STOLEN;
+		}
+		break;
+	default:
+		ulogd_log(ULOGD_NOTICE, "unknown netlink message type\n");
+		break;
+	}
+
+	return NFCT_CB_CONTINUE;
+}
+
 static int setnlbufsiz(struct ulogd_pluginstance *upi, int size)
 {
 	struct nfct_pluginstance *cpi =
@@ -804,13 +837,15 @@ static int get_ctr_zero(struct ulogd_pluginstance *upi)
 	return nfct_query(cpi->cth, NFCT_Q_DUMP_RESET, &family);
 }
 
-static void getctr_timer_cb(struct ulogd_timer *t, void *data)
+static void polling_timer_cb(struct ulogd_timer *t, void *data)
 {
 	struct ulogd_pluginstance *upi = data;
 	struct nfct_pluginstance *cpi =
 			(struct nfct_pluginstance *)upi->private;
+	int family = AF_UNSPEC;
 
-	get_ctr_zero(upi);
+	nfct_query(cpi->pgh, NFCT_Q_DUMP, &family);
+	hashtable_iterate(cpi->ct_active, upi, do_purge);
 	ulogd_add_timer(&cpi->timer, pollint_ce(upi->config_kset).u.value);
 }
 
@@ -825,7 +860,7 @@ static int configure_nfct(struct ulogd_pluginstance *upi,
 	if (ret < 0)
 		return ret;
 
-	ulogd_init_timer(&cpi->timer, upi, getctr_timer_cb);
+	ulogd_init_timer(&cpi->timer, upi, polling_timer_cb);
 	if (pollint_ce(upi->config_kset).u.value != 0)
 		ulogd_add_timer(&cpi->timer,
 				pollint_ce(upi->config_kset).u.value);
@@ -843,7 +878,7 @@ static void overrun_timeout(struct ulogd_timer *a, void *data)
 	nfct_send(cpi->ovh, NFCT_Q_DUMP, &family);
 }
 
-static int constructor_nfct(struct ulogd_pluginstance *upi)
+static int constructor_nfct_events(struct ulogd_pluginstance *upi)
 {
 	struct nfct_pluginstance *cpi =
 			(struct nfct_pluginstance *)upi->private;
@@ -916,6 +951,7 @@ static int constructor_nfct(struct ulogd_pluginstance *upi)
 		}
 	}
 
+	ulogd_log(ULOGD_NOTICE, "NFCT plugin working in event mode\n");
 	return 0;
 
 err_pgh:
@@ -930,9 +966,61 @@ err_cth:
 	return -1;
 }
 
-static int destructor_nfct(struct ulogd_pluginstance *pi)
+static int constructor_nfct_polling(struct ulogd_pluginstance *upi)
 {
-	struct nfct_pluginstance *cpi = (void *) pi->private;
+	struct nfct_pluginstance *cpi =
+			(struct nfct_pluginstance *)upi->private;
+
+	if (usehash_ce(upi->config_kset).u.value == 0) {
+		ulogd_log(ULOGD_FATAL, "NFCT polling mode requires "
+				       "the hashtable\n");
+		goto err;
+	}
+
+	cpi->pgh = nfct_open(NFNL_SUBSYS_CTNETLINK, 0);
+	if (!cpi->pgh) {
+		ulogd_log(ULOGD_FATAL, "error opening ctnetlink\n");
+		goto err;
+	}
+	nfct_callback_register(cpi->pgh, NFCT_T_ALL, &polling_handler, upi);
+
+	cpi->ct_active =
+	     hashtable_create(buckets_ce(upi->config_kset).u.value,
+			      maxentries_ce(upi->config_kset).u.value,
+			      sizeof(struct ct_timestamp),
+			      hash,
+			      compare);
+	if (!cpi->ct_active) {
+		ulogd_log(ULOGD_FATAL, "error allocating hash\n");
+		goto err_hashtable;
+	}
+
+	ulogd_log(ULOGD_NOTICE, "NFCT working in polling mode\n");
+	return 0;
+
+err_hashtable:
+	nfct_close(cpi->pgh);
+err:
+	return -1;
+}
+
+static int constructor_nfct(struct ulogd_pluginstance *upi)
+{
+	if (pollint_ce(upi->config_kset).u.value == 0) {
+		/* listen to ctnetlink events. */
+		return constructor_nfct_events(upi);
+	} else {
+		/* poll from ctnetlink periodically. */
+		return constructor_nfct_polling(upi);
+	}
+	/* should not ever happen. */
+	ulogd_log(ULOGD_FATAL, "invalid NFCT configuration\n");
+	return -1;
+}
+
+static int destructor_nfct_events(struct ulogd_pluginstance *upi)
+{
+	struct nfct_pluginstance *cpi = (void *) upi->private;
 	int rc;
 
 	ulogd_unregister_fd(&cpi->nfct_fd);
@@ -942,7 +1030,7 @@ static int destructor_nfct(struct ulogd_pluginstance *pi)
 		return rc;
 
 
-	if (usehash_ce(pi->config_kset).u.value != 0) {
+	if (usehash_ce(upi->config_kset).u.value != 0) {
 		ulogd_del_timer(&cpi->ov_timer);
 		ulogd_unregister_fd(&cpi->nfct_ov);
 
@@ -960,6 +1048,30 @@ static int destructor_nfct(struct ulogd_pluginstance *pi)
 	return 0;
 }
 
+static int destructor_nfct_polling(struct ulogd_pluginstance *upi)
+{
+	int rc;
+	struct nfct_pluginstance *cpi = (void *)upi->private;
+
+	rc = nfct_close(cpi->pgh);
+	if (rc < 0)
+		return rc;
+
+	return 0;
+}
+
+static int destructor_nfct(struct ulogd_pluginstance *upi)
+{
+	if (pollint_ce(upi->config_kset).u.value == 0) {
+		return destructor_nfct_events(upi);
+	} else {
+		return destructor_nfct_polling(upi);
+	}
+	/* should not ever happen. */
+	ulogd_log(ULOGD_FATAL, "invalid NFCT configuration\n");
+	return -1;
+}
+
 static void signal_nfct(struct ulogd_pluginstance *pi, int signal)
 {
 	switch (signal) {
ulogd.conf.in +1 -0
index 4542fc4..b77d726 100644
@@ -92,6 +92,7 @@ plugin="@libdir@/ulogd/ulogd_raw2packet_BASE.so"
 #netlink_socket_buffer_size=217088
 #netlink_socket_buffer_maxsize=1085440
 #netlink_resync_timeout=60 # seconds to wait to perform resynchronization
+#pollinterval=10 # use poll-based logging instead of event-driven
 
 [ct2]
 #netlink_socket_buffer_size=217088
author maintainer
#3 lore raw

PATCH 3/6 NFCT: use new hashtable implementation for better performance

In reply to Pablo Neira Ayuso

This patch replaces the existing hashtable implementation with a newer that provide better performance since it reduces the number of hash computations.

---
 include/ulogd/hash.h            |   34 +++-----
 input/flow/ulogd_inpflow_NFCT.c |  119 ++++++++++++++++++----------
 src/hash.c                      |  168 +++++++++++++--------------------------
 3 files changed, 152 insertions(+), 169 deletions(-)
include/ulogd/hash.h +15 -19
index 45d2f48..d4aedb8 100644
@@ -2,8 +2,7 @@
 #define _NF_SET_HASH_H_
 
 #include <unistd.h>
-#include "slist.h"
-#include <ulogd/linuxlist.h>
+#include "linuxlist.h"
 
 #include <stdint.h>
 
@@ -15,34 +14,31 @@ struct hashtable {
 	uint32_t limit;
 	uint32_t count;
 	uint32_t initval;
-	uint32_t datasize;
+	
+	uint32_t (*hash)(const void *data, const struct hashtable *table);
+	int	 (*compare)(const void *data1, const void *data2);
 
-	uint32_t	(*hash)(const void *data, struct hashtable *table);
-	int		(*compare)(const void *data1, const void *data2);
-
-	struct slist_head 	members[0];
+	struct llist_head 	members[0];
 };
 
 struct hashtable_node {
-	struct slist_head head;
-	char data[0];
+	struct llist_head head;
 };
 
-struct hashtable_node *hashtable_alloc_node(int datasize, void *data);
-void hashtable_destroy_node(struct hashtable_node *h);
-
 struct hashtable *
-hashtable_create(int hashsize, int limit, int datasize,
-		 uint32_t (*hash)(const void *data, struct hashtable *table),
+hashtable_create(int hashsize, int limit,
+		 uint32_t (*hash)(const void *data,
+		 		  const struct hashtable *table),
 		 int (*compare)(const void *data1, const void *data2));
 void hashtable_destroy(struct hashtable *h);
-
-void *hashtable_add(struct hashtable *table, void *data);
-void *hashtable_get(struct hashtable *table, const void *data);
-int hashtable_del(struct hashtable *table, void *data);
+int hashtable_hash(const struct hashtable *table, const void *data);
+struct hashtable_node *hashtable_find(const struct hashtable *table, const void *data, int id);
+int hashtable_add(struct hashtable *table, struct hashtable_node *n, int id);
+void hashtable_del(struct hashtable *table, struct hashtable_node *node);
 int hashtable_flush(struct hashtable *table);
 int hashtable_iterate(struct hashtable *table, void *data,
-		      int (*iterate)(void *data1, void *data2));
+		      int (*iterate)(void *data, void *n));
+int hashtable_iterate_limit(struct hashtable *table, void *data, uint32_t from, uint32_t steps, int (*iterate)(void *data1, void *n));
 unsigned int hashtable_counter(const struct hashtable *table);
 
 #endif
input/flow/ulogd_inpflow_NFCT.c +79 -40

246 lines not on this page · raw message

src/hash.c +58 -110

237 lines not on this page · raw message

author maintainer
#4 lore raw

PATCH 4/6 NFCT: split event handler if hashtable is used or not

In reply to Pablo Neira Ayuso

This patch splits event_handler into two functions:
event_handler_hashtable and event_handler_no_hashtable. Thus, we register the appropriate handler during the initialization time. This patch is a cleanup.

---
 input/flow/ulogd_inpflow_NFCT.c |   65 +++++++++++++++++++++++----------------
 1 files changed, 38 insertions(+), 27 deletions(-)
input/flow/ulogd_inpflow_NFCT.c +38 -27
index 96aa8ea..da23ada 100644
@@ -570,9 +570,9 @@ do_propagate_ct(struct ulogd_pluginstance *upi,
 	propagate_ct(upi, ct, type, ts);
 }
 
-static int event_handler(enum nf_conntrack_msg_type type,
-			 struct nf_conntrack *ct,
-			 void *data)
+static int
+event_handler_hashtable(enum nf_conntrack_msg_type type,
+			struct nf_conntrack *ct, void *data)
 {
 	struct ulogd_pluginstance *upi = data;
 	struct nfct_pluginstance *cpi =
@@ -580,29 +580,6 @@ static int event_handler(enum nf_conntrack_msg_type type,
 	struct ct_timestamp *ts;
 	int ret, id;
 
-	if (!usehash_ce(upi->config_kset).u.value) {
-		struct ct_timestamp tmp = {
-			.ct = ct,
-		};
-		switch(type) {
-		case NFCT_T_NEW:
-			gettimeofday(&tmp.time[START], NULL);
-			tmp.time[STOP].tv_sec = 0;
-			tmp.time[STOP].tv_usec = 0;
-			break;
-		case NFCT_T_DESTROY:
-			gettimeofday(&tmp.time[STOP], NULL);
-			tmp.time[START].tv_sec = 0;
-			tmp.time[START].tv_usec = 0;
-			break;
-		default:
-			ulogd_log(ULOGD_NOTICE, "unsupported message type\n");
-			break;
-		}
-		do_propagate_ct(upi, ct, type, &tmp);
-		return NFCT_CB_CONTINUE;
-	}
-
 	switch(type) {
 	case NFCT_T_NEW:
 		ts = calloc(sizeof(struct ct_timestamp), 1);
@@ -670,6 +647,34 @@ static int event_handler(enum nf_conntrack_msg_type type,
 }
 
 static int
+event_handler_no_hashtable(enum nf_conntrack_msg_type type,
+			   struct nf_conntrack *ct, void *data)
+{
+	struct ulogd_pluginstance *upi = data;
+	struct ct_timestamp tmp = {
+		.ct = ct,
+	};
+
+	switch(type) {
+	case NFCT_T_NEW:
+		gettimeofday(&tmp.time[START], NULL);
+		tmp.time[STOP].tv_sec = 0;
+		tmp.time[STOP].tv_usec = 0;
+		break;
+	case NFCT_T_DESTROY:
+		gettimeofday(&tmp.time[STOP], NULL);
+		tmp.time[START].tv_sec = 0;
+		tmp.time[START].tv_usec = 0;
+		break;
+	default:
+		ulogd_log(ULOGD_NOTICE, "unsupported message type\n");
+		break;
+	}
+	do_propagate_ct(upi, ct, type, &tmp);
+	return NFCT_CB_CONTINUE;
+}
+
+static int
 polling_handler(enum nf_conntrack_msg_type type,
 		struct nf_conntrack *ct, void *data)
 {
@@ -931,7 +936,13 @@ static int constructor_nfct_events(struct ulogd_pluginstance *upi)
 		goto err_cth;
 	}
 
-	nfct_callback_register(cpi->cth, NFCT_T_ALL, &event_handler, upi);
+	if (usehash_ce(upi->config_kset).u.value != 0) {
+		nfct_callback_register(cpi->cth, NFCT_T_ALL,
+				       &event_handler_hashtable, upi);
+	} else {
+		nfct_callback_register(cpi->cth, NFCT_T_ALL,
+				       &event_handler_no_hashtable, upi);
+	}
 
 	if (nlsockbufsize_ce(upi->config_kset).u.value) {
 		setnlbufsiz(upi, nlsockbufsize_ce(upi->config_kset).u.value);
author maintainer
#5 lore raw

PATCH 5/6 NFCT: fix number of options (missing one)

In reply to Pablo Neira Ayuso

This patch fixes the number of options in NFCT that is actually 8, not 7.

---
 input/flow/ulogd_inpflow_NFCT.c |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)
input/flow/ulogd_inpflow_NFCT.c +1 -1
index da23ada..8e01feb 100644
@@ -71,7 +71,7 @@ struct nfct_pluginstance {
 #define EVENT_MASK	NF_NETLINK_CONNTRACK_NEW | NF_NETLINK_CONNTRACK_DESTROY
 
 static struct config_keyset nfct_kset = {
-	.num_ces = 7,
+	.num_ces = 8,
 	.ces = {
 		{
 			.key	 = "pollinterval",
author maintainer
#6 lore raw

PATCH 6/6 NFCT: fix reset counters via SIGUSR2 signal

In reply to Pablo Neira Ayuso

This patch fixes a feature that allows to force the logging of the existing entries and reset the counters.

---
 input/flow/ulogd_inpflow_NFCT.c |   55 +++++++++++++++++++++++++++++++++++++--
 1 files changed, 52 insertions(+), 3 deletions(-)
input/flow/ulogd_inpflow_NFCT.c +52 -3
index 8e01feb..b52c5b6 100644
@@ -874,13 +874,62 @@ static int read_cb_ovh(int fd, unsigned int what, void *param)
 	return 0;
 }
 
-static int get_ctr_zero(struct ulogd_pluginstance *upi)
+static int
+dump_reset_handler(enum nf_conntrack_msg_type type,
+		   struct nf_conntrack *ct, void *data)
 {
-	int family = 0; /* any */
+	struct ulogd_pluginstance *upi = data;
 	struct nfct_pluginstance *cpi =
 			(struct nfct_pluginstance *)upi->private;
+	int ret = NFCT_CB_CONTINUE, rc, id;
+	struct ct_timestamp *ts;
+
+	switch(type) {
+	case NFCT_T_UPDATE:
+		id = hashtable_hash(cpi->ct_active, ct);
+		ts = (struct ct_timestamp *)
+			hashtable_find(cpi->ct_active, ct, id);
+		if (ts)
+			nfct_copy(ts->ct, ct, NFCT_CP_META);
+		else {
+			ts = calloc(sizeof(struct ct_timestamp), 1);
+			if (ts == NULL)
+				return NFCT_CB_CONTINUE;
+
+			ts->ct = ct;
+			gettimeofday(&ts->time[START], NULL);
+
+			rc = hashtable_add(cpi->ct_active, &ts->hashnode, id);
+			if (rc < 0) {
+				free(ts);
+				return NFCT_CB_CONTINUE;
+			}
+			ret = NFCT_CB_STOLEN;
+		}
+		do_propagate_ct(upi, ct, type, ts);
+		break;
+	default:
+		ulogd_log(ULOGD_NOTICE, "unknown netlink message type\n");
+		break;
+	}
+	return ret;
+}
+
+static void get_ctr_zero(struct ulogd_pluginstance *upi)
+{
+	struct nfct_handle *h;
+	int family = AF_UNSPEC;
+
+	h = nfct_open(CONNTRACK, 0);
+	if (h == NULL) {
+		ulogd_log(ULOGD_FATAL, "Cannot dump and reset counters\n");
+		return;
+	}
+	nfct_callback_register(h, NFCT_T_ALL, &dump_reset_handler, upi);
+	if (nfct_query(h, NFCT_Q_DUMP_RESET, &family) == -1)
+		ulogd_log(ULOGD_FATAL, "Cannot dump and reset counters\n");
 
-	return nfct_query(cpi->cth, NFCT_Q_DUMP_RESET, &family);
+	nfct_close(h);
 }
 
 static void polling_timer_cb(struct ulogd_timer *t, void *data)