hierarchy stats: Only increment the total packet count once per frame

The same hierarchy of protocols can appear multiple times in a frame,
for example if there are multiple PDUs for a protocol that begin in
that frame. Keep track of the last frame where we incremented our
stat node and use that to only increment it once per frame.

Add a "total number of PDUs with this hierarchy" statistic and
display it as a new final column in the GUI. Update the User Guide.

In the purpose of doing this, get rid of temporary variables and
increment the ph_stats_t members directly, since we pass that
into our functions already, and thus have access to the current
packet count.

Fix #17553. Fix #18034. Fix #12565.
This commit is contained in:
John Thacker 2022-04-07 23:44:27 -04:00
parent 4c7865c81b
commit 7a3c2252f5
6 changed files with 51 additions and 21 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 177 KiB

After

Width:  |  Height:  |  Size: 85 KiB

View File

@ -144,7 +144,7 @@ Percent Packets::
The percentage of protocol packets relative to all packets in the capture.
Packets::
The total number of packets of this protocol.
The total number of packets that contain this protocol.
Percent Bytes::
The percentage of protocol bytes relative to the total bytes in the capture.
@ -164,19 +164,23 @@ The absolute number of bytes of this protocol where it was the highest protocol
End Bits/s::
The bandwidth of this protocol relative to the capture time where was the highest protocol in the stack (last dissected).
Packets usually contain multiple protocols. As a result, more than one protocol will
be counted for each packet. Example: In the screenshot IP has 99.9% and TCP
98.5% (which is together much more than 100%).
PDUs::
The total number of PDUs of this protocol.
Packets usually contain multiple protocols. As a result, more than one protocol
will be counted for each packet. Example: In the screenshot 100% of packets
are IP and 99.3% are TCP (which is together much more than 100%).
Protocol layers can consist of packets that wont contain any higher layer
protocol, so the sum of all higher layer packets may not sum up to the protocols
packet count. Example: In the screenshot TCP has 98.5% but the sum of the
subprotocols (TLS, HTTP, etc.) is much less. This can be caused by continuation
frames, TCP protocol overhead, and other undissected data.
protocol, so the sum of all higher layer packets may not sum to the protocol's
packet count. This can be caused by segments and fragments reassembled in other
frames, TCP protocol overhead, and other undissected data. Example: In the
screenshot 99.3% of the packets are TCP but the sum of the subprotocols
(TLS, HTTP, Git, etc.) is much less.
A single packet can contain the same protocol more than once. In this case, the
protocol is counted more than once. For example, ICMP replies and many tunneling
protocols will carry more than one IP header.
entry in the `PDUs` column will be greater than that of `Packets`. Example:
In the screenshot there are many more TLS and Git PDUs than there are packets.
[#ChStatConversations]

View File

@ -68,9 +68,11 @@ find_stat_node(GNode *parent_stat_node, header_field_info *needle_hfinfo)
/* Intialize counters */
stats->hfinfo = needle_hfinfo;
stats->num_pkts_total = 0;
stats->num_pdus_total = 0;
stats->num_pkts_last = 0;
stats->num_bytes_total = 0;
stats->num_bytes_last = 0;
stats->last_pkt = 0;
needle_stat_node = g_node_new(stats);
g_node_append(parent_stat_node, needle_stat_node);
@ -102,7 +104,17 @@ process_node(proto_node *ptree_node, GNode *parent_stat_node, ph_stats_t *ps)
stat_node = find_stat_node(parent_stat_node, finfo->hfinfo);
stats = STAT_NODE_STATS(stat_node);
stats->num_pkts_total++;
/* Only increment the total packet count once per packet for a given
* node, since there could be multiple PDUs in a frame.
* (All the other statistics should be incremented every time,
* including the count for how often a protocol was the last
* protocol in a packet.)
*/
if (stats->last_pkt != ps->tot_packets) {
stats->num_pkts_total++;
stats->last_pkt = ps->tot_packets;
}
stats->num_pdus_total++;
stats->num_bytes_total += finfo->length;
}
@ -190,7 +202,6 @@ ph_stats_new(capture_file *cf)
ph_stats_t *ps;
guint32 framenum;
frame_data *frame;
guint tot_packets, tot_bytes;
progdlg_t *progbar = NULL;
gboolean stop_flag;
int count;
@ -225,9 +236,6 @@ ph_stats_new(capture_file *cf)
stop_flag = FALSE;
tot_packets = 0;
tot_bytes = 0;
wtap_rec_init(&rec);
ws_buffer_init(&buf, 1514);
@ -283,13 +291,20 @@ ph_stats_new(capture_file *cf)
if (frame->passed_dfilter) {
if (frame->has_ts) {
if (tot_packets == 0) {
if (ps->tot_packets == 0) {
double cur_time = nstime_to_sec(&frame->abs_ts);
ps->first_time = cur_time;
ps->last_time = cur_time;
}
}
/* We throw away the statistics if we quit in the middle,
* so increment this first so that the count starts at 1
* when processing records, since we initialize the stat
* nodes' last_pkt to 0.
*/
ps->tot_packets++;
/* we don't care about colinfo */
if (!process_record(cf, frame, NULL, &rec, &buf, ps)) {
/*
@ -301,8 +316,7 @@ ph_stats_new(capture_file *cf)
break;
}
tot_packets++;
tot_bytes += frame->pkt_len;
ps->tot_bytes += frame->pkt_len;
}
count++;
@ -326,9 +340,6 @@ ph_stats_new(capture_file *cf)
return NULL;
}
ps->tot_packets = tot_packets;
ps->tot_bytes = tot_bytes;
return ps;
}

View File

@ -24,9 +24,11 @@ extern "C" {
typedef struct {
header_field_info *hfinfo;
guint num_pkts_total;
guint num_pdus_total;
guint num_pkts_last;
guint num_bytes_total;
guint num_bytes_last;
guint last_pkt;
} ph_stats_node_t;

View File

@ -46,6 +46,7 @@ const int bandwidth_col_ = 5;
const int end_packets_col_ = 6;
const int end_bytes_col_ = 7;
const int end_bandwidth_col_ = 8;
const int pdus_col_ = 9;
class ProtocolHierarchyTreeWidgetItem : public QTreeWidgetItem
{
@ -53,6 +54,7 @@ public:
ProtocolHierarchyTreeWidgetItem(QTreeWidgetItem *parent, ph_stats_node_t& ph_stats_node) :
QTreeWidgetItem(parent),
total_packets_(ph_stats_node.num_pkts_total),
total_pdus_(ph_stats_node.num_pdus_total),
last_packets_(ph_stats_node.num_pkts_last),
total_bytes_(ph_stats_node.num_bytes_total),
last_bytes_(ph_stats_node.num_bytes_last),
@ -87,6 +89,7 @@ public:
setText(end_packets_col_, QString::number(last_packets_));
setText(end_bytes_col_, QString::number(last_bytes_));
setText(end_bandwidth_col_, seconds > 0.0 ? bits_s_to_qstring(end_bits_s_) : UTF8_EM_DASH);
setText(pdus_col_, QString::number(total_pdus_));
}
// Return a QString, int, double, or invalid QVariant representing the raw column data.
@ -110,6 +113,8 @@ public:
return last_bytes_;
case (end_bandwidth_col_):
return end_bits_s_;
case (pdus_col_):
return total_pdus_;
default:
break;
}
@ -137,6 +142,8 @@ public:
return last_bytes_ < other_phtwi.last_bytes_;
case end_bandwidth_col_:
return end_bits_s_ < other_phtwi.end_bits_s_;
case pdus_col_:
return total_pdus_ < other_phtwi.total_pdus_;
default:
break;
}
@ -150,6 +157,7 @@ public:
private:
QString filter_name_;
unsigned total_packets_;
unsigned total_pdus_;
unsigned last_packets_;
unsigned total_bytes_;
unsigned last_bytes_;

View File

@ -70,6 +70,11 @@
<string>End Bits/s</string>
</property>
</column>
<column>
<property name="text">
<string>PDUs</string>
</property>
</column>
</widget>
</item>
<item>