Ticket #29279: infer-throughput.py

File infer-throughput.py, 2.6 KB (added by phw, 3 months ago)

Python script to infer a download's throughput over time.

Line 
1#!/usr/bin/env python2
2"""
3Turn pcap into csv file.
4
5Problem:  A client is downloading a large file from a server and we want to
6          figure out if the throughput of the download degrades over time.
7
8Solution: We analyze the pcap file of the download and extract the ACK segments
9          that the client sends to the server.  From the ACK segments we can
10          infer how much data was transferred in a given time interval
11          (CUM_TIME_THRESHOLD).  We can then plot the number of downloaded
12          bytes per time interval and do a simple qualitative inspection.
13"""
14
15import sys
16
17import scapy.all as scapy
18
19# Change this to whatever client/server tuple you want to analyze.
20CLIENT_TUPLE = ("1.2.3.4", 1234)
21SERVER_TUPLE = ("4.3.2.1", 4321)
22
23# Number of seconds of our time intervals.
24CUM_TIME_THRESHOLD = 1
25
26
27def ignore_packet(packet):
28
29    # Make sure that we only inspect the given client and server IP
30    # addresses.
31    if not packet.haslayer(scapy.IP):
32        return True
33    if not packet[scapy.IP].src == CLIENT_TUPLE[0]:
34        return True
35    if not packet[scapy.IP].dst == SERVER_TUPLE[0]:
36        return True
37
38    # Make sure that we only inspect the given client and server TCP ports.
39    if not packet.haslayer(scapy.TCP):
40        return True
41    if not packet[scapy.TCP].sport == CLIENT_TUPLE[1]:
42        return True
43    if not packet[scapy.TCP].dport == SERVER_TUPLE[1]:
44        return True
45
46    # Make sure that we're only inspecting ACK segments.
47    if packet[scapy.TCP].flags != 16:
48        return True
49
50    return False
51
52
53def process_file(pcap_file):
54
55    prev_ack = None
56    prev_time = None
57    cum_time = 0
58    sent_bytes = 0
59
60    print "bytes,timestamp"
61    packets = scapy.rdpcap(pcap_file)
62    for packet in packets:
63
64        if ignore_packet(packet):
65            continue
66
67        # Remember timestamp and ACK number of the very first segment.
68        if prev_time is None and prev_ack is None:
69            prev_time = packet[scapy.TCP].time
70            prev_ack = packet[scapy.TCP].ack
71            continue
72
73        ack = packet[scapy.TCP].ack
74        sent_bytes += (ack - prev_ack)
75        cum_time += (packet[scapy.TCP].time - prev_time)
76
77        if cum_time > CUM_TIME_THRESHOLD:
78            print "%d,%.2f" % (sent_bytes, int(packet[scapy.TCP].time))
79            sent_bytes = 0
80            cum_time = 0
81
82        prev_ack = ack
83        prev_time = packet[scapy.TCP].time
84
85    return 0
86
87
88if __name__ == "__main__":
89
90    if len(sys.argv) != 2:
91        print >> sys.stderr, "\nUsage: %s PCAP_FILE\n" % sys.argv[0]
92        sys.exit(1)
93    pcap_file = sys.argv[1]
94
95    sys.exit(process_file(pcap_file))