From 367efea8c9ba557a81158a69ecee267706a520eb Mon Sep 17 00:00:00 2001 From: Daniel Borkmann Date: Thu, 28 Mar 2013 18:48:25 +0100 Subject: [PATCH] ring: purge timer before we unmap tx ring buffers If we unmap TX ring buffers and still have timer shots that trigger the kernel to traverse the TX_RING, it can send out random crap in some situations. Prevent this by destroying the timer and flush the TX_RING first in wait mode. Signed-off-by: Daniel Borkmann --- netsniff-ng.c | 19 +++++++++++++++++++ ring_rx.c | 2 +- ring_tx.c | 2 +- ring_tx.h | 5 +++++ trafgen.c | 20 ++++++++++++++++++-- 5 files changed, 44 insertions(+), 4 deletions(-) diff --git a/netsniff-ng.c b/netsniff-ng.c index 0f97acdd..ecb9e9a7 100644 --- a/netsniff-ng.c +++ b/netsniff-ng.c @@ -131,6 +131,21 @@ static void timer_elapsed(int unused) setitimer(ITIMER_REAL, &itimer, NULL); } +static void timer_purge(void) +{ + int ret; + + ret = pull_and_flush_tx_ring_wait(tx_sock); + if (unlikely(ret < 0)) { + if (errno != EBADF && errno != ENOBUFS) + panic("Flushing TX_RING failed: %s!\n", strerror(errno)); + } + + set_itimer_interval_value(&itimer, 0, 0); + setitimer(ITIMER_REAL, &itimer, NULL); +} + + static void timer_next_dump(int unused) { set_itimer_interval_value(&itimer, interval, 0); @@ -289,6 +304,8 @@ static void pcap_to_xmit(struct ctx *ctx) bug_on(gettimeofday(&end, NULL)); timersub(&end, &start, &diff); + timer_purge(); + bpf_release(&bpf_ops); dissector_cleanup_all(); @@ -455,6 +472,8 @@ static void receive_to_xmit(struct ctx *ctx) out: + timer_purge(); + sock_print_net_stats(rx_sock, 0); bpf_release(&bpf_ops); diff --git a/ring_rx.c b/ring_rx.c index 5675a818..d89d7624 100644 --- a/ring_rx.c +++ b/ring_rx.c @@ -30,7 +30,7 @@ void destroy_rx_ring(int sock, struct ring *ring) ret = setsockopt(sock, SOL_PACKET, PACKET_RX_RING, &ring->layout, sizeof(ring->layout)); if (unlikely(ret)) - panic("Cannot destroy the RX_RING!\n"); + panic("Cannot destroy the RX_RING: %s!\n", strerror(errno)); xfree(ring->frames); } diff --git a/ring_tx.c b/ring_tx.c index 6804c43a..2ad1de93 100644 --- a/ring_tx.c +++ b/ring_tx.c @@ -40,7 +40,7 @@ void destroy_tx_ring(int sock, struct ring *ring) ret = setsockopt(sock, SOL_PACKET, PACKET_TX_RING, &ring->layout, sizeof(ring->layout)); if (unlikely(ret)) - panic("Cannot destroy the TX_RING!\n"); + panic("Cannot destroy the TX_RING: %s!\n", strerror(errno)); xfree(ring->frames); } diff --git a/ring_tx.h b/ring_tx.h index 79700455..769f27e1 100644 --- a/ring_tx.h +++ b/ring_tx.h @@ -37,4 +37,9 @@ static inline int pull_and_flush_tx_ring(int sock) return sendto(sock, NULL, 0, MSG_DONTWAIT, NULL, 0); } +static inline int pull_and_flush_tx_ring_wait(int sock) +{ + return sendto(sock, NULL, 0, 0, NULL, 0); +} + #endif /* TX_RING_H */ diff --git a/trafgen.c b/trafgen.c index dc0c54b6..fb41f45a 100644 --- a/trafgen.c +++ b/trafgen.c @@ -127,11 +127,24 @@ static void signal_handler(int number) static void timer_elapsed(int number) { - int ret; + int ret = pull_and_flush_tx_ring(sock); + if (unlikely(ret < 0)) { + /* We could hit EBADF if the socket has been closed before + * the timer was triggered. + */ + if (errno != EBADF && errno != ENOBUFS) + panic("Flushing TX_RING failed: %s!\n", strerror(errno)); + } set_itimer_interval_value(&itimer, 0, interval); + setitimer(ITIMER_REAL, &itimer, NULL); +} - ret = pull_and_flush_tx_ring(sock); +static void timer_purge(void) +{ + int ret; + + ret = pull_and_flush_tx_ring_wait(sock); if (unlikely(ret < 0)) { /* We could hit EBADF if the socket has been closed before * the timer was triggered. @@ -140,6 +153,7 @@ static void timer_elapsed(int number) panic("Flushing TX_RING failed: %s!\n", strerror(errno)); } + set_itimer_interval_value(&itimer, 0, 0); setitimer(ITIMER_REAL, &itimer, NULL); } @@ -669,6 +683,8 @@ static void xmit_fastpath_or_die(struct ctx *ctx, int cpu, unsigned long orig_nu bug_on(gettimeofday(&end, NULL)); timersub(&end, &start, &diff); + timer_purge(); + destroy_tx_ring(sock, &tx_ring); stats[cpu].tx_packets = tx_packets; -- 2.11.4.GIT