1 /*
2 ** $Id$
3 **
4 ** perf.c
5 **
6 ** Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved.
7 ** Copyright (C) 2002-2013 Sourcefire, Inc.
8 ** Dan Roelker <droelker@sourcefire.com>
9 **
10 ** This program is free software; you can redistribute it and/or modify
11 ** it under the terms of the GNU General Public License Version 2 as
12 ** published by the Free Software Foundation. You may not use, modify or
13 ** distribute this program under any other version of the GNU General
14 ** Public License.
15 **
16 ** This program is distributed in the hope that it will be useful,
17 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
18 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 ** GNU General Public License for more details.
20 **
21 ** You should have received a copy of the GNU General Public License
22 ** along with this program; if not, write to the Free Software
23 ** Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24 **
25 **
26 ** DESCRIPTION
27 ** These are the basic functions that are needed to call performance
28 ** functions.
29 **
30 */
31
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include <sys/types.h>
36 #include <sys/stat.h>
37 #include <errno.h>
38
39 #ifndef WIN32
40 # include <time.h>
41 # include <unistd.h>
42 #endif /* WIN32 */
43
44 #ifdef HAVE_CONFIG_H
45 #include "config.h"
46 #endif
47
48 #include "util.h"
49 #include "perf.h"
50 #include "sf_types.h"
51 #include "decode.h"
52 #include "snort.h"
53
54 SFBASE sfBase;
55 SFFLOW sfFlow;
56 SFEVENT sfEvent;
57 int perfmon_rotate_perf_file = 0;
58 static uint32_t pkt_cnt = 0;
59
60 #ifdef SNORT_RELOAD
61 extern SFPERF* perfmon_config;
62 PERFRELOAD_STATUS perfmon_reload_status = PERF_NOT_RELOADING;
63 #endif
64
65 static void UpdatePerfStats(SFPERF *, Packet *p);
66 static bool CheckSampleInterval(SFPERF *, time_t);
67 static inline bool sfCheckFileSize(FILE *, uint32_t);
68 static inline void sfProcessBaseStats(SFPERF *);
69 static inline void sfProcessFlowStats(SFPERF *);
70 static inline void sfProcessFlowIpStats(SFPERF *);
71 static inline void sfProcessEventStats(SFPERF *);
72 static inline int sfRotateFlowIPStatsFile(SFPERF *);
73 static int sfRotateFile(const char *, FILE *, const char *, uint32_t);
74
sfInitPerformanceStatistics(SFPERF * sfPerf)75 void sfInitPerformanceStatistics(SFPERF *sfPerf)
76 {
77 memset(sfPerf, 0, sizeof(SFPERF));
78 sfPerf->sample_interval = 60;
79 sfPerf->flow_max_port_to_track = 1023;
80 sfPerf->perf_flags |= SFPERF_BASE;
81 sfPerf->pkt_cnt = 10000;
82 sfPerf->max_file_size = MAX_PERF_FILE_SIZE;
83 sfPerf->flowip_memcap = 50*1024*1024;
84 sfPerf->base_reset = 1;
85
86 #ifdef LINUX_SMP
87 sfInitProcPidStats(&(sfBase.sfProcPidStats));
88 #endif
89 }
90
WriteTimeStamp(FILE * fh,const char * action)91 static void WriteTimeStamp(FILE *fh, const char *action)
92 {
93 time_t curr_time = time(NULL);
94
95 if (fh == NULL)
96 return;
97
98 fprintf(fh,
99 "################################### "
100 "Perfmon %s: pid=%u at=%.24s (%lu) "
101 "###################################\n",
102 action, getpid(),
103 ctime(&curr_time), (unsigned long)curr_time);
104
105 fflush(fh);
106 }
107
sfOpenBaseStatsFile(const char * file)108 FILE * sfOpenBaseStatsFile(const char *file)
109 {
110 static bool start_up = true;
111 FILE *fh = NULL;
112 bool reload = false;
113
114 #ifdef SNORT_RELAOD
115 reload = perfmon_reload_status != PERF_NOT_RELOADING;
116 #endif
117
118 #ifndef WIN32
119
120 // This file needs to be readable by everyone
121 mode_t old_umask = umask(022);
122 #endif
123
124 if (file != NULL)
125 {
126 // Append to the existing file if just starting up or reloading, otherwise we've
127 // rotated so start a new one.
128 bool append = start_up || reload;
129 fh = fopen(file, append ? "a" : "w");
130 if (fh != NULL)
131 {
132 WriteTimeStamp(fh, append ? "start" : "rotate");
133 LogBasePerfHeader(fh);
134 }
135 }
136
137 #ifndef WIN32
138 umask(old_umask);
139 #endif
140
141 if (start_up)
142 start_up = false;
143
144 return fh;
145 }
146
sfCloseBaseStatsFile(SFPERF * sfPerf)147 void sfCloseBaseStatsFile(SFPERF *sfPerf)
148 {
149 if (sfPerf->fh == NULL)
150 return;
151
152 WriteTimeStamp(sfPerf->fh, "stop");
153 fclose(sfPerf->fh);
154 sfPerf->fh = NULL;
155 }
156
sfOpenFlowStatsFile(const char * file)157 FILE * sfOpenFlowStatsFile(const char *file)
158 {
159 static bool start_up = true;
160 FILE *fh = NULL;
161 bool reload = false;
162
163 #ifdef SNORT_RELOAD
164 reload = perfmon_reload_status != PERF_NOT_RELOADING;
165 #endif
166
167 #ifndef WIN32
168 // This file needs to be readable by everyone
169 mode_t old_umask = umask(022);
170 #endif
171
172 if (file != NULL)
173 {
174 // Append to the existing file if just starting up or reloading, otherwise we've
175 // rotated so start a new one.
176 bool append = start_up || reload;
177 fh = fopen(file, append ? "a" : "w");
178 if (fh != NULL)
179 {
180 WriteTimeStamp(fh, append ? "start" : "rotate");
181 LogFlowPerfHeader(fh);
182 }
183 }
184
185 #ifndef WIN32
186 umask(old_umask);
187 #endif
188
189 if (start_up)
190 start_up = false;
191
192 return fh;
193 }
194
sfCloseFlowStatsFile(SFPERF * sfPerf)195 void sfCloseFlowStatsFile(SFPERF *sfPerf)
196 {
197 if (sfPerf->flow_fh == NULL)
198 return;
199
200 WriteTimeStamp(sfPerf->flow_fh, "stop");
201 fclose(sfPerf->flow_fh);
202 sfPerf->flow_fh = NULL;
203 }
204
sfOpenFlowIPStatsFile(const char * file)205 FILE * sfOpenFlowIPStatsFile(const char *file)
206 {
207 static bool start_up = true;
208 FILE *fh = NULL;
209 bool reload = false;
210
211 #ifdef SNORT_RELOAD
212 reload = perfmon_reload_status != PERF_NOT_RELOADING;
213 #endif
214
215 #ifndef WIN32
216 // This file needs to be readable by everyone
217 mode_t old_umask = umask(022);
218 #endif
219
220 if (file != NULL)
221 {
222 // Append to the existing file if just starting up or reloading, otherwise we've
223 // rotated so start a new one.
224 fh = fopen(file, start_up || reload ? "a" : "w");
225 }
226
227 #ifndef WIN32
228 umask(old_umask);
229 #endif
230
231 if (start_up)
232 start_up = false;
233
234 return fh;
235 }
236
sfCloseFlowIPStatsFile(SFPERF * sfPerf)237 void sfCloseFlowIPStatsFile(SFPERF *sfPerf)
238 {
239 if (sfPerf->flowip_fh == NULL)
240 return;
241
242 fclose(sfPerf->flowip_fh);
243 sfPerf->flowip_fh = NULL;
244 }
245
sfRotateFile(const char * old_file,FILE * old_fh,const char * rotate_prefix,uint32_t max_file_size)246 static int sfRotateFile(const char *old_file, FILE *old_fh,
247 const char *rotate_prefix, uint32_t max_file_size)
248 {
249 time_t ts;
250 struct tm *tm;
251 char rotate_file[PATH_MAX];
252 char *path_ptr;
253 int path_len = 0;
254 struct stat file_stats;
255
256 if (old_file == NULL)
257 return -1;
258
259 if (old_fh == NULL)
260 {
261 ErrorMessage("Perfmonitor: Performance stats file \"%s\" "
262 "isn't open.\n", old_file);
263 return -1;
264 }
265
266 // Close the current stats file if it's already open
267 fclose(old_fh);
268 old_fh = NULL;
269
270 // Rename current stats file with yesterday's date
271 #ifndef WIN32
272 path_ptr = strrchr(old_file, '/');
273 #else
274 path_ptr = strrchr(old_file, '\\');
275 #endif
276
277 if (path_ptr != NULL)
278 {
279 // Take the length of the file/path name up to the path separator and
280 // add one to include path separator
281 path_len = (path_ptr - old_file) + 1;
282 }
283
284 // Get current time, then subtract one day to get yesterday
285 ts = time(NULL);
286 ts -= (24*60*60);
287 tm = localtime(&ts);
288
289 // Create rotate file name based on path, optional prefix and date
290 SnortSnprintf(rotate_file, PATH_MAX, "%.*s%s%s%d-%02d-%02d", path_len, old_file,
291 (rotate_prefix != NULL) ? rotate_prefix : "", (rotate_prefix != NULL) ? "-" : "",
292 tm->tm_year + 1900, tm->tm_mon + 1, tm->tm_mday);
293
294 // If the rotate file doesn't exist, just rename the old one to the new one
295 if (stat(rotate_file, &file_stats) != 0)
296 {
297 if (rename(old_file, rotate_file) != 0)
298 {
299 ErrorMessage("Perfmonitor: Could not rename performance stats "
300 "file from \"%s\" to \"%s\": %s.\n",
301 old_file, rotate_file, strerror(errno));
302 }
303 }
304 else // Otherwise, if it does exist, append data from current stats file to it
305 {
306 char read_buf[4096];
307 size_t num_read, num_wrote;
308 FILE *rotate_fh;
309 int rotate_index = 0;
310 char rotate_file_with_index[PATH_MAX];
311 #ifndef WIN32
312 // This file needs to be readable by everyone
313 mode_t old_umask = umask(022);
314 #endif
315
316 do
317 {
318 do
319 {
320 rotate_index++;
321
322 // Check to see if there are any files already rotated and indexed
323 SnortSnprintf(rotate_file_with_index, PATH_MAX, "%s.%02d",
324 rotate_file, rotate_index);
325
326 } while (stat(rotate_file_with_index, &file_stats) == 0);
327
328 // Subtract one to append to last existing file
329 rotate_index--;
330
331 if (rotate_index == 0)
332 {
333 rotate_file_with_index[0] = 0;
334 rotate_fh = fopen(rotate_file, "a");
335 }
336 else
337 {
338 SnortSnprintf(rotate_file_with_index, PATH_MAX, "%s.%02d",
339 rotate_file, rotate_index);
340 rotate_fh = fopen(rotate_file_with_index, "a");
341 }
342
343 if (rotate_fh == NULL)
344 {
345 ErrorMessage("Perfmonitor: Could not open performance stats "
346 "archive file \"%s\" for appending: %s.\n",
347 *rotate_file_with_index ? rotate_file_with_index : rotate_file,
348 strerror(errno));
349 break;
350 }
351
352 old_fh = fopen(old_file, "r");
353 if (old_fh == NULL)
354 {
355 ErrorMessage("Perfmonitor: Could not open performance stats file "
356 "\"%s\" for reading to copy to archive \"%s\": %s.\n",
357 old_file, (*rotate_file_with_index ? rotate_file_with_index :
358 rotate_file), strerror(errno));
359 break;
360 }
361
362 while (!feof(old_fh))
363 {
364 // This includes the newline from the file.
365 if (fgets(read_buf, sizeof(read_buf), old_fh) == NULL)
366 {
367 if (feof(old_fh))
368 break;
369
370 if (ferror(old_fh))
371 {
372 // A read error occurred
373 ErrorMessage("Perfmonitor: Error reading performance stats "
374 "file \"%s\": %s.\n", old_file, strerror(errno));
375 break;
376 }
377 }
378
379 num_read = strlen(read_buf);
380
381 if (num_read > 0)
382 {
383 int rotate_fd = fileno(rotate_fh);
384
385 if (fstat(rotate_fd, &file_stats) != 0)
386 {
387 ErrorMessage("Perfmonitor: Error getting file "
388 "information for \"%s\": %s.\n",
389 *rotate_file_with_index ? rotate_file_with_index : rotate_file,
390 strerror(errno));
391 break;
392 }
393
394 if (((uint32_t)file_stats.st_size + num_read) > max_file_size)
395 {
396 fclose(rotate_fh);
397
398 rotate_index++;
399
400 // Create new file same as before but with an index added to the end
401 SnortSnprintf(rotate_file_with_index, PATH_MAX, "%s.%02d",
402 rotate_file, rotate_index);
403
404 rotate_fh = fopen(rotate_file_with_index, "a");
405 if (rotate_fh == NULL)
406 {
407 ErrorMessage("Perfmonitor: Could not open performance "
408 "stats archive file \"%s\" for writing: %s.\n",
409 rotate_file_with_index, strerror(errno));
410 break;
411 }
412 }
413
414 num_wrote = fprintf(rotate_fh, "%s", read_buf);
415 if ((num_wrote != num_read) && ferror(rotate_fh))
416 {
417 // A bad write occurred
418 ErrorMessage("Perfmonitor: Error writing to performance "
419 "stats archive file \"%s\": %s.\n", rotate_file, strerror(errno));
420 break;
421 }
422
423 fflush(rotate_fh);
424 }
425 }
426 } while (0);
427
428 if (rotate_fh != NULL)
429 fclose(rotate_fh);
430
431 if (old_fh != NULL)
432 fclose(old_fh);
433
434 #ifndef WIN32
435 umask(old_umask);
436 #endif
437 }
438
439 return 0;
440 }
441
sfRotateBaseStatsFile(SFPERF * sfPerf)442 int sfRotateBaseStatsFile(SFPERF *sfPerf)
443 {
444 if ((sfPerf != NULL) && (sfPerf->file != NULL))
445 {
446 int ret = sfRotateFile(sfPerf->file, sfPerf->fh, NULL, sfPerf->max_file_size);
447 if (ret != 0)
448 return ret;
449
450 if ((sfPerf->fh = sfOpenBaseStatsFile(sfPerf->file)) == NULL)
451 {
452 FatalError("Cannot open performance stats file \"%s\": %s.\n",
453 sfPerf->file, strerror(errno));
454 }
455 }
456
457 return 0;
458 }
459
sfRotateFlowStatsFile(SFPERF * sfPerf)460 int sfRotateFlowStatsFile(SFPERF *sfPerf)
461 {
462 if ((sfPerf != NULL) && (sfPerf->flow_file != NULL))
463 {
464 int ret = sfRotateFile(sfPerf->flow_file, sfPerf->flow_fh, "flow", sfPerf->max_file_size);
465 if (ret != 0)
466 return ret;
467
468 if ((sfPerf->flow_fh = sfOpenFlowStatsFile(sfPerf->flow_file)) == NULL)
469 {
470 FatalError("Perfmonitor: Cannot open flow stats file \"%s\": %s.\n",
471 sfPerf->flow_file, strerror(errno));
472 }
473 }
474
475 return 0;
476 }
477
sfRotateFlowIPStatsFile(SFPERF * sfPerf)478 static inline int sfRotateFlowIPStatsFile(SFPERF *sfPerf)
479 {
480 if ((sfPerf != NULL) && (sfPerf->flowip_file != NULL))
481 {
482 int ret = sfRotateFile(sfPerf->flowip_file, sfPerf->flowip_fh, "flow-ip", sfPerf->max_file_size);
483 if (ret != 0)
484 return ret;
485
486 if ((sfPerf->flowip_fh = sfOpenFlowIPStatsFile(sfPerf->flowip_file)) == NULL)
487 {
488 FatalError("Perfmonitor: Cannot open flow-ip stats file \"%s\": %s.\n",
489 sfPerf->flowip_file, strerror(errno));
490 }
491 }
492
493 return 0;
494 }
495
sfPerformanceStats(SFPERF * sfPerf,Packet * p)496 void sfPerformanceStats(SFPERF *sfPerf, Packet *p)
497 {
498 // Update stats first since other stats from various places like frag3 and
499 // stream5 have been added.
500 UpdatePerfStats(sfPerf, p);
501
502 if ((sfPerf->perf_flags & SFPERF_TIME_COUNT) && !PacketIsRebuilt(p))
503 {
504 pkt_cnt++;
505 sfPerformanceStatsOOB(sfPerf, p->pkth->ts.tv_sec);
506 }
507 }
508
sfPerformanceStatsOOB(SFPERF * sfPerf,time_t curr_time)509 void sfPerformanceStatsOOB(SFPERF *sfPerf, time_t curr_time)
510 {
511 if (sfPerf && pkt_cnt >= sfPerf->pkt_cnt) //For perfect alignment, sfPerf->pkt_count should be set to 0 in config
512 {
513 if (CheckSampleInterval(sfPerf, curr_time))
514 {
515 pkt_cnt = 0;
516
517 if (!(sfPerf->perf_flags & SFPERF_SUMMARY_BASE))
518 {
519 if (sfPerf->perf_flags & SFPERF_BASE)
520 {
521 sfProcessBaseStats(sfPerf);
522 InitBaseStats(&sfBase);
523 }
524 }
525
526 if (!(sfPerf->perf_flags & SFPERF_SUMMARY_FLOW))
527 {
528 if (sfPerf->perf_flags & SFPERF_FLOW)
529 {
530 sfProcessFlowStats(sfPerf);
531 InitFlowStats(&sfFlow);
532 }
533 }
534
535 if (!(sfPerf->perf_flags & SFPERF_SUMMARY_FLOWIP))
536 {
537 if (sfPerf->perf_flags & SFPERF_FLOWIP)
538 {
539 sfProcessFlowIpStats(sfPerf);
540 InitFlowIPStats(&sfFlow);
541 }
542 }
543
544 if (!(sfPerf->perf_flags & SFPERF_SUMMARY_EVENT))
545 {
546 if (sfPerf->perf_flags & SFPERF_EVENT)
547 {
548 sfProcessEventStats(sfPerf);
549 InitEventStats(&sfEvent);
550 }
551 }
552 }
553 }
554 }
555
CheckSampleInterval(SFPERF * sfPerf,time_t curr_time)556 static bool CheckSampleInterval(SFPERF *sfPerf, time_t curr_time)
557 {
558 static time_t last_true = 0;
559
560 //Initial alignment
561 if (last_true == 0)
562 {
563 last_true = curr_time;
564 last_true -= last_true % sfPerf->sample_interval;
565 }
566
567 //Dump on aligned time if possible. If not, get close and say we did.
568 if (curr_time - last_true >= sfPerf->sample_interval)
569 {
570 curr_time -= curr_time % sfPerf->sample_interval;
571 sfBase.time = curr_time;
572 sfFlow.time = curr_time;
573 last_true = curr_time;
574 return true;
575 }
576
577 return false;
578 }
579
InitPerfStats(SFPERF * sfPerf)580 void InitPerfStats(SFPERF *sfPerf)
581 {
582 #ifdef LINUX_SMP
583 memset(&sfBase, 0, offsetof(SFBASE, sfProcPidStats));
584 #else
585 memset(&sfBase, 0, sizeof(SFBASE));
586 #endif
587 memset(&sfFlow, 0, sizeof(SFFLOW));
588 memset(&sfEvent, 0, sizeof(SFEVENT));
589 if (sfPerf->perf_flags & SFPERF_BASE)
590 InitBaseStats(&sfBase);
591
592 if (sfPerf->perf_flags & SFPERF_FLOW)
593 InitFlowStats(&sfFlow);
594
595 if (sfPerf->perf_flags & SFPERF_FLOWIP)
596 InitFlowIPStats(&sfFlow);
597
598 if (sfPerf->perf_flags & SFPERF_EVENT)
599 InitEventStats(&sfEvent);
600 }
601
UpdatePerfStats(SFPERF * sfPerf,Packet * p)602 static void UpdatePerfStats(SFPERF *sfPerf, Packet *p)
603 {
604 bool rebuilt = PacketIsRebuilt(p);
605
606 if (sfPerf->perf_flags & SFPERF_BASE)
607 UpdateBaseStats(&sfBase, p, rebuilt);
608
609 if ((sfPerf->perf_flags & SFPERF_FLOW) && !rebuilt)
610 UpdateFlowStats(&sfFlow, p);
611
612 if ((sfPerf->perf_flags & SFPERF_FLOWIP) && IsIP(p) && !rebuilt)
613 {
614 SFSType type = SFS_TYPE_OTHER;
615
616 if (p->tcph != NULL)
617 type = SFS_TYPE_TCP;
618 else if (p->udph != NULL)
619 type = SFS_TYPE_UDP;
620
621 UpdateFlowIPStats(&sfFlow, GET_SRC_IP(p), GET_DST_IP(p), p->pkth->caplen, type);
622 }
623 }
624
sfCheckFileSize(FILE * fh,uint32_t max_file_size)625 static inline bool sfCheckFileSize(FILE *fh, uint32_t max_file_size)
626 {
627 int fd;
628 struct stat file_stats;
629
630 if (fh == NULL)
631 return false;
632
633 fd = fileno(fh);
634 if ((fstat(fd, &file_stats) == 0)
635 && ((uint32_t)file_stats.st_size >= max_file_size))
636 return true;
637
638 return false;
639 }
640
sfProcessBaseStats(SFPERF * sfPerf)641 static inline void sfProcessBaseStats(SFPERF *sfPerf)
642 {
643 if (!(sfPerf->perf_flags & SFPERF_BASE))
644 return;
645
646 ProcessBaseStats(&sfBase, sfPerf->fh,
647 sfPerf->perf_flags & SFPERF_CONSOLE,
648 sfPerf->perf_flags & SFPERF_MAX_BASE_STATS);
649
650 if ((sfPerf->fh != NULL)
651 && sfCheckFileSize(sfPerf->fh, sfPerf->max_file_size))
652 {
653 sfRotateBaseStatsFile(sfPerf);
654 }
655 }
656
sfProcessFlowStats(SFPERF * sfPerf)657 static inline void sfProcessFlowStats(SFPERF *sfPerf)
658 {
659 if (!(sfPerf->perf_flags & SFPERF_FLOW))
660 return;
661
662 ProcessFlowStats(&sfFlow, sfPerf->flow_fh,
663 sfPerf->perf_flags & SFPERF_CONSOLE);
664
665 if ((sfPerf->flow_fh != NULL)
666 && sfCheckFileSize(sfPerf->flow_fh, sfPerf->max_file_size))
667 {
668 sfRotateFlowStatsFile(sfPerf);
669 }
670 }
671
sfProcessFlowIpStats(SFPERF * sfPerf)672 static inline void sfProcessFlowIpStats(SFPERF *sfPerf)
673 {
674 if (!(sfPerf->perf_flags & SFPERF_FLOWIP))
675 return;
676
677 ProcessFlowIPStats(&sfFlow, sfPerf->flowip_fh,
678 sfPerf->perf_flags & SFPERF_CONSOLE);
679
680 if ((sfPerf->flowip_fh != NULL)
681 && sfCheckFileSize(sfPerf->flowip_fh, sfPerf->max_file_size))
682 {
683 sfRotateFlowIPStatsFile(sfPerf);
684 }
685 }
686
sfProcessEventStats(SFPERF * sfPerf)687 static inline void sfProcessEventStats(SFPERF *sfPerf)
688 {
689 if (!(sfPerf->perf_flags & SFPERF_EVENT))
690 return;
691
692 if (sfPerf->perf_flags & SFPERF_CONSOLE)
693 ProcessEventStats(&sfEvent);
694 }
695
sfPerfStatsSummary(SFPERF * sfPerf)696 void sfPerfStatsSummary(SFPERF *sfPerf)
697 {
698 if (sfPerf == NULL)
699 return;
700
701 if (sfPerf->perf_flags & SFPERF_SUMMARY_BASE)
702 sfProcessBaseStats(sfPerf);
703
704 if (sfPerf->perf_flags & SFPERF_SUMMARY_FLOW)
705 sfProcessFlowStats(sfPerf);
706
707 if (sfPerf->perf_flags & SFPERF_SUMMARY_FLOWIP)
708 sfProcessFlowIpStats(sfPerf);
709
710 if (sfPerf->perf_flags & SFPERF_SUMMARY_EVENT)
711 sfProcessEventStats(sfPerf);
712 }
713
sfInitBaseStats(SFPERF * sfPerf)714 static void sfInitBaseStats(SFPERF *sfPerf)
715 {
716 if (sfPerf->perf_flags & SFPERF_BASE)
717 InitBaseStats(&sfBase);
718 }
719
sfInitFlowStats(SFPERF * sfPerf)720 static void sfInitFlowStats(SFPERF *sfPerf)
721 {
722 if (sfPerf->perf_flags & SFPERF_FLOW)
723 InitFlowStats(&sfFlow);
724 }
725
sfInitFlowIPStats(SFPERF * sfPerf)726 static void sfInitFlowIPStats(SFPERF *sfPerf)
727 {
728 if (sfPerf->perf_flags & SFPERF_FLOWIP)
729 InitFlowIPStats(&sfFlow);
730 }
731
sfInitEventStats(SFPERF * sfPerf)732 static void sfInitEventStats(SFPERF *sfPerf)
733 {
734 if (sfPerf->perf_flags & SFPERF_EVENT)
735 InitEventStats(&sfEvent);
736 }
737
sfFreeFlowStats(SFPERF * sfPerf)738 static void sfFreeFlowStats(SFPERF *sfPerf)
739 {
740 FreeFlowStats(&sfFlow);
741 }
742
sfFreeFlowIPStats(SFPERF * sfPerf)743 static void sfFreeFlowIPStats(SFPERF *sfPerf)
744 {
745 FreeFlowIPStats(&sfFlow);
746 }
747
748 #ifdef SNORT_RELOAD
749 //this function determines what is necessary to swap configs and keep stats and files synchronized
750 //it will perform the actions necessary durring the appropriate stage of ReloadSwap
751 // or you can force it to perform all actions by setting fullSync to a non-zero value
752 //
753 //if fullSync is set to 0 then actions are taken under the following conditions
754 //If files need to be opened they are opened durring ReloadVerify
755 //If stats need to be written to files and flushed it is done durring ReloadSwap
756 //If files need to be closed it is done durring ReloadSwapFree
syncStats(SFPERF * currentSFPerf,SFPERF * newSFPerf,int flag,int summaryFlag,char * currentFile,char * newFile,FILE ** currentFH,FILE ** newFH,void (* processFunc)(SFPERF *),void (* initFunc)(SFPERF *),void (* freeFunc)(SFPERF *),FILE * (* openFileFunc)(const char *),void (* closeFileFunc)(SFPERF *),int fullSync)757 static void syncStats( SFPERF *currentSFPerf, SFPERF *newSFPerf,
758 int flag, int summaryFlag, //if summaryFlag is set then flag is set
759 char *currentFile, char *newFile,
760 FILE **currentFH, FILE **newFH,
761 void (*processFunc)(SFPERF *),
762 void (*initFunc)(SFPERF *), void (*freeFunc)(SFPERF *),
763 FILE* (*openFileFunc)(const char *), void (*closeFileFunc)(SFPERF *),
764 int fullSync)
765 {
766 int old_flags = currentSFPerf->perf_flags;
767 int new_flags = newSFPerf->perf_flags;
768 int config_flags = old_flags | new_flags;
769
770 //summaryFlag implies that flag is set
771 //otherwise code breaks <- I got this implication from other sets of code (i.e. InitPerfStats)
772
773 //these stats were recorded, but are not recorded in new config
774 if (old_flags & flag && !(new_flags & flag))
775 {
776 //we need to flush the stats at the correct time
777 if (perfmon_reload_status == PERF_RELOAD_SWAP || fullSync)
778 //write stats for last period (or summary)
779 (*processFunc)(currentSFPerf);
780 //only close files in ReloadSwapFree to avoid latencies
781 if (perfmon_reload_status == PERF_RELOAD_SWAP_FREE || fullSync)
782 {
783 //not every stat group has a file
784 if (closeFileFunc != NULL)
785 (*closeFileFunc)(currentSFPerf);
786 //not every stat group uses dynamic memory
787 if (freeFunc != NULL)
788 (*freeFunc)(currentSFPerf);
789 }
790 }
791 //these stats were not recorded, but will be recorded in new config
792 else if ( !(old_flags & flag) && new_flags & flag )
793 {
794 if (perfmon_reload_status == PERF_RELOAD_VERIFY || fullSync)
795 {
796 //init/reset stats
797 (*initFunc)(newSFPerf);
798 //open up new file
799 if (openFileFunc)
800 *newFH = (*openFileFunc)(newFile);
801 }
802 }
803 // both configs have flag
804 else if (config_flags & flag)
805 {
806 //one config is not summary
807 if (!(old_flags & summaryFlag && new_flags & summaryFlag))
808 {
809 if (perfmon_reload_status == PERF_RELOAD_SWAP || fullSync)
810 {
811 //log and clear stats
812 (*processFunc)(currentSFPerf);
813 (*initFunc)(currentSFPerf);
814 }
815 }
816 //stat group must have log files
817 if ( openFileFunc != NULL && closeFileFunc != NULL)
818 {
819 //the new file has a new name
820 if ( newFile != NULL
821 && (currentFile == NULL || strcmp(currentFile,newFile) != 0))
822 {
823 if (perfmon_reload_status == PERF_RELOAD_VERIFY || fullSync)
824 *newFH = (*openFileFunc)(newFile);
825 if (perfmon_reload_status == PERF_RELOAD_SWAP_FREE || fullSync)
826 (*closeFileFunc)(currentSFPerf);
827 }
828 //use the same file
829 else if (*currentFH != NULL)
830 {
831 if (perfmon_reload_status == PERF_RELOAD_SWAP || fullSync)
832 *newFH = *currentFH;
833 }
834 }
835 }
836 //else neither config has stats logged
837 }
838
839 //you can have SFPERF_SUMMARY_FLAG without a SFPERF_FLAG, but
840 //perfmon acts as though neither flag is set and doesn't do any logging
841 //for those statisitcs
syncAllStats(SFPERF * currentSFPerf,SFPERF * newSFPerf)842 void syncAllStats(SFPERF *currentSFPerf, SFPERF *newSFPerf)
843 {
844 if (currentSFPerf == NULL || newSFPerf == NULL)
845 return;
846
847 //base stats
848 syncStats( currentSFPerf, newSFPerf,
849 SFPERF_BASE, SFPERF_SUMMARY_BASE,
850 currentSFPerf->file, newSFPerf->file,
851 &(currentSFPerf->fh), &(newSFPerf->fh),
852 &sfProcessBaseStats,
853 &sfInitBaseStats, NULL,
854 &sfOpenBaseStatsFile, &sfCloseBaseStatsFile,
855 0);
856 //flow stats
857 syncStats( currentSFPerf,newSFPerf,
858 SFPERF_FLOW, SFPERF_SUMMARY_FLOW,
859 currentSFPerf->flow_file, newSFPerf->flow_file,
860 &(currentSFPerf->flow_fh), &(newSFPerf->flow_fh),
861 &sfProcessFlowStats,
862 &sfInitFlowStats, &sfFreeFlowStats,
863 &sfOpenFlowStatsFile, &sfCloseFlowStatsFile,
864 0);
865
866 //flowip stats
867 syncStats( currentSFPerf, newSFPerf,
868 SFPERF_FLOWIP, SFPERF_SUMMARY_FLOWIP,
869 currentSFPerf->flowip_file, newSFPerf->flowip_file,
870 &(currentSFPerf->flowip_fh), &(newSFPerf->flowip_fh),
871 &sfProcessFlowIpStats,
872 &sfInitFlowIPStats, &sfFreeFlowIPStats,
873 &sfOpenFlowIPStatsFile, &sfCloseFlowIPStatsFile,
874 0);
875
876 //event stats
877 syncStats( currentSFPerf, newSFPerf,
878 SFPERF_EVENT, SFPERF_SUMMARY_EVENT,
879 NULL, NULL,
880 NULL, NULL,
881 &sfProcessEventStats,
882 &sfInitEventStats, NULL,
883 NULL, NULL,
884 0);
885 }
886 #endif
887
888