diff --git a/CHANGELOG.md b/CHANGELOG.md index 56a10e87..7d6c4b5e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -47,7 +47,7 @@ * New configure options: * `--enable-netsnmp` * `--with-mib-generated-yang-dir=DIR` - * Thanks to Siklu Communications LTD for sponshoring this work + * Thanks to Siklu Communications LTD for sponsoring this work ## 5.8.0 Planned: July 2022 diff --git a/apps/snmp/snmp_handler.c b/apps/snmp/snmp_handler.c index d236eb74..3c67ac3c 100644 --- a/apps/snmp/snmp_handler.c +++ b/apps/snmp/snmp_handler.c @@ -313,18 +313,17 @@ snmp_scalar_get(clicon_handle h, * @param[in] ys Yang node * @param[in] cvk Vector of index/Key variables, if any * @param[in] db Clixon datastore, typically "candidate" - * @param[in] rowstatus Special case: transform createAndGo -> active, createAndWait -> notInService * @param[in] reqinfo * @param[in] requestvb SNMP variables * @retval 0 OK * @retval -1 Error + * @note contains special logic for rowstatus handling */ static int snmp_scalar_set(clicon_handle h, yang_stmt *ys, cvec *cvk, char *db, - int rowstatus, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { @@ -342,6 +341,8 @@ snmp_scalar_set(clicon_handle h, cvec *cvk1; int i; int asn1_type; + int rowstatus = 0; + enum operation_type op = OP_MERGE; clicon_debug(1, "%s", __FUNCTION__); if ((yspec = clicon_dbspec_yang(h)) == NULL){ @@ -372,6 +373,10 @@ snmp_scalar_set(clicon_handle h, /* Extended */ if (type_yang2asn1(ys, &asn1_type, 1) < 0) goto done; + if (asn1_type == CLIXON_ASN_ROWSTATUS){ + /* Must be done before type_snmp2xml: it translates asn1_type */ + rowstatus = 1; + } if ((ret = type_snmp2xml(ys, &asn1_type, requestvb, reqinfo, requests, &valstr)) < 0) goto done; if (ret == 0) @@ -394,6 +399,19 @@ snmp_scalar_set(clicon_handle h, goto done; } } + else if (strcmp(valstr, "destroy") == 0){ /* Remove entry */ + cxobj *xe; + cxobj *xa; + if ((xe = xml_parent(xbot)) != NULL){ + if ((xa = xml_new("operation", xe, CX_ATTR)) == NULL) + goto done; + if (xml_value_set(xa, "delete") < 0) + goto done; + if (xml_namespace_change(xa, NETCONF_BASE_NAMESPACE, NETCONF_BASE_PREFIX) < 0) + goto done; + op = OP_NONE; + } + } } if (xml_value_set(xb, valstr) < 0) goto done; @@ -403,7 +421,7 @@ snmp_scalar_set(clicon_handle h, } if (clixon_xml2cbuf(cb, xtop, 0, 0, -1, 0) < 0) goto done; - if (clicon_rpc_edit_config(h, db, OP_MERGE, cbuf_get(cb)) < 0) + if (clicon_rpc_edit_config(h, db, op, cbuf_get(cb)) < 0) goto done; ok: retval = 0; @@ -469,7 +487,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, NULL, "candidate", 0, reqinfo, requests) < 0) + if (snmp_scalar_set(sh->sh_h, sh->sh_ys, NULL, "candidate", reqinfo, requests) < 0) goto done; break; case MODE_SET_COMMIT: /* 3 */ @@ -805,7 +823,6 @@ snmp_table_set(clicon_handle h, if (snmp_scalar_set(h, ys, cvk_val, "candidate", - 1, reqinfo, requests) < 0) goto done; @@ -836,7 +853,6 @@ snmp_table_set(clicon_handle h, if (snmp_scalar_set(h, ys, cvk_val, "candidate", - 0, reqinfo, requests) < 0) goto done; @@ -846,20 +862,17 @@ snmp_table_set(clicon_handle h, if (snmp_scalar_set(h, ys, cvk_val, "candidate", - 0, reqinfo, requests) < 0) goto done; break; case 3: // notReady + case 6: // destroy if ((ret = netsnmp_request_set_error(requests, SNMP_ERR_INCONSISTENTVALUE)) != SNMPERR_SUCCESS){ clicon_err(OE_SNMP, ret, "netsnmp_request_set_error"); goto ok; } break; - case 6: // destroy - // XXX NYI - break; } } ok: diff --git a/apps/snmp/snmp_lib.c b/apps/snmp/snmp_lib.c index 68236ba7..694546f4 100644 --- a/apps/snmp/snmp_lib.c +++ b/apps/snmp/snmp_lib.c @@ -111,8 +111,6 @@ static const map_str2int snmp_type_map[] = { {NULL, -1} }; -#define CLIXON_ASN_PHYS_ADDR 253 /* Special case phy-address */ -#define CLIXON_ASN_FIXED_STRING 254 /* RFC2578 Sec 7.7: String-valued, fixed-length */ /* Map between clixon "orig" resolved type and ASN.1 types. */ @@ -127,6 +125,7 @@ static const map_str2int snmp_orig_map[] = { {"timestamp", ASN_TIMETICKS}, // 0x43 / 67 {"InetAddress", ASN_IPADDRESS}, // 0x40 / 64 (Dont see this being used) {"ipv4-address", ASN_IPADDRESS}, // 0x40 / 64 (This is used instead) + {"RowStatus", CLIXON_ASN_ROWSTATUS}, // 0x40 / 64 (This is used instead) {"phys-address", CLIXON_ASN_PHYS_ADDR}, /* Clixon extended string type */ {NULL, -1} }; @@ -442,7 +441,7 @@ type_yang2asn1(yang_stmt *ys, * First try original type, first type */ if ((at = clicon_str2int(snmp_orig_map, origtype)) >= 0 && - (extended || (at != CLIXON_ASN_PHYS_ADDR && at != CLIXON_ASN_FIXED_STRING))){ + (extended || (at < CLIXON_ASN_EXTRAS))){ ; } /* Then try fully resolved type */ @@ -522,6 +521,9 @@ type_snmp2xml(yang_stmt *ys, goto done; } switch (*asn1type){ + case CLIXON_ASN_ROWSTATUS: + *asn1type = ASN_INTEGER; + /* fall through */ case ASN_TIMETICKS: // 67 case ASN_INTEGER: // 2 if (cvtype == CGV_STRING){ /* special case for enum */ @@ -699,6 +701,9 @@ type_xml2snmp(char *snmpstr, goto done; } switch (*asn1type){ + case CLIXON_ASN_ROWSTATUS: + *asn1type = ASN_INTEGER; + /* fall through */ case ASN_INTEGER: // 2 *snmplen = 4; if ((*snmpval = malloc(*snmplen)) == NULL){ @@ -991,6 +996,7 @@ snmp_oid2str(oid **oidi, case ASN_COUNTER64: case ASN_COUNTER: case ASN_IPADDRESS: + case CLIXON_ASN_ROWSTATUS: cprintf(enc, "%lu", (*oidi)[i++]); break; case CLIXON_ASN_PHYS_ADDR: /* XXX may need special mapping: ether_aton() ? */ diff --git a/apps/snmp/snmp_lib.h b/apps/snmp/snmp_lib.h index fc47f1f0..5a96938c 100644 --- a/apps/snmp/snmp_lib.h +++ b/apps/snmp/snmp_lib.h @@ -48,7 +48,17 @@ extern "C" { #define CLIXON_ERR_SNMP_MIB 0x1000 #define IETF_YANG_SMIV2_NS "urn:ietf:params:xml:ns:yang:ietf-yang-smiv2" - + +/* Special case/extended Clixon ASN1 types + * Set in type_yang2asn1() if extended is true + * Must be back to proper net-snmp ASN_ types in type_snmp2xml and type_xml2snmp + * before calling netsnmp API +*/ +#define CLIXON_ASN_EXTRAS 253 /* Special case clixon address >= this */ +#define CLIXON_ASN_PHYS_ADDR 253 /* Special case phy-address */ +#define CLIXON_ASN_FIXED_STRING 254 /* RFC2578 Sec 7.7: String-valued, fixed-length */ +#define CLIXON_ASN_ROWSTATUS 255 + /* * Types */ diff --git a/test/test_snmp_rowstatus.sh b/test/test_snmp_rowstatus.sh index 687774fe..2ee7ea15 100755 --- a/test/test_snmp_rowstatus.sh +++ b/test/test_snmp_rowstatus.sh @@ -99,77 +99,86 @@ function testinit(){ function testrun_createAndGo() { - new "createAndGo" - + index=go + new "Configuring a value without a row is a failure" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'notify1\' = 2 2>&1)" 2 "Reason: inconsistentValue" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\' = 2 2>&1)" 2 "Reason: inconsistentValue" new "Set RowStatus to CreateAndGo and set tag" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\' = createAndGo SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'notify1\' = 2)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1' = INTEGER: createAndGo(4)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = createAndGo SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\' = 2)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: createAndGo(4)" new "Rowstatus is active" - expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1' = INTEGER: active(1)" + expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: active(1)" new "Get tag" - expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'notify1\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'notify1' = STRING: 2" + expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'$index' = STRING: 2" new "set storage type" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.\'notify1\' = 1)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'notify1' = INTEGER: other(1)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.\'$index\' = 1)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'$index' = INTEGER: other(1)" } function testrun_createAndWait() { - new "createAndWait" - + index=wait + + new "Configuring a value without a row is a failure" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\' = 2 2>&1)" 2 "Reason: inconsistentValue" + new "Set RowStatus to CreateAndWait and set tag" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\' = createAndWait SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'notify1\' = 2)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1' = INTEGER: createAndWait(5)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = createAndWait SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\' = 2)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: createAndWait(5)" new "Get tag" - expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'notify1\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'notify1' = STRING: 2" + expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'$index' = STRING: 2" new "Get rowstatus" - expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1' = INTEGER: notInService(2)" + expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: notInService(2)" new "Set storagetype" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.\'notify1\' = 1)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'notify1' = INTEGER: other(1)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.\'$index\' = 1)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'$index' = INTEGER: other(1)" new "Set rowstatus to active/ commit" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\' = active)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1' = INTEGER: active(1)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = active)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: active(1)" new "Set storagetype again" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.\'notify1\' = 5)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'notify1' = INTEGER: readOnly(5)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.\'$index\' = 5)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'$index' = INTEGER: readOnly(5)" new "Set rowstatus to createAndWait" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\' = createAndWait)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1' = INTEGER: createAndWait(5)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = createAndWait)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: createAndWait(5)" new "Set second rowstatus to createAndGo" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify2\' = createAndGo)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify2' = INTEGER: createAndGo(4)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'${index}2\' = createAndGo)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'${index}2' = INTEGER: createAndGo(4)" new "Set third rowstatus to createAndWait" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify3\' = createAndWait)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify3' = INTEGER: createAndWait(5)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'${index}3\' = createAndWait)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'${index}3' = INTEGER: createAndWait(5)" new "Set third rowstatus to active" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify3\' = active)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify3' = INTEGER: active(1)" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'${index}3\' = active)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'${index}3' = INTEGER: active(1)" new "Get rowstatus" - expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1' = INTEGER: notInService(2)" + expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: notInService(2)" } function testrun_removeRows() { - new "removeRows" + index=remove new "Set rowstatus to createandgo" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\' = createAndGo)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1'" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = createAndGo)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index'" new "Set rowstatus to destroy" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\' = destroy)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1' = destroy" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = destroy)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: destroy(6)" + new "Get rowstatus" + expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = No Such Instance currently exists at this OID" + + new "Set rowstatus to createandwait" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = createAndWait)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index'" + new "Set rowstatus to destroy" - expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'notify1'" + expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = destroy)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: destroy(6)" - new "get rowstatus" - expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'notify1\')" 0 "No Such Instance currently exists at this OID)" + new "Get rowstatus" + expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = No Such Instance currently exists at this OID" } function testexit() @@ -180,14 +189,14 @@ function testexit() new "SNMP tests" testinit +new "createAndGo" testrun_createAndGo +new "createAndWait" testrun_createAndWait -if $snmp_debug; then - # NYI - testrun_removeRows -fi +new "removeRows" +testrun_removeRows new "Cleaning up" testexit diff --git a/test/test_snmp_set.sh b/test/test_snmp_set.sh index b00f4e38..0d2d31bd 100755 --- a/test/test_snmp_set.sh +++ b/test/test_snmp_set.sh @@ -227,9 +227,19 @@ testrun ifPromiscuousMode INTEGER 1 1 true ${MIB}.1.10 # boolean testrun ifIpAddr IPADDRESS 1.2.3.4 1.2.3.4 1.2.3.4 ${MIB}.1.13 # InetAddress testrun ifPhysAddress STRING ff:ee:dd:cc:bb:aa ff:ee:dd:cc:bb:aa ff:ee:dd:cc:bb:aa ${IFMIB}.2.2.1.6.1 -if $snmp_debug; then # rowstatus - testrun ifStackStatus INTEGER 4 "createAndGo(4)" active ${IFMIB}.31.1.2.1.3.5.9 -fi +# Inline testrun for rowstatus complicated logic +name=ifStackStatus +type=INTEGER +oid=${IFMIB}.31.1.2.1.3.5.9 + +new "Set $name via SNMP" +expectpart "$($snmpset $oid i 4)" 0 "$type: createAndGo(4)" + +new "Check $name via SNMP" +expectpart "$($snmpget $oid)" 0 "$type: active(1)" + +new "Check $name via CLI" +expectpart "$($clixon_cli -1 -f $cfg show config xml)" 0 "<$name>active" new "Cleaning up" testexit