Clarify how the stats_tree flags are used. Some are for the entire tree, some can be set on nodes, and some are internal use only. All of them have to not overlap with the generic tapping system flags for some reason. Update the README for some recent changes adding tap flags to the per packet routine and changing the directory separator to being a double forward slash. ST_FLG_SORT_DESC had backwards comment text, but has always indicated that descending order was to be used (at least in the tshark CLI tap, and in various functions, and in how the preference was interprted, even if the Qt GUI didn't respect it previously.) Also, packet-ltp was using the sort ordering incorrectly, and probably didn't intend for counts to be ascending, so remove it. (It wasn't doing anything other than actually requesting the tap columns, which it didn't need, and the default order of descending count was used.) Fix #20038
271 lines
10 KiB
Plaintext
271 lines
10 KiB
Plaintext
tapping with stats_tree
|
|
|
|
Let's suppose that you want to write a tap only to keep counters, and you
|
|
don't want to get involved with GUI programming or maybe you'd like to make
|
|
it a plugin. A stats_tree might be the way to go. The stats_tree module takes
|
|
care of the representation (GUI for Wireshark and text for TShark) of the
|
|
tap data. So there's very little code to write to make a tap listener usable
|
|
from both Wireshark and TShark.
|
|
|
|
First, you should add the TAP to the dissector in question as described in
|
|
README.tapping .
|
|
|
|
Once the dissector in question is "tapped" you have to write the stats tree
|
|
code which is made of three parts:
|
|
|
|
The init callback routine:
|
|
which will be executed before any packet is passed to the tap. Here you
|
|
should create the "static" nodes of your tree. As well as initialize your
|
|
data.
|
|
|
|
The (per)packet callback routine:
|
|
As the tap_packet callback is going to be called for every packet, it
|
|
should be used to increment the counters.
|
|
|
|
The cleanup callback:
|
|
It is called at the destruction of the stats_tree and might be used to
|
|
free ....
|
|
|
|
Other than that the stats_tree should be registered.
|
|
|
|
If you want to make it a plugin, stats_tree_register() should be called by
|
|
plugin_register_tap_listener() read README.plugins for other information
|
|
regarding Wireshark plugins.
|
|
|
|
If you want it as part of the dissector stats_tree_register() can be called
|
|
either by proto_register_xxx() or if you prefer by proto_reg_handoff_xxx().
|
|
|
|
|
|
A small example of a very basic stats_tree plugin follows.
|
|
|
|
----- example stats_tree plugin ------
|
|
/* udpterm_stats_tree.c
|
|
* A small example of stats_tree plugin that counts udp packets by termination
|
|
* 2005, Luis E. G. Ontanon
|
|
*
|
|
* Wireshark - Network traffic analyzer
|
|
* By Gerald Combs <gerald@wireshark.org>
|
|
* Copyright 1998 Gerald Combs
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <gmodule.h>
|
|
|
|
#include <epan/stats_tree.h>
|
|
#include <epan/dissectors/udp.h>
|
|
|
|
static int st_udp_term;
|
|
static char* st_str_udp_term = "UDP terminations";
|
|
|
|
/* this one initializes the tree, creating the root nodes */
|
|
extern void udp_term_stats_tree_init(stats_tree* st) {
|
|
/* we create a node under which we'll add every termination */
|
|
st_udp_term = stats_tree_create_node(st, st_str_udp_term, 0, STAT_DT_INT, true);
|
|
}
|
|
|
|
/* this one will be called with every udp packet */
|
|
extern tap_packet_status
|
|
udp_term_stats_tree_packet(stats_tree *st, /* st as it was passed to us */
|
|
packet_info *pinfo, /* we'll fetch the addresses from here */
|
|
epan_dissect_t *edt _U_, /* unused */
|
|
const void *p, /* we'll use this to fetch the ports */
|
|
tap_flags_t flags _U_) /* unused */
|
|
{
|
|
static uint8_t str[128];
|
|
e_udphdr* udphdr = (e_udphdr*) p;
|
|
|
|
/* we increment by one (tick) the root node */
|
|
tick_stat_node(st, st_str_udp_term, 0, false);
|
|
|
|
/* we then tick a node for this src_addr:src_port
|
|
if the node doesn't exists it will be created */
|
|
snprintf(str, sizeof(str),"%s:%u",address_to_str(&pinfo->net_src),udphdr->sport);
|
|
tick_stat_node(st, str, st_udp_term, false);
|
|
|
|
/* same thing for dst */
|
|
snprintf(str, sizeof(str),"%s:%u",address_to_str(&pinfo->net_dst),udphdr->dport);
|
|
tick_stat_node(st, str, st_udp_term, false);
|
|
|
|
return 1;
|
|
}
|
|
|
|
WS_DLL_PUBLIC_DEF const char version[] = "0.0";
|
|
|
|
WS_DLL_PUBLIC_DEF void plugin_register_tap_listener(void) {
|
|
|
|
stats_tree_register_plugin("udp", /* the proto we are going to "tap" */
|
|
"udp_terms", /* the abbreviation for this tree (to be used as -z udp_terms,tree) */
|
|
st_str_udp_term, /* the name of the menu and window (use "//" for sub menus)*/
|
|
0, /* tap listener flags for per-packet callback */
|
|
udp_term_stats_tree_packet, /* the per packet callback */
|
|
udp_term_stats_tree_init, /* the init callback */
|
|
NULL ); /* the cleanup callback (in this case there isn't) */
|
|
|
|
}
|
|
|
|
----- END ------
|
|
|
|
the stats_tree API
|
|
==================
|
|
every stats_tree callback has a stats_tree* parameter (st), stats_tree is an obscure
|
|
data structure which should be passed to the api functions.
|
|
|
|
stats_tree_register(tapname, abbr, name, flags, packet_cb, init_cb, cleanup_cb);
|
|
registers a new stats tree with default group REGISTER_STAT_GROUP_UNSORTED
|
|
|
|
stats_tree_register_plugin(tapname, abbr, name, flags, packet_cb, init_cb, cleanup_cb);
|
|
registers a new stats tree from a plugin with the default group REGISTER_STAT_GROUP_UNSORTED
|
|
|
|
stats_tree_set_group(st_config, stat_group);
|
|
changes the menu statistics group for a stats tree
|
|
|
|
stats_tree_parent_id_by_name( st, parent_name)
|
|
returns the id of a candidate parent node given its name
|
|
|
|
flags
|
|
is a bitmask set of flags for the tap listener. Generic tap system flags
|
|
(TL_*) described in README.tapping can be used, along with stat tree specific
|
|
flags that control the default sorting, six for choosing the column and one
|
|
for the order:
|
|
|
|
ST_SORT_COL_NAME
|
|
Sort nodes by node names
|
|
ST_SORT_COL_COUNT
|
|
Sort nodes by node count
|
|
ST_SORT_COL_AVG
|
|
Sort nodes by node average
|
|
ST_SORT_COL_MIN
|
|
Sort nodes by minimum node value
|
|
ST_SORT_COL_MAX
|
|
Sort nodes by maximum node value
|
|
ST_SORT_COL_BURSTRATE
|
|
Sort nodes by burst rate
|
|
|
|
ST_FLG_SORT_DESC
|
|
Sort nodes in descending order using the chosen column
|
|
The default if only a column is given is to use ascending
|
|
order
|
|
|
|
The sort column flags need to be left shifted by ST_FLG_SRTCOL_SHIFT when
|
|
registering. If no sort columns flags are given, values from the preferences
|
|
(found in the "Statistics" module) are used for both column and order. The
|
|
default preferences are to sort in descending order of node count, i.e.,
|
|
(ST_SORT_COL_COUNT << ST_FLG_SRTCOL_SHIFT) | ST_FLG_SORT_DESC
|
|
|
|
Node functions
|
|
==============
|
|
|
|
All the functions that operate on nodes return a parent_id
|
|
|
|
stats_tree_create_node(st, name, parent_id, datatype, with_children)
|
|
Creates a node in the tree (to be used in the in init_cb)
|
|
name: the name of the new node
|
|
parent_id: the id of the parent_node (NULL for root)
|
|
datatype: datatype of the new node, STAT_DT_INT or STAT_DT_FLOAT. The only
|
|
methods implemented for floats are averages.
|
|
with_children: true if this node will have "dynamically created" children
|
|
(i.e. it will be a candidate parent)
|
|
|
|
|
|
stats_tree_create_node_by_pname(st, name, parent_name, datatype, with_children);
|
|
As before but creates a node using its parent's name
|
|
|
|
|
|
stats_tree_create_range_node(st, name, parent_id, ...)
|
|
stats_tree_create_range_node_string(st, name, parent_id, num_str_ranges, str_ranges)
|
|
stats_tree_range_node_with_pname(st, name, parent_name, ...)
|
|
Creates a node in the tree, that will contain a ranges list.
|
|
example:
|
|
stats_tree_create_range_node(st,name,parent_id,
|
|
"-99","100-199","200-299","300-399","400-", NULL);
|
|
|
|
stats_tree_tick_range(st, name, parent_id, value_in_range);
|
|
stats_tree_tick_range_by_pname(st, name, parent_name, value_in_range)
|
|
Increases by one the ranged node and the sub node to whose range the value belongs
|
|
|
|
|
|
stats_tree_create_pivot(st, name, parent_id);
|
|
stats_tree_create_pivot_by_pname(st, name, parent_name);
|
|
Creates a "pivot node"
|
|
|
|
stats_tree_tick_pivot(st, pivot_id, pivoted_string);
|
|
Each time a pivot node will be ticked it will get increased, and, it will
|
|
increase (or create) the children named as pivoted_string
|
|
|
|
the following will either increase or create a node (with value 1) when called
|
|
|
|
tick_stat_node(st, name, parent_id, with_children)
|
|
increases by one a stat_node
|
|
|
|
increase_stat_node(st, name, parent_id, with_children, value)
|
|
increases by value a stat_node
|
|
|
|
set_stat_node(st, name, parent_id, with_children, value)
|
|
sets the value of a stat_node
|
|
|
|
zero_stat_node(st, name, parent_id, with_children)
|
|
resets to zero a stat_node
|
|
|
|
Averages work by tracking both the number of items added to node (the ticking
|
|
action) and the value of each item added to the node. This is done
|
|
automatically for ranged nodes; for other node types you need to call one of
|
|
the functions below to associate item values with each tick.
|
|
|
|
avg_stat_node_add_value_notick(st, name, parent_id, with_children, value)
|
|
avg_stat_node_add_value_int(st, name, parent_id, with_children, value)
|
|
avg_stat_node_add_value_float(st, name, parent_id, with_children, value)
|
|
|
|
The difference between the above functions is whether the item count is
|
|
increased or not. To properly compute the average you need to either call
|
|
avg_stat_node_add_value or avg_stat_node_add_value_notick combined
|
|
tick_stat_node. The later sequence allows for plug-ins which are compatible
|
|
with older Wireshark versions which ignores avg_stat_node_add_value because
|
|
it does not understand the command. This would result in 0 counts for all
|
|
nodes. It is preferred to use avg_stat_node_add_value if you are not writing
|
|
a plug-in.
|
|
|
|
avg_stat_node_add_value_int is used the same way as tick_stat_node with the
|
|
exception that you now specify an additional value associated with the tick.
|
|
|
|
avg_stat_node_add_value_float is used to compute averages of floats, for nodes
|
|
with the STAT_DT_FLOAT datatype.
|
|
|
|
Do not mix increase_stat_node, set_stat_node or zero_stat_node
|
|
with avg_stat_node_add_value_int as this will lead to incorrect results for the
|
|
average value.
|
|
|
|
stats_tree now also support setting flags per node to control the behaviour
|
|
of these nodes. This can be done using the stat_node_set_flags and
|
|
stat_node_clear_flags functions. Currently these flags are defined:
|
|
|
|
ST_FLG_DEF_NOEXPAND: By default the top-level nodes in a tree are
|
|
automatically expanded in the GUI. Setting this flag on
|
|
such a node prevents the node from automatically
|
|
expanding. (However, if there are fewer than some fixed
|
|
total number of nodes, currently 100, in the tree, then
|
|
all the nodes will be expanded anyway.)
|
|
ST_FLG_SORT_TOP: Nodes with this flag is sorted separately from nodes
|
|
without this flag (in effect partitioning tree into a top
|
|
and bottom half. Each half is sorted normally. Top always
|
|
appear first :)
|
|
|
|
The same node manipulations can also be performed via generic functions:
|
|
|
|
stats_tree_manip_node_int(mode, st, name, parent_id, with_children, value);
|
|
stats_tree_manip_node_float(mode, st, name, parent_id, with_children, value);
|
|
|
|
mode is an enum with the following set of values:
|
|
MN_INCREASE
|
|
MN_SET
|
|
MN_AVERAGE
|
|
MN_AVERAGE_NOTICK
|
|
MN_SET_FLAGS
|
|
MN_CLEAR_FLAGS
|
|
|
|
You can find more examples of these in $srcdir/plugins/epan/stats_tree/pinfo_stats_tree.c
|
|
|
|
Luis E. G. Ontanon.
|