SNMP: Large refactorings and new dynamic table support
This commit is contained in:
parent
ebf251455f
commit
150ad3ab8b
4 changed files with 742 additions and 229 deletions
|
|
@ -71,50 +71,120 @@ snmp_common_handler(netsnmp_mib_handler *handler,
|
|||
{
|
||||
int retval = -1;
|
||||
netsnmp_variable_list *requestvb; /* sub of requests */
|
||||
char oidstr0[MAX_OID_LEN*2] = {0,};
|
||||
char oidstr1[MAX_OID_LEN*2] = {0,};
|
||||
char oidstr2[MAX_OID_LEN*2] = {0,};
|
||||
cbuf *cb;
|
||||
|
||||
if (requests == NULL || shp == NULL){
|
||||
clicon_err(OE_XML, EINVAL, "requests or shp is null");
|
||||
goto done;
|
||||
}
|
||||
requestvb = requests->requestvb;
|
||||
if (snprint_objid(oidstr0, sizeof(oidstr0),
|
||||
requestvb->name, requestvb->name_length) < 0){
|
||||
clicon_err(OE_XML, 0, "snprint_objid buffer too small");
|
||||
goto done;
|
||||
}
|
||||
if ((*shp = (clixon_snmp_handle*)handler->myvoid) == NULL){
|
||||
clicon_err(OE_XML, 0, "No myvoid handler");
|
||||
goto done;
|
||||
}
|
||||
if (snprint_objid(oidstr1, sizeof(oidstr1),
|
||||
nhreg->rootoid, nhreg->rootoid_len) < 0){
|
||||
clicon_err(OE_XML, 0, "snprint_objid buffer too small");
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (snprint_objid(oidstr2, sizeof(oidstr2),
|
||||
(*shp)->sh_oid, (*shp)->sh_oidlen) < 0){
|
||||
clicon_err(OE_XML, 0, "snprint_objid buffer too small");
|
||||
goto done;
|
||||
}
|
||||
if (strcmp(oidstr0, oidstr2) == 0)
|
||||
oid_cbuf(cb, (*shp)->sh_oid, (*shp)->sh_oidlen);
|
||||
if (oid_eq(requestvb->name, requestvb->name_length,
|
||||
(*shp)->sh_oid, (*shp)->sh_oidlen) == 0){ /* equal */
|
||||
clicon_debug(1, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__,
|
||||
oidstr2,
|
||||
cbuf_get(cb),
|
||||
snmp_msg_int2str(reqinfo->mode),
|
||||
requests->inclusive, tablehandler?"table":"scalar");
|
||||
else
|
||||
clicon_debug(1, "%s \"%s\"/\"%s\" %s inclusive:%d %s", __FUNCTION__,
|
||||
oidstr2, oidstr0,
|
||||
}
|
||||
else{ /* not equal */
|
||||
cprintf(cb, " (");
|
||||
oid_cbuf(cb, requestvb->name, requestvb->name_length);
|
||||
cprintf(cb, ")");
|
||||
// nhreg->rootoid same as shp
|
||||
clicon_debug(1, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__,
|
||||
cbuf_get(cb),
|
||||
snmp_msg_int2str(reqinfo->mode),
|
||||
requests->inclusive, tablehandler?"table":"scalar");
|
||||
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
#ifdef SNMP_TABLE_DYNAMIC
|
||||
/*!
|
||||
*/
|
||||
static int
|
||||
snmp_scalar_return(cxobj *xs,
|
||||
yang_stmt *ys,
|
||||
oid *oidc,
|
||||
size_t oidclen,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
int retval = -1;
|
||||
int asn1type;
|
||||
char *xmlstr = NULL;
|
||||
char *defaultval = NULL;
|
||||
u_char *snmpval = NULL;
|
||||
size_t snmplen = 0;
|
||||
char *reason = NULL;
|
||||
netsnmp_variable_list *requestvb = requests->requestvb;
|
||||
int ret;
|
||||
|
||||
/* SMI default value, How is this different from yang defaults?
|
||||
*/
|
||||
if (yang_extension_value(ys, "defval", IETF_YANG_SMIV2_NS, NULL, &defaultval) < 0)
|
||||
goto done;
|
||||
if (xs != NULL){
|
||||
if ((ret = type_xml2snmp_pre(xml_body(xs), ys, &xmlstr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGVALUE);
|
||||
goto ok;
|
||||
}
|
||||
}
|
||||
else if (defaultval != NULL){
|
||||
if ((xmlstr = strdup(defaultval)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else{
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
|
||||
goto ok;
|
||||
}
|
||||
if (type_yang2asn1(ys, &asn1type, 1) < 0)
|
||||
goto done;
|
||||
if ((ret = type_xml2snmp(xmlstr, &asn1type, &snmpval, &snmplen, &reason)) < 0)
|
||||
goto done;
|
||||
if (ret == 0){
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, reason);
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_WRONGTYPE);
|
||||
goto ok;
|
||||
}
|
||||
/* see snmplib/snmp_client. somewhat indirect
|
||||
*/
|
||||
if ((ret = snmp_set_var_typed_value(requestvb, asn1type, snmpval, snmplen)) != SNMPERR_SUCCESS){
|
||||
clicon_err(OE_SNMP, ret, "snmp_set_var_typed_value");
|
||||
goto done;
|
||||
}
|
||||
if ((ret = snmp_set_var_objid(requestvb, oidc, oidclen)) != SNMPERR_SUCCESS){
|
||||
clicon_err(OE_SNMP, ret, "snmp_set_var_objid");
|
||||
goto done;
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (xmlstr)
|
||||
free(xmlstr);
|
||||
if (snmpval)
|
||||
free(snmpval);
|
||||
if (reason)
|
||||
free(reason);
|
||||
return retval;
|
||||
}
|
||||
#endif /* SNMP_TABLE_DYNAMIC */
|
||||
|
||||
/*! Scalar handler, set a value to clixon
|
||||
* get xpath: see yang2api_path_fmt / api_path2xpath
|
||||
|
|
@ -125,12 +195,13 @@ snmp_common_handler(netsnmp_mib_handler *handler,
|
|||
* @param[in] defaultval
|
||||
* @param[in] reqinfo
|
||||
* @param[in] requests
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
snmp_scalar_get(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
cvec *cvk,
|
||||
netsnmp_variable_list *requestvb,
|
||||
char *defaultval,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
|
|
@ -147,13 +218,14 @@ snmp_scalar_get(clicon_handle h,
|
|||
int ret;
|
||||
int asn1type;
|
||||
char *reason = NULL;
|
||||
netsnmp_variable_list *requestvb = requests->requestvb;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
/* Prepare backend call by constructing namespace context */
|
||||
if (xml_nsctx_yang(ys, &nsc) < 0)
|
||||
goto done;
|
||||
/* Create xpath from yang (XXX works not for lists) */
|
||||
if (yang2xpath(ys, cvk, &xpath) < 0)
|
||||
if (snmp_yang2xpath(ys, cvk, &xpath) < 0)
|
||||
goto done;
|
||||
/* Do the backend call */
|
||||
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
|
|
@ -198,9 +270,8 @@ snmp_scalar_get(clicon_handle h,
|
|||
}
|
||||
/* see snmplib/snmp_client. somewhat indirect
|
||||
*/
|
||||
requestvb->type = asn1type; // ASN_NULL on input
|
||||
if ((ret = snmp_set_var_value(requestvb, snmpval, snmplen)) != SNMPERR_SUCCESS){
|
||||
clicon_err(OE_SNMP, ret, "snmp_set_var_value");
|
||||
if ((ret = snmp_set_var_typed_value(requestvb, asn1type, snmpval, snmplen)) != SNMPERR_SUCCESS){
|
||||
clicon_err(OE_SNMP, ret, "snmp_set_var_typed_value");
|
||||
goto done;
|
||||
}
|
||||
ok:
|
||||
|
|
@ -226,7 +297,6 @@ snmp_scalar_get(clicon_handle h,
|
|||
static int
|
||||
snmp_scalar_set(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
|
|
@ -239,6 +309,7 @@ snmp_scalar_set(clicon_handle h,
|
|||
int ret;
|
||||
char *valstr = NULL;
|
||||
cbuf *cb = NULL;
|
||||
netsnmp_variable_list *requestvb = requests->requestvb;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
|
|
@ -250,7 +321,6 @@ snmp_scalar_set(clicon_handle h,
|
|||
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;
|
||||
|
|
@ -309,7 +379,7 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
|
|||
switch (reqinfo->mode) {
|
||||
case MODE_GET: /* 160 */
|
||||
if (snmp_scalar_get(sh->sh_h, sh->sh_ys, sh->sh_cvk_orig,
|
||||
requestvb, sh->sh_default, reqinfo, requests) < 0)
|
||||
sh->sh_default, reqinfo, requests) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case MODE_GETNEXT: /* 161 */
|
||||
|
|
@ -328,7 +398,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, sh->sh_ys, requestvb, reqinfo, requests) < 0)
|
||||
if (snmp_scalar_set(sh->sh_h, sh->sh_ys, reqinfo, requests) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case MODE_SET_UNDO: /* 5 */
|
||||
|
|
@ -348,6 +418,227 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
|
|||
return retval;
|
||||
}
|
||||
|
||||
#ifdef SNMP_TABLE_DYNAMIC
|
||||
/*! Create xpath from YANG table OID + 1 + n + cvk/key = requestvb->name
|
||||
* Get yang of leaf from first part of OID
|
||||
* Create xpath with right keys from later part of OID
|
||||
* Query clixon if object exists, if so return value
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] yt Yang of table (of list type)
|
||||
* @param[in] oids OID of ultimate scalar value
|
||||
* @param[in] oidslen OID length of scalar
|
||||
* @param[in] reginfo
|
||||
* @param[in] requests
|
||||
* @retval -1 Error
|
||||
* @retval 0 Object not found
|
||||
* @retval 1 OK
|
||||
*/
|
||||
static int
|
||||
snmp_table_get(clicon_handle h,
|
||||
yang_stmt *yt,
|
||||
oid *oids,
|
||||
size_t oidslen,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
int retval = -1;
|
||||
oid oidt[MAX_OID_LEN] = {0,}; /* Table / list oid */
|
||||
size_t oidtlen = MAX_OID_LEN;
|
||||
oid oidleaf[MAX_OID_LEN] = {0,}; /* Leaf */
|
||||
size_t oidleaflen = MAX_OID_LEN;
|
||||
oid *oidi;
|
||||
size_t oidilen;
|
||||
yang_stmt *ys;
|
||||
yang_stmt *yk;
|
||||
char *xpath = NULL;
|
||||
cvec *cvk_orig;
|
||||
cvec *cvk_val;
|
||||
int i;
|
||||
cg_var *cv;
|
||||
char *defaultval = NULL;
|
||||
int ret;
|
||||
|
||||
/* Get OID from table /list */
|
||||
if ((ret = yangext_oid_get(yt, oidt, &oidtlen, NULL)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto done;
|
||||
/* Get yang of leaf from first part of OID */
|
||||
ys = NULL;
|
||||
while ((ys = yn_each(yt, ys)) != NULL) {
|
||||
if (yang_keyword_get(ys) != Y_LEAF)
|
||||
continue;
|
||||
if ((ret = yangext_oid_get(ys, oidleaf, &oidleaflen, NULL)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto done;
|
||||
assert(oidtlen + 1 == oidleaflen);
|
||||
if (oids[oidleaflen-1] == oidleaf[oidleaflen-1])
|
||||
break;
|
||||
}
|
||||
if (ys == NULL){
|
||||
/* No leaf with matching OID */
|
||||
goto fail;
|
||||
}
|
||||
/* SMI default value, How is this different from yang defaults?
|
||||
*/
|
||||
if (yang_extension_value(ys, "defval", IETF_YANG_SMIV2_NS, NULL, &defaultval) < 0)
|
||||
goto done;
|
||||
|
||||
/* Create xpath with right keys from later part of OID
|
||||
* Inverse of snmp_str2oid
|
||||
*/
|
||||
if ((cvk_orig = yang_cvec_get(yt)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "No keys");
|
||||
goto done;
|
||||
}
|
||||
if ((cvk_val = cvec_dup(cvk_orig)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
oidilen = oidslen-(oidtlen+1);
|
||||
oidi = oids+oidtlen+1;
|
||||
/* Add keys */
|
||||
for (i=0; i<cvec_len(cvk_val); i++){
|
||||
cv = cvec_i(cvk_val, i);
|
||||
if ((yk = yang_find(yt, Y_LEAF, cv_string_get(cv))) == NULL){
|
||||
clicon_err(OE_YANG, 0, "List key %s not found", cv_string_get(cv));
|
||||
goto done;
|
||||
}
|
||||
if (snmp_oid2str(&oidi, &oidilen, yk, cv) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (oidilen != 0){
|
||||
clicon_err(OE_YANG, 0, "Expected oidlen 0 but is %zu", oidilen);
|
||||
goto fail;
|
||||
}
|
||||
/* Get scalar value */
|
||||
if (snmp_scalar_get(h, ys, cvk_val,
|
||||
defaultval,
|
||||
reqinfo,
|
||||
requests) < 0)
|
||||
goto done;
|
||||
// ok:
|
||||
retval = 1;
|
||||
done:
|
||||
if (cvk_val)
|
||||
cvec_free(cvk_val);
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Find "next" objct from oids minus key and return that.
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ylist Yang of table (of list type)
|
||||
* @param[in] oids OID of ultimate scalar value
|
||||
* @param[in] oidslen OID length of scalar
|
||||
* @retval -1 Error
|
||||
* @retval 0 OK
|
||||
*/
|
||||
static int
|
||||
snmp_table_getnext(clicon_handle h,
|
||||
yang_stmt *ylist,
|
||||
oid *oids,
|
||||
size_t oidslen,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *nsc = NULL;
|
||||
char *xpath = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xerr;
|
||||
cxobj *xtable;
|
||||
cxobj *xrow;
|
||||
cxobj *xcol;
|
||||
yang_stmt *ycol;
|
||||
yang_stmt *ys;
|
||||
int ret;
|
||||
cvec *cvk_name;
|
||||
oid oidc[MAX_OID_LEN] = {0,}; /* Table / list oid */
|
||||
size_t oidclen = MAX_OID_LEN;
|
||||
oid oidk[MAX_OID_LEN] = {0,}; /* Key oid */
|
||||
size_t oidklen = MAX_OID_LEN;
|
||||
int getnext = 0;
|
||||
int found = 0;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((ys = yang_parent_get(ylist)) == NULL ||
|
||||
yang_keyword_get(ys) != Y_CONTAINER){
|
||||
clicon_err(OE_YANG, EINVAL, "ylist parent is not list");
|
||||
goto done;
|
||||
}
|
||||
if (xml_nsctx_yang(ys, &nsc) < 0)
|
||||
goto done;
|
||||
if (snmp_yang2xpath(ys, NULL, &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;
|
||||
}
|
||||
if ((xtable = xpath_first(xt, nsc, "%s", xpath)) != NULL) {
|
||||
/* Make a clone of key-list, but replace names with values */
|
||||
if ((cvk_name = yang_cvec_get(ylist)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "No keys");
|
||||
goto done;
|
||||
}
|
||||
xrow = NULL;
|
||||
while ((xrow = xml_child_each(xtable, xrow, CX_ELMNT)) != NULL) {
|
||||
/* Get key part of OID from XML list entry */
|
||||
if ((ret = snmp_xmlkey2val_oid(xrow, cvk_name, NULL, /*&cvk_oid,*/ oidk, &oidklen)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
continue; /* skip row, not all indexes */
|
||||
xcol = NULL;
|
||||
while ((xcol = xml_child_each(xrow, xcol, CX_ELMNT)) != NULL) {
|
||||
if ((ycol = xml_spec(xcol)) == NULL)
|
||||
continue;
|
||||
if (yang_keyword_get(ycol) != Y_LEAF)
|
||||
continue;
|
||||
if ((ret = yangext_oid_get(ycol, oidc, &oidclen, NULL)) < 0)
|
||||
goto done;
|
||||
/* Append key oid */
|
||||
if (oid_append(oidc, &oidclen, oidk, oidklen) < 0)
|
||||
goto done;
|
||||
if (getnext){
|
||||
found++; /* return this */
|
||||
break;
|
||||
}
|
||||
/* Match oidc - key */
|
||||
if ((ret = oid_eq(oidc, oidclen, oids, oidslen)) == 0){
|
||||
getnext++; /* return next object if any */
|
||||
}
|
||||
else if (ret > 0){
|
||||
found++; /* return this */
|
||||
break;
|
||||
}
|
||||
} /* while xcol */
|
||||
if (found)
|
||||
break;
|
||||
} /* while xrow */
|
||||
}
|
||||
if (found){
|
||||
if (snmp_scalar_return(xcol, ycol, oidc, oidclen, reqinfo, requests) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
return retval;
|
||||
}
|
||||
#endif /* SNMP_TABLE_DYNAMIC */
|
||||
|
||||
/*! 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
|
||||
|
|
@ -374,6 +665,9 @@ clixon_snmp_table_handler(netsnmp_mib_handler *handler,
|
|||
cxobj *xt = NULL;
|
||||
cbuf *cb = NULL;
|
||||
int ret;
|
||||
#ifdef SNMP_TABLE_DYNAMIC
|
||||
netsnmp_variable_list *requestvb;
|
||||
#endif
|
||||
|
||||
clicon_debug(2, "%s", __FUNCTION__);
|
||||
if ((ret = snmp_common_handler(handler, nhreg, reqinfo, requests, &sh, 1)) < 0)
|
||||
|
|
@ -382,30 +676,28 @@ clixon_snmp_table_handler(netsnmp_mib_handler *handler,
|
|||
clicon_debug(1, "%s Error table not registered", __FUNCTION__);
|
||||
goto ok;
|
||||
}
|
||||
#ifdef SNMP_TABLE_DYNAMIC
|
||||
requestvb = requests->requestvb;
|
||||
#endif
|
||||
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)
|
||||
/* Create xpath from YANG table OID + 1 + n + cvk/key = requestvb->name
|
||||
*/
|
||||
if ((ret = snmp_table_get(sh->sh_h, sh->sh_ys,
|
||||
requestvb->name, requestvb->name_length,
|
||||
reqinfo, requests)) < 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;
|
||||
}
|
||||
}
|
||||
if (ret == 0)
|
||||
netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
|
||||
#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)
|
||||
if (snmp_table_getnext(sh->sh_h, sh->sh_ys,
|
||||
requestvb->name, requestvb->name_length,
|
||||
reqinfo, requests) < 0)
|
||||
goto done;
|
||||
#endif
|
||||
break;
|
||||
|
|
|
|||
|
|
@ -156,7 +156,16 @@ snmp_msg_int2str(int msg)
|
|||
{
|
||||
return clicon_int2str(snmp_msg_map, msg);
|
||||
}
|
||||
/*! Should be netsnmp lib function, cant find it
|
||||
|
||||
/*! Check equality of two OIDs
|
||||
*
|
||||
* @param[in] objid0 First OID vector
|
||||
* @param[in] objid0len Length of first OID vector
|
||||
* @param[in] objid1 Second OID vector
|
||||
* @param[in] objid1len Length of second OID vector
|
||||
* @retval 0 Equal
|
||||
* @retval !=0 Not equal, see man memcmp
|
||||
* (Should be netsnmp lib function, cant find it)
|
||||
*/
|
||||
int
|
||||
oid_eq(const oid *objid0,
|
||||
|
|
@ -164,11 +173,185 @@ oid_eq(const oid *objid0,
|
|||
const oid *objid1,
|
||||
size_t objid1len)
|
||||
{
|
||||
if (objid0len != objid1len)
|
||||
return 0;
|
||||
if (objid0len < objid1len)
|
||||
return -1;
|
||||
else if (objid0len > objid1len)
|
||||
return 1;
|
||||
else
|
||||
return memcmp(objid0, objid1, objid0len*sizeof(*objid0));
|
||||
}
|
||||
|
||||
/*! Append a second OID to a first
|
||||
* @param[in,out] objid0 First OID vector
|
||||
* @param[in,out] objid0len Length of first OID vector
|
||||
* @param[in] objid1 Second OID vector
|
||||
* @param[in] objid1len Length of second OID vector
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* Assume objid0 is allocated with MAX_OID_LEN > oid0len+oid1len
|
||||
*/
|
||||
int
|
||||
oid_append(const oid *objid0,
|
||||
size_t *objid0len,
|
||||
const oid *objid1,
|
||||
size_t objid1len)
|
||||
{
|
||||
void *dst;
|
||||
|
||||
dst = (void*)objid0;
|
||||
dst += (*objid0len)*sizeof(*objid0);
|
||||
if (memcpy(dst, objid1, objid1len*sizeof(*objid0)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "memcpy");
|
||||
return -1;
|
||||
}
|
||||
*objid0len += objid1len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Print objid to file
|
||||
* @see fprint_objid but prints symbolic
|
||||
*/
|
||||
int
|
||||
oid_cbuf(cbuf *cb,
|
||||
const oid *objid,
|
||||
size_t objidlen)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i=0; i<objidlen; i++)
|
||||
cprintf(cb, ".%lu", objid[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
oid_print(FILE *f,
|
||||
const oid *objid,
|
||||
size_t objidlen)
|
||||
{
|
||||
int retval = -1;
|
||||
cbuf *cb;
|
||||
|
||||
if ((cb = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
oid_cbuf(cb, objid, objidlen);
|
||||
fprintf(stderr, "%s", cbuf_get(cb));
|
||||
fprintf(stderr, "\n");
|
||||
retval = 0;
|
||||
done:
|
||||
if (cb)
|
||||
cbuf_free(cb);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Variant of yang_type_get that follows leafrefs
|
||||
*/
|
||||
static int
|
||||
snmp_yang_type_get(yang_stmt *ys,
|
||||
yang_stmt **yrefp,
|
||||
char **origtypep,
|
||||
yang_stmt **yrestypep,
|
||||
char **restypep)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yrestype; /* resolved type */
|
||||
char *restype; /* resolved type */
|
||||
char *origtype = NULL; /* original type */
|
||||
yang_stmt *ypath;
|
||||
yang_stmt *yref = NULL;
|
||||
|
||||
/* 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 (strcmp(restype, "leafref")==0){
|
||||
if ((ypath = yang_find(yrestype, Y_PATH, NULL)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "No path in leafref");
|
||||
goto done;
|
||||
}
|
||||
if (yang_path_arg(ys, yang_argument_get(ypath), &yref) < 0)
|
||||
goto done;
|
||||
if (yref == NULL){
|
||||
clicon_err(OE_YANG, 0, "No referred YANG node found for leafref path %s", yang_argument_get(ypath));
|
||||
goto done;
|
||||
}
|
||||
if (origtype){
|
||||
free(origtype);
|
||||
origtype = NULL;
|
||||
}
|
||||
if (yang_type_get(yref, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
goto done;
|
||||
restype = yrestype?yang_argument_get(yrestype):NULL;
|
||||
}
|
||||
if (yrefp){
|
||||
if (yref)
|
||||
*yrefp = yref;
|
||||
else
|
||||
*yrefp = ys;
|
||||
}
|
||||
if (origtypep){
|
||||
*origtypep = origtype;
|
||||
origtype = NULL;
|
||||
}
|
||||
if (yrestypep)
|
||||
*yrestypep = yrestype;
|
||||
if (restypep)
|
||||
*restypep = restype;
|
||||
retval = 0;
|
||||
done:
|
||||
if (origtype)
|
||||
free(origtype);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Given a YANG node, return SMIv2 oid extension as OID
|
||||
* @param[in] yn Yang node
|
||||
* @param[out] objid OID vector, assume allocated with MAX_OID_LEN > oidlen
|
||||
* @param[out] objidlen Length of OID vector on return
|
||||
* @param[out] objidstrp Pointer to string (direct not malloced) optional
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid, not found
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
yangext_oid_get(yang_stmt *yn,
|
||||
oid *objid,
|
||||
size_t *objidlen,
|
||||
char **objidstrp)
|
||||
{
|
||||
int retval = -1;
|
||||
int exist = 0;
|
||||
char *oidstr = NULL;
|
||||
yang_stmt *yref = NULL;
|
||||
|
||||
if (yang_keyword_get(yn) == Y_LEAF){
|
||||
if (snmp_yang_type_get(yn, &yref, NULL, NULL, NULL) < 0)
|
||||
goto done;
|
||||
}
|
||||
else
|
||||
yref = yn;
|
||||
/* Get OID from table /list */
|
||||
if (yang_extension_value(yref, "oid", IETF_YANG_SMIV2_NS, &exist, &oidstr) < 0)
|
||||
goto done;
|
||||
if (exist == 0 || oidstr == NULL){
|
||||
clicon_debug(1, "OID not found as SMIv2 yang extension of %s", yang_argument_get(yref));
|
||||
goto fail;
|
||||
}
|
||||
if (snmp_parse_oid(oidstr, objid, objidlen) == NULL){
|
||||
clicon_err(OE_XML, errno, "snmp_parse_oid");
|
||||
goto done;
|
||||
}
|
||||
if (objidstrp)
|
||||
*objidstrp = oidstr;
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Duplicate clixon snmp handler struct
|
||||
* Use signature of libnetsnmp data_clone field of netsnmp_mib_handler in agent_handler.h
|
||||
* @param[in] arg
|
||||
|
|
@ -191,11 +374,6 @@ snmp_handle_clone(void *arg)
|
|||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
return NULL;
|
||||
}
|
||||
if (sh0->sh_cvk_oid &&
|
||||
(sh1->sh_cvk_oid = cvec_dup(sh0->sh_cvk_oid)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
return NULL;
|
||||
}
|
||||
return (void*)sh1;
|
||||
}
|
||||
|
||||
|
|
@ -211,8 +389,6 @@ snmp_handle_free(void *arg)
|
|||
if (sh != NULL){
|
||||
if (sh->sh_cvk_orig)
|
||||
cvec_free(sh->sh_cvk_orig);
|
||||
if (sh->sh_cvk_oid)
|
||||
cvec_free(sh->sh_cvk_oid);
|
||||
if (sh->sh_table_info){
|
||||
if (sh->sh_table_info->indexes){
|
||||
snmp_free_varbind(sh->sh_table_info->indexes);
|
||||
|
|
@ -240,33 +416,13 @@ type_yang2asn1(yang_stmt *ys,
|
|||
int extended)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yrestype; /* resolved type */
|
||||
char *restype; /* resolved type */
|
||||
char *origtype = NULL; /* original type */
|
||||
int at;
|
||||
yang_stmt *ypath;
|
||||
yang_stmt *yref;
|
||||
|
||||
/* Get yang type of leaf and trasnslate to ASN.1 */
|
||||
if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
/* Get yang type of leaf and translate to ASN.1 */
|
||||
if (snmp_yang_type_get(ys, NULL, &origtype, NULL, &restype) < 0)
|
||||
goto done;
|
||||
restype = yrestype?yang_argument_get(yrestype):NULL;
|
||||
/* Special case: leafref, find original type */
|
||||
if (strcmp(restype, "leafref")==0){
|
||||
if ((ypath = yang_find(yrestype, Y_PATH, NULL)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "No path in leafref");
|
||||
goto done;
|
||||
}
|
||||
if (yang_path_arg(ys, yang_argument_get(ypath), &yref) < 0)
|
||||
goto done;
|
||||
if (origtype){
|
||||
free(origtype);
|
||||
origtype = NULL;
|
||||
}
|
||||
if (yang_type_get(yref, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
goto done;
|
||||
restype = yrestype?yang_argument_get(yrestype):NULL;
|
||||
}
|
||||
/* Translate to asn.1
|
||||
* First try original type, first type
|
||||
*/
|
||||
|
|
@ -312,9 +468,8 @@ type_snmp2xml(yang_stmt *ys,
|
|||
char *cvstr;
|
||||
enum cv_type cvtype;
|
||||
cg_var *cv = NULL;
|
||||
yang_stmt *yrestype; /* resolved type */
|
||||
char *restype; /* resolved type */
|
||||
char *origtype = NULL; /* original type */
|
||||
char *restype = NULL; /* resolved type */
|
||||
yang_stmt *yrestype = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (valstr == NULL){
|
||||
|
|
@ -323,9 +478,8 @@ type_snmp2xml(yang_stmt *ys,
|
|||
}
|
||||
cvstr = (char*)clicon_int2str(snmp_type_map, requestvb->type);
|
||||
/* Get yang type of leaf and trasnslate to ASN.1 */
|
||||
if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
if (snmp_yang_type_get(ys, NULL, NULL, &yrestype, &restype) < 0)
|
||||
goto done;
|
||||
restype = yrestype?yang_argument_get(yrestype):NULL;
|
||||
/* special case for enum */
|
||||
if (strcmp(cvstr, "int32")==0 && strcmp(restype, "enumeration") == 0)
|
||||
cvstr = "string";
|
||||
|
|
@ -399,8 +553,6 @@ type_snmp2xml(yang_stmt *ys,
|
|||
clicon_debug(2, "%s %d", __FUNCTION__, retval);
|
||||
if (cv)
|
||||
cv_free(cv);
|
||||
if (origtype)
|
||||
free(origtype);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
|
|
@ -427,8 +579,7 @@ type_xml2snmp_pre(char *xmlstr0,
|
|||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yrestype; /* resolved type */
|
||||
char *restype; /* resolved type */
|
||||
char *origtype = NULL; /* original type */
|
||||
char *restype = NULL; /* resolved type */
|
||||
char *str = NULL;
|
||||
int ret;
|
||||
|
||||
|
|
@ -437,9 +588,8 @@ type_xml2snmp_pre(char *xmlstr0,
|
|||
goto done;
|
||||
}
|
||||
/* Get yang type of leaf and trasnslate to ASN.1 */
|
||||
if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0)
|
||||
if (snmp_yang_type_get(ys, NULL, NULL, &yrestype, &restype) < 0) // XXX yrestype
|
||||
goto done;
|
||||
restype = yrestype?yang_argument_get(yrestype):NULL;
|
||||
if (strcmp(restype, "enumeration") == 0){ /* special case for enum */
|
||||
if ((ret = yang_enum2valstr(yrestype, xmlstr0, &str)) < 0)
|
||||
goto done;
|
||||
|
|
@ -469,8 +619,6 @@ type_xml2snmp_pre(char *xmlstr0,
|
|||
retval = 1;
|
||||
done:
|
||||
clicon_debug(2, "%s %d", __FUNCTION__, retval);
|
||||
if (origtype)
|
||||
free(origtype);
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
|
|
@ -609,14 +757,14 @@ type_xml2snmp(char *snmpstr,
|
|||
/*! Construct an xpath from yang statement, internal fn using cb
|
||||
* Recursively construct it to the top.
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] keyvec Array of [name,val]s as a cvec of key name and values
|
||||
* @param[in] keyvec Cvec of key values
|
||||
* @param[out] cb xpath as cbuf
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @see yang2xpath
|
||||
*/
|
||||
static int
|
||||
yang2xpath_cb(yang_stmt *ys,
|
||||
snmp_yang2xpath_cb(yang_stmt *ys,
|
||||
cvec *keyvec,
|
||||
cbuf *cb)
|
||||
{
|
||||
|
|
@ -633,7 +781,7 @@ yang2xpath_cb(yang_stmt *ys,
|
|||
if (yp != NULL && /* XXX rm */
|
||||
yang_keyword_get(yp) != Y_MODULE &&
|
||||
yang_keyword_get(yp) != Y_SUBMODULE){
|
||||
if (yang2xpath_cb(yp, keyvec, cb) < 0) /* recursive call */
|
||||
if (snmp_yang2xpath_cb(yp, keyvec, cb) < 0) /* recursive call */
|
||||
goto done;
|
||||
if (yang_keyword_get(yp) != Y_CHOICE && yang_keyword_get(yp) != Y_CASE){
|
||||
cprintf(cb, "/");
|
||||
|
|
@ -670,10 +818,10 @@ yang2xpath_cb(yang_stmt *ys,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Construct an xpath from yang statement
|
||||
/*! Construct an xpath from yang statement, limited to SNMP table translations
|
||||
* Recursively construct it to the top.
|
||||
* @param[in] ys Yang statement
|
||||
* @param[in] keyvec Array of [name,val]s as a cvec of key name and values
|
||||
* @param[in] keyvec Cvec of key values
|
||||
* @param[out] xpath Malloced xpath string, use free() after use
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
@ -682,7 +830,7 @@ yang2xpath_cb(yang_stmt *ys,
|
|||
* 2. It is far from complete so maybe keep it here as a special case
|
||||
*/
|
||||
int
|
||||
yang2xpath(yang_stmt *ys,
|
||||
snmp_yang2xpath(yang_stmt *ys,
|
||||
cvec *keyvec,
|
||||
char **xpath)
|
||||
{
|
||||
|
|
@ -693,7 +841,7 @@ yang2xpath(yang_stmt *ys,
|
|||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if (yang2xpath_cb(ys, keyvec, cb) < 0)
|
||||
if (snmp_yang2xpath_cb(ys, keyvec, cb) < 0)
|
||||
goto done;
|
||||
if (xpath && (*xpath = strdup(cbuf_get(cb))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "strdup");
|
||||
|
|
@ -706,27 +854,27 @@ yang2xpath(yang_stmt *ys,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Translate from xml body to OID
|
||||
/*! Translate from xml body string to SMI OID representation
|
||||
* For ints this is one to one, eg 42 -> 42
|
||||
* But for eg strings this is more comples, eg foo -> 3.6.22.22 (or something,...)
|
||||
* But for eg strings this is more complex, eg foo -> 3.6.22.22 (or something,...)
|
||||
* @param[in] str XML body string
|
||||
* @param[in] yi Yang statement
|
||||
* @param[out] objid OID vector
|
||||
* @param[out] objidlen Length of OID vector
|
||||
*/
|
||||
int
|
||||
snmp_body2oid(cxobj *xi,
|
||||
cg_var *cv)
|
||||
snmp_str2oid(char *str,
|
||||
yang_stmt *yi,
|
||||
oid *objid,
|
||||
size_t *objidlen)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yi;
|
||||
int asn1_type;
|
||||
char *body;
|
||||
size_t len;
|
||||
cbuf *enc = NULL;
|
||||
int i;
|
||||
int j = 0;
|
||||
|
||||
if ((yi = xml_spec(xi)) == NULL)
|
||||
goto ok;
|
||||
if (type_yang2asn1(yi, &asn1_type, 0) < 0)
|
||||
goto done;
|
||||
body = xml_body(xi);
|
||||
switch (asn1_type){
|
||||
case ASN_INTEGER:
|
||||
case ASN_GAUGE:
|
||||
|
|
@ -734,30 +882,76 @@ snmp_body2oid(cxobj *xi,
|
|||
case ASN_COUNTER64:
|
||||
case ASN_COUNTER:
|
||||
case ASN_IPADDRESS:
|
||||
if (cv_string_set(cv, body) < 0){
|
||||
clicon_err(OE_UNIX, errno, "cv_string_set");
|
||||
goto done;
|
||||
}
|
||||
objid[j++] = atoi(str);
|
||||
break;
|
||||
case ASN_OCTET_STR:{ /* encode to N.c.c.c.c */
|
||||
if ((enc = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
len = strlen(body);
|
||||
cprintf(enc, "%zu", len);
|
||||
for (i=0; i<len; i++)
|
||||
cprintf(enc, ".%u", body[i]&0xff);
|
||||
if (cv_string_set(cv, cbuf_get(enc)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "cv_string_set");
|
||||
goto done;
|
||||
}
|
||||
objid[j++] = strlen(str);
|
||||
for (i=0; i<strlen(str); i++)
|
||||
objid[j++] = str[i]&0xff;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
ok:
|
||||
*objidlen = j;
|
||||
// ok:
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Translate from SMI OID representation to name
|
||||
* For ints this is one to one, eg 42 -> 42
|
||||
* But for eg strings this is more comples, eg foo -> 3.6.22.22 (or something,...)
|
||||
* @param[in,out] oidi ObjID vector
|
||||
* @param[in,out] oidilen Length of ObjID vector
|
||||
* @param[in] yk Yang statement of key
|
||||
* @param[out] cv CLIgen variable string notation as "x.y.z"
|
||||
*/
|
||||
int
|
||||
snmp_oid2str(oid **oidi,
|
||||
size_t *oidilen,
|
||||
yang_stmt *yk,
|
||||
cg_var *cv)
|
||||
{
|
||||
int retval = -1;
|
||||
int asn1_type;
|
||||
int i = 0;
|
||||
cbuf *enc = NULL;
|
||||
size_t len;
|
||||
|
||||
if (type_yang2asn1(yk, &asn1_type, 0) < 0)
|
||||
goto done;
|
||||
if ((enc = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
switch (asn1_type){
|
||||
case ASN_INTEGER:
|
||||
case ASN_GAUGE:
|
||||
case ASN_TIMETICKS:
|
||||
case ASN_COUNTER64:
|
||||
case ASN_COUNTER:
|
||||
case ASN_IPADDRESS:
|
||||
cprintf(enc, "%lu", (*oidi)[i++]);
|
||||
if (cv_string_set(cv, cbuf_get(enc)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "cv_string_set");
|
||||
goto done;
|
||||
}
|
||||
break;
|
||||
case ASN_OCTET_STR: /* decode from N.c.c.c.c */
|
||||
len = (*oidi)[i++];
|
||||
for (; i<len; i++){
|
||||
cprintf(enc, "%c", (char)((*oidi)[i]&0xff));
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
if (i){
|
||||
(*oidi) += i;
|
||||
(*oidilen) -= i;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (enc)
|
||||
|
|
@ -812,6 +1006,79 @@ clixon_snmp_err_cb(void *handle,
|
|||
return 0;
|
||||
}
|
||||
|
||||
/*! Given a XML list entry, return value and OID vector
|
||||
*
|
||||
* Given an XML list/table entry x with keys [i,j], such as:
|
||||
* <x><i>1</i><j>a</j>...</x>
|
||||
* where i and j are list keys (table indexes)
|
||||
* Return two vectors:
|
||||
* - cvk_val: A vector of key values: [1,a]
|
||||
* - cvk_oid: A vector of OIDs: [1, 1.97]
|
||||
*
|
||||
* @param[in] xentry XML list entry
|
||||
* @param[in] cvk_name Vector of list keys
|
||||
* @param[out] cvk_val Vector of XML key values
|
||||
* @param[out] objidk OID key part, to be appended to node OID
|
||||
* @retval -1 Error
|
||||
* @retval 0 Invalid (not all indexes present)
|
||||
* @retval 1 OK
|
||||
* Both cvk_val and cvk_oid can be re-used in successive calls but need to be freed w cvec_free after use
|
||||
*/
|
||||
int
|
||||
snmp_xmlkey2val_oid(cxobj *xentry,
|
||||
cvec *cvk_name,
|
||||
cvec **cvk_val,
|
||||
oid *objidk,
|
||||
size_t *objidklen)
|
||||
{
|
||||
int retval = -1;
|
||||
cxobj *xi;
|
||||
int i;
|
||||
cg_var *cv;
|
||||
cg_var *cv0;
|
||||
oid objid[MAX_OID_LEN] = {0,};
|
||||
size_t objidlen = MAX_OID_LEN;
|
||||
|
||||
*objidklen = 0;
|
||||
if (cvk_val){
|
||||
if (*cvk_val){
|
||||
cvec_free(*cvk_val);
|
||||
if ((*cvk_val = cvec_dup(cvk_name)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
else if ((*cvk_val = cvec_dup(cvk_name)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
for (i=0; i<cvec_len(cvk_name); i++){
|
||||
cv0 = cvec_i(cvk_name, i);
|
||||
if ((xi = xml_find_type(xentry, NULL, cv_string_get(cv0), CX_ELMNT)) == NULL)
|
||||
break;
|
||||
if (cvk_val){
|
||||
cv = cvec_i(*cvk_val, i);
|
||||
if (cv_string_set(cv, xml_body(xi)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "cv_string_set");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
if (snmp_str2oid(xml_body(xi), xml_spec(xi), objid, &objidlen) < 0)
|
||||
goto done;
|
||||
if (oid_append(objidk, objidklen, objid, objidlen) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (i < cvec_len(cvk_name))
|
||||
goto fail; /* skip row, not all indexes */
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*========== libnetsnmp-specific code ===============
|
||||
* Peeks into internal lib global variables, may be sensitive to library change
|
||||
*/
|
||||
|
|
@ -859,8 +1126,7 @@ clixon_snmp_api_oid_find(oid *oid0,
|
|||
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__);
|
||||
oid_eq(oid0, oid0len, tree1->name_a, tree1->namelen)==0){
|
||||
retval = 1;
|
||||
}
|
||||
else
|
||||
|
|
@ -868,3 +1134,4 @@ clixon_snmp_api_oid_find(oid *oid0,
|
|||
// done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,8 @@ extern "C" {
|
|||
/* Need some way to multiplex SNMP_ and MIB errors on OE_SNMP error handler */
|
||||
#define CLIXON_ERR_SNMP_MIB 0x1000
|
||||
|
||||
#define IETF_YANG_SMIV2_NS "urn:ietf:params:xml:ns:yang:ietf-yang-smiv2"
|
||||
|
||||
/*
|
||||
* Types
|
||||
*/
|
||||
|
|
@ -58,17 +60,21 @@ struct clixon_snmp_handle {
|
|||
oid sh_oid[MAX_OID_LEN]; /* OID for debug, may be removed? */
|
||||
size_t sh_oidlen;
|
||||
char *sh_default; /* MIB default value leaf only */
|
||||
cvec *sh_cvk_orig; /* Index/Key variables (original) */
|
||||
cvec *sh_cvk_oid; /* Index/Key variables (OID translated) */
|
||||
netsnmp_table_registration_info *sh_table_info; /* To mimic table-handler in libnetsnmp code*/
|
||||
cvec *sh_cvk_orig; /* Index/Key variable values (original) */
|
||||
netsnmp_table_registration_info *sh_table_info; /* To mimic table-handler in libnetsnmp code
|
||||
* save only to free properly */
|
||||
|
||||
};
|
||||
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 oid_append(const oid *objid0, size_t *objid0len, const oid *objid1, size_t objid1len);
|
||||
int oid_cbuf(cbuf *cb, const oid *objid, size_t objidlen);
|
||||
int oid_print(FILE *f, const oid *objid, size_t objidlen);
|
||||
int yangext_oid_get(yang_stmt *yn, oid *objid, size_t *objidlen, char **objidstr);
|
||||
int snmp_access_str2int(char *modes_str);
|
||||
const char *snmp_msg_int2str(int msg);
|
||||
void *snmp_handle_clone(void *arg);
|
||||
|
|
@ -81,9 +87,11 @@ int type_snmp2xml(yang_stmt *ys,
|
|||
char **valstr);
|
||||
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_yang2xpath(yang_stmt *ys, cvec *keyvec, char **xpath);
|
||||
int snmp_str2oid(char *str, yang_stmt *yi, oid *objid, size_t *objidlen);
|
||||
int snmp_oid2str(oid **oidi, size_t *oidilen, yang_stmt *yi, cg_var *cv);
|
||||
int clixon_snmp_err_cb(void *handle, int suberr, cbuf *cb);
|
||||
int snmp_xmlkey2val_oid(cxobj *xrow, cvec *cvk_name, cvec **cvk_orig, oid *objidk, size_t *objidklen);
|
||||
|
||||
/*========== libnetsnmp-specific code =============== */
|
||||
int clixon_snmp_api_agent_check(void);
|
||||
|
|
|
|||
|
|
@ -80,9 +80,6 @@
|
|||
#include "snmp_register.h"
|
||||
#include "snmp_handler.h"
|
||||
|
||||
#define IETF_YANG_SMIV2_NS "urn:ietf:params:xml:ns:yang:ietf-yang-smiv2"
|
||||
|
||||
|
||||
/*! Parse smiv2 extensions for YANG leaf
|
||||
* Typical leaf:
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2.1.1";
|
||||
|
|
@ -91,8 +88,8 @@
|
|||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Mib-Yang node
|
||||
* @param[in] cvk_orig Vector of untranslated key/index values (eg "foo")
|
||||
* @param[in] cvk_oid Vector of translated to OID key/index values. (eg "3.6.22.22")
|
||||
|
||||
* @param[in] oidk Part of OID thatrepresents key
|
||||
* @param[in] oidklen Length of oidk
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* netsnmp_subtree_find(oid1,sz1, 0, 0)
|
||||
|
|
@ -100,8 +97,9 @@
|
|||
static int
|
||||
mibyang_leaf_register(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
cvec *cvk_orig,
|
||||
cvec *cvk_oid)
|
||||
cvec *cvk_val,
|
||||
oid *oidk,
|
||||
size_t oidklen)
|
||||
{
|
||||
int retval = -1;
|
||||
netsnmp_handler_registration *nhreg = NULL;
|
||||
|
|
@ -109,35 +107,23 @@ mibyang_leaf_register(clicon_handle h,
|
|||
int ret;
|
||||
char *modes_str = NULL;
|
||||
char *default_str = NULL;
|
||||
char *oidstr = NULL;
|
||||
oid oid1[MAX_OID_LEN] = {0,};
|
||||
size_t oid1len = MAX_OID_LEN;
|
||||
int modes;
|
||||
char *name;
|
||||
clixon_snmp_handle *sh;
|
||||
cg_var *cvi;
|
||||
cbuf *cboid = NULL;
|
||||
|
||||
/* Get OID from leaf */
|
||||
if (yang_extension_value(ys, "oid", IETF_YANG_SMIV2_NS, NULL, &oidstr) < 0)
|
||||
goto done;
|
||||
if (oidstr == NULL)
|
||||
goto ok;
|
||||
/* Append sub-keys to original oidstr, use cligen-buf
|
||||
*/
|
||||
if ((cboid = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
cprintf(cboid, "%s", oidstr);
|
||||
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, &oid1len) == NULL){
|
||||
clicon_err(OE_XML, 0, "snmp_parse_oid(%s)", cbuf_get(cboid));
|
||||
// goto done;
|
||||
goto ok; // XXX skip
|
||||
}
|
||||
if ((ret = yangext_oid_get(ys, oid1, &oid1len, NULL)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
if (oid_append(oid1, &oid1len, oidk, oidklen) < 0)
|
||||
goto done;
|
||||
/* Check if already registered */
|
||||
if (clixon_snmp_api_oid_find(oid1, oid1len) == 1)
|
||||
goto ok;
|
||||
|
|
@ -178,13 +164,8 @@ mibyang_leaf_register(clicon_handle h,
|
|||
memcpy(sh->sh_oid, oid1, sizeof(oid1));
|
||||
sh->sh_oidlen = oid1len;
|
||||
sh->sh_default = default_str;
|
||||
if (cvk_orig &&
|
||||
(sh->sh_cvk_orig = cvec_dup(cvk_orig)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
if (cvk_oid &&
|
||||
(sh->sh_cvk_oid = cvec_dup(cvk_oid)) == NULL){
|
||||
if (cvk_val &&
|
||||
(sh->sh_cvk_orig = cvec_dup(cvk_val)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
|
|
@ -209,7 +190,8 @@ mibyang_leaf_register(clicon_handle h,
|
|||
clicon_err(OE_SNMP, ret-CLIXON_ERR_SNMP_MIB, "netsnmp_register_instance");
|
||||
goto done;
|
||||
}
|
||||
clicon_debug(1, "%s %s registered", __FUNCTION__, cbuf_get(cboid));
|
||||
oid_cbuf(cboid, oid1, oid1len);
|
||||
clicon_debug(1, "%s register: %s %s", __FUNCTION__, name, cbuf_get(cboid));
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -262,14 +244,10 @@ mibyang_table_register(clicon_handle h,
|
|||
goto done;
|
||||
}
|
||||
/* Get OID from parent container */
|
||||
if (yang_extension_value(ys, "oid", IETF_YANG_SMIV2_NS, NULL, &oidstr) < 0)
|
||||
if ((ret = yangext_oid_get(ys, oid1, &oid1len, &oidstr)) < 0)
|
||||
goto done;
|
||||
if (oidstr == NULL)
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
if (snmp_parse_oid(oidstr, oid1, &oid1len) == NULL){
|
||||
clicon_err(OE_XML, errno, "snmp_parse_oid");
|
||||
goto done;
|
||||
}
|
||||
name = yang_argument_get(ys);
|
||||
|
||||
/* Userdata to pass around in netsmp callbacks
|
||||
|
|
@ -347,8 +325,8 @@ mibyang_table_register(clicon_handle h,
|
|||
clicon_err(OE_SNMP, ret, "netsnmp_register_table");
|
||||
goto done;
|
||||
}
|
||||
sh->sh_table_info = table_info;
|
||||
clicon_debug(1, "%s %s registered", __FUNCTION__, oidstr);
|
||||
sh->sh_table_info = table_info; /* Keep to free at exit */
|
||||
clicon_debug(1, "%s register: %s %s", __FUNCTION__, name, oidstr);
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
|
|
@ -381,13 +359,11 @@ mibyang_table_poll(clicon_handle h,
|
|||
cxobj *xcol;
|
||||
yang_stmt *y;
|
||||
cvec *cvk_name;
|
||||
cg_var *cv0;
|
||||
cvec *cvk_orig = NULL; /* vector of index keys: original index */
|
||||
cvec *cvk_oid = NULL; /* vector of index keys: translated to OID */
|
||||
cg_var *cv;
|
||||
int i;
|
||||
cxobj *xi;
|
||||
cvec *cvk_val = NULL; /* vector of index keys: original index */
|
||||
yang_stmt *ys;
|
||||
int ret;
|
||||
oid oidk[MAX_OID_LEN] = {0,};
|
||||
size_t oidklen = MAX_OID_LEN;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((ys = yang_parent_get(ylist)) == NULL ||
|
||||
|
|
@ -397,7 +373,7 @@ mibyang_table_poll(clicon_handle h,
|
|||
}
|
||||
if (xml_nsctx_yang(ys, &nsc) < 0)
|
||||
goto done;
|
||||
if (yang2xpath(ys, NULL, &xpath) < 0)
|
||||
if (snmp_yang2xpath(ys, NULL, &xpath) < 0)
|
||||
goto done;
|
||||
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
|
||||
goto done;
|
||||
|
|
@ -413,42 +389,15 @@ mibyang_table_poll(clicon_handle h,
|
|||
}
|
||||
xrow = NULL;
|
||||
while ((xrow = xml_child_each(xtable, xrow, CX_ELMNT)) != NULL) {
|
||||
if (cvk_orig){
|
||||
cvec_free(cvk_orig);
|
||||
cvk_orig = NULL;
|
||||
}
|
||||
if ((cvk_orig = cvec_dup(cvk_name)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
if ((ret = snmp_xmlkey2val_oid(xrow, cvk_name, &cvk_val, oidk, &oidklen)) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (cvk_oid){
|
||||
cvec_free(cvk_oid);
|
||||
cvk_oid = NULL;
|
||||
}
|
||||
if ((cvk_oid = cvec_dup(cvk_name)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
for (i=0; i<cvec_len(cvk_name); i++){
|
||||
cv0 = cvec_i(cvk_name, i);
|
||||
if ((xi = xml_find_type(xrow, NULL, cv_string_get(cv0), CX_ELMNT)) == NULL)
|
||||
break;
|
||||
cv = cvec_i(cvk_orig, i);
|
||||
if (cv_string_set(cv, xml_body(xi)) < 0){
|
||||
clicon_err(OE_UNIX, errno, "cv_string_set");
|
||||
goto done;
|
||||
}
|
||||
cv = cvec_i(cvk_oid, i);
|
||||
if (snmp_body2oid(xi, cv) < 0)
|
||||
goto done;
|
||||
}
|
||||
if (i<cvec_len(cvk_name))
|
||||
if (ret == 0)
|
||||
continue; /* skip row, not all indexes */
|
||||
xcol = NULL;
|
||||
while ((xcol = xml_child_each(xrow, xcol, CX_ELMNT)) != NULL) {
|
||||
if ((y = xml_spec(xcol)) == NULL)
|
||||
continue;
|
||||
if (mibyang_leaf_register(h, y, cvk_orig, cvk_oid) < 0)
|
||||
if (mibyang_leaf_register(h, y, cvk_val, oidk, oidklen) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
|
|
@ -457,11 +406,8 @@ mibyang_table_poll(clicon_handle h,
|
|||
done:
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (cvk_orig)
|
||||
cvec_free(cvk_orig);
|
||||
if (cvk_oid)
|
||||
cvec_free(cvk_oid);
|
||||
|
||||
if (cvk_val)
|
||||
cvec_free(cvk_val);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (nsc)
|
||||
|
|
@ -502,7 +448,7 @@ mibyang_traverse(clicon_handle h,
|
|||
clicon_debug(1, "%s %s", __FUNCTION__, yang_argument_get(yn));
|
||||
switch(yang_keyword_get(yn)){
|
||||
case Y_LEAF:
|
||||
if (mibyang_leaf_register(h, yn, NULL, NULL) < 0)
|
||||
if (mibyang_leaf_register(h, yn, NULL, NULL, 0) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_CONTAINER: /* See list case */
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue