nexmon – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | tapping with stats_tree |
2 | |||
3 | Let's suppose that you want to write a tap only to keep counters, and you |
||
4 | don't want to get involved with GUI programming or maybe you'd like to make |
||
5 | it a plugin. A stats_tree might be the way to go. The stats_tree module takes |
||
6 | care of the representation (GUI for wireshark and text for tshark) of the |
||
7 | tap data. So there's very little code to write to make a tap listener usable |
||
8 | from both wireshark and tshark. |
||
9 | |||
10 | First, you should add the TAP to the dissector in question as described in |
||
11 | README.tapping . |
||
12 | |||
13 | Once the dissector in question is "tapped" you have to write the stats tree |
||
14 | code which is made of three parts: |
||
15 | |||
16 | The init callback routine: |
||
17 | which will be executed before any packet is passed to the tap. Here you |
||
18 | should create the "static" nodes of your tree. As well as initialize your |
||
19 | data. |
||
20 | |||
21 | The (per)packet callback routine: |
||
22 | As the tap_packet callback is going to be called for every packet, it |
||
23 | should be used to increment the counters. |
||
24 | |||
25 | The cleanup callback: |
||
26 | It is called at the destruction of the stats_tree and might be used to |
||
27 | free .... |
||
28 | |||
29 | Other than that the stats_tree should be registered. |
||
30 | |||
31 | If you want to make it a plugin, stats_tree_register() should be called by |
||
32 | plugin_register_tap_listener() read README.plugin for other information |
||
33 | regarding wireshark plugins. |
||
34 | |||
35 | If you want it as part of the dissector stats_tree_register() can be called |
||
36 | either by proto_register_xxx() or if you prefer by proto_reg_handoff_xxx(). |
||
37 | |||
38 | |||
39 | A small example of a very basic stats_tree plugin follows. |
||
40 | |||
41 | ----- example stats_tree plugin ------ |
||
42 | /* udpterm_stats_tree.c |
||
43 | * A small example of stats_tree plugin that counts udp packets by termination |
||
44 | * 2005, Luis E. G. Ontanon |
||
45 | * |
||
46 | * Wireshark - Network traffic analyzer |
||
47 | * By Gerald Combs <gerald@wireshark.org> |
||
48 | * Copyright 1998 Gerald Combs |
||
49 | * |
||
50 | * This program is free software; you can redistribute it and/or |
||
51 | * modify it under the terms of the GNU General Public License |
||
52 | * as published by the Free Software Foundation; either version 2 |
||
53 | * of the License, or (at your option) any later version. |
||
54 | * |
||
55 | * This program is distributed in the hope that it will be useful, |
||
56 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
57 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
58 | * GNU General Public License for more details. |
||
59 | * |
||
60 | * You should have received a copy of the GNU General Public License |
||
61 | * along with this program; if not, write to the Free Software |
||
62 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. |
||
63 | */ |
||
64 | |||
65 | #include "config.h" |
||
66 | |||
67 | #ifndef ENABLE_STATIC |
||
68 | #include <gmodule.h> |
||
69 | #else |
||
70 | #include <glib.h> |
||
71 | #endif |
||
72 | |||
73 | #include <epan/stats_tree.h> |
||
74 | #include <epan/dissectors/udp.h> |
||
75 | |||
76 | static int st_udp_term; |
||
77 | static gchar* st_str_udp_term = "UDP terminations"; |
||
78 | |||
79 | /* this one initializes the tree, creating the root nodes */ |
||
80 | extern void udp_term_stats_tree_init(stats_tree* st) { |
||
81 | /* we create a node under which we'll add every termination */ |
||
82 | st_udp_term = stats_tree_create_node(st, st_str_udp_term, 0, TRUE); |
||
83 | } |
||
84 | |||
85 | /* this one will be called with every udp packet */ |
||
86 | extern int udp_term_stats_tree_packet(stats_tree *st, /* st as it was passed to us */ |
||
87 | packet_info *pinfo, /* we'll fetch the addresses from here */ |
||
88 | epan_dissect_t *edt _U_, /* unused */ |
||
89 | const void *p) /* we'll use this to fetch the ports */ |
||
90 | { |
||
91 | static guint8 str[128]; |
||
92 | e_udphdr* udphdr = (e_udphdr*) p; |
||
93 | |||
94 | /* we increment by one (tick) the root node */ |
||
95 | tick_stat_node(st, st_str_udp_term, 0, FALSE); |
||
96 | |||
97 | /* we then tick a node for this src_addr:src_port |
||
98 | if the node doesn't exists it will be created */ |
||
99 | g_snprintf(str, sizeof(str),"%s:%u",address_to_str(&pinfo->net_src),udphdr->sport); |
||
100 | tick_stat_node(st, str, st_udp_term, FALSE); |
||
101 | |||
102 | /* same thing for dst */ |
||
103 | g_snprintf(str, sizeof(str),"%s:%u",address_to_str(&pinfo->net_dst),udphdr->dport); |
||
104 | tick_stat_node(st, str, st_udp_term, FALSE); |
||
105 | |||
106 | return 1; |
||
107 | } |
||
108 | |||
109 | #ifndef ENABLE_STATIC |
||
110 | WS_DLL_PUBLIC_DEF const gchar version[] = "0.0"; |
||
111 | |||
112 | WS_DLL_PUBLIC_DEF void plugin_register_tap_listener(void) { |
||
113 | |||
114 | stats_tree_register_plugin("udp", /* the proto we are going to "tap" */ |
||
115 | "udp_terms", /* the abbreviation for this tree (to be used as -z udp_terms,tree) */ |
||
116 | st_str_udp_term, /* the name of the menu and window (use "/" for sub menus)*/ |
||
117 | 0, /* tap listener flags for per-packet callback */ |
||
118 | udp_term_stats_tree_packet, /* the per packet callback */ |
||
119 | udp_term_stats_tree_init, /* the init callback */ |
||
120 | NULL ); /* the cleanup callback (in this case there isn't) */ |
||
121 | |||
122 | } |
||
123 | #endif |
||
124 | |||
125 | ----- END ------ |
||
126 | |||
127 | the stats_tree API |
||
128 | ================== |
||
129 | every stats_tree callback has a stats_tree* parameter (st), stats_tree is an obscure |
||
130 | data structure which should be passed to the api functions. |
||
131 | |||
132 | stats_tree_register( tapname, abbr, name, flags, packet_cb, init_cb, cleanup_cb); |
||
133 | registers a new stats tree |
||
134 | |||
135 | stats_tree_register_plugin(tapname, abbr, name, flags, packet_cb, init_cb, cleanup_cb); |
||
136 | registers a new stats tree from a plugin |
||
137 | |||
138 | stats_tree_parent_id_by_name( st, parent_name) |
||
139 | returns the id of a candidate parent node given its name |
||
140 | |||
141 | |||
142 | Node functions |
||
143 | ============== |
||
144 | |||
145 | All the functions that operate on nodes return a parent_id |
||
146 | |||
147 | stats_tree_create_node(st, name, parent_id, with_children) |
||
148 | Creates a node in the tree (to be used in the in init_cb) |
||
149 | name: the name of the new node |
||
150 | parent_id: the id of the parent_node (NULL for root) |
||
151 | with_children: TRUE if this node will have "dynamically created" children |
||
152 | (i.e. it will be a candidate parent) |
||
153 | |||
154 | |||
155 | stats_tree_create_node_by_pname(st, name, parent_name, with_children); |
||
156 | As before but creates a node using its parent's name |
||
157 | |||
158 | |||
159 | stats_tree_create_range_node(st, name, parent_id, ...) |
||
160 | stats_tree_create_range_node_string(st, name, parent_id, num_str_ranges, str_ranges) |
||
161 | stats_tree_range_node_with_pname(st, name, parent_name, ...) |
||
162 | Creates a node in the tree, that will contain a ranges list. |
||
163 | example: |
||
164 | stats_tree_create_range_node(st,name,parent_id, |
||
165 | "-99","100-199","200-299","300-399","400-", NULL); |
||
166 | |||
167 | stats_tree_tick_range( st, name, parent_id, value_in_range); |
||
168 | stats_tree_tick_range_by_pname(st,name,parent_name,value_in_range) |
||
169 | Increases by one the ranged node and the sub node to whose range the value belongs |
||
170 | |||
171 | |||
172 | stats_tree_create_pivot(st, name, parent_id); |
||
173 | stats_tree_create_pivot_by_pname(st, name, parent_name); |
||
174 | Creates a "pivot node" |
||
175 | |||
176 | stats_tree_tick_pivot(st, pivot_id, pivoted_string); |
||
177 | Each time a pivot node will be ticked it will get increased, and, it will |
||
178 | increase (or create) the children named as pivoted_string |
||
179 | |||
180 | |||
181 | the following will either increase or create a node (with value 1) when called |
||
182 | |||
183 | tick_stat_node(st,name,parent_id,with_children) |
||
184 | increases by one a stat_node |
||
185 | |||
186 | increase_stat_node(st,name,parent_id,with_children,value) |
||
187 | increases by value a stat_node |
||
188 | |||
189 | set_stat_node(st,name,parent_id,with_children,value) |
||
190 | sets the value of a stat_node |
||
191 | |||
192 | zero_stat_node(st,name,parent_id,with_children) |
||
193 | resets to zero a stat_node |
||
194 | |||
195 | Averages work by tracking both the number of items added to node (the ticking |
||
196 | action) and the value of each item added to the node. This is done |
||
197 | automatically for ranged nodes; for other node types you need to call one of |
||
198 | the functions below to associate item values with each tick. |
||
199 | |||
200 | avg_stat_node_add_value_notick(st,name,parent_id,with_children,value) |
||
201 | avg_stat_node_add_value(st,name,parent_id,with_children,value) |
||
202 | |||
203 | The difference between the above functions is whether the item count is |
||
204 | increased or not. To properly compute the average you need to either call |
||
205 | avg_stat_node_add_value or avg_stat_node_add_value_notick combined |
||
206 | tick_stat_node. The later sequence allows for plug-ins which are compatible |
||
207 | with older wireshark versions which ignores avg_stat_node_add_value because |
||
208 | it does not understand the command. This would result in 0 counts for all |
||
209 | nodes. It is preferred to use avg_stat_node_add_value if you are not writing |
||
210 | a plug-in. |
||
211 | |||
212 | avg_stat_node_add_value is used the same way as tick_stat_node with the |
||
213 | exception that you now specify an additional value associated with the tick. |
||
214 | |||
215 | Do not mix increase_stat_node, set_stat_node or zero_stat_node |
||
216 | with avg_stat_node_add_value as this will lead to incorrect results for the |
||
217 | average value. |
||
218 | |||
219 | stats_tree now also support setting flags per node to control the behaviour |
||
220 | of these nodes. This can be done using the stat_node_set_flags and |
||
221 | stat_node_clear_flags functions. Currently these flags are defined: |
||
222 | |||
223 | ST_FLG_DEF_NOEXPAND: By default the top-level nodes in a tree are |
||
224 | automatically expanded in the GUI. Setting this flag on |
||
225 | such a node prevents the node from automatically expanding. |
||
226 | ST_FLG_SORT_TOP: Nodes with this flag is sorted separately from nodes |
||
227 | without this flag (in effect partitioning tree into a top and |
||
228 | bottom half. Each half is sorted normally. Top always appear |
||
229 | first :) |
||
230 | |||
231 | You can find more examples of these in $srcdir/plugins/stats_tree/pinfo_stats_tree.c |
||
232 | |||
233 | Luis E. G. Ontanon. |