From 58b363d32bf9b8b504c5664ae4d8b3bb1fab6ddb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sun, 28 Feb 2010 16:01:38 +0100 Subject: conntrackd: split __run() routine for poll and event-driven modes This patch splits the __run() routine into two functions, run_polling() and run_events() that are selected once in run-time. We save one branch in a loop that intensively executed. Signed-off-by: Pablo Neira Ayuso --- src/run.c | 176 +++++++++++++++++++++++++++++++++++++------------------------- 1 file changed, 105 insertions(+), 71 deletions(-) (limited to 'src') diff --git a/src/run.c b/src/run.c index 803bbcc..f68dd91 100644 --- a/src/run.c +++ b/src/run.c @@ -451,7 +451,7 @@ init(void) return 0; } -static void __run(struct timeval *next_alarm) +static void run_events(struct timeval *next_alarm) { int ret; fd_set readfds = STATE(fds)->readfds; @@ -473,77 +473,102 @@ static void __run(struct timeval *next_alarm) if (FD_ISSET(STATE(local).fd, &readfds)) do_local_server_step(&STATE(local), NULL, local_handler); - if (!(CONFIG(flags) & CTD_POLL)) { - /* conntrack event has happened */ - if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { - ret = nfct_catch(STATE(event)); - /* reset event iteration limit counter */ - STATE(event_iterations_limit) = - CONFIG(event_iterations_limit); - if (ret == -1) { - switch(errno) { - case ENOBUFS: - /* We have hit ENOBUFS, it's likely that we are - * losing events. Two possible situations may - * trigger this error: - * - * 1) The netlink receiver buffer is too small: - * increasing the netlink buffer size should - * be enough. However, some event messages - * got lost. We have to resync ourselves - * with the kernel table conntrack table to - * resolve the inconsistency. - * - * 2) The receiver is too slow to process the - * netlink messages so that the queue gets - * full quickly. This generally happens - * if the system is under heavy workload - * (busy CPU). In this case, increasing the - * size of the netlink receiver buffer - * would not help anymore since we would - * be delaying the overrun. Moreover, we - * should avoid resynchronizations. We - * should do our best here and keep - * replicating as much states as possible. - * If workload lowers at some point, - * we resync ourselves. - */ - nl_resize_socket_buffer(STATE(event)); - if (CONFIG(nl_overrun_resync) > 0 && - STATE(mode)->internal->flags & - INTERNAL_F_RESYNC) { - add_alarm(&STATE(resync_alarm), - CONFIG(nl_overrun_resync),0); - } - STATE(stats).nl_catch_event_failed++; - STATE(stats).nl_overrun++; - break; - case ENOENT: - /* - * We received a message from another - * netfilter subsystem that we are not - * interested in. Just ignore it. - */ - break; - case EAGAIN: - break; - default: - STATE(stats).nl_catch_event_failed++; - break; - } + /* we have receive an event from ctnetlink */ + if (FD_ISSET(nfct_fd(STATE(event)), &readfds)) { + ret = nfct_catch(STATE(event)); + /* reset event iteration limit counter */ + STATE(event_iterations_limit) = CONFIG(event_iterations_limit); + if (ret == -1) { + switch(errno) { + case ENOBUFS: + /* We have hit ENOBUFS, it's likely that we are + * losing events. Two possible situations may + * trigger this error: + * + * 1) The netlink receiver buffer is too small: + * increasing the netlink buffer size should + * be enough. However, some event messages + * got lost. We have to resync ourselves + * with the kernel table conntrack table to + * resolve the inconsistency. + * + * 2) The receiver is too slow to process the + * netlink messages so that the queue gets + * full quickly. This generally happens + * if the system is under heavy workload + * (busy CPU). In this case, increasing the + * size of the netlink receiver buffer + * would not help anymore since we would + * be delaying the overrun. Moreover, we + * should avoid resynchronizations. We + * should do our best here and keep + * replicating as much states as possible. + * If workload lowers at some point, + * we resync ourselves. + */ + nl_resize_socket_buffer(STATE(event)); + if (CONFIG(nl_overrun_resync) > 0 && + STATE(mode)->internal->flags & INTERNAL_F_RESYNC) { + add_alarm(&STATE(resync_alarm), + CONFIG(nl_overrun_resync),0); } + STATE(stats).nl_catch_event_failed++; + STATE(stats).nl_overrun++; + break; + case ENOENT: + /* + * We received a message from another + * netfilter subsystem that we are not + * interested in. Just ignore it. + */ + break; + case EAGAIN: + /* No more events to receive, try later. */ + break; + default: + STATE(stats).nl_catch_event_failed++; + break; } - if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { - nfct_catch(STATE(resync)); - if (STATE(mode)->internal->purge) - STATE(mode)->internal->purge(); - } - } else { - /* using polling mode */ - if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { - nfct_catch(STATE(resync)); } } + /* we previously requested a resync due to buffer overrun. */ + if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) { + nfct_catch(STATE(resync)); + if (STATE(mode)->internal->purge) + STATE(mode)->internal->purge(); + } + + if (STATE(mode)->run) + STATE(mode)->run(&readfds); + + sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); +} + +static void run_polling(struct timeval *next_alarm) +{ + int ret; + fd_set readfds = STATE(fds)->readfds; + + ret = select(STATE(fds)->maxfd + 1, &readfds, NULL, NULL, next_alarm); + if (ret == -1) { + /* interrupted syscall, retry */ + if (errno == EINTR) + return; + + STATE(stats).select_failed++; + return; + } + + /* signals are racy */ + sigprocmask(SIG_BLOCK, &STATE(block), NULL); + + /* order received via UNIX socket */ + if (FD_ISSET(STATE(local).fd, &readfds)) + do_local_server_step(&STATE(local), NULL, local_handler); + + /* we requested a dump from the kernel via polling_alarm */ + if (FD_ISSET(nfct_fd(STATE(resync)), &readfds)) + nfct_catch(STATE(resync)); if (STATE(mode)->run) STATE(mode)->run(&readfds); @@ -551,8 +576,8 @@ static void __run(struct timeval *next_alarm) sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); } -void __attribute__((noreturn)) -run(void) +static void __attribute__((noreturn)) +do_run(void (*run_step)(struct timeval *next_alarm)) { struct timeval next_alarm; struct timeval *next = NULL; @@ -567,6 +592,15 @@ run(void) next = get_next_alarm_run(&next_alarm); sigprocmask(SIG_UNBLOCK, &STATE(block), NULL); - __run(next); + run_step(next); + } +} + +void run(void) +{ + if (CONFIG(flags) & CTD_POLL) { + do_run(run_polling); + } else { + do_run(run_events); } } -- cgit v1.2.3