SNMP: Step towards dynamic tables
This commit is contained in:
parent
5d1c78ead5
commit
94c00a2584
5 changed files with 186 additions and 114 deletions
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue