diff options
author | Mario J. Rugiero <mrugiero@gmail.com> | 2020-02-16 20:47:40 -0300 |
---|---|---|
committer | Mario Rugiero <mario.rugiero@wildlifestudios.com> | 2020-06-15 20:44:21 -0300 |
commit | a1119a18874410d4d51a61d2e582d25b7c578a54 (patch) | |
tree | 622aa4874b0e49d903f8dd1fc4fbb8d45d17fb77 /pcap-linux.c | |
parent | 0b5dba664659779c2533bffa1355ff964af10853 (diff) |
Linux: proper memory sync for PACKET_MMAP.
Release and acquire packets using GCC builtins (compatible with
many other common-place compilers).
Should fix #898.
Diffstat (limited to 'pcap-linux.c')
-rw-r--r-- | pcap-linux.c | 27 |
1 files changed, 18 insertions, 9 deletions
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 <linux/types.h> #include <linux/filter.h> @@ -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) { |