SNMP: fix SNMP set access of table entries

[Conversion of ethernet address (PhysAddress) and IP address (IPAddress) crashes agent](https://github.com/clicon/clixon/issues/340)
Hwaddress and IP adress for scalar and table set should now work
This commit is contained in:
Olof hagsand 2022-06-22 09:57:25 +02:00
parent fa87b7d59f
commit f6fe9f6a64
8 changed files with 335 additions and 94 deletions

View file

@ -111,7 +111,6 @@ snmp_common_handler(netsnmp_mib_handler *handler,
return retval; return retval;
} }
#ifdef SNMP_TABLE_DYNAMIC
/*! /*!
*/ */
static int static int
@ -193,7 +192,6 @@ snmp_scalar_return(cxobj *xs,
free(reason); free(reason);
return retval; 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
@ -233,7 +231,7 @@ snmp_scalar_get(clicon_handle h,
/* 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 */
if (snmp_yang2xpath(ys, cvk, &xpath) < 0) if (snmp_yang2xpath(ys, cvk, &xpath) < 0)
goto done; goto done;
/* Do the backend call */ /* Do the backend call */
@ -315,11 +313,13 @@ 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,
cvec *cvk,
netsnmp_agent_request_info *reqinfo, netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests) netsnmp_request_info *requests)
{ {
int retval = -1; int retval = -1;
char *api_path = NULL; char *api_path = NULL;
char *api_path_fmt = NULL;
cxobj *xtop = NULL; cxobj *xtop = NULL;
cxobj *xbot = NULL; cxobj *xbot = NULL;
cxobj *xb; cxobj *xb;
@ -328,6 +328,11 @@ snmp_scalar_set(clicon_handle h,
char *valstr = NULL; char *valstr = NULL;
cbuf *cb = NULL; cbuf *cb = NULL;
netsnmp_variable_list *requestvb = requests->requestvb; netsnmp_variable_list *requestvb = requests->requestvb;
cvec *cvk1;
int i;
int asn1_type;
clicon_debug(1, "%s", __FUNCTION__);
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");
@ -335,7 +340,16 @@ snmp_scalar_set(clicon_handle h,
} }
if ((xtop = xml_new(NETCONF_INPUT_CONFIG, NULL, CX_ELMNT)) == NULL) if ((xtop = xml_new(NETCONF_INPUT_CONFIG, NULL, CX_ELMNT)) == NULL)
goto done; goto done;
if (yang2api_path_fmt(ys, 0, &api_path) < 0) if (yang2api_path_fmt(ys, 0, &api_path_fmt) < 0)
goto done;
/* Need to prepend an element to fit api_path_fmt2api_path cvv parameter */
if ((cvk1 = cvec_new(1)) == NULL){
clicon_err(OE_UNIX, errno, "cvec_new");
goto done;
}
for (i=0; i<cvec_len(cvk); i++)
cvec_append_var(cvk1, cvec_i(cvk,i));
if (api_path_fmt2api_path(api_path_fmt, cvk1, &api_path, NULL) < 0)
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;
@ -345,7 +359,10 @@ snmp_scalar_set(clicon_handle h,
} }
if ((xb = xml_new("body", xbot, CX_BODY)) == NULL) if ((xb = xml_new("body", xbot, CX_BODY)) == NULL)
goto done; goto done;
if ((ret = type_snmp2xml(ys, requestvb, reqinfo, requests, &valstr)) < 0) /* Extended */
if (type_yang2asn1(ys, &asn1_type, 1) < 0)
goto done;
if ((ret = type_snmp2xml(ys, &asn1_type, requestvb, reqinfo, requests, &valstr)) < 0)
goto done; goto done;
if (ret == 0) if (ret == 0)
goto ok; goto ok;
@ -362,6 +379,10 @@ snmp_scalar_set(clicon_handle h,
ok: ok:
retval = 0; retval = 0;
done: done:
if (cvk1)
cvec_free(cvk1);
if (api_path_fmt)
free(api_path_fmt);
if (api_path) if (api_path)
free(api_path); free(api_path);
if (cb) if (cb)
@ -412,34 +433,33 @@ clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
clicon_debug(1, "%s Expected type:%d, got: %d", __FUNCTION__, requestvb->type, asn1_type); clicon_debug(1, "%s Expected type:%d, got: %d", __FUNCTION__, requestvb->type, asn1_type);
if ((ret = netsnmp_request_set_error(requests, SNMP_ERR_WRONGTYPE)) != SNMPERR_SUCCESS){ if ((ret = netsnmp_request_set_error(requests, SNMP_ERR_WRONGTYPE)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error"); clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto done; goto ok;
} }
} }
break; break;
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, reqinfo, requests) < 0) if (snmp_scalar_set(sh->sh_h, sh->sh_ys, NULL, reqinfo, requests) < 0)
goto done; goto done;
break; break;
case MODE_SET_UNDO: /* 5 */
if (clicon_rpc_discard_changes(sh->sh_h) < 0)
goto done;
break;
case MODE_SET_COMMIT: /* 3 */ case MODE_SET_COMMIT: /* 3 */
if (clicon_rpc_commit(sh->sh_h) < 0) if (clicon_rpc_commit(sh->sh_h) < 0)
goto done; goto done;
break; break;
case MODE_SET_FREE: /* 4 */ case MODE_SET_FREE: /* 4 */
break; break;
case MODE_SET_UNDO: /* 5 */
if (clicon_rpc_discard_changes(sh->sh_h) < 0)
goto done;
break;
} }
ok:
retval = SNMP_ERR_NOERROR; retval = SNMP_ERR_NOERROR;
done: done:
return retval; return retval;
} }
#ifdef SNMP_TABLE_DYNAMIC
/*! Create xpath from YANG table OID + 1 + n + cvk/key = requestvb->name /*! Create xpath from YANG table OID + 1 + n + cvk/key = requestvb->name
* Get yang of leaf from first part of OID * Get yang of leaf from first part of OID
* Create xpath with right keys from later part of OID * Create xpath with right keys from later part of OID
@ -556,6 +576,127 @@ snmp_table_get(clicon_handle h,
goto done; goto done;
} }
/*! Set value in table
* 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_set(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;
int ret;
int asn1_type;
netsnmp_variable_list *requestvb;
/* 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;
/* reset oid */
oidleaflen = MAX_OID_LEN;
if ((ret = yangext_oid_get(ys, oidleaf, &oidleaflen, NULL)) < 0)
goto done;
if (ret == 0)
goto done;
if (oidtlen + 1 != oidleaflen) /* Indexes may be from other OID scope, skip those */
continue;
if (oids[oidleaflen-1] == oidleaf[oidleaflen-1])
break;
}
if (ys == NULL){
/* No leaf with matching OID */
goto fail;
}
if (type_yang2asn1(ys, &asn1_type, 0) < 0)
goto done;
requestvb = requests->requestvb;
if (requestvb->type != asn1_type){
clicon_debug(1, "%s Expected type:%d, got: %d", __FUNCTION__, requestvb->type, asn1_type);
if ((ret = netsnmp_request_set_error(requests, SNMP_ERR_WRONGTYPE)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto ok;
}
}
/* 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;
}
/* read through keys and create cvk */
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;
}
if (snmp_scalar_set(h, ys,
cvk_val,
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. /*! Find "next" objct from oids minus key and return that.
* @param[in] h Clixon handle * @param[in] h Clixon handle
* @param[in] ylist Yang of table (of list type) * @param[in] ylist Yang of table (of list type)
@ -670,7 +811,6 @@ snmp_table_getnext(clicon_handle h,
xml_nsctx_free(nsc); xml_nsctx_free(nsc);
return retval; 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,...
@ -698,9 +838,7 @@ 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; 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)
@ -709,12 +847,9 @@ 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; requestvb = requests->requestvb;
#endif
switch(reqinfo->mode){ switch(reqinfo->mode){
case MODE_GET: // 160 case MODE_GET: // 160
#ifdef SNMP_TABLE_DYNAMIC
/* Create xpath from YANG table OID + 1 + n + cvk/key = requestvb->name /* Create xpath from YANG table OID + 1 + n + cvk/key = requestvb->name
*/ */
if ((ret = snmp_table_get(sh->sh_h, sh->sh_ys, if ((ret = snmp_table_get(sh->sh_h, sh->sh_ys,
@ -728,10 +863,8 @@ clixon_snmp_table_handler(netsnmp_mib_handler *handler,
} }
clicon_debug(1, "%s Nosuchinstance", __FUNCTION__); clicon_debug(1, "%s Nosuchinstance", __FUNCTION__);
} }
#endif
break; break;
case MODE_GETNEXT: // 161 case MODE_GETNEXT: // 161
#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 ((ret = snmp_table_getnext(sh->sh_h, sh->sh_ys, if ((ret = snmp_table_getnext(sh->sh_h, sh->sh_ys,
requestvb->name, requestvb->name_length, requestvb->name, requestvb->name_length,
@ -746,14 +879,35 @@ clixon_snmp_table_handler(netsnmp_mib_handler *handler,
} }
clicon_debug(1, "%s No such object", __FUNCTION__); clicon_debug(1, "%s No such object", __FUNCTION__);
} }
#endif
break; break;
case MODE_SET_RESERVE1: case MODE_SET_RESERVE1: // 0
case MODE_SET_RESERVE2: // Check types: compare type in requestvb to yang type (or do later)
case MODE_SET_ACTION: break;
case MODE_SET_COMMIT: case MODE_SET_RESERVE2: // 1
break;
case MODE_SET_ACTION: // 2
if ((ret = snmp_table_set(sh->sh_h, sh->sh_ys,
requestvb->name, requestvb->name_length,
reqinfo, requests)) < 0)
goto done;
if (ret == 0){
if ((ret = netsnmp_request_set_error(requests, SNMP_NOSUCHINSTANCE)) != SNMPERR_SUCCESS){
clicon_err(OE_SNMP, ret, "netsnmp_request_set_error");
goto done;
}
clicon_debug(1, "%s Nosuchinstance", __FUNCTION__);
}
break;
case MODE_SET_COMMIT: // 3
if (clicon_rpc_commit(sh->sh_h) < 0)
goto done;
break;
case MODE_SET_FREE: // 4
break;
case MODE_SET_UNDO : // 5
if (clicon_rpc_discard_changes(sh->sh_h) < 0)
goto done;
break; break;
} }
ok: ok:
retval = SNMP_ERR_NOERROR; retval = SNMP_ERR_NOERROR;

