From 5e5d8cdb3cfed98f1af3f3e265220c90df684674 Mon Sep 17 00:00:00 2001 From: "/C=EU/ST=EU/CN=Pablo Neira Ayuso/emailAddress=pablo@netfilter.org" Date: Wed, 9 Apr 2008 15:25:59 +0000 Subject: improve netlink overrun handling --- ChangeLog | 1 + include/conntrackd.h | 8 ++++- include/netlink.h | 4 +++ src/netlink.c | 21 +++++++++++++ src/run.c | 27 ++++++++++++++-- src/stats-mode.c | 36 ++++++++++----------- src/sync-mode.c | 89 +++++++++++++++++++++------------------------------- 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 : 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 : 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 #include @@ -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 #include #include +#include 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 -- cgit v1.2.3