Main Page | Modules | Class List | Directories | File List | Class Members | File Members | Related Pages

spp_perfmonitor.c

Go to the documentation of this file.
00001 /* $Id$ 
00002 **
00003 **  spp_perfmonitor.c
00004 **
00005 **  Copyright (C) 2002 Sourcefire, Inc.
00006 **  Marc Norton <mnorton@sourcefire.com>
00007 **  Dan Roelker <droelker@sourcefire.com>
00008 **
00009 **  NOTES
00010 **  6.4.02 - Initial Source Code.  Norton/Roelker
00011 **
00012 **  This program is free software; you can redistribute it and/or modify
00013 **  it under the terms of the GNU General Public License as published by
00014 **  the Free Software Foundation; either version 2 of the License, or
00015 **  (at your option) any later version.
00016 **
00017 **  This program is distributed in the hope that it will be useful,
00018 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
00019 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00020 **  GNU General Public License for more details.
00021 **
00022 **  You should have received a copy of the GNU General Public License
00023 **  along with this program; if not, write to the Free Software
00024 **  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00025 **
00026 */
00027 
00028 #include <stdlib.h>
00029 #include <ctype.h>
00030 #include "plugbase.h"
00031 #include "mstring.h"
00032 #include "util.h"
00033 #include "debug.h"
00034 #include "parser.h"
00035 
00036 #include "snort.h"
00037 #include "perf.h"
00038 
00039 /*
00040 *  Protype these forward references, and don't clutter up the name space
00041 */
00042 static void PerfMonitorInit(u_char *args);
00043 static void ParsePerfMonitorArgs(char *args);
00044 static void ProcessPerfMonitor(Packet *p, void *);
00045 void PerfMonitorCleanExit(int, void *);
00046 
00047 /*
00048  * Function: SetupPerfMonitor()
00049  *
00050  * Purpose: Registers the preprocessor keyword and initialization 
00051  *          function into the preprocessor list.  This is the function that
00052  *          gets called from InitPreprocessors() in plugbase.c.
00053  *
00054  * Arguments: None.
00055  *
00056  * Returns: void function
00057  *
00058  */
00059 void SetupPerfMonitor()
00060 {
00061     /* link the preprocessor keyword to the init function in 
00062        the preproc list */
00063     RegisterPreprocessor("PerfMonitor", PerfMonitorInit);
00064 
00065     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Preprocessor: PerfMonitor is setup...\n"););
00066 }
00067 
00068 /*
00069  * Function: PerfMonitorInit(u_char *)
00070  *
00071  * Purpose: Calls the argument parsing function, performs final setup on data
00072  *          structs, links the preproc function into the function list.
00073  *
00074  * Arguments: args => ptr to argument string
00075  *
00076  * Returns: void function
00077  *
00078  */
00079 static void PerfMonitorInit(u_char *args)
00080 {
00081     DEBUG_WRAP(DebugMessage(DEBUG_PLUGIN,"Preprocessor: PerfMonitor Initialized\n"););
00082 
00083     /* parse the argument list from the rules file */
00084     ParsePerfMonitorArgs((char*)args);
00085 
00086     /* Set the preprocessor function into the function list */
00087     AddFuncToPreprocList(ProcessPerfMonitor);
00088 }
00089 
00090 /*
00091    Perf file -  specified on the command line 
00092 */
00093 static char perf_file[1025]={""};
00094 void SetPerfmonitorFile( char * s )
00095 {
00096    if( strlen(s) < sizeof(perf_file)-1 )
00097    {
00098       strcpy(perf_file,s);
00099    }
00100 }
00101 
00102 /*
00103  * Function: ParsePerfMonitorArgs(char *)
00104  *
00105  * Purpose: Process the preprocessor arguements from the rules file and 
00106  *          initialize the preprocessor's data struct.  This function doesn't
00107  *          have to exist if it makes sense to parse the args in the init 
00108  *          function.
00109  *
00110  * Arguments: args => argument list
00111  *
00112  *
00113  *  perfmonitor: [ time 10 flow ]
00114  *
00115  * Returns: void function
00116  *
00117  */
00118 static void ParsePerfMonitorArgs( char *args)
00119 {
00120     char **Tokens=NULL;
00121     int   iTokenNum=0;
00122     int   i, iTime=60, iFlow=0, iEvents=0, iMaxPerfStats=0;
00123     int   iFile=0, iSnortFile=0, iConsole=0, iPkts=10000, iReset=0;
00124     int   iStatsExit=0;
00125     char  file[1025];
00126     char  snortfile[1025];
00127     int   iRet;
00128     char  *pcEnd;
00129 
00130     if( args )
00131     {
00132        Tokens = mSplit(args, " \t", 50, &iTokenNum, '\\');
00133     }
00134     
00135     for( i = 0; i < iTokenNum; i++ )
00136     {
00137         /* Check for a 'time number' parameter */
00138         if( strcmp( Tokens[i],"time")==0 )
00139         {
00140             /* make sure we have at least one more argument */
00141             if( i == (iTokenNum-1) )
00142             {
00143                 FatalError("%s(%d) => Missing Time.  The value must be a "
00144                            "positive integer number.\n", file_name, file_line);
00145             }
00146 
00147             iTime = strtol(Tokens[++i], &pcEnd, 10);
00148             if(iTime <= 0 || *pcEnd)
00149                 FatalError("%s(%d) => Invalid Time.  The value must be a "
00150                            "positive integer number.\n", file_name, file_line);
00151         }
00152         else if( strcmp( Tokens[i],"flow")==0 )
00153         {
00154             /*
00155             **  This parameter turns on the flow statistics.
00156             **  Flow statistics give you the traffic profile
00157             **  that snort is processing.  This helps in
00158             **  troubleshooting and performance tuning.
00159             */
00160             iFlow = 1;
00161         }       
00162         else if( strcmp( Tokens[i],"accumulate")==0)
00163         {
00164             iReset=0;
00165         }
00166         else if( strcmp( Tokens[i],"reset")==0 )
00167         {
00168             iReset=1;
00169         }
00170         else if( strcmp( Tokens[i],"events")==0 )
00171         {
00172             /*
00173             **  The events paramenter gives the total number
00174             **  of qualified and non-qualified events during
00175             **  the processing sample time.  This allows 
00176             **  performance problems to be seen in a general
00177             **  manner.
00178             */
00179             iEvents = 1;
00180         }
00181         else if(!strcmp(Tokens[i], "max"))
00182         {
00183             iMaxPerfStats = 1;
00184         }
00185         else if(!strcmp(Tokens[i], "console"))
00186         {
00187             iConsole = 1;
00188         }
00189         else if(!strcmp(Tokens[i], "file"))
00190         {
00191             if( i == (iTokenNum-1) )
00192             {
00193                 FatalError("%s(%d) => Missing 'file' argument.  This value "
00194                            "is the file that save stats.\n", 
00195                            file_name, file_line);
00196             }
00197 
00198             iFile = 1;
00199             
00200             strncpy( file, Tokens[++i], sizeof(file)-1 );
00201             file[sizeof(file)-1] = 0x00;
00202         }
00203         else if(!strcmp(Tokens[i], "snortfile"))
00204         {
00205             if( i == (iTokenNum-1) )
00206             {
00207                 FatalError("%s(%d) => Missing 'snortfile' argument.  This "
00208                            "value is the file that save stats.\n", 
00209                            file_name, file_line);
00210             }
00211 
00212             iSnortFile = 1;
00213 
00214             if(pv.log_dir[strlen(pv.log_dir)-1] == '/')
00215             {
00216                 iRet = snprintf(snortfile, sizeof(snortfile),
00217                                 "%s%s", pv.log_dir, Tokens[++i]);
00218             }
00219             else
00220             {
00221                 iRet = snprintf(snortfile, sizeof(snortfile),
00222                                 "%s/%s", pv.log_dir, Tokens[++i]);
00223             }
00224 
00225             if(iRet < 0)
00226             {
00227                 FatalError("%s(%d) => 'snortfile' argument path is too long.\n",
00228                            file_name, file_line);
00229             }
00230         }
00231         else if(!strcmp(Tokens[i], "pktcnt"))
00232         {
00233             if( i == (iTokenNum-1) )
00234             {
00235                 FatalError("%s(%d) => Missing 'pktcnt' argument.  This value "
00236                            "should be a positive integer or zero.\n", 
00237                            file_name, file_line);
00238             }
00239 
00240             iPkts = atoi(Tokens[++i]);
00241             if( iPkts < 0 )
00242                 iPkts = 1000;
00243         }
00244         else if (!strcmp(Tokens[i], "atexitonly"))
00245         {
00246             iStatsExit = 1;
00247         }
00248         else
00249         {
00250             FatalError("%s(%d)=> Invalid parameter '%s' to preprocessor"
00251                        " PerfMonitor.\n", file_name, file_line, Tokens[i]);
00252         }
00253     }
00254 
00255     mSplitFree(&Tokens, iTokenNum);
00256 
00257     /*
00258     *  Initialize the performance system and set flags
00259     */
00260     sfInitPerformanceStatistics(&sfPerf);
00261      
00262     sfSetPerformanceSampleTime( &sfPerf, iTime );
00263 
00264     sfSetPerformanceStatistics( &sfPerf, SFPERF_BASE );
00265     
00266     sfSetPerformanceAccounting( &sfPerf, iReset );
00267     
00268     if( iFlow  ) sfSetPerformanceStatistics( &sfPerf, SFPERF_FLOW );
00269     
00270     if( iEvents) sfSetPerformanceStatistics( &sfPerf, SFPERF_EVENT );
00271 
00272     if( iMaxPerfStats ) sfSetPerformanceStatistics(&sfPerf, SFPERF_BASE_MAX);
00273      
00274     if( iConsole ) sfSetPerformanceStatistics( &sfPerf, SFPERF_CONSOLE );
00275 
00276     if( iFile && iSnortFile )
00277     {
00278         FatalError("%s(%d)=> Cannot log to both 'file' and 'snortfile'.\n",
00279                    file_name, file_line);
00280     }
00281     
00282     if( iFile || iSnortFile || strlen(perf_file) ) 
00283     {
00284         /* use command line override if applicable */
00285         if( strlen(perf_file) )
00286         {
00287             iFile=1;
00288             if( sfSetPerformanceStatisticsEx( &sfPerf, SFPERF_FILE, perf_file ) )
00289             {
00290                 FatalError("Cannot open performance log file '%s'\n",perf_file);
00291             }
00292         }
00293         else
00294         {
00295             if(iFile)
00296             {
00297                 if( sfSetPerformanceStatisticsEx( &sfPerf, SFPERF_FILE, file ) )
00298                 {
00299                     FatalError("Cannot open performance log file '%s'\n",file);
00300                 }
00301             }
00302             else if(iSnortFile)
00303             {
00304                 if( sfSetPerformanceStatisticsEx(&sfPerf, SFPERF_FILE, snortfile) )
00305                 {
00306                     FatalError("Cannot open performance log file '%s'\n",snortfile);
00307                 }
00308             }
00309         }
00310     }
00311     
00312     if( iPkts) sfSetPerformanceStatisticsEx( &sfPerf, SFPERF_PKTCNT, &iPkts );
00313     if( iStatsExit) sfSetPerformanceStatisticsEx( &sfPerf, SFPERF_SUMMARY, &iStatsExit );
00314 
00315     LogMessage("PerfMonitor config:\n");
00316     LogMessage("    Time:           %d seconds\n", iTime);
00317     LogMessage("    Flow Stats:     %s\n", iFlow ? "ACTIVE" : "INACTIVE");
00318     LogMessage("    Event Stats:    %s\n", iEvents ? "ACTIVE" : "INACTIVE");
00319     LogMessage("    Max Perf Stats: %s\n", 
00320             iMaxPerfStats ? "ACTIVE" : "INACTIVE");
00321     LogMessage("    Console Mode:   %s\n", iConsole ? "ACTIVE" : "INACTIVE");
00322     LogMessage("    File Mode:      %s\n", 
00323             iFile ? file : "INACTIVE");
00324     LogMessage("    SnortFile Mode: %s\n", 
00325             iSnortFile ? snortfile : "INACTIVE");
00326     LogMessage("    Packet Count:   %d\n", iPkts);
00327     LogMessage("    Dump Summary:   %s\n", sfPerf.iPerfFlags & SFPERF_SUMMARY ?
00328         "Yes" : "No");
00329 
00330     if (sfPerf.iPerfFlags & SFPERF_SUMMARY)
00331     {
00332         AddFuncToCleanExitList(PerfMonitorCleanExit, NULL);
00333         CheckSampleInterval(time(NULL), &sfPerf);
00334     }
00335    
00336     return;
00337 }
00338 
00339 
00340 /*
00341  * Function: ProcessPerfMonitor(Packet *)
00342  *
00343  * Purpose: Perform the preprocessor's intended function.  This can be
00344  *          simple (statistics collection) or complex (IP defragmentation)
00345  *          as you like.  Try not to destroy the performance of the whole
00346  *          system by trying to do too much....
00347  *
00348  * Arguments: p => pointer to the current packet data struct 
00349  *
00350  * Returns: void function
00351  *
00352  */
00353 static void ProcessPerfMonitor(Packet *p, void *context)
00354 {
00355     /*
00356     *  Performance Statistics  
00357     */
00358     if (!(p->preprocessors & PP_PERFMONITOR))
00359         return;
00360 
00361     if (pv.rotate_perf_file)
00362     {
00363         sfRotatePerformanceStatisticsFile(&sfPerf);
00364         pv.rotate_perf_file = 0;
00365     }
00366 
00367     if(sfPerf.sample_interval > 0)
00368     {
00369         if(p->pkth)
00370         {
00371             sfPerformanceStats(&sfPerf, p->pkt, p->pkth->caplen, 
00372                                p->packet_flags & PKT_REBUILT_STREAM);
00373         }
00374     }
00375     
00376     if( p->tcph )
00377     {
00378         if((p->tcph->th_flags & TH_SYN) && !(p->tcph->th_flags & TH_ACK))
00379         {
00380             /* changed to measure syns */
00381             sfPerf.sfBase.iSyns++;
00382         }
00383         else if((p->tcph->th_flags & TH_SYN) && (p->tcph->th_flags & TH_ACK ))
00384         {
00385             /* this is a better approximation of connections */
00386             sfPerf.sfBase.iSynAcks++;
00387         }
00388     }
00389 
00390     /*
00391     *  TCP Flow Perf
00392     */
00393     if(sfPerf.iPerfFlags & SFPERF_FLOW)
00394    {
00395         /*
00396         **  TCP Flow Stats
00397         */
00398         if( p->tcph )
00399         {
00400             UpdateTCPFlowStatsEx(p->sp, p->dp, p->pkth->caplen);
00401         }
00402         /*
00403         *  UDP Flow Stats
00404         */
00405         else if( p->udph )
00406             UpdateUDPFlowStatsEx(p->sp, p->dp, p->pkth->caplen);
00407 
00408         /*
00409         *  Get stats for ICMP packets
00410         */
00411         else if( p->icmph )
00412             UpdateICMPFlowStatsEx(p->icmph->type, p->pkth->caplen);
00413     }
00414 
00415     return;
00416 }
00417 
00418 /**
00419  * CleanExit func required by preprocessors
00420  */
00421 void PerfMonitorCleanExit(int signal, void *foo)
00422 {
00423     sfProcessPerfStats(&sfPerf);
00424     return;
00425 }
00426 

Generated on Sun May 14 14:51:16 2006 by  doxygen 1.4.2