SNMP frontend: Generalized type handling for set functions
SPlit scalar_handler into get and set subfunctions
This commit is contained in:
parent
34fe439f53
commit
ea03363c3a
8 changed files with 285 additions and 398 deletions
|
|
@ -118,6 +118,143 @@ done:
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Scalar handler, set a value to clixon
|
||||
* get xpath: see yang2api_path_fmt / api_path2xpath
|
||||
*/
|
||||
static int
|
||||
snmp_scalar_get(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
netsnmp_variable_list *requestvb,
|
||||
char *defaultval,
|
||||
enum cv_type cvtype,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *nsc = NULL;
|
||||
char *xpath = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xerr;
|
||||
cxobj *x;
|
||||
char *valstr = NULL;
|
||||
u_char *snmpval = NULL;
|
||||
size_t snmplen;
|
||||
int ret;
|
||||
|
||||
if (xml_nsctx_yang(ys, &nsc) < 0)
|
||||
goto done;
|
||||
if (yang2xpath(ys, &xpath) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clixon_netconf_error(xerr, "clicon_rpc_get", NULL);
|
||||
goto done;
|
||||
}
|
||||
/* Get value, either from xml, or smiv2 default */
|
||||
if ((x = xpath_first(xt, nsc, "%s", xpath)) != NULL) {
|
||||
valstr = xml_body(x);
|
||||
}
|
||||
else if ((valstr = defaultval) != NULL)
|
||||
;
|
||||
else{
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = type_yang2snmp(valstr, cvtype, reqinfo, requests, &snmpval, &snmplen)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
|
||||
/* 1. use cligen object and get rwa buf / size from that, OR
|
||||
* + have parse function from YANG
|
||||
* - does not have
|
||||
* 2. use union netsnmp_vardata and pass that here?
|
||||
* 3. Make cv2asn1 conversion function <--
|
||||
*/
|
||||
|
||||
/* see snmplib/snmp_client.c */
|
||||
if (snmp_set_var_value(requestvb,
|
||||
snmpval,
|
||||
snmplen) != 0){
|
||||
clicon_err(OE_SNMP, 0, "snmp_set_var_value");
|
||||
goto done;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (snmpval)
|
||||
free(snmpval);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Scalar handler, get a value from clixon
|
||||
*/
|
||||
static int
|
||||
snmp_scalar_set(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
int retval = -1;
|
||||
char *api_path = NULL;
|
||||
cxobj *xtop = NULL;
|
||||
cxobj *xbot = NULL;
|
||||
cxobj *xb;
|
||||
yang_stmt *yspec;
|
||||
int ret;
|
||||
char *valstr = NULL;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
if ((xtop = xml_new(NETCONF_INPUT_CONFIG, NULL, CX_ELMNT)) == NULL)
|
||||
goto done;
|
||||
if (yang2api_path_fmt(ys, 0, &api_path) < 0)
|
||||
goto done;
|
||||
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, NULL, NULL)) < 0)
|
||||
goto done;
|
||||
|
||||
if (ret == 0){
|
||||
clicon_err(OE_XML, 0, "api_path2xml %s invalid", api_path);
|
||||
goto done;
|
||||
}
|
||||
if ((xb = xml_new("body", xbot, CX_BODY)) == NULL)
|
||||
goto done;
|
||||
if ((ret = type_snmp2yang(requestvb, reqinfo, requests, &valstr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
if (xml_value_set(xb, valstr) < 0)
|
||||
goto done;
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_xml2cbuf(cb, xtop, 0, 0, -1) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_edit_config(h, "candidate", OP_MERGE, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (xtop)
|
||||
xml_free(xtop);
|
||||
if (valstr)
|
||||
free(valstr);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! SNMP Scalar operation handler
|
||||
* Calls order: READ:160,
|
||||
|
|
@ -131,25 +268,13 @@ snmp_scalar_handler(netsnmp_mib_handler *handler,
|
|||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
int retval = -1;
|
||||
clixon_snmp_handle *sh;
|
||||
yang_stmt *ys;
|
||||
clicon_handle h;
|
||||
cg_var *cv = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xerr;
|
||||
cvec *nsc = NULL;
|
||||
cxobj *x;
|
||||
char *xpath = NULL;
|
||||
int asn1_type;
|
||||
enum cv_type cvtype;
|
||||
char *valstr;
|
||||
u_char *snmpval = NULL;
|
||||
size_t snmplen;
|
||||
int ret;
|
||||
int retval = -1;
|
||||
clixon_snmp_handle *sh;
|
||||
yang_stmt *ys;
|
||||
int asn1_type;
|
||||
netsnmp_variable_list *requestvb; /* sub of requests */
|
||||
cbuf *cb = NULL;
|
||||
|
||||
enum cv_type cvtype;
|
||||
|
||||
/*
|
||||
* can be used to pass information on a per-pdu basis from a
|
||||
* helper to the later handlers
|
||||
|
|
@ -174,7 +299,6 @@ snmp_scalar_handler(netsnmp_mib_handler *handler,
|
|||
requests->inclusive);
|
||||
sh = (clixon_snmp_handle*)nhreg->my_reg_void;
|
||||
ys = sh->sh_ys;
|
||||
h = sh->sh_h;
|
||||
// fprint_objid(stderr, nhreg->rootoid, nhreg->rootoid_len);
|
||||
assert(sh->sh_oidlen == requestvb->name_length);
|
||||
assert(requestvb->name_length == nhreg->rootoid_len);
|
||||
|
|
@ -188,123 +312,43 @@ snmp_scalar_handler(netsnmp_mib_handler *handler,
|
|||
SNMP_NOSUCHOBJECT);
|
||||
return SNMP_ERR_NOERROR;
|
||||
#endif
|
||||
|
||||
if (yang2snmp_types(ys, &asn1_type, &cvtype) < 0)
|
||||
goto done;
|
||||
|
||||
/* see net-snmp/agent/snmp_agent.h / net-snmp/library/snmp.h */
|
||||
switch (reqinfo->mode) {
|
||||
case MODE_GET: // 160
|
||||
case MODE_GET: /* 160 */
|
||||
requestvb->type = asn1_type; // ASN_NULL on input
|
||||
|
||||
/* get xpath: see yang2api_path_fmt / api_path2xpath
|
||||
New fn: yang2xpath?
|
||||
clicon_rpc_get()
|
||||
<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/if:interfaces\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\" /></get></rpc>"
|
||||
|
||||
*/
|
||||
|
||||
if (xml_nsctx_yang(ys, &nsc) < 0)
|
||||
if (snmp_scalar_get(sh->sh_h, ys, requestvb, sh->sh_default, cvtype, reqinfo, requests) < 0)
|
||||
goto done;
|
||||
if (yang2xpath(ys, &xpath) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clixon_netconf_error(xerr, "clicon_rpc_get", NULL);
|
||||
goto done;
|
||||
}
|
||||
/* Get value, either from xml, or smiv2 default */
|
||||
if ((x = xpath_first(xt, nsc, "%s", xpath)) != NULL) {
|
||||
valstr = xml_body(x);
|
||||
}
|
||||
else if ((valstr = sh->sh_default) != NULL)
|
||||
;
|
||||
else{
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = type_yang2snmp(valstr, cvtype, reqinfo, requests, &snmpval, &snmplen)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
|
||||
/* 1. use cligen object and get rwa buf / size from that, OR
|
||||
* + have parse function from YANG
|
||||
* - does not have
|
||||
* 2. use union netsnmp_vardata and pass that here?
|
||||
* 3. Make cv2asn1 conversion function <--
|
||||
*/
|
||||
|
||||
/* see snmplib/snmp_client.c */
|
||||
if (snmp_set_var_value(requestvb,
|
||||
snmpval,
|
||||
snmplen) != 0){
|
||||
clicon_err(OE_SNMP, 0, "snmp_set_var_value");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case MODE_GETNEXT: // 161
|
||||
case MODE_GETNEXT: /* 161 */
|
||||
assert(0); // Not seen?
|
||||
break;
|
||||
case MODE_SET_RESERVE1: // 0
|
||||
case MODE_SET_RESERVE1: /* 0 */
|
||||
if (requestvb->type != asn1_type)
|
||||
netsnmp_set_request_error(reqinfo, requests,
|
||||
SNMP_ERR_WRONGTYPE);
|
||||
break;
|
||||
|
||||
case MODE_SET_RESERVE2: // 1
|
||||
case MODE_SET_RESERVE2: /* 1 */
|
||||
break;
|
||||
|
||||
case MODE_SET_ACTION: // 2
|
||||
/*
|
||||
* update current
|
||||
*/
|
||||
/* yang2xpath -> xpath2xml
|
||||
* accesses = *(requestvb->val.integer);
|
||||
* rpc edit-config
|
||||
<data></data>
|
||||
*/
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/*! XXX only int */
|
||||
cprintf(cb, "<config><NET-SNMP-EXAMPLES-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:NET-SNMP-EXAMPLES-MIB\"><netSnmpExampleScalars><netSnmpExampleInteger>%ld</netSnmpExampleInteger></netSnmpExampleScalars></NET-SNMP-EXAMPLES-MIB></config>", *requestvb->val.integer);
|
||||
if (clicon_rpc_edit_config(h, "candidate", OP_MERGE, cbuf_get(cb)) < 0)
|
||||
case MODE_SET_ACTION: /* 2 */
|
||||
if (snmp_scalar_set(sh->sh_h, ys, requestvb, reqinfo, requests) < 0)
|
||||
goto done;
|
||||
break;
|
||||
|
||||
case MODE_SET_UNDO: // 5
|
||||
if (clicon_rpc_discard_changes(h) < 0)
|
||||
case MODE_SET_UNDO: /* 5 */
|
||||
if (clicon_rpc_discard_changes(sh->sh_h) < 0)
|
||||
goto done;
|
||||
break;
|
||||
|
||||
case MODE_SET_COMMIT: // 3
|
||||
if (clicon_rpc_commit(h) < 0)
|
||||
case MODE_SET_COMMIT: /* 3 */
|
||||
if (clicon_rpc_commit(sh->sh_h) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case MODE_SET_FREE: // 4
|
||||
/*
|
||||
* nothing to do
|
||||
*/
|
||||
case MODE_SET_FREE: /* 4 */
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
retval = SNMP_ERR_NOERROR;
|
||||
done:
|
||||
if (snmpval)
|
||||
free(snmpval);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
if (cv)
|
||||
cv_free(cv);
|
||||
return retval;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,8 +54,9 @@
|
|||
#include <pwd.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
#include <sys/types.h>
|
||||
|
||||
/* net-snmp */
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
|
|
@ -91,16 +92,19 @@ static const map_str2int snmp_access_map[] = {
|
|||
/* Map between clixon and ASN.1 types.
|
||||
* @see net-snmp/library/asn1.h
|
||||
* @see union netsnmp_vardata in net-snmp/types.h
|
||||
* XXX not complete
|
||||
* XXX TimeTicks
|
||||
*/
|
||||
static const map_str2int snmp_type_map[] = {
|
||||
{"bool", ASN_BOOLEAN},
|
||||
|
||||
{"int32", ASN_INTEGER},
|
||||
{"bits", ASN_BIT_STR},
|
||||
{"string", ASN_OCTET_STR},
|
||||
{"empty", ASN_NULL},
|
||||
//XXX {"", ASN_OBJECT_ID},
|
||||
// XXX {"", ASN_SEQUENCE},
|
||||
// XXX {"", ASN_SET},
|
||||
// {"bool", ASN_BOOLEAN},
|
||||
// {"empty", ASN_NULL},
|
||||
// {"bits", ASN_BIT_STR},
|
||||
// {"", ASN_OBJECT_ID},
|
||||
// {"", ASN_SEQUENCE},
|
||||
// {"", ASN_SET},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
||||
|
|
@ -130,7 +134,13 @@ snmp_msg_int2str(int msg)
|
|||
{
|
||||
return clicon_int2str(snmp_msg_map, msg);
|
||||
}
|
||||
/*!
|
||||
/*! Translate from YANG to SNMP asn1.1 type ids (not value)
|
||||
*
|
||||
* @param[in] ys YANG leaf node
|
||||
* @param[out] asn1_type ASN.1 type id
|
||||
* @param[out] cvtype Clixon cv type
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
yang2snmp_types(yang_stmt *ys,
|
||||
|
|
@ -141,31 +151,38 @@ yang2snmp_types(yang_stmt *ys,
|
|||
yang_stmt *yrestype; /* resolved type */
|
||||
char *restype; /* resolved type */
|
||||
char *origtype=NULL; /* original type */
|
||||
int at;
|
||||
|
||||
/* Get yang type of leaf and trasnslate to ASN.1 */
|
||||
if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
goto done;
|
||||
restype = yrestype?yang_argument_get(yrestype):NULL;
|
||||
if (clicon_type2cv(origtype, restype, ys, cvtype) < 0)
|
||||
goto done;
|
||||
/* translate to asn.1 */
|
||||
*asn1_type = clicon_str2int(snmp_type_map, restype);
|
||||
if ((at = clicon_str2int(snmp_type_map, restype)) < 0){
|
||||
clicon_err(OE_YANG, 0, "No snmp translation for YANG %s type:%s",
|
||||
yang_argument_get(ys), restype);
|
||||
// goto done;
|
||||
}
|
||||
if (asn1_type)
|
||||
*asn1_type = at;
|
||||
if (cvtype && clicon_type2cv(origtype, restype, ys, cvtype) < 0)
|
||||
goto done;
|
||||
clicon_debug(1, "%s type:%s", __FUNCTION__, restype);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Translate from yang/xml/clixon to SNMP/ASN.1
|
||||
**
|
||||
* The tran
|
||||
*
|
||||
* @param[in] valstr Clixon/yang/xml string value
|
||||
* @param[in] cvtype Type of clixon type
|
||||
* @param[in] reqinfo snmpd API struct for error
|
||||
* @param[in] requests snmpd API struct for error
|
||||
* @param[out] snmpval Malloc:ed snmp type
|
||||
* @param[out] snmplen Length of snmp type
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid value
|
||||
* @retval 0 Invalid value or type
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
|
|
@ -216,6 +233,7 @@ type_yang2snmp(char *valstr,
|
|||
break;
|
||||
}
|
||||
default:
|
||||
assert(0); // XXX
|
||||
clicon_debug(1, "%s %s not supported", __FUNCTION__, cv_type2str(cvtype));
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE);
|
||||
goto fail;
|
||||
|
|
@ -231,6 +249,66 @@ type_yang2snmp(char *valstr,
|
|||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
/*! Translate from yang/xml/clixon to SNMP/ASN.1
|
||||
*
|
||||
* @param[in] snmpval Malloc:ed snmp type
|
||||
* @param[in] snmplen Length of snmp type
|
||||
* @param[in] reqinfo snmpd API struct for error
|
||||
* @param[in] requests snmpd API struct for error
|
||||
* @param[out] valstr Clixon/yang/xml string value, free after use)
|
||||
* @retval 1 OK, and valstr set
|
||||
* @retval 0 Invalid value or type
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
type_snmp2yang(netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests,
|
||||
char **valstr)
|
||||
{
|
||||
int retval = -1;
|
||||
char *cvtypestr;
|
||||
enum cv_type cvtype;
|
||||
cg_var *cv;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (valstr == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "valstr is NULL");
|
||||
goto done;
|
||||
}
|
||||
cvtypestr = (char*)clicon_int2str(snmp_type_map, requestvb->type);
|
||||
cvtype = cv_str2type(cvtypestr);
|
||||
if ((cv = cv_new(cvtype)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cv_new");
|
||||
goto done;
|
||||
}
|
||||
switch (requestvb->type){
|
||||
case ASN_BOOLEAN:
|
||||
case ASN_INTEGER:
|
||||
cv_int32_set(cv, *requestvb->val.integer);
|
||||
break;
|
||||
case ASN_OCTET_STR:
|
||||
cv_string_set(cv, (char*)requestvb->val.string);
|
||||
break;
|
||||
default:
|
||||
assert(0); // XXX
|
||||
clicon_debug(1, "%s %s not supported", __FUNCTION__, cv_type2str(cvtype));
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE);
|
||||
goto fail;
|
||||
break;
|
||||
}
|
||||
if ((*valstr = cv2str_dup(cv)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cv2str_dup");
|
||||
goto done;
|
||||
}
|
||||
retval = 1;
|
||||
done:
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, retval);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Construct an xpath from yang statement, internal fn using cb
|
||||
* Recursively construct it to the top.
|
||||
|
|
@ -263,9 +341,10 @@ yang2xpath_cb(yang_stmt *ys,
|
|||
cprintf(cb, "/");
|
||||
}
|
||||
}
|
||||
cprintf(cb, "%s:", yang_find_myprefix(ys));
|
||||
if (yang_keyword_get(ys) != Y_CHOICE && yang_keyword_get(ys) != Y_CASE)
|
||||
if (yang_keyword_get(ys) != Y_CHOICE && yang_keyword_get(ys) != Y_CASE){
|
||||
cprintf(cb, "%s:", yang_find_myprefix(ys));
|
||||
cprintf(cb, "%s", yang_argument_get(ys));
|
||||
}
|
||||
switch (yang_keyword_get(ys)){
|
||||
case Y_LIST: // XXX not xpaths
|
||||
cvk = yang_cvec_get(ys); /* Use Y_LIST cache, see ys_populate_list() */
|
||||
|
|
@ -290,7 +369,6 @@ yang2xpath_cb(yang_stmt *ys,
|
|||
}
|
||||
|
||||
/*! Construct an xpath from yang statement
|
||||
|
||||
* Recursively construct it to the top.
|
||||
* @param[in] ys Yang statement
|
||||
* @param[out] xpath Malloced xpath string, use free() after use
|
||||
|
|
|
|||
|
|
@ -64,6 +64,10 @@ int yang2snmp_types(yang_stmt *ys, int *asn1_type, enum cv_type *cvtype);
|
|||
int type_yang2snmp(char *valstr, enum cv_type cvtype,
|
||||
netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests,
|
||||
u_char **snmpval, size_t *snmplen);
|
||||
int type_snmp2yang(netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests,
|
||||
char **valstr);
|
||||
int yang2xpath(yang_stmt *ys, char **xpath);
|
||||
int clixon_table_create(netsnmp_table_data_set *table, yang_stmt *ys, clicon_handle h);
|
||||
|
||||
|
|
|
|||
|
|
@ -448,8 +448,8 @@ main(int argc,
|
|||
/* Init snmp as subagent */
|
||||
if (clixon_snmp_subagent(h, logdst) < 0)
|
||||
goto done;
|
||||
/* Init mib-translated yangs and register callbacks */
|
||||
if (clixon_snmp_mib_yangs(h) < 0)
|
||||
/* Init and traverse mib-translated yangs and register callbacks */
|
||||
if (clixon_snmp_traverse_mibyangs(h) < 0)
|
||||
goto done;
|
||||
|
||||
if (dbg)
|
||||
|
|
|
|||
|
|
@ -81,258 +81,6 @@
|
|||
|
||||
#define IETF_YANG_SMIV2_NS "urn:ietf:params:xml:ns:yang:ietf-yang-smiv2"
|
||||
|
||||
#if 0
|
||||
/*! SNMP table operation handlre
|
||||
|
||||
* Callorder: 161,160,.... 0, 1,2,3, 160,161,...
|
||||
* see https://net-snmp.sourceforge.io/dev/agent/data_set_8c-example.html#_a0
|
||||
*/
|
||||
int
|
||||
snmp_table_handler(netsnmp_mib_handler *handler,
|
||||
netsnmp_handler_registration *nhreg,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
int retval = SNMP_ERR_GENERR;
|
||||
clixon_snmp_handle *sh;
|
||||
netsnmp_table_data_set *table;
|
||||
yang_stmt *ys;
|
||||
clicon_handle h;
|
||||
yang_stmt *ylist;
|
||||
cvec *nsc = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cbuf *cb = NULL;
|
||||
|
||||
clicon_debug(1, "%s %s %s", __FUNCTION__,
|
||||
handler->handler_name,
|
||||
snmp_msg_int2str(reqinfo->mode));
|
||||
sh = (clixon_snmp_handle*)nhreg->my_reg_void;
|
||||
ys = sh->sh_ys;
|
||||
h = sh->sh_h;
|
||||
table = sh->sh_table;
|
||||
|
||||
if ((ylist = yang_find(ys, Y_LIST, NULL)) == NULL)
|
||||
goto ok;
|
||||
|
||||
if (clixon_table_create(table, ys, h) < 0)
|
||||
goto done;
|
||||
|
||||
switch(reqinfo->mode){
|
||||
case MODE_GETNEXT: // 160
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
/*! SNMP Scalar operation handler
|
||||
* Calls order: READ:160,
|
||||
* WRITE: 0, 1, 2, 3,
|
||||
* MODE_SET_RESERVE1, MODE_SET_RESERVE2, MODE_SET_ACTION, MODE_SET_COMMIT
|
||||
*
|
||||
*/
|
||||
int
|
||||
snmp_scalar_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;
|
||||
yang_stmt *ys;
|
||||
clicon_handle h;
|
||||
cg_var *cv = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xerr;
|
||||
cvec *nsc = NULL;
|
||||
cxobj *x;
|
||||
char *xpath = NULL;
|
||||
int asn1_type;
|
||||
enum cv_type cvtype;
|
||||
char *valstr;
|
||||
u_char *snmpval = NULL;
|
||||
size_t snmplen;
|
||||
int ret;
|
||||
netsnmp_variable_list *requestvb; /* sub of requests */
|
||||
cbuf *cb = NULL;
|
||||
|
||||
/*
|
||||
* can be used to pass information on a per-pdu basis from a
|
||||
* helper to the later handlers
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_data_list *agent_data;
|
||||
netsnmp_free_agent_data_set()
|
||||
*/
|
||||
requestvb = requests->requestvb;
|
||||
if (0)
|
||||
fprintf(stderr, "%s %s %s\n", __FUNCTION__,
|
||||
handler->handler_name,
|
||||
snmp_msg_int2str(reqinfo->mode)
|
||||
);
|
||||
|
||||
if (0)
|
||||
fprintf(stderr, "inclusive:%d\n",
|
||||
requests->inclusive
|
||||
);
|
||||
clicon_debug(1, "%s %s %s %d", __FUNCTION__,
|
||||
handler->handler_name,
|
||||
snmp_msg_int2str(reqinfo->mode),
|
||||
requests->inclusive);
|
||||
sh = (clixon_snmp_handle*)nhreg->my_reg_void;
|
||||
ys = sh->sh_ys;
|
||||
h = sh->sh_h;
|
||||
// fprint_objid(stderr, nhreg->rootoid, nhreg->rootoid_len);
|
||||
assert(sh->sh_oidlen == requestvb->name_length);
|
||||
assert(requestvb->name_length == nhreg->rootoid_len);
|
||||
assert(snmp_oid_compare(sh->sh_oid, sh->sh_oidlen,
|
||||
requestvb->name, requestvb->name_length) == 0);
|
||||
assert(snmp_oid_compare(requestvb->name, requestvb->name_length,
|
||||
nhreg->rootoid, nhreg->rootoid_len) == 0);
|
||||
|
||||
#if 0 /* If oid match fails */
|
||||
netsnmp_set_request_error(reqinfo, requests,
|
||||
SNMP_NOSUCHOBJECT);
|
||||
return SNMP_ERR_NOERROR;
|
||||
#endif
|
||||
|
||||
if (yang2snmp_types(ys, &asn1_type, &cvtype) < 0)
|
||||
goto done;
|
||||
|
||||
/* see net-snmp/agent/snmp_agent.h / net-snmp/library/snmp.h */
|
||||
switch (reqinfo->mode) {
|
||||
case MODE_GET: // 160
|
||||
requestvb->type = asn1_type; // ASN_NULL on input
|
||||
|
||||
/* get xpath: see yang2api_path_fmt / api_path2xpath
|
||||
New fn: yang2xpath?
|
||||
clicon_rpc_get()
|
||||
<rpc $DEFAULTNS><get><filter type=\"xpath\" select=\"/if:interfaces\" xmlns:if=\"urn:ietf:params:xml:ns:yang:ietf-interfaces\" /></get></rpc>"
|
||||
|
||||
*/
|
||||
|
||||
if (xml_nsctx_yang(ys, &nsc) < 0)
|
||||
goto done;
|
||||
if (yang2xpath(ys, &xpath) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
if ((xerr = xpath_first(xt, NULL, "/rpc-error")) != NULL){
|
||||
clixon_netconf_error(xerr, "clicon_rpc_get", NULL);
|
||||
goto done;
|
||||
}
|
||||
/* Get value, either from xml, or smiv2 default */
|
||||
if ((x = xpath_first(xt, nsc, "%s", xpath)) != NULL) {
|
||||
valstr = xml_body(x);
|
||||
}
|
||||
else if ((valstr = sh->sh_default) != NULL)
|
||||
;
|
||||
else{
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
|
||||
goto ok;
|
||||
}
|
||||
if ((ret = type_yang2snmp(valstr, cvtype, reqinfo, requests, &snmpval, &snmplen)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
|
||||
/* 1. use cligen object and get rwa buf / size from that, OR
|
||||
* + have parse function from YANG
|
||||
* - does not have
|
||||
* 2. use union netsnmp_vardata and pass that here?
|
||||
* 3. Make cv2asn1 conversion function <--
|
||||
*/
|
||||
|
||||
/* see snmplib/snmp_client.c */
|
||||
if (snmp_set_var_value(requestvb,
|
||||
snmpval,
|
||||
snmplen) != 0){
|
||||
clicon_err(OE_SNMP, 0, "snmp_set_var_value");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case MODE_GETNEXT: // 161
|
||||
assert(0); // Not seen?
|
||||
break;
|
||||
case MODE_SET_RESERVE1: // 0
|
||||
if (requestvb->type != asn1_type)
|
||||
netsnmp_set_request_error(reqinfo, requests,
|
||||
SNMP_ERR_WRONGTYPE);
|
||||
break;
|
||||
|
||||
case MODE_SET_RESERVE2: // 1
|
||||
break;
|
||||
|
||||
case MODE_SET_ACTION: // 2
|
||||
/*
|
||||
* update current
|
||||
*/
|
||||
/* yang2xpath -> xpath2xml
|
||||
* accesses = *(requestvb->val.integer);
|
||||
* rpc edit-config
|
||||
<data></data>
|
||||
*/
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
/*! XXX only int */
|
||||
cprintf(cb, "<config><NET-SNMP-EXAMPLES-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:NET-SNMP-EXAMPLES-MIB\"><netSnmpExampleScalars><netSnmpExampleInteger>%ld</netSnmpExampleInteger></netSnmpExampleScalars></NET-SNMP-EXAMPLES-MIB></config>", *requestvb->val.integer);
|
||||
if (clicon_rpc_edit_config(h, "candidate", OP_MERGE, cbuf_get(cb)) < 0)
|
||||
goto done;
|
||||
break;
|
||||
|
||||
case MODE_SET_UNDO: // 5
|
||||
if (clicon_rpc_discard_changes(h) < 0)
|
||||
goto done;
|
||||
break;
|
||||
|
||||
case MODE_SET_COMMIT: // 3
|
||||
if (clicon_rpc_commit(h) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case MODE_SET_FREE: // 4
|
||||
/*
|
||||
* nothing to do
|
||||
*/
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
retval = SNMP_ERR_NOERROR;
|
||||
done:
|
||||
if (snmpval)
|
||||
free(snmpval);
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
if (cv)
|
||||
cv_free(cv);
|
||||
return retval;
|
||||
}
|
||||
#endif
|
||||
|
||||
/*! Parse smiv2 extensions for YANG container/list
|
||||
*
|
||||
* Typical table:
|
||||
|
|
@ -457,7 +205,10 @@ mib_yang_leaf(clicon_handle h,
|
|||
}
|
||||
if (yang_extension_value(ys, "max-access", IETF_YANG_SMIV2_NS, NULL, &modes_str) < 0)
|
||||
goto done;
|
||||
|
||||
#if 0 /* Sanity check of types */
|
||||
if (yang2snmp_types(ys, NULL, NULL) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
/* Get modes (access) read-only, read-write, not-accessible, oaccessible-for-notify
|
||||
*/
|
||||
if (modes_str == NULL)
|
||||
|
|
@ -489,10 +240,8 @@ mib_yang_leaf(clicon_handle h,
|
|||
memcpy(sh->sh_oid, oid1, sizeof(oid1));
|
||||
sh->sh_oidlen = sz1;
|
||||
sh->sh_default = default_str;
|
||||
if ((nhreg = netsnmp_handler_registration_create(name,
|
||||
handler,
|
||||
oid1,
|
||||
sz1,
|
||||
if ((nhreg = netsnmp_handler_registration_create(name, handler,
|
||||
oid1, sz1,
|
||||
modes)) == NULL){
|
||||
clicon_err(OE_SNMP, errno, "netsnmp_handler_registration_create");
|
||||
netsnmp_handler_free(handler);
|
||||
|
|
@ -587,7 +336,7 @@ mib_traverse(clicon_handle h,
|
|||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_snmp_mib_yangs(clicon_handle h)
|
||||
clixon_snmp_traverse_mibyangs(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
char *modname;
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ extern "C" {
|
|||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int clixon_snmp_mib_yangs(clicon_handle h);
|
||||
int clixon_snmp_traverse_mibyangs(clicon_handle h);
|
||||
|
||||
#endif /* _SNMP_REGISTER_H_ */
|
||||
|
||||
|
|
|
|||
|
|
@ -386,6 +386,8 @@ yang2api_path_fmt_1(yang_stmt *ys,
|
|||
* @param[in] ys Yang statement
|
||||
* @param[in] inclkey If set include key leaf (eg last leaf d in ex)
|
||||
* @param[out] api_path_fmt XML api path. Needs to be freed after use.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
|
||||
*/
|
||||
int
|
||||
|
|
@ -902,7 +904,7 @@ api_path2xpath(char *api_path,
|
|||
* @param[in] nodeclass Set to schema nodes, data nodes, etc
|
||||
* @param[in] strict Break if api-path is not "complete" otherwise ignore and continue
|
||||
* @param[out] xbotp Resulting xml tree
|
||||
* @param[out] ybotp Yang spec matching xpathp
|
||||
* @param[out] ybotp Yang spec matching xpathp
|
||||
* @param[out] xerr Netconf error message (if retval=0)
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid api_path or associated XML, netconf error
|
||||
|
|
@ -1144,7 +1146,7 @@ api_path2xml_vec(char **vec,
|
|||
* @param[in,out] xtop Incoming XML tree
|
||||
* @param[in] nodeclass Set to schema nodes, data nodes, etc
|
||||
* @param[in] strict Break if api-path is not "complete" otherwise ignore and continue
|
||||
* @param[out] xbotp Resulting xml tree (end of xpath)
|
||||
* @param[out] xbotp Resulting xml tree (end of xpath) (optional)
|
||||
* @param[out] ybotp Yang spec matching xbotp
|
||||
* @param[out] xerr Netconf error message (if retval=0)
|
||||
* @retval 1 OK
|
||||
|
|
|
|||
|
|
@ -104,16 +104,17 @@ testinit
|
|||
|
||||
# NET-SNMP-EXAMPLES-MIB::netSnmpExamples
|
||||
MIB=".1.3.6.1.4.1.8072.2"
|
||||
OID="${MIB}.1.1" # netSnmpExampleInteger
|
||||
OID1="${MIB}.1.1" # netSnmpExampleInteger
|
||||
OID3="${MIB}.1.3" # netSnmpExampleString
|
||||
|
||||
new "Test SNMP get for default value"
|
||||
expectpart "$($snmpget $OID)" 0 "$OID = INTEGER: 42"
|
||||
expectpart "$($snmpget $OID1)" 0 "$OID1 = INTEGER: 42"
|
||||
|
||||
new "Set new value to OID"
|
||||
expectpart "$($snmpset $OID i 1234)" 0 "$OID = INTEGER: 1234"
|
||||
new "Set new value to OID1"
|
||||
expectpart "$($snmpset $OID1 i 1234)" 0 "$OID1 = INTEGER: 1234"
|
||||
|
||||
new "Get new value"
|
||||
expectpart "$($snmpget $OID)" 0 "$OID = INTEGER: 1234"
|
||||
expectpart "$($snmpget $OID1)" 0 "$OID1 = INTEGER: 1234"
|
||||
|
||||
new "Set new value via NETCONF"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><default-operation>none</default-operation><target><candidate/></target><config><NET-SNMP-EXAMPLES-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:NET-SNMP-EXAMPLES-MIB\"><netSnmpExampleScalars><netSnmpExampleInteger>999</netSnmpExampleInteger></netSnmpExampleScalars></NET-SNMP-EXAMPLES-MIB></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
|
@ -122,7 +123,16 @@ new "netconf commit"
|
|||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
|
||||
|
||||
new "Get new value"
|
||||
expectpart "$($snmpget $OID)" 0 "$OID = INTEGER: 999"
|
||||
expectpart "$($snmpget $OID1)" 0 "$OID1 = INTEGER: 999"
|
||||
|
||||
new "Test SNMP get string for default value"
|
||||
expectpart "$($snmpget $OID3)" 0 "$OID3 = STRING: So long, and thanks for all the fish!."
|
||||
|
||||
new "Set new string value to OID3"
|
||||
expectpart "$($snmpset $OID3 s foobar)" 0 "$OID3 = STRING: foobar"
|
||||
|
||||
new "Get new value"
|
||||
expectpart "$($snmpget $OID3)" 0 "$OID3 = STRING: foobar"
|
||||
|
||||
new "Cleaning up"
|
||||
testexit
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue