On Sun, 2024-10-20 at 01:03 -0700, Guy Harris wrote:
> 
> 
> > On Oct 20, 2024, at 12:11 AM, Garri Djavadyan
> > <g.djavad...@gmail.com> wrote:
> > 
> > On Sat, 2024-10-19 at 23:58 -0700, Guy Harris wrote:
> > > On Oct 19, 2024, at 5:01 PM, Garri Djavadyan
> > > <g.djavad...@gmail.com>
> > > wrote:
> > > 
> > > > I am looking for a way to force tcpdump flush Linux OS buffer
> > > > before
> > > > terminating. I have checked the man page and the mailing list
> > > > archives
> > > > but did not manage to find anything related.
> > > > 
> > > > When I terminate tcpdump process with SIGINT or SIGTERM, the
> > > > process
> > > > quits immediately, leaving packets in the buffer. I know that
> > > > the
> > > > signal USR2 forces the buffer to be flushed, but it does stop
> > > > filling
> > > > the buffer and the process remains active.
> > > > 
> > > > I have to use a very big buffer with a very slow storage, much
> > > > slower
> > > > than the rate of coming packets received by the filter, and it
> > > > is
> > > > preferred not to lose a single packet after initiating
> > > > termination
> > > > the
> > > > process.
> > > 
> > > OK, so is the buffer to which you're referring the buffer that
> > > holds
> > > captured packets for tcpdump to read, i.e. the *input* buffer for
> > > tcpdump, rather than, for example, the standard I/O buffer
> > > containing
> > > packet dissection text to be printed or the I/O buffer containing
> > > packets to be written to the file specified by -w, i.e. an
> > > *output*
> > > buffer for tcpdump?
> > 
> > Correct. I meant the input buffer, specified with the -B flag.
> 
> OK, so by "flushing" the buffer - which, for an input buffer, usually
> means discarding everything that's in the buffer and, for an output
> buffer, usually means writing the buffer contents to the target file
> - you meant "draining" the buffer, as in "processing all the packets
> in the buffer".

Thank you for the correction. Indeed, I should have used "draining"
here.


> > When I terminate tcpdump process with SIGINT or SIGTERM, the
> > process
> > quits immediately, leaving packets in the buffer. I know that the
> > signal USR2 forces the buffer to be flushed, but it does stop
> > filling
> > the buffer and the process remains active.
> 
> No, SIGUSR2 flushes the *output* buffer for the file being written to
> with -w.  The tcpdump man page does not make that clear; I will
> update it to do so.

Hmm. I see. Thank you in advance for updating the man page.


> > I have to use a very big buffer with a very slow storage, much
> > slower
> > than the rate of coming packets received by the filter, and it is
> > preferred not to lose a single packet after initiating termination
> > the
> > process.
> 
> What do you mean by "with a very slow storage"?  You can set the size
> with -B, but that just tells the capture mechanism in the kernel how
> big a buffer to allocate.  It's not as if it tells it to be stored in
> some slower form of memory.

Let me show an example. To demonstrate the issue, I am generating 2MB/s
stream of dummy packets:

[src]# pv -L 2M /dev/zero | dd bs=1472 > /dev/udp/192.168.0.1/12345


and dumping them to a storage, with cgroup-v2-restricted write speed of
1MB/s:

[dst]# lsblk /dev/loop0
NAME  MAJ:MIN RM  SIZE RO TYPE MOUNTPOINTS
loop0   7:0    0  3.9G  0 loop /mnt/test

[dst]# cat /sys/fs/cgroup/test/io.max
7:0 rbps=max wbps=1024000 riops=max wiops=max


To temporarily avoid kernel-level drops, I set a 1GB (sufficient to get
needed packets before it overflows) input buffer:

[dst]# tcpdump -i veth0 -w /mnt/test/udp.pcap -B 1024000


Now, if start inspecting tcpdump's stats every second:

[dst]# while true; do killall -10 tcpdump; sleep 1; done


