diff --git a/CHANGELOG.md b/CHANGELOG.md index f6bacd77..41dec11b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -105,6 +105,7 @@ Developers may need to change their code ### Corrected Bugs +* Fixed: [SNMP: snmpwalk is slow and can timeout #404 ](https://github.com/clicon/clixon/issues/404) * Fixed: [SNMP accepts only u32 & u64 #405](https://github.com/clicon/clixon/issues/405) * Fixed: [Yang leaves without smiv2:oid directive are not shown well in snmpwalk #398](https://github.com/clicon/clixon/issues/398) * Fixed: [Netconf commit confirm session-id mismatch #407](https://github.com/clicon/clixon/issues/407) diff --git a/apps/snmp/snmp_handler.c b/apps/snmp/snmp_handler.c index ba45f05b..ee314906 100644 --- a/apps/snmp/snmp_handler.c +++ b/apps/snmp/snmp_handler.c @@ -149,7 +149,7 @@ snmp_scalar_return(cxobj *xs, /* SMI default value, How is this different from yang defaults? */ - if (yang_extension_value(ys, "defval", IETF_YANG_SMIV2_NS, NULL, &defaultval) < 0) + if (yang_extension_value_opt(ys, "smiv2:defval", NULL, &defaultval) < 0) goto done; if (xs != NULL && (body = xml_body(xs)) != NULL){ if ((ret = type_xml2snmp_pre(body, ys, &xmlstr)) < 0) // XXX <--- @@ -887,7 +887,7 @@ snmp_table_get(clicon_handle h, } /* SMI default value, How is this different from yang defaults? */ - if (yang_extension_value(ys, "defval", IETF_YANG_SMIV2_NS, NULL, &defaultval) < 0) + if (yang_extension_value_opt(ys, "smiv2:defval", NULL, &defaultval) < 0) goto done; /* Create xpath with right keys from later part of OID @@ -1033,7 +1033,7 @@ snmp_table_set(clicon_handle h, char *modes_str = NULL; int modes; - if (yang_extension_value(ys, "max-access", IETF_YANG_SMIV2_NS, NULL, &modes_str) < 0) + if (yang_extension_value_opt(ys, "smiv2:max-access", NULL, &modes_str) < 0) goto done; if (modes_str){ modes = snmp_access_str2int(modes_str); diff --git a/apps/snmp/snmp_lib.c b/apps/snmp/snmp_lib.c index 6ccb1734..06977f63 100644 --- a/apps/snmp/snmp_lib.c +++ b/apps/snmp/snmp_lib.c @@ -335,6 +335,56 @@ snmp_yang_type_get(yang_stmt *ys, return retval; } +/*! Specialized and optimized variant of yang_extension_value + * + * In this optimized version, "id" on the form ":" is hardcoded + * and not derived from "name" and "namespace" in the original version. + + * @param[in] ys Yang statement where unknown statement may occur referencing to extension + * @param[out] exist The extension exists. + * @param[out] value clispec operator (hide/none) - direct pointer into yang, dont free + * @retval 0 OK: Look in exist and value for return value + * @retval -1 Error + * + * @note This optimizatoin may not work if the unknown statements are augmented in ys. + * @see yang_extension_value for the generic function + */ +int +yang_extension_value_opt(yang_stmt *ys, + char *id, + int *exist, + char **value) +{ + int retval = -1; + yang_stmt *yext; + cg_var *cv; + + if (ys == NULL){ + clicon_err(OE_YANG, EINVAL, "ys is NULL"); + goto done; + } + if (exist) + *exist = 0; + yext = NULL; /* This loop gets complicated in the case the extension is augmented */ + while ((yext = yn_each(ys, yext)) != NULL) { + if (yang_keyword_get(yext) != Y_UNKNOWN) + continue; + if (strcmp(yang_argument_get(yext), id) != 0) + continue; + break; + } + if (yext != NULL){ /* Found */ + if (exist) + *exist = 1; + if (value && + (cv = yang_cv_get(yext)) != NULL) + *value = cv_string_get(cv); + } + retval = 0; + done: + 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 @@ -361,8 +411,8 @@ yangext_oid_get(yang_stmt *yn, } else yref = yn; - /* Get OID from table /list */ - if (yang_extension_value(yref, "oid", IETF_YANG_SMIV2_NS, &exist, &oidstr) < 0) + /* Get OID from table /list */ + if (yang_extension_value_opt(yref, "smiv2:oid", &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)); @@ -382,20 +432,19 @@ yangext_oid_get(yang_stmt *yn, goto done; } - - /*! Given a YANG node, return 1 if leaf has oid directive in it, otherwise 0 * @param[in] yn Yang node * @retval 1 found * @retval 0 not found */ -int yangext_is_oid_exist(yang_stmt *yn) { +int +yangext_is_oid_exist(yang_stmt *yn) { int exist = 0; char *oidstr = NULL; if ((yang_keyword_get(yn) != Y_LEAF) || - (yang_extension_value(yn, "oid", IETF_YANG_SMIV2_NS, &exist, &oidstr) < 0) || + (yang_extension_value_opt(yn, "smiv2:oid", &exist, &oidstr) < 0) || (exist == 0) || (oidstr == NULL)) { return 0; @@ -495,8 +544,9 @@ type_yang2asn1(yang_stmt *ys, yang_stmt *yrp; char *display_hint = NULL; yrp = yang_parent_get(yrestype); - if (yang_extension_value(yrp, "display-hint", IETF_YANG_SMIV2_NS, NULL, &display_hint) < 0) + if (yang_extension_value_opt(yrp, "smiv2:display-hint", NULL, &display_hint) < 0) goto done; + /* RFC2578/2579 but maybe all strings with display-hint should use this, eg exist>0? */ if (display_hint && (strcmp(display_hint, "255a")==0 || diff --git a/apps/snmp/snmp_lib.h b/apps/snmp/snmp_lib.h index c86a58a6..6399c032 100644 --- a/apps/snmp/snmp_lib.h +++ b/apps/snmp/snmp_lib.h @@ -86,6 +86,7 @@ int oid_append(const oid *objid0, size_t *objid0len, const oid *objid1, size_ int oid_cbuf(cbuf *cb, const oid *objid, size_t objidlen); int oid_print(FILE *f, const oid *objid, size_t objidlen); int snmp_yang_type_get(yang_stmt *ys, yang_stmt **yrefp, char **origtypep, yang_stmt **yrestypep, char **restypep); +int yang_extension_value_opt(yang_stmt *ys, char *id, int *exist, char **value); int yangext_oid_get(yang_stmt *yn, oid *objid, size_t *objidlen, char **objidstr); int yangext_is_oid_exist(yang_stmt *yn); int snmp_access_str2int(char *modes_str); diff --git a/apps/snmp/snmp_register.c b/apps/snmp/snmp_register.c index 52883a6e..53c0d91d 100644 --- a/apps/snmp/snmp_register.c +++ b/apps/snmp/snmp_register.c @@ -127,7 +127,7 @@ mibyang_leaf_register(clicon_handle h, /* Check if already registered */ if (clixon_snmp_api_oid_find(oid1, oid1len) == 1) goto ok; - if (yang_extension_value(ys, "max-access", IETF_YANG_SMIV2_NS, NULL, &modes_str) < 0) + if (yang_extension_value_opt(ys, "smiv2:max-access", NULL, &modes_str) < 0) goto done; /* Only for sanity check of types initially to fail early */ if (type_yang2asn1(ys, NULL, 0) < 0) @@ -141,9 +141,8 @@ mibyang_leaf_register(clicon_handle h, /* SMI default value, How is this different from yang defaults? */ - if (yang_extension_value(ys, "defval", IETF_YANG_SMIV2_NS, NULL, &default_str) < 0) + if (yang_extension_value_opt(ys, "smiv2:defval", NULL, &default_str) < 0) goto done; - name = yang_argument_get(ys); /* Stateless function, just returns ptr */ if ((handler = netsnmp_create_handler(name, clixon_snmp_scalar_handler)) == NULL){ diff --git a/lib/src/clixon_yang.c b/lib/src/clixon_yang.c index aba7a779..b158d3d2 100644 --- a/lib/src/clixon_yang.c +++ b/lib/src/clixon_yang.c @@ -3734,6 +3734,7 @@ yang_anydata_add(yang_stmt *yp, * } * @endcode * @see ys_populate_unknown Called when parsing YANG + * XXX consider optimizing, the call to yang_find_prefix_by_namespace may be slow */ int yang_extension_value(yang_stmt *ys, @@ -3766,6 +3767,7 @@ yang_extension_value(yang_stmt *ys, continue; if ((ymod = ys_module(yext)) == NULL) continue; + /* XXX this is slow */ if ((ret = yang_find_prefix_by_namespace(ymod, ns, &prefix)) < 0) goto done; if (ret == 0) /* not found (this may happen in augment and maybe should be treated otherwise) */