SNMP: Large refactorings and new dynamic table support

This commit is contained in:
Olof hagsand 2022-06-15 21:19:47 +02:00
parent ebf251455f
commit 150ad3ab8b
4 changed files with 742 additions and 229 deletions

View file

@ -71,50 +71,120 @@ snmp_common_handler(netsnmp_mib_handler *handler,
{ {
int retval = -1; int retval = -1;
netsnmp_variable_list *requestvb; /* sub of requests */ netsnmp_variable_list *requestvb; /* sub of requests */
char oidstr0[MAX_OID_LEN*2] = {0,}; cbuf *cb;
char oidstr1[MAX_OID_LEN*2] = {0,};
char oidstr2[MAX_OID_LEN*2] = {0,};
if (requests == NULL || shp == NULL){ if (requests == NULL || shp == NULL){
clicon_err(OE_XML, EINVAL, "requests or shp is null"); clicon_err(OE_XML, EINVAL, "requests or shp is null");
goto done; goto done;
} }
requestvb = requests->requestvb; 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){ if ((*shp = (clixon_snmp_handle*)handler->myvoid) == NULL){
clicon_err(OE_XML, 0, "No myvoid handler"); clicon_err(OE_XML, 0, "No myvoid handler");
goto done; goto done;
} }
if (snprint_objid(oidstr1, sizeof(oidstr1), if ((cb = cbuf_new()) == NULL){
nhreg->rootoid, nhreg->rootoid_len) < 0){ clicon_err(OE_UNIX, errno, "cbuf_new");
clicon_err(OE_XML, 0, "snprint_objid buffer too small");
goto done; goto done;
} }
if (snprint_objid(oidstr2, sizeof(oidstr2), oid_cbuf(cb, (*shp)->sh_oid, (*shp)->sh_oidlen);
(*shp)->sh_oid, (*shp)->sh_oidlen) < 0){ if (oid_eq(requestvb->name, requestvb->name_length,
clicon_err(OE_XML, 0, "snprint_objid buffer too small"); (*shp)->sh_oid, (*shp)->sh_oidlen) == 0){ /* equal */
goto done;
}
if (strcmp(oidstr0, oidstr2) == 0)
clicon_debug(1, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__, clicon_debug(1, "%s \"%s\" %s inclusive:%d %s", __FUNCTION__,
oidstr2, cbuf_get(cb),
snmp_msg_int2str(reqinfo->mode), snmp_msg_int2str(reqinfo->mode),
requests->inclusive, tablehandler?"table":"scalar"); requests->inclusive, tablehandler?"table":"scalar");
else }
clicon_debug(1, "%s \"%s\"/\"%s\" %s inclusive:%d %s", __FUNCTION__, else{ /* not equal */
oidstr2, oidstr0, 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), snmp_msg_int2str(reqinfo->mode),
requests->inclusive, tablehandler?"table":"scalar"); requests->inclusive, tablehandler?"table":"scalar");
}
retval = 0; retval = 0;
done: done:
if (cb)
cbuf_free(cb);
return retval; 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 /*! Scalar handler, set a value to clixon
* get xpath: see yang2api_path_fmt / api_path2xpath * get xpath: see yang2api_path_fmt / api_path2xpath
@ -125,12 +195,13 @@ snmp_common_handler(netsnmp_mib_handler *handler,
* @param[in] defaultval * @param[in] defaultval
* @param[in] reqinfo * @param[in] reqinfo
* @param[in] requests * @param[in] requests
* @retval 0 OK
* @retval -1 Error
*/ */
static int static int
snmp_scalar_get(clicon_handle h, snmp_scalar_get(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cvec *cvk, cvec *cvk,
netsnmp_variable_list *requestvb,
char *defaultval, char *defaultval,
netsnmp_agent_request_info *reqinfo, netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests) netsnmp_request_info *requests)
@ -147,13 +218,14 @@ snmp_scalar_get(clicon_handle h,
int ret; int ret;
int asn1type; int asn1type;
char *reason = NULL; char *reason = NULL;
netsnmp_variable_list *requestvb = requests->requestvb;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
/* Prepare backend call by constructing namespace context */ /* Prepare backend call by constructing namespace context */
if (xml_nsctx_yang(ys, &nsc) < 0) if (xml_nsctx_yang(ys, &nsc) < 0)
goto done; goto done;
/* Create xpath from yang (XXX works not for lists) */ /* Create xpath from yang (XXX works not for lists) */
if (yang2xpath(ys, cvk, &xpath) < 0) if (snmp_yang2xpath(ys, cvk, &xpath) < 0)
goto done; goto done;
/* Do the backend call */ /* Do the backend call */
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0) 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 /* see snmplib/snmp_client. somewhat indirect
*/ */
requestvb->type = asn1type; // ASN_NULL on input if ((ret = snmp_set_var_typed_value(requestvb, asn1type, snmpval, snmplen)) != SNMPERR_SUCCESS){
if ((ret = snmp_set_var_value(requestvb, snmpval, snmplen)) != SNMPERR_SUCCESS){ clicon_err(OE_SNMP, ret, "snmp_set_var_typed_value");
clicon_err(OE_SNMP, ret, "snmp_set_var_value");
goto done; goto done;
} }
ok: ok:
@ -226,7 +297,6 @@ snmp_scalar_get(clicon_handle h,
static int static int
snmp_scalar_set(clicon_handle h, snmp_scalar_set(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
netsnmp_variable_list *requestvb,
netsnmp_agent_request_info *reqinfo, netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests) netsnmp_request_info *requests)
{ {
@ -239,6 +309,7 @@ snmp_scalar_set(clicon_handle h,
int ret; int ret;
char *valstr = NULL; char *valstr = NULL;
cbuf *cb = NULL; cbuf *cb = NULL;
netsnmp_variable_list *requestvb = requests->requestvb;
if ((yspec = clicon_dbspec_yang(h)) == NULL){ if ((yspec = clicon_dbspec_yang(h)) == NULL){
clicon_err(OE_FATAL, 0, "No DB_SPEC"); clicon_err(OE_FATAL, 0, "No DB_SPEC");
@ -250,7 +321,6 @@ snmp_scalar_set(clicon_handle h,
goto done; goto done;
if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, NULL, NULL)) < 0) if ((ret = api_path2xml(api_path, yspec, xtop, YC_DATANODE, 1, &xbot, NULL, NULL)) < 0)
goto done; goto done;
if (ret == 0){ if (ret == 0){
clicon_err(OE_XML, 0, "api_path2xml %s invalid", api_path); clicon_err(OE_XML, 0, "api_path2xml %s invalid", api_path);
goto done; goto done;
@ -309,7 +379,7 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
switch (reqinfo->mode) { switch (reqinfo->mode) {
case MODE_GET: /* 160 */ case MODE_GET: /* 160 */
if (snmp_scalar_get(sh->sh_h, sh->sh_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) sh->sh_default, reqinfo, requests) < 0)
goto done; goto done;
break; break;
case MODE_GETNEXT: /* 161 */ case MODE_GETNEXT: /* 161 */
@ -328,7 +398,7 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
case MODE_SET_RESERVE2: /* 1 */ case MODE_SET_RESERVE2: /* 1 */
break; break;
case MODE_SET_ACTION: /* 2 */ 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; goto done;
break; break;
case MODE_SET_UNDO: /* 5 */ case MODE_SET_UNDO: /* 5 */
@ -348,6 +418,227 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
return retval; 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 /*! SNMP table operation handler
* Callorder: 161,160,.... 0, 1,2,3, 160,161,... * Callorder: 161,160,.... 0, 1,2,3, 160,161,...
* see https://net-snmp.sourceforge.io/dev/agent/data_set_8c-example.html#_a0 * 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; cxobj *xt = NULL;
cbuf *cb = NULL; cbuf *cb = NULL;
int ret; int ret;
#ifdef SNMP_TABLE_DYNAMIC
netsnmp_variable_list *requestvb;
#endif
clicon_debug(2, "%s", __FUNCTION__); clicon_debug(2, "%s", __FUNCTION__);
if ((ret = snmp_common_handler(handler, nhreg, reqinfo, requests, &sh, 1)) < 0) 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__); clicon_debug(1, "%s Error table not registered", __FUNCTION__);
goto ok; goto ok;
} }
#ifdef SNMP_TABLE_DYNAMIC
requestvb = requests->requestvb;
#endif
switch(reqinfo->mode){ switch(reqinfo->mode){
case MODE_GET: // 160 case MODE_GET: // 160
#ifdef SNMP_TABLE_DYNAMIC #ifdef SNMP_TABLE_DYNAMIC
/* Register table sub-oid:s of existing entries in clixon */ /* Create xpath from YANG table OID + 1 + n + cvk/key = requestvb->name
if (mibyang_table_poll(sh->sh_h, sh->sh_ys) < 0) */
if ((ret = snmp_table_get(sh->sh_h, sh->sh_ys,
requestvb->name, requestvb->name_length,
reqinfo, requests)) < 0)
goto done; goto done;
#if 1 if (ret == 0)
{ netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHINSTANCE);
if ((ret = netsnmp_call_next_handler(handler, nhreg, reqinfo, requests)) < 0){
clicon_err(OE_SNMP, ret, "netsnmp_call_next_handler");
goto done;
}
}
#endif #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; break;
case MODE_GETNEXT: // 161 case MODE_GETNEXT: // 161
#ifdef SNMP_TABLE_DYNAMIC #ifdef SNMP_TABLE_DYNAMIC
/* Register table sub-oid:s of existing entries in clixon */ /* 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; goto done;
#endif #endif
break; break;

View file

@ -156,7 +156,16 @@ snmp_msg_int2str(int msg)
{ {
return clicon_int2str(snmp_msg_map, 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 int
oid_eq(const oid *objid0, oid_eq(const oid *objid0,
@ -164,11 +173,185 @@ oid_eq(const oid *objid0,
const oid *objid1, const oid *objid1,
size_t objid1len) size_t objid1len)
{ {
if (objid0len != objid1len) if (objid0len < objid1len)
return 0; return -1;
else if (objid0len > objid1len)
return 1;
else
return memcmp(objid0, objid1, objid0len*sizeof(*objid0)); 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 /*! Duplicate clixon snmp handler struct
* Use signature of libnetsnmp data_clone field of netsnmp_mib_handler in agent_handler.h * Use signature of libnetsnmp data_clone field of netsnmp_mib_handler in agent_handler.h
* @param[in] arg * @param[in] arg
@ -191,11 +374,6 @@ snmp_handle_clone(void *arg)
clicon_err(OE_UNIX, errno, "cvec_dup"); clicon_err(OE_UNIX, errno, "cvec_dup");
return NULL; 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; return (void*)sh1;
} }
@ -211,8 +389,6 @@ snmp_handle_free(void *arg)
if (sh != NULL){ if (sh != NULL){
if (sh->sh_cvk_orig) if (sh->sh_cvk_orig)
cvec_free(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){
if (sh->sh_table_info->indexes){ if (sh->sh_table_info->indexes){
snmp_free_varbind(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 extended)
{ {
int retval = -1; int retval = -1;
yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */ char *restype; /* resolved type */
char *origtype = NULL; /* original type */ char *origtype = NULL; /* original type */
int at; int at;
yang_stmt *ypath;
yang_stmt *yref;
/* Get yang type of leaf and trasnslate to ASN.1 */ /* Get yang type of leaf and translate to ASN.1 */
if (yang_type_get(ys, &origtype, &yrestype, NULL, NULL, NULL, NULL, NULL) < 0) if (snmp_yang_type_get(ys, NULL, &origtype, NULL, &restype) < 0)
goto done; 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 /* Translate to asn.1
* First try original type, first type * First try original type, first type
*/ */
@ -312,9 +468,8 @@ type_snmp2xml(yang_stmt *ys,
char *cvstr; char *cvstr;
enum cv_type cvtype; enum cv_type cvtype;
cg_var *cv = NULL; cg_var *cv = NULL;
yang_stmt *yrestype; /* resolved type */ char *restype = NULL; /* resolved type */
char *restype; /* resolved type */ yang_stmt *yrestype = NULL;
char *origtype = NULL; /* original type */
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
if (valstr == NULL){ if (valstr == NULL){
@ -323,9 +478,8 @@ type_snmp2xml(yang_stmt *ys,
} }
cvstr = (char*)clicon_int2str(snmp_type_map, requestvb->type); cvstr = (char*)clicon_int2str(snmp_type_map, requestvb->type);
/* Get yang type of leaf and trasnslate to ASN.1 */ /* 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; goto done;
restype = yrestype?yang_argument_get(yrestype):NULL;
/* special case for enum */ /* special case for enum */
if (strcmp(cvstr, "int32")==0 && strcmp(restype, "enumeration") == 0) if (strcmp(cvstr, "int32")==0 && strcmp(restype, "enumeration") == 0)
cvstr = "string"; cvstr = "string";
@ -399,8 +553,6 @@ type_snmp2xml(yang_stmt *ys,
clicon_debug(2, "%s %d", __FUNCTION__, retval); clicon_debug(2, "%s %d", __FUNCTION__, retval);
if (cv) if (cv)
cv_free(cv); cv_free(cv);
if (origtype)
free(origtype);
return retval; return retval;
fail: fail:
retval = 0; retval = 0;
@ -427,8 +579,7 @@ type_xml2snmp_pre(char *xmlstr0,
{ {
int retval = -1; int retval = -1;
yang_stmt *yrestype; /* resolved type */ yang_stmt *yrestype; /* resolved type */
char *restype; /* resolved type */ char *restype = NULL; /* resolved type */
char *origtype = NULL; /* original type */
char *str = NULL; char *str = NULL;
int ret; int ret;
@ -437,9 +588,8 @@ type_xml2snmp_pre(char *xmlstr0,
goto done; goto done;
} }
/* Get yang type of leaf and trasnslate to ASN.1 */ /* 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; goto done;
restype = yrestype?yang_argument_get(yrestype):NULL;
if (strcmp(restype, "enumeration") == 0){ /* special case for enum */ if (strcmp(restype, "enumeration") == 0){ /* special case for enum */
if ((ret = yang_enum2valstr(yrestype, xmlstr0, &str)) < 0) if ((ret = yang_enum2valstr(yrestype, xmlstr0, &str)) < 0)
goto done; goto done;
@ -469,8 +619,6 @@ type_xml2snmp_pre(char *xmlstr0,
retval = 1; retval = 1;
done: done:
clicon_debug(2, "%s %d", __FUNCTION__, retval); clicon_debug(2, "%s %d", __FUNCTION__, retval);
if (origtype)
free(origtype);
return retval; return retval;
fail: fail:
retval = 0; retval = 0;
@ -609,14 +757,14 @@ type_xml2snmp(char *snmpstr,
/*! Construct an xpath from yang statement, internal fn using cb /*! Construct an xpath from yang statement, internal fn using cb
* Recursively construct it to the top. * Recursively construct it to the top.
* @param[in] ys Yang statement * @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 * @param[out] cb xpath as cbuf
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error
* @see yang2xpath * @see yang2xpath
*/ */
static int static int
yang2xpath_cb(yang_stmt *ys, snmp_yang2xpath_cb(yang_stmt *ys,
cvec *keyvec, cvec *keyvec,
cbuf *cb) cbuf *cb)
{ {
@ -633,7 +781,7 @@ yang2xpath_cb(yang_stmt *ys,
if (yp != NULL && /* XXX rm */ if (yp != NULL && /* XXX rm */
yang_keyword_get(yp) != Y_MODULE && yang_keyword_get(yp) != Y_MODULE &&
yang_keyword_get(yp) != Y_SUBMODULE){ 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; goto done;
if (yang_keyword_get(yp) != Y_CHOICE && yang_keyword_get(yp) != Y_CASE){ if (yang_keyword_get(yp) != Y_CHOICE && yang_keyword_get(yp) != Y_CASE){
cprintf(cb, "/"); cprintf(cb, "/");
@ -670,10 +818,10 @@ yang2xpath_cb(yang_stmt *ys,
return retval; 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. * Recursively construct it to the top.
* @param[in] ys Yang statement * @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 * @param[out] xpath Malloced xpath string, use free() after use
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @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 * 2. It is far from complete so maybe keep it here as a special case
*/ */
int int
yang2xpath(yang_stmt *ys, snmp_yang2xpath(yang_stmt *ys,
cvec *keyvec, cvec *keyvec,
char **xpath) char **xpath)
{ {
@ -693,7 +841,7 @@ yang2xpath(yang_stmt *ys,
clicon_err(OE_UNIX, errno, "cbuf_new"); clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
} }
if (yang2xpath_cb(ys, keyvec, cb) < 0) if (snmp_yang2xpath_cb(ys, keyvec, cb) < 0)
goto done; goto done;
if (xpath && (*xpath = strdup(cbuf_get(cb))) == NULL){ if (xpath && (*xpath = strdup(cbuf_get(cb))) == NULL){
clicon_err(OE_UNIX, errno, "strdup"); clicon_err(OE_UNIX, errno, "strdup");
@ -706,27 +854,27 @@ yang2xpath(yang_stmt *ys,
return retval; 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 * 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 int
snmp_body2oid(cxobj *xi, snmp_str2oid(char *str,
cg_var *cv) yang_stmt *yi,
oid *objid,
size_t *objidlen)
{ {
int retval = -1; int retval = -1;
yang_stmt *yi;
int asn1_type; int asn1_type;
char *body;
size_t len;
cbuf *enc = NULL;
int i; int i;
int j = 0;
if ((yi = xml_spec(xi)) == NULL)
goto ok;
if (type_yang2asn1(yi, &asn1_type, 0) < 0) if (type_yang2asn1(yi, &asn1_type, 0) < 0)
goto done; goto done;
body = xml_body(xi);
switch (asn1_type){ switch (asn1_type){
case ASN_INTEGER: case ASN_INTEGER:
case ASN_GAUGE: case ASN_GAUGE:
@ -734,30 +882,76 @@ snmp_body2oid(cxobj *xi,
case ASN_COUNTER64: case ASN_COUNTER64:
case ASN_COUNTER: case ASN_COUNTER:
case ASN_IPADDRESS: case ASN_IPADDRESS:
if (cv_string_set(cv, body) < 0){ objid[j++] = atoi(str);
clicon_err(OE_UNIX, errno, "cv_string_set");
goto done;
}
break; break;
case ASN_OCTET_STR:{ /* encode to N.c.c.c.c */ case ASN_OCTET_STR:{ /* encode to N.c.c.c.c */
if ((enc = cbuf_new()) == NULL){ objid[j++] = strlen(str);
clicon_err(OE_UNIX, errno, "cbuf_new"); for (i=0; i<strlen(str); i++)
goto done; objid[j++] = str[i]&0xff;
}
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;
}
break; break;
} }
default: default:
break; 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; retval = 0;
done: done:
if (enc) if (enc)
@ -812,6 +1006,79 @@ clixon_snmp_err_cb(void *handle,
return 0; 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 =============== /*========== libnetsnmp-specific code ===============
* Peeks into internal lib global variables, may be sensitive to library change * 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; netsnmp_subtree *tree1 = NULL;
if ((tree1 = netsnmp_subtree_find(oid0, oid0len, NULL, "")) != NULL && if ((tree1 = netsnmp_subtree_find(oid0, oid0len, NULL, "")) != NULL &&
oid_eq(oid0, oid0len, tree1->name_a, tree1->namelen)){ oid_eq(oid0, oid0len, tree1->name_a, tree1->namelen)==0){
fprintf(stderr, "%s EQUAL==================\n", __FUNCTION__);
retval = 1; retval = 1;
} }
else else
@ -868,3 +1134,4 @@ clixon_snmp_api_oid_find(oid *oid0,
// done: // done:
return retval; return retval;
} }

View file

@ -47,6 +47,8 @@ extern "C" {
/* Need some way to multiplex SNMP_ and MIB errors on OE_SNMP error handler */ /* Need some way to multiplex SNMP_ and MIB errors on OE_SNMP error handler */
#define CLIXON_ERR_SNMP_MIB 0x1000 #define CLIXON_ERR_SNMP_MIB 0x1000
#define IETF_YANG_SMIV2_NS "urn:ietf:params:xml:ns:yang:ietf-yang-smiv2"
/* /*
* Types * Types
*/ */
@ -58,17 +60,21 @@ struct clixon_snmp_handle {
oid sh_oid[MAX_OID_LEN]; /* OID for debug, may be removed? */ oid sh_oid[MAX_OID_LEN]; /* OID for debug, may be removed? */
size_t sh_oidlen; size_t sh_oidlen;
char *sh_default; /* MIB default value leaf only */ char *sh_default; /* MIB default value leaf only */
cvec *sh_cvk_orig; /* Index/Key variables (original) */ cvec *sh_cvk_orig; /* Index/Key variable values (original) */
cvec *sh_cvk_oid; /* Index/Key variables (OID translated) */ netsnmp_table_registration_info *sh_table_info; /* To mimic table-handler in libnetsnmp code
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; typedef struct clixon_snmp_handle clixon_snmp_handle;
/* /*
* Prototypes * Prototypes
*/ */
int oid_eq(const oid * objid0, size_t objid0len, const oid * objid1, size_t objid1len); 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); int snmp_access_str2int(char *modes_str);
const char *snmp_msg_int2str(int msg); const char *snmp_msg_int2str(int msg);
void *snmp_handle_clone(void *arg); void *snmp_handle_clone(void *arg);
@ -81,9 +87,11 @@ int type_snmp2xml(yang_stmt *ys,
char **valstr); char **valstr);
int type_xml2snmp_pre(char *xmlstr, yang_stmt *ys, char **snmpstr); 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 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_yang2xpath(yang_stmt *ys, cvec *keyvec, char **xpath);
int snmp_body2oid(cxobj *xi, cg_var *cv); 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 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 =============== */ /*========== libnetsnmp-specific code =============== */
int clixon_snmp_api_agent_check(void); int clixon_snmp_api_agent_check(void);

View file

@ -80,9 +80,6 @@
#include "snmp_register.h" #include "snmp_register.h"
#include "snmp_handler.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 /*! Parse smiv2 extensions for YANG leaf
* Typical leaf: * Typical leaf:
* smiv2:oid "1.3.6.1.4.1.8072.2.1.1"; * smiv2:oid "1.3.6.1.4.1.8072.2.1.1";
@ -91,8 +88,8 @@
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ys Mib-Yang node * @param[in] ys Mib-Yang node
* @param[in] cvk_orig Vector of untranslated key/index values (eg "foo") * @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 0 OK
* @retval -1 Error * @retval -1 Error
* netsnmp_subtree_find(oid1,sz1, 0, 0) * netsnmp_subtree_find(oid1,sz1, 0, 0)
@ -100,8 +97,9 @@
static int static int
mibyang_leaf_register(clicon_handle h, mibyang_leaf_register(clicon_handle h,
yang_stmt *ys, yang_stmt *ys,
cvec *cvk_orig, cvec *cvk_val,
cvec *cvk_oid) oid *oidk,
size_t oidklen)
{ {
int retval = -1; int retval = -1;
netsnmp_handler_registration *nhreg = NULL; netsnmp_handler_registration *nhreg = NULL;
@ -109,35 +107,23 @@ mibyang_leaf_register(clicon_handle h,
int ret; int ret;
char *modes_str = NULL; char *modes_str = NULL;
char *default_str = NULL; char *default_str = NULL;
char *oidstr = NULL;
oid oid1[MAX_OID_LEN] = {0,}; oid oid1[MAX_OID_LEN] = {0,};
size_t oid1len = MAX_OID_LEN; size_t oid1len = MAX_OID_LEN;
int modes; int modes;
char *name; char *name;
clixon_snmp_handle *sh; clixon_snmp_handle *sh;
cg_var *cvi;
cbuf *cboid = NULL; 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){ if ((cboid = cbuf_new()) == NULL){
clicon_err(OE_UNIX, errno, "cbuf_new"); clicon_err(OE_UNIX, errno, "cbuf_new");
goto done; goto done;
} }
cprintf(cboid, "%s", oidstr); if ((ret = yangext_oid_get(ys, oid1, &oid1len, NULL)) < 0)
cvi = NULL; goto done;
while ((cvi = cvec_each(cvk_oid, cvi)) != NULL) if (ret == 0)
cprintf(cboid, ".%s", cv_string_get(cvi)); goto ok;
if (snmp_parse_oid(cbuf_get(cboid), oid1, &oid1len) == NULL){ if (oid_append(oid1, &oid1len, oidk, oidklen) < 0)
clicon_err(OE_XML, 0, "snmp_parse_oid(%s)", cbuf_get(cboid)); goto done;
// goto done;
goto ok; // XXX skip
}
/* Check if already registered */ /* Check if already registered */
if (clixon_snmp_api_oid_find(oid1, oid1len) == 1) if (clixon_snmp_api_oid_find(oid1, oid1len) == 1)
goto ok; goto ok;
@ -178,13 +164,8 @@ mibyang_leaf_register(clicon_handle h,
memcpy(sh->sh_oid, oid1, sizeof(oid1)); memcpy(sh->sh_oid, oid1, sizeof(oid1));
sh->sh_oidlen = oid1len; sh->sh_oidlen = oid1len;
sh->sh_default = default_str; sh->sh_default = default_str;
if (cvk_orig && if (cvk_val &&
(sh->sh_cvk_orig = cvec_dup(cvk_orig)) == NULL){ (sh->sh_cvk_orig = cvec_dup(cvk_val)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_dup");
goto done;
}
if (cvk_oid &&
(sh->sh_cvk_oid = cvec_dup(cvk_oid)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_dup"); clicon_err(OE_UNIX, errno, "cvec_dup");
goto done; goto done;
} }
@ -209,7 +190,8 @@ mibyang_leaf_register(clicon_handle h,
clicon_err(OE_SNMP, ret-CLIXON_ERR_SNMP_MIB, "netsnmp_register_instance"); clicon_err(OE_SNMP, ret-CLIXON_ERR_SNMP_MIB, "netsnmp_register_instance");
goto done; 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: ok:
retval = 0; retval = 0;
done: done:
@ -262,14 +244,10 @@ mibyang_table_register(clicon_handle h,
goto done; goto done;
} }
/* Get OID from parent container */ /* 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; goto done;
if (oidstr == NULL) if (ret == 0)
goto ok; 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); name = yang_argument_get(ys);
/* Userdata to pass around in netsmp callbacks /* 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"); clicon_err(OE_SNMP, ret, "netsnmp_register_table");
goto done; goto done;
} }
sh->sh_table_info = table_info; sh->sh_table_info = table_info; /* Keep to free at exit */
clicon_debug(1, "%s %s registered", __FUNCTION__, oidstr); clicon_debug(1, "%s register: %s %s", __FUNCTION__, name, oidstr);
ok: ok:
retval = 0; retval = 0;
done: done:
@ -381,13 +359,11 @@ mibyang_table_poll(clicon_handle h,
cxobj *xcol; cxobj *xcol;
yang_stmt *y; yang_stmt *y;
cvec *cvk_name; cvec *cvk_name;
cg_var *cv0; cvec *cvk_val = NULL; /* vector of index keys: original index */
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;
yang_stmt *ys; yang_stmt *ys;
int ret;
oid oidk[MAX_OID_LEN] = {0,};
size_t oidklen = MAX_OID_LEN;
clicon_debug(1, "%s", __FUNCTION__); clicon_debug(1, "%s", __FUNCTION__);
if ((ys = yang_parent_get(ylist)) == NULL || if ((ys = yang_parent_get(ylist)) == NULL ||
@ -397,7 +373,7 @@ mibyang_table_poll(clicon_handle h,
} }
if (xml_nsctx_yang(ys, &nsc) < 0) if (xml_nsctx_yang(ys, &nsc) < 0)
goto done; goto done;
if (yang2xpath(ys, NULL, &xpath) < 0) if (snmp_yang2xpath(ys, NULL, &xpath) < 0)
goto done; goto done;
if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0) if (clicon_rpc_get(h, xpath, nsc, CONTENT_ALL, -1, &xt) < 0)
goto done; goto done;
@ -413,42 +389,15 @@ mibyang_table_poll(clicon_handle h,
} }
xrow = NULL; xrow = NULL;
while ((xrow = xml_child_each(xtable, xrow, CX_ELMNT)) != NULL) { while ((xrow = xml_child_each(xtable, xrow, CX_ELMNT)) != NULL) {
if (cvk_orig){ if ((ret = snmp_xmlkey2val_oid(xrow, cvk_name, &cvk_val, oidk, &oidklen)) < 0)
cvec_free(cvk_orig);
cvk_orig = NULL;
}
if ((cvk_orig = cvec_dup(cvk_name)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_dup");
goto done; goto done;
} if (ret == 0)
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))
continue; /* skip row, not all indexes */ continue; /* skip row, not all indexes */
xcol = NULL; xcol = NULL;
while ((xcol = xml_child_each(xrow, xcol, CX_ELMNT)) != NULL) { while ((xcol = xml_child_each(xrow, xcol, CX_ELMNT)) != NULL) {
if ((y = xml_spec(xcol)) == NULL) if ((y = xml_spec(xcol)) == NULL)
continue; 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; goto done;
} }
} }
@ -457,11 +406,8 @@ mibyang_table_poll(clicon_handle h,
done: done:
if (xpath) if (xpath)
free(xpath); free(xpath);
if (cvk_orig) if (cvk_val)
cvec_free(cvk_orig); cvec_free(cvk_val);
if (cvk_oid)
cvec_free(cvk_oid);
if (xt) if (xt)
xml_free(xt); xml_free(xt);
if (nsc) if (nsc)
@ -502,7 +448,7 @@ mibyang_traverse(clicon_handle h,
clicon_debug(1, "%s %s", __FUNCTION__, yang_argument_get(yn)); clicon_debug(1, "%s %s", __FUNCTION__, yang_argument_get(yn));
switch(yang_keyword_get(yn)){ switch(yang_keyword_get(yn)){
case Y_LEAF: case Y_LEAF:
if (mibyang_leaf_register(h, yn, NULL, NULL) < 0) if (mibyang_leaf_register(h, yn, NULL, NULL, 0) < 0)
goto done; goto done;
break; break;
case Y_CONTAINER: /* See list case */ case Y_CONTAINER: /* See list case */