View file

@ -58,6 +58,9 @@
#include <signal.h> #include <signal.h>
#include <assert.h> #include <assert.h>
#include <sys/types.h> #include <sys/types.h>
#include <sys/socket.h>
#include <netinet/in.h> /* inet_addr */
#include <arpa/inet.h>
#include <netinet/ether.h> /* ether_aton */ #include <netinet/ether.h> /* ether_aton */
/* net-snmp */ /* net-snmp */
@ -104,6 +107,7 @@ static const map_str2int snmp_type_map[] = {
{"uint32", ASN_TIMETICKS}, // 0x43 / 67 {"uint32", ASN_TIMETICKS}, // 0x43 / 67
{"uint64", ASN_COUNTER64}, // 0x46 / 70 {"uint64", ASN_COUNTER64}, // 0x46 / 70
{"boolean", ASN_INTEGER}, // 2 special case -> enumeration {"boolean", ASN_INTEGER}, // 2 special case -> enumeration
{"string", ASN_IPADDRESS}, // 64
{NULL, -1} {NULL, -1}
}; };
@ -467,10 +471,11 @@ type_yang2asn1(yang_stmt *ys,
* @retval 1 OK, and valstr set * @retval 1 OK, and valstr set
* @retval 0 Invalid value or type * @retval 0 Invalid value or type
* @retval -1 Error * @retval -1 Error
* @see type_xml2snmpstr for snmpget * @see type_xml2snmp for snmpget
*/ */
int int
type_snmp2xml(yang_stmt *ys, type_snmp2xml(yang_stmt *ys,
int *asn1type,
netsnmp_variable_list *requestvb, netsnmp_variable_list *requestvb,
netsnmp_agent_request_info *reqinfo, netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests, netsnmp_request_info *requests,
@ -481,6 +486,7 @@ type_snmp2xml(yang_stmt *ys,
enum cv_type cvtype; enum cv_type cvtype;
cg_var *cv = NULL; cg_var *cv = NULL;
char *restype = NULL; /* resolved type */ char *restype = NULL; /* resolved type */
char *origtype = NULL; /* original type */
yang_stmt *yrestype = NULL; yang_stmt *yrestype = NULL;
int ret; int ret;
@ -489,9 +495,12 @@ type_snmp2xml(yang_stmt *ys,
clicon_err(OE_UNIX, EINVAL, "valstr is NULL"); clicon_err(OE_UNIX, EINVAL, "valstr is NULL");
goto done; goto done;
} }
cvstr = (char*)clicon_int2str(snmp_type_map, requestvb->type); if ((cvstr = (char*)clicon_int2str(snmp_type_map, requestvb->type)) == NULL){
clicon_err(OE_XML, 0, "No mapping for snmp type %d", requestvb->type);
goto done;
}
/* Get yang type of leaf and trasnslate to ASN.1 */ /* Get yang type of leaf and trasnslate to ASN.1 */
if (snmp_yang_type_get(ys, NULL, NULL, &yrestype, &restype) < 0) if (snmp_yang_type_get(ys, NULL, &origtype, &yrestype, &restype) < 0)
goto done; goto done;
/* 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)
@ -503,7 +512,7 @@ type_snmp2xml(yang_stmt *ys,
clicon_err(OE_UNIX, errno, "cv_new"); clicon_err(OE_UNIX, errno, "cv_new");
goto done; goto done;
} }
switch (requestvb->type){ switch (*asn1type){
case ASN_TIMETICKS: // 67 case ASN_TIMETICKS: // 67
case ASN_INTEGER: // 2 case ASN_INTEGER: // 2
if (cvtype == CGV_STRING){ /* special case for enum */ if (cvtype == CGV_STRING){ /* special case for enum */
@ -534,9 +543,19 @@ type_snmp2xml(yang_stmt *ys,
case ASN_GAUGE: // 0x42 case ASN_GAUGE: // 0x42
cv_uint32_set(cv, *requestvb->val.integer); cv_uint32_set(cv, *requestvb->val.integer);
break; break;
case CLIXON_ASN_ADMIN_STRING: // XXX case ASN_IPADDRESS:{
case CLIXON_ASN_PHYS_ADDR: // XXX struct in_addr addr;
assert(0); memcpy(&addr.s_addr, requestvb->val.string, 4);
cv_string_set(cv, inet_ntoa(addr));
break;
}
case CLIXON_ASN_ADMIN_STRING:
cv_string_set(cv, (char*)requestvb->val.string);
*asn1type = ASN_OCTET_STR;
break;
case CLIXON_ASN_PHYS_ADDR:
cv_string_set(cv, ether_ntoa((const struct ether_addr *)requestvb->val.string));
*asn1type = ASN_OCTET_STR;
break; break;
case ASN_OCTET_STR: // 4 case ASN_OCTET_STR: // 4
cv_string_set(cv, (char*)requestvb->val.string); cv_string_set(cv, (char*)requestvb->val.string);
@ -567,6 +586,8 @@ type_snmp2xml(yang_stmt *ys,
retval = 1; retval = 1;
done: done:
clicon_debug(2, "%s %d", __FUNCTION__, retval); clicon_debug(2, "%s %d", __FUNCTION__, retval);
if (origtype)
free(origtype);
if (cv) if (cv)
cv_free(cv); cv_free(cv);
return retval; return retval;
@ -734,6 +755,17 @@ type_xml2snmp(char *snmpstr,
goto fail; goto fail;
} }
break; break;
case ASN_IPADDRESS:{
in_addr_t saddr;
*snmplen = 4;
if ((*snmpval = malloc(*snmplen)) == NULL){
clicon_err(OE_UNIX, errno, "malloc");
goto done;
}
saddr = (int32_t)inet_addr(snmpstr);
memcpy(*snmpval, &saddr, 4);
break;
}
case CLIXON_ASN_PHYS_ADDR:{ case CLIXON_ASN_PHYS_ADDR:{
struct ether_addr *eaddr; struct ether_addr *eaddr;
*snmplen = sizeof(*eaddr); *snmplen = sizeof(*eaddr);

View file

@ -81,6 +81,7 @@ void *snmp_handle_clone(void *arg);
void snmp_handle_free(void *arg); void snmp_handle_free(void *arg);
int type_yang2asn1(yang_stmt *ys, int *asn1_type, int extended); int type_yang2asn1(yang_stmt *ys, int *asn1_type, int extended);
int type_snmp2xml(yang_stmt *ys, int type_snmp2xml(yang_stmt *ys,
int *asn1type,
netsnmp_variable_list *requestvb, netsnmp_variable_list *requestvb,
netsnmp_agent_request_info *reqinfo, netsnmp_agent_request_info *reqinfo,
netsnmp_request_info *requests, netsnmp_request_info *requests,

View file

@ -459,11 +459,6 @@ mibyang_traverse(clicon_handle h,
/* Register table entry handler itself (not column/row leafs) */ /* Register table entry handler itself (not column/row leafs) */
if (mibyang_table_register(h, yn) < 0) if (mibyang_table_register(h, yn) < 0)
goto done; goto done;
#ifndef SNMP_TABLE_DYNAMIC
/* Register table sub-oid:s of existing entries in clixon */
if (mibyang_table_poll(h, yn) < 0)
goto done;
#endif
goto ok; goto ok;
} }
break; break;

View file

@ -163,3 +163,4 @@
* If not set, client will exit * If not set, client will exit
*/ */
#define PROTO_RESTART_RECONNECT #define PROTO_RESTART_RECONNECT

View file

@ -426,7 +426,7 @@ yang2api_path_fmt(yang_stmt *ys,
* @param[in] api_path_fmt XML key format, eg /aaa/%s/name * @param[in] api_path_fmt XML key format, eg /aaa/%s/name
* @param[in] cvv cligen variable vector, one for every wildchar in api_path_fmt * @param[in] cvv cligen variable vector, one for every wildchar in api_path_fmt
* @param[out] api_path api_path, eg /aaa/17. Free after use * @param[out] api_path api_path, eg /aaa/17. Free after use
* @param[out] cvvi 1..cvv-len. Index into cvv of last cvv entry used, For example, * @param[out] cvv_i 1..cvv-len. Index into cvv of last cvv entry used, For example,
* if same as len of cvv, all were used, if < some entries were not * if same as len of cvv, all were used, if < some entries were not
* @retval 0 OK * @retval 0 OK
* @retval -1 Error * @retval -1 Error

View file

@ -214,7 +214,15 @@ ifStackStatus OBJECT-TYPE
interfaces, and many implementations will choose not to interfaces, and many implementations will choose not to
support write-access for any type of interface." support write-access for any type of interface."
::= { clixonExampleScalars 12 } ::= { clixonExampleScalars 12 }
ifIpAddr OBJECT-TYPE
SYNTAX InetAddress
MAX-ACCESS read-write
STATUS current
DESCRIPTION
"Example IP"
::= { clixonExampleScalars 13 }
-- --
-- Example Tables -- Example Tables
-- --
@ -265,6 +273,7 @@ nsIETFWGChair2 OBJECT-TYPE
"The other name, if one exists, of the chairs for the IETF "The other name, if one exists, of the chairs for the IETF
working group." working group."
::= { clixonIETFWGEntry 3 } ::= { clixonIETFWGEntry 3 }
-- --
-- A table used in a table_iterator example -- A table used in a table_iterator example
-- (agent/mibgroup/examples/clixonHostsTable*.[ch]) -- (agent/mibgroup/examples/clixonHostsTable*.[ch])

View file

@ -5,7 +5,7 @@
# Magic line must be first in script (see README.md) # Magic line must be first in script (see README.md)
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
APPNAME=snmp APPNAME=example
# XXX skip for now # XXX skip for now
if [ ${ENABLE_NETSNMP} != "yes" ]; then if [ ${ENABLE_NETSNMP} != "yes" ]; then
@ -17,7 +17,7 @@ snmpd=$(type -p snmpd)
snmpget="$(type -p snmpget) -On -c public -v2c localhost " snmpget="$(type -p snmpget) -On -c public -v2c localhost "
snmpset="$(type -p snmpset) -On -c public -v2c localhost " snmpset="$(type -p snmpset) -On -c public -v2c localhost "
cfg=$dir/conf_startup.xml cfg=$dir/conf.xml
fyang=$dir/clixon-example.yang fyang=$dir/clixon-example.yang
# AgentX unix socket # AgentX unix socket
@ -35,7 +35,12 @@ cat <<EOF > $cfg
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR> <CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
<CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK> <CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK>
<CLICON_SNMP_MIB>CLIXON-TYPES-MIB</CLICON_SNMP_MIB> <CLICON_SNMP_MIB>CLIXON-TYPES-MIB</CLICON_SNMP_MIB>
<CLICON_SNMP_MIB>IF-MIB</CLICON_SNMP_MIB>
<CLICON_VALIDATE_STATE_XML>true</CLICON_VALIDATE_STATE_XML> <CLICON_VALIDATE_STATE_XML>true</CLICON_VALIDATE_STATE_XML>
<CLICON_FEATURE>ietf-netconf:startup</CLICON_FEATURE>
<CLICON_CLI_MODE>$APPNAME</CLICON_CLI_MODE>
<CLICON_CLI_DIR>/usr/local/lib/$APPNAME/cli</CLICON_CLI_DIR>
<CLICON_CLISPEC_DIR>/usr/local/lib/$APPNAME/clispec</CLICON_CLISPEC_DIR>
</clixon-config> </clixon-config>
EOF EOF
@ -47,14 +52,48 @@ module clixon-example{
import CLIXON-TYPES-MIB { import CLIXON-TYPES-MIB {
prefix "clixon-types"; prefix "clixon-types";
} }
import IF-MIB {
prefix "if-mib";
}
deviation "/clixon-types:CLIXON-TYPES-MIB" { deviation "/clixon-types:CLIXON-TYPES-MIB" {
deviate replace { deviate replace {
config true; config true;
} }
} }
deviation "/if-mib:IF-MIB" {
deviate replace {
config true;
}
}
} }
EOF EOF
if true; then # Dont start with a state (default)
cat <<EOF > $dir/startup_db
EOF
else # Start with a state (debug)
cat <<EOF > $dir/startup_db
<${DATASTORE_TOP}>
<CLIXON-TYPES-MIB xmlns="urn:ietf:params:xml:ns:yang:smiv2:CLIXON-TYPES-MIB">
<clixonExampleScalars>
<clixonExampleInteger>42</clixonExampleInteger>
<ifIpAddr>4.3.2.1</ifIpAddr>
</clixonExampleScalars>
</CLIXON-TYPES-MIB>
<IF-MIB xmlns="urn:ietf:params:xml:ns:yang:smiv2:IF-MIB">
<ifTable>
<ifEntry>
<ifIndex>1</ifIndex>
<ifPhysAddress>aa:bb:cc:dd:ee:ff</ifPhysAddress>
</ifEntry>
</ifTable>
</IF-MIB>
</${DATASTORE_TOP}>
EOF
fi
function testinit(){ function testinit(){
new "test params: -f $cfg" new "test params: -f $cfg"
@ -69,7 +108,7 @@ function testinit(){
sudo pkill -f clixon_backend sudo pkill -f clixon_backend
new "Starting backend" new "Starting backend"
start_backend -s init -f $cfg start_backend -s startup -f $cfg
fi fi
new "wait backend" new "wait backend"
@ -88,6 +127,59 @@ function testinit(){
wait_snmp wait_snmp
} }
# Set value via SNMP, read value via SNMP and CLI
# Args:
# 1: name
# 2: type
# 3: value SNMP value
# 4: xvalue XML/Clixon value
# 5: OID
function testrun()
{
name=$1
type=$2
value=$3
xvalue=$4
oid=$5
# Type from man snmpset
case $type in
"INTEGER")
set_type="i"
;;
"STRING")
set_type="s"
;;
"TIMETICKS")
set_type="t"
;;
"IPADDRESS")
set_type="a"
;;
*)
set_type="s"
;;
esac
new "Set $name via SNMP"
if [ $type == "STRING" ]; then
echo "$snmpset $oid $set_type $value"
expectpart "$($snmpset $oid $set_type $value)" 0 "$type:" "$value"
else
echo "$snmpset $oid $set_type $value"
expectpart "$($snmpset $oid $set_type $value)" 0 "$type: $value"
fi
new "Check $name via SNMP"
if [ $type == "STRING" ]; then
expectpart "$($snmpget $oid)" 0 "$type:" "$value"
else
expectpart "$($snmpget $oid)" 0 "$type: $value"
fi
new "Check $name via CLI"
expectpart "$($clixon_cli -1 -f $cfg show config xml)" 0 "<$name>$xvalue</$name>"
}
function testexit(){ function testexit(){
stop_snmp stop_snmp
} }
@ -95,59 +187,16 @@ function testexit(){
new "SNMP tests" new "SNMP tests"
testinit testinit
# NET-SNMP-EXAMPLES-MIB::netSnmpExamples
MIB=".1.3.6.1.4.1.8072.200" MIB=".1.3.6.1.4.1.8072.200"
OID1="${MIB}.1.1" # netSnmpExampleInteger IFMIB=".1.3.6.1.2.1"
OID2="${MIB}.1.2" # netSnmpExampleSleeper
OID3="${MIB}.1.3" # netSnmpExampleString
OID15="${MIB}.2.1.1.1" # nsIETFWGName testrun clixonExampleInteger INTEGER 1234 1234 ${MIB}.1.1
OID16="${MIB}.2.1.1.2" # nsIETFWGChair1 testrun clixonExampleSleeper INTEGER -1 -1 ${MIB}.1.2
OID17="${MIB}.2.1.1.3" # nsIETFWGChair2 testrun clixonExampleString STRING foobar foobar ${MIB}.1.3
OID18="${MIB}.2.2" # netSnmpHostsTable testrun ifPromiscuousMode INTEGER 1 true ${MIB}.1.10 # boolean
OID19="${MIB}.2.2.1.1" # netSnmpHostName testrun ifIpAddr IPADDRESS 1.2.3.4 1.2.3.4 ${MIB}.1.13 # InetAddress
OID20="${MIB}.2.2.1.2" # netSnmpHostAddressType
OID21="${MIB}.2.2.1.3" # netSnmpHostAddress
OID22="${MIB}.2.2.1.4" # netSnmpHostStorage
OID23="${MIB}.2.2.1.5" # netSnmpHostRowStatus
new "Setting netSnmpExampleInteger" testrun ifPhysAddress STRING ff:ee:dd:cc:bb:aa ff:ee:dd:cc:bb:aa ${IFMIB}.2.2.1.6.1 # active
validate_set $OID1 "INTEGER" 1234
validate_oid $OID1 $OID1 "INTEGER" 1234
new "Setting netSnmpExampleSleeper"
validate_set $OID2 "INTEGER" -1
validate_oid $OID2 $OID2 "INTEGER" -1
new "Set new value via NETCONF"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><edit-config><default-operation>none</default-operation><target><candidate/></target><config><CLIXON-TYPES-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:CLIXON-TYPES-MIB\"><clixonExampleScalars><clixonExampleInteger>999</clixonExampleInteger></clixonExampleScalars></CLIXON-TYPES-MIB></config></edit-config></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
new "netconf commit"
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><commit/></rpc>" "" "<rpc-reply $DEFAULTNS><ok/></rpc-reply>"
new "Validate value set from NETCONF"
validate_oid $OID1 $OID1 "INTEGER" 999
new "Setting netSnmpExampleString"
validate_oid $OID3 $OID3 "STRING" "\"So long, and thanks for all the fish!\""
validate_set $OID3 "STRING" "foo bar"
validate_oid $OID3 $OID3 "STRING" "\"foo bar\""
# new "Setting column nsIETFWGChair1"
# validate_set $OID16 "STRING" "asd"
# validate_oid $OID16 $OID16 "STRING" "asd"
# new "Setting column nsIETFWGChair2"
# validate_set $OID17 "STRING" "asd"
# validate_oid $OID17 $OID16 "STRING" "asdasd"
# new "Setting column netSnmpHostName"
# validate_set $OID19 "STRING" "asd"
# validate_oid $OID19 $OID19 "STRING" "asdasd"
# new "Setting netSnmpHostName"
# validate_set $OID20 "STRING" ipv6
# validate_oid $OID20 $OID20 "STRING" "asdasd"
new "Cleaning up" new "Cleaning up"
testexit testexit