Add service_response_time_table for TShark srt stats.

This is a "refactoring part 1" of the srt stats.  This first step is using the service_response_time_table for all (possible) TShark srt stats.  Next step will be combining the GTK and TShark service_response_time_table, so there is more code reuse and the "shared structure names" between GTK and TShark service_response_time_table won't seem as bad.

Maybe it can even go one step farther and handle a dynamic number of columns so this refactoring can apply to all srt stats.

Change-Id: Ief28e7e55f7dbbf4f2d9bb6f1a1592b87b866137
Reviewed-on: https://code.wireshark.org/review/8210
Reviewed-by: Michael Mann <mmann78@netscape.net>
Reviewed-by: Anders Broman <a.broman58@gmail.com>
This commit is contained in:
Michael Mann 2015-04-26 12:26:05 -04:00 committed by Anders Broman
parent 8c996a2736
commit 0b368ea23f
9 changed files with 357 additions and 515 deletions

View File

@ -1116,6 +1116,7 @@ if(ENABLE_EXTCAP)
endif()
set(TSHARK_TAP_SRC
ui/cli/cli_service_response_time_table.c
ui/cli/tap-afpstat.c
ui/cli/tap-ansi_astat.c
ui/cli/tap-bootpstat.c

View File

@ -38,6 +38,7 @@ GENERATOR_FILES =
# sources for TShark taps
TSHARK_TAP_SRC = \
cli_service_response_time_table.c \
tap-afpstat.c \
tap-ansi_astat.c \
tap-bootpstat.c \
@ -82,4 +83,5 @@ TSHARK_TAP_SRC = \
tap-wspstat.c
noinst_HEADERS = \
tshark-tap.h
tshark-tap.h \
cli_service_response_time_table.h

View File

@ -0,0 +1,166 @@
/* cli_service_response_time_table.c
* TShark service_response_time_table based on GTK version by Ronnie Sahlberg
* Helper routines common to all service response time statistics
* tap.
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "config.h"
#include <stdio.h>
#include "epan/packet_info.h"
#include "epan/value_string.h"
#include "ui/cli/cli_service_response_time_table.h"
#define NANOSECS_PER_SEC 1000000000
void
init_srt_table(const char *name, srt_stat_table *rst, int num_procs, const char* proc_column_name, const char *filter_string)
{
int i;
if(filter_string){
rst->filter_string=g_strdup(filter_string);
} else {
rst->filter_string=NULL;
}
rst->name = name;
rst->proc_column_name = proc_column_name;
rst->num_procs=num_procs;
rst->procedures=(srt_procedure_t *)g_malloc(sizeof(srt_procedure_t)*num_procs);
for(i=0;i<num_procs;i++){
time_stat_init(&rst->procedures[i].stats);
rst->procedures[i].index = 0;
rst->procedures[i].procedure = NULL;
}
}
void
init_srt_table_row(srt_stat_table *rst, int indx, const char *procedure)
{
/* we have discovered a new procedure. Extend the table accordingly */
if(indx>=rst->num_procs){
int old_num_procs=rst->num_procs;
int i;
rst->num_procs=indx+1;
rst->procedures=(srt_procedure_t *)g_realloc(rst->procedures, sizeof(srt_procedure_t)*(rst->num_procs));
for(i=old_num_procs;i<rst->num_procs;i++){
time_stat_init(&rst->procedures[i].stats);
rst->procedures[i].index = i;
rst->procedures[i].procedure=NULL;
}
}
rst->procedures[indx].index = indx;
rst->procedures[indx].procedure=g_strdup(procedure);
}
void
add_srt_table_data(srt_stat_table *rst, int indx, const nstime_t *req_time, packet_info *pinfo)
{
srt_procedure_t *rp;
nstime_t t, delta;
g_assert(indx >= 0 && indx < rst->num_procs);
rp=&rst->procedures[indx];
/* calculate time delta between request and reply */
t=pinfo->fd->abs_ts;
nstime_delta(&delta, &t, req_time);
time_stat_update(&rp->stats, &delta, pinfo);
}
void
draw_srt_table_data(srt_stat_table *rst, gboolean draw_header, gboolean draw_footer)
{
int i;
guint64 td;
guint64 sum;
if (draw_header) {
printf("\n");
printf("===================================================================\n");
printf("%s SRT Statistics:\n", rst->name);
printf("Filter: %s\n", rst->filter_string ? rst->filter_string : "");
}
printf("Index %-22s Calls Min SRT Max SRT Avg SRT Sum SRT\n", (rst->proc_column_name != NULL) ? rst->proc_column_name : "Procedure");
for(i=0;i<rst->num_procs;i++){
/* ignore procedures with no calls (they don't have rows) */
if(rst->procedures[i].stats.num==0){
continue;
}
/* Scale the average SRT in units of 1us and round to the nearest us.
tot.secs is a time_t which may be 32 or 64 bits (or even floating)
depending uon the platform. After casting tot.secs to 64 bits, it
would take a capture with a duration of over 136 *years* to
overflow the secs portion of td. */
td = ((guint64)(rst->procedures[i].stats.tot.secs))*NANOSECS_PER_SEC + rst->procedures[i].stats.tot.nsecs;
sum = (td + 500) / 1000;
td = ((td / rst->procedures[i].stats.num) + 500) / 1000;
printf("%5u %-22s %6u %3d.%06d %3d.%06d %3d.%06d %3d.%06d\n",
i, rst->procedures[i].procedure,
rst->procedures[i].stats.num,
(int)rst->procedures[i].stats.min.secs, (rst->procedures[i].stats.min.nsecs+500)/1000,
(int)rst->procedures[i].stats.max.secs, (rst->procedures[i].stats.max.nsecs+500)/1000,
(int)(td/1000000), (int)(td%1000000),
(int)(sum/1000000), (int)(sum%1000000)
);
}
if (draw_footer)
printf("==================================================================\n");
}
void
free_srt_table_data(srt_stat_table *rst)
{
int i;
for(i=0;i<rst->num_procs;i++){
g_free(rst->procedures[i].procedure);
rst->procedures[i].procedure=NULL;
}
g_free(rst->filter_string);
rst->filter_string=NULL;
g_free(rst->procedures);
rst->procedures=NULL;
rst->num_procs=0;
}
/*
* Editor modelines - http://www.wireshark.org/tools/modelines.html
*
* Local variables:
* c-basic-offset: 8
* tab-width: 8
* indent-tabs-mode: t
* End:
*
* vi: set shiftwidth=8 tabstop=8 noexpandtab:
* :indentSize=8:tabSize=8:noTabs=false:
*/

