1 /**************************************************************************** 2 * 3 * Copyright (C) 2014-2021 Cisco and/or its affiliates. All rights reserved. 4 * Copyright (C) 2006-2013 Sourcefire, Inc. 5 * 6 * This program is free software; you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License Version 2 as 8 * published by the Free Software Foundation. You may not use, modify or 9 * distribute this program under any other version of the GNU General 10 * Public License. 11 * 12 * This program is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 * GNU General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with this program; if not, write to the Free Software 19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 20 * 21 ****************************************************************************/ 22 23 /* 24 ** ppm.h - packet performance monitor 25 ** 26 ** Author: Marc Norton <mnorton@sourcefire.com> 27 ** 28 */ 29 30 #ifndef __PACKET_PROCESSING_MONITOR_H__ 31 #define __PACKET_PROCESSING_MONITOR_H__ 32 33 #ifdef PPM_MGR 34 35 #include "sf_types.h" 36 #include "cpuclock.h" 37 38 #define cputime get_clockticks 39 40 typedef uint64_t PPM_TICKS; 41 typedef uint64_t PPM_USECS; 42 typedef unsigned int PPM_SECS; 43 44 struct _SnortConfig; 45 46 extern struct _SnortConfig *snort_conf; 47 48 typedef struct 49 { 50 /* config section */ 51 int enabled; 52 53 PPM_TICKS max_pkt_ticks; 54 int pkt_log; /* alert,console,syslog */ 55 int pkt_action; /* suspend */ 56 57 PPM_TICKS max_rule_ticks; 58 uint64_t rule_threshold; /* rules must fail this many times in a row to suspend */ 59 60 int rule_log; /* alert,console,syslog */ 61 int rule_action; /* suspend */ 62 63 #ifdef DEBUG 64 int debug_pkts; 65 int debug_rules; 66 #endif 67 68 /* stats section */ 69 unsigned int rule_event_cnt; 70 unsigned int pkt_event_cnt; 71 72 uint64_t tot_pkt_time; /* ticks */ 73 uint64_t tot_pkts; 74 75 uint64_t tot_rule_time; /* ticks */ 76 uint64_t tot_rules; 77 78 uint64_t tot_nc_rule_time; /* ticks */ 79 uint64_t tot_nc_rules; 80 81 uint64_t tot_pcre_rule_time; /* ticks */ 82 uint64_t tot_pcre_rules; 83 84 uint64_t max_suspend_ticks; 85 86 } ppm_cfg_t; 87 88 typedef struct 89 { 90 uint64_t pktcnt; 91 uint64_t start, cur, tot; 92 uint64_t subtract; 93 PPM_TICKS max_pkt_ticks; 94 unsigned int rule_tests; 95 unsigned int pcre_rule_tests; 96 unsigned int nc_rule_tests; 97 98 } ppm_pkt_timer_t; 99 100 typedef struct 101 { 102 uint64_t start, cur, tot; 103 PPM_TICKS max_rule_ticks; 104 105 } ppm_rule_timer_t; 106 107 /* global data */ 108 #define PPM_MAX_TIMERS 10 109 extern PPM_TICKS ppm_tpu; 110 extern ppm_pkt_timer_t ppm_pkt_times[PPM_MAX_TIMERS]; 111 extern ppm_pkt_timer_t *ppm_pt; 112 extern unsigned int ppm_pkt_index; 113 extern ppm_rule_timer_t ppm_rule_times[PPM_MAX_TIMERS]; 114 extern ppm_rule_timer_t *ppm_rt; 115 extern unsigned int ppm_rule_times_index; 116 extern uint64_t ppm_cur_time; 117 extern int ppm_abort_this_pkt; 118 extern int ppm_suspend_this_rule; 119 120 #define PPM_LOG_ALERT 1 121 #define PPM_LOG_MESSAGE 2 122 #define PPM_ACTION_SUSPEND 1 123 124 /* Config flags */ 125 #define PPM_ENABLED() (snort_conf->ppm_cfg.enabled > 0) 126 #define PPM_PKTS_ENABLED() (snort_conf->ppm_cfg.max_pkt_ticks > 0) 127 #define PPM_RULES_ENABLED() (snort_conf->ppm_cfg.max_rule_ticks > 0) 128 129 /* packet, rule event flags */ 130 #define PPM_PACKET_ABORT_FLAG() ppm_abort_this_pkt 131 #define PPM_RULE_SUSPEND_FLAG() ppm_suspend_this_rule 132 133 #define PPM_INC_PKT_CNT() snort_conf->ppm_cfg.tot_pkts++ 134 #define PPM_PKT_CNT() ppm_pt->pktcnt 135 #define PPM_PKT_LOG(p) if (ppm_abort_this_pkt) ppm_pkt_log(&snort_conf->ppm_cfg,p) 136 #define PPM_RULE_LOG(cnt,p) ppm_rule_log(&snort_conf->ppm_cfg,cnt,p) 137 #define PPM_ACCUM_PKT_TIME() snort_conf->ppm_cfg.tot_pkt_time += ppm_pt->tot; 138 #define PPM_ACCUM_RULE_TIME() \ 139 snort_conf->ppm_cfg.tot_rule_time += ppm_rt->tot; \ 140 snort_conf->ppm_cfg.tot_rules++; 141 #define PPM_ACCUM_NC_RULE_TIME() \ 142 snort_conf->ppm_cfg.tot_nc_rule_time += ppm_rt->tot; \ 143 snort_conf->ppm_cfg.tot_nc_rules++; 144 #define PPM_ACCUM_PCRE_RULE_TIME() \ 145 snort_conf->ppm_cfg.tot_pcre_rule_time += ppm_rt->tot; \ 146 snort_conf->ppm_cfg.tot_pcre_rules++; 147 #define PPM_GET_TIME() cputime(ppm_cur_time) 148 #define PPM_PKT_RULE_TESTS() ppm_pt->rule_tests 149 #define PPM_PKT_PCRE_RULE_TESTS() ppm_pt->pcre_rule_tests 150 #define PPM_PKT_NC_RULE_TESTS() ppm_pt->nc_rule_tests 151 #define PPM_INC_PKT_RULE_TESTS() if(ppm_pt)ppm_pt->rule_tests++ 152 #define PPM_INC_PKT_PCRE_RULE_TESTS() if(ppm_pt)ppm_pt->pcre_rule_tests++ 153 #define PPM_INC_PKT_NC_RULE_TESTS() if(ppm_pt)ppm_pt->nc_rule_tests++ 154 #ifdef DEBUG 155 #define PPM_DEBUG_PKTS() snort_conf->ppm_cfg.debug_pkts 156 #endif 157 158 #define PPM_PRINT_PKT_TIME(a) LogMessage(a, ppm_ticks_to_usecs((PPM_TICKS)ppm_pt->tot) ); 159 160 #ifdef PPM_TEST 161 /* use usecs instead of ticks for rule suspension during pcap playback */ 162 #define PPM_RULE_TIME(p) ((p->pkth->ts.tv_sec * 1000000) + p->pkth->ts.tv_usec) 163 #else 164 #define PPM_RULE_TIME(p) ppm_cur_time 165 #endif 166 167 #define PPM_INIT_PKT_TIMER() \ 168 if(ppm_pkt_index < PPM_MAX_TIMERS) \ 169 { \ 170 ppm_pt = &ppm_pkt_times[ppm_pkt_index++]; \ 171 ppm_abort_this_pkt = 0; \ 172 ppm_pt->pktcnt = snort_conf->ppm_cfg.tot_pkts; \ 173 ppm_pt->start = ppm_cur_time; \ 174 ppm_pt->subtract = 0; \ 175 ppm_pt->rule_tests = 0; \ 176 ppm_pt->pcre_rule_tests = 0; \ 177 ppm_pt->nc_rule_tests = 0; \ 178 ppm_pt->max_pkt_ticks = snort_conf->ppm_cfg.max_pkt_ticks; \ 179 ppm_init_rules(); \ 180 } 181 182 #define PPM_TOTAL_PKT_TIME() \ 183 if( ppm_pt) \ 184 { \ 185 ppm_pt->tot = ppm_cur_time - ppm_pt->start - ppm_pt->subtract; \ 186 } 187 188 #define PPM_END_PKT_TIMER() \ 189 if( (ppm_pkt_index > 0) && ppm_pt) \ 190 { \ 191 ppm_pkt_index--; \ 192 if( ppm_pkt_index > 0 ) \ 193 { \ 194 /*ppm_pkt_times[ppm_pkt_index-1].subtract=ppm_pt->tot; */ \ 195 ppm_pt = &ppm_pkt_times[ppm_pkt_index-1]; \ 196 } \ 197 else \ 198 { \ 199 ppm_pt=0; \ 200 } \ 201 } 202 203 #define PPM_INIT_RULE_TIMER() \ 204 if(ppm_rule_times_index < PPM_MAX_TIMERS) \ 205 { \ 206 ppm_rt = &ppm_rule_times[ppm_rule_times_index++]; \ 207 ppm_suspend_this_rule = 0; \ 208 ppm_rt->start=ppm_cur_time; \ 209 ppm_rt->max_rule_ticks = snort_conf->ppm_cfg.max_rule_ticks; \ 210 } 211 212 #define PPM_END_RULE_TIMER() \ 213 if(( ppm_rule_times_index > 0) && ppm_rt ) \ 214 { \ 215 ppm_rule_times_index--; \ 216 if (ppm_rule_times_index > 0) \ 217 { \ 218 ppm_rt=&ppm_rule_times[ppm_rule_times_index-1]; \ 219 } else { \ 220 ppm_rt=NULL; \ 221 } \ 222 } 223 224 /* To print the log if ppm is enabled and ppm_abort_this_pkt is 1 */ 225 #define PPM_LATENCY_TRACE() \ 226 if( ppm_abort_this_pkt ) \ 227 { \ 228 if( pkt_trace_enabled ) \ 229 { \ 230 if( !PacketIsRebuilt(p)) \ 231 { \ 232 addPktTraceData(VERDICT_REASON_NO_BLOCK, snprintf(trace_line, MAX_TRACE_LINE, \ 233 "PL flag : (1)")); \ 234 } \ 235 else \ 236 { \ 237 addPktTraceData(VERDICT_REASON_NO_BLOCK, snprintf(trace_line, MAX_TRACE_LINE, \ 238 "PL/R flag : (1)")); \ 239 } \ 240 } \ 241 } \ 242 243 /* use PPM_GET_TIME; first to get the current time */ 244 #define PPM_PACKET_TEST() \ 245 if( ppm_pt ) \ 246 { \ 247 ppm_pt->tot = ppm_cur_time - ppm_pt->start /*- ppm_pt->subtract*/; \ 248 if(ppm_pt->tot > ppm_pt->max_pkt_ticks) \ 249 { \ 250 if( snort_conf->ppm_cfg.pkt_action & PPM_ACTION_SUSPEND ) \ 251 ppm_abort_this_pkt = 1; \ 252 } \ 253 } 254 255 #if 0 && defined(PPM_TEST) 256 #define PPM_DBG_CSV(state, otn, when) \ 257 LogMessage( \ 258 "PPM, %u, %u, %s, " STDu64 "\n", \ 259 otn->sigInfo.generator, otn->sigInfo.id, state, when \ 260 ) 261 #else 262 #define PPM_DBG_CSV(state, otn, when) 263 #endif 264 265 /* use PPM_GET_TIME; first to get the current time */ 266 #define PPM_RULE_TEST(root,p) \ 267 if( ppm_rt ) \ 268 { \ 269 ppm_rt->tot = ppm_cur_time - ppm_rt->start; \ 270 if(ppm_rt->tot > ppm_rt->max_rule_ticks) \ 271 { \ 272 if( snort_conf->ppm_cfg.rule_action & PPM_ACTION_SUSPEND ) \ 273 { \ 274 int ii; \ 275 ppm_suspend_this_rule = 1; \ 276 (root)->ppm_disable_cnt++; \ 277 if( pkt_trace_enabled ) \ 278 { \ 279 addPktTraceData(VERDICT_REASON_NO_BLOCK, snprintf(trace_line, MAX_TRACE_LINE, \ 280 "RL flag : (1)")); \ 281 } \ 282 for ( ii = 0; ii< root->num_children; ii++) \ 283 { \ 284 root->children[ii]->ppm_disable_cnt++; \ 285 } \ 286 if( (root)->ppm_disable_cnt >= snort_conf->ppm_cfg.rule_threshold ) \ 287 { \ 288 ppm_set_rule_event(&snort_conf->ppm_cfg, root); \ 289 (root)->tree_state=RULE_STATE_DISABLED; \ 290 (root)->ppm_suspend_time=PPM_RULE_TIME(p); \ 291 PPM_DBG_CSV("disabled", (root), (root)->ppm_suspend_time); \ 292 } \ 293 else \ 294 { \ 295 (root)->ppm_suspend_time=0; \ 296 } \ 297 } \ 298 else \ 299 { \ 300 (root)->ppm_suspend_time=0; \ 301 if( (root)->ppm_disable_cnt > 0 ) \ 302 (root)->ppm_disable_cnt--; \ 303 } \ 304 } \ 305 } 306 307 #define PPM_REENABLE_TREE(root,p) \ 308 if( (root)->ppm_suspend_time && snort_conf->ppm_cfg.max_suspend_ticks ) \ 309 { \ 310 PPM_TICKS now = PPM_RULE_TIME(p); \ 311 PPM_TICKS then = (root)->ppm_suspend_time + snort_conf->ppm_cfg.max_suspend_ticks; \ 312 if( now > then ) \ 313 { \ 314 (root)->ppm_suspend_time=0; \ 315 (root)->tree_state=RULE_STATE_ENABLED; \ 316 ppm_clear_rule_event(&snort_conf->ppm_cfg, root); \ 317 PPM_DBG_CSV("enabled", (root), now); \ 318 } \ 319 else \ 320 { \ 321 PPM_DBG_CSV("pending", (root), then-now); \ 322 } \ 323 } 324 325 void ppm_init(ppm_cfg_t *); 326 #ifdef DEBUG 327 void ppm_set_debug_rules(ppm_cfg_t *, int); 328 void ppm_set_debug_pkts(ppm_cfg_t *, int); 329 #endif 330 331 void ppm_set_pkt_action(ppm_cfg_t *, int); 332 void ppm_set_pkt_log(ppm_cfg_t *, int); 333 334 void ppm_set_rule_action(ppm_cfg_t *, int); 335 void ppm_set_rule_threshold(ppm_cfg_t *, unsigned int); 336 void ppm_set_rule_log(ppm_cfg_t *, int); 337 338 void ppm_set_max_pkt_time(ppm_cfg_t *, PPM_USECS); 339 void ppm_set_max_rule_time(ppm_cfg_t *, PPM_USECS); 340 void ppm_set_max_suspend_time(ppm_cfg_t *, PPM_SECS); 341 342 void ppm_print_cfg(ppm_cfg_t *); 343 void ppm_print_summary(ppm_cfg_t *); 344 double ppm_ticks_to_usecs( PPM_TICKS ); 345 346 void ppm_pkt_log(ppm_cfg_t*, Packet*); 347 void ppm_set_rule_event (ppm_cfg_t *, detection_option_tree_root_t *); 348 void ppm_clear_rule_event (ppm_cfg_t *, detection_option_tree_root_t *); 349 void ppm_rule_log(ppm_cfg_t *, uint64_t, Packet *); 350 351 void ppm_init_rules(void); 352 void ppm_set_rule(detection_option_tree_root_t *, PPM_TICKS); 353 354 #define PPM_INIT() ppm_init() 355 #define PPM_PRINT_CFG(x) ppm_print_cfg(x) 356 #define PPM_PRINT_SUMMARY(x) ppm_print_summary(x) 357 358 #else /* !PPM_MGR */ 359 360 #define PPM_GET_TIME() 361 #define PPM_SET_TIME() 362 363 364 #endif /* PPM_MGR */ 365 366 #endif /* __PACKET_PROCESSING_MONITOR_H__ */ 367 368