diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-02-15 15:43:56 +0200 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2012-02-15 17:24:43 +0200 |
commit | efecb9a56bb848eb6b0dd45b9a69020e80ac8b0c (patch) | |
tree | 763bc75011389bc0eeb8a93a035c978da013295e | |
parent | 8af027bd45b4b12917ed8687c4846722b74f3a2c (diff) | |
download | slb-efecb9a56bb848eb6b0dd45b9a69020e80ac8b0c.tar.gz slb-efecb9a56bb848eb6b0dd45b9a69020e80ac8b0c.tar.bz2 |
Implement simple indexing feature.
* NEWS: Update.
* src/config.c (cb_table,cb_index): New callbacks.
(cb_server_variable): Implement index replacements in MIBs.
(cb_server_assert): Clone locus.
(server_kw): New keywords: table, index.
(server_kw) <variable>: Change base ptr.
(slb_server_new): Allocate srv->tables and srv->indices.
* src/oidtab.c (oidtab_install): New function.
(_create_ref): Call oidtab_install.
* src/slb.h (slb_varinstance) <vi_mib>: Remove const qualifier.
<vi_index,vi_idxpos,vi_locus>: New members.
(slb_server) <test_pdu>: Rename to pdu. All uses updated.
(oidtab_install,table_lookup,table_lookupz)
(idxnum_lookup,idxnum_lookupz)
(index_lookup,index_lookupz): New protos.
(slb_table,slb_idxnum,slb_index): New structs.
(slb_server) <tables,indices>: New members.
* src/snmploop.c (process_next,_process_pdu)
(asynch_response_next): New functions.
(server_process_pdu): Rewrite using new functions.
(send_requests): Handle unresolved oids. Return number of ones waiting
to be resolved.
(resolve_tables): New function.
(snmploop): Resolve tables as necessary.
* src/symimp.c (table_lookup,table_lookupz)
(index_lookup,index_lookupz)
(idxnum_lookup,idxnum_lookupz): New functions.
-rw-r--r-- | NEWS | 22 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | src/config.c | 169 | ||||
-rw-r--r-- | src/oidtab.c | 14 | ||||
-rw-r--r-- | src/slb.h | 54 | ||||
-rw-r--r-- | src/snmploop.c | 295 | ||||
-rw-r--r-- | src/symimp.c | 45 | ||||
-rw-r--r-- | src/test.c | 16 |
8 files changed, 566 insertions, 53 deletions
@@ -1,11 +1,11 @@ -SLB NEWS -- history of user-visible changes. 2011-05-11 -Copyright (C) 2011 Sergey Poznyakoff +SLB NEWS -- history of user-visible changes. 2012-02-15 +Copyright (C) 2011, 2012 Sergey Poznyakoff See the end of file for copying conditions. Please send SLB bug reports to <gray+slb@gnu.org.ua> -Version 1.0.92 (Git) +Version 1.0.93 (Git) * Support SNMPv3 * Default SNMP version is 2c @@ -14,7 +14,21 @@ Version 1.0.92 (Git) * Variable assignments in expressions * Detection of SNMP counter overflows * Comma operator +* Support for indexed MIBs +This feature allows you to use symbolic names instead of the fixed MIBs +for MIBs that are part of SNMP subtrees. For example, to get number of +packets sent over eth0 into variable "out", you would do the following: + + table iftable IF-MIB::ifDescr; + index x eth0 iftable; + variable out "IF-MIB::ifOutUcastPkts.$x"; + +The first statement converts entire subtree into a "table" named "iftable". +The second one defines "x" as an index into an entry in that table that has +the value "eth0". +Finally, in the third statement, this index is used to define a MIB. + Version 1.0, 2011-04-26 @@ -24,7 +38,7 @@ First release. ========================================================================= Copyright information: -Copyright (C) 2011 Sergey Poznyakoff +Copyright (C) 2011, 2012 Sergey Poznyakoff Permission is granted to anyone to make or distribute verbatim copies of this document as received, in any medium, provided that the diff --git a/configure.ac b/configure.ac index 893bd81..74082bb 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ # This file is part of SLB -*- autoconf -*- -# Copyright (C) 2011 Sergey Poznyakoff +# Copyright (C) 2011, 2012 Sergey Poznyakoff # # SLB is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ # along with SLB. If not, see <http://www.gnu.org/licenses/>. AC_PREREQ(2.63) -AC_INIT([slb], 1.0.92, [gray+slb@gnu.org.ua]) +AC_INIT([slb], 1.0.93, [gray+slb@gnu.org.ua]) AC_CONFIG_SRCDIR([src/slb.c]) AC_CONFIG_AUX_DIR([build-aux]) AC_CONFIG_HEADER([config.h]) diff --git a/src/config.c b/src/config.c index b28a22a..3bc4126 100644 --- a/src/config.c +++ b/src/config.c @@ -1,5 +1,5 @@ /* This file is part of SLB - Copyright (C) 2011 Sergey Poznyakoff + Copyright (C) 2011, 2012 Sergey Poznyakoff SLB is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -15,6 +15,7 @@ along with SLB. If not, see <http://www.gnu.org/licenses/>. */ #include "slb.h" +#include "wordsplit.h" struct grecs_list *mib_file_list; @@ -165,13 +166,93 @@ cb_server_expression(enum grecs_callback_command cmd, } int +cb_table(enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, + void *cb_data) +{ + struct grecs_symtab *tp = *(struct grecs_symtab **)varptr; + struct slb_table *tab; + size_t oidlen; + oid oid[MAX_OID_LEN]; + int install; + + if (assert_n_strings(locus, cmd, value, 2, 2)) + return 1; + + oidlen = MAX_OID_LEN; + if (!read_objid(value->v.arg.v[1]->v.string, oid, &oidlen)) { + grecs_error(locus, 0, _("cannot parse oid")); + return 1; + } + + install = 1; + tab = table_lookupz(tp, value->v.arg.v[0]->v.string, &install); + if (!install) { + grecs_error(locus, 0, + _("redefinition of table %s"), tab->tab_sym.name); + grecs_symtab_clear(tab->tab_idx); + } else + tab->tab_idx = grecs_symtab_create_default(sizeof(size_t)); + + tab->tab_oidlen = oidlen; + memcpy(tab->tab_oid, oid, sizeof(oid)); + + return 0; +} + +int +cb_index(enum grecs_callback_command cmd, + grecs_locus_t *locus, + void *varptr, + grecs_value_t *value, + void *cb_data) +{ + struct slb_server *srv = varptr; + struct slb_table *tab; + struct slb_index *idx; + int install; + + if (assert_n_strings(locus, cmd, value, 3, 3)) + return 1; + tab = table_lookupz(srv->tables, value->v.arg.v[2]->v.string, NULL); + if (!tab) { + grecs_error(locus, 0, + _("no SNMP table of such name known: %s"), + value->v.arg.v[2]->v.string); + return 1; + } + + install = 1; + idx = index_lookupz(srv->indices, value->v.arg.v[0]->v.string, + &install); + if (!install) + grecs_error(locus, 0, + _("redefinition of table %s"), tab->tab_sym.name); + idx->idx_table = tab; + idx->idx_tag = grecs_strdup(value->v.arg.v[1]->v.string); + + return 0; +} + +static void +clone_locus(grecs_locus_t *dst, grecs_locus_t *src) +{ + *dst = *src; + dst->beg.file = grecs_strdup(dst->beg.file); + dst->end.file = grecs_strdup(dst->end.file); +} + +int cb_server_variable(enum grecs_callback_command cmd, grecs_locus_t *locus, void *varptr, grecs_value_t *value, void *cb_data) { - struct grecs_symtab *vt = *(struct grecs_symtab **)varptr; + struct slb_server *srv = varptr; + struct grecs_symtab *vt = srv->varinst; struct slb_varinstance *inst; int install; char *name; @@ -187,15 +268,77 @@ cb_server_variable(enum grecs_callback_command cmd, if (!install) grecs_error(locus, 0, _("redefinition of %s"), inst->vi_sym.name); + clone_locus(&inst->vi_locus, locus); if (value->type == GRECS_TYPE_ARRAY && value->v.arg.c >= 2) { + struct wordsplit ws; + int err = 0; + size_t i; + + ws.ws_delim = "."; + if (wordsplit(value->v.arg.v[1]->v.string, &ws, + WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_DELIM)) { + grecs_error(locus, 0, + _("can't split oid: %s"), + wordsplit_strerror(&ws)); + return 1; + } + + for (i = 0; i < ws.ws_wordc; i++) { + if (ws.ws_wordv[i][0] == '$') { + char *name = ws.ws_wordv[i] + 1; + + if (inst->vi_index) { + grecs_error(locus, 0, + _("OID can have at most " + "one index")); + err = 1; + break; + } + + inst->vi_index = index_lookupz(srv->indices, + name, + NULL); + if (!inst->vi_index) { + grecs_error(locus, 0, + _("unknown index: %s"), + name); + err = 1; + break; + } + inst->vi_idxpos = ws.ws_wordc - i; + } + + } + wordsplit_free(&ws); + if (err) + return 1; + + inst->vi_mib = grecs_strdup(value->v.arg.v[1]->v.string); + if (inst->vi_index) { + char *str = (char*)inst->vi_mib; + char *p, *q; + + for (p = str + strlen(str) - 1, i = 0; p > str; p--) { + if (*p == '.' && ++i == inst->vi_idxpos) + break; + } + ++p; + *p++ = '1'; + q = strchr(p, '.'); + if (q == NULL) + *p++ = 0; + else if (q > p) + memmove(p, q, strlen(q) + 1); + srv->flags |= SLB_SRV_TAB_REFERENCED; + } + inst->vi_oidlen = MAX_OID_LEN; - if (!read_objid(value->v.arg.v[1]->v.string, - inst->vi_oid, &inst->vi_oidlen)) { + if (!read_objid(inst->vi_mib, inst->vi_oid, + &inst->vi_oidlen)) { grecs_error(locus, 0, _("cannot parse oid")); return 1; } - inst->vi_mib = grecs_strdup(value->v.arg.v[1]->v.string); inst->vi_flags = SLV_VIF_SNMP; if (value->v.arg.c == 3) { @@ -299,7 +442,7 @@ cb_server_assert(enum grecs_callback_command cmd, ap->value = grecs_strdup(value->v.arg.v[2]->v.string); ap->flags = flags; - ap->locus = *locus; + clone_locus(&ap->locus, locus); return 0; } @@ -616,10 +759,20 @@ static struct grecs_keyword server_kw[] = { grecs_type_string, GRECS_AGGR, NULL, offsetof(struct slb_server, expr), cb_server_expression }, + { "table", N_("<name: string> <base-oid: string>"), + N_("Define SNMP table"), + grecs_type_string, GRECS_DFLT, + NULL, offsetof(struct slb_server, tables), + cb_table }, + { "index", N_("<name: string> <tag: string> <table: string>"), + N_("Define an index into SNMP table"), + grecs_type_string, GRECS_DFLT, + NULL, 0, + cb_index }, { "variable", N_("<name: string> <oid: string>"), N_("Define SNMP variable"), grecs_type_string, GRECS_MULT, - NULL, offsetof(struct slb_server, varinst), + NULL, 0, cb_server_variable }, { "constant", N_("<name: string> <value: string>"), N_("Define a constant"), @@ -647,6 +800,8 @@ slb_server_new(const char *id) srv->snmpver = snmp_version; srv->varinst = grecs_symtab_create_default(sizeof(struct slb_varinstance)); srv->macros = grecs_symtab_create_default(sizeof(struct slb_macro)); + srv->tables = grecs_symtab_create_default(sizeof(struct slb_table)); + srv->indices = grecs_symtab_create_default(sizeof(struct slb_index)); srv->assertions = assertion_symtab_create(); return srv; } diff --git a/src/oidtab.c b/src/oidtab.c index c6d4c28..c713a2b 100644 --- a/src/oidtab.c +++ b/src/oidtab.c @@ -63,16 +63,22 @@ oidref_free(void *p) free(p); } -static int -_create_ref(void *sym, void *data) +int +oidtab_install(struct grecs_symtab *oidtab, struct slb_varinstance *vinst) { - struct slb_varinstance *vinst = sym; - struct grecs_symtab *oidtab = data; struct slb_oidref key; int install = 1; key.inst = vinst; return grecs_symtab_lookup_or_install(oidtab, &key, &install) == NULL; +} + +static int +_create_ref(void *sym, void *data) +{ + struct slb_varinstance *vinst = sym; + struct grecs_symtab *oidtab = data; + return oidtab_install(oidtab, vinst); } struct grecs_symtab * @@ -1,5 +1,5 @@ /* This file is part of SLB - Copyright (C) 2011 Sergey Poznyakoff + Copyright (C) 2011, 2012 Sergey Poznyakoff SLB is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -176,12 +176,15 @@ struct slb_varref { struct slb_varinstance { struct grecs_syment vi_sym; - const char *vi_mib; + char *vi_mib; oid vi_oid[MAX_OID_LEN]; size_t vi_oidlen; double vi_value; int vi_flags; char *vi_extra; + struct slb_index *vi_index; + size_t vi_idxpos; + grecs_locus_t vi_locus; }; struct slb_expression { @@ -224,9 +227,44 @@ void varinst_clear(struct grecs_symtab *vit); int varinst_allset(struct grecs_symtab *vit); struct grecs_symtab *create_oidtab(struct grecs_symtab *vit); +int oidtab_install(struct grecs_symtab *oidtab, struct slb_varinstance *vinst); struct slb_varinstance *oidtab_lookup(struct grecs_symtab *oidtab, oid *name, size_t name_length); + +struct slb_table { + struct grecs_syment tab_sym; + oid tab_oid[MAX_OID_LEN]; + size_t tab_oidlen; + struct grecs_symtab *tab_idx; +}; + +struct slb_table *table_lookup(struct grecs_symtab *tab, const char *name, + size_t len, int *install); +struct slb_table *table_lookupz(struct grecs_symtab *tab, const char *name, + int *install); + +struct slb_idxnum { + struct grecs_syment idxnum_sym; + size_t idxnum_num; +}; + +struct slb_idxnum *idxnum_lookup(struct grecs_symtab *tab, + const char *name, size_t len, + int *install); +struct slb_idxnum *idxnum_lookupz(struct grecs_symtab *tab, const char *name, + int *install); + + +struct slb_index { + struct grecs_syment idx_sym; + char *idx_tag; + struct slb_table *idx_table; +}; +struct slb_index *index_lookup(struct grecs_symtab *tab, const char *name, + size_t len, int *install); +struct slb_index *index_lookupz(struct grecs_symtab *tab, const char *name, + int *install); int symtab_register_expression(struct grecs_symtab **pexptab, struct slb_expression *expr); @@ -291,8 +329,10 @@ struct slb_snmp_v3 { u_int engine_time; /* initial engine time for remote engine */ }; -#define SLB_SRV_DISABLED 0x01 -#define SLB_SRV_COMPUTED 0x02 +#define SLB_SRV_DISABLED 0x01 /* Server is disabled */ +#define SLB_SRV_COMPUTED 0x02 /* Expression has been computed */ +#define SLB_SRV_TAB_REFERENCED 0x04 /* Variables refer to SNMP tables */ +#define SLB_SRV_TAB_RESOLVED 0x08 /* Table references resolved */ struct slb_server { char *id; /* Server ID */ @@ -309,14 +349,18 @@ struct slb_server { struct grecs_symtab *oidtab; /* A reverse index to the entries from varinst */ struct grecs_symtab *macros; /* Defined macros */ + struct grecs_symtab *tables; /* SNMP tables */ + struct grecs_symtab *indices; /* Indices to SNMP tables */ struct slb_node_state *state; /* Preserved node states for expression evaluator */ struct grecs_symtab *exprtab; /* Table of expressions used by output driver of this server */ struct slb_expression *expr; /* Expression returning the server load "weight" */ + struct snmp_session *sess; /* SNMP session */ - struct snmp_pdu *test_pdu; /* A PDU used only in test mode */ + struct snmp_pdu *pdu; /* PDU used in test mode and when handling + GETNEXT requests. */ double weight; /* Last computed server weight (relative load) */ int flags; /* Server flags */ struct slb_server *next; /* Next server in the list */ diff --git a/src/snmploop.c b/src/snmploop.c index d54b84f..c39a159 100644 --- a/src/snmploop.c +++ b/src/snmploop.c @@ -1,5 +1,5 @@ /* This file is part of SLB - Copyright (C) 2011 Sergey Poznyakoff + Copyright (C) 2011, 2012 Sergey Poznyakoff SLB is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -122,10 +122,11 @@ process_result(struct slb_server *srv, struct snmp_pdu *pdu) vp->name_length, NULL); if (ap && assertion_test(ap, vp)) { logmsg(LOG_NOTICE, - "%s:%d: %s: assertion \"%s\" failed", + "%s:%d: %s: assertion \"%s\" failed, got %s", ap->locus.beg.file, ap->locus.beg.line, srvid(srv), - ap->text); + ap->text, + ap->buf); return; } @@ -177,27 +178,156 @@ process_result(struct slb_server *srv, struct snmp_pdu *pdu) } } -void -server_process_pdu(int operation, struct slb_server *srv, struct snmp_pdu *pdu) +static int +slb_table_grow(struct slb_table *tab, struct variable_list *vp) +{ + size_t out_len = 0; + size_t bufsize = 16; + unsigned char *buf = grecs_malloc(bufsize); + struct slb_idxnum *ent; + int install = 1; + int rc; + + /* This is needed by sprint_realloc_value. + Very unfortunate. */ + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_QUICK_PRINT, 1); + rc = sprint_realloc_value(&buf, &bufsize, &out_len, + 1, vp->name, vp->name_length, vp); + /* On the other hand, assertions assume data type prefix */ + netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, + NETSNMP_DS_LIB_QUICK_PRINT, 0); + if (rc == 0) { + logmsg(LOG_ERR, + "cannot format variable: %s", + snmp_api_errstring(snmp_errno)); + return 1; + } + + ent = idxnum_lookupz(tab->tab_idx, buf, &install); + ent->idxnum_num = vp->name[tab->tab_oidlen]; + + return 0; +} + +struct table_match_closure { + struct grecs_symtab *tables; + oid *oid; + size_t oidlen; + struct slb_table *result; +}; + +static int +table_match_var(void *sym, void *data) +{ + struct slb_table *tab = sym; + struct table_match_closure *clos = data; + + if (clos->oidlen >= tab->tab_oidlen + && memcmp(tab->tab_oid, clos->oid, + tab->tab_oidlen * sizeof(clos->oid[0])) == 0) { + /* Select longest matching prefix */ + if (!clos->result || + clos->result->tab_oidlen < tab->tab_oidlen) + clos->result = tab; + } + return 0; +} + +static struct slb_table * +oid_to_table(struct slb_server *srv, oid *oid, size_t oidlen) +{ + struct table_match_closure clos; + + clos.tables = srv->tables; + clos.oid = oid; + clos.oidlen = oidlen; + clos.result = NULL; + grecs_symtab_enumerate(srv->tables, table_match_var, &clos); + return clos.result; +} + + +static void +process_next(struct slb_server *srv, struct snmp_pdu *pdu) +{ + struct variable_list *vp; + struct snmp_pdu *pdu2; + size_t varcnt = 0; + + if (debug_level[SLB_DEBCAT_SNMP] >= 2 && + !(srv->flags & SLB_SRV_COMPUTED)) { + debug_printf("%s replied", srvid(srv)); + srv->flags |= SLB_SRV_COMPUTED; + } + debug(SLB_DEBCAT_SNMP, 10, ("reply from %s", srvid(srv))); + + pdu2 = snmp_clone_pdu(srv->pdu); + snmp_free_varbind(pdu2->variables); + pdu2->variables = NULL; + srv->pdu = pdu2; + + for (vp = pdu->variables; vp; vp = vp->next_variable) { + struct slb_table *tab = + oid_to_table(srv, vp->name, vp->name_length); + if (!tab) + continue; + slb_table_grow(tab, vp); + snmp_add_null_var(pdu2, vp->name, vp->name_length); + varcnt++; + } + + if (varcnt && snmp_send(srv->sess, pdu2)) + active_count++; + else + snmp_free_pdu(pdu2); +} + +static void +_process_pdu(int operation, struct slb_server *srv, + struct snmp_pdu *pdu, + void (*proc)(struct slb_server *, struct snmp_pdu *), + int clrflag) { if (operation == NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE) { - process_result(srv, pdu); + proc(srv, pdu); } else { logmsg(LOG_ERR, "server %s: timeout", srvid(srv)); /* Re-initialize server state */ slb_node_state_init(srv->state); srv->expr->ex_eval_count = 0; + if (clrflag) + srv->flags &= ~clrflag; } } +void +server_process_pdu(int operation, struct slb_server *srv, + struct snmp_pdu *pdu) +{ + _process_pdu(operation, srv, pdu, process_result, 0); +} + int asynch_response(int operation, struct snmp_session *sp, int reqid, struct snmp_pdu *pdu, void *magic) { struct slb_server *srv = magic; - server_process_pdu(operation, srv, pdu); active_count--; + _process_pdu(operation, srv, pdu, process_result, 0); + return 1; +} + +int +asynch_response_next(int operation, struct snmp_session *sp, int reqid, + struct snmp_pdu *pdu, void *magic) +{ + struct slb_server *srv = magic; + + active_count--; + _process_pdu(operation, srv, pdu, process_next, + SLB_SRV_TAB_RESOLVED); return 1; } @@ -223,11 +353,21 @@ add_snmp_assertion(void *sym, void *data) return 0; } -static void +static int +add_table_var(void *sym, void *data) +{ + struct slb_table *tab = sym; + struct snmp_pdu *req = data; + snmp_add_null_var(req, tab->tab_oid, tab->tab_oidlen); + return 0; +} + +static size_t send_requests() { struct slb_server *srv; - + size_t refcnt = 0; + debug(SLB_DEBCAT_SNMP, 1, ("sending requests")); for (srv = srv_head; srv; srv = srv->next) { struct snmp_session sess; @@ -296,25 +436,43 @@ send_requests() sess.engineBoots = srv->snmp_v3.engine_boots; sess.engineTime = srv->snmp_v3.engine_time; } - - sess.callback = asynch_response; + sess.callback_magic = srv; + + if ((srv->flags & SLB_SRV_TAB_REFERENCED) && + !(srv->flags & SLB_SRV_TAB_RESOLVED)) { + sess.callback = asynch_response_next; + refcnt++; + + req = snmp_pdu_create(SNMP_MSG_GETNEXT); + grecs_symtab_enumerate(srv->tables, add_table_var, + req); + srv->flags |= SLB_SRV_TAB_RESOLVED; + } else { + sess.callback = asynch_response; + varinst_unset(srv->varinst); + + req = snmp_pdu_create(SNMP_MSG_GET); + grecs_symtab_enumerate(srv->varinst, + add_snmp_var, + req); + grecs_symtab_enumerate(srv->assertions, + add_snmp_assertion, + req); + } + srv->flags &= ~SLB_SRV_COMPUTED; + if (!(srv->sess = snmp_open(&sess))) { - logmsg(LOG_ERR, "server %s: snmp_open failed: %s", - srvid(srv), snmp_api_errstring(snmp_errno)); + logmsg(LOG_ERR, + "server %s: snmp_open failed: %s", + srvid(srv), + snmp_api_errstring(snmp_errno)); continue; } - varinst_unset(srv->varinst); - srv->flags &= ~SLB_SRV_COMPUTED; - - req = snmp_pdu_create(SNMP_MSG_GET); - grecs_symtab_enumerate(srv->varinst, add_snmp_var, req); - grecs_symtab_enumerate(srv->assertions, add_snmp_assertion, - req); - if (snmp_send(srv->sess, req)) { active_count++; + srv->pdu = req; } else { logmsg(LOG_ERR, "server %s: snmp_send failed: %s", srvid(srv), snmp_api_errstring(snmp_errno)); @@ -323,6 +481,92 @@ send_requests() srv->sess = NULL; } } + return refcnt; +} + +static int +resolve_varinst_index(void *sym, void *data) +{ + struct slb_varinstance *vinst = sym; + struct slb_server *srv = data; + + if (vinst->vi_index) { + struct slb_index *idx = vinst->vi_index; + struct slb_idxnum *ent = + idxnum_lookupz(idx->idx_table->tab_idx, + idx->idx_tag, NULL); + if (ent) { + unsigned char *buf; + size_t buf_len = 256; + size_t out_len = 0; + int ovf = 0; + + vinst->vi_oid[vinst->vi_oidlen - vinst->vi_idxpos] = + ent->idxnum_num; + + buf = grecs_malloc(buf_len); + netsnmp_sprint_realloc_objid(&buf, + &buf_len, + &out_len, 1, + &ovf, + vinst->vi_oid, + vinst->vi_oidlen); + + logmsg(LOG_INFO, + "%s:%d: (%s) %s resolved to %s", + vinst->vi_locus.beg.file, + vinst->vi_locus.beg.line, + srvid(srv), + vinst->vi_mib, + buf); + + /* FIXME: This has a side effect of converting + the MIB to numeric form. */ + free(vinst->vi_mib); + vinst->vi_mib = buf; + oidtab_install(srv->oidtab, vinst); + return 0; + } + + logmsg(LOG_NOTICE, + "%s:%d: cannot resolve %s; disabling server %s", + vinst->vi_locus.beg.file, + vinst->vi_locus.beg.line, + vinst->vi_mib, + srvid(srv)); + srv->flags |= SLB_SRV_DISABLED; + return 1; + } + return 0; +} + +#if 0 +static int +resolve_assertion_index(void *sym, void *data) +{ + struct slb_assertion *ap = sym; + struct slb_server *srv = data; + return 1;//FIXME +} +#endif + +static void +resolve_tables() +{ + struct slb_server *srv; + for (srv = srv_head; srv; srv = srv->next) { + if (srv->flags & SLB_SRV_DISABLED || + !(srv->flags & SLB_SRV_TAB_RESOLVED)) + continue; + grecs_symtab_enumerate(srv->varinst, + resolve_varinst_index, + srv); +#if 0 + grecs_symtab_enumerate(srv->assertions, + resolve_assertion_index, + srv); +#endif + } } static void @@ -403,7 +647,14 @@ snmploop() { active_count = 0; slb_loop_serial++; - send_requests(); + if (send_requests()) { + /* Process tables */ + debug(SLB_DEBCAT_SNMP, 2, ("getting subtrees")); + recv_loop(); + debug(SLB_DEBCAT_SNMP, 2, ("resolving indexed variables")); + resolve_tables(); + send_requests(); + } slb_loop_ts = time(NULL); recv_loop(); sess_cleanup(); diff --git a/src/symimp.c b/src/symimp.c index 2d54c18..d8d693c 100644 --- a/src/symimp.c +++ b/src/symimp.c @@ -1,5 +1,5 @@ /* This file is part of SLB - Copyright (C) 2011 Sergey Poznyakoff + Copyright (C) 2011, 2012 Sergey Poznyakoff SLB is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -163,3 +163,46 @@ macro_lookupz(struct grecs_symtab *mt, const char *name, int *install) _lookupz(mt, name, install, "macro"); } +struct slb_table * +table_lookup(struct grecs_symtab *tab, const char *name, size_t len, + int *install) +{ + return (struct slb_table *) + _lookup(tab, name, len, install, "table"); +} + +struct slb_table * +table_lookupz(struct grecs_symtab *tab, const char *name, int *install) +{ + return (struct slb_table *) + _lookupz(tab, name, install, "table"); +} + +struct slb_index * +index_lookup(struct grecs_symtab *tab, const char *name, size_t len, + int *install) +{ + return (struct slb_index *) + _lookup(tab, name, len, install, "index"); +} + +struct slb_index * +index_lookupz(struct grecs_symtab *tab, const char *name, int *install) +{ + return (struct slb_index *) + _lookupz(tab, name, install, "index"); +} + +struct slb_idxnum * +idxnum_lookup(struct grecs_symtab *tab, const char *name, size_t len, + int *install) +{ + return (struct slb_idxnum *) + _lookup(tab, name, len, install, "idxnum"); +} + +struct slb_idxnum * +idxnum_lookupz(struct grecs_symtab *tab, const char *name, int *install) +{ + return (struct slb_idxnum *) _lookupz(tab, name, install, "indnum"); +} @@ -85,8 +85,8 @@ input_read_server(struct slb_server *srv) int wsflags = WRDSF_NOVAR | WRDSF_NOCMD | WRDSF_QUOTE | WRDSF_SQUEEZE_DELIMS; - if (!srv->test_pdu) - srv->test_pdu = snmp_pdu_create(SNMP_MSG_GET); + if (!srv->pdu) + srv->pdu = snmp_pdu_create(SNMP_MSG_GET); while (1) { oid oid[MAX_OID_LEN]; size_t oidlen; @@ -127,7 +127,7 @@ input_read_server(struct slb_server *srv) continue; } - if (snmp_add_var(srv->test_pdu, oid, oidlen, + if (snmp_add_var(srv->pdu, oid, oidlen, *ws.ws_wordv[1], ws.ws_wordv[2])) { logmsg(LOG_CRIT, "%s:%d: cannot add variable: %s", @@ -151,14 +151,14 @@ test_server_replies() varinst_unset(srv->varinst); srv->flags &= ~SLB_SRV_COMPUTED; - server_process_pdu(srv->test_pdu ? + server_process_pdu(srv->pdu ? NETSNMP_CALLBACK_OP_RECEIVED_MESSAGE : NETSNMP_CALLBACK_OP_TIMED_OUT, srv, - srv->test_pdu); - if (srv->test_pdu) { - snmp_free_pdu(srv->test_pdu); - srv->test_pdu = NULL; + srv->pdu); + if (srv->pdu) { + snmp_free_pdu(srv->pdu); + srv->pdu = NULL; } } sort(); |