From a1119a18874410d4d51a61d2e582d25b7c578a54 Mon Sep 17 00:00:00 2001 From: "Mario J. Rugiero" Date: Sun, 16 Feb 2020 20:47:40 -0300 Subject: Linux: proper memory sync for PACKET_MMAP. Release and acquire packets using GCC builtins (compatible with many other common-place compilers). Should fix #898. --- pcap-linux.c | 27 ++++++++++++++++++--------- 1 file changed, 18 insertions(+), 9 deletions(-) (limited to 'pcap-linux.c') diff --git a/pcap-linux.c b/pcap-linux.c index 546d0369..3ba8f710 100644 --- a/pcap-linux.c +++ b/pcap-linux.c @@ -117,6 +117,15 @@ # define HAVE_TPACKET3 #endif /* TPACKET3_HDRLEN */ +#define packet_mmap_acquire(pkt) \ + (__atomic_load_n(&pkt->tp_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL) +#define packet_mmap_release(pkt) \ + (__atomic_store_n(&pkt->tp_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE)) +#define packet_mmap_v3_acquire(pkt) \ + (__atomic_load_n(&pkt->hdr.bh1.block_status, __ATOMIC_ACQUIRE) != TP_STATUS_KERNEL) +#define packet_mmap_v3_release(pkt) \ + (__atomic_store_n(&pkt->hdr.bh1.block_status, TP_STATUS_KERNEL, __ATOMIC_RELEASE)) + #include #include @@ -3680,11 +3689,11 @@ pcap_get_ring_frame_status(pcap_t *handle, int offset) h.raw = RING_GET_FRAME_AT(handle, offset); switch (handlep->tp_version) { case TPACKET_V2: - return (h.h2->tp_status); + return __atomic_load_n(&h.h2->tp_status, __ATOMIC_ACQUIRE); break; #ifdef HAVE_TPACKET3 case TPACKET_V3: - return (h.h3->hdr.bh1.block_status); + return __atomic_load_n(&h.h3->hdr.bh1.block_status, __ATOMIC_ACQUIRE); break; #endif } @@ -4264,7 +4273,7 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); - if (h.h2->tp_status == TP_STATUS_KERNEL) { + if (!packet_mmap_acquire(h.h2)) { /* * The current frame is owned by the kernel; wait for * a frame to be handed to us. @@ -4283,7 +4292,7 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, * it's still owned by the kernel. */ h.raw = RING_GET_CURRENT_FRAME(handle); - if (h.h2->tp_status == TP_STATUS_KERNEL) + if (!packet_mmap_acquire(h.h2)) break; ret = pcap_handle_packet_mmap( @@ -4311,7 +4320,7 @@ pcap_read_linux_mmap_v2(pcap_t *handle, int max_packets, pcap_handler callback, * after having been filtered by the kernel, count * the one we've just processed. */ - h.h2->tp_status = TP_STATUS_KERNEL; + packet_mmap_release(h.h2); if (handlep->blocks_to_filter_in_userland > 0) { handlep->blocks_to_filter_in_userland--; if (handlep->blocks_to_filter_in_userland == 0) { @@ -4350,7 +4359,7 @@ again: if (handlep->current_packet == NULL) { /* wait for frames availability.*/ h.raw = RING_GET_CURRENT_FRAME(handle); - if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) { + if (!packet_mmap_v3_acquire(h.h3)) { /* * The current frame is owned by the kernel; wait * for a frame to be handed to us. @@ -4362,7 +4371,7 @@ again: } } h.raw = RING_GET_CURRENT_FRAME(handle); - if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) { + if (!packet_mmap_v3_acquire(h.h3)) { if (pkts == 0 && handlep->timeout == 0) { /* Block until we see a packet. */ goto again; @@ -4377,7 +4386,7 @@ again: if (handlep->current_packet == NULL) { h.raw = RING_GET_CURRENT_FRAME(handle); - if (h.h3->hdr.bh1.block_status == TP_STATUS_KERNEL) + if (!packet_mmap_v3_acquire(h.h3)) break; handlep->current_packet = h.raw + h.h3->hdr.bh1.offset_to_first_pkt; @@ -4429,7 +4438,7 @@ again: * filtered by the kernel, count the one we've * just processed. */ - h.h3->hdr.bh1.block_status = TP_STATUS_KERNEL; + packet_mmap_v3_release(h.h3); if (handlep->blocks_to_filter_in_userland > 0) { handlep->blocks_to_filter_in_userland--; if (handlep->blocks_to_filter_in_userland == 0) { -- cgit v1.2.3