Skip to content

Commit

Permalink
driver/rawnetworkinterfacedriver: implement live streaming
Browse files Browse the repository at this point in the history
Adds support for live streaming of captured packets such that they can
be processed in real time by tests instead of needing to capture for a
set period of time time and do post-processing.

As an example:

```python
import dpkt

drv = target.get_driver("RawNetworkInterfaceDriver")

with drv.record(None, timeout=60) as p:
    pcap = dpkt.pcap.Reader(p.stdout)
    for timestamp, buf in pcap:
        eth = dpkt.ethernet.Ethernet(buf)
        ....
```

Signed-off-by: Joshua Watt <[email protected]>
Signed-off-by: Bastian Krause <[email protected]>
  • Loading branch information
JoshuaWatt authored and Bastian-Krause committed Oct 14, 2024
1 parent 4f6fe09 commit dcfa087
Show file tree
Hide file tree
Showing 2 changed files with 18 additions and 6 deletions.
4 changes: 4 additions & 0 deletions helpers/labgrid-raw-interface
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,10 @@ def main(program, options):
if program == "tcpdump":
args.append("-n")
args.append(f"--interface={options.ifname}")
# Write out each packet as it is received
args.append("--packet-buffered")
# Capture complete packets (for compatibility with older tcpdump versions)
args.append("--snapshot-length=0")
args.append("-w")
args.append("-")

Expand Down
20 changes: 14 additions & 6 deletions labgrid/driver/rawnetworkinterfacedriver.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ def start_record(self, filename, *, count=None, timeout=None):
Starts tcpdump on bound network interface resource.
Args:
filename (str): name of a file to record to
filename (str): name of a file to record to, or None to record to stdout
count (int): optional, exit after receiving this many number of packets
timeout (int): optional, number of seconds to capture packets before tcpdump exits
Returns:
Expand All @@ -74,8 +74,11 @@ def start_record(self, filename, *, count=None, timeout=None):
cmd.append("--timeout")
cmd.append(str(timeout))
cmd = self._wrap_command(cmd)
with open(filename, "wb") as outdata:
self._record_handle = subprocess.Popen(cmd, stdout=outdata, stderr=subprocess.PIPE)
if filename is None:
self._record_handle = subprocess.Popen(cmd, stdout=subprocess.PIPE)
else:
with open(filename, "wb") as outdata:
self._record_handle = subprocess.Popen(cmd, stdout=outdata, stderr=subprocess.PIPE)
return self._record_handle

@Driver.check_active
Expand All @@ -90,6 +93,11 @@ def stop_record(self, *, timeout=None):
"""
try:
self._stop(self._record_handle, timeout=timeout)
except subprocess.TimeoutExpired:
# If live streaming packets, there is no reason to wait for tcpdump
# to finish, so expect a timeout if piping to stdout
if self._record_handle.stdout is None:
raise
finally:
self._record_handle = None

Expand All @@ -101,18 +109,18 @@ def record(self, filename, *, count=None, timeout=None):
Either count or timeout must be specified.
Args:
filename (str): name of a file to record to
filename (str): name of a file to record to, or None to live stream packets
count (int): optional, exit after receiving this many number of packets
timeout (int): optional, number of seconds to capture packets before tcpdump exits
Returns:
Popen object of tcpdump process.
Popen object of tcpdump process. If filename is None, packets can be read from stdout
"""
assert count or timeout

try:
yield self.start_record(filename, count=count, timeout=timeout)
finally:
self.stop_record()
self.stop_record(timeout=0 if filename is None else None)

@Driver.check_active
@step(args=["filename"])
Expand Down

0 comments on commit dcfa087

Please sign in to comment.