Decoding Iperf CSV Output: Understanding Bidirectional Transfer Data Columns with -y C and -r Flags


3 views

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:

  1. Timestamp: Measurement time in YYYYMMDDHHMMSS format
  2. Source IP
  3. Source Port
  4. Destination IP
  5. Destination Port
  6. Stream ID: Odd numbers = client→server, Even numbers = server→client
  7. Interval: Time range in seconds (start-end)
  8. Transfer bytes
  9. 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 server
  • 1 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