View File

@ -0,0 +1,97 @@
/* cli_service_response_time_table.h
* TShark service_response_time_table based on GTK version by Ronnie Sahlberg
* Helper routines common to all service response time statistics
* tap.
*
* Wireshark - Network traffic analyzer
* By Gerald Combs <gerald@wireshark.org>
* Copyright 1998 Gerald Combs
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef __CLI_SERVICE_RESPONSE_TIME_TABLE_H__
#define __CLI_SERVICE_RESPONSE_TIME_TABLE_H__
#include "wsutil/nstime.h"
#include "epan/timestats.h"
/** @file
* Helper routines common to all service response time statistics tap.
*/
/** Procedure data */
typedef struct _srt_procedure_t {
int index;
timestat_t stats; /**< stats */
char *procedure; /**< column entries */
} srt_procedure_t;
/** Statistics table */
typedef struct _srt_stat_table {
const char *name; /**< table name */
char *filter_string; /**< append procedure number (%d) to this string
to create a display filter */
int num_procs; /**< number of elements on procedures array */
const char *proc_column_name; /**< procedure column name (if different from default) */
srt_procedure_t *procedures;/**< the procedures array */
} srt_stat_table;
/** Init an srt table data structure.
*
* @param name the table name
* @param rst the srt table to init
* @param num_procs number of procedures
* @param proc_column_name procedure column name (if different from "Procedure")
* @param filter_string filter string or NULL
*/
void init_srt_table(const char *name, srt_stat_table *rst, int num_procs, const char* proc_column_name, const char *filter_string);
/** Init an srt table row data structure.
*
* @param rst the srt table
* @param index number of procedure
* @param procedure the procedures name
*/
void init_srt_table_row(srt_stat_table *rst, int index, const char *procedure);
/** Add srt response to table row data. This will not draw the data!
*
* @param rst the srt table
* @param index number of procedure
* @param req_time the time of the corresponding request
* @param pinfo current packet info
*/
void add_srt_table_data(srt_stat_table *rst, int index, const nstime_t *req_time, packet_info *pinfo);
/** Draw the srt table data.
*
* @param rst the srt table
*/
void draw_srt_table_data(srt_stat_table *rst, gboolean draw_header, gboolean draw_footer);
/** Reset the srt table data.
*
* @param rst the srt table
*/
void reset_srt_table_data(srt_stat_table *rst);
/** Free the srt table data.
*
* @param rst the srt table
*/
void free_srt_table_data(srt_stat_table *rst);
#endif /* __CLI_SERVICE_RESPONSE_TIME_TABLE_H__ */

View File

