summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog1
-rw-r--r--include/conntrackd.h8
-rw-r--r--include/netlink.h4
-rw-r--r--src/netlink.c21
-rw-r--r--src/run.c27
-rw-r--r--src/stats-mode.c36
-rw-r--r--src/sync-mode.c89
7 files changed, 111 insertions, 75 deletions
diff --git a/ChangeLog b/ChangeLog
index 4bd878b..4ca2af1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -5,6 +5,7 @@ Pablo Neira Ayuso <pablo@netfilter.org>:
o remove .svn directory from make distcheck tarballs (reported by B.Benjamini)
o fix minor compilation issue in amd64 with gcc4.3 (reported by Daniel Schepler)
o fix asymmetric path support (reported by Gary Richards)
+o improve netlink overrun handling
Krzysztof Oledzki <ole@ans.pl>:
o fix minor compilation warning
diff --git a/include/conntrackd.h b/include/conntrackd.h
index 69c1303..57ac7e4 100644
--- a/include/conntrackd.h
+++ b/include/conntrackd.h
@@ -3,6 +3,7 @@
#include "mcast.h"
#include "local.h"
+#include "alarm.h"
#include <stdint.h>
#include <stdio.h>
@@ -104,6 +105,8 @@ struct ct_general_state {
struct nfct_handle *event; /* event handler */
struct nfct_handle *dump; /* dump handler */
+ struct nfct_handle *overrun; /* overrun handler */
+ struct alarm_block overrun_alarm;
struct fds *fds;
@@ -158,7 +161,10 @@ struct ct_mode {
int (*local)(int fd, int type, void *data);
void (*kill)(void);
void (*dump)(struct nf_conntrack *ct);
- void (*overrun)(void);
+ int (*overrun)(enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ void *data);
+ int (*purge)(void);
void (*event_new)(struct nf_conntrack *ct);
void (*event_upd)(struct nf_conntrack *ct);
int (*event_dst)(struct nf_conntrack *ct);
diff --git a/include/netlink.h b/include/netlink.h
index d345656..a46fe11 100644
--- a/include/netlink.h
+++ b/include/netlink.h
@@ -10,6 +10,10 @@ int nl_init_event_handler(void);
int nl_init_dump_handler(void);
+int nl_init_overrun_handler(void);
+
+int nl_overrun_request_resync(void);
+
void nl_resize_socket_buffer(struct nfct_handle *h);
int nl_dump_conntrack_table(void);
diff --git a/src/netlink.c b/src/netlink.c
index 1ab75e4..10c4643 100644
--- a/src/netlink.c
+++ b/src/netlink.c
@@ -158,6 +158,21 @@ int nl_init_dump_handler(void)
return 0;
}
+int nl_init_overrun_handler(void)
+{
+ STATE(overrun) = nfct_open(CONNTRACK, 0);
+ if (!STATE(overrun))
+ return -1;
+
+ fcntl(nfct_fd(STATE(overrun)), F_SETFL, O_NONBLOCK);
+
+ nfct_callback_register(STATE(overrun),
+ NFCT_T_ALL,
+ STATE(mode)->overrun,
+ NULL);
+ return 0;
+}
+
static int warned = 0;
void nl_resize_socket_buffer(struct nfct_handle *h)
@@ -195,6 +210,12 @@ int nl_dump_conntrack_table(void)
return nfct_query(STATE(dump), NFCT_Q_DUMP, &CONFIG(family));
}
+int nl_overrun_request_resync(void)
+{
+ int family = CONFIG(family);
+ return nfct_send(STATE(overrun), NFCT_Q_DUMP, &family);
+}
+
int nl_exist_conntrack(struct nf_conntrack *ct)
{
int ret;
diff --git a/src/run.c b/src/run.c
index b259f2e..63761b4 100644
--- a/src/run.c
+++ b/src/run.c
@@ -89,6 +89,12 @@ void local_handler(int fd, void *data)
dlog(LOG_WARNING, "unknown local request %d", type);
}
+static void do_overrun_alarm(struct alarm_block *a, void *data)
+{
+ nl_overrun_request_resync();
+ add_alarm(&STATE(overrun_alarm), 2, 0);
+}
+
int
init(void)
{
@@ -129,6 +135,15 @@ init(void)
return -1;
}
+ if (nl_init_overrun_handler() == -1) {
+ dlog(LOG_ERR, "can't open netlink handler: %s",
+ strerror(errno));
+ dlog(LOG_ERR, "no ctnetlink kernel support?");
+ return -1;
+ }
+
+ init_alarm(&STATE(overrun_alarm), NULL, do_overrun_alarm);
+
STATE(fds) = create_fds();
if (STATE(fds) == NULL) {
dlog(LOG_ERR, "can't create file descriptor pool");
@@ -137,6 +152,7 @@ init(void)
register_fd(STATE(local).fd, STATE(fds));
register_fd(nfct_fd(STATE(event)), STATE(fds));
+ register_fd(nfct_fd(STATE(overrun)), STATE(fds));
if (STATE(mode)->register_fds &&
STATE(mode)->register_fds(STATE(fds)) == -1) {
@@ -203,8 +219,8 @@ static void __run(struct timeval *next_alarm)
* size and resync with master conntrack table.
*/
nl_resize_socket_buffer(STATE(event));
- /* XXX: schedule overrun call via alarm */
- STATE(mode)->overrun();
+ nl_overrun_request_resync();
+ add_alarm(&STATE(overrun_alarm), 2, 0);
break;
case ENOENT:
/*
@@ -223,6 +239,13 @@ static void __run(struct timeval *next_alarm)
}
}
+ if (FD_ISSET(nfct_fd(STATE(overrun)), &readfds)) {
+ del_alarm(&STATE(overrun_alarm));
+ nfct_catch(STATE(overrun));
+ if (STATE(mode)->purge)
+ STATE(mode)->purge();
+ }
+
if (STATE(mode)->run)
STATE(mode)->run(&readfds);
diff --git a/src/stats-mode.c b/src/stats-mode.c
index 42fa35a..3773feb 100644
--- a/src/stats-mode.c
+++ b/src/stats-mode.c
@@ -22,10 +22,12 @@
#include "cache.h"
#include "log.h"
#include "conntrackd.h"
+#include "us-conntrack.h"
#include <errno.h>
#include <string.h>
#include <stdlib.h>
+#include <libnetfilter_conntrack/libnetfilter_conntrack.h>
static int init_stats(void)
{
@@ -93,9 +95,9 @@ static void dump_stats(struct nf_conntrack *ct)
debug_ct(ct, "resync entry");
}
-static int overrun_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
+static int overrun_stats(enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ void *data)
{
if (ignore_conntrack(ct))
return NFCT_CB_CONTINUE;
@@ -115,28 +117,25 @@ static int overrun_cb(enum nf_conntrack_msg_type type,
return NFCT_CB_CONTINUE;
}
-static void overrun_stats(void)
+static int purge_step(void *data1, void *data2)
{
int ret;
- struct nfct_handle *h;
- int family = CONFIG(family);
+ struct us_conntrack *u = data2;
- h = nfct_open(CONNTRACK, 0);
- if (!h) {
- dlog(LOG_ERR, "can't open overrun handler");
- return;
+ ret = nfct_query(STATE(dump), NFCT_Q_GET, u->ct);
+ if (ret == -1 && errno == ENOENT) {
+ debug_ct(u->ct, "overrun purge stats");
+ cache_del(STATE_STATS(cache), u->ct);
}
- nfct_callback_register(h, NFCT_T_ALL, overrun_cb, NULL);
-
- cache_flush(STATE_STATS(cache));
+ return 0;
+}
- ret = nfct_query(h, NFCT_Q_DUMP, &family);
- if (ret == -1)
- dlog(LOG_ERR,
- "overrun query error %s", strerror(errno));
+static int purge_stats(void)
+{
+ cache_iterate(STATE_STATS(cache), NULL, purge_step);
- nfct_close(h);
+ return 0;
}
static void event_new_stats(struct nf_conntrack *ct)
@@ -187,6 +186,7 @@ struct ct_mode stats_mode = {
.kill = kill_stats,
.dump = dump_stats,
.overrun = overrun_stats,
+ .purge = purge_stats,
.event_new = event_new_stats,
.event_upd = event_update_stats,
.event_dst = event_destroy_stats
diff --git a/src/sync-mode.c b/src/sync-mode.c
index 79afcdf..3851e4a 100644
--- a/src/sync-mode.c
+++ b/src/sync-mode.c
@@ -350,9 +350,40 @@ static void mcast_send_sync(struct us_conntrack *u,
STATE_SYNC(sync)->send(net, u);
}
-static int overrun_cb(enum nf_conntrack_msg_type type,
- struct nf_conntrack *ct,
- void *data)
+static int purge_step(void *data1, void *data2)
+{
+ int ret;
+ struct nfct_handle *h = STATE(dump);
+ struct us_conntrack *u = data2;
+
+ ret = nfct_query(h, NFCT_Q_GET, u->ct);
+ if (ret == -1 && errno == ENOENT) {
+ size_t len;
+ struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY);
+
+ debug_ct(u->ct, "overrun purge resync");
+
+ len = prepare_send_netmsg(STATE_SYNC(mcast_client), net);
+ mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len);
+ if (STATE_SYNC(sync)->send)
+ STATE_SYNC(sync)->send(net, u);
+
+ cache_del(STATE_SYNC(internal), u->ct);
+ }
+
+ return 0;
+}
+
+static int purge_sync(void)
+{
+ cache_iterate(STATE_SYNC(internal), NULL, purge_step);
+
+ return 0;
+}
+
+static int overrun_sync(enum nf_conntrack_msg_type type,
+ struct nf_conntrack *ct,
+ void *data)
{
struct us_conntrack *u;
@@ -387,57 +418,6 @@ static int overrun_cb(enum nf_conntrack_msg_type type,
return NFCT_CB_CONTINUE;
}
-static int overrun_purge_step(void *data1, void *data2)
-{
- int ret;
- struct nfct_handle *h = data1;
- struct us_conntrack *u = data2;
-
- ret = nfct_query(h, NFCT_Q_GET, u->ct);
- if (ret == -1 && errno == ENOENT) {
- size_t len;
- struct nethdr *net = BUILD_NETMSG(u->ct, NFCT_Q_DESTROY);
-
- debug_ct(u->ct, "overrun purge resync");
-
- len = prepare_send_netmsg(STATE_SYNC(mcast_client), net);
- mcast_buffered_send_netmsg(STATE_SYNC(mcast_client), net, len);
- if (STATE_SYNC(sync)->send)
- STATE_SYNC(sync)->send(net, u);
-
- cache_del(STATE_SYNC(internal), u->ct);
- }
-
- return 0;
-}
-
-/* it's likely that we're losing events, just try to do our best here */
-static void overrun_sync(void)
-{
- int ret;
- struct nfct_handle *h;
- int family = CONFIG(family);
-
- h = nfct_open(CONNTRACK, 0);
- if (!h) {
- dlog(LOG_ERR, "can't open overrun handler");
- return;
- }
-
- nfct_callback_register(h, NFCT_T_ALL, overrun_cb, NULL);
-
- ret = nfct_query(h, NFCT_Q_DUMP, &family);
- if (ret == -1)
- dlog(LOG_ERR,
- "overrun query error %s", strerror(errno));
-
- nfct_callback_unregister(h);
-
- cache_iterate(STATE_SYNC(internal), h, overrun_purge_step);
-
- nfct_close(h);
-}
-
static void event_new_sync(struct nf_conntrack *ct)
{
struct us_conntrack *u;
@@ -505,6 +485,7 @@ struct ct_mode sync_mode = {
.kill = kill_sync,
.dump = dump_sync,
.overrun = overrun_sync,
+ .purge = purge_sync,
.event_new = event_new_sync,
.event_upd = event_update_sync,
.event_dst = event_destroy_sync