From 66654e116395e8cf3d40e83453e212b670abb632 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 10:02:00 +0100 Subject: enhance optimizer: detect eq-comparison for syslog facility ... and replace it with a (much faster) prifilt() call --- ChangeLog | 6 +++ grammar/rainerscript.c | 140 +++++++++++++++++++++++++++++++++++++++++++++---- runtime/srutils.c | 22 ++++---- 3 files changed, 148 insertions(+), 20 deletions(-) diff --git a/ChangeLog b/ChangeLog index 8a15969f..38364d92 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,9 @@ --------------------------------------------------------------------------- Version 7.3.5 [devel] 2012-11-?? +- enhanced script optimizer to optimize common PRI-based comparisons + These constructs are especially used in SUSE default config files, + but also by many users (as they are more readable than the equivalent + PRI-based filter). - bugfix: segfault on imuxsock startup if system log socket is used and no ratelimiting supported. Happens only during initial config read phase, once this is over, everything works stable. @@ -14,6 +18,8 @@ Version 7.3.5 [devel] 2012-11-?? executed (due to missing template due to template error). - bugfix[minor]: invalid error code when mmnormalize could not access rulebase +- bugfix(kind of): script optimizer did not work for complex boolean + expressions - doc bugfix: corrections and improvements in mmnormalize html doc page --------------------------------------------------------------------------- Version 7.3.4 [devel] 2012-11-23 diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index f7f09697..d39d5f2a 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -50,9 +50,69 @@ DEFobjCurrIf(obj) DEFobjCurrIf(regexp) -void cnfexprOptimize(struct cnfexpr *expr); +struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr); static void cnfstmtOptimizePRIFilt(struct cnfstmt *stmt); static void cnfarrayPrint(struct cnfarray *ar, int indent); +struct cnffunc * cnffuncNew_prifilt(int fac); + +/* debug support: convert token to a human-readable string. Note that + * this function only supports a single thread due to a static buffer. + * This is deemed a solid solution, as it is intended to be used during + * startup, only. + * NOTE: This function MUST be updated if new tokens are defined in the + * grammar. + */ +char * +tokenToString(int token) +{ + char *tokstr; + static char tokbuf[512]; + + switch(token) { + case NAME: tokstr = "NAME"; break; + case FUNC: tokstr = "FUNC"; break; + case BEGINOBJ: tokstr ="BEGINOBJ"; break; + case ENDOBJ: tokstr ="ENDOBJ"; break; + case BEGIN_ACTION: tokstr ="BEGIN_ACTION"; break; + case BEGIN_PROPERTY: tokstr ="BEGIN_PROPERTY"; break; + case BEGIN_CONSTANT: tokstr ="BEGIN_CONSTANT"; break; + case BEGIN_TPL: tokstr ="BEGIN_TPL"; break; + case BEGIN_RULESET: tokstr ="BEGIN_RULESET"; break; + case STOP: tokstr ="STOP"; break; + case SET: tokstr ="SET"; break; + case UNSET: tokstr ="UNSET"; break; + case CONTINUE: tokstr ="CONTINUE"; break; + case CALL: tokstr ="CALL"; break; + case LEGACY_ACTION: tokstr ="LEGACY_ACTION"; break; + case LEGACY_RULESET: tokstr ="LEGACY_RULESET"; break; + case PRIFILT: tokstr ="PRIFILT"; break; + case PROPFILT: tokstr ="PROPFILT"; break; + case IF: tokstr ="IF"; break; + case THEN: tokstr ="THEN"; break; + case ELSE: tokstr ="ELSE"; break; + case OR: tokstr ="OR"; break; + case AND: tokstr ="AND"; break; + case NOT: tokstr ="NOT"; break; + case VAR: tokstr ="VAR"; break; + case STRING: tokstr ="STRING"; break; + case NUMBER: tokstr ="NUMBER"; break; + case CMP_EQ: tokstr ="CMP_EQ"; break; + case CMP_NE: tokstr ="CMP_NE"; break; + case CMP_LE: tokstr ="CMP_LE"; break; + case CMP_GE: tokstr ="CMP_GE"; break; + case CMP_LT: tokstr ="CMP_LT"; break; + case CMP_GT: tokstr ="CMP_GT"; break; + case CMP_CONTAINS: tokstr ="CMP_CONTAINS"; break; + case CMP_CONTAINSI: tokstr ="CMP_CONTAINSI"; break; + case CMP_STARTSWITH: tokstr ="CMP_STARTSWITH"; break; + case CMP_STARTSWITHI: tokstr ="CMP_STARTSWITHI"; break; + case UMINUS: tokstr ="UMINUS"; break; + default: snprintf(tokbuf, sizeof(tokbuf), "%c[%d]", token, token); + tokstr = tokbuf; break; + } + return tokstr; +} + char* getFIOPName(unsigned iFIOP) @@ -275,8 +335,8 @@ nvlstPrint(struct nvlst *lst) dbgprintf("\tname: '%s', value '%s'\n", name, value); free(value); break; - default:dbgprintf("nvlstPrint: unknown type '%c' [%d]\n", - lst->val.datatype, lst->val.datatype); + default:dbgprintf("nvlstPrint: unknown type '%s'\n", + tokenToString(lst->val.datatype)); break; } free(name); @@ -1253,7 +1313,7 @@ cnfexprEval(struct cnfexpr *expr, struct var *ret, void* usrptr) int bMustFree, bMustFree2; long long n_r, n_l; - dbgprintf("eval expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("eval expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); switch(expr->nodetype) { /* note: comparison operations are extremely similar. The code can be copyied, only * places flagged with "CMP" need to be changed. @@ -1655,7 +1715,7 @@ void cnfexprDestruct(struct cnfexpr *expr) { - dbgprintf("cnfexprDestruct expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("cnfexprDestruct expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); switch(expr->nodetype) { case CMP_NE: case CMP_EQ: @@ -2323,14 +2383,41 @@ constFoldConcat(struct cnfexpr *expr) } +/* optimize a comparison with a variable as left-hand operand */ +static inline struct cnfexpr* +cnfexprOptimize_CMP_var(struct cnfexpr *expr) +{ + struct cnffunc *func; + + dbgprintf("VAR, name is '%s'\n", ((struct cnfvar*)expr->l)->name); + if(!strcmp("$syslogfacility-text", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'S') { + char *cstr = es_str2cstr(((struct cnfstringval*)expr->r)->estr, NULL); + int fac = decodeSyslogName((uchar*)cstr, syslogFacNames); + if(fac == -1) { + parser_errmsg("invalid facility '%s', expression will always " + "evaluate to FALSE", cstr); + } else { + /* we can acutally optimize! */ + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + cnfexprDestruct(expr); + func = cnffuncNew_prifilt(fac); + expr = (struct cnfexpr*) func; + } + free(cstr); + } + } + return expr; +} + /* (recursively) optimize an expression */ -void +struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr) { long long ln, rn; struct cnfexpr *exprswap; - dbgprintf("optimize expr %p, type '%c'(%u)\n", expr, expr->nodetype, expr->nodetype); + dbgprintf("optimize expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); switch(expr->nodetype) { case '&': constFoldConcat(expr); @@ -2367,6 +2454,8 @@ cnfexprOptimize(struct cnfexpr *expr) break; case CMP_NE: case CMP_EQ: + expr->l = cnfexprOptimize(expr->l); + expr->r = cnfexprOptimize(expr->r); if(expr->l->nodetype == 'A') { if(expr->r->nodetype == 'A') { parser_errmsg("warning: '==' or '<>' " @@ -2377,11 +2466,22 @@ cnfexprOptimize(struct cnfexpr *expr) expr->l = expr->r; expr->r = exprswap; } + } else if(expr->l->nodetype == 'V') { + expr = cnfexprOptimize_CMP_var(expr); } - default:/* nodetype we cannot optimize */ + break; + case AND: + case OR:/* keep recursion goin' on... */ + expr->l = cnfexprOptimize(expr->l); + expr->r = cnfexprOptimize(expr->r); + break; + case NOT:/* keep recursion goin' on... */ + expr->r = cnfexprOptimize(expr->r); + break; + default:/* nodetypes we cannot optimize */ break; } - + return expr; } /* removes NOPs from a statement list and returns the @@ -2715,6 +2815,7 @@ finalize_it: RETiRet; } + struct cnffunc * cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) { @@ -2757,6 +2858,27 @@ cnffuncNew(es_str_t *fname, struct cnffparamlst* paramlst) return func; } + +/* A special function to create a prifilt() expression during optimization + * phase. + */ +struct cnffunc * +cnffuncNew_prifilt(int fac) +{ + struct cnffunc* func; + + if((func = malloc(sizeof(struct cnffunc))) != NULL) { + func->nodetype = 'F'; + func->fname = es_newStrFromCStr("prifilt", sizeof("prifilt")-1); + func->nParams = 0; + func->fID = CNFFUNC_PRIFILT; + func->funcdata = calloc(1, sizeof(struct funcData_prifilt)); + ((struct funcData_prifilt *)func->funcdata)->pmask[fac >> 3] = TABLE_ALLPRI; + } + return func; +} + + /* returns 0 if everything is OK and config parsing shall continue, * and 1 if things are so wrong that config parsing shall be aborted. */ diff --git a/runtime/srutils.c b/runtime/srutils.c index f420c0f7..bc753dbf 100644 --- a/runtime/srutils.c +++ b/runtime/srutils.c @@ -524,8 +524,7 @@ char *rs_strerror_r(int errnum, char *buf, size_t buflen) { } -/* Decode a symbolic name to a numeric value - */ +/* Decode a symbolic name to a numeric value */ int decodeSyslogName(uchar *name, syslogName_t *codetab) { register syslogName_t *c; @@ -535,22 +534,23 @@ int decodeSyslogName(uchar *name, syslogName_t *codetab) ASSERT(name != NULL); ASSERT(codetab != NULL); - dbgprintf("symbolic name: %s", name); - if (isdigit((int) *name)) - { - dbgprintf("\n"); + DBGPRINTF("symbolic name: %s", name); + if(isdigit((int) *name)) { + DBGPRINTF("\n"); return (atoi((char*) name)); } strncpy((char*) buf, (char*) name, 79); - for (p = buf; *p; p++) + for(p = buf; *p; p++) { if (isupper((int) *p)) *p = tolower((int) *p); - for (c = codetab; c->c_name; c++) - if (!strcmp((char*) buf, (char*) c->c_name)) - { - dbgprintf(" ==> %d\n", c->c_val); + } + for(c = codetab; c->c_name; c++) { + if(!strcmp((char*) buf, (char*) c->c_name)) { + DBGPRINTF(" ==> %d\n", c->c_val); return (c->c_val); } + } + DBGPRINTF("\n"); return (-1); } -- cgit v1.2.3 From b49e20f0912f77dc9f4e3b849b11aed5d915a7d8 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 11:11:15 +0100 Subject: script optimizer: support NOT pri matches --- grammar/rainerscript.c | 46 ++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 42 insertions(+), 4 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index d39d5f2a..413964d6 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -144,6 +144,15 @@ getFIOPName(unsigned iFIOP) return pRet; } +static void +prifiltInvert(struct funcData_prifilt *prifilt) +{ + int i; + for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) { + prifilt->pmask[i] = ~prifilt->pmask[i]; + } +} + void readConfFile(FILE *fp, es_str_t **str) @@ -1715,7 +1724,13 @@ void cnfexprDestruct(struct cnfexpr *expr) { - dbgprintf("cnfexprDestruct expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); + if(expr == NULL) { + /* this is valid and can happen during optimizer run! */ + DBGPRINTF("cnfexprDestruct got NULL ptr - valid, so doing nothing\n"); + return; + } + + DBGPRINTF("cnfexprDestruct expr %p, type '%s'\n", expr, tokenToString(expr->nodetype)); switch(expr->nodetype) { case CMP_NE: case CMP_EQ: @@ -2383,13 +2398,15 @@ constFoldConcat(struct cnfexpr *expr) } -/* optimize a comparison with a variable as left-hand operand */ +/* optimize a comparison with a variable as left-hand operand + * NOTE: Currently support CMP_EQ, CMP_NE only and code NEEDS + * TO BE CHANGED for other comparisons! + */ static inline struct cnfexpr* cnfexprOptimize_CMP_var(struct cnfexpr *expr) { struct cnffunc *func; - dbgprintf("VAR, name is '%s'\n", ((struct cnfvar*)expr->l)->name); if(!strcmp("$syslogfacility-text", ((struct cnfvar*)expr->l)->name)) { if(expr->r->nodetype == 'S') { char *cstr = es_str2cstr(((struct cnfstringval*)expr->r)->estr, NULL); @@ -2400,8 +2417,10 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) } else { /* we can acutally optimize! */ DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); - cnfexprDestruct(expr); func = cnffuncNew_prifilt(fac); + if(expr->nodetype == CMP_NE) + prifiltInvert(func->funcdata); + cnfexprDestruct(expr); expr = (struct cnfexpr*) func; } free(cstr); @@ -2410,6 +2429,24 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) return expr; } +static inline struct cnfexpr* +cnfexprOptimize_NOT(struct cnfexpr *expr) +{ + struct cnffunc *func; + + if(expr->r->nodetype == 'F') { + func = (struct cnffunc *)expr->r; + if(func->fID == CNFFUNC_PRIFILT) { + DBGPRINTF("optimize NOT prifilt() to inverted prifilt()\n"); + expr->r = NULL; + cnfexprDestruct(expr); + prifiltInvert(func->funcdata); + expr = (struct cnfexpr*) func; + } + } + return expr; +} + /* (recursively) optimize an expression */ struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr) @@ -2477,6 +2514,7 @@ cnfexprOptimize(struct cnfexpr *expr) break; case NOT:/* keep recursion goin' on... */ expr->r = cnfexprOptimize(expr->r); + expr = cnfexprOptimize_NOT(expr); break; default:/* nodetypes we cannot optimize */ break; -- cgit v1.2.3 From 79e09b2bf8167e281beab0115ea280914f428919 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 11:24:05 +0100 Subject: script optimizer: optimize and/or on PRI filters --- grammar/rainerscript.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 413964d6..5d68d944 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -153,6 +153,21 @@ prifiltInvert(struct funcData_prifilt *prifilt) } } +/* combine a prifilt with AND/OR (the respective token values are + * used to keep things simple). + */ +static void +prifiltCombine(struct funcData_prifilt *prifilt, struct funcData_prifilt *prifilt2, int mode) +{ + int i; + for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) { + if(mode == AND) + prifilt->pmask[i] = prifilt->pmask[i] & prifilt2->pmask[i]; + else + prifilt->pmask[i] = prifilt->pmask[i] | prifilt2->pmask[i]; + } +} + void readConfFile(FILE *fp, es_str_t **str) @@ -2447,6 +2462,27 @@ cnfexprOptimize_NOT(struct cnfexpr *expr) return expr; } +static inline struct cnfexpr* +cnfexprOptimize_AND_OR(struct cnfexpr *expr) +{ + struct cnffunc *funcl, *funcr; + + if(expr->l->nodetype == 'F') { + if(expr->r->nodetype == 'F') { + funcl = (struct cnffunc *)expr->l; + funcr = (struct cnffunc *)expr->r; + if(funcl->fID == CNFFUNC_PRIFILT && funcr->fID == CNFFUNC_PRIFILT) { + DBGPRINTF("optimize combine AND/OR prifilt()\n"); + expr->l = NULL; + prifiltCombine(funcl->funcdata, funcr->funcdata, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) funcl; + } + } + } + return expr; +} + /* (recursively) optimize an expression */ struct cnfexpr* cnfexprOptimize(struct cnfexpr *expr) @@ -2511,6 +2547,7 @@ cnfexprOptimize(struct cnfexpr *expr) case OR:/* keep recursion goin' on... */ expr->l = cnfexprOptimize(expr->l); expr->r = cnfexprOptimize(expr->r); + expr = cnfexprOptimize_AND_OR(expr); break; case NOT:/* keep recursion goin' on... */ expr->r = cnfexprOptimize(expr->r); -- cgit v1.2.3 From 39b75f728860597b26cd93bbc297ad9eac6fea1f Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 11:28:00 +0100 Subject: bugfix: optimizer stopped prematurely on some operations --- grammar/rainerscript.c | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 5d68d944..8284d87a 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2543,6 +2543,17 @@ cnfexprOptimize(struct cnfexpr *expr) expr = cnfexprOptimize_CMP_var(expr); } break; + case CMP_LE: + case CMP_GE: + case CMP_LT: + case CMP_GT: + case CMP_CONTAINS: + case CMP_CONTAINSI: + case CMP_STARTSWITH: + case CMP_STARTSWITHI: + expr->l = cnfexprOptimize(expr->l); + expr->r = cnfexprOptimize(expr->r); + break; case AND: case OR:/* keep recursion goin' on... */ expr->l = cnfexprOptimize(expr->l); -- cgit v1.2.3 From b2a7f20af7fa6bc54de132dffe2c2e9108ca2889 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 12:27:16 +0100 Subject: script optimizer: severity eq/ne to prifilt() --- grammar/rainerscript.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 8284d87a..27b22487 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -153,6 +153,22 @@ prifiltInvert(struct funcData_prifilt *prifilt) } } +/* set prifilt so that it matches for all severities, sev is its numerical + * value. Mode is one of the compop tokens CMP_EQ, CMP_LT, CMP_LE, CMP_GT, + * CMP_GE, CMP_NE. + */ +static void +prifiltSetSeverity(struct funcData_prifilt *prifilt, int sev, int mode) +{ + int i; + for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) { + if(mode == CMP_EQ || mode == CMP_NE) + prifilt->pmask[i] = 1 << sev; + } + if(mode == CMP_NE) + prifiltInvert(prifilt); +} + /* combine a prifilt with AND/OR (the respective token values are * used to keep things simple). */ @@ -2440,6 +2456,20 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) } free(cstr); } + } else if(!strcmp("$syslogseverity", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'N') { + int sev = (int) ((struct cnfnumval*)expr->r)->val; + if(sev >= 0 && sev <= 7) { + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */ + prifiltSetSeverity(func->funcdata, sev, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) func; + } else { + parser_errmsg("invalid syslogseverity %d, expression will always " + "evaluate to FALSE", sev); + } + } } return expr; } @@ -2610,8 +2640,7 @@ cnfstmtOptimizeIf(struct cnfstmt *stmt) struct cnffunc *func; struct funcData_prifilt *prifilt; - expr = stmt->d.s_if.expr; - cnfexprOptimize(expr); + expr = stmt->d.s_if.expr = cnfexprOptimize(stmt->d.s_if.expr); stmt->d.s_if.t_then = removeNOPs(stmt->d.s_if.t_then); stmt->d.s_if.t_else = removeNOPs(stmt->d.s_if.t_else); cnfstmtOptimize(stmt->d.s_if.t_then); @@ -2629,8 +2658,11 @@ cnfstmtOptimizeIf(struct cnfstmt *stmt) sizeof(prifilt->pmask)); stmt->d.s_prifilt.t_then = t_then; stmt->d.s_prifilt.t_else = t_else; - stmt->printable = (uchar*) - es_str2cstr(((struct cnfstringval*)func->expr[0])->estr, NULL); + if(func->nParams == 0) + stmt->printable = (uchar*)strdup("[Optimizer Result]"); + else + stmt->printable = (uchar*) + es_str2cstr(((struct cnfstringval*)func->expr[0])->estr, NULL); cnfexprDestruct(expr); cnfstmtOptimizePRIFilt(stmt); } @@ -2737,7 +2769,7 @@ dbgprintf("RRRR: stmtOptimize: stmt %p, nodetype %u\n", stmt, stmt->nodetype); cnfstmtOptimize(stmt->d.s_propfilt.t_then); break; case S_SET: - cnfexprOptimize(stmt->d.s_set.expr); + stmt->d.s_set.expr = cnfexprOptimize(stmt->d.s_set.expr); break; case S_ACT: cnfstmtOptimizeAct(stmt); -- cgit v1.2.3 From a71660d49804caec0e0beb0cfaa2b5cd64fc1af6 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 12:53:39 +0100 Subject: script optimizer: severity lt/le/gt/ge to prifilt() --- grammar/rainerscript.c | 62 +++++++++++++++++++++++++++++++++++++------------- 1 file changed, 46 insertions(+), 16 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 27b22487..353d012e 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -160,10 +160,22 @@ prifiltInvert(struct funcData_prifilt *prifilt) static void prifiltSetSeverity(struct funcData_prifilt *prifilt, int sev, int mode) { + static int lessthanmasks[] = { 0x00, 0x01, 0x03, 0x07, 0x0f, 0x1f, 0x3f, 0x7f, 0xff }; int i; for(i = 0 ; i < LOG_NFACILITIES+1 ; ++i) { if(mode == CMP_EQ || mode == CMP_NE) prifilt->pmask[i] = 1 << sev; + else if(mode == CMP_LT) + prifilt->pmask[i] = lessthanmasks[sev]; + else if(mode == CMP_LE) + prifilt->pmask[i] = lessthanmasks[sev+1]; + else if(mode == CMP_GT) + prifilt->pmask[i] = ~lessthanmasks[sev+1]; + else if(mode == CMP_GE) + prifilt->pmask[i] = ~lessthanmasks[sev]; + else + DBGPRINTF("prifiltSetSeverity: program error, invalid mode %s\n", + tokenToString(mode)); } if(mode == CMP_NE) prifiltInvert(prifilt); @@ -2429,6 +2441,32 @@ constFoldConcat(struct cnfexpr *expr) } +/* optimize comparisons with syslog severity. This is a special + * handler as the numerical values also support GT, LT, etc ops. + */ +static inline struct cnfexpr* +cnfexprOptimize_CMP_severity(struct cnfexpr *expr) +{ + struct cnffunc *func; + + if(!strcmp("$syslogseverity", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'N') { + int sev = (int) ((struct cnfnumval*)expr->r)->val; + if(sev >= 0 && sev <= 7) { + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */ + prifiltSetSeverity(func->funcdata, sev, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) func; + } else { + parser_errmsg("invalid syslogseverity %d, expression will always " + "evaluate to FALSE", sev); + } + } + } + return expr; +} + /* optimize a comparison with a variable as left-hand operand * NOTE: Currently support CMP_EQ, CMP_NE only and code NEEDS * TO BE CHANGED for other comparisons! @@ -2456,20 +2494,8 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) } free(cstr); } - } else if(!strcmp("$syslogseverity", ((struct cnfvar*)expr->l)->name)) { - if(expr->r->nodetype == 'N') { - int sev = (int) ((struct cnfnumval*)expr->r)->val; - if(sev >= 0 && sev <= 7) { - DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); - func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */ - prifiltSetSeverity(func->funcdata, sev, expr->nodetype); - cnfexprDestruct(expr); - expr = (struct cnfexpr*) func; - } else { - parser_errmsg("invalid syslogseverity %d, expression will always " - "evaluate to FALSE", sev); - } - } + } else { + expr = cnfexprOptimize_CMP_severity(expr); } return expr; } @@ -2577,6 +2603,10 @@ cnfexprOptimize(struct cnfexpr *expr) case CMP_GE: case CMP_LT: case CMP_GT: + expr->l = cnfexprOptimize(expr->l); + expr->r = cnfexprOptimize(expr->r); + expr = cnfexprOptimize_CMP_severity(expr); + break; case CMP_CONTAINS: case CMP_CONTAINSI: case CMP_STARTSWITH: @@ -2585,12 +2615,12 @@ cnfexprOptimize(struct cnfexpr *expr) expr->r = cnfexprOptimize(expr->r); break; case AND: - case OR:/* keep recursion goin' on... */ + case OR: expr->l = cnfexprOptimize(expr->l); expr->r = cnfexprOptimize(expr->r); expr = cnfexprOptimize_AND_OR(expr); break; - case NOT:/* keep recursion goin' on... */ + case NOT: expr->r = cnfexprOptimize(expr->r); expr = cnfexprOptimize_NOT(expr); break; -- cgit v1.2.3 From 3c9fb9017fedcc0637f235e4c348287112f18447 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 15:36:34 +0100 Subject: script optimizer: support numerical facilities in compare operations as well --- grammar/rainerscript.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 58 insertions(+), 5 deletions(-) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index 353d012e..e4c4f519 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -153,7 +153,7 @@ prifiltInvert(struct funcData_prifilt *prifilt) } } -/* set prifilt so that it matches for all severities, sev is its numerical +/* set prifilt so that it matches for some severities, sev is its numerical * value. Mode is one of the compop tokens CMP_EQ, CMP_LT, CMP_LE, CMP_GT, * CMP_GE, CMP_NE. */ @@ -181,6 +181,45 @@ prifiltSetSeverity(struct funcData_prifilt *prifilt, int sev, int mode) prifiltInvert(prifilt); } +/* set prifilt so that it matches for some facilities, fac is its numerical + * value. Mode is one of the compop tokens CMP_EQ, CMP_LT, CMP_LE, CMP_GT, + * CMP_GE, CMP_NE. For the given facilities, all severities are enabled. + * NOTE: fac MUST be in the range 0..24 (not multiplied by 8)! + */ +static void +prifiltSetFacility(struct funcData_prifilt *prifilt, int fac, int mode) +{ + int i; + + memset(prifilt->pmask, 0, sizeof(prifilt->pmask)); + switch(mode) { + case CMP_EQ: + prifilt->pmask[fac] = TABLE_ALLPRI; + break; + case CMP_NE: + prifilt->pmask[fac] = TABLE_ALLPRI; + prifiltInvert(prifilt); + break; + case CMP_LT: + for(i = 0 ; i < fac ; ++i) + prifilt->pmask[i] = TABLE_ALLPRI; + break; + case CMP_LE: + for(i = 0 ; i < fac+1 ; ++i) + prifilt->pmask[i] = TABLE_ALLPRI; + break; + case CMP_GE: + for(i = fac ; i < LOG_NFACILITIES+1 ; ++i) + prifilt->pmask[i] = TABLE_ALLPRI; + break; + case CMP_GT: + for(i = fac+1 ; i < LOG_NFACILITIES+1 ; ++i) + prifilt->pmask[i] = TABLE_ALLPRI; + break; + default:break; + } +} + /* combine a prifilt with AND/OR (the respective token values are * used to keep things simple). */ @@ -2441,11 +2480,11 @@ constFoldConcat(struct cnfexpr *expr) } -/* optimize comparisons with syslog severity. This is a special +/* optimize comparisons with syslog severity/facility. This is a special * handler as the numerical values also support GT, LT, etc ops. */ static inline struct cnfexpr* -cnfexprOptimize_CMP_severity(struct cnfexpr *expr) +cnfexprOptimize_CMP_severity_facility(struct cnfexpr *expr) { struct cnffunc *func; @@ -2463,6 +2502,20 @@ cnfexprOptimize_CMP_severity(struct cnfexpr *expr) "evaluate to FALSE", sev); } } + } else if(!strcmp("$syslogfacility", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'N') { + int fac = (int) ((struct cnfnumval*)expr->r)->val; + if(fac >= 0 && fac <= 24) { + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + func = cnffuncNew_prifilt(0); /* fac is irrelevant, set below... */ + prifiltSetFacility(func->funcdata, fac, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) func; + } else { + parser_errmsg("invalid syslogfacility %d, expression will always " + "evaluate to FALSE", fac); + } + } } return expr; } @@ -2495,7 +2548,7 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) free(cstr); } } else { - expr = cnfexprOptimize_CMP_severity(expr); + expr = cnfexprOptimize_CMP_severity_facility(expr); } return expr; } @@ -2605,7 +2658,7 @@ cnfexprOptimize(struct cnfexpr *expr) case CMP_GT: expr->l = cnfexprOptimize(expr->l); expr->r = cnfexprOptimize(expr->r); - expr = cnfexprOptimize_CMP_severity(expr); + expr = cnfexprOptimize_CMP_severity_facility(expr); break; case CMP_CONTAINS: case CMP_CONTAINSI: -- cgit v1.2.3 From a8437e146808ee68c9b5979767a186a3da079107 Mon Sep 17 00:00:00 2001 From: Rainer Gerhards Date: Tue, 11 Dec 2012 15:46:08 +0100 Subject: script optimizer: support textual severities in compare operations as well --- grammar/rainerscript.c | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/grammar/rainerscript.c b/grammar/rainerscript.c index e4c4f519..8f20bfcd 100644 --- a/grammar/rainerscript.c +++ b/grammar/rainerscript.c @@ -2547,6 +2547,23 @@ cnfexprOptimize_CMP_var(struct cnfexpr *expr) } free(cstr); } + } else if(!strcmp("$syslogseverity-text", ((struct cnfvar*)expr->l)->name)) { + if(expr->r->nodetype == 'S') { + char *cstr = es_str2cstr(((struct cnfstringval*)expr->r)->estr, NULL); + int sev = decodeSyslogName((uchar*)cstr, syslogPriNames); + if(sev == -1) { + parser_errmsg("invalid syslogseverity '%s', expression will always " + "evaluate to FALSE", cstr); + } else { + /* we can acutally optimize! */ + DBGPRINTF("optimizer: change comparison OP to FUNC prifilt()\n"); + func = cnffuncNew_prifilt(0); + prifiltSetSeverity(func->funcdata, sev, expr->nodetype); + cnfexprDestruct(expr); + expr = (struct cnfexpr*) func; + } + free(cstr); + } } else { expr = cnfexprOptimize_CMP_severity_facility(expr); } -- cgit v1.2.3