diff --git a/apps/snmp/snmp_handler.c b/apps/snmp/snmp_handler.c index f2550577..c4723a4b 100644 --- a/apps/snmp/snmp_handler.c +++ b/apps/snmp/snmp_handler.c @@ -103,75 +103,18 @@ snmp_common_handler(netsnmp_mib_handler *handler, clicon_debug(1, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__, oidstr2, snmp_msg_int2str(reqinfo->mode), - requests->inclusive, tablehandler?"table":""); + requests->inclusive, tablehandler?"table":"scalar"); else clicon_debug(1, "%s \"%s\"/\"%s\" %s inclusive:%d %s", __FUNCTION__, oidstr2, oidstr0, snmp_msg_int2str(reqinfo->mode), - requests->inclusive, tablehandler?"table":""); + requests->inclusive, tablehandler?"table":"scalar"); retval = 0; done: return retval; } -/*! SNMP table operation handler - * Callorder: 161,160,.... 0, 1,2,3, 160,161,... - * see https://net-snmp.sourceforge.io/dev/agent/data_set_8c-example.html#_a0 - * - * see table_array.[ch] simplify the task of - * writing a table handler for the net-snmp agent when the data being - * accessed is in an oid sorted form and must be accessed externally. - * - * netsnmp_table_build_oid_from_index() - * - * table_container.[ch] - * - * build_new_oid - */ -int -clixon_snmp_table_handler(netsnmp_mib_handler *handler, - netsnmp_handler_registration *nhreg, - netsnmp_agent_request_info *reqinfo, - netsnmp_request_info *requests) -{ - int retval = -1; - clixon_snmp_handle *sh = NULL; - cvec *nsc = NULL; - cxobj *xt = NULL; - cbuf *cb = NULL; - int ret; - - clicon_debug(1, "%s", __FUNCTION__); - if ((ret = snmp_common_handler(handler, nhreg, reqinfo, requests, &sh, 1)) < 0) - goto done; - switch(reqinfo->mode){ - case MODE_GETNEXT: // 160 -#ifdef SNMP_TABLE_DYNAMIC - /* Register table sub-oid:s of existing entries in clixon */ - if (mibyang_table_poll(sh->sh_h, sh->sh_ys) < 0) - goto done; -#endif - break; - case MODE_GET: // 160 - case MODE_SET_RESERVE1: - case MODE_SET_RESERVE2: - case MODE_SET_ACTION: - case MODE_SET_COMMIT: - break; - - } -// ok: - retval = SNMP_ERR_NOERROR; - done: - if (xt) - xml_free(xt); - if (cb) - cbuf_free(cb); - if (nsc) - xml_nsctx_free(nsc); - return retval; -} /*! Scalar handler, set a value to clixon * get xpath: see yang2api_path_fmt / api_path2xpath @@ -356,18 +299,16 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler, { int retval = -1; clixon_snmp_handle *sh = NULL; - yang_stmt *ys; int asn1_type; netsnmp_variable_list *requestvb = requests->requestvb; clicon_debug(2, "%s", __FUNCTION__); if (snmp_common_handler(handler, nhreg, reqinfo, requests, &sh, 0) < 0) goto done; - ys = sh->sh_ys; /* see net-snmp/agent/snmp_agent.h / net-snmp/library/snmp.h */ switch (reqinfo->mode) { case MODE_GET: /* 160 */ - if (snmp_scalar_get(sh->sh_h, ys, sh->sh_cvk_orig, + if (snmp_scalar_get(sh->sh_h, sh->sh_ys, sh->sh_cvk_orig, requestvb, sh->sh_default, reqinfo, requests) < 0) goto done; break; @@ -376,7 +317,7 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler, break; case MODE_SET_RESERVE1: /* 0 */ /* Translate from YANG ys leaf type to SNMP asn1.1 type ids (not value), also cvtype */ - if (type_yang2asn1(ys, &asn1_type, 0) < 0) + if (type_yang2asn1(sh->sh_ys, &asn1_type, 0) < 0) goto done; if (requestvb->type != asn1_type){ clicon_debug(1, "%s Expected type:%d, got: %d", __FUNCTION__, requestvb->type, asn1_type); @@ -387,7 +328,7 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler, case MODE_SET_RESERVE2: /* 1 */ break; case MODE_SET_ACTION: /* 2 */ - if (snmp_scalar_set(sh->sh_h, ys, requestvb, reqinfo, requests) < 0) + if (snmp_scalar_set(sh->sh_h, sh->sh_ys, requestvb, reqinfo, requests) < 0) goto done; break; case MODE_SET_UNDO: /* 5 */ @@ -406,3 +347,83 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler, done: return retval; } + +/*! SNMP table operation handler + * Callorder: 161,160,.... 0, 1,2,3, 160,161,... + * see https://net-snmp.sourceforge.io/dev/agent/data_set_8c-example.html#_a0 + * + * see table_array.[ch] simplify the task of + * writing a table handler for the net-snmp agent when the data being + * accessed is in an oid sorted form and must be accessed externally. + * + * netsnmp_table_build_oid_from_index() + * + * table_container.[ch] + * + * build_new_oid + */ +int +clixon_snmp_table_handler(netsnmp_mib_handler *handler, + netsnmp_handler_registration *nhreg, + netsnmp_agent_request_info *reqinfo, + netsnmp_request_info *requests) +{ + int retval = -1; + clixon_snmp_handle *sh = NULL; + cvec *nsc = NULL; + cxobj *xt = NULL; + cbuf *cb = NULL; + int ret; + + clicon_debug(2, "%s", __FUNCTION__); + if ((ret = snmp_common_handler(handler, nhreg, reqinfo, requests, &sh, 1)) < 0) + goto done; + if (sh->sh_ys == NULL){ + clicon_debug(1, "%s Error table not registered", __FUNCTION__); + goto ok; + } + switch(reqinfo->mode){ + case MODE_GET: // 160 +#ifdef SNMP_TABLE_DYNAMIC + /* Register table sub-oid:s of existing entries in clixon */ + if (mibyang_table_poll(sh->sh_h, sh->sh_ys) < 0) + goto done; +#if 1 + { + if ((ret = netsnmp_call_next_handler(handler, nhreg, reqinfo, requests)) < 0){ + clicon_err(OE_SNMP, ret, "netsnmp_call_next_handler"); + goto done; + } + } +#endif + // Wrong sh, need to make another call + // if (snmp_scalar_get(sh->sh_h, sh->sh_ys, sh->sh_cvk_orig, + // requestvb, sh->sh_default, reqinfo, requests) < 0) +#endif + // Then try and get actual scalar + break; + case MODE_GETNEXT: // 161 +#ifdef SNMP_TABLE_DYNAMIC + /* Register table sub-oid:s of existing entries in clixon */ + if (mibyang_table_poll(sh->sh_h, sh->sh_ys) < 0) + goto done; +#endif + break; + case MODE_SET_RESERVE1: + case MODE_SET_RESERVE2: + case MODE_SET_ACTION: + case MODE_SET_COMMIT: + break; + + } + ok: + retval = SNMP_ERR_NOERROR; + done: + if (xt) + xml_free(xt); + if (cb) + cbuf_free(cb); + if (nsc) + xml_nsctx_free(nsc); + return retval; +} diff --git a/apps/snmp/snmp_lib.c b/apps/snmp/snmp_lib.c index a6c82243..a739f1a1 100644 --- a/apps/snmp/snmp_lib.c +++ b/apps/snmp/snmp_lib.c @@ -156,6 +156,18 @@ snmp_msg_int2str(int msg) { return clicon_int2str(snmp_msg_map, msg); } +/*! Should be netsnmp lib function, cant find it + */ +int +oid_eq(const oid *objid0, + size_t objid0len, + const oid *objid1, + size_t objid1len) +{ + if (objid0len != objid1len) + return 0; + return memcmp(objid0, objid1, objid0len*sizeof(*objid0)); +} /*! Duplicate clixon snmp handler struct * Use signature of libnetsnmp data_clone field of netsnmp_mib_handler in agent_handler.h @@ -753,45 +765,17 @@ snmp_body2oid(cxobj *xi, return retval; } -/*========== libnetsnmp-specific code =============== - * Peeks into internal lib global variables, may be sensitive to library change - */ -/*! Check if netsnmp is connected - * @retval 1 yes, running - * @retval 0 No, not running - * XXX: this peeks into the "main_session" global variable in agent/snmp_agent.c - * Tried to find API function but failed - */ -int -snmp_agent_check(void) -{ - extern netsnmp_session *main_session; - - return (main_session != NULL) ? 1 : 0; -} - -/*! Cleanup remaining libnetsnmb memory - * XXX: this peeks into the "tclist" global variable in snmplib/parse.c - * Tried to find API function but failed - */ -int -snmp_agent_cleanup(void) -{ - extern void *tclist; - - if (tclist) - free(tclist); - return 0; -} - -/* Specialized SNMP error category log/err callback +/*! Specialized SNMP error category log/err callback * - * This function displays all negative SNMP errors on the form SNMPERR_* that are not SNMPERR_SUCCESS(=0) - * There are also positive SNMP errors on the form SNMP_ERR_* which are not properly handled below + * This function displays all negative SNMP errors on the form SNMPERR_* that are not + * SNMPERR_SUCCESS(=0) + * There are also positive SNMP errors on the form SNMP_ERR_* which are not properly handled + * below * @param[in] handle Application-specific handle - * @param[in] suberr Application-specific handle, points to SNMP_ERR_* unless < -0x1000 in which - case they are MIB_* errors defined in agent_registry.h - * @param[out] cb Read log/error string into this buffer + * @param[in] suberr Application-specific handle, points to SNMP_ERR_* unless + < CLIXON_ERR_SNMP_MIB in which case they are MIB_* errors defined + in agent_registry.h + * @param[out] cb Read log/error string into this buffer * @note Some SNMP API functions sometimes returns NULL/ptr or other return values that do not fall into * this category, then OE_SNMP should NOT be used. */ @@ -827,3 +811,60 @@ clixon_snmp_err_cb(void *handle, } return 0; } + +/*========== libnetsnmp-specific code =============== + * Peeks into internal lib global variables, may be sensitive to library change + */ +/*! Check if netsnmp is connected + * @retval 1 yes, running + * @retval 0 No, not running + * XXX: this peeks into the "main_session" global variable in agent/snmp_agent.c + * Tried to find API function but failed + */ +int +clixon_snmp_api_agent_check(void) +{ + extern netsnmp_session *main_session; + + return (main_session != NULL) ? 1 : 0; +} + +/*! Cleanup remaining libnetsnmb memory + * XXX: this peeks into the "tclist" global variable in snmplib/parse.c + * Tried to find API function but failed + */ +int +clixon_snmp_api_agent_cleanup(void) +{ + extern void *tclist; + + if (tclist) + free(tclist); + return 0; +} + +/*! See if oid is registered + * This is good enough for add, + * But for delete a more advanced function is needed + * @see netsnmp_subtree_load + * @retval -1 Error + * @retval 0 Not found + * @retval 1 Found + */ +int +clixon_snmp_api_oid_find(oid *oid0, + size_t oid0len) +{ + int retval = -1; + netsnmp_subtree *tree1 = NULL; + + if ((tree1 = netsnmp_subtree_find(oid0, oid0len, NULL, "")) != NULL && + oid_eq(oid0, oid0len, tree1->name_a, tree1->namelen)){ + fprintf(stderr, "%s EQUAL==================\n", __FUNCTION__); + retval = 1; + } + else + retval = 0; + // done: + return retval; +} diff --git a/apps/snmp/snmp_lib.h b/apps/snmp/snmp_lib.h index 98939681..8b53a907 100644 --- a/apps/snmp/snmp_lib.h +++ b/apps/snmp/snmp_lib.h @@ -67,6 +67,8 @@ typedef struct clixon_snmp_handle clixon_snmp_handle; /* * Prototypes */ + +int oid_eq(const oid * objid0, size_t objid0len, const oid * objid1, size_t objid1len); int snmp_access_str2int(char *modes_str); const char *snmp_msg_int2str(int msg); void *snmp_handle_clone(void *arg); @@ -81,10 +83,13 @@ int type_xml2snmp_pre(char *xmlstr, yang_stmt *ys, char **snmpstr); int type_xml2snmp(char *snmpstr, int *asn1type, u_char **snmpval, size_t *snmplen, char **reason); int yang2xpath(yang_stmt *ys, cvec *keyvec, char **xpath); int snmp_body2oid(cxobj *xi, cg_var *cv); -int snmp_agent_check(void); -int snmp_agent_cleanup(void); int clixon_snmp_err_cb(void *handle, int suberr, cbuf *cb); +/*========== libnetsnmp-specific code =============== */ +int clixon_snmp_api_agent_check(void); +int clixon_snmp_api_agent_cleanup(void); +int clixon_snmp_api_oid_find(oid *oid1, size_t oidlen); + #endif /* _SNMP_LIB_H_ */ #ifdef __cplusplus diff --git a/apps/snmp/snmp_main.c b/apps/snmp/snmp_main.c index 1db56424..0a0fbc6c 100644 --- a/apps/snmp/snmp_main.c +++ b/apps/snmp/snmp_main.c @@ -110,7 +110,7 @@ snmp_terminate(clicon_handle h) snmp_shutdown(__FUNCTION__); shutdown_agent(); - snmp_agent_cleanup(); + clixon_snmp_api_agent_cleanup(); clicon_rpc_close_session(h); if ((yspec = clicon_dbspec_yang(h)) != NULL) ys_free(yspec); @@ -267,7 +267,7 @@ clixon_snmp_init_subagent(clicon_handle h, /* example-demon will be used to read example-demon.conf files. */ init_snmp(__PROGRAM__); - if (!snmp_agent_check()){ + if (!clixon_snmp_api_agent_check()){ clicon_err(OE_DAEMON, 0, "Connection to SNMP agent failed"); goto done; } diff --git a/apps/snmp/snmp_register.c b/apps/snmp/snmp_register.c index 88760f18..b4e86b37 100644 --- a/apps/snmp/snmp_register.c +++ b/apps/snmp/snmp_register.c @@ -95,6 +95,7 @@ * @retval 0 OK * @retval -1 Error + * netsnmp_subtree_find(oid1,sz1, 0, 0) */ static int mibyang_leaf_register(clicon_handle h, @@ -110,7 +111,7 @@ mibyang_leaf_register(clicon_handle h, char *default_str = NULL; char *oidstr = NULL; oid oid1[MAX_OID_LEN] = {0,}; - size_t sz1 = MAX_OID_LEN; + size_t oid1len = MAX_OID_LEN; int modes; char *name; clixon_snmp_handle *sh; @@ -132,11 +133,14 @@ mibyang_leaf_register(clicon_handle h, cvi = NULL; while ((cvi = cvec_each(cvk_oid, cvi)) != NULL) cprintf(cboid, ".%s", cv_string_get(cvi)); - if (snmp_parse_oid(cbuf_get(cboid), oid1, &sz1) == NULL){ + if (snmp_parse_oid(cbuf_get(cboid), oid1, &oid1len) == NULL){ clicon_err(OE_XML, 0, "snmp_parse_oid(%s)", cbuf_get(cboid)); // goto done; goto ok; // XXX skip } + /* Check if already registered */ + if (clixon_snmp_api_oid_find(oid1, oid1len) == 1) + goto ok; if (yang_extension_value(ys, "max-access", IETF_YANG_SMIV2_NS, NULL, &modes_str) < 0) goto done; /* Only for sanity check of types initially to fail early */ @@ -155,7 +159,7 @@ mibyang_leaf_register(clicon_handle h, goto done; name = yang_argument_get(ys); - + /* Stateless function, just returns ptr */ if ((handler = netsnmp_create_handler(name, clixon_snmp_scalar_handler)) == NULL){ clicon_err(OE_XML, errno, "netsnmp_create_handler"); goto done; @@ -172,7 +176,7 @@ mibyang_leaf_register(clicon_handle h, sh->sh_h = h; sh->sh_ys = ys; memcpy(sh->sh_oid, oid1, sizeof(oid1)); - sh->sh_oidlen = sz1; + sh->sh_oidlen = oid1len; sh->sh_default = default_str; if (cvk_orig && (sh->sh_cvk_orig = cvec_dup(cvk_orig)) == NULL){ @@ -184,8 +188,9 @@ mibyang_leaf_register(clicon_handle h, clicon_err(OE_UNIX, errno, "cvec_dup"); goto done; } + /* Stateless function, just returns ptr */ if ((nhreg = netsnmp_handler_registration_create(name, handler, - oid1, sz1, + oid1, oid1len, modes)) == NULL){ clicon_err(OE_XML, errno, "netsnmp_handler_registration_create"); netsnmp_handler_free(handler); @@ -238,7 +243,7 @@ mibyang_table_register(clicon_handle h, netsnmp_handler_registration *nhreg; char *oidstr = NULL; oid oid1[MAX_OID_LEN] = {0,}; - size_t sz1 = MAX_OID_LEN; + size_t oid1len = MAX_OID_LEN; char *name; clixon_snmp_handle *sh; int ret; @@ -261,7 +266,7 @@ mibyang_table_register(clicon_handle h, goto done; if (oidstr == NULL) goto ok; - if (snmp_parse_oid(oidstr, oid1, &sz1) == NULL){ + if (snmp_parse_oid(oidstr, oid1, &oid1len) == NULL){ clicon_err(OE_XML, errno, "snmp_parse_oid"); goto done; } @@ -279,14 +284,14 @@ mibyang_table_register(clicon_handle h, sh->sh_ys = ylist; memcpy(sh->sh_oid, oid1, sizeof(oid1)); - sh->sh_oidlen = sz1; + sh->sh_oidlen = oid1len; if ((handler = netsnmp_create_handler(name, clixon_snmp_table_handler)) == NULL){ clicon_err(OE_XML, errno, "netsnmp_create_handler"); goto done; } if ((nhreg = netsnmp_handler_registration_create(name, handler, - oid1, sz1, + oid1, oid1len, HANDLER_CAN_RWRITE)) == NULL){ clicon_err(OE_XML, errno, "netsnmp_handler_registration_create"); netsnmp_handler_free(handler);