it is clearly seen that the input buffer is being filled at 1MB/s rate
(the diff between the generated traffic rate (2MB/s) and the writing
speed of the storage (1MB/s):

tcpdump: 0 packets captured, 0 packets received by filter, 0 packets
dropped by kernel
tcpdump: 218 packets captured, 715 packets received by filter, 0
packets dropped by kernel
tcpdump: 890 packets captured, 2145 packets received by filter, 0
packets dropped by kernel
tcpdump: 1575 packets captured, 3575 packets received by filter, 0
packets dropped by kernel
tcpdump: 2246 packets captured, 5005 packets received by filter, 0
packets dropped by kernel
tcpdump: 2931 packets captured, 6435 packets received by filter, 0
packets dropped by kernel
tcpdump: 3603 packets captured, 7867 packets received by filter, 0
packets dropped by kernel
tcpdump: 4288 packets captured, 9440 packets received by filter, 0
packets dropped by kernel
tcpdump: 4960 packets captured, 10870 packets received by filter, 0
packets dropped by kernel
tcpdump: 5645 packets captured, 12300 packets received by filter, 0
packets dropped by kernel
tcpdump: 6317 packets captured, 13730 packets received by filter, 0
packets dropped by kernel
tcpdump: 6988 packets captured, 15160 packets received by filter, 0
packets dropped by kernel
tcpdump: 7675 packets captured, 16590 packets received by filter, 0
packets dropped by kernel
tcpdump: 8347 packets captured, 18020 packets received by filter, 0
packets dropped by kernel
tcpdump: 9032 packets captured, 19450 packets received by filter, 0
packets dropped by kernel
tcpdump: 9704 packets captured, 20880 packets received by filter, 0
packets dropped by kernel
tcpdump: 10389 packets captured, 22310 packets received by filter, 0
packets dropped by kernel
tcpdump: 11061 packets captured, 23740 packets received by filter, 0
packets dropped by kernel


If at this point I stop tcpdump, then more than 10k packets will be
lost.


> > There are a few options to overcome the problem. For example,
> > by dumping packets to the memory storage first (e.g. /dev/shm)
> 
> Presumably meaning you specified "-w /dev/shm" or something such as
> that?
> 
> If so, how does that make a difference?

I mean I can first dump packets to the lightning-fast RAM storage and
after being done with the capturing part, copy the dump to the slow
storage.

For example, with RAM-based destination, no large buffer is needed in
my case:

[dst]# tcpdump -i veth0 -w /dev/shm/udp.pcap
...
tcpdump: 0 packets captured, 0 packets received by filter, 0 packets
dropped by kernel
tcpdump: 328 packets captured, 429 packets received by filter, 0
packets dropped by kernel
tcpdump: 1804 packets captured, 1859 packets received by filter, 0
packets dropped by kernel
tcpdump: 3280 packets captured, 3289 packets received by filter, 0
packets dropped by kernel
tcpdump: 4592 packets captured, 4719 packets received by filter, 0
packets dropped by kernel
tcpdump: 6232 packets captured, 6292 packets received by filter, 0
packets dropped by kernel
tcpdump: 7710 packets captured, 7724 packets received by filter, 0
packets dropped by kernel
tcpdump: 9022 packets captured, 9154 packets received by filter, 0
packets dropped by kernel
tcpdump: 10498 packets captured, 10584 packets received by filter, 0
packets dropped by kernel
tcpdump: 11974 packets captured, 12014 packets received by filter, 0
packets dropped by kernel
tcpdump: 13286 packets captured, 13444 packets received by filter, 0
packets dropped by kernel
tcpdump: 14927 packets captured, 15018 packets received by filter, 0
packets dropped by kernel


The RAM-based storage is fast enough, so the diff between the
"captured" and "received by filter" counters is minimal, not posing any
considerations for losing significant number of packets.


> > Still, I wonder if this can be done by tcpdump itself.
> 
> That would require that tcpdump be able to tell the capture mechanism
> to stop capturing packets; otherwise, tcpdump could continue reading
> packets from the buffer an processing them, but it's not as if the
> capture mechanism will stop adding packets to the buffer, so that
> would behave as if tcpdump continued capturing.
> 
> There is no current mechanism in libpcap by which tcpdump (or any
> other program using libpcap to capture networking traffic, e.e.
> Wireshark) can indicate to libpcap that it doesn't want any *more*
> packets from the network device, but wants to be able to keep reading
> from the packets already *in* the buffer until the last packet has
> been retrieved. That means tcpdump can't be told to do that with any
> existing version of libpcap.

I see. Thank you so much for the explanation.

Do you think this case can justify feature requests both for libpcap
and tcpdump on github?


Thank you.

Regards,
Garri
_______________________________________________
tcpdump-workers mailing list -- tcpdump-workers@lists.tcpdump.org
To unsubscribe send an email to tcpdump-workers-le...@lists.tcpdump.org
%(web_page_url)slistinfo%(cgiext)s/%(_internal_name)s

Reply via email to