@ -30,16 +30,18 @@
#include <epan/packet_info.h>
#include <epan/tap.h>
#include <epan/stat_tap_ui.h>
#include <ui/cli/cli_service_response_time_table.h>
#include <epan/value_string.h>
#include <epan/dissectors/packet-afp.h>
#include "epan/timestats.h"
void register_tap_listener_afpstat(void);
#define AFP_NUM_PROCEDURES 256
/* used to keep track of the statistics for an entire program interface */
typedef struct _afpstat_t {
char *filter;
timestat_t proc[256];
srt_stat_table afp_srt_table;
} afpstat_t;
static int
@ -47,23 +49,13 @@ afpstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const voi
{
afpstat_t *ss = (afpstat_t *)pss;
const afp_request_val *request_val = (const afp_request_val *)prv;
nstime_t t, deltat;
timestat_t *sp = NULL;
/* if we havnt seen the request, just ignore it */
if (!request_val) {
return 0;
}
sp = &(ss->proc[request_val->command]);
/* calculate time delta between request and reply */
t = pinfo->fd->abs_ts;
nstime_delta(&deltat, &t, &request_val->req_time);
if (sp) {
time_stat_update(sp, &deltat, pinfo);
}
add_srt_table_data(&ss->afp_srt_table, request_val->command, &request_val->req_time, pinfo);
return 1;
}
@ -72,40 +64,8 @@ static void
afpstat_draw(void *pss)
{
afpstat_t *ss = (afpstat_t *)pss;
guint32 i;
guint64 td;
gchar* tmp_str;
printf("\n");
printf("===================================================================\n");
printf("AFP SRT Statistics:\n");
printf("Filter: %s\n", ss->filter ? ss->filter : "");
printf("Commands Calls Min SRT Max SRT Avg SRT\n");
for (i=0; i<256; i++) {
/* nothing seen, nothing to do */
if (ss->proc[i].num == 0) {
continue;
}
/* scale it to units of 10us.*/
td = ss->proc[i].tot.secs;
td = td*100000+(int)ss->proc[i].tot.nsecs/10000;
if (ss->proc[i].num) {
td /= ss->proc[i].num;
} else {
td = 0;
}
tmp_str = val_to_str_ext_wmem(NULL, i, &CommandCode_vals_ext, "Unknown (%u)");
printf("%-25s %6u %3d.%05d %3d.%05d %3" G_GINT64_MODIFIER "u.%05" G_GINT64_MODIFIER "u\n",
tmp_str,
ss->proc[i].num,
(int)ss->proc[i].min.secs, ss->proc[i].min.nsecs/10000,
(int)ss->proc[i].max.secs, ss->proc[i].max.nsecs/10000,
td/100000, td%100000
);
wmem_free(NULL, tmp_str);
}
printf("===================================================================\n");
draw_srt_table_data(&ss->afp_srt_table, TRUE, TRUE);
}
@ -119,33 +79,22 @@ afpstat_init(const char *opt_arg, void *userdata _U_)
if (!strncmp(opt_arg, "afp,srt,", 8)) {
filter = opt_arg+8;
} else {
filter = NULL;
}
ss = g_new(afpstat_t, 1);
if (filter) {
ss->filter = g_strdup(filter);
} else {
ss->filter = NULL;
}
for (i=0; i<256; i++) {
ss->proc[i].num = 0;
ss->proc[i].min_num = 0;
ss->proc[i].max_num = 0;
ss->proc[i].min.secs = 0;
ss->proc[i].min.nsecs = 0;
ss->proc[i].max.secs = 0;
ss->proc[i].max.nsecs = 0;
ss->proc[i].tot.secs = 0;
ss->proc[i].tot.nsecs = 0;
init_srt_table("AFP", &ss->afp_srt_table, AFP_NUM_PROCEDURES, NULL, filter ? g_strdup(filter) : NULL);
for (i = 0; i < AFP_NUM_PROCEDURES; i++)
{
gchar* tmp_str = val_to_str_ext_wmem(NULL, i, &CommandCode_vals_ext, "Unknown(%u)");
init_srt_table_row(&ss->afp_srt_table, i, tmp_str);
wmem_free(NULL, tmp_str);
}
error_string = register_tap_listener("afp", ss, filter, 0, NULL, afpstat_packet, afpstat_draw);
if (error_string) {
/* error, we failed to attach to the tap. clean up */
g_free(ss->filter);
free_srt_table_data(&ss->afp_srt_table);
g_free(ss);
fprintf(stderr, "tshark: Couldn't register afp,srt tap: %s\n",

View File

@ -30,6 +30,7 @@
#include <epan/packet_info.h>
#include <epan/tap.h>
#include <epan/stat_tap_ui.h>
#include <ui/cli/cli_service_response_time_table.h>
#include <epan/value_string.h>
#include <epan/dissectors/packet-ldap.h>
#include "epan/timestats.h"
@ -38,12 +39,9 @@ void register_tap_listener_ldapstat(void);
#define LDAP_NUM_PROCEDURES 24
#define NANOSECS_PER_SEC G_GUINT64_CONSTANT(1000000000)
/* used to keep track of the statistics for an entire program interface */
typedef struct _ldapstat_t {
char *filter;
timestat_t proc[LDAP_NUM_PROCEDURES];
srt_stat_table ldap_srt_table;
} ldapstat_t;
static int
@ -51,8 +49,6 @@ ldapstat_packet(void *pldap, packet_info *pinfo, epan_dissect_t *edt _U_, const
{
const ldap_call_response_t *ldap=(const ldap_call_response_t *)psi;
ldapstat_t *fs=(ldapstat_t *)pldap;
timestat_t *sp = NULL;
nstime_t t, deltat;
/* we are only interested in reply packets */
if(ldap->is_request){
@ -78,15 +74,7 @@ ldapstat_packet(void *pldap, packet_info *pinfo, epan_dissect_t *edt _U_, const
return 0;
}
sp = &(fs->proc[ldap->protocolOpTag]);
/* calculate time delta between request and reply */
t = pinfo->fd->abs_ts;
nstime_delta(&deltat, &t, &ldap->req_time);
if (sp) {
time_stat_update(sp, &deltat, pinfo);
}
add_srt_table_data(&fs->ldap_srt_table, ldap->protocolOpTag, &ldap->req_time, pinfo);
return 1;
}
@ -94,41 +82,8 @@ static void
ldapstat_draw(void *pss)
{
ldapstat_t *ss = (ldapstat_t *)pss;
guint32 i;
guint64 td, sum;
gchar* tmp_str;
printf("\n");
printf("===================================================================\n");
printf("LDAP SRT Statistics:\n");
printf("Filter: %s\n", ss->filter ? ss->filter : "");
printf("Index Procedure Calls Min SRT Max SRT Avg SRT Sum SRT\n");
for (i=0; i<LDAP_NUM_PROCEDURES; i++) {
/* nothing seen, nothing to do */
if (ss->proc[i].num == 0) {
continue;
}
/* Scale the average SRT in units of 1us and round to the nearest us.
tot.secs is a time_t which may be 32 or 64 bits (or even floating)
depending uon the platform. After casting tot.secs to 64 bits, it
would take a capture with a duration of over 136 *years* to
overflow the secs portion of td. */
td = ((guint64)(ss->proc[i].tot.secs))*NANOSECS_PER_SEC + ss->proc[i].tot.nsecs;
sum = (td + 500) / 1000;
td = ((td / ss->proc[i].num) + 500) / 1000;
tmp_str = val_to_str_wmem(NULL, i, ldap_procedure_names, "Unknown (%u)");
printf("%5u %-20s %6u %3d.%06d %3d.%06d %3d.%06d %3d.%06d\n",
i, tmp_str,
ss->proc[i].num,
(int)ss->proc[i].min.secs, (ss->proc[i].min.nsecs+500)/1000,
(int)ss->proc[i].max.secs, (ss->proc[i].max.nsecs+500)/1000,
(int)(td/1000000), (int)(td%1000000),
(int)(sum/1000000), (int)(sum%1000000)
);
wmem_free(NULL, tmp_str);
}
printf("===================================================================\n");
draw_srt_table_data(&ss->ldap_srt_table, TRUE, TRUE);
}
@ -138,20 +93,24 @@ ldapstat_init(const char *opt_arg, void *userdata _U_)
ldapstat_t *ldap;
const char *filter = NULL;
GString *error_string;
int i;
if (!strncmp(opt_arg, "ldap,srt,", 8)) {
filter = opt_arg+8;
}
ldap=(ldapstat_t *)g_malloc0(sizeof(ldapstat_t));
if (filter) {
ldap->filter = g_strdup(filter);
ldap = g_new(ldapstat_t,1);
init_srt_table("LDAP", &ldap->ldap_srt_table, LDAP_NUM_PROCEDURES, NULL, filter ? g_strdup(filter) : NULL);
for (i = 0; i < LDAP_NUM_PROCEDURES; i++)
{
init_srt_table_row(&ldap->ldap_srt_table, i, val_to_str_const(i, ldap_procedure_names, "<unknown>"));
}
error_string = register_tap_listener("ldap", ldap, filter, 0, NULL, ldapstat_packet, ldapstat_draw);
if (error_string) {
/* error, we failed to attach to the tap. clean up */
g_free(ldap->filter);
free_srt_table_data(&ldap->ldap_srt_table);
g_free(ldap);
fprintf(stderr, "tshark: Couldn't register ldap,srt tap: %s\n",

View File

@ -36,61 +36,22 @@
#include <epan/tap.h>
#include <epan/stat_tap_ui.h>
#include <epan/dissectors/packet-rpc.h>
#include <ui/cli/cli_service_response_time_table.h>
#define MICROSECS_PER_SEC 1000000
#define NANOSECS_PER_SEC 1000000000
void register_tap_listener_rpcstat(void);
/* used to keep track of statistics for a specific procedure */
typedef struct _rpc_procedure_t {
const char *proc;
int num;
nstime_t min;
nstime_t max;
nstime_t tot;
} rpc_procedure_t;
/* used to keep track of the statistics for an entire program interface */
typedef struct _rpcstat_t {
const char *prog;
char *filter;
guint32 program;
guint32 version;
guint32 num_procedures;
rpc_procedure_t *procedures;
srt_stat_table rpc_srt_table;
} rpcstat_t;
/* This callback is never used by tshark but it is here for completeness.
* When registering below, we could just have left this function as NULL.
*
* When used by wireshark, this function will be called whenever we would need
* to reset all state, such as when wireshark opens a new file, when it
* starts a new capture, when it rescans the packetlist after some prefs have
* changed etc.
*
* So if your application has some state it needs to clean up in those
* situations, here is a good place to put that code.
*/
static void
rpcstat_reset(void *prs)
{
rpcstat_t *rs = (rpcstat_t *)prs;
guint32 i;
for (i=0; i<rs->num_procedures; i++) {
rs->procedures[i].num = 0;
rs->procedures[i].min.secs = 0;
rs->procedures[i].min.nsecs = 0;
rs->procedures[i].max.secs = 0;
rs->procedures[i].max.nsecs = 0;
rs->procedures[i].tot.secs = 0;
rs->procedures[i].tot.nsecs = 0;
}
}
/* This callback is invoked whenever the tap system has seen a packet we might
* be interested in. The function is to be used to only update internal state
@ -124,10 +85,8 @@ rpcstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const voi
{
rpcstat_t *rs = (rpcstat_t *)prs;
const rpc_call_info_value *ri = (const rpc_call_info_value *)pri;
nstime_t delta;
rpc_procedure_t *rp;
if (ri->proc >= rs->num_procedures) {
if ((int)ri->proc >= rs->rpc_srt_table.num_procs) {
/* don't handle this since its outside of known table */
return 0;
}
@ -140,44 +99,7 @@ rpcstat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const voi
return 0;
}
rp = &(rs->procedures[ri->proc]);
/* calculate time delta between request and reply */
nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->req_time);
if (rp->num == 0) {
rp->max.secs = delta.secs;
rp->max.nsecs = delta.nsecs;
}
if (rp->num == 0) {
rp->min.secs = delta.secs;
rp->min.nsecs = delta.nsecs;
}
if ( (delta.secs < rp->min.secs)
|| ( (delta.secs == rp->min.secs)
&& (delta.nsecs < rp->min.nsecs) ) ) {
rp->min.secs = delta.secs;
rp->min.nsecs = delta.nsecs;
}
if ( (delta.secs > rp->max.secs)
|| ( (delta.secs == rp->max.secs)
&& (delta.nsecs > rp->max.nsecs) ) ) {
rp->max.secs = delta.secs;
rp->max.nsecs = delta.nsecs;
}
rp->tot.secs += delta.secs;
rp->tot.nsecs += delta.nsecs;
if (rp->tot.nsecs > NANOSECS_PER_SEC) {
rp->tot.nsecs -= NANOSECS_PER_SEC;
rp->tot.secs++;
}
rp->num++;
add_srt_table_data(&rs->rpc_srt_table, ri->proc, &ri->req_time, pinfo);
return 1;
}
@ -195,31 +117,8 @@ static void
rpcstat_draw(void *prs)
{
rpcstat_t *rs = (rpcstat_t *)prs;
guint32 i;
guint64 td;
printf("\n");
printf("==================================================================\n");
printf("%s Version %u SRT Statistics:\n", rs->prog, rs->version);
printf("Filter: %s\n", rs->filter ? rs->filter : "");
printf("Procedure Calls Min SRT Max SRT Avg SRT Total\n");
for (i=0; i<rs->num_procedures; i++) {
if (rs->procedures[i].num == 0) {
continue;
}
/* Scale the average SRT in units of 1us and round to the nearest us. */
td = ((guint64)(rs->procedures[i].tot.secs)) * NANOSECS_PER_SEC + rs->procedures[i].tot.nsecs;
td = ((td / rs->procedures[i].num) + 500) / 1000;
printf("%-15s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u %3d.%06d\n",
rs->procedures[i].proc,
rs->procedures[i].num,
(int)(rs->procedures[i].min.secs), (rs->procedures[i].min.nsecs+500)/1000,
(int)(rs->procedures[i].max.secs), (rs->procedures[i].max.nsecs+500)/1000,
td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC,
(int)(rs->procedures[i].tot.secs), (rs->procedures[i].tot.nsecs+500)/1000
);
}
printf("==================================================================\n");
draw_srt_table_data(&rs->rpc_srt_table, TRUE, TRUE);
}
static guint32 rpc_program = 0;
@ -266,17 +165,16 @@ static void
rpcstat_init(const char *opt_arg, void *userdata _U_)
{
rpcstat_t *rs;
guint32 i;
int i;
int program, version;
int pos = 0;
const char *filter = NULL;
GString *error_string;
static char table_name[100];
if (sscanf(opt_arg, "rpc,srt,%d,%d,%n", &program, &version, &pos) == 2) {
if (pos) {
filter = opt_arg+pos;
} else {
filter = NULL;
}
} else {
fprintf(stderr, "tshark: invalid \"-z rpc,srt,<program>,<version>[,<filter>]\" argument\n");
@ -287,11 +185,7 @@ rpcstat_init(const char *opt_arg, void *userdata _U_)
rs->prog = rpc_prog_name(program);
rs->program = program;
rs->version = version;
if (filter) {
rs->filter = g_strdup(filter);
} else {
rs->filter = NULL;
}
rpc_program = program;
rpc_version = version;
rpc_min_proc = -1;
@ -303,18 +197,11 @@ rpcstat_init(const char *opt_arg, void *userdata _U_)
exit(1);
}
rs->num_procedures = rpc_max_proc+1;
rs->procedures = g_new(rpc_procedure_t, rs->num_procedures+1);
for (i=0; i<rs->num_procedures; i++) {
rs->procedures[i].proc = rpc_proc_name(program, version, i);
rs->procedures[i].num = 0;
rs->procedures[i].min.secs = 0;
rs->procedures[i].min.nsecs = 0;
rs->procedures[i].max.secs = 0;
rs->procedures[i].max.nsecs = 0;
rs->procedures[i].tot.secs = 0;
rs->procedures[i].tot.nsecs = 0;
g_snprintf(table_name, sizeof(table_name), "%s Version %u", rs->prog, rs->version);
init_srt_table(table_name, &rs->rpc_srt_table, rpc_max_proc+1, NULL, filter ? g_strdup(filter) : NULL);
for (i = 0; i < rs->rpc_srt_table.num_procs; i++)
{
init_srt_table_row(&rs->rpc_srt_table, i, rpc_proc_name(program, version, i));
}
/* It is possible to create a filter and attach it to the callbacks. Then the
@ -328,11 +215,10 @@ rpcstat_init(const char *opt_arg, void *userdata _U_)
* (Perhaps the user only wants the stats for nis+ traffic for certain objects?)
*/
error_string = register_tap_listener("rpc", rs, filter, 0, rpcstat_reset, rpcstat_packet, rpcstat_draw);
error_string = register_tap_listener("rpc", rs, filter, 0, NULL, rpcstat_packet, rpcstat_draw);
if (error_string) {
/* error, we failed to attach to the tap. clean up */
g_free(rs->procedures);
g_free(rs->filter);
free_srt_table_data(&rs->rpc_srt_table);
g_free(rs);
fprintf(stderr, "tshark: Couldn't register rpc,srt tap: %s\n",

View File

@ -26,6 +26,7 @@
#include <string.h>
#include <epan/packet_info.h>
#include <epan/stat_tap_ui.h>
#include <ui/cli/cli_service_response_time_table.h>
#include <epan/tap.h>
#include <epan/conversation.h>
#include <epan/dissectors/packet-scsi.h>
@ -37,54 +38,20 @@
void register_tap_listener_scsistat(void);
static guint8 scsi_program = 0;
/* used to keep track of statistics for a specific procedure */
typedef struct _scsi_procedure_t {
char *proc;
int num;
nstime_t min;
nstime_t max;
nstime_t tot;
} scsi_procedure_t;
#define SCSI_NUM_PROCEDURES 256
/* used to keep track of the statistics for an entire program interface */
typedef struct _scsistat_t {
guint8 cmdset;
char *filter;
value_string_ext *cdbnames_ext;
const char *prog;
#define MAX_PROCEDURES 256
scsi_procedure_t *procedures;
srt_stat_table scsi_srt_table;
} scsistat_t;
#define MICROSECS_PER_SEC 1000000
#define NANOSECS_PER_SEC 1000000000
static void
scsistat_reset(void *prs)
{
scsistat_t *rs = (scsistat_t *)prs;
guint32 i;
for(i = 0; i < MAX_PROCEDURES; i++) {
rs->procedures[i].num = 0;
rs->procedures[i].min.secs = 0;
rs->procedures[i].min.nsecs = 0;
rs->procedures[i].max.secs = 0;
rs->procedures[i].max.nsecs = 0;
rs->procedures[i].tot.secs = 0;
rs->procedures[i].tot.nsecs = 0;
}
}
static int
scsistat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const void *pri)
{
scsistat_t *rs = (scsistat_t *)prs;
const scsi_task_data_t *ri = (const scsi_task_data_t *)pri;
nstime_t delta;
scsi_procedure_t *rp;
/* we are only interested in response packets */
if (ri->type != SCSI_PDU_TYPE_RSP) {
@ -99,38 +66,7 @@ scsistat_packet(void *prs, packet_info *pinfo, epan_dissect_t *edt _U_, const vo
return 0;
}
rp = &(rs->procedures[ri->itlq->scsi_opcode]);
/* calculate time delta between request and reply */
nstime_delta(&delta, &pinfo->fd->abs_ts, &ri->itlq->fc_time);
if (rp->num == 0) {
rp->max.secs = delta.secs;
rp->max.nsecs = delta.nsecs;
}
if (rp->num == 0) {
rp->min.secs = delta.secs;
rp->min.nsecs = delta.nsecs;
}
if ( (delta.secs < rp->min.secs)
|| ( (delta.secs == rp->min.secs)
&& (delta.nsecs < rp->min.nsecs) ) ) {
rp->min.secs = delta.secs;
rp->min.nsecs = delta.nsecs;
}
if ( (delta.secs > rp->max.secs)
|| ( (delta.secs == rp->max.secs)
&& (delta.nsecs > rp->max.nsecs) ) ) {
rp->max.secs = delta.secs;
rp->max.nsecs= delta.nsecs;
}
rp->tot.secs += delta.secs;
rp->tot.nsecs += delta.nsecs;
if (rp->tot.nsecs > NANOSECS_PER_SEC) {
rp->tot.nsecs -= NANOSECS_PER_SEC;
rp->tot.secs++;
}
rp->num++;
add_srt_table_data(&rs->scsi_srt_table, ri->itlq->scsi_opcode, &ri->itlq->fc_time, pinfo);
return 1;
}
@ -138,33 +74,8 @@ static void
scsistat_draw(void *prs)
{
scsistat_t *rs = (scsistat_t *)prs;
guint32 i;
guint64 td;
printf("\n");
printf("===========================================================\n");
printf("SCSI %s SRT Statistics:\n", rs->prog);
printf("Filter: %s\n", rs->filter ? rs->filter : "");
printf("Procedure Calls Min SRT Max SRT Avg SRT\n");
for(i=0; i < MAX_PROCEDURES; i++) {
if (rs->procedures[i].num == 0) {
continue;
}
/* scale it to units of 1us.*/
td = ((guint64)(rs->procedures[i].tot.secs)) * NANOSECS_PER_SEC + rs->procedures[i].tot.nsecs;
td = ((td / rs->procedures[i].num) + 500) / 1000;
printf("%-19s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
rs->procedures[i].proc,
rs->procedures[i].num,
(int)(rs->procedures[i].min.secs),
(rs->procedures[i].min.nsecs+500)/1000,
(int)(rs->procedures[i].max.secs),
(rs->procedures[i].max.nsecs+500)/1000,
(td/MICROSECS_PER_SEC), (td%MICROSECS_PER_SEC)
);
}
printf("===========================================================\n");
draw_srt_table_data(&rs->scsi_srt_table, TRUE, TRUE);
}
static void
@ -174,76 +85,68 @@ scsistat_init(const char *opt_arg, void* userdata _U_)
guint32 i;
int program, pos;
const char *filter = NULL;
value_string_ext *cdbnames_ext;
GString *error_string;
const char *table_name;
pos = 0;
if (sscanf(opt_arg, "scsi,srt,%d,%n", &program, &pos) == 1) {
if (pos) {
filter = opt_arg+pos;
} else {
filter = NULL;
}
} else {
fprintf(stderr, "tshark: invalid \"-z scsi,srt,<cmdset>[,<filter>]\" argument\n");
exit(1);
}
scsi_program = program;
rs = g_new(scsistat_t,1);
if (filter) {
rs->filter = g_strdup(filter);
} else {
rs->filter = NULL;
}
rs->cmdset = program;
switch(program) {
case SCSI_DEV_SBC:
rs->prog = "SBC (disk)";
rs->cdbnames_ext = &scsi_sbc_vals_ext;
table_name = "SCSI SBC (disk)";
cdbnames_ext = &scsi_sbc_vals_ext;
break;
case SCSI_DEV_SSC:
rs->prog = "SSC (tape)";
rs->cdbnames_ext = &scsi_ssc_vals_ext;
table_name = "SCSI SSC (tape)";
cdbnames_ext = &scsi_ssc_vals_ext;
break;
case SCSI_DEV_CDROM:
rs->prog = "MMC (cd/dvd)";
rs->cdbnames_ext = &scsi_mmc_vals_ext;
table_name = "SCSI MMC (cd/dvd)";
cdbnames_ext = &scsi_mmc_vals_ext;
break;
case SCSI_DEV_SMC:
rs->prog = "SMC (tape robot)";
rs->cdbnames_ext = &scsi_smc_vals_ext;
table_name = "SCSI SMC (tape robot)";
cdbnames_ext = &scsi_smc_vals_ext;
break;
case SCSI_DEV_OSD:
rs->prog = "OSD (object based)";
rs->cdbnames_ext = &scsi_osd_vals_ext;
table_name = "SCSI OSD (object based)";
cdbnames_ext = &scsi_osd_vals_ext;
break;
default:
/* Default to the SBC (disk), since this is what EMC SCSI seem to always be */
rs->cmdset = 0;
rs->prog = "SBC (disk)";
rs->cdbnames_ext = &scsi_sbc_vals_ext;
table_name = "SCSI SBC (disk)";
cdbnames_ext = &scsi_sbc_vals_ext;
break;
}
rs->procedures = g_new(scsi_procedure_t,MAX_PROCEDURES);
for(i=0; i < MAX_PROCEDURES; i++) {
rs->procedures[i].proc = val_to_str_ext_wmem(NULL, i, rs->cdbnames_ext, "Unknown-0x%02x");
rs->procedures[i].num = 0;
rs->procedures[i].min.secs = 0;
rs->procedures[i].min.nsecs = 0;
rs->procedures[i].max.secs = 0;
rs->procedures[i].max.nsecs = 0;
rs->procedures[i].tot.secs = 0;
rs->procedures[i].tot.nsecs = 0;
init_srt_table(table_name, &rs->scsi_srt_table, SCSI_NUM_PROCEDURES, NULL, filter ? g_strdup(filter) : NULL);
for (i = 0; i < SCSI_NUM_PROCEDURES; i++)
{
init_srt_table_row(&rs->scsi_srt_table, i, val_to_str_ext_const(i, cdbnames_ext, "<unknown>"));
}
error_string = register_tap_listener("scsi", rs, filter, 0, scsistat_reset, scsistat_packet, scsistat_draw);
error_string = register_tap_listener("scsi", rs, filter, 0, NULL, scsistat_packet, scsistat_draw);
if (error_string) {
/* error, we failed to attach to the tap. clean up */
for(i=0; i < MAX_PROCEDURES; i++) {
wmem_free(NULL, rs->procedures[i].proc);
}
g_free(rs->procedures);
g_free(rs->filter);
free_srt_table_data(&rs->scsi_srt_table);
g_free(rs);
fprintf(stderr, "tshark: Couldn't register scsi,srt tap: %s\n",

View File

@ -30,31 +30,26 @@
#include <epan/tap.h>
#include <epan/stat_tap_ui.h>
#include "epan/value_string.h"
#include <ui/cli/cli_service_response_time_table.h>
#include <epan/dissectors/packet-smb.h>
#include "epan/timestats.h"
#define MICROSECS_PER_SEC 1000000
#define NANOSECS_PER_SEC 1000000000
void register_tap_listener_smbstat(void);
#define SMB_NUM_PROCEDURES 256
/* used to keep track of the statistics for an entire program interface */
typedef struct _smbstat_t {
char *filter;
timestat_t proc[256];
timestat_t trans2[256];
timestat_t nt_trans[256];
srt_stat_table smb_srt_table;
srt_stat_table trans2_srt_table;
srt_stat_table nt_srt_table;
} smbstat_t;
static int
smbstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const void *psi)
{
smbstat_t *ss = (smbstat_t *)pss;
const smb_info_t *si = (const smb_info_t *)psi;
nstime_t t, deltat;
timestat_t *sp = NULL;
/* we are only interested in reply packets */
if (si->request) {
@ -70,25 +65,17 @@ smbstat_packet(void *pss, packet_info *pinfo, epan_dissect_t *edt _U_, const voi
/*nt transaction*/
if (sti) {
sp = &(ss->nt_trans[sti->subcmd]);
add_srt_table_data(&ss->nt_srt_table, sti->subcmd, &si->sip->req_time, pinfo);
}
} else if (si->cmd == 0x32 && si->sip->extra_info_type == SMB_EI_T2I) {
smb_transact2_info_t *st2i = (smb_transact2_info_t *)si->sip->extra_info;
/*transaction2*/
if (st2i) {
sp = &(ss->trans2[st2i->subcmd]);
add_srt_table_data(&ss->trans2_srt_table, st2i->subcmd, &si->sip->req_time, pinfo);
}
} else {
sp = &(ss->proc[si->cmd]);
}
/* calculate time delta between request and reply */
t = pinfo->fd->abs_ts;
nstime_delta(&deltat, &t, &si->sip->req_time);
if (sp) {
time_stat_update(sp, &deltat, pinfo);
add_srt_table_data(&ss->smb_srt_table,si->cmd, &si->sip->req_time, pinfo);
}
return 1;
@ -98,93 +85,12 @@ static void
smbstat_draw(void *pss)
{
smbstat_t *ss = (smbstat_t *)pss;
guint32 i;
guint64 td;
gchar* tmp_str;
draw_srt_table_data(&ss->smb_srt_table, TRUE, FALSE);
printf("\n");
printf("=================================================================\n");
printf("SMB SRT Statistics:\n");
printf("Filter: %s\n", ss->filter ? ss->filter : "");
printf("Commands Calls Min SRT Max SRT Avg SRT\n");
for (i=0; i<256; i++) {
/* nothing seen, nothing to do */
if (ss->proc[i].num == 0) {
continue;
}
/* we deal with transaction2 later */
if (i == 0x32) {
continue;
}
/* we deal with nt transaction later */
if (i == 0xA0) {
continue;
}
/* Scale the average SRT in units of 1us and round to the nearest us. */
td = ((guint64)(ss->proc[i].tot.secs)) * NANOSECS_PER_SEC + ss->proc[i].tot.nsecs;
td = ((td / ss->proc[i].num) + 500) / 1000;
tmp_str = val_to_str_ext_wmem(NULL, i, &smb_cmd_vals_ext, "Unknown (0x%02x)");
printf("%-25s %6u %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
tmp_str,
ss->proc[i].num,
(int)(ss->proc[i].min.secs), (ss->proc[i].min.nsecs+500)/1000,
(int)(ss->proc[i].max.secs), (ss->proc[i].max.nsecs+500)/1000,
td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
);
wmem_free(NULL, tmp_str);
}
draw_srt_table_data(&ss->trans2_srt_table, FALSE, FALSE);
printf("\n");
printf("Transaction2 Commands Calls Min SRT Max SRT Avg SRT\n");
for (i=0; i<256; i++) {
/* nothing seen, nothing to do */
if (ss->trans2[i].num == 0) {
continue;
}
/* Scale the average SRT in units of 1us and round to the nearest us. */
td = ((guint64)(ss->trans2[i].tot.secs)) * NANOSECS_PER_SEC + ss->trans2[i].tot.nsecs;
td = ((td / ss->trans2[i].num) + 500) / 1000;
tmp_str = val_to_str_ext_wmem(NULL, i, &trans2_cmd_vals_ext, "Unknown (0x%02x)");
printf("%-25s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
tmp_str,
ss->trans2[i].num,
(int)(ss->trans2[i].min.secs), (ss->trans2[i].min.nsecs+500)/1000,
(int)(ss->trans2[i].max.secs), (ss->trans2[i].max.nsecs+500)/1000,
td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
);
wmem_free(NULL, tmp_str);
}
printf("\n");
printf("NT Transaction Commands Calls Min SRT Max SRT Avg SRT\n");
for (i=0; i<256; i++) {
/* nothing seen, nothing to do */
if (ss->nt_trans[i].num == 0) {
continue;
}
/* Scale the average SRT in units of 1us and round to the nearest us. */
td = ((guint64)(ss->nt_trans[i].tot.secs)) * NANOSECS_PER_SEC + ss->nt_trans[i].tot.nsecs;
td = ((td / ss->nt_trans[i].num) + 500) / 1000;
tmp_str = val_to_str_ext_wmem(NULL, i, &nt_cmd_vals_ext, "Unknown (0x%02x)");
printf("%-25s %6d %3d.%06d %3d.%06d %3" G_GINT64_MODIFIER "u.%06" G_GINT64_MODIFIER "u\n",
tmp_str,
ss->nt_trans[i].num,
(int)(ss->nt_trans[i].min.secs), (ss->nt_trans[i].min.nsecs+500)/1000,
(int)(ss->nt_trans[i].max.secs), (ss->nt_trans[i].max.nsecs+500)/1000,
td/MICROSECS_PER_SEC, td%MICROSECS_PER_SEC
);
wmem_free(NULL, tmp_str);
}
printf("=================================================================\n");
draw_srt_table_data(&ss->nt_srt_table, FALSE, TRUE);
}
@ -198,53 +104,26 @@ smbstat_init(const char *opt_arg, void *userdata _U_)
if (!strncmp(opt_arg, "smb,srt,", 8)) {
filter = opt_arg + 8;
} else {
filter = NULL;
}
ss = g_new(smbstat_t, 1);
if (filter) {
ss->filter = g_strdup(filter);
} else {
ss->filter = NULL;
}
for (i=0; i<256; i++) {
ss->proc[i].num = 0;
ss->proc[i].min_num = 0;
ss->proc[i].max_num = 0;
ss->proc[i].min.secs = 0;
ss->proc[i].min.nsecs = 0;
ss->proc[i].max.secs = 0;
ss->proc[i].max.nsecs = 0;
ss->proc[i].tot.secs = 0;
ss->proc[i].tot.nsecs = 0;
ss->trans2[i].num = 0;
ss->trans2[i].min_num = 0;
ss->trans2[i].max_num = 0;
ss->trans2[i].min.secs = 0;
ss->trans2[i].min.nsecs = 0;
ss->trans2[i].max.secs = 0;
ss->trans2[i].max.nsecs = 0;
ss->trans2[i].tot.secs = 0;
ss->trans2[i].tot.nsecs = 0;
ss->nt_trans[i].num = 0;
ss->nt_trans[i].min_num = 0;
ss->nt_trans[i].max_num = 0;
ss->nt_trans[i].min.secs = 0;
ss->nt_trans[i].min.nsecs = 0;
ss->nt_trans[i].max.secs = 0;
ss->nt_trans[i].max.nsecs = 0;
ss->nt_trans[i].tot.secs = 0;
ss->nt_trans[i].tot.nsecs = 0;
init_srt_table("SMB", &ss->smb_srt_table, SMB_NUM_PROCEDURES, "Commands", filter ? g_strdup(filter) : NULL);
init_srt_table("SMB", &ss->trans2_srt_table, SMB_NUM_PROCEDURES, "Transaction2 Commands", filter ? g_strdup(filter) : NULL);
init_srt_table("SMB", &ss->nt_srt_table, SMB_NUM_PROCEDURES, "NT Transaction Commands", filter ? g_strdup(filter) : NULL);
for (i = 0; i < SMB_NUM_PROCEDURES; i++)
{
init_srt_table_row(&ss->smb_srt_table, i, val_to_str_ext_const(i, &smb_cmd_vals_ext, "<unknown>"));
init_srt_table_row(&ss->trans2_srt_table, i, val_to_str_ext_const(i, &trans2_cmd_vals_ext, "<unknown>"));
init_srt_table_row(&ss->nt_srt_table, i, val_to_str_ext_const(i, &nt_cmd_vals_ext, "<unknown>"));
}
error_string = register_tap_listener("smb", ss, filter, 0, NULL, smbstat_packet, smbstat_draw);
if (error_string) {
/* error, we failed to attach to the tap. clean up */
g_free(ss->filter);
free_srt_table_data(&ss->smb_srt_table);
free_srt_table_data(&ss->trans2_srt_table);
free_srt_table_data(&ss->nt_srt_table);
g_free(ss);
fprintf(stderr, "tshark: Couldn't register smb,srt tap: %s\n",