From 7dbbcd501b708a53ee68e30ea99f52fed3386fa4 Mon Sep 17 00:00:00 2001 From: Ben Greear Date: Fri, 5 Oct 2018 14:25:16 -0700 Subject: [PATCH] wifi-diag: reporting data. --- wifi_diag/Packet.pm | 10 ++- wifi_diag/PeerConn.pm | 6 +- wifi_diag/Tid.pm | 150 ++++++++++++++++++++++++++++++++---- wifi_diag/wifi_pcap_diag.pl | 77 +++++++++++++++++- 4 files changed, 225 insertions(+), 18 deletions(-) diff --git a/wifi_diag/Packet.pm b/wifi_diag/Packet.pm index f66af665..a0d2db9e 100644 --- a/wifi_diag/Packet.pm +++ b/wifi_diag/Packet.pm @@ -8,6 +8,7 @@ sub new { my %options = @_; my $self = { + raw_pkt => "", seqno => -1, # block-ack will not have a seqno acked_by => -1, block_acked_by => -1, @@ -63,6 +64,7 @@ sub append { $self->{ba_starting_seq} = $1; } elsif ($ln =~ /.* = TID for which a Basic BlockAck frame is requested: (\S+)/) { + #print STDERR "tid: $1\n"; $self->{ba_tid} = hex($1); } elsif ($ln =~ /^\s*Block Ack Bitmap: (\S+)/) { @@ -195,7 +197,13 @@ sub was_acked { sub wants_ack { my $self = shift; - my $rcvr_b0 = substring(self->receiver(), 0, 1); + my $rcvr_b0 = substr($self->receiver(), 0, 1); + if ($rcvr_b0 eq "U") { + #print STDERR "wants-ack, receiver: " . $self->receiver() . "\n"; + #print STDERR $self->raw_pkt() . "\n"; + #exit(1); + return 0; + } my $rb0 = hex("$rcvr_b0"); if ($rb0 & 0x1) { return 0; # Don't ack bcast/bcast frames diff --git a/wifi_diag/PeerConn.pm b/wifi_diag/PeerConn.pm index 03ae772c..642a2961 100644 --- a/wifi_diag/PeerConn.pm +++ b/wifi_diag/PeerConn.pm @@ -16,7 +16,7 @@ sub new { bless($self, $class); - my $mcs_fname = $self->hash_str() . "-rpt.txt"; + my $mcs_fname = $self->{report_prefix} . "conn-" . $self->hash_str() . "-rpt.txt"; open(my $MCS, ">", $mcs_fname) or die("Can't open $mcs_fname for writing: $!\n"); $self->{mcs_fh} = $MCS; @@ -62,7 +62,9 @@ sub find_or_create_tid { $tid = $self->{tids}[$tidno]; } else { - $tid = Tid->new(tidno => $tidno, + $tid = Tid->new(glb_fh_ba => $self->{glb_fh_ba}, + tidno => $tidno, + report_prefix => $self->{report_prefix}, addr_a => $self->local_addr(), addr_b => $self->peer_addr(), ); diff --git a/wifi_diag/Tid.pm b/wifi_diag/Tid.pm index e4819838..bb686d4e 100644 --- a/wifi_diag/Tid.pm +++ b/wifi_diag/Tid.pm @@ -2,9 +2,11 @@ package Tid; use warnings; use strict; + use bigint; my $warn_dup_ba_once = 1; +my $max_pkt_store = 250; sub new { my $class = shift; @@ -12,20 +14,49 @@ sub new { my $self = { pkts => [], - tx_retrans => 0, - rx_retrans => 0, + tx_retrans_pkts => 0, + rx_retrans_pkts => 0, + tx_amsdu_retrans_pkts => 0, + rx_amsdu_retrans_pkts => 0, rx_pkts => 0, tx_pkts => 0, + rx_amsdu_pkts => 0, + tx_amsdu_pkts => 0, + dummy_rx_pkts => 0, + dummy_tx_pkts => 0, tot_pkts => 0, + last_tot_pks => 0, + last_rx_pks => 0, + last_tx_pks => 0, + last_rx_retrans_pks => 0, + last_tx_retrans_pks => 0, + last_dummy_rx_pks => 0, + last_dummy_tx_pks => 0, + last_ps_timestamp => 0, + last_rx_amsdu_pkts => 0, + last_tx_amsdu_pkts => 0, + last_tx_amsdu_retrans_pkts => 0, + last_rx_amsdu_retrans_pkts => 0, %options, }; bless($self, $class); - my $rpt_fname = $self->{addr_a} . "." . $self->{addr_b} . "-" . $self->tidno() . "-" . "rpt.txt"; + my $rpt_fname = $self->{report_prefix} . + "tid-" . $self->tidno() . "-" . + $self->{addr_a} . "." . + $self->{addr_b} . "-rpt.txt"; open(my $MCS, ">", $rpt_fname) or die("Can't open $rpt_fname for writing: $!\n"); $self->{mcs_fh} = $MCS; + $rpt_fname = $self->{report_prefix} . "tid-" . $self->tidno() . "-" . $self->{addr_a} . "." . $self->{addr_b} . "-ps-rpt.txt"; + open(my $MCS_PS, ">", $rpt_fname) or die("Can't open $rpt_fname for writing: $!\n"); + $self->{mcs_fh_ps} = $MCS_PS; + + $rpt_fname = $self->{report_prefix} . "tid-" . $self->tidno() . "-" . $self->{addr_a} . "." . $self->{addr_b} . "-ba-rpt.txt"; + open(my $BA, ">", $rpt_fname) or die("Can't open $rpt_fname for writing: $!\n"); + $self->{fh_ba} = $BA; + return $self; } @@ -41,19 +72,31 @@ sub add_pkt { $self->{tot_pkts}++; if ($pkt->receiver() eq $self->{addr_a}) { $self->{rx_pkts}++; + $self->{rx_amsdu_pkts} += $pkt->{amsdu_frame_count}; if ($pkt->retrans()) { - $self->{rx_retrans}++; + $self->{rx_retrans_pkts}++; + $self->{rx_amsdu_retrans_pkts} += $pkt->{amsdu_frame_count} } } else { $self->{tx_pkts}++; - $self->{tx_retrans}++; + $self->{tx_amsdu_pkts} += $pkt->{amsdu_frame_count}; + if ($pkt->retrans()) { + $self->{tx_retrans_pkts}++; + $self->{tx_amsdu_retrans_pkts} += $pkt->{amsdu_frame_count}; + } + } + + if ($self->{last_ps_timestamp} == 0) { + $self->{last_ps_timestamp} = $pkt->timestamp(); } my $pkt_count = @{$self->{pkts}}; # If this is a block-ack, then check for previous frames that would match. if ($pkt->type_subtype() eq "802.11 Block Ack (0x0019)") { + my $ba_dup = 0; + my $ba_tot = 0; my $transmitter = $pkt->transmitter(); my $starting_seqno = $pkt->{ba_starting_seq}; my $i; @@ -61,10 +104,12 @@ sub add_pkt { my $bi_as_long = 0; my $bi_mask = 0; my $q; + my $last_timestamp = 0; + for ($q = 0; $q < 8; $q++) { my $bmap_octet = substr($bitmap, $q * 2, 2); my $bmi = hex($bmap_octet); - #print "bmap-octet: $bmap_octet bmi: " . hex($bmi) . "\n"; + #print STDERR "bmap-octet: $bmap_octet bmi: " . hex($bmi) . "\n"; $bi_as_long |= ($bmi << ($q * 8)); } @@ -89,12 +134,22 @@ sub add_pkt { $tmp->frame_num() . " already block-acked by frame: " . $tmp->block_acked_by() . ". This warning will not be shown again.\n"; $warn_dup_ba_once = 0; } + $ba_dup++; } elsif ($tmp->acked_by() != -1) { print "WARNING: block-ack frame: " . $pkt->frame_num() . " acking frame: " . $tmp->frame_num() . " already acked by frame: " . $tmp->acked_by() . "\n"; } $tmp->set_block_acked_by($pkt->frame_num()); + $ba_tot++; + + # Only calculate timestamp if previous packet was last one ACKd and it is not a dummy + # otherwise we probably failed to capture some frames. + if ($i == ($pkt_count - 1)) { + if ($tmp->{raw_pkt} ne "") { + $last_timestamp = $tmp->timestamp(); + } + } } } } @@ -110,39 +165,108 @@ sub add_pkt { $missing_str .= $missing_seqno . " "; # Add a dummy pkt - my $dummy = Packet->new(transmitter => $pkt->receiver(), + my $dummy = Packet->new(frame_num => -1, + receiver => $pkt->transmitter(), + transmitter => $pkt->receiver(), data_subtype => "DUMMY_BA_ACKED", timestamp => $pkt->timestamp(), seqno => $missing_seqno, tid => $self->tidno()); - $dummy->block_acked_by($pkt->frame_num()); + $dummy->set_block_acked_by($pkt->frame_num()); push(@{$self->{pkts}}, $dummy); + if ($pkt->transmitter() eq $self->{addr_b}) { + $self->{dummy_rx_pkts}++; + } + else { + $self->{dummy_tx_pkts}++; + } #print "pushing dummy pkt, seqno: $missing_seqno\n"; + $ba_tot++; } } print "WARNING: block-ack frame: " . $pkt->frame_num() . " acked frames we did not capture, found-these: " . $bi_mask->as_hex . " acked these: " . $bi_as_long->as_hex . " missing: " . $missing->as_hex . "($missing_str), starting-seq-no: $starting_seqno\n"; } - } + + my $new_ba = $ba_tot - $ba_dup; + my $fh_ba = $self->{fh_ba}; + my $glb = $self->{glb_fh_ba}; + my $ts_diff; + if ($last_timestamp == 0) { + $ts_diff = "0.0"; + } + else { + $ts_diff = sprintf("%.10f", $pkt->timestamp() - $last_timestamp); + } + my $ln = "" . $pkt->timestamp() . "\t" . $self->tidno() . "\t$ba_tot\t$ba_dup\t$new_ba\t$ts_diff\n"; + + print $fh_ba $ln; # Tid specific data file + print $glb $ln; # Global data file + }# if block-ack frame # Shift off old frames. while ($pkt_count > 0) { my $tmp = shift(@{$self->{pkts}}); if (($tmp->timestamp() + 60 < $pkt->timestamp()) || - ($pkt_count > 1000)) { + ($pkt_count > $max_pkt_store)) { if (! $tmp->was_acked()) { if ($tmp->wants_ack()) { print "WARNING: did not find ack for frame: " . $tmp->frame_num() . ", removing after processing frame: " . $pkt->frame_num() . "\n"; } } $pkt_count--; - next; # Drop frames when we have more than 1000 or they are older than 1 minute ago + next; # Drop frames when we have more than $max_pkt_store or they are older than 1 minute ago } # Put this one back on unshift(@{$self->{pkts}}, $tmp); last; } + if ($self->{last_ps_timestamp} + 1.0 < $pkt->{timestamp}) { + my $diff = $pkt->{timestamp} - $self->{last_ps_timestamp}; + my $period_tot_pkts = $self->{tot_pkts} - $self->{last_tot_pkts}; + my $period_rx_pkts = $self->{rx_pkts} - $self->{last_rx_pkts}; + my $period_rx_amsdu_pkts = $self->{rx_amsdu_pkts} - $self->{last_rx_amsdu_pkts}; + my $period_rx_retrans_pkts = $self->{rx_retrans_pkts} - $self->{last_rx_retrans_pkts}; + my $period_rx_retrans_amsdu_pkts = $self->{rx_retrans_amsdu_pkts} - $self->{last_rx_retrans_amsdu_pkts}; + my $period_tx_pkts = $self->{tx_pkts} - $self->{last_tx_pkts}; + my $period_tx_amsdu_pkts = $self->{tx_amsdu_pkts} - $self->{last_tx_amsdu_pkts}; + my $period_tx_retrans_pkts = $self->{tx_retrans_pkts} - $self->{last_tx_retrans_pkts}; + my $period_tx_retrans_amsdu_pkts = $self->{tx_retrans_amsdu_pkts} - $self->{last_tx_retrans_amsdu_pkts}; + my $period_dummy_rx_pkts = $self->{dummy_rx_pkts} - $self->{last_dummy_rx_pkts}; + my $period_dummy_tx_pkts = $self->{dummy_tx_pkts} - $self->{last_dummy_tx_pkts}; + + my $period_tot_pkts_ps = $period_tot_pkts / $diff; + my $period_rx_pkts_ps = $period_rx_pkts / $diff; + my $period_rx_amsdu_pkts_ps = $period_rx_amsdu_pkts / $diff; + my $period_rx_retrans_pkts_ps = $period_rx_retrans_pkts / $diff; + my $period_rx_retrans_amsdu_pkts_ps = $period_rx_retrans_amsdu_pkts / $diff; + my $period_tx_pkts_ps = $period_tx_pkts / $diff; + my $period_tx_amsdu_pkts_ps = $period_tx_amsdu_pkts / $diff; + my $period_tx_retrans_pkts_ps = $period_tx_retrans_pkts / $diff; + my $period_tx_retrans_amsdu_pkts_ps = $period_tx_retrans_amsdu_pkts / $diff; + my $period_dummy_rx_pkts_ps = $period_dummy_rx_pkts / $diff; + my $period_dummy_tx_pkts_ps = $period_dummy_tx_pkts / $diff; + + $self->{last_ps_timestamp} = $pkt->timestamp(); + $self->{last_tot_pkts} = $self->{tot_pkts}; + $self->{last_rx_pkts} = $self->{rx_pkts}; + $self->{last_rx_amsdu_pkts} = $self->{rx_amsdu_pkts}; + $self->{last_rx_retrans_pkts} = $self->{rx_retrans_pkts}; + $self->{last_rx_retrans_amsdu_pkts} = $self->{rx_retrans_amsdu_pkts}; + $self->{last_tx_pkts} = $self->{tx_pkts}; + $self->{last_tx_amsdu_pkts} = $self->{tx_amsdu_pkts}; + $self->{last_tx_retrans_pkts} = $self->{tx_retrans_pkts}; + $self->{last_tx_retrans_amsdu_pkts} = $self->{tx_retrans_amsdu_pkts}; + $self->{last_dummy_rx_pkts} = $self->{dummy_rx_pkts}; + $self->{last_dummy_tx_pkts} = $self->{dummy_tx_pkts}; + + my $fh_ps = $self->{mcs_fh_ps}; + print $fh_ps "" . $pkt->timestamp() . "\t" . $self->tidno() . "\t$diff\t$period_tot_pkts_ps\t" . + "$period_rx_pkts_ps\t$period_rx_retrans_pkts_ps\t$period_rx_amsdu_pkts_ps\t$period_rx_retrans_amsdu_pkts_ps\t$period_dummy_rx_pkts_ps\t" . + "$period_tx_pkts_ps\t$period_tx_retrans_pkts_ps\t$period_tx_amsdu_pkts_ps\t$period_tx_retrans_amsdu_pkts_ps\t$period_dummy_tx_pkts_ps\n"; + } + # Generate reporting data for this pkt my $fh = $self->{mcs_fh}; print $fh "" . $pkt->timestamp() . "\t" . $self->tidno() . "\t" . $pkt->datarate() . "\t" . $pkt->retrans() . "\n"; @@ -158,8 +282,8 @@ sub get_pkts { sub printme { my $self = shift; print " tidno: " . $self->tidno() . " pkt-count: " . $self->get_pkts() - . " tx-pkts: " . $self->{tx_pkts} . " tx-retrans: " . $self->{tx_retrans} - . " rx-pkts: " . $self->{rx_pkts} . " rx-retrans: " . $self->{rx_retrans} . "\n"; + . " tx-pkts: " . $self->{tx_pkts} . " tx-retrans: " . $self->{tx_retrans_pkts} + . " rx-pkts: " . $self->{rx_pkts} . " rx-retrans: " . $self->{rx_retrans_pkts} . "\n"; } 1; diff --git a/wifi_diag/wifi_pcap_diag.pl b/wifi_diag/wifi_pcap_diag.pl index f5dd2627..a9604220 100755 --- a/wifi_diag/wifi_pcap_diag.pl +++ b/wifi_diag/wifi_pcap_diag.pl @@ -10,11 +10,45 @@ use Carp; use PeerConn; use Packet; +use Getopt::Long; my %peer_conns = (); +my $pkts_sofar = 0; +my $start_time = time(); + my $cur_pkt = Packet->new(raw_pkt => ""); my $last_pkt = Packet->new(raw_pkt => ""); +my $glb_fh_ba; + +my $dut = ""; +my $report_prefix = "wifi-diag-"; +my $non_dut_frames = 0; +my $show_help = 0; + +my $usage = "$0 +--dut {bssid-of-DUT} # Orient reports with this as upstream peer (lower-case MAC address) +--report_prefix {string} # Prefix used for report files (default is $report_prefix) +--help # Show this help info. +"; + + +GetOptions +( + 'help|h' => \$show_help, + 'dut=s' => \$dut, + 'report_prefix=s' => \$report_prefix, + ) || (print($usage) && exit(1)); + + +if ($show_help) { + print $usage; + exit 0 +} + +my $rpt_fname = $report_prefix . "glb-ba-rpt.txt"; +open($glb_fh_ba, ">", $rpt_fname) or die("Can't open $rpt_fname for writing: $!\n"); + while (<>) { my $ln = $_; @@ -34,14 +68,29 @@ if ($cur_pkt->raw_pkt() ne "") { processPkt($cur_pkt); } +printProgress(); + # Print out all peer-conns we found for my $conn (values %peer_conns) { $conn->printme(); $conn->gen_graphs(); } +if ($dut ne "") { + print "NON-DUT frames in capture: $non_dut_frames\n"; +} + exit 0; +sub printProgress { + my $now = time(); + my $diff_sec = $now - $start_time; + my $hour = int($diff_sec / (60 * 60)); + my $min = int($diff_sec / 60); + my $sec = $diff_sec - ($hour * 60 * 60 + $min * 60); + my $pps = int($pkts_sofar / $diff_sec); + print STDERR "NOTE: Processed $pkts_sofar packets in $hour:$min:$sec far ($pps pps).\n"; +} sub processPkt { my $pkt = shift; @@ -51,6 +100,11 @@ sub processPkt { # Add graph point for retransmits # Check sequence-no gap + $pkts_sofar++; + if (($pkts_sofar % 10000) == 0) { + printProgress(); + } + # If pkt is an ACK, it will not have a sender address. Guess based on # previous packet. if ($pkt->type_subtype() eq "Acknowledgement (0x001d)") { @@ -75,6 +129,15 @@ sub processPkt { } } + if ($dut ne "") { + # Ignore frames not to/from DUT + if (!(($dut eq $pkt->receiver()) || + ($dut eq $pkt->transmitter()))) { + $non_dut_frames++; + return; + } + } + my $hash = $pkt->receiver() . "." . $pkt->transmitter(); my $hash2 = $pkt->transmitter() . "." . $pkt->receiver(); @@ -87,8 +150,18 @@ sub processPkt { $peer_conn = $peer_conns{$hash2}; } else { - $peer_conn = PeerConn->new(local_addr => $pkt->receiver(), - peer_addr => $pkt->transmitter()); + if ($dut eq $pkt->receiver()) { + $peer_conn = PeerConn->new(glb_fh_ba => $glb_fh_ba, + report_prefix => $report_prefix, + local_addr => $pkt->transmitter(), + peer_addr => $pkt->receiver()); + } + else { + $peer_conn = PeerConn->new(glb_fh_ba => $glb_fh_ba, + report_prefix => $report_prefix, + local_addr => $pkt->receiver(), + peer_addr => $pkt->transmitter()); + } $peer_conns{$hash} = $peer_conn; } }