Skip to content

Commit dcfa087

Browse files
JoshuaWattBastian-Krause
authored andcommitted
driver/rawnetworkinterfacedriver: implement live streaming
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]>
1 parent 4f6fe09 commit dcfa087

File tree

2 files changed

+18
-6
lines changed

2 files changed

+18
-6
lines changed

helpers/labgrid-raw-interface

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,10 @@ def main(program, options):
6060
if program == "tcpdump":
6161
args.append("-n")
6262
args.append(f"--interface={options.ifname}")
63+
# Write out each packet as it is received
64+
args.append("--packet-buffered")
65+
# Capture complete packets (for compatibility with older tcpdump versions)
66+
args.append("--snapshot-length=0")
6367
args.append("-w")
6468
args.append("-")
6569

labgrid/driver/rawnetworkinterfacedriver.py

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ def start_record(self, filename, *, count=None, timeout=None):
5959
Starts tcpdump on bound network interface resource.
6060
6161
Args:
62-
filename (str): name of a file to record to
62+
filename (str): name of a file to record to, or None to record to stdout
6363
count (int): optional, exit after receiving this many number of packets
6464
timeout (int): optional, number of seconds to capture packets before tcpdump exits
6565
Returns:
@@ -74,8 +74,11 @@ def start_record(self, filename, *, count=None, timeout=None):
7474
cmd.append("--timeout")
7575
cmd.append(str(timeout))
7676
cmd = self._wrap_command(cmd)
77-
with open(filename, "wb") as outdata:
78-
self._record_handle = subprocess.Popen(cmd, stdout=outdata, stderr=subprocess.PIPE)
77+
if filename is None:
78+
self._record_handle = subprocess.Popen(cmd, stdout=subprocess.PIPE)
79+
else:
80+
with open(filename, "wb") as outdata:
81+
self._record_handle = subprocess.Popen(cmd, stdout=outdata, stderr=subprocess.PIPE)
7982
return self._record_handle
8083

8184
@Driver.check_active
@@ -90,6 +93,11 @@ def stop_record(self, *, timeout=None):
9093
"""
9194
try:
9295
self._stop(self._record_handle, timeout=timeout)
96+
except subprocess.TimeoutExpired:
97+
# If live streaming packets, there is no reason to wait for tcpdump
98+
# to finish, so expect a timeout if piping to stdout
99+
if self._record_handle.stdout is None:
100+
raise
93101
finally:
94102
self._record_handle = None
95103

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

112120
try:
113121
yield self.start_record(filename, count=count, timeout=timeout)
114122
finally:
115-
self.stop_record()
123+
self.stop_record(timeout=0 if filename is None else None)
116124

117125
@Driver.check_active
118126
@step(args=["filename"])

0 commit comments

Comments
 (0)