mirror of
				https://github.com/Telecominfraproject/wlan-lanforge-scripts.git
				synced 2025-10-31 02:38:03 +00:00 
			
		
		
		
	wifi-diag: Better no-ack detection and some cleanup.
It now reports expected 'no-ack' frames at least in a fairly simplistic test case.
This commit is contained in:
		| @@ -6,11 +6,15 @@ use strict; | ||||
| use bignum; | ||||
| use bigint; | ||||
|  | ||||
| our $d_counter = 0; | ||||
|  | ||||
| sub new { | ||||
|   my $class = shift; | ||||
|   my %options = @_; | ||||
|  | ||||
|   my $self = { | ||||
| 	      ba_valid => 0, | ||||
| 	      dbg => "NA", | ||||
| 	      priority => "", | ||||
| 	      wmm_info => "", | ||||
| 	      raw_pkt => "", | ||||
| @@ -37,9 +41,28 @@ sub new { | ||||
| 	     }; | ||||
|  | ||||
|   bless($self, $class); | ||||
|  | ||||
|   if ($self->frame_num() == -1) { | ||||
|     $self->{dummy_counter} = $d_counter; | ||||
|     $d_counter++; | ||||
|     print "Creating dummy pkt: " . $self->{dummy_counter} . "\n"; | ||||
|   } | ||||
|   else { | ||||
|     $self->{dummy_counter} = -1; | ||||
|   } | ||||
|  | ||||
|   return($self); | ||||
| } | ||||
|  | ||||
| sub desc { | ||||
|   my $self = shift; | ||||
|   my $rv = $self->frame_num() . " len: " . $self->{bytes_on_wire}; | ||||
|   if ($self->frame_num() == -1) { | ||||
|     $rv = $rv . " dummy-counter: " . $self->{dummy_counter} . " dbg: " . $self->{dbg} | ||||
|   } | ||||
|   return $rv; | ||||
| } | ||||
|  | ||||
| sub raw_pkt { | ||||
|   my $self = shift; | ||||
|   return $self->{raw_pkt}; | ||||
| @@ -248,6 +271,35 @@ sub wants_ack { | ||||
|   if ($rb0 & 0x1) { | ||||
|     return 0;  # Don't ack bcast/bcast frames | ||||
|   } | ||||
|  | ||||
|   if ($self->type_subtype() eq "802.11 Block Ack (0x0019)") { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if ($self->type_subtype() eq "802.11 Block Ack Req (0x0018)") { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if ($self->type_subtype() eq "VHT NDP Announcement (0x0015)") { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if ($self->type_subtype() eq "Clear-to-send (0x001c)") { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if ($self->type_subtype() eq "Request-to-send (0x001b)") { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if ($self->type_subtype() eq "Acknowledgement (0x001d)") { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   if ($self->type_subtype() eq "Action No Ack (0x000e)") { | ||||
|     return 0; | ||||
|   } | ||||
|  | ||||
|   # TODO:  Need to parse QoS no-ack frames too, this will return false positives currently | ||||
|   return 1; | ||||
| } | ||||
|   | ||||
| @@ -81,40 +81,65 @@ sub find_or_create_tid { | ||||
|   return $tid; | ||||
| } | ||||
|  | ||||
| sub tx_no_ack_found { | ||||
| sub sum_tids { | ||||
|   my $self = shift; | ||||
|   my $var = shift; | ||||
|  | ||||
|   my $tid_count = @{$self->{tids}}; | ||||
|  | ||||
|   my $rv = 0; | ||||
|  | ||||
|   my $i; | ||||
|   for ($i = 0; $i < $tid_count; $i++) { | ||||
|     #print "Checking tid: $i\n"; | ||||
|     if (exists $self->{tids}[$i]) { | ||||
|       #print "Printing tid: $i\n"; | ||||
|       $rv += $self->{tids}[$i]->tx_no_ack_found(); | ||||
|       #print "Done printing tid: $i\n"; | ||||
|       if ($var == 0) { | ||||
| 	$rv += $self->{tids}[$i]->tx_no_ack_found_all(); | ||||
|       } | ||||
|       elsif ($var == 1) { | ||||
| 	$rv += $self->{tids}[$i]->tx_no_ack_found_big(); | ||||
|       } | ||||
|       elsif ($var == 2) { | ||||
| 	$rv += $self->{tids}[$i]->rx_no_ack_found_all(); | ||||
|       } | ||||
|       elsif ($var == 3) { | ||||
| 	$rv += $self->{tids}[$i]->rx_no_ack_found_big(); | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   return $rv; | ||||
| } | ||||
|  | ||||
| sub rx_no_ack_found { | ||||
| sub tx_no_ack_found_all { | ||||
|   my $self = shift; | ||||
|   return $self->sum_tids(0); | ||||
| } | ||||
|  | ||||
| sub tx_no_ack_found_big { | ||||
|   my $self = shift; | ||||
|   return $self->sum_tids(1); | ||||
| } | ||||
|  | ||||
| sub rx_no_ack_found_all { | ||||
|   my $self = shift; | ||||
|   return $self->sum_tids(2); | ||||
| } | ||||
|  | ||||
| sub rx_no_ack_found_big { | ||||
|   my $self = shift; | ||||
|   return $self->sum_tids(3); | ||||
| } | ||||
|  | ||||
| sub notify_done { | ||||
|   my $self = shift; | ||||
|   my $tid_count = @{$self->{tids}}; | ||||
|  | ||||
|   my $rv = 0; | ||||
|  | ||||
|   my $i; | ||||
|   for ($i = 0; $i < $tid_count; $i++) { | ||||
|     #print "Checking tid: $i\n"; | ||||
|     if (exists $self->{tids}[$i]) { | ||||
|       #print "Printing tid: $i\n"; | ||||
|       $rv += $self->{tids}[$i]->rx_no_ack_found(); | ||||
|       #print "Done printing tid: $i\n"; | ||||
|       $self->{tids}[$i]->check_remaining_pkts(); | ||||
|     } | ||||
|   } | ||||
|   return $rv; | ||||
| } | ||||
|  | ||||
| sub printme { | ||||
|   | ||||
| @@ -15,8 +15,10 @@ sub new { | ||||
|  | ||||
|   my $self = { | ||||
| 	      pkts => [], | ||||
| 	      rx_no_ack_found => 0, | ||||
| 	      tx_no_ack_found => 0, | ||||
| 	      rx_no_ack_found_all => 0, | ||||
| 	      rx_no_ack_found_big => 0, | ||||
| 	      tx_no_ack_found_all => 0, | ||||
| 	      tx_no_ack_found_big => 0, | ||||
| 	      tx_retrans_pkts => 0, | ||||
| 	      rx_retrans_pkts => 0, | ||||
| 	      tx_amsdu_retrans_pkts => 0, | ||||
| @@ -181,7 +183,8 @@ sub add_pkt { | ||||
| 	  $missing_str .= $missing_seqno . " "; | ||||
|  | ||||
| 	  # Add a dummy pkt | ||||
| 	  my $dummy = Packet->new(frame_num => -1, | ||||
| 	  my $dummy = Packet->new(dbg => "tid-add-pkt", | ||||
| 				  frame_num => -1, | ||||
| 				  receiver => $pkt->transmitter(), | ||||
| 				  transmitter => $pkt->receiver(), | ||||
| 				  data_subtype => "DUMMY_BA_ACKED", | ||||
| @@ -229,12 +232,25 @@ sub add_pkt { | ||||
| 	($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"; | ||||
| 	  if ($tmp->transmitter() eq $self->{addr_a}) { | ||||
| 	    $self->{tx_no_ack_found}++; | ||||
| 	    $self->{tx_no_ack_found_all}++; | ||||
| 	    if ($tmp->{bytes_on_wire} > 1000) { | ||||
| 	      print "WARNING:  did not find ack for BIG TX frame: " . $tmp->desc() . ", removing after processing frame: " . $pkt->frame_num() . "\n"; | ||||
| 	      $self->{tx_no_ack_found_big}++; | ||||
| 	    } | ||||
| 	    else { | ||||
| 	    $self->{rx_no_ack_found}++; | ||||
| 	      print "WARNING:  did not find ack for small TX frame: " . $tmp->desc() . ", removing after processing frame: " . $pkt->frame_num() . "\n"; | ||||
| 	    } | ||||
| 	  } | ||||
| 	  else { | ||||
| 	    $self->{rx_no_ack_found_all}++; | ||||
| 	    if ($tmp->{bytes_on_wire} > 1000) { | ||||
| 	      print "WARNING:  did not find ack for BIG RX frame: " . $tmp->desc() . ", removing after processing frame: " . $pkt->frame_num() . "\n"; | ||||
| 	      $self->{rx_no_ack_found_big}++; | ||||
| 	    } | ||||
| 	    else { | ||||
| 	      print "WARNING:  did not find ack for small RX frame: " . $tmp->desc() . ", removing after processing frame: " . $pkt->frame_num() . "\n"; | ||||
| 	    } | ||||
| 	  } | ||||
| 	} | ||||
|       } | ||||
| @@ -308,19 +324,65 @@ sub add_pkt { | ||||
|   push(@{$self->{pkts}}, $pkt); | ||||
| } | ||||
|  | ||||
| sub check_remaining_pkts { | ||||
|   my $self = shift; | ||||
|  | ||||
|   my $pkt_count = @{$self->{pkts}}; | ||||
|  | ||||
|   # Shift off old frames. | ||||
|   while ($pkt_count > 0) { | ||||
|     my $tmp = shift(@{$self->{pkts}}); | ||||
|     if (! $tmp->was_acked()) { | ||||
|       if ($tmp->wants_ack()) { | ||||
| 	if ($tmp->transmitter() eq $self->{addr_a}) { | ||||
| 	  $self->{tx_no_ack_found_all}++; | ||||
| 	  if ($tmp->{bytes_on_wire} > 1000) { | ||||
| 	    print "WARNING:  did not find ack for BIG TX frame: " . $tmp->desc() . ", removing at end of file.\n"; | ||||
| 	    $self->{tx_no_ack_found_big}++; | ||||
| 	  } | ||||
| 	  else { | ||||
| 	    print "WARNING:  did not find ack for small TX frame: " . $tmp->desc() . ", removing at end of file.\n"; | ||||
| 	  } | ||||
| 	} | ||||
| 	else { | ||||
| 	  $self->{rx_no_ack_found_all}++; | ||||
| 	  if ($tmp->{bytes_on_wire} > 1000) { | ||||
| 	    print "WARNING:  did not find ack for BIG RX frame: " . $tmp->desc() . ", removing at end of file.\n"; | ||||
| 	    $self->{rx_no_ack_found_big}++; | ||||
| 	  } | ||||
| 	  else { | ||||
| 	    print "WARNING:  did not find ack for small RX frame: " . $tmp->desc() . ", removing at end of file.\n"; | ||||
| 	  } | ||||
| 	} | ||||
|       } | ||||
|     } | ||||
|     $pkt_count--; | ||||
|   } | ||||
| } | ||||
|  | ||||
| sub get_pkts { | ||||
|   my $self = shift; | ||||
|   return @{$self->{pkts}}; | ||||
| } | ||||
|  | ||||
| sub tx_no_ack_found { | ||||
| sub tx_no_ack_found_all { | ||||
|   my $self = shift; | ||||
|   return $self->{tx_no_ack_found}; | ||||
|   return $self->{tx_no_ack_found_all}; | ||||
| } | ||||
|  | ||||
| sub rx_no_ack_found { | ||||
| sub tx_no_ack_found_big { | ||||
|   my $self = shift; | ||||
|   return $self->{rx_no_ack_found}; | ||||
|   return $self->{tx_no_ack_found_big}; | ||||
| } | ||||
|  | ||||
| sub rx_no_ack_found_all { | ||||
|   my $self = shift; | ||||
|   return $self->{rx_no_ack_found_all}; | ||||
| } | ||||
|  | ||||
| sub rx_no_ack_found_big { | ||||
|   my $self = shift; | ||||
|   return $self->{rx_no_ack_found_big}; | ||||
| } | ||||
|  | ||||
| sub printme { | ||||
| @@ -328,7 +390,8 @@ sub printme { | ||||
|   print "   tidno: " . $self->tidno() . " pkt-count: " . $self->get_pkts() | ||||
|     . " tx-pkts: " . $self->{tx_pkts} . " tx-retrans: " . $self->{tx_retrans_pkts} | ||||
|     . " rx-pkts: " . $self->{rx_pkts} . " rx-retrans: " . $self->{rx_retrans_pkts} | ||||
|     . " tx-no-acks: " . $self->{tx_no_ack_found} . " rx-no-acks: " . $self->{rx_no_ack_found} | ||||
|     . " tx-no-acks-all: " . $self->{tx_no_ack_found_all} . " tx-no-acks-big: " . $self->{tx_no_ack_found_big} | ||||
|     . " rx-no-acks-all: " . $self->{rx_no_ack_found_all} . " rx-no-acks-big: " . $self->{rx_no_ack_found_big} | ||||
|     . "\n"; | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -37,11 +37,11 @@ my $input_line_count = 0; | ||||
| my $pkts_sofar = 0; | ||||
| my $start_time = time(); | ||||
|  | ||||
| my $cur_pkt = Packet->new(raw_pkt => "", frame_num => -1); | ||||
| my $last_pkt = Packet->new(raw_pkt => "", frame_num => -1, is_rx => 0); | ||||
| my $first_ampdu_pkt = Packet->new(raw_pkt => "", frame_num => -1); | ||||
| my $last_ba_rx_pkt = Packet->new(raw_pkt => "", frame_num => -1); | ||||
| my $last_ba_tx_pkt = Packet->new(raw_pkt => "", frame_num => -1); | ||||
| my $cur_pkt = Packet->new(raw_pkt => "", frame_num => -1, dbg => "cur_pkt"); | ||||
| my $last_pkt = Packet->new(raw_pkt => "", frame_num => -1, is_rx => 0, dbg => "last_pkt"); | ||||
| my $first_ampdu_pkt = Packet->new(raw_pkt => "", frame_num => -1, dbg => "first_ampdu_pkt"); | ||||
| my $last_ba_rx_pkt = Packet->new(raw_pkt => "", frame_num => -1, dbg => "last_ba_rx_pkt"); | ||||
| my $last_ba_tx_pkt = Packet->new(raw_pkt => "", frame_num => -1, dbg => "last_ba_tx_pkt"); | ||||
|  | ||||
|  | ||||
| my $glb_fh_ba_tx; | ||||
| @@ -52,8 +52,10 @@ my $glb_fh_mcs_rx; | ||||
| my $glb_fh_rtx_tx; | ||||
| my $glb_fh_rtx_rx; | ||||
|  | ||||
| my $tx_no_ack_found = 0; | ||||
| my $rx_no_ack_found = 0; | ||||
| my $tx_no_ack_found_big = 0; | ||||
| my $rx_no_ack_found_big = 0; | ||||
| my $tx_no_ack_found_all = 0; | ||||
| my $rx_no_ack_found_all = 0; | ||||
|  | ||||
| my %glb_mcs_tx_hash = (); | ||||
| my %glb_mcs_rx_hash = (); | ||||
| @@ -187,8 +189,9 @@ while (<>) { | ||||
|       processPkt($cur_pkt); | ||||
|     } | ||||
|     $cur_pkt = Packet->new(frame_num => $1, | ||||
| 			   bytes_on_write => $2, | ||||
| 			   raw_pkt => $ln); | ||||
| 			   bytes_on_wire => $2, | ||||
| 			   raw_pkt => $ln, | ||||
| 			   dbg => "main-$1"); | ||||
|   } else { | ||||
|     $cur_pkt->append($ln); | ||||
|   } | ||||
| @@ -202,8 +205,11 @@ printProgress(); | ||||
|  | ||||
| # Sum up some stats | ||||
| for my $conn (values %peer_conns) { | ||||
|   $tx_no_ack_found += $conn->tx_no_ack_found(); | ||||
|   $rx_no_ack_found += $conn->rx_no_ack_found(); | ||||
|   $conn->notify_done(); | ||||
|   $tx_no_ack_found_big += $conn->tx_no_ack_found_big(); | ||||
|   $rx_no_ack_found_big += $conn->rx_no_ack_found_big(); | ||||
|   $tx_no_ack_found_all += $conn->tx_no_ack_found_all(); | ||||
|   $rx_no_ack_found_all += $conn->rx_no_ack_found_all(); | ||||
| } | ||||
|  | ||||
| $report_html .= genGlobalReports(); | ||||
| @@ -341,8 +347,10 @@ sub htmlMcsHistogram { | ||||
|   } | ||||
|   $html .= "TX (Big) Retransmit count: $tx_retrans_pkts_big<br>\n"; | ||||
|  | ||||
|   $html .= "RX no-ack-found: $rx_no_ack_found<br>\n"; | ||||
|   $html .= "TX no-ack-found: $tx_no_ack_found<br>\n"; | ||||
|   $html .= "RX (All) no-ack-found: $rx_no_ack_found_all<br>\n"; | ||||
|   $html .= "RX (Big) no-ack-found: $rx_no_ack_found_big<br>\n"; | ||||
|   $html .= "TX (All) no-ack-found: $tx_no_ack_found_all<br>\n"; | ||||
|   $html .= "TX (Big) no-ack-found: $tx_no_ack_found_big<br>\n"; | ||||
|  | ||||
|   if ($delta_time_tx_count) { | ||||
|     $html .= "TX average gap between AMPDU frames (ms): " . (($delta_time_tx * 1000.0) / $delta_time_tx_count) . "<br>\n"; | ||||
| @@ -584,22 +592,22 @@ sub processPkt { | ||||
|   if ($pkt->{is_ampdu} || $pkt->{is_msdu}) { | ||||
|     if ($last_pkt->frame_num() != -1 && (!($last_pkt->{is_ampdu} || $last_pkt->{is_msdu}))) { | ||||
|       # This is first ampdu since a non-ampdu frame.  Calculate diff between that and last BA | ||||
|       if ($pkt->{is_rx} && ($last_ba_tx_pkt->frame_num() != -1)) { | ||||
|       if ($pkt->{is_rx} && ($last_ba_tx_pkt->{ba_valid})) { | ||||
| 	my $diff = $pkt->timestamp() - $last_ba_tx_pkt->timestamp(); | ||||
| 	$ba_ampdu_gap_rx += $diff; | ||||
| 	$ba_ampdu_gap_rx_count++; | ||||
| 	if ($diff > 0.001) { | ||||
| 	  print "INFO:  TX BA to RX AMPDU gap: $diff between frames: " . $last_ba_tx_pkt->frame_num() . " and: " . $pkt->frame_num() . "\n"; | ||||
| 	} | ||||
| 	$last_ba_tx_pkt->{frame_num} = -1; | ||||
|       } elsif ((!$pkt->{is_rx}) && ($last_ba_rx_pkt->frame_num() != -1)) { | ||||
| 	$last_ba_tx_pkt->{ba_valid} = 0; | ||||
|       } elsif ((!$pkt->{is_rx}) && ($last_ba_rx_pkt->{ba_valid})) { | ||||
| 	my $diff = $pkt->timestamp() - $last_ba_rx_pkt->timestamp(); | ||||
| 	$ba_ampdu_gap_tx += $diff; | ||||
| 	$ba_ampdu_gap_tx_count++; | ||||
| 	if ($diff > 0.001) { | ||||
| 	  print "INFO:  RX BA to TX AMPDU gap: $diff between frames: " . $last_ba_rx_pkt->frame_num() . " and: " . $pkt->frame_num() . "\n"; | ||||
| 	} | ||||
| 	$last_ba_rx_pkt->{frame_num} = -1; | ||||
| 	$last_ba_rx_pkt->{ba_valid} = 0; | ||||
|       } | ||||
|     } | ||||
|  | ||||
| @@ -642,18 +650,20 @@ sub processPkt { | ||||
|     if ($pkt->type_subtype() eq "802.11 Block Ack (0x0019)") { | ||||
|       # Only grab the initial BA in case we have one side ignoring BA | ||||
|       if ($pkt->{is_rx}) { | ||||
| 	if ($last_ba_rx_pkt->{frame_num} == -1) { | ||||
| 	if (!$last_ba_rx_pkt->{ba_valid}) { | ||||
| 	  $last_ba_rx_pkt = $pkt; | ||||
| 	  $last_ba_rx_pkt->{ba_valid} = 1; | ||||
| 	} else { | ||||
| 	  print "NOTE:  Multiple RX block-acks seen without ampdu between them, first BA frame: " . $last_ba_rx_pkt->frame_num() | ||||
| 	    . " this BA frame num: " . $pkt->frame_num() . "\n"; | ||||
| 	  $dup_ba_rx++; | ||||
| 	} | ||||
|       } else { | ||||
| 	if ($last_ba_tx_pkt->{frame_num} == -1) { | ||||
| 	if (!$last_ba_tx_pkt->{ba_valid}) { | ||||
| 	  $last_ba_tx_pkt = $pkt; | ||||
| 	  $last_ba_tx_pkt->{ba_valid} = 1; | ||||
| 	} else { | ||||
| 	  print "NOTE:  Multiple TX block-acks seen without ampdu between them, first BA frame: " . $last_ba_rx_pkt->frame_num() | ||||
| 	  print "NOTE:  Multiple TX block-acks seen without ampdu between them, first BA frame: " . $last_ba_tx_pkt->frame_num() | ||||
| 	    . " this BA frame num: " . $pkt->frame_num() . "\n"; | ||||
| 	  $dup_ba_tx++; | ||||
| 	} | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ben Greear
					Ben Greear