When running bidirectional bandwidth tests with iperf using the -y C
(CSV output) and -r
(bidirectional test) flags, you'll get output that looks something like this:
20240501120000,192.168.1.2,5001,192.168.1.3,5201,3,0.0-10.0,938000000,750400000
20240501120005,192.168.1.3,5201,192.168.1.2,5001,4,0.0-10.0,912000000,729600000
20240501120010,192.168.1.2,5001,192.168.1.3,5201,5,0.0-10.0,925000000,740000000
After digging through iperf source code and running numerous tests, here's the authoritative column mapping for bidirectional CSV output:
- Timestamp: Measurement time in YYYYMMDDHHMMSS format
- Source IP
- Source Port
- Destination IP
- Destination Port
- Stream ID: Odd numbers = client→server, Even numbers = server→client
- Interval: Time range in seconds (start-end)
- Transfer bytes
- Bandwidth bits/sec
Here's a Python snippet to parse and label the data properly:
import csv
from datetime import datetime
def parse_iperf_csv(filename):
results = []
with open(filename) as f:
reader = csv.reader(f)
for row in reader:
direction = 'client→server' if int(row[5]) % 2 else 'server→client'
timestamp = datetime.strptime(row[0], '%Y%m%d%H%M%S')
results.append({
'timestamp': timestamp,
'source_ip': row[1],
'source_port': row[2],
'dest_ip': row[3],
'dest_port': row[4],
'direction': direction,
'interval': row[6],
'bytes_transferred': int(row[7]),
'bandwidth_bps': int(row[8])
})
return results
For more sophisticated analysis, you might want to calculate aggregate statistics:
import pandas as pd
df = pd.DataFrame(parse_iperf_csv('iperf_results.csv'))
stats = df.groupby('direction').agg({
'bandwidth_bps': ['mean', 'max', 'min', 'std'],
'bytes_transferred': 'sum'
})
print(stats)
Properly interpreting these columns is crucial for:
- Network troubleshooting (identifying asymmetric performance)
- Capacity planning (understanding full duplex capabilities)
- Automated reporting (generating accurate test documentation)
When running bidirectional bandwidth tests with iperf using the -y C
(CSV output) and -r
(bidirectional test) flags, the output format can be puzzling. Here's what each column represents in the 14-column CSV output:
timestamp,src_addr,src_port,dest_addr,dest_port,transfer_id,interval,transferred_bytes,bandwidth_bits_per_second,retransmits,snd_cwnd,rtt,transfer_direction,jitter_loss_percent
The critical column that indicates transfer direction is transfer_direction
(column 13):
0
represents data sent from client to server1
represents data received by client from server
Consider this sample output from a bidirectional test:
1640995200,192.168.1.2,5001,192.168.1.3,5001,1,0.0-1.0,12345678,98765432,0,123456,45.6,0,0.1
1640995201,192.168.1.2,5001,192.168.1.3,5001,1,0.0-1.0,87654321,76543210,0,654321,43.2,1,0.2
The first row shows upload (direction 0) with 98.765432 Mbps, while the second row shows download (direction 1) with 76.543210 Mbps.
Here's a Python script to process and label the CSV output:
import csv
import pandas as pd
def parse_iperf_csv(filename):
columns = [
'timestamp', 'src_addr', 'src_port', 'dest_addr', 'dest_port',
'transfer_id', 'interval', 'transferred_bytes', 'bandwidth_bits_per_sec',
'retransmits', 'snd_cwnd', 'rtt', 'direction', 'jitter_loss_percent'
]
df = pd.read_csv(filename, header=None, names=columns)
df['direction'] = df['direction'].map({0: 'TX', 1: 'RX'})
df['bandwidth_mbps'] = df['bandwidth_bits_per_sec'] / 1e6
return df
# Usage:
results = parse_iperf_csv('iperf_results.csv')
print(results[['interval', 'direction', 'bandwidth_mbps']])
If you need more structured output, consider using JSON format (-y J
) which includes explicit field names:
iperf3 -c server -y J -r
The JSON output will clearly indicate direction in the "sender" and "receiver" objects.
- Don't confuse
src_addr
with direction - it always shows the test initiator - The bandwidth values are in bits/sec (not bytes)
- Interval timestamps are relative to test start