Merge branch 'snmp'
This commit is contained in:
commit
1d78241115
47 changed files with 8494 additions and 46 deletions
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
|
|
@ -2,9 +2,9 @@ name: Clixon CI
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ master, http-data ]
|
||||
branches: [ master, snmp ]
|
||||
pull_request:
|
||||
branches: [ master, http-data ]
|
||||
branches: [ master, snmp ]
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
|
|
|||
16
CHANGELOG.md
16
CHANGELOG.md
|
|
@ -35,6 +35,20 @@
|
|||
* [3.3.2](#332) Aug 27 2017
|
||||
* [3.3.1](#331) June 7 2017
|
||||
|
||||
## SNMP branch
|
||||
|
||||
* Clixon SNMP frontend
|
||||
* Support of SNMP for retreiving and setting values via net-snmp using a MIB-YANG mapping defined in RFC6643.
|
||||
* For details, see [SNMP section of user manual](https://clixon-docs.readthedocs.io/en/latest/snmp.html)
|
||||
* YANG `clixon-config@2022-03-21.yang` changes:
|
||||
* Added options:
|
||||
* `CLICON_SNMP_AGENT_SOCK`
|
||||
* `CLICON_SNMP_MIB`
|
||||
* New configure options:
|
||||
* `--enable-netsnmp`
|
||||
* `--with-mib-generated-yang-dir=DIR`
|
||||
* Thanks to Siklu Communications LTD for sponsoring this work
|
||||
|
||||
## 5.8.0
|
||||
Planned: July 2022
|
||||
|
||||
|
|
@ -121,8 +135,6 @@ Developers may need to change their code
|
|||
The Clixon 5.7 release introduces (long overdue) NETCONF chunked framing as defined
|
||||
in RFC 6242. It also introduces a limited http data service and lots of bugfixes.
|
||||
|
||||
### New features
|
||||
|
||||
* Implementation of "chunked framing" according to RFC6242 for Netconf 1.1.
|
||||
* First hello is 1.0 EOM framing, then successing rpc is chunked framing
|
||||
* See
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ VPATH = @srcdir@
|
|||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
with_restconf = @with_restconf@
|
||||
enable_netsnmp = @enable_netsnmp@
|
||||
|
||||
SHELL = /bin/sh
|
||||
|
||||
|
|
@ -47,6 +48,11 @@ SUBDIRS += netconf
|
|||
ifdef with_restconf
|
||||
SUBDIRS += restconf
|
||||
endif
|
||||
ifdef enable_netsnmp
|
||||
ifeq ($(enable_netsnmp),yes)
|
||||
SUBDIRS += snmp
|
||||
endif
|
||||
endif
|
||||
|
||||
.PHONY: all clean depend install $(SUBDIRS)
|
||||
|
||||
|
|
|
|||
|
|
@ -453,7 +453,7 @@ usage(clicon_handle h,
|
|||
"\t-p <dir>\tAdd Yang directory path (see CLICON_YANG_DIR)\n"
|
||||
"\t-b <dir>\tSpecify datastore directory\n"
|
||||
"\t-F\t\tRun in foreground, do not run as daemon\n"
|
||||
"\t-z\t\tKill other config daemon and exit\n"
|
||||
"\t-z\t\tKill other backend daemon and exit\n"
|
||||
"\t-a UNIX|IPv4|IPv6 Internal backend socket family\n"
|
||||
"\t-u <path|addr>\tInternal socket domain path or IP addr (see -a)(default: %s)\n"
|
||||
"\t-P <file>\tPid filename (default: %s)\n"
|
||||
|
|
@ -1004,7 +1004,7 @@ main(int argc,
|
|||
goto done;
|
||||
|
||||
/* Write pid-file */
|
||||
if ((pid = pidfile_write(pidfile)) < 0)
|
||||
if (pidfile_write(pidfile) < 0)
|
||||
goto done;
|
||||
|
||||
if (set_signal(SIGTERM, backend_sig_term, NULL) < 0){
|
||||
|
|
|
|||
|
|
@ -861,7 +861,7 @@ cli_show_options(clicon_handle h,
|
|||
else
|
||||
fprintf(stdout, "%s: NULL\n", keys[i]);
|
||||
}
|
||||
/* Next print CLICON_FEATURE and CLICON_YANG_DIR from config tree
|
||||
/* Next print CLICON_FEATURE, CLICON_YANG_DIR and CLICON_SNMP_MIB from config tree
|
||||
* Since they are lists they are placed in the config tree.
|
||||
*/
|
||||
x = NULL;
|
||||
|
|
@ -876,6 +876,12 @@ cli_show_options(clicon_handle h,
|
|||
continue;
|
||||
fprintf(stdout, "%s: \"%s\"\n", xml_name(x), xml_body(x));
|
||||
}
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(clicon_conf_xml(h), x, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(x), "CLICON_SNMP_MIB") != 0)
|
||||
continue;
|
||||
fprintf(stdout, "%s: \"%s\"\n", xml_name(x), xml_body(x));
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (keys)
|
||||
|
|
|
|||
134
apps/snmp/Makefile.in
Normal file
134
apps/snmp/Makefile.in
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#
|
||||
# ***** BEGIN LICENSE BLOCK *****
|
||||
#
|
||||
# Copyright (C) 2022 Olof Hagsand and Kristofer Hallin
|
||||
#
|
||||
# This file is part of CLIXON
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
# You may obtain a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
#
|
||||
# Alternatively, the contents of this file may be used under the terms of
|
||||
# the GNU General Public License Version 3 or later (the "GPL"),
|
||||
# in which case the provisions of the GPL are applicable instead
|
||||
# of those above. If you wish to allow use of your version of this file only
|
||||
# under the terms of the GPL, and not to allow others to
|
||||
# use your version of this file under the terms of Apache License version 2,
|
||||
# indicate your decision by deleting the provisions above and replace them with
|
||||
# the notice and other provisions required by the GPL. If you do not delete
|
||||
# the provisions above, a recipient may use your version of this file under
|
||||
# the terms of any one of the Apache License version 2 or the GPL.
|
||||
#
|
||||
# ***** END LICENSE BLOCK *****
|
||||
#
|
||||
#
|
||||
VPATH = @srcdir@
|
||||
srcdir = @srcdir@
|
||||
top_srcdir = @top_srcdir@
|
||||
CC = @CC@
|
||||
CFLAGS = @CFLAGS@
|
||||
LINKAGE = @LINKAGE@
|
||||
INSTALLFLAGS = @INSTALLFLAGS@
|
||||
LDFLAGS = @LDFLAGS@
|
||||
|
||||
prefix = @prefix@
|
||||
datarootdir = @datarootdir@
|
||||
exec_prefix = @exec_prefix@
|
||||
bindir = @bindir@
|
||||
libdir = @libdir@
|
||||
sbindir = @sbindir@
|
||||
mandir = @mandir@
|
||||
libexecdir = @libexecdir@
|
||||
localstatedir = @localstatedir@
|
||||
sysconfdir = @sysconfdir@
|
||||
includedir = @includedir@
|
||||
HOST_VENDOR = @host_vendor@
|
||||
|
||||
SH_SUFFIX = @SH_SUFFIX@
|
||||
LIBSTATIC_SUFFIX = @LIBSTATIC_SUFFIX@
|
||||
CLIXON_MAJOR = @CLIXON_VERSION_MAJOR@
|
||||
CLIXON_MINOR = @CLIXON_VERSION_MINOR@
|
||||
|
||||
# Use this clixon lib for linking
|
||||
ifeq ($(LINKAGE),dynamic)
|
||||
CLIXON_LIB = libclixon$(SH_SUFFIX).$(CLIXON_MAJOR).$(CLIXON_MINOR)
|
||||
else
|
||||
CLIXON_LIB = libclixon$(LIBSTATIC_SUFFIX)
|
||||
endif
|
||||
|
||||
# For dependency
|
||||
LIBDEPS = $(top_srcdir)/lib/src/$(CLIXON_LIB)
|
||||
|
||||
LIBS = -L$(top_srcdir)/lib/src $(top_srcdir)/lib/src/$(CLIXON_LIB) @LIBS@
|
||||
|
||||
CPPFLAGS = @CPPFLAGS@
|
||||
|
||||
ifeq ($(LINKAGE),dynamic)
|
||||
CPPFLAGS += -fPIC
|
||||
endif
|
||||
|
||||
INCLUDES = -I. -I$(top_srcdir)/lib/src -I$(top_srcdir)/lib -I$(top_srcdir)/include -I$(top_srcdir) @INCLUDES@
|
||||
|
||||
# Application
|
||||
APPL = clixon_snmp
|
||||
|
||||
# Common source - not accessible from plugin - independent of restconf package (fcgi|native)
|
||||
APPSRC =
|
||||
APPSRC += snmp_main.c
|
||||
APPSRC += snmp_register.c
|
||||
APPSRC += snmp_handler.c
|
||||
APPSRC += snmp_lib.c
|
||||
|
||||
APPOBJ = $(APPSRC:.c=.o)
|
||||
|
||||
all: $(APPL)
|
||||
|
||||
# Dependency of clixon library (LIBDEPS)
|
||||
$(top_srcdir)/lib/src/$(CLIXON_LIB):
|
||||
(cd $(top_srcdir)/lib/src && $(MAKE) $(MFLAGS) $(CLIXON_LIB))
|
||||
|
||||
clean:
|
||||
rm -f *.core $(APPL) $(APPOBJ) *.o
|
||||
rm -f *.gcda *.gcno *.gcov # coverage
|
||||
|
||||
distclean: clean
|
||||
rm -f Makefile *~ .depend
|
||||
|
||||
# Put daemon in bin
|
||||
# Put other executables in libexec/
|
||||
install: $(APPL)
|
||||
install -d -m 0755 $(DESTDIR)$(sbindir)
|
||||
install -m 0755 $(INSTALLFLAGS) $(APPL) $(DESTDIR)$(sbindir)
|
||||
|
||||
install-include:
|
||||
|
||||
uninstall:
|
||||
rm -f $(DESTDIR)$(sbindir)/$(APPL)
|
||||
|
||||
.SUFFIXES:
|
||||
.SUFFIXES: .c .o
|
||||
|
||||
.c.o:
|
||||
$(CC) $(INCLUDES) -D__PROGRAM__=\"clixon_snmp\" $(CPPFLAGS) $(CFLAGS) -c $<
|
||||
|
||||
$(APPL) : $(APPOBJ) $(LIBDEPS)
|
||||
echo $(APPOBJ)
|
||||
echo $(LIBDEPS)
|
||||
$(CC) $(LDFLAGS) $^ $(LIBS) -o $@
|
||||
|
||||
TAGS:
|
||||
find . -name '*.[chyl]' -print | etags -
|
||||
|
||||
depend:
|
||||
$(CC) $(DEPENDFLAGS) @DEFS@ $(INCLUDES) $(CFLAGS) -MM $(APPFCGI) $(APPSRC) > .depend
|
||||
|
||||
#include .depend
|
||||
1360
apps/snmp/snmp_handler.c
Normal file
1360
apps/snmp/snmp_handler.c
Normal file
File diff suppressed because it is too large
Load diff
61
apps/snmp/snmp_handler.h
Normal file
61
apps/snmp/snmp_handler.h
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2022 Olof Hagsand and Kristofer Hallin
|
||||
Sponsored by Siklu Communications LTD
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _SNMP_HANDLER_H_
|
||||
#define _SNMP_HANDLER_H_
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int clixon_snmp_table_handler(netsnmp_mib_handler *handler,
|
||||
netsnmp_handler_registration *nhreg,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests);
|
||||
int clixon_snmp_scalar_handler(netsnmp_mib_handler *handler,
|
||||
netsnmp_handler_registration *nhreg,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests);
|
||||
|
||||
#endif /* _SNMP_HANDLER_H_ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
1208
apps/snmp/snmp_lib.c
Normal file
1208
apps/snmp/snmp_lib.c
Normal file
File diff suppressed because it is too large
Load diff
117
apps/snmp/snmp_lib.h
Normal file
117
apps/snmp/snmp_lib.h
Normal file
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2022 Olof Hagsand and Kristofer Hallin
|
||||
Sponsored by Siklu Communications LTD
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _SNMP_LIB_H_
|
||||
#define _SNMP_LIB_H_
|
||||
|
||||
/*
|
||||
* Constants
|
||||
*/
|
||||
/* Need some way to multiplex SNMP_ and MIB errors on OE_SNMP error handler */
|
||||
#define CLIXON_ERR_SNMP_MIB 0x1000
|
||||
|
||||
#define IETF_YANG_SMIV2_NS "urn:ietf:params:xml:ns:yang:ietf-yang-smiv2"
|
||||
|
||||
/* 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
|
||||
*/
|
||||
/* Userdata to pass around in netsmp callbacks
|
||||
*/
|
||||
struct clixon_snmp_handle {
|
||||
clicon_handle sh_h;
|
||||
yang_stmt *sh_ys; /* Leaf for scalar, list for table */
|
||||
oid sh_oid[MAX_OID_LEN]; /* OID for debug, may be removed? */
|
||||
size_t sh_oidlen;
|
||||
char *sh_default; /* MIB default value leaf only */
|
||||
cvec *sh_cvk_orig; /* Index/Key variable values (original) */
|
||||
netsnmp_table_registration_info *sh_table_info; /* To mimic table-handler in libnetsnmp code
|
||||
* save only to free properly */
|
||||
};
|
||||
typedef struct clixon_snmp_handle clixon_snmp_handle;
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int oid_eq(const oid * objid0, size_t objid0len, const oid * objid1, size_t objid1len);
|
||||
int oid_append(const oid *objid0, size_t *objid0len, const oid *objid1, size_t objid1len);
|
||||
int oid_cbuf(cbuf *cb, const oid *objid, size_t objidlen);
|
||||
int oid_print(FILE *f, const oid *objid, size_t objidlen);
|
||||
int snmp_yang_type_get(yang_stmt *ys, yang_stmt **yrefp, char **origtypep, yang_stmt **yrestypep, char **restypep);
|
||||
int yangext_oid_get(yang_stmt *yn, oid *objid, size_t *objidlen, char **objidstr);
|
||||
int snmp_access_str2int(char *modes_str);
|
||||
const char *snmp_msg_int2str(int msg);
|
||||
void *snmp_handle_clone(void *arg);
|
||||
void snmp_handle_free(void *arg);
|
||||
int type_yang2asn1(yang_stmt *ys, int *asn1_type, int extended);
|
||||
int type_snmp2xml(yang_stmt *ys,
|
||||
int *asn1type,
|
||||
netsnmp_variable_list *requestvb,
|
||||
netsnmp_agent_request_info *reqinfo,
|
||||
netsnmp_request_info *requests,
|
||||
char **valstr);
|
||||
int type_xml2snmp_pre(char *xmlstr, yang_stmt *ys, char **snmpstr);
|
||||
int type_xml2snmp(char *snmpstr, int *asn1type, u_char **snmpval, size_t *snmplen, char **reason);
|
||||
int snmp_yang2xpath(yang_stmt *ys, cvec *keyvec, char **xpath);
|
||||
int snmp_str2oid(char *str, yang_stmt *yi, oid *objid, size_t *objidlen);
|
||||
int snmp_oid2str(oid **oidi, size_t *oidilen, yang_stmt *yi, cg_var *cv);
|
||||
int clixon_snmp_err_cb(void *handle, int suberr, cbuf *cb);
|
||||
int snmp_xmlkey2val_oid(cxobj *xrow, cvec *cvk_name, cvec **cvk_orig, oid *objidk, size_t *objidklen);
|
||||
|
||||
/*========== libnetsnmp-specific code =============== */
|
||||
int clixon_snmp_api_agent_check(void);
|
||||
int clixon_snmp_api_agent_cleanup(void);
|
||||
int clixon_snmp_api_oid_find(oid *oid1, size_t oidlen);
|
||||
|
||||
#endif /* _SNMP_LIB_H_ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
550
apps/snmp/snmp_main.c
Normal file
550
apps/snmp/snmp_main.c
Normal file
|
|
@ -0,0 +1,550 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2022 Olof Hagsand and Kristofer Hallin
|
||||
Sponsored by Siklu Communications LTD
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
* This is the clixon_snmp daemon
|
||||
* It assumes a netsnmp damon is running.
|
||||
* - If netsnmp does not run, clixon_snmp will not start
|
||||
* - If netsnmp dies, clixon_snmp will exit
|
||||
* - If netsnmp is restarted, clixon_snmp should also be restarted
|
||||
* It is possible to be more resilient, such as setting a timer and trying again, in fact, libnetsnmp
|
||||
* has some such mechanisms but these are NOT implemented
|
||||
* @see RFC 6643 Translation of Structure of Management Information Version 2 (SMIv2)
|
||||
* MIB Modules to YANG Modules
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
/* net-snmp */
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#include "snmp_lib.h"
|
||||
#include "snmp_register.h"
|
||||
|
||||
/* Command line options to be passed to getopt(3) */
|
||||
#define SNMP_OPTS "hD:f:l:o:z"
|
||||
|
||||
/* Forward */
|
||||
static int clixon_snmp_input_cb(int s, void *arg);
|
||||
|
||||
/*! Return (hardcoded) pid file
|
||||
*/
|
||||
static char*
|
||||
clicon_snmp_pidfile(clicon_handle h)
|
||||
{
|
||||
return "/var/tmp/clixon_snmp.pid";
|
||||
}
|
||||
|
||||
/*! Signal terminates process
|
||||
* Just set exit flag for proper exit in event loop
|
||||
*/
|
||||
static void
|
||||
clixon_snmp_sig_term(int arg)
|
||||
{
|
||||
clicon_log(LOG_NOTICE, "%s: %s: pid: %u Signal %d",
|
||||
__PROGRAM__, __FUNCTION__, getpid(), arg);
|
||||
/* This should ensure no more accepts or incoming packets are processed because next time eventloop
|
||||
* is entered, it will terminate.
|
||||
* However there may be a case of sockets closing rather abruptly for clients
|
||||
*/
|
||||
clixon_exit_set(1);
|
||||
}
|
||||
|
||||
/*! Clean and close all state of netconf process (but dont exit).
|
||||
* Cannot use h after this
|
||||
* @param[in] h Clixon handle
|
||||
*/
|
||||
static int
|
||||
snmp_terminate(clicon_handle h)
|
||||
{
|
||||
yang_stmt *yspec;
|
||||
cvec *nsctx;
|
||||
cxobj *x = NULL;
|
||||
char *pidfile = clicon_snmp_pidfile(h);
|
||||
|
||||
snmp_shutdown(__FUNCTION__);
|
||||
shutdown_agent();
|
||||
clixon_snmp_api_agent_cleanup();
|
||||
if (clicon_ptr_get(h, "snmp-rowstatus-tree", (void**)&x) == 0 && x){
|
||||
xml_free(x);
|
||||
x = NULL;
|
||||
}
|
||||
clicon_rpc_close_session(h);
|
||||
if ((yspec = clicon_dbspec_yang(h)) != NULL)
|
||||
ys_free(yspec);
|
||||
if ((yspec = clicon_config_yang(h)) != NULL)
|
||||
ys_free(yspec);
|
||||
if ((nsctx = clicon_nsctx_global_get(h)) != NULL)
|
||||
cvec_free(nsctx);
|
||||
if ((x = clicon_conf_xml(h)) != NULL)
|
||||
xml_free(x);
|
||||
xpath_optimize_exit();
|
||||
clixon_event_exit();
|
||||
clicon_handle_exit(h);
|
||||
clixon_err_exit();
|
||||
clicon_log_exit();
|
||||
if (pidfile)
|
||||
unlink(pidfile);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*! Get which sockets are used from SNMP API, the register single sockets into clixon event system
|
||||
*
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] register if 1 register snmp sockets with event handler. If 0 close and unregister
|
||||
* This is a workaround for netsnmps API usiing fdset:s, instead an fdset is created before calling
|
||||
* the snmp api
|
||||
* if you use select(), see snmp_select_info() in snmp_api(3)
|
||||
* snmp_select_info(int *numfds, fd_set *fdset, struct timeval *timeout, int *block)
|
||||
* @see clixon_snmp_input_cb
|
||||
*/
|
||||
static int
|
||||
clixon_snmp_fdset_register(clicon_handle h,
|
||||
int regfd)
|
||||
{
|
||||
int retval = -1;
|
||||
int numfds = 0;
|
||||
fd_set readfds;
|
||||
struct timeval timeout = { LONG_MAX, 0 };
|
||||
int block = 0;
|
||||
int nr;
|
||||
int s;
|
||||
|
||||
FD_ZERO(&readfds);
|
||||
if ((nr = snmp_sess_select_info(NULL, &numfds, &readfds, &timeout, &block)) < 0){
|
||||
clicon_err(OE_XML, errno, "snmp_select_error");
|
||||
goto done;
|
||||
}
|
||||
/* eg 4, 6, 8 */
|
||||
for (s=0; s<numfds; s++){
|
||||
if (FD_ISSET(s, &readfds)){
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, s);
|
||||
if (regfd){
|
||||
if (clixon_event_reg_fd(s, clixon_snmp_input_cb, h, "snmp socket") < 0)
|
||||
goto done;
|
||||
}
|
||||
else{
|
||||
if (clixon_event_unreg_fd(s, clixon_snmp_input_cb) < 0)
|
||||
goto done;
|
||||
close(s);
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Callback for single socket
|
||||
* This is a workaround for netsnmps API usiing fdset:s, instead an fdset is created before calling
|
||||
* the snmp api
|
||||
* @param[in] s Read socket
|
||||
* @param[in] arg Clixon handle
|
||||
*/
|
||||
static int
|
||||
clixon_snmp_input_cb(int s,
|
||||
void *arg)
|
||||
{
|
||||
int retval = -1;
|
||||
fd_set readfds;
|
||||
clicon_handle h = (clicon_handle)arg;
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "%s %d", __FUNCTION__, s);
|
||||
FD_ZERO(&readfds);
|
||||
FD_SET(s, &readfds);
|
||||
(void)snmp_read(&readfds);
|
||||
if (clixon_event_poll(s) < 0){
|
||||
if (errno == EBADF){
|
||||
clicon_err_reset();
|
||||
/* Close the active socket */
|
||||
if (clixon_event_unreg_fd(s, clixon_snmp_input_cb) < 0)
|
||||
goto done;
|
||||
close(s);
|
||||
/* and then the others */
|
||||
if (clixon_snmp_fdset_register(h, 0) < 0)
|
||||
goto done;
|
||||
if ((ret = snmp_close_sessions()) != 1){
|
||||
clicon_err(OE_SNMP, ret, "snmp_close_sessions");
|
||||
goto done;
|
||||
}
|
||||
/* Signal normal exit to upper layers (=event handling)
|
||||
* One can signal error and return -1, but it is nicer with an orderly exit
|
||||
*/
|
||||
clixon_exit_set(1);
|
||||
}
|
||||
else {
|
||||
clicon_err(OE_UNIX, errno, "poll");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Init netsnmp agent connection
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] logdst Log destination, see clixon_log.h
|
||||
* @see snmp_terminate
|
||||
*/
|
||||
static int
|
||||
clixon_snmp_init_subagent(clicon_handle h,
|
||||
int logdst)
|
||||
{
|
||||
int retval = -1;
|
||||
char *sockpath = NULL;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if (logdst == CLICON_LOG_SYSLOG)
|
||||
snmp_enable_calllog();
|
||||
else
|
||||
snmp_enable_stderrlog();
|
||||
/* 0 if master, 1 if client */
|
||||
netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE, 1);
|
||||
/* don't load config and don't load/save persistent file */
|
||||
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DONT_PERSIST_STATE, 1);
|
||||
/* don't load persistent file */
|
||||
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_LOAD, 1);
|
||||
/* don't save persistent file */
|
||||
netsnmp_ds_set_boolean(NETSNMP_DS_LIBRARY_ID, NETSNMP_DS_LIB_DISABLE_PERSISTENT_SAVE, 1);
|
||||
|
||||
if (clicon_debug_get())
|
||||
netsnmp_ds_set_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_VERBOSE, 1);
|
||||
|
||||
if ((sockpath = clicon_option_str(h, "CLICON_SNMP_AGENT_SOCK")) == NULL){
|
||||
clicon_err(OE_XML, 0, "CLICON_SNMP_AGENT_SOCK not set");
|
||||
goto done;
|
||||
}
|
||||
/* XXX: This should be configurable. */
|
||||
netsnmp_ds_set_string(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_X_SOCKET, sockpath);
|
||||
|
||||
/* initialize the agent library */
|
||||
init_agent(__PROGRAM__);
|
||||
|
||||
/* example-demon will be used to read example-demon.conf files. */
|
||||
init_snmp(__PROGRAM__);
|
||||
|
||||
if (!clixon_snmp_api_agent_check()){
|
||||
clicon_err(OE_DAEMON, 0, "Connection to SNMP agent failed");
|
||||
goto done;
|
||||
}
|
||||
|
||||
if (set_signal(SIGTERM, clixon_snmp_sig_term, NULL) < 0){
|
||||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
||||
goto done;
|
||||
}
|
||||
if (set_signal(SIGINT, clixon_snmp_sig_term, NULL) < 0){
|
||||
clicon_err(OE_DAEMON, errno, "Setting signal");
|
||||
goto done;
|
||||
}
|
||||
if (set_signal(SIGPIPE, SIG_IGN, NULL) < 0){
|
||||
clicon_err(OE_UNIX, errno, "Setting SIGPIPE signal");
|
||||
goto done;
|
||||
}
|
||||
/* Workaround for netsnmps API use of fdset:s instead of sockets */
|
||||
if (clixon_snmp_fdset_register(h, 1) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Usage help routine
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] argv0 command line
|
||||
*/
|
||||
static void
|
||||
usage(clicon_handle h,
|
||||
char *argv0)
|
||||
{
|
||||
fprintf(stderr, "usage:%s\n"
|
||||
"where options are\n"
|
||||
"\t-h\t\tHelp\n"
|
||||
"\t-D <level>\tDebug level\n"
|
||||
"\t-f <file>\tConfiguration file (mandatory)\n"
|
||||
"\t-l (e|o|s|f<file>) Log on std(e)rr, std(o)ut, (s)yslog(default), (f)ile\n"
|
||||
"\t-z\t\tKill other %s daemon and exit\n"
|
||||
"\t-o \"<option>=<value>\"\tGive configuration option overriding config file (see clixon-config.yang)\n",
|
||||
argv0, argv0
|
||||
);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc,
|
||||
char **argv)
|
||||
{
|
||||
int retval = -1;
|
||||
int c;
|
||||
char *argv0 = argv[0];
|
||||
clicon_handle h;
|
||||
int logdst = CLICON_LOG_STDERR;
|
||||
struct passwd *pw;
|
||||
yang_stmt *yspec = NULL;
|
||||
char *str;
|
||||
uint32_t id;
|
||||
cvec *nsctx_global = NULL; /* Global namespace context */
|
||||
size_t cligen_buflen;
|
||||
size_t cligen_bufthreshold;
|
||||
int dbg = 0;
|
||||
size_t sz;
|
||||
int pid;
|
||||
char *pidfile = NULL;
|
||||
struct stat st;
|
||||
int zap = 0;
|
||||
|
||||
/* Create handle */
|
||||
if ((h = clicon_handle_init()) == NULL)
|
||||
return -1;
|
||||
/* In the startup, logs to stderr & debug flag set later */
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, logdst);
|
||||
|
||||
/* Set username to clixon handle. Use in all communication to backend */
|
||||
if ((pw = getpwuid(getuid())) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "getpwuid");
|
||||
goto done;
|
||||
}
|
||||
if (clicon_username_set(h, pw->pw_name) < 0)
|
||||
goto done;
|
||||
while ((c = getopt(argc, argv, SNMP_OPTS)) != -1)
|
||||
switch (c) {
|
||||
case 'h' : /* help */
|
||||
usage(h, argv[0]);
|
||||
break;
|
||||
case 'D' : /* debug */
|
||||
if (sscanf(optarg, "%d", &dbg) != 1)
|
||||
usage(h, argv[0]);
|
||||
break;
|
||||
case 'f': /* override config file */
|
||||
if (!strlen(optarg))
|
||||
usage(h, argv[0]);
|
||||
clicon_option_str_set(h, "CLICON_CONFIGFILE", optarg);
|
||||
break;
|
||||
case 'l': /* Log destination: s|e|o */
|
||||
if ((logdst = clicon_log_opt(optarg[0])) < 0)
|
||||
usage(h, argv[0]);
|
||||
if (logdst == CLICON_LOG_FILE &&
|
||||
strlen(optarg)>1 &&
|
||||
clicon_log_file(optarg+1) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Logs, error and debug to stderr or syslog, set debug level
|
||||
*/
|
||||
clicon_log_init(__PROGRAM__, dbg?LOG_DEBUG:LOG_INFO, logdst);
|
||||
clicon_debug_init(dbg, NULL);
|
||||
|
||||
/*
|
||||
* Register error category and error/log callbacks for netsnmp special error handling
|
||||
*/
|
||||
if (clixon_err_cat_reg(OE_SNMP, /* category */
|
||||
h, /* handle (can be NULL) */
|
||||
clixon_snmp_err_cb /* log fn */
|
||||
) < 0)
|
||||
goto done;
|
||||
|
||||
yang_init(h);
|
||||
|
||||
/* Find, read and parse configfile */
|
||||
if (clicon_options_main(h) < 0)
|
||||
goto done;
|
||||
|
||||
/* Now rest of options */
|
||||
optind = 1;
|
||||
opterr = 0;
|
||||
while ((c = getopt(argc, argv, SNMP_OPTS)) != -1)
|
||||
switch (c) {
|
||||
case 'h' : /* help */
|
||||
case 'D' : /* debug */
|
||||
case 'f': /* config file */
|
||||
case 'l': /* log */
|
||||
break; /* see above */
|
||||
case 'o':{ /* Configuration option */
|
||||
char *val;
|
||||
if ((val = index(optarg, '=')) == NULL)
|
||||
usage(h, argv0);
|
||||
*val++ = '\0';
|
||||
if (clicon_option_add(h, optarg, val) < 0)
|
||||
goto done;
|
||||
break;
|
||||
}
|
||||
case 'z': /* Zap other process */
|
||||
zap++;
|
||||
break;
|
||||
default:
|
||||
usage(h, argv[0]);
|
||||
break;
|
||||
}
|
||||
argc -= optind;
|
||||
argv += optind;
|
||||
|
||||
/* Access the remaining argv/argc options (after --) w clicon-argv_get() */
|
||||
clicon_argv_set(h, argv0, argc, argv);
|
||||
|
||||
/* Check pid-file, if zap kill the old daemon, else return here */
|
||||
if ((pidfile = clicon_snmp_pidfile(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "pidfile not set");
|
||||
goto done;
|
||||
}
|
||||
if (pidfile_get(pidfile, &pid) < 0)
|
||||
goto done;
|
||||
if (zap){
|
||||
if (pid && pidfile_zapold(pid) < 0)
|
||||
return -1;
|
||||
if (lstat(pidfile, &st) == 0)
|
||||
unlink(pidfile);
|
||||
snmp_terminate(h);
|
||||
exit(0); /* OK */
|
||||
}
|
||||
else if (pid){
|
||||
clicon_err(OE_DAEMON, 0, "Clixon_snmp daemon already running with pid %d\n(Try killing it with %s -z)",
|
||||
pid, argv0);
|
||||
return -1; /* goto done deletes pidfile */
|
||||
}
|
||||
/* Here there is either no old process or we have killed it,.. */
|
||||
if (lstat(pidfile, &st) == 0)
|
||||
unlink(pidfile);
|
||||
|
||||
/* Init cligen buffers */
|
||||
cligen_buflen = clicon_option_int(h, "CLICON_CLI_BUF_START");
|
||||
cligen_bufthreshold = clicon_option_int(h, "CLICON_CLI_BUF_THRESHOLD");
|
||||
cbuf_alloc_set(cligen_buflen, cligen_bufthreshold);
|
||||
|
||||
if ((sz = clicon_option_int(h, "CLICON_LOG_STRING_LIMIT")) != 0)
|
||||
clicon_log_string_limit_set(sz);
|
||||
|
||||
/* Set default namespace according to CLICON_NAMESPACE_NETCONF_DEFAULT */
|
||||
xml_nsctx_namespace_netconf_default(h);
|
||||
|
||||
/* Add (hardcoded) netconf features in case ietf-netconf loaded here
|
||||
* Otherwise it is loaded in netconf_module_load below
|
||||
*/
|
||||
if (netconf_module_features(h) < 0)
|
||||
goto done;
|
||||
|
||||
/* Create top-level yang spec and store as option */
|
||||
if ((yspec = yspec_new()) == NULL)
|
||||
goto done;
|
||||
clicon_dbspec_yang_set(h, yspec);
|
||||
|
||||
/* Load Yang modules
|
||||
* 1. Load a yang module as a specific absolute filename */
|
||||
if ((str = clicon_yang_main_file(h)) != NULL){
|
||||
if (yang_spec_parse_file(h, str, yspec) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* 2. Load a (single) main module */
|
||||
if ((str = clicon_yang_module_main(h)) != NULL){
|
||||
if (yang_spec_parse_module(h, str, clicon_yang_module_revision(h),
|
||||
yspec) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* 3. Load all modules in a directory */
|
||||
if ((str = clicon_yang_main_dir(h)) != NULL){
|
||||
if (yang_spec_load_dir(h, str, yspec) < 0)
|
||||
goto done;
|
||||
}
|
||||
/* Load clixon lib yang module */
|
||||
if (yang_spec_parse_module(h, "clixon-lib", NULL, yspec) < 0)
|
||||
goto done;
|
||||
/* Load yang module library, RFC7895 */
|
||||
if (yang_modules_init(h) < 0)
|
||||
goto done;
|
||||
/* Add netconf yang spec, used by netconf client and as internal protocol */
|
||||
if (netconf_module_load(h) < 0)
|
||||
goto done;
|
||||
/* Here all modules are loaded
|
||||
* Compute and set canonical namespace context
|
||||
*/
|
||||
if (xml_nsctx_yangspec(yspec, &nsctx_global) < 0)
|
||||
goto done;
|
||||
if (clicon_nsctx_global_set(h, nsctx_global) < 0)
|
||||
goto done;
|
||||
|
||||
if (dbg)
|
||||
clicon_option_dump(h, dbg);
|
||||
|
||||
/* Get session id from backend hello */
|
||||
clicon_session_id_set(h, getpid());
|
||||
|
||||
/* Send hello request to backend to get session-id back
|
||||
* This is done once at the beginning of the session and then this is
|
||||
* used by the client, even though new TCP sessions are created for
|
||||
* each message sent to the backend.
|
||||
*/
|
||||
if (clicon_hello_req(h, &id) < 0)
|
||||
goto done;
|
||||
clicon_session_id_set(h, id);
|
||||
|
||||
/* Init snmp as subagent */
|
||||
if (clixon_snmp_init_subagent(h, logdst) < 0)
|
||||
goto done;
|
||||
|
||||
/* Init and traverse mib-translated yangs and register callbacks */
|
||||
if (clixon_snmp_traverse_mibyangs(h) < 0)
|
||||
goto done;
|
||||
|
||||
/* Write pid-file */
|
||||
if (pidfile_write(pidfile) < 0)
|
||||
goto done;
|
||||
/* main event loop */
|
||||
if (clixon_event_loop(h) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
snmp_terminate(h);
|
||||
clicon_log_init(__PROGRAM__, LOG_INFO, 0); /* Log on syslog no stderr */
|
||||
clicon_log(LOG_NOTICE, "%s: %u Terminated", __PROGRAM__, getpid());
|
||||
return retval;
|
||||
}
|
||||
532
apps/snmp/snmp_register.c
Normal file
532
apps/snmp/snmp_register.c
Normal file
|
|
@ -0,0 +1,532 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2022 Olof Hagsand and Kristofer Hallin
|
||||
Sponsored by Siklu Communications LTD
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
* See RFC 6643
|
||||
* Extensions are grouped in some categories, the one I have seen are, example:
|
||||
* 1. leaf
|
||||
* smiv2:max-access "read-write";
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2.1.1";
|
||||
* smiv2:defval "42"; (not always)
|
||||
* 2. container, list
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2.1";
|
||||
* 3. module level
|
||||
* smiv2:alias "netSnmpExamples" {
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2";
|
||||
*
|
||||
* SNMP messages:
|
||||
* 160 MODE_GETNEXT / SNMP_MSG_GET
|
||||
* 161 MODE_GET / SNMP_MSG_GETNEXT
|
||||
* 0 MODE_SET_RESERVE1
|
||||
* 1 MODE_SET_RESERVE2
|
||||
* 2 MODE_SET_ACTION
|
||||
* 3 MODE_SET_COMMIT
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "clixon_config.h" /* generated by config & autoconf */
|
||||
#endif
|
||||
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <pwd.h>
|
||||
#include <syslog.h>
|
||||
#include <errno.h>
|
||||
#include <sys/types.h>
|
||||
#include <signal.h>
|
||||
#include <assert.h>
|
||||
|
||||
/* net-snmp */
|
||||
#include <net-snmp/net-snmp-config.h>
|
||||
#include <net-snmp/net-snmp-includes.h>
|
||||
#include <net-snmp/agent/net-snmp-agent-includes.h>
|
||||
|
||||
/* cligen */
|
||||
#include <cligen/cligen.h>
|
||||
|
||||
/* clicon */
|
||||
#include <clixon/clixon.h>
|
||||
|
||||
#include "snmp_lib.h"
|
||||
#include "snmp_register.h"
|
||||
#include "snmp_handler.h"
|
||||
|
||||
/*! Parse smiv2 extensions for YANG leaf
|
||||
* Typical leaf:
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2.1.1";
|
||||
* smiv2:max-access "read-write";
|
||||
* smiv2:defval "42"; (optional)
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Mib-Yang node
|
||||
* @param[in] cvk_orig Vector of untranslated key/index values (eg "foo")
|
||||
* @param[in] oidk Part of OID thatrepresents key
|
||||
* @param[in] oidklen Length of oidk
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* netsnmp_subtree_find(oid1,sz1, 0, 0)
|
||||
*/
|
||||
static int
|
||||
mibyang_leaf_register(clicon_handle h,
|
||||
yang_stmt *ys,
|
||||
cvec *cvk_val,
|
||||
oid *oidk,
|
||||
size_t oidklen)
|
||||
{
|
||||
int retval = -1;
|
||||
netsnmp_handler_registration *nhreg = NULL;
|
||||
netsnmp_mib_handler *handler;
|
||||
int ret;
|
||||
char *modes_str = NULL;
|
||||
char *default_str = NULL;
|
||||
oid oid1[MAX_OID_LEN] = {0,};
|
||||
size_t oid1len = MAX_OID_LEN;
|
||||
int modes;
|
||||
char *name;
|
||||
clixon_snmp_handle *sh;
|
||||
cbuf *cboid = NULL;
|
||||
|
||||
if ((cboid = cbuf_new()) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cbuf_new");
|
||||
goto done;
|
||||
}
|
||||
if ((ret = yangext_oid_get(ys, oid1, &oid1len, NULL)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
if (oid_append(oid1, &oid1len, oidk, oidklen) < 0)
|
||||
goto done;
|
||||
/* Check if already registered */
|
||||
if (clixon_snmp_api_oid_find(oid1, oid1len) == 1)
|
||||
goto ok;
|
||||
if (yang_extension_value(ys, "max-access", IETF_YANG_SMIV2_NS, NULL, &modes_str) < 0)
|
||||
goto done;
|
||||
/* Only for sanity check of types initially to fail early */
|
||||
if (type_yang2asn1(ys, NULL, 0) < 0)
|
||||
goto done;
|
||||
|
||||
/* Get modes (access) read-only, read-write, not-accessible, accessible-for-notify
|
||||
*/
|
||||
if (modes_str == NULL)
|
||||
goto ok;
|
||||
modes = snmp_access_str2int(modes_str);
|
||||
|
||||
/* SMI default value, How is this different from yang defaults?
|
||||
*/
|
||||
if (yang_extension_value(ys, "defval", IETF_YANG_SMIV2_NS, 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){
|
||||
clicon_err(OE_XML, errno, "netsnmp_create_handler");
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* Userdata to pass around in netsmp callbacks
|
||||
* XXX: not deallocated
|
||||
*/
|
||||
if ((sh = malloc(sizeof(*sh))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(sh, 0, sizeof(*sh));
|
||||
sh->sh_h = h;
|
||||
sh->sh_ys = ys;
|
||||
memcpy(sh->sh_oid, oid1, sizeof(oid1));
|
||||
sh->sh_oidlen = oid1len;
|
||||
sh->sh_default = default_str;
|
||||
if (cvk_val &&
|
||||
(sh->sh_cvk_orig = cvec_dup(cvk_val)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "cvec_dup");
|
||||
goto done;
|
||||
}
|
||||
/* Stateless function, just returns ptr */
|
||||
if ((nhreg = netsnmp_handler_registration_create(name, handler,
|
||||
oid1, oid1len,
|
||||
modes)) == NULL){
|
||||
clicon_err(OE_XML, errno, "netsnmp_handler_registration_create");
|
||||
netsnmp_handler_free(handler);
|
||||
goto done;
|
||||
}
|
||||
/* Register our application data and how to free it */
|
||||
handler->myvoid = (void*)sh;
|
||||
handler->data_clone = snmp_handle_clone;
|
||||
handler->data_free = snmp_handle_free;
|
||||
|
||||
/*
|
||||
* XXX: nhreg->agent_data
|
||||
*/
|
||||
if ((ret = netsnmp_register_instance(nhreg)) != SNMPERR_SUCCESS){
|
||||
/* Note MIB_ errors, not regular SNMPERR_ */
|
||||
clicon_err(OE_SNMP, ret-CLIXON_ERR_SNMP_MIB, "netsnmp_register_instance");
|
||||
goto done;
|
||||
}
|
||||
oid_cbuf(cboid, oid1, oid1len);
|
||||
clicon_debug(1, "%s register: %s %s", __FUNCTION__, name, cbuf_get(cboid));
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
if (cboid)
|
||||
cbuf_free(cboid);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Register table entry handler itself (not column/row leafs)
|
||||
*
|
||||
* Parse smiv2 extensions for YANG container/list
|
||||
*
|
||||
* Typical table:
|
||||
* container x {
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2.2.1";
|
||||
* list y{
|
||||
*
|
||||
* }
|
||||
* }
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Mib-Yang node (container)
|
||||
* @param[in] yl Mib-Yang node (list)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
static int
|
||||
mibyang_table_register(clicon_handle h,
|
||||
yang_stmt *ylist)
|
||||
{
|
||||
int retval = -1;
|
||||
netsnmp_handler_registration *nhreg;
|
||||
char *oidstr = NULL;
|
||||
oid oid1[MAX_OID_LEN] = {0,};
|
||||
size_t oid1len = MAX_OID_LEN;
|
||||
char *name;
|
||||
clixon_snmp_handle *sh;
|
||||
int ret;
|
||||
netsnmp_mib_handler *handler;
|
||||
netsnmp_table_registration_info *table_info = NULL;
|
||||
cvec *cvk = NULL; /* vector of index keys */
|
||||
cg_var *cvi;
|
||||
char *keyname;
|
||||
yang_stmt *yleaf;
|
||||
int asn1type;
|
||||
yang_stmt *ys;
|
||||
|
||||
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;
|
||||
}
|
||||
/* Get OID from parent container */
|
||||
if ((ret = yangext_oid_get(ys, oid1, &oid1len, &oidstr)) < 0)
|
||||
goto done;
|
||||
if (ret == 0)
|
||||
goto ok;
|
||||
name = yang_argument_get(ys);
|
||||
|
||||
/* Userdata to pass around in netsmp callbacks
|
||||
* XXX: not deallocated
|
||||
*/
|
||||
if ((sh = malloc(sizeof(*sh))) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "malloc");
|
||||
goto done;
|
||||
}
|
||||
memset(sh, 0, sizeof(*sh));
|
||||
sh->sh_h = h;
|
||||
sh->sh_ys = ylist;
|
||||
|
||||
memcpy(sh->sh_oid, oid1, sizeof(oid1));
|
||||
sh->sh_oidlen = oid1len;
|
||||
|
||||
if ((handler = netsnmp_create_handler(name, clixon_snmp_table_handler)) == NULL){
|
||||
clicon_err(OE_XML, errno, "netsnmp_create_handler");
|
||||
goto done;
|
||||
}
|
||||
if ((nhreg = netsnmp_handler_registration_create(name, handler,
|
||||
oid1, oid1len,
|
||||
HANDLER_CAN_RWRITE)) == NULL){
|
||||
clicon_err(OE_XML, errno, "netsnmp_handler_registration_create");
|
||||
netsnmp_handler_free(handler);
|
||||
goto done;
|
||||
}
|
||||
/* Register our application data and how to free it */
|
||||
handler->myvoid =(void*)sh;
|
||||
handler->data_clone = snmp_handle_clone;
|
||||
handler->data_free = snmp_handle_free;
|
||||
|
||||
/* See netsnmp_register_table_data_set */
|
||||
if ((table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info)) == NULL){
|
||||
clicon_err(OE_UNIX, errno, "SNMP_MALLOC_TYPEDEF");
|
||||
goto done;
|
||||
}
|
||||
/* Keys, go through keys */
|
||||
if ((cvk = yang_cvec_get(ylist)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "No keys");
|
||||
goto done;
|
||||
}
|
||||
cvi = NULL;
|
||||
/* Iterate over individual keys */
|
||||
while ((cvi = cvec_each(cvk, cvi)) != NULL) {
|
||||
keyname = cv_string_get(cvi);
|
||||
if ((yleaf = yang_find(ylist, Y_LEAF, keyname)) == NULL){
|
||||
clicon_err(OE_XML, 0, "List statement \"%s\" has no key leaf \"%s\"",
|
||||
yang_argument_get(ylist), keyname);
|
||||
goto done;
|
||||
}
|
||||
if (type_yang2asn1(yleaf, &asn1type, 0) < 0)
|
||||
// goto done;
|
||||
goto ok; // XXX skip
|
||||
if (snmp_varlist_add_variable(&table_info->indexes,
|
||||
NULL, // oid name
|
||||
0, // oid len
|
||||
asn1type,
|
||||
NULL, // value
|
||||
0) == NULL){
|
||||
clicon_err(OE_XML, errno, "snmp_varlist_add_variable");
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
table_info->min_column = 1;
|
||||
|
||||
/* Count columns */
|
||||
yleaf = NULL;
|
||||
table_info->max_column = 0;
|
||||
while ((yleaf = yn_each(ylist, yleaf)) != NULL) {
|
||||
if (yang_keyword_get(yleaf) == Y_LEAF)
|
||||
table_info->max_column++;
|
||||
}
|
||||
if ((ret = netsnmp_register_table(nhreg, table_info)) != SNMPERR_SUCCESS){
|
||||
clicon_err(OE_SNMP, ret, "netsnmp_register_table");
|
||||
goto done;
|
||||
}
|
||||
sh->sh_table_info = table_info; /* Keep to free at exit */
|
||||
clicon_debug(1, "%s register: %s %s", __FUNCTION__, name, oidstr);
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Register table sub-oid:s of existing entries in clixon
|
||||
* This assumes a table contains a set of keys and a list of leafs only
|
||||
* The function makes a query to the datastore and registers all table entries that
|
||||
* currently exists. This means it registers for a static table. If new rows or columns
|
||||
* are created or deleted this will not change the OID registration.
|
||||
* That is, the table registration is STATIC
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] ys Mib-Yang node (container)
|
||||
* @param[in] ylist Mib-Yang node (list)
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
mibyang_table_poll(clicon_handle h,
|
||||
yang_stmt *ylist)
|
||||
{
|
||||
int retval = -1;
|
||||
cvec *nsc = NULL;
|
||||
char *xpath = NULL;
|
||||
cxobj *xt = NULL;
|
||||
cxobj *xerr;
|
||||
cxobj *xtable;
|
||||
cxobj *xrow;
|
||||
cxobj *xcol;
|
||||
yang_stmt *y;
|
||||
cvec *cvk_name;
|
||||
cvec *cvk_val = NULL; /* vector of index keys: original index */
|
||||
yang_stmt *ys;
|
||||
int ret;
|
||||
oid oidk[MAX_OID_LEN] = {0,};
|
||||
size_t oidklen = MAX_OID_LEN;
|
||||
|
||||
clicon_debug(1, "%s", __FUNCTION__);
|
||||
if ((ys = yang_parent_get(ylist)) == NULL ||
|
||||
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) {
|
||||
if ((ret = snmp_xmlkey2val_oid(xrow, cvk_name, &cvk_val, 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 ((y = xml_spec(xcol)) == NULL)
|
||||
continue;
|
||||
if (mibyang_leaf_register(h, y, cvk_val, oidk, oidklen) < 0)
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (xpath)
|
||||
free(xpath);
|
||||
if (cvk_val)
|
||||
cvec_free(cvk_val);
|
||||
if (xt)
|
||||
xml_free(xt);
|
||||
if (nsc)
|
||||
xml_nsctx_free(nsc);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Traverse mib-yang tree, identify scalars and tables, register OID and callbacks
|
||||
*
|
||||
* The tree is traversed depth-first, which at least guarantees that a parent is
|
||||
* traversed before a child.
|
||||
* Extensions are grouped in some categories, the one I have seen are, example:
|
||||
* 1. leaf
|
||||
* smiv2:max-access "read-write";
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2.1.1";
|
||||
* smiv2:defval "42"; (not always)
|
||||
* 2. container, list
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2.1";
|
||||
* 3. module level
|
||||
* smiv2:alias "netSnmpExamples" {
|
||||
* smiv2:oid "1.3.6.1.4.1.8072.2";
|
||||
|
||||
* @param[in] h Clixon handle
|
||||
* @param[in] yn yang node
|
||||
* @param[in] table Yang node is within table
|
||||
* @retval 0 OK, all nodes traversed
|
||||
* @retval -1 Error, aborted at first error encounter
|
||||
*/
|
||||
static int
|
||||
mibyang_traverse(clicon_handle h,
|
||||
yang_stmt *yn)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *ys = NULL;
|
||||
yang_stmt *yp;
|
||||
int ret;
|
||||
|
||||
clicon_debug(1, "%s %s", __FUNCTION__, yang_argument_get(yn));
|
||||
switch(yang_keyword_get(yn)){
|
||||
case Y_LEAF:
|
||||
if (mibyang_leaf_register(h, yn, NULL, NULL, 0) < 0)
|
||||
goto done;
|
||||
break;
|
||||
case Y_CONTAINER: /* See list case */
|
||||
break;
|
||||
case Y_LIST: /* If parent is container -> identify as table */
|
||||
yp = yang_parent_get(yn);
|
||||
if (yang_keyword_get(yp) == Y_CONTAINER){
|
||||
/* Register table entry handler itself (not column/row leafs) */
|
||||
if (mibyang_table_register(h, yn) < 0)
|
||||
goto done;
|
||||
goto ok;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
/* Traverse data nodes in tree (module is special case */
|
||||
ys = NULL;
|
||||
while ((ys = yn_each(yn, ys)) != NULL) {
|
||||
if (!yang_schemanode(ys))
|
||||
continue;
|
||||
if ((ret = mibyang_traverse(h, ys)) < 0)
|
||||
goto done;
|
||||
if (ret > 0){
|
||||
retval = ret;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
ok:
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Init mib-translated yangs and register callbacks by traversing the yang
|
||||
*
|
||||
* @þaram[in] h Clixon handle
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
clixon_snmp_traverse_mibyangs(clicon_handle h)
|
||||
{
|
||||
int retval = -1;
|
||||
char *modname;
|
||||
cxobj *x;
|
||||
yang_stmt *yspec;
|
||||
yang_stmt *ymod;
|
||||
|
||||
if ((yspec = clicon_dbspec_yang(h)) == NULL){
|
||||
clicon_err(OE_FATAL, 0, "No DB_SPEC");
|
||||
goto done;
|
||||
}
|
||||
/* Loop over clixon configuration file to find all CLICON_SNMP_MIB, and
|
||||
* then loop over all those MIBs to register OIDs with netsnmp
|
||||
*/
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(clicon_conf_xml(h), x, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(x), "CLICON_SNMP_MIB") != 0)
|
||||
continue;
|
||||
if ((modname = xml_body(x)) == NULL)
|
||||
continue;
|
||||
clicon_debug(1, "%s %s: \"%s\"", __FUNCTION__, xml_name(x), modname);
|
||||
/* Note, here we assume the Yang is loaded by some other mechanism and
|
||||
* error if it not found.
|
||||
* Alternatively, that YANG could be loaded.
|
||||
* Problem is, if clixon_snmp has not loaded it, has backend done it?
|
||||
* What happens if backend has not loaded it?
|
||||
*/
|
||||
if ((ymod = yang_find(yspec, Y_MODULE, modname)) == NULL){
|
||||
clicon_err(OE_YANG, 0, "Mib-translated-yang %s not loaded", modname);
|
||||
goto done;
|
||||
}
|
||||
/* Recursively traverse the mib-yang to find extensions */
|
||||
if (mibyang_traverse(h, ymod) < 0)
|
||||
goto done;
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
55
apps/snmp/snmp_register.h
Normal file
55
apps/snmp/snmp_register.h
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
*
|
||||
***** BEGIN LICENSE BLOCK *****
|
||||
|
||||
Copyright (C) 2022 Olof Hagsand and Kristofer Hallin
|
||||
Sponsored by Siklu Communications LTD
|
||||
|
||||
This file is part of CLIXON.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
Alternatively, the contents of this file may be used under the terms of
|
||||
the GNU General Public License Version 3 or later (the "GPL"),
|
||||
in which case the provisions of the GPL are applicable instead
|
||||
of those above. If you wish to allow use of your version of this file only
|
||||
under the terms of the GPL, and not to allow others to
|
||||
use your version of this file under the terms of Apache License version 2,
|
||||
indicate your decision by deleting the provisions above and replace them with
|
||||
the notice and other provisions required by the GPL. If you do not delete
|
||||
the provisions above, a recipient may use your version of this file under
|
||||
the terms of any one of the Apache License version 2 or the GPL.
|
||||
|
||||
***** END LICENSE BLOCK *****
|
||||
|
||||
*/
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifndef _SNMP_REGISTER_H_
|
||||
#define _SNMP_REGISTER_H_
|
||||
|
||||
/*
|
||||
* Prototypes
|
||||
*/
|
||||
int mibyang_table_poll(clicon_handle h, yang_stmt *ylist);
|
||||
int clixon_snmp_traverse_mibyangs(clicon_handle h);
|
||||
|
||||
#endif /* _SNMP_REGISTER_H_ */
|
||||
|
||||
#ifdef __cplusplus
|
||||
} /* extern "C" */
|
||||
#endif
|
||||
|
||||
160
configure
vendored
160
configure
vendored
|
|
@ -632,12 +632,14 @@ ac_ct_CXX
|
|||
CXXFLAGS
|
||||
CXX
|
||||
CPP
|
||||
MIB_GENERATED_YANG_DIR
|
||||
YANG_STANDARD_DIR
|
||||
YANG_INSTALLDIR
|
||||
CLIXON_YANG_PATCH
|
||||
with_libxml2
|
||||
HAVE_HTTP1
|
||||
HAVE_LIBNGHTTP2
|
||||
enable_netsnmp
|
||||
with_restconf
|
||||
LINKAGE
|
||||
LIBSTATIC_SUFFIX
|
||||
|
|
@ -722,6 +724,8 @@ enable_publish
|
|||
with_restconf
|
||||
enable_http1
|
||||
enable_nghttp2
|
||||
enable_netsnmp
|
||||
with_mib_generated_yang_dir
|
||||
with_configfile
|
||||
with_libxml2
|
||||
with_sigaction
|
||||
|
|
@ -1374,6 +1378,7 @@ Optional Features:
|
|||
only
|
||||
--disable-nghttp2 Disable nghttp2 for native restconf http/2, ie
|
||||
http/1 only
|
||||
--enable-netsnmp Enable net-snmp Clixon YANG mapping
|
||||
|
||||
|
||||
Optional Packages:
|
||||
|
|
@ -1384,6 +1389,9 @@ Optional Packages:
|
|||
--with-restconf=fcgi FCGI interface for stand-alone web rev-proxy eg
|
||||
nginx
|
||||
--without-restconf Disable restconf altogether
|
||||
--with-mib-generated-yang-dir=DIR
|
||||
Directory of generated YANG specs (default:
|
||||
$prefix/share/mib-yangs)
|
||||
--with-configfile=FILE Set default path to config file
|
||||
--with-libxml2 Use gnome/libxml2 regex engine
|
||||
--without-sigaction Don't use sigaction
|
||||
|
|
@ -3385,7 +3393,8 @@ test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
|
|||
|
||||
|
||||
|
||||
# Set to native or fcgi -> compile apps/restconf
|
||||
# Set to native or fcgi -> compile apps/restconf
|
||||
# Enable build of apps/snmp
|
||||
HAVE_LIBNGHTTP2=false
|
||||
# consider using neutral constant such as with-http2
|
||||
HAVE_HTTP1=false
|
||||
|
|
@ -3396,6 +3405,8 @@ HAVE_HTTP1=false
|
|||
|
||||
# Examples require standard IETF YANGs. You need to provide these for example and tests
|
||||
|
||||
# SNMP tests require generated YANGs from MIBs
|
||||
|
||||
|
||||
#
|
||||
ac_ext=c
|
||||
|
|
@ -5301,6 +5312,149 @@ if test "${with_restconf+set}" = set; then :
|
|||
fi
|
||||
|
||||
|
||||
# This is for net-snmp
|
||||
# Check whether --enable-netsnmp was given.
|
||||
if test "${enable_netsnmp+set}" = set; then :
|
||||
enableval=$enable_netsnmp;
|
||||
if test "$enableval" = no; then
|
||||
enable_netsnmp=no
|
||||
else
|
||||
enable_netsnmp=yes
|
||||
fi
|
||||
|
||||
else
|
||||
enable_netsnmp=no
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: checking netsnmp is enabled: $enable_netsnmp" >&5
|
||||
$as_echo "checking netsnmp is enabled: $enable_netsnmp" >&6; }
|
||||
|
||||
if test "$enable_netsnmp" = "yes"; then
|
||||
# All libs are:
|
||||
# libnetsnmp, libnetsnmpagent, libnetsnmpmibs, libnetsnmptrapd, libnetsnmphelpers
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for init_snmp in -lnetsnmp" >&5
|
||||
$as_echo_n "checking for init_snmp in -lnetsnmp... " >&6; }
|
||||
if ${ac_cv_lib_netsnmp_init_snmp+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lnetsnmp $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char init_snmp ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return init_snmp ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_netsnmp_init_snmp=yes
|
||||
else
|
||||
ac_cv_lib_netsnmp_init_snmp=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netsnmp_init_snmp" >&5
|
||||
$as_echo "$ac_cv_lib_netsnmp_init_snmp" >&6; }
|
||||
if test "x$ac_cv_lib_netsnmp_init_snmp" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_LIBNETSNMP 1
|
||||
_ACEOF
|
||||
|
||||
LIBS="-lnetsnmp $LIBS"
|
||||
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for init_agent in -lnetsnmpagent" >&5
|
||||
$as_echo_n "checking for init_agent in -lnetsnmpagent... " >&6; }
|
||||
if ${ac_cv_lib_netsnmpagent_init_agent+:} false; then :
|
||||
$as_echo_n "(cached) " >&6
|
||||
else
|
||||
ac_check_lib_save_LIBS=$LIBS
|
||||
LIBS="-lnetsnmpagent $LIBS"
|
||||
cat confdefs.h - <<_ACEOF >conftest.$ac_ext
|
||||
/* end confdefs.h. */
|
||||
|
||||
/* Override any GCC internal prototype to avoid an error.
|
||||
Use char because int might match the return type of a GCC
|
||||
builtin and then its argument prototype would still apply. */
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
#endif
|
||||
char init_agent ();
|
||||
int
|
||||
main ()
|
||||
{
|
||||
return init_agent ();
|
||||
;
|
||||
return 0;
|
||||
}
|
||||
_ACEOF
|
||||
if ac_fn_c_try_link "$LINENO"; then :
|
||||
ac_cv_lib_netsnmpagent_init_agent=yes
|
||||
else
|
||||
ac_cv_lib_netsnmpagent_init_agent=no
|
||||
fi
|
||||
rm -f core conftest.err conftest.$ac_objext \
|
||||
conftest$ac_exeext conftest.$ac_ext
|
||||
LIBS=$ac_check_lib_save_LIBS
|
||||
fi
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_netsnmpagent_init_agent" >&5
|
||||
$as_echo "$ac_cv_lib_netsnmpagent_init_agent" >&6; }
|
||||
if test "x$ac_cv_lib_netsnmpagent_init_agent" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_LIBNETSNMPAGENT 1
|
||||
_ACEOF
|
||||
|
||||
LIBS="-lnetsnmpagent $LIBS"
|
||||
|
||||
fi
|
||||
|
||||
for ac_header in net-snmp/net-snmp-config.h
|
||||
do :
|
||||
ac_fn_c_check_header_mongrel "$LINENO" "net-snmp/net-snmp-config.h" "ac_cv_header_net_snmp_net_snmp_config_h" "$ac_includes_default"
|
||||
if test "x$ac_cv_header_net_snmp_net_snmp_config_h" = xyes; then :
|
||||
cat >>confdefs.h <<_ACEOF
|
||||
#define HAVE_NET_SNMP_NET_SNMP_CONFIG_H 1
|
||||
_ACEOF
|
||||
|
||||
else
|
||||
as_fn_error $? "snmp is missing" "$LINENO" 5
|
||||
fi
|
||||
|
||||
done
|
||||
|
||||
|
||||
|
||||
# MIB_GENERATED_YANG_DIR is where clixon assumes generated YANGs from MIBs are stored
|
||||
# This is NOT installed by Clixon and is not needed for core system
|
||||
# However, it is required by SNMP tests.
|
||||
# To generate: for i in /usr/share/snmp/mibs/*; do smidump -f yang $i > `basename -s .txt $i`.yang; done
|
||||
|
||||
# Check whether --with-mib-generated-yang-dir was given.
|
||||
if test "${with_mib_generated_yang_dir+set}" = set; then :
|
||||
withval=$with_mib_generated_yang_dir; MIB_GENERATED_YANG_DIR="$withval"
|
||||
else
|
||||
MIB_GENERATED_YANG_DIR="${prefix}/share/mib-yangs"
|
||||
|
||||
fi
|
||||
|
||||
{ $as_echo "$as_me:${as_lineno-$LINENO}: result: Generated YANGs from MIB files are expected to be in ${MIB_GENERATED_YANG_DIR}" >&5
|
||||
$as_echo "Generated YANGs from MIB files are expected to be in ${MIB_GENERATED_YANG_DIR}" >&6; }
|
||||
fi
|
||||
|
||||
# Set default config file location
|
||||
CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml
|
||||
|
||||
|
|
@ -5569,7 +5723,7 @@ fi
|
|||
|
||||
|
||||
|
||||
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/main/Makefile example/main/example.xml extras/rpm/Makefile docker/Makefile docker/base/Makefile docker/clixon-dev/Makefile docker/main/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/mandatory/Makefile doc/Makefile test/Makefile test/config.sh test/cicd/Makefile test/vagrant/Makefile"
|
||||
ac_config_files="$ac_config_files Makefile lib/Makefile lib/src/Makefile lib/clixon/Makefile apps/Makefile apps/cli/Makefile apps/backend/Makefile apps/netconf/Makefile apps/restconf/Makefile apps/snmp/Makefile include/Makefile etc/Makefile etc/clixonrc example/Makefile example/main/Makefile example/main/example.xml extras/rpm/Makefile docker/Makefile docker/base/Makefile docker/clixon-dev/Makefile docker/main/Makefile util/Makefile yang/Makefile yang/clixon/Makefile yang/mandatory/Makefile doc/Makefile test/Makefile test/config.sh test/cicd/Makefile test/vagrant/Makefile"
|
||||
|
||||
cat >confcache <<\_ACEOF
|
||||
# This file is a shell script that caches the results of configure
|
||||
|
|
@ -6272,6 +6426,7 @@ do
|
|||
"apps/backend/Makefile") CONFIG_FILES="$CONFIG_FILES apps/backend/Makefile" ;;
|
||||
"apps/netconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/netconf/Makefile" ;;
|
||||
"apps/restconf/Makefile") CONFIG_FILES="$CONFIG_FILES apps/restconf/Makefile" ;;
|
||||
"apps/snmp/Makefile") CONFIG_FILES="$CONFIG_FILES apps/snmp/Makefile" ;;
|
||||
"include/Makefile") CONFIG_FILES="$CONFIG_FILES include/Makefile" ;;
|
||||
"etc/Makefile") CONFIG_FILES="$CONFIG_FILES etc/Makefile" ;;
|
||||
"etc/clixonrc") CONFIG_FILES="$CONFIG_FILES etc/clixonrc" ;;
|
||||
|
|
@ -6878,4 +7033,3 @@ if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
|
|||
$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
|
||||
fi
|
||||
|
||||
|
||||
|
|
|
|||
38
configure.ac
38
configure.ac
|
|
@ -114,7 +114,8 @@ AC_SUBST(LIBS)
|
|||
AC_SUBST(SH_SUFFIX)
|
||||
AC_SUBST(LIBSTATIC_SUFFIX)
|
||||
AC_SUBST(LINKAGE)
|
||||
AC_SUBST(with_restconf) # Set to native or fcgi -> compile apps/restconf
|
||||
AC_SUBST(with_restconf) # Set to native or fcgi -> compile apps/restconf
|
||||
AC_SUBST(enable_netsnmp) # Enable build of apps/snmp
|
||||
AC_SUBST(HAVE_LIBNGHTTP2,false) # consider using neutral constant such as with-http2
|
||||
AC_SUBST(HAVE_HTTP1,false)
|
||||
AC_SUBST(with_libxml2)
|
||||
|
|
@ -123,6 +124,8 @@ AC_SUBST(CLIXON_YANG_PATCH)
|
|||
AC_SUBST(YANG_INSTALLDIR)
|
||||
# Examples require standard IETF YANGs. You need to provide these for example and tests
|
||||
AC_SUBST(YANG_STANDARD_DIR)
|
||||
# SNMP tests require generated YANGs from MIBs
|
||||
AC_SUBST(MIB_GENERATED_YANG_DIR)
|
||||
|
||||
#
|
||||
AC_PROG_CC()
|
||||
|
|
@ -275,6 +278,37 @@ AC_ARG_WITH([restconf],
|
|||
AC_ARG_WITH([restconf],
|
||||
AS_HELP_STRING([--without-restconf],[Disable restconf altogether]))
|
||||
|
||||
# This is for net-snmp
|
||||
AC_ARG_ENABLE(netsnmp, AS_HELP_STRING([--enable-netsnmp],[Enable net-snmp Clixon YANG mapping]),[
|
||||
if test "$enableval" = no; then
|
||||
enable_netsnmp=no
|
||||
else
|
||||
enable_netsnmp=yes
|
||||
fi
|
||||
],
|
||||
[ enable_netsnmp=no])
|
||||
AC_MSG_RESULT(checking netsnmp is enabled: $enable_netsnmp)
|
||||
|
||||
if test "$enable_netsnmp" = "yes"; then
|
||||
# All libs are:
|
||||
# libnetsnmp, libnetsnmpagent, libnetsnmpmibs, libnetsnmptrapd, libnetsnmphelpers
|
||||
AC_CHECK_LIB(netsnmp, init_snmp)
|
||||
AC_CHECK_LIB(netsnmpagent, init_agent)
|
||||
AC_CHECK_HEADERS(net-snmp/net-snmp-config.h,[], AC_MSG_ERROR([snmp is missing]))
|
||||
|
||||
|
||||
# MIB_GENERATED_YANG_DIR is where clixon assumes generated YANGs from MIBs are stored
|
||||
# This is NOT installed by Clixon and is not needed for core system
|
||||
# However, it is required by SNMP tests.
|
||||
# To generate: for i in /usr/share/snmp/mibs/*; do smidump -f yang $i > `basename -s .txt $i`.yang; done
|
||||
AC_ARG_WITH(mib-generated-yang-dir,
|
||||
[AS_HELP_STRING([--with-mib-generated-yang-dir=DIR],[Directory of generated YANG specs (default: $prefix/share/mib-yangs)])],
|
||||
[MIB_GENERATED_YANG_DIR="$withval"],
|
||||
[MIB_GENERATED_YANG_DIR="${prefix}/share/mib-yangs"]
|
||||
)
|
||||
AC_MSG_RESULT(Generated YANGs from MIB files are expected to be in ${MIB_GENERATED_YANG_DIR})
|
||||
fi
|
||||
|
||||
# Set default config file location
|
||||
CLIXON_DEFAULT_CONFIG=/usr/local/etc/clixon.xml
|
||||
AC_ARG_WITH([configfile],
|
||||
|
|
@ -352,6 +386,7 @@ AC_OUTPUT(Makefile
|
|||
apps/backend/Makefile
|
||||
apps/netconf/Makefile
|
||||
apps/restconf/Makefile
|
||||
apps/snmp/Makefile
|
||||
include/Makefile
|
||||
etc/Makefile
|
||||
etc/clixonrc
|
||||
|
|
@ -373,4 +408,3 @@ AC_OUTPUT(Makefile
|
|||
test/cicd/Makefile
|
||||
test/vagrant/Makefile
|
||||
)
|
||||
|
||||
|
|
|
|||
|
|
@ -39,6 +39,9 @@ MAINTAINER Olof Hagsand <olof@hagsand.se>
|
|||
# For clixon and cligen
|
||||
RUN apk add --update git make build-base gcc flex bison curl-dev
|
||||
|
||||
# For netsnmp
|
||||
RUN apk add --update net-snmp net-snmp-dev
|
||||
|
||||
WORKDIR /usr/local/share
|
||||
|
||||
# Checkout standard YANG models for tests (note >1G for full repo)
|
||||
|
|
@ -76,7 +79,7 @@ WORKDIR /clixon/clixon
|
|||
COPY clixon .
|
||||
|
||||
# Configure, build and install clixon
|
||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --without-restconf --with-yang-standard-dir=/usr/local/share/yang/standard
|
||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --without-restconf --with-yang-standard-dir=/usr/local/share/yang/standard --enable-netsnmp --with-mib-generated-yang-dir=/usr/local/share/mib-yangs/
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
|
|
@ -103,6 +106,9 @@ WORKDIR /clixon
|
|||
COPY startsystem.sh startsystem.sh
|
||||
RUN install startsystem.sh /clixon/build/bin/
|
||||
|
||||
# Add our generated YANG files
|
||||
RUN git clone https://github.com/clicon/mib-yangs.git /usr/local/share/mib-yangs
|
||||
|
||||
#
|
||||
# Stage 2
|
||||
# The second step skips the development environment and builds a runtime system
|
||||
|
|
@ -112,6 +118,16 @@ MAINTAINER Olof Hagsand <olof@hagsand.se>
|
|||
# For clixon and cligen
|
||||
RUN apk add --update flex bison fcgi-dev
|
||||
|
||||
# For SNMP
|
||||
RUN apk add --update net-snmp net-snmp-tools
|
||||
|
||||
# Some custom configuration for SNMP
|
||||
RUN echo "master agentx" > /etc/snmp/snmpd.conf
|
||||
RUN echo "agentaddress 127.0.0.1" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "rwcommunity public localhost" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "agentXSocket unix:/var/run/snmp.sock" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "agentxperms 777 777" >> /etc/snmp/snmpd.conf
|
||||
|
||||
# Test-specific (for test scripts)
|
||||
RUN apk add --update sudo curl procps grep make bash expect
|
||||
|
||||
|
|
@ -120,6 +136,7 @@ RUN adduser -D -H clicon
|
|||
|
||||
COPY --from=0 /clixon/build/ /usr/local/
|
||||
COPY --from=0 /usr/local/share/yang/* /usr/local/share/yang/standard/
|
||||
COPY --from=0 /usr/local/share/mib-yangs/* /usr/local/share/mib-yangs/
|
||||
|
||||
# Log to stderr.
|
||||
CMD /usr/local/bin/startsystem.sh
|
||||
|
|
|
|||
|
|
@ -38,6 +38,9 @@ MAINTAINER Olof Hagsand <olof@hagsand.se>
|
|||
# For clixon and cligen
|
||||
RUN apk add --update git make build-base gcc flex bison fcgi-dev curl-dev
|
||||
|
||||
# For netsnmp
|
||||
RUN apk add --update net-snmp net-snmp-dev
|
||||
|
||||
# Checkut standard YANG models for tests (note >1G for full repo)
|
||||
WORKDIR /usr/local/share
|
||||
RUN mkdir yang
|
||||
|
|
@ -77,7 +80,7 @@ RUN adduser -D -H -G www-data www-data
|
|||
RUN apk add --update nginx
|
||||
|
||||
# Configure, build and install clixon
|
||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=fcgi --with-yang-standard-dir=/usr/local/share/yang/standard
|
||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=fcgi --with-yang-standard-dir=/usr/local/share/yang/standard --enable-netsnmp --with-mib-generated-yang-dir=/usr/local/share/mib-yangs/
|
||||
RUN make
|
||||
RUN make install
|
||||
|
||||
|
|
@ -104,6 +107,9 @@ WORKDIR /clixon
|
|||
COPY startsystem_fcgi.sh startsystem.sh
|
||||
RUN install startsystem.sh /clixon/build/bin/
|
||||
|
||||
# Add our generated YANG files
|
||||
RUN git clone https://github.com/clicon/mib-yangs.git /usr/local/share/mib-yangs
|
||||
|
||||
#
|
||||
# Stage 2
|
||||
# The second step skips the development environment and builds a runtime system
|
||||
|
|
@ -113,6 +119,16 @@ MAINTAINER Olof Hagsand <olof@hagsand.se>
|
|||
# For clixon and cligen
|
||||
RUN apk add --update flex bison fcgi-dev
|
||||
|
||||
# For SNMP
|
||||
RUN apk add --update net-snmp net-snmp-tools
|
||||
|
||||
# Some custom configuration for SNMP
|
||||
RUN echo "master agentx" > /etc/snmp/snmpd.conf
|
||||
RUN echo "agentaddress 127.0.0.1" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "rwcommunity public localhost" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "agentXSocket unix:/var/run/snmp.sock" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "agentxperms 777 777" >> /etc/snmp/snmpd.conf
|
||||
|
||||
# Need to add www user manually, but group www-data already exists on Alpine
|
||||
RUN adduser -D -H -G www-data www-data
|
||||
# nginx adds group www-data
|
||||
|
|
@ -131,6 +147,7 @@ RUN adduser www-data clicon
|
|||
|
||||
COPY --from=0 /clixon/build/ /usr/local/
|
||||
COPY --from=0 /usr/local/share/yang/* /usr/local/share/yang/standard/
|
||||
COPY --from=0 /usr/local/share/mib-yangs/* /usr/local/share/mib-yangs/
|
||||
|
||||
# Manually created
|
||||
RUN mkdir /www-data
|
||||
|
|
|
|||
|
|
@ -41,6 +41,9 @@ RUN apk add --update git make build-base gcc flex bison curl-dev
|
|||
# nghttp2 dependencies
|
||||
RUN apk add --update nghttp2
|
||||
|
||||
# For netsnmp
|
||||
RUN apk add --update net-snmp net-snmp-dev
|
||||
|
||||
# Checkut models
|
||||
WORKDIR /usr/local/share/
|
||||
|
||||
|
|
@ -88,7 +91,7 @@ WORKDIR /clixon/clixon
|
|||
COPY clixon .
|
||||
|
||||
# Configure, build and install clixon
|
||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=native --enable-nghttp2 --enable-http1 --with-yang-standard-dir=/usr/local/share/yang/standard
|
||||
RUN ./configure --prefix=/clixon/build --with-cligen=/clixon/build --with-restconf=native --enable-nghttp2 --enable-http1 --with-yang-standard-dir=/usr/local/share/yang/standard --enable-netsnmp --with-mib-generated-yang-dir=/usr/local/share/mib-yangs/
|
||||
|
||||
RUN make
|
||||
RUN make install
|
||||
|
|
@ -111,11 +114,17 @@ RUN install *.sh /clixon/build/bin/test
|
|||
RUN install *.exp /clixon/build/bin/test
|
||||
RUN install clixon.png /clixon/build/bin/test
|
||||
|
||||
RUN install -d /clixon/build/mibs
|
||||
RUN install mibs/* /clixon/build/mibs
|
||||
|
||||
# Copy startscript
|
||||
WORKDIR /clixon
|
||||
COPY startsystem_native.sh startsystem.sh
|
||||
RUN install startsystem.sh /clixon/build/bin/
|
||||
|
||||
# Add our generated YANG files
|
||||
RUN git clone https://github.com/clicon/mib-yangs.git /usr/local/share/mib-yangs
|
||||
|
||||
#
|
||||
# Stage 2
|
||||
# The second step skips the development environment and builds a runtime system
|
||||
|
|
@ -136,6 +145,16 @@ RUN apk add --update nghttp2
|
|||
# Test-specific (for test scripts)
|
||||
RUN apk add --update sudo curl procps grep make bash expect
|
||||
|
||||
# For SNMP
|
||||
RUN apk add --update net-snmp net-snmp-tools
|
||||
|
||||
# Some custom configuration for SNMP
|
||||
RUN echo "master agentx" > /etc/snmp/snmpd.conf
|
||||
RUN echo "agentaddress 127.0.0.1" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "rwcommunity public localhost" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "agentXSocket unix:/var/run/snmp.sock" >> /etc/snmp/snmpd.conf
|
||||
RUN echo "agentxperms 777 777" >> /etc/snmp/snmpd.conf
|
||||
|
||||
# Expose https port for restconf
|
||||
EXPOSE 80/tcp
|
||||
EXPOSE 443/tcp
|
||||
|
|
@ -147,6 +166,8 @@ COPY --from=0 /clixon/build/ /usr/local/
|
|||
COPY --from=0 /usr/local/share/yang/* /usr/local/share/yang/standard/
|
||||
COPY --from=0 /usr/local/share/yang/* /usr/local/share/yang/experimental/
|
||||
COPY --from=0 /usr/local/share/openconfig/* /usr/local/share/openconfig/
|
||||
COPY --from=0 /usr/local/share/mib-yangs/* /usr/local/share/mib-yangs/
|
||||
COPY --from=0 /clixon/build/mibs/* /usr/share/snmp/mibs/
|
||||
|
||||
# Start the backend and restconf deamons
|
||||
CMD /usr/local/bin/startsystem.sh
|
||||
|
|
|
|||
|
|
@ -82,6 +82,10 @@ chmod 775 /usr/local/bin/test/site.sh
|
|||
/usr/local/sbin/clixon_backend -D $DBG -s running -l e # logs on docker logs
|
||||
>&2 echo "clixon_backend started"
|
||||
|
||||
# Start snmpd, we need this for the SNMP tests and the app clixon_snmp. Log to stdout, then we can
|
||||
# use Docker logs to see what's happening.
|
||||
snmpd -Lo -p /var/run/snmpd.pid -I -ifXTable -I -ifTable -I -system_mib -I -sysORTable -I -snmpNotifyFilterTable -I -snmpNotifyTable -I -snmpNotifyFilterProfileTable
|
||||
|
||||
# Alt: let backend be in foreground, but test scripts may
|
||||
# want to restart backend
|
||||
/bin/sleep 100000000
|
||||
|
|
|
|||
|
|
@ -130,6 +130,10 @@ chmod g+w /www-data/fastcgi_restconf.sock
|
|||
/usr/local/sbin/clixon_backend -D $DBG -s running -l e # logs on docker logs
|
||||
>&2 echo "clixon_backend started"
|
||||
|
||||
# Start snmpd, we need this for the SNMP tests and the app clixon_snmp. Log to stdout, then we can
|
||||
# use Docker logs to see what's happening.
|
||||
snmpd -Lo -p /var/run/snmpd.pid -I -ifXTable -I -ifTable -I -system_mib -I -sysORTable -I -snmpNotifyFilterTable -I -snmpNotifyTable -I -snmpNotifyFilterProfileTable
|
||||
|
||||
# Alt: let backend be in foreground, but test scripts may
|
||||
# want to restart backend
|
||||
/bin/sleep 100000000
|
||||
|
|
|
|||
|
|
@ -125,6 +125,12 @@ openssl req -x509 -config ./ca.cnf -nodes -newkey rsa:4096 -keyout /etc/ssl/priv
|
|||
/usr/local/sbin/clixon_backend -D $DBG -s running -l e # logs on docker logs
|
||||
>&2 echo "clixon_backend started"
|
||||
|
||||
# Start snmpd, we need this for the SNMP tests and the app clixon_snmp. Log to stdout, then we can
|
||||
# use Docker logs to see what's happening.
|
||||
snmpd -Lo -p /var/run/snmpd.pid -I -ifXTable -I -ifTable -I -system_mib -I -sysORTable -I -snmpNotifyFilterTable -I -snmpNotifyTable -I -snmpNotifyFilterProfileTable
|
||||
|
||||
sleep 3
|
||||
|
||||
# Alt: let backend be in foreground, but test scripts may
|
||||
# want to restart backend
|
||||
/bin/sleep 100000000
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@
|
|||
/* Define to 1 if you have the `getresuid' function. */
|
||||
#undef HAVE_GETRESUID
|
||||
|
||||
/* Enable HTTP/1 (default true) */
|
||||
/* Set to true to enable Native HTTP/1 */
|
||||
#undef HAVE_HTTP1
|
||||
|
||||
/* Define to 1 if you have the `inet_aton' function. */
|
||||
|
|
@ -60,6 +60,12 @@
|
|||
/* Define to 1 if you have the `m' library (-lm). */
|
||||
#undef HAVE_LIBM
|
||||
|
||||
/* Define to 1 if you have the `netsnmp' library (-lnetsnmp). */
|
||||
#undef HAVE_LIBNETSNMP
|
||||
|
||||
/* Define to 1 if you have the `netsnmpagent' library (-lnetsnmpagent). */
|
||||
#undef HAVE_LIBNETSNMPAGENT
|
||||
|
||||
/* Define to 1 if you have the `nghttp2' library (-lnghttp2). */
|
||||
#undef HAVE_LIBNGHTTP2
|
||||
|
||||
|
|
@ -75,6 +81,9 @@
|
|||
/* Define to 1 if you have the <memory.h> header file. */
|
||||
#undef HAVE_MEMORY_H
|
||||
|
||||
/* Define to 1 if you have the <net-snmp/net-snmp-config.h> header file. */
|
||||
#undef HAVE_NET_SNMP_NET_SNMP_CONFIG_H
|
||||
|
||||
/* Define to 1 if you have the <nghttp2/nghttp2.h> header file. */
|
||||
#undef HAVE_NGHTTP2_NGHTTP2_H
|
||||
|
||||
|
|
|
|||
|
|
@ -164,4 +164,3 @@
|
|||
*/
|
||||
#define PROTO_RESTART_RECONNECT
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -55,7 +55,8 @@
|
|||
|
||||
/*
|
||||
* Types
|
||||
* Add error category here, but must also add an entry in EV variable in clixon_err.c
|
||||
* Add error category here,
|
||||
* @see EV variable in clixon_err.c but must also add an entry there
|
||||
*/
|
||||
enum clicon_err{
|
||||
/* 0 means error not set) */
|
||||
|
|
@ -78,6 +79,7 @@ enum clicon_err{
|
|||
OE_UNDEF,
|
||||
/*-- From here error extensions using clixon_err_cat_reg, XXX register dynamically? --*/
|
||||
OE_SSL, /* Openssl errors, see eg ssl_get_error */
|
||||
OE_SNMP , /* Netsnmp error */
|
||||
OE_NGHTTP2, /* nghttp2 errors, see HAVE_LIBNGHTTP2 */
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -70,6 +70,8 @@ int xml2xpath(cxobj *x, cvec *nsc, char **xpath);
|
|||
int assign_namespace_element(cxobj *x0, cxobj *x1, cxobj *x1p);
|
||||
int assign_namespace_body(cxobj *x0, cxobj *x1);
|
||||
int xml_merge(cxobj *x0, cxobj *x1, yang_stmt *yspec, char **reason);
|
||||
int yang_valstr2enum(yang_stmt *ytype, char *valstr, char **enumstr);
|
||||
int yang_enum2valstr(yang_stmt *ytype, char *enumstr, char **valstr);
|
||||
int yang_enum_int_value(cxobj *node, int32_t *val);
|
||||
int xml_copy_marked(cxobj *x0, cxobj *x1);
|
||||
int yang_check_when_xpath(cxobj *xn, cxobj *xp, yang_stmt *yn, int *hit, int *nrp, char **xpathp);
|
||||
|
|
|
|||
|
|
@ -124,6 +124,7 @@ static struct errvec EV[] = {
|
|||
{"Undefined", OE_UNDEF},
|
||||
/* From here error extensions using clixon_err_cat_reg */
|
||||
{"OpenSSL error", OE_SSL},
|
||||
{"SNMP error", OE_SNMP},
|
||||
{"Nghttp2 error", OE_NGHTTP2},
|
||||
{NULL, -1}
|
||||
};
|
||||
|
|
|
|||
|
|
@ -133,7 +133,7 @@ static const map_str2int yang_regexp_map[] = {
|
|||
* @param[in] dbglevel Debug level
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* @note CLICON_FEATURE and CLICON_YANG_DIR are treated specially since they are lists
|
||||
* @note CLICON_FEATURE, CLICON_YANG_DIR and CLICON_SNMP_MIB are treated specially since they are lists
|
||||
*/
|
||||
int
|
||||
clicon_option_dump(clicon_handle h,
|
||||
|
|
@ -161,7 +161,7 @@ clicon_option_dump(clicon_handle h,
|
|||
else
|
||||
clicon_debug(dbglevel, "%s = NULL", keys[i]);
|
||||
}
|
||||
/* Next print CLICON_FEATURE and CLICON_YANG_DIR from config tree
|
||||
/* Next print CLICON_FEATURE, CLICON_YANG_DIR and CLICON_SNMP_DIR from config tree
|
||||
* Since they are lists they are placed in the config tree.
|
||||
*/
|
||||
x = NULL;
|
||||
|
|
@ -176,6 +176,12 @@ clicon_option_dump(clicon_handle h,
|
|||
continue;
|
||||
clicon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
|
||||
}
|
||||
x = NULL;
|
||||
while ((x = xml_child_each(clicon_conf_xml(h), x, CX_ELMNT)) != NULL) {
|
||||
if (strcmp(xml_name(x), "CLICON_SNMP_MIB") != 0)
|
||||
continue;
|
||||
clicon_debug(dbglevel, "%s =\t \"%s\"", xml_name(x), xml_body(x));
|
||||
}
|
||||
retval = 0;
|
||||
done:
|
||||
if (keys)
|
||||
|
|
@ -333,7 +339,8 @@ parse_configfile(clicon_handle h,
|
|||
continue;
|
||||
/* List options for configure options that are lists or leaf-lists: append to main */
|
||||
if (strcmp(name,"CLICON_FEATURE")==0 ||
|
||||
strcmp(name,"CLICON_YANG_DIR")==0){
|
||||
strcmp(name,"CLICON_YANG_DIR")==0 ||
|
||||
strcmp(name,"CLICON_SNMP_MIB")==0){
|
||||
if (xml_addsub(xt, xec) < 0)
|
||||
goto done;
|
||||
continue;
|
||||
|
|
@ -381,6 +388,8 @@ parse_configfile(clicon_handle h,
|
|||
continue;
|
||||
if (strcmp(name,"CLICON_YANG_DIR")==0)
|
||||
continue;
|
||||
if (strcmp(name,"CLICON_SNMP_MIB")==0)
|
||||
continue;
|
||||
if (clicon_hash_add(copt,
|
||||
name,
|
||||
body,
|
||||
|
|
@ -424,7 +433,8 @@ clicon_option_add(clicon_handle h,
|
|||
cxobj *x;
|
||||
|
||||
if (strcmp(name, "CLICON_FEATURE")==0 ||
|
||||
strcmp(name, "CLICON_YANG_DIR")==0){
|
||||
strcmp(name, "CLICON_YANG_DIR")==0 ||
|
||||
strcmp(name, "CLICON_SNMP_MIB")==0){
|
||||
if ((x = clicon_conf_xml(h)) == NULL){
|
||||
clicon_err(OE_UNIX, ENOENT, "option %s not found (clicon_conf_xml_set has not been called?)", name);
|
||||
goto done;
|
||||
|
|
|
|||
|
|
@ -386,6 +386,8 @@ yang2api_path_fmt_1(yang_stmt *ys,
|
|||
* @param[in] ys Yang statement
|
||||
* @param[in] inclkey If set include key leaf (eg last leaf d in ex)
|
||||
* @param[out] api_path_fmt XML api path. Needs to be freed after use.
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
* "api-path" is "URI-encoded path expression" definition in RFC8040 3.5.3
|
||||
*/
|
||||
int
|
||||
|
|
@ -424,7 +426,7 @@ yang2api_path_fmt(yang_stmt *ys,
|
|||
* @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[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
|
||||
* @retval 0 OK
|
||||
* @retval -1 Error
|
||||
|
|
@ -902,7 +904,7 @@ api_path2xpath(char *api_path,
|
|||
* @param[in] nodeclass Set to schema nodes, data nodes, etc
|
||||
* @param[in] strict Break if api-path is not "complete" otherwise ignore and continue
|
||||
* @param[out] xbotp Resulting xml tree
|
||||
* @param[out] ybotp Yang spec matching xpathp
|
||||
* @param[out] ybotp Yang spec matching xpathp
|
||||
* @param[out] xerr Netconf error message (if retval=0)
|
||||
* @retval 1 OK
|
||||
* @retval 0 Invalid api_path or associated XML, netconf error
|
||||
|
|
@ -1144,7 +1146,7 @@ api_path2xml_vec(char **vec,
|
|||
* @param[in,out] xtop Incoming XML tree
|
||||
* @param[in] nodeclass Set to schema nodes, data nodes, etc
|
||||
* @param[in] strict Break if api-path is not "complete" otherwise ignore and continue
|
||||
* @param[out] xbotp Resulting xml tree (end of xpath)
|
||||
* @param[out] xbotp Resulting xml tree (end of xpath) (optional)
|
||||
* @param[out] ybotp Yang spec matching xbotp
|
||||
* @param[out] xerr Netconf error message (if retval=0)
|
||||
* @retval 1 OK
|
||||
|
|
|
|||
|
|
@ -186,7 +186,7 @@ clicon_rpc_msg(clicon_handle h,
|
|||
#ifdef RPC_USERNAME_ASSERT
|
||||
assert(strstr(msg->op_body, "username")!=NULL); /* XXX */
|
||||
#endif
|
||||
clicon_debug(1, "%s request:%s", __FUNCTION__, msg->op_body);
|
||||
clicon_debug(2, "%s request:%s", __FUNCTION__, msg->op_body);
|
||||
/* Create a socket and connect to it, either UNIX, IPv4 or IPv6 per config options */
|
||||
if (clicon_rpc_msg_once(h, msg, &retdata, &eof, &s) < 0)
|
||||
goto done;
|
||||
|
|
@ -215,7 +215,7 @@ clicon_rpc_msg(clicon_handle h,
|
|||
goto done;
|
||||
#endif
|
||||
}
|
||||
clicon_debug(1, "%s retdata:%s", __FUNCTION__, retdata);
|
||||
clicon_debug(2, "%s retdata:%s", __FUNCTION__, retdata);
|
||||
|
||||
if (retdata){
|
||||
/* Cannot populate xret here because need to know RPC name (eg "lock") in order to associate yang
|
||||
|
|
@ -581,7 +581,7 @@ clicon_rpc_get_config(clicon_handle h,
|
|||
* @note xml arg need to have <config> as top element
|
||||
* @code
|
||||
* if (clicon_rpc_edit_config(h, "running", OP_MERGE,
|
||||
* "<config><a>4</a></config>") < 0)
|
||||
* "<config><a xmlns="urn:example:clixon">4</a></config>") < 0)
|
||||
* err;
|
||||
* @endcode
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -1810,6 +1810,74 @@ xml_merge(cxobj *x0,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Given a YANG (enum) type node and a value, return the string containing corresponding int str
|
||||
*
|
||||
* @param[in] ytype YANG type noden
|
||||
* @param[in] valstr Integer string value
|
||||
* @param[out] enumstr Value of enum, dont free
|
||||
*/
|
||||
int
|
||||
yang_valstr2enum(yang_stmt *ytype,
|
||||
char *valstr,
|
||||
char **enumstr)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yenum = NULL;
|
||||
yang_stmt *yval;
|
||||
|
||||
if (enumstr == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "str is NULL");
|
||||
goto done;
|
||||
}
|
||||
while ((yenum = yn_each(ytype, yenum)) != NULL) {
|
||||
if ((yval = yang_find(yenum, Y_VALUE, NULL)) == NULL)
|
||||
goto done;
|
||||
if (strcmp(yang_argument_get(yval), valstr) == 0)
|
||||
break;
|
||||
}
|
||||
if (yenum)
|
||||
*enumstr = yang_argument_get(yenum);
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
/*! Given a YANG (enum) type node and a value, return the string containing corresponding int str
|
||||
*
|
||||
* @param[in] ytype YANG type noden
|
||||
* @param[in] enumstr Value of enum
|
||||
* @param[out] valstr Corresponding string containing an int (direct pointer, dont free)
|
||||
* @retval 1 OK, result in valstr
|
||||
* @retval 0 Invalid, not found
|
||||
* @retval -1 Error
|
||||
*/
|
||||
int
|
||||
yang_enum2valstr(yang_stmt *ytype,
|
||||
char *enumstr,
|
||||
char **valstr)
|
||||
{
|
||||
int retval = -1;
|
||||
yang_stmt *yenum;
|
||||
yang_stmt *yval;
|
||||
|
||||
if (valstr == NULL){
|
||||
clicon_err(OE_UNIX, EINVAL, "valstr is NULL");
|
||||
goto done;
|
||||
}
|
||||
if ((yenum = yang_find(ytype, Y_ENUM, enumstr)) == NULL)
|
||||
goto fail;
|
||||
/* Should assign value if yval not found */
|
||||
if ((yval = yang_find(yenum, Y_VALUE, NULL)) == NULL)
|
||||
goto done;
|
||||
*valstr = yang_argument_get(yval);
|
||||
retval = 1;
|
||||
done:
|
||||
return retval;
|
||||
fail:
|
||||
retval = 0;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/*! Get integer value from xml node from yang enumeration
|
||||
* @param[in] node XML node in a tree
|
||||
* @param[out] val Integer value returned
|
||||
|
|
@ -1832,9 +1900,8 @@ yang_enum_int_value(cxobj *node,
|
|||
yang_stmt *ys;
|
||||
yang_stmt *ytype;
|
||||
yang_stmt *yrestype; /* resolved type */
|
||||
yang_stmt *yenum;
|
||||
yang_stmt *yval;
|
||||
char *reason = NULL;
|
||||
char *intstr = NULL;
|
||||
|
||||
if (node == NULL)
|
||||
goto done;
|
||||
|
|
@ -1853,20 +1920,16 @@ yang_enum_int_value(cxobj *node,
|
|||
}
|
||||
if (yrestype==NULL || strcmp(yang_argument_get(yrestype), "enumeration"))
|
||||
goto done;
|
||||
if ((yenum = yang_find(yrestype, Y_ENUM, xml_body(node))) == NULL)
|
||||
goto done;
|
||||
/* Should assign value if yval not found */
|
||||
if ((yval = yang_find(yenum, Y_VALUE, NULL)) == NULL)
|
||||
if (yang_enum2valstr(yrestype, xml_body(node), &intstr) < 0)
|
||||
goto done;
|
||||
/* reason is string containing why int could not be parsed */
|
||||
if (parse_int32(yang_argument_get(yval), val, &reason) < 0)
|
||||
if (parse_int32(intstr, val, &reason) < 0)
|
||||
goto done;
|
||||
retval = 0;
|
||||
done:
|
||||
return retval;
|
||||
}
|
||||
|
||||
|
||||
/*! Given XML tree x0 with marked nodes, copy marked nodes to new tree x1
|
||||
* Two marks are used: XML_FLAG_MARK and XML_FLAG_CHANGE
|
||||
*
|
||||
|
|
|
|||
|
|
@ -1364,7 +1364,7 @@ yang_find_prefix_by_namespace(yang_stmt *ys,
|
|||
goto done;
|
||||
}
|
||||
|
||||
/*! Given a yang statement and local prefi valid in module , find namespace
|
||||
/*! Given a yang statement and local prefix valid in module, find namespace
|
||||
*
|
||||
* @param[in] ys Yang statement in module tree (or module itself)
|
||||
* @param[in] prefix Local prefix to access module with (direct pointer)
|
||||
|
|
@ -3661,7 +3661,7 @@ yang_anydata_add(yang_stmt *yp,
|
|||
|
||||
/*! Find extension argument and return if extension exists and its argument value
|
||||
*
|
||||
* @param[in] ys Yang statement where unknown statement may occur referncing to extension
|
||||
* @param[in] ys Yang statement where unknown statement may occur referencing to extension
|
||||
* @param[in] name Name of the extension
|
||||
* @param[in] ns The namespace of the module where the extension is defined
|
||||
* @param[out] exist The extension exists.
|
||||
|
|
@ -3678,7 +3678,7 @@ yang_anydata_add(yang_stmt *yp,
|
|||
* // use extension value
|
||||
* }
|
||||
* @endcode
|
||||
* @see ys_populate_unknown Called when parsing YANGo
|
||||
* @see ys_populate_unknown Called when parsing YANG
|
||||
*/
|
||||
int
|
||||
yang_extension_value(yang_stmt *ys,
|
||||
|
|
|
|||
|
|
@ -474,7 +474,7 @@ ys_do_refine(yang_stmt *yr,
|
|||
return retval;
|
||||
}
|
||||
|
||||
/*! Yang node yg is a leaf in yang node list yn
|
||||
/*! Check if Yang node y is a leaf in yang node list yp
|
||||
* Could be made to a generic function used elsewhere as well
|
||||
* @param[in] y Yang leaf
|
||||
* @param[in] yp Yang list parent
|
||||
|
|
@ -504,7 +504,6 @@ ys_iskey(yang_stmt *y,
|
|||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/*! Helper function to yang_expand_grouping
|
||||
* @param[in] yn Yang parent node of uses ststement
|
||||
* @param[in] ys Uses statement
|
||||
|
|
@ -790,7 +789,10 @@ yang_parse_str(char *str,
|
|||
if (yang_scan_exit(&yy) < 0)
|
||||
goto done;
|
||||
}
|
||||
ymod = yy.yy_module;
|
||||
if ((ymod = yy.yy_module) == NULL){
|
||||
clicon_err(OE_YANG, 0, "No module in YANG %s", name);
|
||||
goto done;
|
||||
}
|
||||
/* Add filename for debugging and errors, see also ys_linenum on (each symbol?) */
|
||||
if (yang_filename_set(ymod, name) < 0)
|
||||
goto done;
|
||||
|
|
|
|||
34
scripts/mib_to_yang.sh
Executable file
34
scripts/mib_to_yang.sh
Executable file
|
|
@ -0,0 +1,34 @@
|
|||
#/usr/bin/env bash
|
||||
|
||||
# Traverses a directory ($MIBDIR) and tries to convert each file from SMI format
|
||||
# to YANG and preserve directory structure etc.
|
||||
# This script can be used like this: ./mib_to_yang /usr/share/snmp/mibs yang/
|
||||
|
||||
MIBDIR=$1
|
||||
YANGDIR=$2
|
||||
|
||||
function parse_mibs(){
|
||||
indir=$1
|
||||
outdir=$2
|
||||
|
||||
for i in $indir/*; do
|
||||
outfile="$outdir`basename $i | cut -d"." -f1`.yang"
|
||||
SMIPATH=$MIBDIR smidump -f yang -k $i > $outfile
|
||||
done
|
||||
}
|
||||
|
||||
if [ $# -ne 2 ]; then
|
||||
echo "Usage: $0 <MIB directory, usually /usr/share/snmp/mibs> <out directory, for example yang/>"
|
||||
exit
|
||||
fi
|
||||
|
||||
for i in `find $MIBDIR -type d -or -type l`; do
|
||||
if [ `basename $i` == `basename $MIBDIR` ]; then
|
||||
outdir=$YANGDIR
|
||||
else
|
||||
outdir="$YANGDIR`basename $i`/"
|
||||
fi
|
||||
|
||||
mkdir -p $outdir
|
||||
parse_mibs $i $outdir
|
||||
done
|
||||
|
|
@ -67,6 +67,8 @@ You can prefix a test with `BE=0` if you want to run your own backend.
|
|||
|
||||
You can prefix a test with `RC=0` if you want to run your own restconf process.
|
||||
|
||||
You can prefix a test with `SN=0` if you want to run your own SNMP process (in combination with `BE=0`)
|
||||
|
||||
To run with debug flags, use the `DBG=<number>` environment variable.
|
||||
|
||||
Other variables include:
|
||||
|
|
@ -150,6 +152,26 @@ If you do not have them, generate self-signed certs, eg as follows:
|
|||
|
||||
There are also client-cert tests, eg `test_ssl_certs.sh`
|
||||
|
||||
## SNMP
|
||||
|
||||
Clixon snmp frontend tests require a running netsnmpd and converted YANG files from MIB.
|
||||
|
||||
Netsnmpd is 5.9 or later and can be started via systemd. For the tests
|
||||
to run, the systems IFMIB should be disabled: `-I -ifTable,ifNumber,ifXTable,`, etc.
|
||||
|
||||
One way to start snmpd on Ubuntu, known to be working for the tests are: snmpd -Lo -p /var/run/snmpd.pid -I -ifXTable -I -ifTable -I -system_mib -I -sysORTable -I -snmpNotifyFilterTable -I -snmpNotifyTable -I -snmpNotifyFilterProfileTable
|
||||
|
||||
Converted YANG files are available at `https://github.com/clicon/mib-yangs` or alternatively use `smidump` version 0.5 or later. Clixon expects them to be at `/usr/local/share/mib-yangs/` by default, or configured by `--with-mib-generated-yang-dir=DIR`.
|
||||
|
||||
You also need to configure a unix socket for agent. Example of /etc/snmp/snmpd.conf:
|
||||
```
|
||||
master agentx
|
||||
agentaddress 127.0.0.1,[::1]
|
||||
rwcommunity public localhost
|
||||
agentXSocket unix:/var/run/snmp.sock
|
||||
agentxperms 777 777
|
||||
```
|
||||
|
||||
## Known issues
|
||||
|
||||
[Workaround: Unicode double-quote in iana-if-type@2022-03-07.yang](https://github.com/clicon/clixon/issues/315)
|
||||
|
|
|
|||
|
|
@ -52,6 +52,9 @@ HAVE_HTTP1=@HAVE_HTTP1@
|
|||
# use it you need to set Clixon config option CLICON_YANG_REGEXP to libxml2
|
||||
WITH_LIBXML2=@with_libxml2@
|
||||
|
||||
# Check if we have support for Net-SNMP enabled or not.
|
||||
ENABLE_NETSNMP=@enable_netsnmp@
|
||||
|
||||
# C++ compiler
|
||||
CXX=@CXX@
|
||||
|
||||
|
|
@ -92,3 +95,4 @@ YANG_STANDARD_DIR=@YANG_STANDARD_DIR@
|
|||
|
||||
YANG_INSTALLDIR=@YANG_INSTALLDIR@
|
||||
|
||||
MIB_GENERATED_YANG_DIR=@MIB_GENERATED_YANG_DIR@
|
||||
|
|
|
|||
119
test/lib.sh
119
test/lib.sh
|
|
@ -53,6 +53,7 @@ testname=
|
|||
# 1: Start valgrind at every new testcase. Check result every next new
|
||||
# 2: Start valgrind every new backend start. Check when backend stops
|
||||
# 3: Start valgrind every new restconf start. Check when restconf stops
|
||||
# 4: Start valgrind every new snmp start. Check when snmp stops
|
||||
#
|
||||
: ${valgrindtest=0}
|
||||
|
||||
|
|
@ -73,6 +74,9 @@ testname=
|
|||
# eg logging to a file: RCLOG="-l f/www-data/restconf.log"
|
||||
: ${RCLOG:=}
|
||||
|
||||
# If set to 0, override starting of clixon_snmp in test (you bring your own)
|
||||
: ${SN:=1}
|
||||
|
||||
# Namespace: netconf base
|
||||
BASENS='urn:ietf:params:xml:ns:netconf:base:1.0'
|
||||
|
||||
|
|
@ -182,6 +186,13 @@ BUSER=clicon
|
|||
|
||||
: ${clixon_backend:=clixon_backend}
|
||||
|
||||
: ${clixon_snmp:=$(type -p clixon_snmp)}
|
||||
|
||||
: ${clixon_snmp_pidfile:="/var/tmp/clixon_snmp.pid"}
|
||||
|
||||
# Temporary debug var, set to trigger remaining snmp errors
|
||||
: ${snmp_debug:=false}
|
||||
|
||||
# Source the site-specific definitions for test script variables, if site.sh
|
||||
# exists. The variables defined in site.sh override any variables of the same
|
||||
# names in the environment in the current execution.
|
||||
|
|
@ -204,6 +215,76 @@ if [ ! -z ${YANG_STANDARD_DIR} ]; then
|
|||
: ${IETFRFC=$YANG_STANDARD_DIR/ietf/RFC}
|
||||
fi
|
||||
|
||||
: ${SNMPCHECK:=true}
|
||||
|
||||
if $SNMPCHECK; then
|
||||
snmpget="$(type -p snmpget) -On -c public -v2c localhost "
|
||||
snmpbulkget="$(type -p snmpbulkget) -On -c public -v2c localhost "
|
||||
snmpset="$(type -p snmpset) -On -c public -v2c localhost "
|
||||
snmpgetstr="$(type -p snmpget) -c public -v2c localhost "
|
||||
snmpgetnext="$(type -p snmpgetnext) -On -c public -v2c localhost "
|
||||
snmpgetnextstr="$(type -p snmpgetnext) -c public -v2c localhost "
|
||||
snmptable="$(type -p snmptable) -c public -v2c localhost "
|
||||
snmpwalk="$(type -p snmpwalk) -c public -v2c localhost "
|
||||
snmptranslate="$(type -p snmptranslate) "
|
||||
|
||||
if [ "${ENABLE_NETSNMP}" == "yes" ]; then
|
||||
pgrep snmpd > /dev/null
|
||||
if [ $? != 0 ]; then
|
||||
echo -e "\e[31m\nenable-netsnmp set but snmpd not running, start with:"
|
||||
echo "systemctl start snmpd"
|
||||
echo ""
|
||||
echo "snmpd must be configured to use a Unix socket for agent communication"
|
||||
echo "and have a rwcommunity configured, make sure the following lines are"
|
||||
echo "added to /etc/snmp/snmpd.conf:"
|
||||
echo ""
|
||||
echo " rwcommunity public localhost"
|
||||
echo " agentXSocket unix:/var/run/snmp.sock"
|
||||
echo " agentxperms 777 777"
|
||||
echo ""
|
||||
echo "If you don't rely on systemd you can configure the lines above"
|
||||
echo "and start snmpd manually with 'snmpd -Lo -p /var/run/snmpd.pid'."
|
||||
echo -e "\e[0m"
|
||||
exit -1
|
||||
fi
|
||||
fi
|
||||
|
||||
function validate_oid(){
|
||||
oid=$1
|
||||
oid2=$2
|
||||
type=$3
|
||||
value=$4
|
||||
result=$5
|
||||
|
||||
name="$($snmptranslate $oid)"
|
||||
name2="$($snmptranslate $oid2)"
|
||||
|
||||
if [[ $oid =~ ^([0-9]|\.)+$ ]]; then
|
||||
get=$snmpget
|
||||
getnext=$snmpgetnext
|
||||
else
|
||||
get=$snmpgetstr
|
||||
getnext=$snmpgetnextstr
|
||||
fi
|
||||
|
||||
if [ $oid == $oid2 ]; then
|
||||
if [ -z "$result" ]; then
|
||||
result="$oid = $type: $value"
|
||||
fi
|
||||
|
||||
new "Validating OID: $oid2 = $type: $value"
|
||||
expectpart "$($get $oid)" 0 "$result"
|
||||
else
|
||||
if [ -z "$result" ]; then
|
||||
result="$oid2 = $type: $value"
|
||||
fi
|
||||
|
||||
new "Validating next OID: $oid2 = $type: $value"
|
||||
expectpart "$($getnext $oid)" 0 "$result"
|
||||
fi
|
||||
}
|
||||
fi
|
||||
|
||||
# Check sanity between --with-restconf setting and if nginx is started by systemd or not
|
||||
# This check is optional because some installs, such as vagrant make a non-systemd/direct
|
||||
# start
|
||||
|
|
@ -413,6 +494,31 @@ function chunked_framing()
|
|||
printf "\n#%s\n%s\n##\n" ${length} "${str}"
|
||||
}
|
||||
|
||||
# Start clixon_snmp
|
||||
function start_snmp(){
|
||||
cfg=$1
|
||||
|
||||
rm -f ${clixon_snmp_pidfile}
|
||||
|
||||
$clixon_snmp -f $cfg -D $DBG &
|
||||
|
||||
if [ $? -ne 0 ]; then
|
||||
err
|
||||
fi
|
||||
}
|
||||
|
||||
# Stop clixon_snmp and Valgrind if needed
|
||||
function stop_snmp(){
|
||||
if [ $valgrindtest -eq 4 ]; then
|
||||
pkill -f clixon_snmp
|
||||
sleep 1
|
||||
checkvalgrind
|
||||
else
|
||||
killall -q clixon_snmp
|
||||
fi
|
||||
rm -f ${clixon_snmp_pidfile}
|
||||
}
|
||||
|
||||
# Start backend with all varargs.
|
||||
# If valgrindtest == 2, start valgrind
|
||||
function start_backend(){
|
||||
|
|
@ -544,6 +650,19 @@ function wait_restconf_stopped(){
|
|||
fi
|
||||
}
|
||||
|
||||
# Use pidfile to check snmp started. pidfile is created after init in clixon_snmp
|
||||
function wait_snmp()
|
||||
{
|
||||
let i=0;
|
||||
while [ ! -f ${clixon_snmp_pidfile} ]; do
|
||||
if [ $i -ge $DEMLOOP ]; then
|
||||
err1 "snmp timeout $DEMWAIT seconds"
|
||||
fi
|
||||
sleep $DEMSLEEP
|
||||
let i++;
|
||||
done
|
||||
}
|
||||
|
||||
# End of test, final tests before normal exit of test
|
||||
# Note this is a single test started by new, not a total test suite
|
||||
function endtest()
|
||||
|
|
|
|||
16
test/mem.sh
16
test/mem.sh
|
|
@ -18,6 +18,7 @@ function memonce(){
|
|||
clixon_netconf=
|
||||
clixon_backend=
|
||||
clixon_restconf=
|
||||
clixon_snmp=
|
||||
case "$what" in
|
||||
'cli')
|
||||
valgrindtest=1
|
||||
|
|
@ -43,8 +44,15 @@ function memonce(){
|
|||
clixon_restconf="/usr/bin/valgrind --num-callers=50 --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_restconf"
|
||||
|
||||
;;
|
||||
'snmp')
|
||||
valgrindtest=4 # This means snmp valgrind test
|
||||
sudo chmod 660 $valgrindfile
|
||||
: ${DEMWAIT:=15} # valgrind snmp needs some time to get up
|
||||
clixon_snmp="/usr/bin/valgrind --num-callers=50 --leak-check=full --show-leak-kinds=all --suppressions=./valgrind-clixon.supp --track-fds=yes --trace-children=no --child-silent-after-fork=yes --log-file=$valgrindfile clixon_snmp"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "usage: $0 cli|netconf|restconf|backend" # valgrind memleak checks
|
||||
echo "usage: $0 cli|netconf|restconf|backend|snmp" # valgrind memleak checks
|
||||
rm -f $valgrindfile
|
||||
exit -1
|
||||
;;
|
||||
|
|
@ -86,16 +94,16 @@ function println(){
|
|||
}
|
||||
|
||||
if [ -z "$*" ]; then
|
||||
cmds="backend restconf cli netconf"
|
||||
cmds="backend restconf cli netconf snmp"
|
||||
else
|
||||
cmds=$*
|
||||
fi
|
||||
|
||||
# First run sanity
|
||||
for c in $cmds; do
|
||||
if [ $c != cli -a $c != netconf -a $c != restconf -a $c != backend ]; then
|
||||
if [ $c != cli -a $c != netconf -a $c != restconf -a $c != backend -a $c != snmp ]; then
|
||||
echo "c:$c"
|
||||
echo "usage: $0 [cli|netconf|restconf|backend]+"
|
||||
echo "usage: $0 [cli|netconf|restconf|backend|snmp]+"
|
||||
echo " with no args run all"
|
||||
exit -1
|
||||
fi
|
||||
|
|
|
|||
450
test/mibs/CLIXON-TYPES-MIB.txt
Normal file
450
test/mibs/CLIXON-TYPES-MIB.txt
Normal file
|
|
@ -0,0 +1,450 @@
|
|||
CLIXON-TYPES-MIB DEFINITIONS ::= BEGIN
|
||||
--
|
||||
-- Example MIB objects for agent module example implementations
|
||||
--
|
||||
IMPORTS
|
||||
MODULE-IDENTITY, OBJECT-TYPE, Integer32,
|
||||
TimeTicks, Counter32, Gauge32, Counter64,
|
||||
NOTIFICATION-TYPE, IpAddress FROM SNMPv2-SMI
|
||||
SnmpAdminString FROM SNMP-FRAMEWORK-MIB
|
||||
netSnmp FROM NET-SNMP-MIB
|
||||
TruthValue, TimeStamp,
|
||||
RowStatus, StorageType FROM SNMPv2-TC
|
||||
InetAddressType, InetAddress FROM INET-ADDRESS-MIB
|
||||
IANAifType FROM IANAifType-MIB
|
||||
;
|
||||
clixonExamples MODULE-IDENTITY
|
||||
LAST-UPDATED "200406150000Z"
|
||||
ORGANIZATION "www.net-snmp.org"
|
||||
CONTACT-INFO
|
||||
"postal: Wes Hardaker
|
||||
P.O. Box 382
|
||||
Davis CA 95617
|
||||
email: net-snmp-coders@lists.sourceforge.net"
|
||||
DESCRIPTION
|
||||
"Example MIB objects for agent module example implementations"
|
||||
REVISION "200406150000Z"
|
||||
DESCRIPTION
|
||||
"Corrected notification example definitions"
|
||||
REVISION "200202060000Z"
|
||||
DESCRIPTION
|
||||
"First draft"
|
||||
::= { netSnmp 200 }
|
||||
--
|
||||
-- top level structure
|
||||
--
|
||||
clixonExampleScalars OBJECT IDENTIFIER ::= { clixonExamples 1 }
|
||||
clixonExampleTables OBJECT IDENTIFIER ::= { clixonExamples 2 }
|
||||
clixonExampleNotifications OBJECT IDENTIFIER ::= { clixonExamples 3 }
|
||||
clixonTables OBJECT IDENTIFIER ::= { clixonExamples 4 }
|
||||
clixonInetTables OBJECT IDENTIFIER ::= { clixonExamples 5 }
|
||||
clixonExampleNotificationPrefix OBJECT IDENTIFIER
|
||||
::= { clixonExampleNotifications 0 }
|
||||
clixonExampleNotificationObjects OBJECT IDENTIFIER
|
||||
::= { clixonExampleNotifications 2 }
|
||||
-- clixonTutorial OBJECT IDENTIFIER ::= { clixonExamples 4 }
|
||||
--
|
||||
-- Example scalars
|
||||
--
|
||||
|
||||
clixonExampleInteger OBJECT-TYPE
|
||||
SYNTAX Integer32
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"This is a simple object which merely houses a writable
|
||||
integer. It's only purposes is to hold the value of a single
|
||||
integer. Writing to it will simply change the value for
|
||||
subsequent GET/GETNEXT/GETBULK retrievals.
|
||||
This example object is implemented in the
|
||||
agent/mibgroup/examples/scalar_int.c file."
|
||||
DEFVAL { 42 }
|
||||
::= { clixonExampleScalars 1 }
|
||||
clixonExampleSleeper OBJECT-TYPE
|
||||
SYNTAX Integer32
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"This is a simple object which is a basic integer. It's value
|
||||
indicates the number of seconds that the agent will take in
|
||||
responding to requests of this object. This is implemented
|
||||
in a way which will allow the agent to keep responding to
|
||||
other requests while access to this object is blocked. It is
|
||||
writable, and changing it's value will change the amount of
|
||||
time the agent will effectively wait for before returning a
|
||||
response when this object is manipulated. Note that SET
|
||||
requests through this object will take longer, since the
|
||||
delay is applied to each internal transaction phase, which
|
||||
could result in delays of up to 4 times the value of this
|
||||
object.
|
||||
This example object is implemented in the
|
||||
agent/mibgroup/examples/delayed_instance.c file."
|
||||
DEFVAL { 1 }
|
||||
::= { clixonExampleScalars 2 }
|
||||
clixonExampleString OBJECT-TYPE
|
||||
SYNTAX SnmpAdminString
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"This is a simple object which merely houses a writable
|
||||
string. It's only purposes is to hold the value of a single
|
||||
string. Writing to it will simply change the value for
|
||||
subsequent GET/GETNEXT/GETBULK retrievals.
|
||||
This example object is implemented in the
|
||||
agent/mibgroup/examples/watched.c file."
|
||||
DEFVAL { "So long, and thanks for all the fish!" }
|
||||
::= { clixonExampleScalars 3 }
|
||||
ifTableLastChange OBJECT-TYPE
|
||||
SYNTAX TimeTicks
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The value of sysUpTime at the time of the last creation or
|
||||
deletion of an entry in the ifTable. If the number of
|
||||
entries has been unchanged since the last re-initialization
|
||||
of the local network management subsystem, then this object
|
||||
contains a zero value."
|
||||
::= { clixonExampleScalars 4 }
|
||||
ifType OBJECT-TYPE
|
||||
SYNTAX IANAifType
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The type of interface. Additional values for ifType are
|
||||
assigned by the Internet Assigned Numbers Authority (IANA),
|
||||
through updating the syntax of the IANAifType textual
|
||||
convention."
|
||||
::= { clixonExampleScalars 5 }
|
||||
ifSpeed OBJECT-TYPE
|
||||
SYNTAX Gauge32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"An estimate of the interface's current bandwidth in bits
|
||||
per second. For interfaces which do not vary in bandwidth
|
||||
or for those where no accurate estimation can be made, this
|
||||
object should contain the nominal bandwidth. If the
|
||||
bandwidth of the interface is greater than the maximum value
|
||||
reportable by this object then this object should report its
|
||||
maximum value (4,294,967,295) and ifHighSpeed must be used
|
||||
to report the interace's speed. For a sub-layer which has
|
||||
no concept of bandwidth, this object should be zero."
|
||||
::= { clixonExampleScalars 6 }
|
||||
ifAdminStatus OBJECT-TYPE
|
||||
SYNTAX INTEGER {
|
||||
up(1), -- ready to pass packets
|
||||
down(2),
|
||||
testing(3) -- in some test mode
|
||||
}
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The desired state of the interface. The testing(3) state
|
||||
indicates that no operational packets can be passed. When a
|
||||
managed system initializes, all interfaces start with
|
||||
ifAdminStatus in the down(2) state. As a result of either
|
||||
explicit management action or per configuration information
|
||||
retained by the managed system, ifAdminStatus is then
|
||||
changed to either the up(1) or testing(3) states (or remains
|
||||
in the down(2) state)."
|
||||
::= { clixonExampleScalars 7}
|
||||
ifInOctets OBJECT-TYPE
|
||||
SYNTAX Counter32
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The total number of octets received on the interface,
|
||||
including framing characters.
|
||||
Discontinuities in the value of this counter can occur at
|
||||
re-initialization of the management system, and at other
|
||||
times as indicated by the value of
|
||||
ifCounterDiscontinuityTime."
|
||||
::= { clixonExampleScalars 8}
|
||||
ifHCInOctets OBJECT-TYPE
|
||||
SYNTAX Counter64
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The total number of octets received on the interface,
|
||||
including framing characters. This object is a 64-bit
|
||||
version of ifInOctets.
|
||||
Discontinuities in the value of this counter can occur at
|
||||
re-initialization of the management system, and at other
|
||||
times as indicated by the value of
|
||||
ifCounterDiscontinuityTime."
|
||||
::= { clixonExampleScalars 9}
|
||||
ifPromiscuousMode OBJECT-TYPE
|
||||
SYNTAX TruthValue
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"This object has a value of false(2) if this interface only
|
||||
accepts packets/frames that are addressed to this station.
|
||||
This object has a value of true(1) when the station accepts
|
||||
all packets/frames transmitted on the media. The value
|
||||
true(1) is only legal on certain types of media. If legal,
|
||||
setting this object to a value of true(1) may require the
|
||||
interface to be reset before becoming effective.
|
||||
The value of ifPromiscuousMode does not affect the reception
|
||||
of broadcast and multicast packets/frames by the interface."
|
||||
::= { clixonExampleScalars 10 }
|
||||
ifCounterDiscontinuityTime OBJECT-TYPE
|
||||
SYNTAX TimeStamp
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The value of sysUpTime on the most recent occasion at which
|
||||
any one or more of this interface's counters suffered a
|
||||
discontinuity. The relevant counters are the specific
|
||||
instances associated with this interface of any Counter32 or
|
||||
Counter64 object contained in the ifTable or ifXTable. If
|
||||
no such discontinuities have occurred since the last re-
|
||||
initialization of the local management subsystem, then this
|
||||
object contains a zero value."
|
||||
::= { clixonExampleScalars 11 }
|
||||
ifStackStatus OBJECT-TYPE
|
||||
SYNTAX RowStatus
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The status of the relationship between two sub-layers.
|
||||
Changing the value of this object from 'active' to
|
||||
'notInService' or 'destroy' will likely have consequences up
|
||||
and down the interface stack. Thus, write access to this
|
||||
object is likely to be inappropriate for some types of
|
||||
interfaces, and many implementations will choose not to
|
||||
support write-access for any type of interface."
|
||||
::= { clixonExampleScalars 12 }
|
||||
|
||||
ifIpAddr OBJECT-TYPE
|
||||
SYNTAX IpAddress
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"IP address example."
|
||||
::= { clixonExampleScalars 13 }
|
||||
|
||||
--
|
||||
-- Example Tables
|
||||
--
|
||||
clixonIETFWGTable OBJECT-TYPE
|
||||
SYNTAX SEQUENCE OF ClixonIETFWGEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"This table merely contains a set of data which is otherwise
|
||||
useless for true network management. It is a table which
|
||||
describes properies about a IETF Working Group, such as the
|
||||
names of the two working group chairs.
|
||||
This example table is implemented in the
|
||||
agent/mibgroup/examples/data_set.c file."
|
||||
::= { clixonExampleTables 1 }
|
||||
clixonIETFWGEntry OBJECT-TYPE
|
||||
SYNTAX ClixonIETFWGEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A row describing a given working group"
|
||||
INDEX { nsIETFWGName }
|
||||
::= {clixonIETFWGTable 1 }
|
||||
ClixonIETFWGEntry ::= SEQUENCE {
|
||||
nsIETFWGName INTEGER,
|
||||
nsIETFWGChair1 OCTET STRING,
|
||||
nsIETFWGChair2 OCTET STRING
|
||||
}
|
||||
nsIETFWGName OBJECT-TYPE
|
||||
SYNTAX INTEGER (1..2147483647)
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The name of the IETF Working Group this table describes."
|
||||
::= { clixonIETFWGEntry 1 }
|
||||
nsIETFWGChair1 OBJECT-TYPE
|
||||
SYNTAX OCTET STRING
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"One of the names of the chairs for the IETF working group."
|
||||
::= { clixonIETFWGEntry 2 }
|
||||
nsIETFWGChair2 OBJECT-TYPE
|
||||
SYNTAX OCTET STRING
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The other name, if one exists, of the chairs for the IETF
|
||||
working group."
|
||||
::= { clixonIETFWGEntry 3 }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
clixonTable OBJECT-TYPE
|
||||
SYNTAX SEQUENCE OF ClixonEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"This table merely contains a set of data which is otherwise
|
||||
useless for true network management. It is a table which
|
||||
describes properies about a IETF Working Group, such as the
|
||||
names of the two working group chairs.
|
||||
This example table is implemented in the
|
||||
agent/mibgroup/examples/data_set.c file."
|
||||
::= { clixonTables 1 }
|
||||
clixonEntry OBJECT-TYPE
|
||||
SYNTAX ClixonEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A row describing a given working group"
|
||||
INDEX { nsName }
|
||||
::= {clixonTable 1 }
|
||||
ClixonEntry ::= SEQUENCE {
|
||||
nsName INTEGER,
|
||||
nsChair1 OCTET STRING,
|
||||
nsChair2 OCTET STRING
|
||||
}
|
||||
nsName OBJECT-TYPE
|
||||
SYNTAX INTEGER (1..2147483647)
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The name of the IETF Working Group this table describes."
|
||||
::= { clixonEntry 1 }
|
||||
nsChair1 OBJECT-TYPE
|
||||
SYNTAX OCTET STRING
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"One of the names of the chairs for the IETF working group."
|
||||
::= { clixonEntry 2 }
|
||||
nsChair2 OBJECT-TYPE
|
||||
SYNTAX OCTET STRING
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The other name, if one exists, of the chairs for the IETF
|
||||
working group."
|
||||
::= { clixonEntry 3 }
|
||||
|
||||
|
||||
--
|
||||
-- A table used in a table_iterator example
|
||||
-- (agent/mibgroup/examples/clixonHostsTable*.[ch])
|
||||
--
|
||||
clixonHostsTable OBJECT-TYPE
|
||||
SYNTAX SEQUENCE OF ClixonHostsEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"An example table that implements a wrapper around the
|
||||
/etc/hosts file on a machine using the iterator helper API."
|
||||
::= { clixonExampleTables 2 }
|
||||
clixonHostsEntry OBJECT-TYPE
|
||||
SYNTAX ClixonHostsEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A host name mapped to an ip address"
|
||||
INDEX { clixonHostName }
|
||||
::= { clixonHostsTable 1 }
|
||||
ClixonHostsEntry ::= SEQUENCE {
|
||||
clixonHostName OCTET STRING,
|
||||
clixonHostAddressType InetAddressType,
|
||||
clixonHostAddress InetAddress,
|
||||
clixonHostStorage StorageType,
|
||||
clixonHostRowStatus RowStatus
|
||||
}
|
||||
|
||||
clixonHostName OBJECT-TYPE
|
||||
SYNTAX OCTET STRING (SIZE(0..64))
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A host name that exists in the /etc/hosts (unix) file."
|
||||
::= { clixonHostsEntry 1 }
|
||||
clixonHostAddressType OBJECT-TYPE
|
||||
SYNTAX InetAddressType
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The address type of then given host."
|
||||
::= { clixonHostsEntry 2 }
|
||||
clixonHostAddress OBJECT-TYPE
|
||||
SYNTAX InetAddress
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The address of then given host."
|
||||
::= { clixonHostsEntry 3 }
|
||||
clixonHostStorage OBJECT-TYPE
|
||||
SYNTAX StorageType
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION "The storage type for this conceptual row."
|
||||
DEFVAL { nonVolatile }
|
||||
::= { clixonHostsEntry 4 }
|
||||
clixonHostRowStatus OBJECT-TYPE
|
||||
SYNTAX RowStatus
|
||||
MAX-ACCESS read-create
|
||||
STATUS current
|
||||
DESCRIPTION "The status of this conceptual row."
|
||||
::= { clixonHostsEntry 5 }
|
||||
|
||||
clixonObjectID OBJECT-TYPE
|
||||
SYNTAX OBJECT IDENTIFIER
|
||||
MAX-ACCESS read-only
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The vendor's authoritative identification of the
|
||||
network management subsystem contained in the entity.
|
||||
This value is allocated within the SMI enterprises
|
||||
subtree (1.3.6.1.4.1) and provides an easy and
|
||||
unambiguous means for determining `what kind of box' is
|
||||
being managed. For example, if vendor `Flintstones,
|
||||
Inc.' was assigned the subtree 1.3.6.1.4.1.424242,
|
||||
it could assign the identifier 1.3.6.1.4.1.424242.1.1
|
||||
to its `Fred Router'."
|
||||
::= { netSnmp 3 }
|
||||
|
||||
|
||||
clixonInetTable OBJECT-TYPE
|
||||
SYNTAX SEQUENCE OF ClixonInetEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"This table merely contains a set of data which is otherwise
|
||||
useless for true network management. It is a table which
|
||||
describes properies about a IETF Working Group, such as the
|
||||
names of the two working group chairs.
|
||||
This example table is implemented in the
|
||||
agent/mibgroup/examples/data_set.c file."
|
||||
::= { clixonExampleTables 3 }
|
||||
clixonInetEntry OBJECT-TYPE
|
||||
SYNTAX ClixonInetEntry
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"A row describing a given working group"
|
||||
INDEX { clixonAddress }
|
||||
::= {clixonInetTable 1 }
|
||||
ClixonInetEntry ::= SEQUENCE {
|
||||
clixonAddress InetAddress,
|
||||
clixonString OCTET STRING
|
||||
}
|
||||
clixonAddress OBJECT-TYPE
|
||||
SYNTAX InetAddress
|
||||
MAX-ACCESS not-accessible
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"The name of the IETF Working Group this table describes."
|
||||
::= { clixonInetEntry 2 }
|
||||
clixonString OBJECT-TYPE
|
||||
SYNTAX OCTET STRING
|
||||
MAX-ACCESS read-write
|
||||
STATUS current
|
||||
DESCRIPTION
|
||||
"One of the names of the chairs for the IETF working group."
|
||||
::= { clixonInetEntry 3 }
|
||||
|
||||
END
|
||||
1411
test/mibs/ENTITY-MIB
Normal file
1411
test/mibs/ENTITY-MIB
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -208,6 +208,12 @@ wait_backend
|
|||
new "expand identityref 1st level"
|
||||
expectpart "$(echo "set identityrefs identityref ?" | $clixon_cli -f $cfg 2> /dev/null)" 0 "ex:des" "ex:des2" "ex:des3"
|
||||
|
||||
# XXX something wrong sometimes in this test on docker.
|
||||
# Expected:
|
||||
# <name>
|
||||
# CLI syntax error: "set leafrefs leafref": Incomplete command
|
||||
echo "set leafrefs leafref ?" | $clixon_cli -f $cfg -o CLICON_CLI_EXPAND_LEAFREF=false
|
||||
|
||||
new "expand leafref 1st level"
|
||||
expectpart "$(echo "set leafrefs leafref ?" | $clixon_cli -f $cfg -o CLICON_CLI_EXPAND_LEAFREF=false 2> /dev/null)" 0 "<name>" --not-- "91" "92" "93"
|
||||
|
||||
|
|
|
|||
516
test/test_snmp_entity.sh
Executable file
516
test/test_snmp_entity.sh
Executable file
|
|
@ -0,0 +1,516 @@
|
|||
#!/usr/bin/env bash
|
||||
# SNMP "smoketest" Basic snmpget test for a scalar
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
# Re-use main example backend state callbacks
|
||||
APPNAME=example
|
||||
|
||||
if [ ${ENABLE_NETSNMP} != "yes" ]; then
|
||||
echo "Skipping test, Net-SNMP support not enabled."
|
||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
fi
|
||||
|
||||
cfg=$dir/conf_startup.xml
|
||||
fyang=$dir/clixon-example.yang
|
||||
fstate=$dir/state.xml
|
||||
|
||||
# AgentX unix socket
|
||||
SOCK=/var/run/snmp.sock
|
||||
|
||||
# Relies on example_backend.so for $fstate file handling
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${YANG_STANDARD_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${MIB_GENERATED_YANG_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_BACKEND_PIDFILE>/var/tmp/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||
<CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK>
|
||||
<CLICON_SNMP_MIB>ENTITY-MIB</CLICON_SNMP_MIB>
|
||||
<CLICON_VALIDATE_STATE_XML>true</CLICON_VALIDATE_STATE_XML>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module clixon-example{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import ENTITY-MIB {
|
||||
prefix "entity-mib";
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# This is state data written to file that backend reads from (on request)
|
||||
# integer and string have values, sleeper does not and uses default (=1)
|
||||
|
||||
cat <<EOF > $fstate
|
||||
<ENTITY-MIB xmlns="urn:ietf:params:xml:ns:yang:smiv2:ENTITY-MIB">
|
||||
<entPhysicalTable>
|
||||
<entPhysicalEntry>
|
||||
<entPhysicalIndex>1</entPhysicalIndex>
|
||||
<entPhysicalDescr>Entity 1</entPhysicalDescr>
|
||||
<entPhysicalVendorType>1.3.6.1.2.1.4</entPhysicalVendorType>
|
||||
<entPhysicalContainedIn>9</entPhysicalContainedIn>
|
||||
<entPhysicalClass>powerSupply</entPhysicalClass>
|
||||
<entPhysicalParentRelPos>123</entPhysicalParentRelPos>
|
||||
<entPhysicalName>ABCD1234</entPhysicalName>
|
||||
<entPhysicalHardwareRev>REV 099</entPhysicalHardwareRev>
|
||||
<entPhysicalFirmwareRev>REV 123</entPhysicalFirmwareRev>
|
||||
<entPhysicalSoftwareRev>Clixon Version XXX.YYY year ZZZ</entPhysicalSoftwareRev>
|
||||
<entPhysicalSerialNum>1234-1234-ABCD-ABCD</entPhysicalSerialNum>
|
||||
<entPhysicalMfgName>Olof Hagsand Datakonsult AB</entPhysicalMfgName>
|
||||
<entPhysicalModelName>Model AA.BB</entPhysicalModelName>
|
||||
<entPhysicalAlias>Alias 123</entPhysicalAlias>
|
||||
<entPhysicalAssetID>Asset 123</entPhysicalAssetID>
|
||||
<entPhysicalIsFRU>true</entPhysicalIsFRU>
|
||||
<entPhysicalMfgDate>11111111</entPhysicalMfgDate>
|
||||
<!-- <entPhysicalUris></entPhysicalUris>-->
|
||||
<!-- <entPhysicalUUID></entPhysicalUUID> -->
|
||||
</entPhysicalEntry>
|
||||
<entPhysicalEntry>
|
||||
<entPhysicalIndex>2</entPhysicalIndex>
|
||||
<entPhysicalDescr>Entity 2</entPhysicalDescr>
|
||||
<entPhysicalVendorType>1.3.6.1.2.1.4</entPhysicalVendorType>
|
||||
<entPhysicalContainedIn>4</entPhysicalContainedIn>
|
||||
<entPhysicalClass>powerSupply</entPhysicalClass>
|
||||
<entPhysicalParentRelPos>999</entPhysicalParentRelPos>
|
||||
<entPhysicalName>XXZZ11994</entPhysicalName>
|
||||
<entPhysicalHardwareRev>REV 100</entPhysicalHardwareRev>
|
||||
<entPhysicalFirmwareRev>REV 234</entPhysicalFirmwareRev>
|
||||
<entPhysicalSoftwareRev>Clixon Version XXX.YYY year ZZZ</entPhysicalSoftwareRev>
|
||||
<entPhysicalSerialNum>2345-2345-ABCD-ABCD</entPhysicalSerialNum>
|
||||
<entPhysicalMfgName>Olof Hagsand Datakonsult AB</entPhysicalMfgName>
|
||||
<entPhysicalModelName>Model CC.DD</entPhysicalModelName>
|
||||
<entPhysicalAlias>Alias 456</entPhysicalAlias>
|
||||
<entPhysicalAssetID>Asset 456</entPhysicalAssetID>
|
||||
<entPhysicalIsFRU>false</entPhysicalIsFRU>
|
||||
<entPhysicalMfgDate>22222222</entPhysicalMfgDate>
|
||||
<!-- <entPhysicalUris></entPhysicalUris> -->
|
||||
<!-- <entPhysicalUUID></entPhysicalUUID> -->
|
||||
</entPhysicalEntry>
|
||||
</entPhysicalTable>
|
||||
</ENTITY-MIB>
|
||||
EOF
|
||||
|
||||
function testinit(){
|
||||
new "test params: -f $cfg -- -sS $fstate"
|
||||
if [ $BE -ne 0 ]; then
|
||||
# Kill old backend and start a new one
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "Failed to start backend"
|
||||
fi
|
||||
|
||||
sudo pkill -f clixon_backend
|
||||
|
||||
new "Starting backend"
|
||||
start_backend -s init -f $cfg -- -sS $fstate
|
||||
fi
|
||||
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
if [ $SN -ne 0 ]; then
|
||||
# Kill old clixon_snmp, if any
|
||||
new "Terminating any old clixon_snmp processes"
|
||||
sudo killall -q clixon_snmp
|
||||
|
||||
new "Starting clixon_snmp"
|
||||
start_snmp $cfg &
|
||||
fi
|
||||
|
||||
new "wait snmp"
|
||||
wait_snmp
|
||||
}
|
||||
|
||||
function testexit(){
|
||||
stop_snmp
|
||||
}
|
||||
|
||||
ENTITY_OID=".1.3.6.1.2.1.47.1.1.1"
|
||||
|
||||
OID1="${ENTITY_OID}.1.1.1"
|
||||
OID2="${ENTITY_OID}.1.1.2"
|
||||
OID3="${ENTITY_OID}.1.2.1"
|
||||
OID4="${ENTITY_OID}.1.2.2"
|
||||
OIDX="${ENTITY_OID}.1.3.1"
|
||||
OIDY="${ENTITY_OID}.1.3.2"
|
||||
OID5="${ENTITY_OID}.1.4.1"
|
||||
OID6="${ENTITY_OID}.1.4.2"
|
||||
OID7="${ENTITY_OID}.1.5.1"
|
||||
OID8="${ENTITY_OID}.1.5.2"
|
||||
OID9="${ENTITY_OID}.1.6.1"
|
||||
OID10="${ENTITY_OID}.1.6.2"
|
||||
OID11="${ENTITY_OID}.1.7.1"
|
||||
OID12="${ENTITY_OID}.1.7.2"
|
||||
OID13="${ENTITY_OID}.1.8.1"
|
||||
OID14="${ENTITY_OID}.1.8.2"
|
||||
OID15="${ENTITY_OID}.1.9.1"
|
||||
OID16="${ENTITY_OID}.1.9.2"
|
||||
OID17="${ENTITY_OID}.1.10.1"
|
||||
OID18="${ENTITY_OID}.1.10.2"
|
||||
OID19="${ENTITY_OID}.1.11.1"
|
||||
OID20="${ENTITY_OID}.1.11.2"
|
||||
OID21="${ENTITY_OID}.1.12.1"
|
||||
OID22="${ENTITY_OID}.1.12.2"
|
||||
OID23="${ENTITY_OID}.1.13.1"
|
||||
OID24="${ENTITY_OID}.1.13.2"
|
||||
OID25="${ENTITY_OID}.1.14.1"
|
||||
OID26="${ENTITY_OID}.1.14.2"
|
||||
OID27="${ENTITY_OID}.1.15.1"
|
||||
OID28="${ENTITY_OID}.1.15.2"
|
||||
OID29="${ENTITY_OID}.1.16.1"
|
||||
OID30="${ENTITY_OID}.1.16.2"
|
||||
OID31="${ENTITY_OID}.1.17.1"
|
||||
OID32="${ENTITY_OID}.1.17.2"
|
||||
|
||||
NAME1="ENTITY-MIB::entPhysicalIndex.1"
|
||||
NAME2="ENTITY-MIB::entPhysicalIndex.2"
|
||||
NAME3="ENTITY-MIB::entPhysicalDescr.1"
|
||||
NAME4="ENTITY-MIB::entPhysicalDescr.2"
|
||||
NAMEX="ENTITY-MIB::entPhysicalVendorType.1"
|
||||
NAMEY="ENTITY-MIB::entPhysicalVendorType.2"
|
||||
NAME5="ENTITY-MIB::entPhysicalContainedIn.1"
|
||||
NAME6="ENTITY-MIB::entPhysicalContainedIn.2"
|
||||
NAME7="ENTITY-MIB::entPhysicalClass.1"
|
||||
NAME8="ENTITY-MIB::entPhysicalClass.2"
|
||||
NAME9="ENTITY-MIB::entPhysicalParentRelPos.1"
|
||||
NAME10="ENTITY-MIB::entPhysicalParentRelPos.2"
|
||||
NAME11="ENTITY-MIB::entPhysicalName.1"
|
||||
NAME12="ENTITY-MIB::entPhysicalName.2"
|
||||
NAME13="ENTITY-MIB::entPhysicalHardwareRev.1"
|
||||
NAME14="ENTITY-MIB::entPhysicalHardwareRev.2"
|
||||
NAME15="ENTITY-MIB::entPhysicalFirmwareRev.1"
|
||||
NAME16="ENTITY-MIB::entPhysicalFirmwareRev.2"
|
||||
NAME17="ENTITY-MIB::entPhysicalSoftwareRev.1"
|
||||
NAME18="ENTITY-MIB::entPhysicalSoftwareRev.2"
|
||||
NAME19="ENTITY-MIB::entPhysicalSerialNum.1"
|
||||
NAME20="ENTITY-MIB::entPhysicalSerialNum.2"
|
||||
NAME21="ENTITY-MIB::entPhysicalMfgName.1"
|
||||
NAME22="ENTITY-MIB::entPhysicalMfgName.2"
|
||||
NAME23="ENTITY-MIB::entPhysicalModelName.1"
|
||||
NAME24="ENTITY-MIB::entPhysicalModelName.2"
|
||||
NAME25="ENTITY-MIB::entPhysicalAlias.1"
|
||||
NAME26="ENTITY-MIB::entPhysicalAlias.2"
|
||||
NAME27="ENTITY-MIB::entPhysicalAssetID.1"
|
||||
NAME28="ENTITY-MIB::entPhysicalAssetID.2"
|
||||
NAME29="ENTITY-MIB::entPhysicalIsFRU.1"
|
||||
NAME30="ENTITY-MIB::entPhysicalIsFRU.2"
|
||||
NAME31="ENTITY-MIB::entPhysicalMfgDate.1"
|
||||
NAME32="ENTITY-MIB::entPhysicalMfgDate.2"
|
||||
NAME33="ENTITY-MIB::entPhysicalUris.1"
|
||||
NAME34="ENTITY-MIB::entPhysicalUris.2"
|
||||
NAME35="ENTITY-MIB::entPhysicalUris.2"
|
||||
|
||||
new "SNMP system tests"
|
||||
testinit
|
||||
|
||||
new "Get index, $OID1"
|
||||
validate_oid $OID1 $OID1 "INTEGER" "1"
|
||||
validate_oid $NAME1 $NAME1 "INTEGER" "1"
|
||||
|
||||
new "Get next $OID1"
|
||||
validate_oid $OID1 $OID2 "INTEGER" "2"
|
||||
validate_oid $NAME1 $NAME2 "INTEGER" "2"
|
||||
|
||||
new "Get index, $OID2"
|
||||
validate_oid $OID2 $OID2 "INTEGER" "2"
|
||||
validate_oid $NAME2 $NAME2 "INTEGER" "2"
|
||||
|
||||
new "Get next $OID2"
|
||||
validate_oid $OID2 $OID3 "STRING" "\"Entity 1\""
|
||||
validate_oid $NAME2 $NAME3 "STRING" "Entity 1"
|
||||
|
||||
new "Get index, $OID3"
|
||||
validate_oid $OID3 $OID3 "STRING" "\"Entity 1\""
|
||||
validate_oid $NAME3 $NAME3 "STRING" "Entity 1"
|
||||
|
||||
new "Get next $OID4"
|
||||
validate_oid $OID3 $OID4 "STRING" "\"Entity 2\""
|
||||
validate_oid $NAME3 $NAME4 "STRING" "Entity 2"
|
||||
|
||||
new "Get index, $OID4"
|
||||
validate_oid $OID4 $OID4 "STRING" "\"Entity 2\""
|
||||
validate_oid $NAME4 $NAME4 "STRING" "Entity 2"
|
||||
|
||||
new "Get next $OID4"
|
||||
validate_oid $OID4 $OIDX "OID" ".1.3.6.1.2.1.4"
|
||||
validate_oid $NAME4 $NAMEX "OID" "IP-MIB::ip"
|
||||
|
||||
new "Get $NAMEX"
|
||||
validate_oid $OIDX $OIDX "OID" ".1.3.6.1.2.1.4"
|
||||
validate_oid $NAMEX $NAMEX "OID" "IP-MIB::ip"
|
||||
|
||||
new "Get next $NAMEX"
|
||||
validate_oid $OIDX $OIDY "OID" ".1.3.6.1.2.1.4"
|
||||
validate_oid $NAMEX $NAMEY "OID" "IP-MIB::ip"
|
||||
|
||||
new "Get $NAMEY"
|
||||
validate_oid $OIDY $OIDY "OID" ".1.3.6.1.2.1.4"
|
||||
validate_oid $NAMEY $NAMEY "OID" "IP-MIB::ip"
|
||||
|
||||
new "Get next $NAMEY"
|
||||
validate_oid $OIDY $OID5 "INTEGER" 9
|
||||
validate_oid $NAMEY $NAME5 "INTEGER" 9
|
||||
|
||||
new "Get container, $OID5"
|
||||
validate_oid $OID5 $OID5 "INTEGER" "9"
|
||||
validate_oid $NAME5 $NAME5 "INTEGER" "9"
|
||||
|
||||
new "Get next container, $OID5"
|
||||
validate_oid $OID5 $OID6 "INTEGER" "4"
|
||||
validate_oid $NAME5 $NAME6 "INTEGER" "4"
|
||||
|
||||
new "Get container, $OID6"
|
||||
validate_oid $OID6 $OID6 "INTEGER" "4"
|
||||
validate_oid $NAME6 $NAME6 "INTEGER" "4"
|
||||
|
||||
new "Get next container, $OID6"
|
||||
validate_oid $OID6 $OID7 "INTEGER" "6"
|
||||
validate_oid $NAME6 $NAME7 "INTEGER" "powerSupply(6)"
|
||||
|
||||
new "Get container, $OID7"
|
||||
validate_oid $OID7 $OID7 "INTEGER" "6"
|
||||
validate_oid $NAME7 $NAME7 "INTEGER" "powerSupply(6)"
|
||||
|
||||
new "Get next container, $OID7"
|
||||
validate_oid $OID7 $OID8 "INTEGER" "6"
|
||||
validate_oid $NAME7 $NAME8 "INTEGER" "powerSupply(6)"
|
||||
|
||||
new "Get container, $OID8"
|
||||
validate_oid $OID8 $OID8 "INTEGER" "6"
|
||||
validate_oid $NAME8 $NAME8 "INTEGER" "powerSupply(6)"
|
||||
|
||||
new "Get next container, $OID8"
|
||||
validate_oid $OID8 $OID9 "INTEGER" 123
|
||||
validate_oid $NAME8 $NAME9 "INTEGER" 123
|
||||
|
||||
new "Get name, $OID9"
|
||||
validate_oid $OID9 $OID9 "INTEGER" 123
|
||||
validate_oid $NAME9 $NAME9 "INTEGER" 123
|
||||
|
||||
new "Get next, $OID9"
|
||||
validate_oid $OID9 $OID10 "INTEGER" 999
|
||||
validate_oid $NAME9 $NAME10 "INTEGER" 999
|
||||
|
||||
new "Get name, $OID10"
|
||||
validate_oid $OID10 $OID10 "INTEGER" 999
|
||||
validate_oid $NAME10 $NAME10 "INTEGER" 999
|
||||
|
||||
new "Get name, $OID11"
|
||||
validate_oid $OID11 $OID11 "STRING" "\"ABCD1234\""
|
||||
validate_oid $NAME11 $NAME11 "STRING" "ABCD1234"
|
||||
|
||||
new "Get next, $OID11"
|
||||
validate_oid $OID11 $OID12 "STRING" "\"XXZZ11994\""
|
||||
validate_oid $NAME11 $NAME12 "STRING" "XXZZ11994"
|
||||
|
||||
new "Get name, $OID12"
|
||||
validate_oid $OID12 $OID12 "STRING" "\"XXZZ11994\""
|
||||
validate_oid $NAME12 $NAME12 "STRING" "XXZZ11994"
|
||||
|
||||
new "Get next, $OID12"
|
||||
validate_oid $OID12 $OID13 "STRING" "\"REV 099\""
|
||||
validate_oid $NAME12 $NAME13 "STRING" "REV 099"
|
||||
|
||||
new "Get rev, $OID13"
|
||||
validate_oid $OID13 $OID13 "STRING" "\"REV 099\""
|
||||
validate_oid $NAME13 $NAME13 "STRING" "REV 099"
|
||||
|
||||
new "Get next hw rev, $OID13"
|
||||
validate_oid $OID13 $OID14 "STRING" "\"REV 100\""
|
||||
validate_oid $NAME13 $NAME14 "STRING" "REV 100"
|
||||
|
||||
new "Get hw rev, $OID14"
|
||||
validate_oid $OID14 $OID14 "STRING" "\"REV 100\""
|
||||
validate_oid $NAME14 $NAME14 "STRING" "REV 100"
|
||||
|
||||
new "Get next hw rev, $OID14"
|
||||
validate_oid $OID14 $OID15 "STRING" "\"REV 123\""
|
||||
validate_oid $NAME14 $NAME15 "STRING" "REV 123"
|
||||
|
||||
new "Get fw rev, $OID15"
|
||||
validate_oid $OID15 $OID15 "STRING" "\"REV 123\""
|
||||
validate_oid $NAME15 $NAME15 "STRING" "REV 123"
|
||||
|
||||
new "Get next fw rev, $OID15"
|
||||
validate_oid $OID15 $OID16 "STRING" "\"REV 234\""
|
||||
validate_oid $NAME15 $NAME16 "STRING" "REV 234"
|
||||
|
||||
new "Get fw rev, $OID16"
|
||||
validate_oid $OID16 $OID16 "STRING" "\"REV 234\""
|
||||
validate_oid $NAME16 $NAME16 "STRING" "REV 234"
|
||||
|
||||
new "Get next fw rev, $OID16"
|
||||
validate_oid $OID16 $OID17 "STRING" "\"Clixon Version XXX.YYY year ZZZ\""
|
||||
validate_oid $NAME16 $NAME17 "STRING" "Clixon Version XXX.YYY year ZZZ"
|
||||
|
||||
new "Get sw rev, $OID7"
|
||||
validate_oid $OID17 $OID17 "STRING" "\"Clixon Version XXX.YYY year ZZZ\""
|
||||
validate_oid $NAME17 $NAME17 "STRING" "Clixon Version XXX.YYY year ZZZ"
|
||||
|
||||
new "Get next sw rev, $OID17"
|
||||
validate_oid $OID17 $OID18 "STRING" "\"Clixon Version XXX.YYY year ZZZ\""
|
||||
validate_oid $NAME17 $NAME18 "STRING" "Clixon Version XXX.YYY year ZZZ"
|
||||
|
||||
new "Get sw rev, $OID18"
|
||||
validate_oid $OID18 $OID18 "STRING" "\"Clixon Version XXX.YYY year ZZZ\""
|
||||
validate_oid $NAME18 $NAME18 "STRING" "Clixon Version XXX.YYY year ZZZ"
|
||||
|
||||
new "Get next sw rev, $OID18"
|
||||
validate_oid $OID18 $OID19 "STRING" "\"1234-1234-ABCD-ABCD\""
|
||||
validate_oid $NAME18 $NAME19 "STRING" "1234-1234-ABCD-ABCD"
|
||||
|
||||
new "Get serial, $OID19"
|
||||
validate_oid $OID19 $OID19 "STRING" "\"1234-1234-ABCD-ABCD\""
|
||||
validate_oid $NAME19 $NAME19 "STRING" "1234-1234-ABCD-ABCD"
|
||||
|
||||
new "Get next serial, $OID19"
|
||||
validate_oid $OID19 $OID20 "STRING" "\"2345-2345-ABCD-ABCD\""
|
||||
validate_oid $NAME19 $NAME20 "STRING" "2345-2345-ABCD-ABCD"
|
||||
|
||||
new "Get serial, $OID20"
|
||||
validate_oid $OID20 $OID20 "STRING" "\"2345-2345-ABCD-ABCD\""
|
||||
validate_oid $NAME20 $NAME20 "STRING" "2345-2345-ABCD-ABCD"
|
||||
|
||||
new "Get next serial, $OID20"
|
||||
validate_oid $OID20 $OID21 "STRING" "\"Olof Hagsand Datakonsult AB\""
|
||||
validate_oid $NAME20 $NAME21 "STRING" "Olof Hagsand Datakonsult AB"
|
||||
|
||||
new "Get manufacturer, $OID21"
|
||||
validate_oid $OID21 $OID21 "STRING" "\"Olof Hagsand Datakonsult AB\""
|
||||
validate_oid $NAME21 $NAME21 "STRING" "Olof Hagsand Datakonsult AB"
|
||||
|
||||
new "Get next manufacturer, $OID21"
|
||||
validate_oid $OID21 $OID22 "STRING" "\"Olof Hagsand Datakonsult AB\""
|
||||
validate_oid $NAME21 $NAME22 "STRING" "Olof Hagsand Datakonsult AB"
|
||||
|
||||
new "Get manufacturer, $OID22"
|
||||
validate_oid $OID22 $OID22 "STRING" "\"Olof Hagsand Datakonsult AB\""
|
||||
validate_oid $NAME22 $NAME22 "STRING" "Olof Hagsand Datakonsult AB"
|
||||
|
||||
new "Get next manufacturer, $OID22"
|
||||
validate_oid $OID22 $OID23 "STRING" "\"Model AA.BB\""
|
||||
validate_oid $NAME22 $NAME23 "STRING" "Model AA.BB"
|
||||
|
||||
new "Get model, $OID23"
|
||||
validate_oid $OID23 $OID23 "STRING" "\"Model AA.BB\""
|
||||
validate_oid $NAME23 $NAME23 "STRING" "Model AA.BB"
|
||||
|
||||
new "Get next model, $OID23"
|
||||
validate_oid $OID23 $OID24 "STRING" "\"Model CC.DD\""
|
||||
validate_oid $NAME23 $NAME24 "STRING" "Model CC.DD"
|
||||
|
||||
new "Get model, $OID24"
|
||||
validate_oid $OID24 $OID24 "STRING" "\"Model CC.DD\""
|
||||
validate_oid $NAME24 $NAME24 "STRING" "Model CC.DD"
|
||||
|
||||
new "Get next model, $OID24"
|
||||
validate_oid $OID24 $OID25 "STRING" "\"Alias 123\""
|
||||
validate_oid $NAME24 $NAME25 "STRING" "Alias 123"
|
||||
|
||||
new "Get alias, $OID25"
|
||||
validate_oid $OID25 $OID25 "STRING" "\"Alias 123\""
|
||||
validate_oid $NAME25 $NAME25 "STRING" "Alias 123"
|
||||
|
||||
new "Get next alias, $OID25"
|
||||
validate_oid $OID25 $OID26 "STRING" "\"Alias 456\""
|
||||
validate_oid $NAME25 $NAME26 "STRING" "Alias 456"
|
||||
|
||||
new "Get alias, $OID26"
|
||||
validate_oid $OID26 $OID26 "STRING" "\"Alias 456\""
|
||||
validate_oid $NAME26 $NAME26 "STRING" "Alias 456"
|
||||
|
||||
new "Get next alias, $OID26"
|
||||
validate_oid $OID26 $OID27 "STRING" "\"Asset 123\""
|
||||
validate_oid $NAME26 $NAME27 "STRING" "Asset 123"
|
||||
|
||||
new "Get asset, $OID27"
|
||||
validate_oid $OID27 $OID27 "STRING" "\"Asset 123\""
|
||||
validate_oid $NAME27 $NAME27 "STRING" "Asset 123"
|
||||
|
||||
new "Get next asset, $OID27"
|
||||
validate_oid $OID27 $OID28 "STRING" "\"Asset 456\""
|
||||
validate_oid $NAME27 $NAME28 "STRING" "Asset 456"
|
||||
|
||||
new "Get asset, $OID28"
|
||||
validate_oid $OID28 $OID28 "STRING" "\"ASSET 456\""
|
||||
validate_oid $NAME28 $NAME28 "STRING" "ASSET 456"
|
||||
|
||||
new "Get next asset, $OID28"
|
||||
validate_oid $OID28 $OID29 "INTEGER" "1"
|
||||
validate_oid $NAME28 $NAME29 "INTEGER" "true(1)"
|
||||
|
||||
new "Get fru, $OID29"
|
||||
validate_oid $OID29 $OID29 "INTEGER" "1"
|
||||
validate_oid $NAME29 $NAME29 "INTEGER" "true(1)"
|
||||
|
||||
new "Get next fru, $OID29"
|
||||
validate_oid $OID29 $OID30 "INTEGER" "0"
|
||||
validate_oid $NAME29 $NAME30 "INTEGER" "0"
|
||||
|
||||
new "Get fru 2, $OID30"
|
||||
validate_oid $OID30 $OID30 "INTEGER" "0"
|
||||
validate_oid $NAME30 $NAME30 "INTEGER" "0"
|
||||
|
||||
new "Get next fru 2, $OID30"
|
||||
validate_oid $NAME30 $NAME31 "STRING" "12593-49-49,49:49:49.49"
|
||||
|
||||
new "Get mfg date, $OID31"
|
||||
validate_oid $NAME31 $NAME31 "STRING" "12593-49-49,49:49:49.49"
|
||||
|
||||
new "Get next mfg date, $OID31"
|
||||
validate_oid $NAME31 $NAME32 "STRING" "12850-50-50,50:50:50.50"
|
||||
|
||||
new "Get mfg date, $OID32"
|
||||
validate_oid $NAME32 $NAME32 "STRING" "12850-50-50,50:50:50.50"
|
||||
|
||||
new "Validate snmpwalk"
|
||||
expectpart "$($snmpwalk $ENTITY_OID)" 0 "SNMPv2-SMI::mib-2.47.1.1.1.1.1.1 = INTEGER: 1" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.1.2 = INTEGER: 2" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.2.1 = STRING: \"Entity 1\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.2.2 = STRING: \"Entity 2\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.3.1 = OID: IP-MIB::ip" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.3.2 = OID: IP-MIB::ip" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.4.1 = INTEGER: 9" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.4.2 = INTEGER: 4" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.5.1 = INTEGER: 6" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.5.2 = INTEGER: 6" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.6.1 = INTEGER: 123" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.6.2 = INTEGER: 999" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.7.1 = STRING: \"ABCD1234\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.7.2 = STRING: \"XXZZ11994\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.8.1 = STRING: \"REV 099\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.8.2 = STRING: \"REV 100\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.9.1 = STRING: \"REV 123\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.9.2 = STRING: \"REV 234\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.10.1 = STRING: \"Clixon Version XXX.YYY year ZZZ\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.10.2 = STRING: \"Clixon Version XXX.YYY year ZZZ\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.11.1 = STRING: \"1234-1234-ABCD-ABCD\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.11.2 = STRING: \"2345-2345-ABCD-ABCD\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.12.1 = STRING: \"Olof Hagsand Datakonsult AB\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.12.2 = STRING: \"Olof Hagsand Datakonsult AB\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.13.1 = STRING: \"Model AA.BB\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.13.2 = STRING: \"Model CC.DD\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.14.1 = STRING: \"Alias 123\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.14.2 = STRING: \"Alias 456\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.15.1 = STRING: \"Asset 123\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.15.2 = STRING: \"Asset 456\"" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.16.1 = INTEGER: 1" \
|
||||
"SNMPv2-SMI::mib-2.47.1.1.1.1.16.2 = INTEGER: 0" \
|
||||
|
||||
new "Cleaning up"
|
||||
# testexit
|
||||
|
||||
new "endtest"
|
||||
endtest
|
||||
286
test/test_snmp_get.sh
Executable file
286
test/test_snmp_get.sh
Executable file
|
|
@ -0,0 +1,286 @@
|
|||
#!/usr/bin/env bash
|
||||
# SNMP "smoketest" Basic snmpget test for a scalar
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
# Re-use main example backend state callbacks
|
||||
APPNAME=example
|
||||
|
||||
if [ ${ENABLE_NETSNMP} != "yes" ]; then
|
||||
echo "Skipping test, Net-SNMP support not enabled."
|
||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
fi
|
||||
|
||||
cfg=$dir/conf_startup.xml
|
||||
fyang=$dir/clixon-example.yang
|
||||
fstate=$dir/state.xml
|
||||
|
||||
# AgentX unix socket
|
||||
SOCK=/var/run/snmp.sock
|
||||
|
||||
# Relies on example_backend.so for $fstate file handling
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${YANG_STANDARD_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${MIB_GENERATED_YANG_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_BACKEND_PIDFILE>/var/tmp/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||
<CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK>
|
||||
<CLICON_SNMP_MIB>CLIXON-TYPES-MIB</CLICON_SNMP_MIB>
|
||||
<CLICON_VALIDATE_STATE_XML>true</CLICON_VALIDATE_STATE_XML>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module clixon-example{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import CLIXON-TYPES-MIB {
|
||||
prefix "clixon-types";
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# This is state data written to file that backend reads from (on request)
|
||||
# integer and string have values, sleeper does not and uses default (=1)
|
||||
|
||||
cat <<EOF > $fstate
|
||||
<CLIXON-TYPES-MIB xmlns="urn:ietf:params:xml:ns:yang:smiv2:CLIXON-TYPES-MIB">
|
||||
<clixonExampleScalars>
|
||||
<clixonExampleInteger>0x7fffffff</clixonExampleInteger>
|
||||
<clixonExampleSleeper>-1</clixonExampleSleeper>
|
||||
<clixonExampleString>This is not default</clixonExampleString>
|
||||
<ifTableLastChange>12345</ifTableLastChange>
|
||||
<ifType>modem</ifType>
|
||||
<ifSpeed>123123123</ifSpeed>
|
||||
<ifAdminStatus>testing</ifAdminStatus>
|
||||
<ifInOctets>123456</ifInOctets>
|
||||
<ifHCInOctets>4294967296</ifHCInOctets>
|
||||
<ifPromiscuousMode>true</ifPromiscuousMode>
|
||||
<ifCounterDiscontinuityTime>1234567890</ifCounterDiscontinuityTime>
|
||||
<ifStackStatus>active</ifStackStatus>
|
||||
</clixonExampleScalars>
|
||||
<clixonIETFWGTable>
|
||||
<clixonIETFWGEntry>
|
||||
<nsIETFWGName>42</nsIETFWGName>
|
||||
<nsIETFWGChair1>Name1</nsIETFWGChair1>
|
||||
<nsIETFWGChair2>Name2</nsIETFWGChair2>
|
||||
</clixonIETFWGEntry>
|
||||
</clixonIETFWGTable>
|
||||
<clixonHostsTable>
|
||||
<clixonHostsEntry>
|
||||
<clixonHostName>test</clixonHostName>
|
||||
<clixonHostAddressType>ipv4</clixonHostAddressType>
|
||||
<clixonHostAddress>10.20.30.40</clixonHostAddress>
|
||||
<clixonHostStorage>permanent</clixonHostStorage>
|
||||
<clixonHostRowStatus>active</clixonHostRowStatus>
|
||||
</clixonHostsEntry>
|
||||
</clixonHostsTable>
|
||||
<clixonInetTable>
|
||||
<clixonInetEntry>
|
||||
<clixonAddress>1.2.3.4</clixonAddress>
|
||||
<clixonString>foo</clixonString>
|
||||
</clixonInetEntry>
|
||||
<clixonInetEntry>
|
||||
<clixonAddress>2.2.2.2</clixonAddress>
|
||||
<clixonString>bar</clixonString>
|
||||
</clixonInetEntry>
|
||||
</clixonInetTable>
|
||||
</CLIXON-TYPES-MIB>
|
||||
EOF
|
||||
|
||||
function testinit(){
|
||||
new "test params: -f $cfg -- -sS $fstate"
|
||||
if [ $BE -ne 0 ]; then
|
||||
# Kill old backend and start a new one
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "Failed to start backend"
|
||||
fi
|
||||
|
||||
sudo pkill -f clixon_backend
|
||||
|
||||
new "Starting backend"
|
||||
start_backend -s init -f $cfg -- -sS $fstate
|
||||
fi
|
||||
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
if [ $SN -ne 0 ]; then
|
||||
# Kill old clixon_snmp, if any
|
||||
new "Terminating any old clixon_snmp processes"
|
||||
sudo killall -q clixon_snmp
|
||||
|
||||
new "Starting clixon_snmp"
|
||||
start_snmp $cfg &
|
||||
fi
|
||||
|
||||
new "wait snmp"
|
||||
wait_snmp
|
||||
}
|
||||
|
||||
function testexit(){
|
||||
stop_snmp
|
||||
}
|
||||
|
||||
new "SNMP tests"
|
||||
testinit
|
||||
|
||||
MIB=".1.3.6.1.4.1.8072.200"
|
||||
OID1="${MIB}.1.1" # netSnmpExampleInteger
|
||||
OID2="${MIB}.1.2" # netSnmpExampleSleeper
|
||||
OID3="${MIB}.1.3" # netSnmpExampleString
|
||||
OID4="${MIB}.1.4" # ifTableLastChange 12345678
|
||||
OID5="${MIB}.1.5" # ifType modem(48)
|
||||
OID6="${MIB}.1.6" # ifSpeed 123123123
|
||||
OID7="${MIB}.1.7" # ifAdminStatus testing(3)
|
||||
OID8="${MIB}.1.8" # ifInOctets 123456
|
||||
OID9="${MIB}.1.9" # ifHCInOctets 4294967296
|
||||
OID10="${MIB}.1.10" # ifPromiscuousMode true(1)
|
||||
OID11="${MIB}.1.11" # ifCounterDiscontinuityTime 1234567890 TimeStamp
|
||||
OID12="${MIB}.1.12" # ifStackStatus active(1)
|
||||
OID13="${MIB}.2.1" # netSnmpIETFWGTable
|
||||
OID14="${MIB}.2.1.1" # netSnmpIETFWGEntry
|
||||
OID15="${MIB}.2.1.1.1.42" # nsIETFWGName
|
||||
OID16="${MIB}.2.1.1.2.42" # nsIETFWGChair1
|
||||
OID17="${MIB}.2.1.1.3.42" # nsIETFWGChair2
|
||||
OID18="${MIB}.2.2" # netSnmpHostsTable
|
||||
OID19="${MIB}.2.2.1.1.4.116.101.115.116" # netSnmpHostName
|
||||
OID20="${MIB}.2.2.1.2.4.116.101.115.116" # netSnmpHostAddressType
|
||||
OID21="${MIB}.2.2.1.3" # netSnmpHostAddress
|
||||
OID22="${MIB}.2.2.1.4" # netSnmpHostStorage
|
||||
OID23="${MIB}.2.2.1.5" # netSnmpHostRowStatus
|
||||
|
||||
NAME1="CLIXON-TYPES-MIB::clixonExampleInteger"
|
||||
NAME2="CLIXON-TYPES-MIB::clixonExampleSleeper"
|
||||
NAME3="CLIXON-TYPES-MIB::clixonExampleString"
|
||||
NAME4="CLIXON-TYPES-MIB::ifTableLastChange"
|
||||
NAME5="CLIXON-TYPES-MIB::ifType"
|
||||
NAME6="CLIXON-TYPES-MIB::ifSpeed"
|
||||
NAME7="CLIXON-TYPES-MIB::ifAdminStatus"
|
||||
NAME8="CLIXON-TYPES-MIB::ifInOctets"
|
||||
NAME9="CLIXON-TYPES-MIB::ifHCInOctets"
|
||||
NAME10="CLIXON-TYPES-MIB::ifPromiscuousMode"
|
||||
NAME11="CLIXON-TYPES-MIB::ifCounterDiscontinuityTime"
|
||||
NAME12="CLIXON-TYPES-MIB::ifStackStatus"
|
||||
NAME13="CLIXON-TYPES-MIB::netSnmpIETFWGTable"
|
||||
NAME14="CLIXON-TYPES-MIB::netSnmpIETFWGEntry"
|
||||
NAME15="CLIXON-TYPES-MIB::nsIETFWGName"
|
||||
NAME16="CLIXON-TYPES-MIB::nsIETFWGChair1"
|
||||
NAME17="CLIXON-TYPES-MIB::nsIETFWGChair2"
|
||||
NAME18="CLIXON-TYPES-MIB::netSnmpHostsTable"
|
||||
NAME19="CLIXON-TYPES-MIB::netSnmpHostName"
|
||||
NAME20="CLIXON-TYPES-MIB::netSnmpHostAddressType"
|
||||
NAME21="CLIXON-TYPES-MIB::netSnmpHostAddress"
|
||||
NAME22="CLIXON-TYPES-MIB::netSnmpHostStorage"
|
||||
NAME23="CLIXON-TYPES-MIB::netSnmpHostRowStatus"
|
||||
|
||||
new "$snmpget"
|
||||
|
||||
new "Get netSnmpExampleInteger"
|
||||
validate_oid $OID1 $OID1 "INTEGER" 2147483647
|
||||
validate_oid $OID1 $OID2 "INTEGER" -1
|
||||
validate_oid $NAME1 $NAME1 "INTEGER" 2147483647
|
||||
validate_oid $NAME1 $NAME2 "INTEGER" -1
|
||||
|
||||
new "Get netSnmpExampleSleeper"
|
||||
validate_oid $OID2 $OID2 "INTEGER" -1
|
||||
validate_oid $OID2 $OID3 "STRING" "\"This is not default\""
|
||||
validate_oid $NAME2 $NAME2 "INTEGER" -1
|
||||
validate_oid $NAME2 $NAME3 "STRING" "This is not default"
|
||||
|
||||
new "Get netSnmpExampleString"
|
||||
validate_oid $OID3 $OID3 "STRING" "\"This is not default\""
|
||||
validate_oid $OID3 $OID4 "Timeticks" "(12345) 0:02:03.45"
|
||||
validate_oid $NAME3 $NAME3 "STRING" "This is not default"
|
||||
validate_oid $NAME3 $NAME4 "Timeticks" "(12345) 0:02:03.45"
|
||||
|
||||
new "Get ifTableLastChange"
|
||||
validate_oid $OID4 $OID4 "Timeticks" "(12345) 0:02:03.45"
|
||||
validate_oid $OID4 $OID5 "INTEGER" 48
|
||||
validate_oid $NAME4 $NAME4 "Timeticks" "(12345) 0:02:03.45"
|
||||
validate_oid $NAME4 $NAME5 "INTEGER" "modem(48)"
|
||||
|
||||
new "Get ifType"
|
||||
validate_oid $OID5 $OID5 "INTEGER" 48
|
||||
validate_oid $OID5 $OID6 "Gauge32" 123123123
|
||||
validate_oid $NAME5 $NAME5 "INTEGER" "modem(48)"
|
||||
validate_oid $NAME5 $NAME6 "Gauge32" 123123123
|
||||
|
||||
new "Get ifSpeed"
|
||||
validate_oid $OID6 $OID6 "Gauge32" 123123123
|
||||
validate_oid $OID6 $OID7 "INTEGER" 3
|
||||
validate_oid $NAME6 $NAME6 "Gauge32" 123123123
|
||||
validate_oid $NAME6 $NAME7 "INTEGER" "testing(3)"
|
||||
|
||||
new "Get ifAdminStatus"
|
||||
validate_oid $OID7 $OID7 "INTEGER" 3
|
||||
validate_oid $OID7 $OID8 "Counter32" 123456
|
||||
validate_oid $NAME7 $NAME7 "INTEGER" "testing(3)"
|
||||
validate_oid $NAME7 $NAME8 "Counter32" 123456
|
||||
|
||||
new "Get ifInOctets"
|
||||
validate_oid $OID8 $OID8 "Counter32" 123456
|
||||
validate_oid $OID8 $OID9 "Counter64" 4294967296
|
||||
validate_oid $NAME8 $NAME8 "Counter32" 123456
|
||||
validate_oid $NAME8 $NAME9 "Counter64" 4294967296
|
||||
|
||||
new "Get ifInHCOctets"
|
||||
validate_oid $OID9 $OID9 "Counter64" 4294967296
|
||||
validate_oid $OID9 $OID10 "INTEGER" 1
|
||||
|
||||
validate_oid $NAME9 $NAME9 "Counter64" 4294967296
|
||||
validate_oid $NAME9 $NAME10 "INTEGER" "true(1)"
|
||||
|
||||
new "Get ifPromiscuousMode"
|
||||
validate_oid $OID10 $OID10 "INTEGER" 1
|
||||
validate_oid $OID10 $OID11 "Timeticks" "(1234567890) 142 days, 21:21:18.90"
|
||||
validate_oid $NAME10 $NAME10 "INTEGER" "true(1)"
|
||||
validate_oid $NAME10 $NAME11 "Timeticks" "(1234567890) 142 days, 21:21:18.90"
|
||||
|
||||
new "Get ifCounterDiscontinuityTime"
|
||||
validate_oid $OID11 $OID11 "Timeticks" "(1234567890) 142 days, 21:21:18.90"
|
||||
validate_oid $OID11 $OID12 "INTEGER" 1
|
||||
validate_oid $NAME11 $NAME11 "Timeticks" "(1234567890) 142 days, 21:21:18.90"
|
||||
validate_oid $NAME11 $NAME12 "INTEGER" "active(1)"
|
||||
|
||||
new "Get ifStackStatus"
|
||||
validate_oid $OID12 $OID12 "INTEGER" 1
|
||||
validate_oid $NAME12 $NAME12 "INTEGER" "active(1)"
|
||||
|
||||
new "Get bulk OIDs"
|
||||
expectpart "$($snmpbulkget $OID1)" 0 "$OID2 = INTEGER: -1" "$OID3 = STRING: \"This is not default\"" "$OID4 = Timeticks: (12345) 0:02:03.45" "$OID5 = INTEGER: 48" "$OID6 = Gauge32: 123123123" "$OID7 = INTEGER: 3" "$OID8 = Counter32: 123456" "$OID9 = Counter64: 4294967296" "$OID10 = INTEGER: 1" "$OID11 = Timeticks: (1234567890) 142 days, 21:21:18.90"
|
||||
|
||||
new "Test SNMP getnext netSnmpIETFWGTable"
|
||||
validate_oid $OID15 $OID15 "INTEGER" 42
|
||||
|
||||
new "Test SNMP get nsIETFWGName"
|
||||
validate_oid $OID15 $OID15 "INTEGER" 42
|
||||
|
||||
new "Test SNMP getnext nsIETFWGName"
|
||||
expectpart "$($snmpgetnext $OID15)" 0 "Hex-STRING: 4E 61 6D 65 31 00"
|
||||
|
||||
new "Test SNMP getnext netSnmpHostsTable"
|
||||
expectpart "$($snmpgetnext $OID18)" 0 "$OID19 = Hex-STRING: 74 65 73 74 00"
|
||||
|
||||
new "Test SNMP get netSnmpHostName"
|
||||
expectpart "$($snmpget $OID19)" 0 "$OID19 = Hex-STRING: 74 65 73 74 00"
|
||||
|
||||
new "Test SNMP getnext netSnmpHostName"
|
||||
expectpart "$($snmpgetnext $OID19)" 0 "$OID20 = INTEGER: 1"
|
||||
|
||||
new "Cleaning up"
|
||||
testexit
|
||||
|
||||
new "endtest"
|
||||
endtest
|
||||
469
test/test_snmp_ifmib.sh
Executable file
469
test/test_snmp_ifmib.sh
Executable file
|
|
@ -0,0 +1,469 @@
|
|||
#!/usr/bin/env bash
|
||||
# SNMP "smoketest" Basic snmpget test for a scalar
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
# Re-use main example backend state callbacks
|
||||
APPNAME=example
|
||||
|
||||
if [ ${ENABLE_NETSNMP} != "yes" ]; then
|
||||
echo "Skipping test, Net-SNMP support not enabled."
|
||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
fi
|
||||
|
||||
snmpd=$(type -p snmpd)
|
||||
snmpget="$(type -p snmpget) -On -c public -v2c localhost "
|
||||
snmpgetnext="$(type -p snmpgetnext) -On -c public -v2c localhost "
|
||||
snmptable="$(type -p snmptable) -c public -v2c localhost "
|
||||
snmpwalk="$(type -p snmpwalk) -c public -v2c localhost "
|
||||
|
||||
cfg=$dir/conf_startup.xml
|
||||
fyang=$dir/clixon-example.yang
|
||||
fstate=$dir/state.xml
|
||||
|
||||
# AgentX unix socket
|
||||
SOCK=/var/run/snmp.sock
|
||||
|
||||
# Relies on example_backend.so for $fstate file handling
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${YANG_STANDARD_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${MIB_GENERATED_YANG_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_BACKEND_PIDFILE>/var/tmp/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||
<CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK>
|
||||
<CLICON_SNMP_MIB>IF-MIB</CLICON_SNMP_MIB>
|
||||
<CLICON_VALIDATE_STATE_XML>false</CLICON_VALIDATE_STATE_XML>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module clixon-example{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import IF-MIB {
|
||||
prefix "if-mib";
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# This is state data written to file that backend reads from (on request)
|
||||
# integer and string have values, sleeper does not and uses default (=1)
|
||||
|
||||
cat <<EOF > $fstate
|
||||
<IF-MIB xmlns="urn:ietf:params:xml:ns:yang:smiv2:IF-MIB">
|
||||
<interfaces>
|
||||
<ifNumber>1</ifNumber>
|
||||
</interfaces>
|
||||
<ifMIBObjects>
|
||||
<ifTableLastChange>0</ifTableLastChange>
|
||||
<ifStackLastChange>0</ifStackLastChange>
|
||||
</ifMIBObjects>
|
||||
<ifTable>
|
||||
<ifEntry>
|
||||
<ifIndex>1</ifIndex>
|
||||
<ifDescr>Test</ifDescr>
|
||||
<ifType>ethernetCsmacd</ifType>
|
||||
<ifMtu>1500</ifMtu>
|
||||
<ifSpeed>10000000</ifSpeed>
|
||||
<ifPhysAddress>aa:bb:cc:dd:ee:ff</ifPhysAddress>
|
||||
<ifAdminStatus>testing</ifAdminStatus>
|
||||
<ifOperStatus>up</ifOperStatus>
|
||||
<ifLastChange>0</ifLastChange>
|
||||
<ifInOctets>123</ifInOctets>
|
||||
<ifInUcastPkts>124</ifInUcastPkts>
|
||||
<ifInNUcastPkts>124</ifInNUcastPkts>
|
||||
<ifInDiscards>125</ifInDiscards>
|
||||
<ifInErrors>126</ifInErrors>
|
||||
<ifInUnknownProtos>127</ifInUnknownProtos>
|
||||
<ifOutOctets>128</ifOutOctets>
|
||||
<ifOutUcastPkts>129</ifOutUcastPkts>
|
||||
<ifOutNUcastPkts>129</ifOutNUcastPkts>
|
||||
<ifOutDiscards>130</ifOutDiscards>
|
||||
<ifOutErrors>131</ifOutErrors>
|
||||
<ifOutQLen>132</ifOutQLen>
|
||||
<ifSpecific>0.0</ifSpecific>
|
||||
</ifEntry>
|
||||
<ifEntry>
|
||||
<ifIndex>2</ifIndex>
|
||||
<ifDescr>Test 2</ifDescr>
|
||||
<ifType>ethernetCsmacd</ifType>
|
||||
<ifMtu>1400</ifMtu>
|
||||
<ifSpeed>1000</ifSpeed>
|
||||
<ifPhysAddress>11:22:33:44:55:66</ifPhysAddress>
|
||||
<ifAdminStatus>down</ifAdminStatus>
|
||||
<ifOperStatus>down</ifOperStatus>
|
||||
<ifLastChange>0</ifLastChange>
|
||||
<ifInOctets>111</ifInOctets>
|
||||
<ifInUcastPkts>222</ifInUcastPkts>
|
||||
<ifInNUcastPkts>333</ifInNUcastPkts>
|
||||
<ifInDiscards>444</ifInDiscards>
|
||||
<ifInErrors>555</ifInErrors>
|
||||
<ifInUnknownProtos>666</ifInUnknownProtos>
|
||||
<ifOutOctets>777</ifOutOctets>
|
||||
<ifOutUcastPkts>888</ifOutUcastPkts>
|
||||
<ifOutNUcastPkts>999</ifOutNUcastPkts>
|
||||
<ifOutDiscards>101010</ifOutDiscards>
|
||||
<ifOutErrors>111111</ifOutErrors>
|
||||
<ifOutQLen>111</ifOutQLen>
|
||||
<ifSpecific>1.2.3</ifSpecific>
|
||||
</ifEntry>
|
||||
</ifTable>
|
||||
<ifRcvAddressTable>
|
||||
<ifRcvAddressEntry>
|
||||
<ifIndex>1</ifIndex>
|
||||
<ifRcvAddressAddress>11:bb:cc:dd:ee:ff</ifRcvAddressAddress>
|
||||
<ifRcvAddressStatus>active</ifRcvAddressStatus>
|
||||
<ifRcvAddressType>other</ifRcvAddressType>
|
||||
</ifRcvAddressEntry>
|
||||
<ifRcvAddressEntry>
|
||||
<ifIndex>2</ifIndex>
|
||||
<ifRcvAddressAddress>aa:22:33:44:55:66</ifRcvAddressAddress>
|
||||
<ifRcvAddressStatus>createAndGo</ifRcvAddressStatus>
|
||||
<ifRcvAddressType>volatile</ifRcvAddressType>
|
||||
</ifRcvAddressEntry>
|
||||
</ifRcvAddressTable>
|
||||
</IF-MIB>
|
||||
EOF
|
||||
|
||||
# This is the expected result from snmpwalk:
|
||||
# $ snmpwalk -cpublic -v2c localhost IF-MIB::ifTable # .1.3.6.1.2.1.2.2
|
||||
# IF-MIB::ifIndex.1 = INTEGER: 1
|
||||
# IF-MIB::ifDescr.1 = STRING: Test
|
||||
# IF-MIB::ifType.1 = INTEGER: ethernetCsmacd(6)
|
||||
# IF-MIB::ifMtu.1 = INTEGER: 1500
|
||||
# IF-MIB::ifSpeed.1 = Gauge32: 10000000
|
||||
# IF-MIB::ifPhysAddress.1 = STRING: aa:bb:cc:dd:ee:ff
|
||||
# IF-MIB::ifAdminStatus.1 = INTEGER: up(1)
|
||||
# IF-MIB::ifOperStatus.1 = INTEGER: up(1)
|
||||
# IF-MIB::ifLastChange.1 = Timeticks: (0) 0:00:00.00
|
||||
# IF-MIB::ifInOctets.1 = Counter32: 123
|
||||
# IF-MIB::ifInUcastPkts.1 = Counter32: 123
|
||||
# IF-MIB::ifInNUcastPkts.1 = Counter32: 123
|
||||
# IF-MIB::ifInDiscards.1 = Counter32: 123
|
||||
# IF-MIB::ifInErrors.1 = Counter32: 123
|
||||
# IF-MIB::ifInUnknownProtos.1 = Counter32: 123
|
||||
# IF-MIB::ifOutOctets.1 = Counter32: 123
|
||||
# IF-MIB::ifOutUcastPkts.1 = Counter32: 123
|
||||
# IF-MIB::ifOutNUcastPkts.1 = Counter32: 123
|
||||
# IF-MIB::ifOutDiscards.1 = Counter32: 123
|
||||
# IF-MIB::ifOutErrors.1 = Counter32: 123
|
||||
# IF-MIB::ifOutQLen.1 = Gauge32: 123
|
||||
# IF-MIB::ifSpecific.1 = OID: SNMPv2-SMI::zeroDotZero
|
||||
|
||||
function testinit(){
|
||||
new "test params: -f $cfg -- -sS $fstate"
|
||||
if [ $BE -ne 0 ]; then
|
||||
# Kill old backend and start a new one
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "Failed to start backend"
|
||||
fi
|
||||
|
||||
sudo pkill -f clixon_backend
|
||||
|
||||
new "Starting backend"
|
||||
start_backend -s init -f $cfg -- -sS $fstate
|
||||
fi
|
||||
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
if [ $SN -ne 0 ]; then
|
||||
# Kill old clixon_snmp, if any
|
||||
new "Terminating any old clixon_snmp processes"
|
||||
sudo killall -q clixon_snmp
|
||||
|
||||
new "Starting clixon_snmp"
|
||||
start_snmp $cfg &
|
||||
fi
|
||||
|
||||
new "wait snmp"
|
||||
wait_snmp
|
||||
}
|
||||
|
||||
function testexit(){
|
||||
stop_snmp
|
||||
}
|
||||
|
||||
new "SNMP tests"
|
||||
testinit
|
||||
|
||||
# IF-MIB::interfaces
|
||||
MIB=".1.3.6.1.2.1"
|
||||
for (( i=1; i<23; i++ )); do
|
||||
eval OID${i}="${MIB}.2.2.1.$i.1"
|
||||
done
|
||||
|
||||
OID24=".1.3.6.1.2.1.31.1.4.1.1.1.17.49.49.58.98.98.58.99.99.58.100.100.58.101.101.58.102.102"
|
||||
OID25=".1.3.6.1.2.1.31.1.4.1.1.2.17.97.97.58.50.50.58.51.51.58.52.52.58.53.53.58.54.54"
|
||||
OID26=".1.3.6.1.2.1.31.1.4.1.2.1.17.49.49.58.98.98.58.99.99.58.100.100.58.101.101.58.102.102"
|
||||
OID27=".1.3.6.1.2.1.31.1.4.1.2.2.17.97.97.58.50.50.58.51.51.58.52.52.58.53.53.58.54.54"
|
||||
OID28=".1.3.6.1.2.1.31.1.4.1.3.1.17.49.49.58.98.98.58.99.99.58.100.100.58.101.101.58.102.102"
|
||||
OID29=".1.3.6.1.2.1.31.1.4.1.3.2.17.97.97.58.50.50.58.51.51.58.52.52.58.53.53.58.54.54"
|
||||
|
||||
NAME1="IF-MIB::ifIndex"
|
||||
NAME2="IF-MIB::ifDescr"
|
||||
NAME3="IF-MIB::ifType"
|
||||
NAME4="IF-MIB::ifMtu"
|
||||
NAME5="IF-MIB::ifSpeed"
|
||||
NAME6="IF-MIB::ifPhysAddress"
|
||||
NAME7="IF-MIB::ifAdminStatus"
|
||||
NAME8="IF-MIB::ifOperStatus"
|
||||
NAME9="IF-MIB::ifLastChange"
|
||||
NAME10="IF-MIB::ifInOctets"
|
||||
NAME11="IF-MIB::ifInUcastPkts"
|
||||
NAME12="IF-MIB::ifInNUcastPkts"
|
||||
NAME13="IF-MIB::ifInDiscards"
|
||||
NAME14="IF-MIB::ifInErrors"
|
||||
NAME15="IF-MIB::ifInUnknownProtos"
|
||||
NAME16="IF-MIB::ifOutOctets"
|
||||
NAME17="IF-MIB::ifOutUcastPkts"
|
||||
NAME18="IF-MIB::ifOutNUcastPkts"
|
||||
NAME19="IF-MIB::ifOutDiscards"
|
||||
NAME20="IF-MIB::ifOutErrors"
|
||||
NAME21="IF-MIB::ifOutQLen"
|
||||
NAME22="IF-MIB::ifSpecific"
|
||||
|
||||
NAME24="IF-MIB::ifRcvAddressAddress.1.17.49.49.58.98.98.58.99.99.58.100.100.58.101.101.58.102.102"
|
||||
NAME25="IF-MIB::ifRcvAddressAddress.2.17.97.97.58.50.50.58.51.51.58.52.52.58.53.53.58.54.54"
|
||||
NAME26="IF-MIB::ifRcvAddressStatus.1.17.49.49.58.98.98.58.99.99.58.100.100.58.101.101.58.102.102"
|
||||
NAME27="IF-MIB::ifRcvAddressStatus.2.17.97.97.58.50.50.58.51.51.58.52.52.58.53.53.58.54.54"
|
||||
NAME28="IF-MIB::ifRcvAddressType.1.17.49.49.58.98.98.58.99.99.58.100.100.58.101.101.58.102.102"
|
||||
NAME29="IF-MIB::ifRcvAddressType.2.17.97.97.58.50.50.58.51.51.58.52.52.58.53.53.58.54.54"
|
||||
|
||||
new "$snmpget"
|
||||
|
||||
new "Test SNMP get all entries in ifTable"
|
||||
|
||||
new "Test $OID1 ifIndex"
|
||||
validate_oid $OID1 $OID1 "INTEGER" "1"
|
||||
validate_oid "$NAME1.1" "$NAME1.1" "INTEGER" 1
|
||||
validate_oid "$NAME1.1" "$NAME1.2" "INTEGER" 2
|
||||
|
||||
new "Test $OID2 ifDescr"
|
||||
validate_oid $OID2 $OID2 "STRING" "Test"
|
||||
validate_oid $NAME2.1 $NAME2.1 "STRING" "Test"
|
||||
validate_oid $NAME2.2 $NAME2.2 "STRING" "Test"
|
||||
|
||||
new "Test $OID3 ifType"
|
||||
validate_oid $OID3 $OID3 "INTEGER" "ethernetCsmacd(6)"
|
||||
validate_oid $NAME3.1 $NAME3.1 "INTEGER" "ethernetCsmacd(6)"
|
||||
validate_oid $NAME3.2 $NAME3.2 "INTEGER" "ethernetCsmacd(6)"
|
||||
|
||||
new "Test $OID4 ifMtu"
|
||||
validate_oid $OID4 $OID4 "INTEGER" "1500"
|
||||
validate_oid $NAME4.1 $NAME4.1 "INTEGER" 1500
|
||||
validate_oid $NAME4.2 $NAME4.2 "INTEGER" 1400
|
||||
|
||||
new "Test $OID5 ifSpeed"
|
||||
validate_oid $OID5 $OID5 "Gauge32" "10000000"
|
||||
validate_oid $NAME5.1 $NAME5.1 "Gauge32" 10000000
|
||||
validate_oid $NAME5.2 $NAME5.2 "Gauge32" 1000
|
||||
|
||||
new "Test $OID6 ifPhysAddress yang:phys-address"
|
||||
validate_oid $OID6 $OID6 "STRING" "aa.bb:cc:dd:ee:ff"
|
||||
validate_oid $NAME6.1 $NAME6.1 "STRING" "aa.bb:cc:dd:ee:ff"
|
||||
validate_oid $NAME6.2 $NAME6.2 "STRING" "11:22:33:44:55:66"
|
||||
|
||||
new "Test $OID7 ifAdminStatus"
|
||||
validate_oid $OID7 $OID7 "INTEGER" "testing(3)"
|
||||
validate_oid $NAME7.1 $NAME7.1 "INTEGER" "testing(3)"
|
||||
validate_oid $NAME7.2 $NAME7.2 "INTEGER" "down(2)"
|
||||
|
||||
new "Test $OID8 ifOperStatus"
|
||||
validate_oid $OID8 $OID8 "INTEGER" "up(1)"
|
||||
validate_oid $NAME8.1 $NAME8.1 "INTEGER" "up(1)"
|
||||
validate_oid $NAME8.2 $NAME8.2 "INTEGER" "down(2)"
|
||||
|
||||
new "Test $OID9 ifLastChange"
|
||||
validate_oid $OID9 $OID9 "Timeticks" "(0) 0:00:00.00"
|
||||
validate_oid $NAME9.1 $NAME9.1 "Timeticks" "(0) 0:00:00.00"
|
||||
validate_oid $NAME9.2 $NAME9.2 "Timeticks" "(0) 0:00:00.00"
|
||||
|
||||
new "Test $OID10 ifInOctets"
|
||||
validate_oid $OID10 $OID10 "Counter32" 123
|
||||
validate_oid $NAME10.1 $NAME10.1 "Counter32" 123
|
||||
validate_oid $NAME10.2 $NAME10.2 "Counter32" 111
|
||||
|
||||
new "Test $OID11 ifInUcastPkts"
|
||||
validate_oid $OID11 $OID11 "Counter32" 124
|
||||
validate_oid $NAME11.1 $NAME11.1 "Counter32" 124
|
||||
validate_oid $NAME11.2 $NAME11.2 "Counter32" 222
|
||||
|
||||
new "Test $OID12 ifInNUcastPkts"
|
||||
validate_oid $OID12 $OID12 "Counter32" 124
|
||||
validate_oid $NAME12.1 $NAME12.1 "Counter32" 124
|
||||
validate_oid $NAME12.2 $NAME12.2 "Counter32" 333
|
||||
|
||||
new "Test $OID13 ifInDiscards"
|
||||
validate_oid $OID13 $OID13 "Counter32" 125
|
||||
validate_oid $NAME13.1 $NAME13.1 "Counter32" 125
|
||||
validate_oid $NAME13.2 $NAME13.2 "Counter32" 444
|
||||
|
||||
new "Test $OID14 ifInErrors"
|
||||
validate_oid $OID14 $OID14 "Counter32" 126
|
||||
validate_oid $NAME14.1 $NAME14.1 "Counter32" 126
|
||||
validate_oid $NAME14.2 $NAME14.2 "Counter32" 555
|
||||
|
||||
new "Test $OID15 ifInUnknownProtos"
|
||||
validate_oid $OID15 $OID15 "Counter32" 127
|
||||
validate_oid $NAME15.1 $NAME15.1 "Counter32" 127
|
||||
validate_oid $NAME15.2 $NAME15.2 "Counter32" 666
|
||||
|
||||
new "Test $OID16 ifOutOctets"
|
||||
validate_oid $OID16 $OID16 "Counter32" 128
|
||||
validate_oid $NAME16.1 $NAME16.1 "Counter32" 128
|
||||
validate_oid $NAME16.2 $NAME16.2 "Counter32" 777
|
||||
|
||||
new "Test $OID17 ifOutUcastPkts"
|
||||
validate_oid $OID17 $OID17 "Counter32" 129
|
||||
validate_oid $NAME17.1 $NAME17.1 "Counter32" 129
|
||||
validate_oid $NAME17.2 $NAME17.2 "Counter32" 888
|
||||
|
||||
new "Test $OID18 ifOutNUcastPkts"
|
||||
validate_oid $OID18 $OID18 "Counter32" 129
|
||||
validate_oid $NAME18.1 $NAME18.1 "Counter32" 129
|
||||
validate_oid $NAME18.2 $NAME18.2 "Counter32" 999
|
||||
|
||||
new "Test $OID19 ifOutDiscards"
|
||||
validate_oid $OID19 $OID19 "Counter32" 130
|
||||
validate_oid $NAME19.1 $NAME19.1 "Counter32" 130
|
||||
validate_oid $NAME19.2 $NAME19.2 "Counter32" 101010
|
||||
|
||||
new "Test $OID20 ifOutErrors"
|
||||
validate_oid $OID20 $OID20 "Counter32" 131
|
||||
validate_oid $NAME20.1 $NAME20.1 "Counter32" 131
|
||||
validate_oid $NAME20.2 $NAME20.2 "Counter32" 111111
|
||||
|
||||
new "Test $OID21 ifOutQLen"
|
||||
validate_oid $OID21 $OID21 "Gauge32" 132
|
||||
validate_oid $NAME21.1 $NAME21.1 "Gauge32" 132
|
||||
validate_oid $NAME21.2 $NAME21.2 "Gauge32" 111
|
||||
|
||||
new "Test $OID22 ifSpecific"
|
||||
validate_oid $OID22 $OID22 "OID" ".0.0"
|
||||
validate_oid $NAME22.1 $NAME22.1 "OID" "SNMPv2-SMI::zeroDotZero"
|
||||
validate_oid $NAME22.2 $NAME22.2 "OID" "iso.2.3"
|
||||
|
||||
new "Test ifTable"
|
||||
expectpart "$($snmptable IF-MIB::ifTable)" 0 "Test 2" "1400" "1000" "11:22:33:44:55:66" "down" "111" "222" "333" "444" "555" "666" "777" "888" "999" "101010" "111111" "111"
|
||||
|
||||
new "Walk the walk..."
|
||||
expectpart "$($snmpwalk IF-MIB::ifTable)" 0 "IF-MIB::ifIndex.1 = INTEGER: 1" \
|
||||
"IF-MIB::ifIndex.2 = INTEGER: 2" \
|
||||
"IF-MIB::ifDescr.1 = STRING: Test." \
|
||||
"IF-MIB::ifDescr.2 = STRING: Test 2." \
|
||||
"IF-MIB::ifType.1 = INTEGER: ethernetCsmacd(6)" \
|
||||
"IF-MIB::ifType.2 = INTEGER: ethernetCsmacd(6)" \
|
||||
"IF-MIB::ifMtu.1 = INTEGER: 1500" \
|
||||
"IF-MIB::ifMtu.2 = INTEGER: 1400" \
|
||||
"IF-MIB::ifSpeed.1 = Gauge32: 10000000" \
|
||||
"IF-MIB::ifSpeed.2 = Gauge32: 1000" \
|
||||
"IF-MIB::ifPhysAddress.1 = STRING: aa:bb:cc:dd:ee:ff" \
|
||||
"IF-MIB::ifPhysAddress.2 = STRING: 11:22:33:44:55:66" \
|
||||
"IF-MIB::ifAdminStatus.1 = INTEGER: testing(3)" \
|
||||
"IF-MIB::ifAdminStatus.2 = INTEGER: down(2)" \
|
||||
"IF-MIB::ifOperStatus.1 = INTEGER: up(1)" \
|
||||
"IF-MIB::ifOperStatus.2 = INTEGER: down(2)" \
|
||||
"IF-MIB::ifLastChange.1 = Timeticks: (0) 0:00:00.00" \
|
||||
"IF-MIB::ifLastChange.2 = Timeticks: (0) 0:00:00.00" \
|
||||
"IF-MIB::ifInOctets.1 = Counter32: 123" \
|
||||
"IF-MIB::ifInOctets.2 = Counter32: 111" \
|
||||
"IF-MIB::ifInUcastPkts.1 = Counter32: 124" \
|
||||
"IF-MIB::ifInUcastPkts.2 = Counter32: 222" \
|
||||
"IF-MIB::ifInNUcastPkts.1 = Counter32: 124" \
|
||||
"IF-MIB::ifInNUcastPkts.2 = Counter32: 333" \
|
||||
"IF-MIB::ifInDiscards.1 = Counter32: 125" \
|
||||
"IF-MIB::ifInDiscards.2 = Counter32: 444" \
|
||||
"IF-MIB::ifInErrors.1 = Counter32: 126" \
|
||||
"IF-MIB::ifInErrors.2 = Counter32: 555" \
|
||||
"IF-MIB::ifInUnknownProtos.1 = Counter32: 127" \
|
||||
"IF-MIB::ifInUnknownProtos.2 = Counter32: 666" \
|
||||
"IF-MIB::ifOutOctets.1 = Counter32: 128" \
|
||||
"IF-MIB::ifOutOctets.2 = Counter32: 777" \
|
||||
"IF-MIB::ifOutUcastPkts.1 = Counter32: 129" \
|
||||
"IF-MIB::ifOutUcastPkts.2 = Counter32: 888" \
|
||||
"IF-MIB::ifOutNUcastPkts.1 = Counter32: 129" \
|
||||
"IF-MIB::ifOutNUcastPkts.2 = Counter32: 999" \
|
||||
"IF-MIB::ifOutDiscards.1 = Counter32: 130" \
|
||||
"IF-MIB::ifOutDiscards.2 = Counter32: 101010" \
|
||||
"IF-MIB::ifOutErrors.1 = Counter32: 131" \
|
||||
"IF-MIB::ifOutErrors.2 = Counter32: 111111" \
|
||||
"IF-MIB::ifOutQLen.1 = Gauge32: 132" \
|
||||
"IF-MIB::ifOutQLen.2 = Gauge32: 111" \
|
||||
"IF-MIB::ifSpecific.1 = OID: SNMPv2-SMI::zeroDotZero" \
|
||||
"IF-MIB::ifSpecific.2 = OID: iso.2.3"
|
||||
|
||||
new "Test $OID24"
|
||||
validate_oid $OID24 $OID24 "STRING" "11:bb:cc:dd:ee:ff"
|
||||
validate_oid $NAME24 $NAME24 "STRING" "11:bb:cc:dd:ee:ff" "IF-MIB::ifRcvAddressAddress.1.\"11:bb:cc:dd:ee:ff\" = STRING: 11:bb:cc:dd:ee:ff"
|
||||
|
||||
new "Get next $OID24"
|
||||
validate_oid $OID24 $OID25 "STRING" "aa:22:33:44:55:66"
|
||||
validate_oid $NAME24 $NAME25 "STRING" "aa:22:33:44:55:66" "IF-MIB::ifRcvAddressAddress.2.\"aa:22:33:44:55:66\" = STRING: aa:22:33:44:55:66"
|
||||
|
||||
new "Get $NAME25"
|
||||
|
||||
validate_oid $OID25 $OID25 "STRING" "aa:22:33:44:55:66"
|
||||
validate_oid $NAME25 $NAME25 "STRING" "aa:22:33:44:55:66" "IF-MIB::ifRcvAddressAddress.2.\"aa:22:33:44:55:66\" = STRING: aa:22:33:44:55:66"
|
||||
|
||||
new "Get next $OID25"
|
||||
|
||||
validate_oid $OID25 $OID26 "INTEGER" "active(1)"
|
||||
validate_oid $NAME25 $NAME26 "INTEGER" "active(1)" "IF-MIB::ifRcvAddressStatus.1.\"11:bb:cc:dd:ee:ff\" = INTEGER: active(1)"
|
||||
|
||||
new "Get $OID26"
|
||||
|
||||
validate_oid $OID26 $OID26 "INTEGER" "active(1)"
|
||||
validate_oid $NAME26 $NAME26 "INTEGER" "active(1)" "IF-MIB::ifRcvAddressStatus.1.\"11:bb:cc:dd:ee:ff\" = INTEGER: active(1)"
|
||||
|
||||
new "Get next $OID26"
|
||||
|
||||
validate_oid $OID26 $OID27 "INTEGER" "createAndGo(4)"
|
||||
validate_oid $NAME26 $NAME27 "INTEGER" "createAndGo(4)" "IF-MIB::ifRcvAddressStatus.2.\"aa:22:33:44:55:66\" = INTEGER: createAndGo(4)"
|
||||
|
||||
new "Get $OID27"
|
||||
|
||||
validate_oid $OID27 $OID27 "INTEGER" "createAndGo(4)"
|
||||
validate_oid $NAME27 $NAME27 "INTEGER" "createAndGo(4)" "IF-MIB::ifRcvAddressStatus.2.\"aa:22:33:44:55:66\" = INTEGER: createAndGo(4)"
|
||||
|
||||
new "Get next $OID27"
|
||||
|
||||
validate_oid $OID27 $OID28 "INTEGER" "other(1)"
|
||||
validate_oid $NAME27 $NAME28 "INTEGER" "other(1)" "IF-MIB::ifRcvAddressType.1.\"11:bb:cc:dd:ee:ff\" = INTEGER: other(1)"
|
||||
|
||||
new "Get $OID28"
|
||||
|
||||
validate_oid $OID28 $OID28 "INTEGER" "other(1)"
|
||||
validate_oid $NAME28 $NAME28 "INTEGER" "other(1)" "IF-MIB::ifRcvAddressType.1.\"11:bb:cc:dd:ee:ff\" = INTEGER: other(1)"
|
||||
|
||||
new "Get next $OID28"
|
||||
|
||||
validate_oid $OID28 $OID29 "INTEGER" "volatile(2)"
|
||||
validate_oid $NAME28 $NAME29 "INTEGER" "volatile(2)" "IF-MIB::ifRcvAddressType.2.\"aa:22:33:44:55:66\" = INTEGER: volatile(2)"
|
||||
|
||||
new "Test ifTable"
|
||||
expectpart "$($snmptable IF-MIB::ifRcvAddressTable)" 0 "SNMP table: IF-MIB::ifRcvAddressTable" "ifRcvAddressStatus" "ifRcvAddressType" "active" "other" "createAndGo" "volatile"
|
||||
|
||||
new "Walk ifRcvTable"
|
||||
expectpart "$($snmpwalk IF-MIB::ifRcvAddressTable)" 0 "IF-MIB::ifRcvAddressAddress.1.\"11:bb:cc:dd:ee:ff\" = STRING: 11:bb:cc:dd:ee:ff" \
|
||||
"IF-MIB::ifRcvAddressAddress.2.\"aa:22:33:44:55:66\" = STRING: aa:22:33:44:55:66" \
|
||||
"IF-MIB::ifRcvAddressStatus.1.\"11:bb:cc:dd:ee:ff\" = INTEGER: active(1)" \
|
||||
"IF-MIB::ifRcvAddressStatus.2.\"aa:22:33:44:55:66\" = INTEGER: createAndGo(4)" \
|
||||
"IF-MIB::ifRcvAddressType.1.\"11:bb:cc:dd:ee:ff\" = INTEGER: other(1)" \
|
||||
"IF-MIB::ifRcvAddressType.2.\"aa:22:33:44:55:66\" = INTEGER: volatile(2)"
|
||||
|
||||
testexit
|
||||
|
||||
new "endtest"
|
||||
endtest
|
||||
226
test/test_snmp_rowstatus.sh
Executable file
226
test/test_snmp_rowstatus.sh
Executable file
|
|
@ -0,0 +1,226 @@
|
|||
#!/usr/bin/env bash
|
||||
# SNMP table rowstatus tests
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
APPNAME=example
|
||||
|
||||
# XXX skip for now
|
||||
if [ ${ENABLE_NETSNMP} != "yes" ]; then
|
||||
echo "Skipping test, Net-SNMP support not enabled."
|
||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
fi
|
||||
|
||||
snmpd=$(type -p snmpd)
|
||||
snmpget="$(type -p snmpget) -c public -v2c localhost "
|
||||
snmpset="$(type -p snmpset) -c public -v2c localhost "
|
||||
|
||||
cfg=$dir/conf.xml
|
||||
fyang=$dir/clixon-example.yang
|
||||
|
||||
# AgentX unix socket
|
||||
SOCK=/var/run/snmp.sock
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${YANG_STANDARD_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${MIB_GENERATED_YANG_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_PIDFILE>/var/tmp/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||
<CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK>
|
||||
<CLICON_SNMP_MIB>SNMP-NOTIFICATION-MIB</CLICON_SNMP_MIB>
|
||||
<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>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module clixon-example{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import SNMP-NOTIFICATION-MIB {
|
||||
prefix "snmp-notification";
|
||||
}
|
||||
deviation "/snmp-notification:SNMP-NOTIFICATION-MIB" {
|
||||
deviate replace {
|
||||
config true;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
cat <<EOF > $dir/startup_db
|
||||
<${DATASTORE_TOP}>
|
||||
</${DATASTORE_TOP}>
|
||||
EOF
|
||||
|
||||
function testinit(){
|
||||
new "test params: -f $cfg"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
# Kill old backend and start a new one
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "Failed to start backend"
|
||||
fi
|
||||
|
||||
sudo pkill -f clixon_backend
|
||||
|
||||
new "Starting backend"
|
||||
start_backend -s startup -f $cfg
|
||||
fi
|
||||
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
if [ $SN -ne 0 ]; then
|
||||
# Kill old clixon_snmp, if any
|
||||
new "Terminating any old clixon_snmp processes"
|
||||
sudo killall -q clixon_snmp
|
||||
|
||||
new "Starting clixon_snmp"
|
||||
start_snmp $cfg &
|
||||
fi
|
||||
|
||||
new "wait snmp"
|
||||
wait_snmp
|
||||
}
|
||||
|
||||
function testrun_createAndGo()
|
||||
{
|
||||
index=go
|
||||
|
||||
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 CreateAndGo and set tag"
|
||||
expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = createAndGo SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\' = 2)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: createAndGo(4)"
|
||||
|
||||
new "Check rowstatus is active"
|
||||
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.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'$index' = STRING: 2"
|
||||
|
||||
new "Get tag via netconf: candidate"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/sn:SNMP-NOTIFICATION-MIB/sn:snmpNotifyTable/sn:snmpNotifyEntry[sn:snmpNotifyName='$index']/sn:snmpNotifyTag\" xmlns:sn=\"urn:ietf:params:xml:ns:yang:smiv2:SNMP-NOTIFICATION-MIB\"/></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data><SNMP-NOTIFICATION-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:SNMP-NOTIFICATION-MIB\"><snmpNotifyTable><snmpNotifyEntry><snmpNotifyName>$index</snmpNotifyName><snmpNotifyTag>2</snmpNotifyTag></snmpNotifyEntry></snmpNotifyTable></SNMP-NOTIFICATION-MIB></data></rpc-reply>"
|
||||
|
||||
new "Get tag via netconf: running"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><running/></source><filter type=\"xpath\" select=\"/sn:SNMP-NOTIFICATION-MIB/sn:snmpNotifyTable/sn:snmpNotifyEntry[sn:snmpNotifyName='$index']/sn:snmpNotifyTag\" xmlns:sn=\"urn:ietf:params:xml:ns:yang:smiv2:SNMP-NOTIFICATION-MIB\"/></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data><SNMP-NOTIFICATION-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:SNMP-NOTIFICATION-MIB\"><snmpNotifyTable><snmpNotifyEntry><snmpNotifyName>$index</snmpNotifyName><snmpNotifyTag>2</snmpNotifyTag></snmpNotifyEntry></snmpNotifyTable></SNMP-NOTIFICATION-MIB></data></rpc-reply>"
|
||||
|
||||
new "set storage type"
|
||||
expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.\'$index\' = 1)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'$index' = INTEGER: other(1)"
|
||||
}
|
||||
|
||||
function testrun_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.\'$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.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'$index' = STRING: 2"
|
||||
|
||||
new "Get tag via netconf: candidate expect fail"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/sn:SNMP-NOTIFICATION-MIB/sn:snmpNotifyTable/sn:snmpNotifyEntry[sn:snmpNotifyName='$index']/sn:snmpNotifyTag\" xmlns:sn=\"urn:ietf:params:xml:ns:yang:smiv2:SNMP-NOTIFICATION-MIB\"/></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data/></rpc-reply>"
|
||||
|
||||
new "Get rowstatus"
|
||||
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.\'$index\' = 1)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'$index' = INTEGER: other(1)"
|
||||
|
||||
new "Set rowstatus to active/ commit"
|
||||
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.\'$index\' = 5)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyStorageType.'$index' = INTEGER: readOnly(5)"
|
||||
|
||||
new "Set rowstatus to createAndWait"
|
||||
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.\'${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.\'${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.\'${index}3\' = active)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'${index}3' = INTEGER: active(1)"
|
||||
|
||||
new "Get rowstatus"
|
||||
expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: notInService(2)"
|
||||
}
|
||||
|
||||
function testrun_removeRows()
|
||||
{
|
||||
index=remove
|
||||
|
||||
new "Set RowStatus to CreateAndGo and set tag"
|
||||
expectpart "$($snmpset SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.\'$index\' = createAndGo SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\' = 2)" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyRowStatus.'$index' = INTEGER: createAndGo(4)"
|
||||
|
||||
new "Get tag"
|
||||
expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'$index' = STRING: 2"
|
||||
|
||||
new "Get tag via netconf"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/sn:SNMP-NOTIFICATION-MIB/sn:snmpNotifyTable/sn:snmpNotifyEntry[sn:snmpNotifyName='$index']/sn:snmpNotifyTag\" xmlns:sn=\"urn:ietf:params:xml:ns:yang:smiv2:SNMP-NOTIFICATION-MIB\"/></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data><SNMP-NOTIFICATION-MIB xmlns=\"urn:ietf:params:xml:ns:yang:smiv2:SNMP-NOTIFICATION-MIB\"><snmpNotifyTable><snmpNotifyEntry><snmpNotifyName>$index</snmpNotifyName><snmpNotifyTag>2</snmpNotifyTag></snmpNotifyEntry></snmpNotifyTable></SNMP-NOTIFICATION-MIB></data></rpc-reply>"
|
||||
|
||||
new "Set rowstatus to 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"
|
||||
|
||||
# Default value is ""
|
||||
new "Get tag"
|
||||
expectpart "$($snmpget SNMP-NOTIFICATION-MIB::snmpNotifyTag.\'$index\')" 0 "SNMP-NOTIFICATION-MIB::snmpNotifyTag.'$index' = STRING: " --not-- "= STRING: 2"
|
||||
|
||||
new "Get tag via netconf: candidate expect fail"
|
||||
expecteof_netconf "$clixon_netconf -qf $cfg" 0 "$DEFAULTHELLO" "<rpc $DEFAULTNS><get-config><source><candidate/></source><filter type=\"xpath\" select=\"/sn:SNMP-NOTIFICATION-MIB/sn:snmpNotifyTable/sn:snmpNotifyEntry[sn:snmpNotifyName='$index']/sn:snmpNotifyTag\" xmlns:sn=\"urn:ietf:params:xml:ns:yang:smiv2:SNMP-NOTIFICATION-MIB\"/></get-config></rpc>" "" "<rpc-reply $DEFAULTNS><data/></rpc-reply>"
|
||||
|
||||
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.\'$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"
|
||||
}
|
||||
|
||||
function testexit()
|
||||
{
|
||||
stop_snmp
|
||||
}
|
||||
|
||||
new "SNMP tests"
|
||||
testinit
|
||||
|
||||
new "createAndGo"
|
||||
testrun_createAndGo
|
||||
|
||||
new "createAndWait"
|
||||
testrun_createAndWait
|
||||
|
||||
new "removeRows"
|
||||
testrun_removeRows
|
||||
|
||||
new "Cleaning up"
|
||||
testexit
|
||||
|
||||
new "endtest"
|
||||
endtest
|
||||
248
test/test_snmp_set.sh
Executable file
248
test/test_snmp_set.sh
Executable file
|
|
@ -0,0 +1,248 @@
|
|||
#!/usr/bin/env bash
|
||||
# snmpset. This requires deviation of MIB-YANG to make write operations
|
||||
# Get default value, set new value via SNMP and check it, set new value via NETCONF and check
|
||||
# Selected types from CLIXON/IF-MIB/ENTITY mib
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
APPNAME=example
|
||||
|
||||
# XXX skip for now
|
||||
if [ ${ENABLE_NETSNMP} != "yes" ]; then
|
||||
echo "Skipping test, Net-SNMP support not enabled."
|
||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
fi
|
||||
|
||||
snmpd=$(type -p snmpd)
|
||||
snmpget="$(type -p snmpget) -On -c public -v2c localhost "
|
||||
snmpset="$(type -p snmpset) -On -c public -v2c localhost "
|
||||
|
||||
cfg=$dir/conf.xml
|
||||
fyang=$dir/clixon-example.yang
|
||||
|
||||
# AgentX unix socket
|
||||
SOCK=/var/run/snmp.sock
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${YANG_STANDARD_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${MIB_GENERATED_YANG_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_PIDFILE>/var/tmp/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||
<CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK>
|
||||
<CLICON_SNMP_MIB>CLIXON-TYPES-MIB</CLICON_SNMP_MIB>
|
||||
<CLICON_SNMP_MIB>IF-MIB</CLICON_SNMP_MIB>
|
||||
<CLICON_SNMP_MIB>ENTITY-MIB</CLICON_SNMP_MIB>
|
||||
<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>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module clixon-example{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import CLIXON-TYPES-MIB {
|
||||
prefix "clixon-types";
|
||||
}
|
||||
import IF-MIB {
|
||||
prefix "if-mib";
|
||||
}
|
||||
import ENTITY-MIB {
|
||||
prefix "entity-mib";
|
||||
}
|
||||
deviation "/clixon-types:CLIXON-TYPES-MIB" {
|
||||
deviate replace {
|
||||
config true;
|
||||
}
|
||||
}
|
||||
deviation "/if-mib:IF-MIB" {
|
||||
deviate replace {
|
||||
config true;
|
||||
}
|
||||
}
|
||||
deviation "/entity-mib:ENTITY-MIB" {
|
||||
deviate replace {
|
||||
config true;
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
if true; then # Dont start with a state (default)
|
||||
cat <<EOF > $dir/startup_db
|
||||
<${DATASTORE_TOP}>
|
||||
</${DATASTORE_TOP}>
|
||||
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">
|
||||
<ifStackTable>
|
||||
<ifStackEntry>
|
||||
<ifStackHigherLayer>9</ifStackHigherLayer>
|
||||
<ifStackLowerLayer>9</ifStackLowerLayer>
|
||||
</ifStackEntry>
|
||||
</ifStackTable>
|
||||
<ifTable>
|
||||
<ifEntry>
|
||||
<ifIndex>1</ifIndex>
|
||||
<ifPhysAddress>aa:bb:cc:dd:ee:ff</ifPhysAddress>
|
||||
</ifEntry>
|
||||
</ifTable>
|
||||
</IF-MIB>
|
||||
</${DATASTORE_TOP}>
|
||||
EOF
|
||||
fi
|
||||
|
||||
function testinit(){
|
||||
new "test params: -f $cfg"
|
||||
|
||||
if [ $BE -ne 0 ]; then
|
||||
# Kill old backend and start a new one
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "Failed to start backend"
|
||||
fi
|
||||
|
||||
sudo pkill -f clixon_backend
|
||||
|
||||
new "Starting backend"
|
||||
start_backend -s startup -f $cfg
|
||||
fi
|
||||
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
if [ $SN -ne 0 ]; then
|
||||
# Kill old clixon_snmp, if any
|
||||
new "Terminating any old clixon_snmp processes"
|
||||
sudo killall -q clixon_snmp
|
||||
|
||||
new "Starting clixon_snmp"
|
||||
start_snmp $cfg &
|
||||
fi
|
||||
|
||||
new "wait snmp"
|
||||
wait_snmp
|
||||
}
|
||||
|
||||
# Set value via SNMP, read value via SNMP and CLI
|
||||
# Args:
|
||||
# 1: name
|
||||
# 2: type
|
||||
# 3: value SNMP value
|
||||
# 4: value2 SNMP value2 (as shown "after" snmpset)
|
||||
# 5: xvalue XML/Clixon value
|
||||
# 6: OID
|
||||
function testrun()
|
||||
{
|
||||
name=$1
|
||||
type=$2
|
||||
value=$3
|
||||
value2=$4
|
||||
xvalue=$5
|
||||
oid=$6
|
||||
|
||||
# Type from man snmpset
|
||||
case $type in
|
||||
"INTEGER")
|
||||
set_type="i"
|
||||
;;
|
||||
"STRING")
|
||||
set_type="s"
|
||||
;;
|
||||
"HEX STRING")
|
||||
set_type="x"
|
||||
;;
|
||||
"TIMETICKS")
|
||||
set_type="t"
|
||||
;;
|
||||
"IPADDRESS")
|
||||
set_type="a"
|
||||
;;
|
||||
"OBJID")
|
||||
set_type="o"
|
||||
;;
|
||||
"BITS")
|
||||
set_type="b"
|
||||
;;
|
||||
*)
|
||||
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: $value2"
|
||||
fi
|
||||
new "Check $name via SNMP"
|
||||
if [ "$type" == "STRING" ]; then
|
||||
expectpart "$($snmpget $oid)" 0 "$type:" "$value"
|
||||
else
|
||||
expectpart "$($snmpget $oid)" 0 "$type: $value2"
|
||||
fi
|
||||
|
||||
new "Check $name via CLI"
|
||||
expectpart "$($clixon_cli -1 -f $cfg show config xml)" 0 "<$name>$xvalue</$name>"
|
||||
}
|
||||
|
||||
function testexit(){
|
||||
stop_snmp
|
||||
}
|
||||
|
||||
new "SNMP tests"
|
||||
testinit
|
||||
|
||||
MIB=".1.3.6.1.4.1.8072.200"
|
||||
IFMIB=".1.3.6.1.2.1"
|
||||
ENTMIB=".1.3.6.1.2.1.47.1.1.1"
|
||||
|
||||
testrun clixonExampleInteger INTEGER 1234 1234 1234 ${MIB}.1.1
|
||||
testrun clixonExampleSleeper INTEGER -1 -1 -1 ${MIB}.1.2
|
||||
testrun clixonExampleString STRING foobar foobar foobar ${MIB}.1.3
|
||||
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
|
||||
|
||||
# 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</$name>"
|
||||
|
||||
new "Cleaning up"
|
||||
testexit
|
||||
|
||||
new "endtest"
|
||||
endtest
|
||||
239
test/test_snmp_system.sh
Executable file
239
test/test_snmp_system.sh
Executable file
|
|
@ -0,0 +1,239 @@
|
|||
#!/usr/bin/env bash
|
||||
# SNMP system MIB test
|
||||
|
||||
# Magic line must be first in script (see README.md)
|
||||
s="$_" ; . ./lib.sh || if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
|
||||
# Re-use main example backend state callbacks
|
||||
APPNAME=example
|
||||
|
||||
if [ ${ENABLE_NETSNMP} != "yes" ]; then
|
||||
echo "Skipping test, Net-SNMP support not enabled."
|
||||
if [ "$s" = $0 ]; then exit 0; else return 0; fi
|
||||
fi
|
||||
|
||||
snmpd=$(type -p snmpd)
|
||||
snmpget="$(type -p snmpget) -On -c public -v2c localhost "
|
||||
snmpwalk="$(type -p snmpwalk) -On -c public -v2c localhost "
|
||||
snmpwalkstr="$(type -p snmpwalk) -c public -v2c localhost "
|
||||
snmpgetnext="$(type -p snmpgetnext) -On -c public -v2c localhost "
|
||||
snmptable="$(type -p snmptable) -c public -v2c localhost "
|
||||
|
||||
cfg=$dir/conf_startup.xml
|
||||
fyang=$dir/clixon-example.yang
|
||||
fstate=$dir/state.xml
|
||||
|
||||
# AgentX unix socket
|
||||
SOCK=/var/run/snmp.sock
|
||||
|
||||
# Relies on example_backend.so for $fstate file handling
|
||||
|
||||
cat <<EOF > $cfg
|
||||
<clixon-config xmlns="http://clicon.org/config">
|
||||
<CLICON_CONFIGFILE>$cfg</CLICON_CONFIGFILE>
|
||||
<CLICON_YANG_DIR>${YANG_INSTALLDIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${YANG_STANDARD_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_DIR>${MIB_GENERATED_YANG_DIR}</CLICON_YANG_DIR>
|
||||
<CLICON_YANG_MAIN_FILE>$fyang</CLICON_YANG_MAIN_FILE>
|
||||
<CLICON_SOCK>$dir/$APPNAME.sock</CLICON_SOCK>
|
||||
<CLICON_BACKEND_DIR>/usr/local/lib/$APPNAME/backend</CLICON_BACKEND_DIR>
|
||||
<CLICON_BACKEND_PIDFILE>/var/tmp/$APPNAME.pidfile</CLICON_BACKEND_PIDFILE>
|
||||
<CLICON_XMLDB_DIR>$dir</CLICON_XMLDB_DIR>
|
||||
<CLICON_SNMP_AGENT_SOCK>unix:$SOCK</CLICON_SNMP_AGENT_SOCK>
|
||||
<CLICON_SNMP_MIB>SNMPv2-MIB</CLICON_SNMP_MIB>
|
||||
<CLICON_VALIDATE_STATE_XML>true</CLICON_VALIDATE_STATE_XML>
|
||||
</clixon-config>
|
||||
EOF
|
||||
|
||||
cat <<EOF > $fyang
|
||||
module clixon-example{
|
||||
yang-version 1.1;
|
||||
namespace "urn:example:clixon";
|
||||
prefix ex;
|
||||
import SNMPv2-MIB {
|
||||
prefix "snmpv2-mib";
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# This is state data written to file that backend reads from (on request)
|
||||
# integer and string have values, sleeper does not and uses default (=1)
|
||||
|
||||
cat <<EOF > $fstate
|
||||
<SNMPv2-MIB xmlns="urn:ietf:params:xml:ns:yang:smiv2:SNMPv2-MIB">
|
||||
<system>
|
||||
<sysName>Test</sysName>
|
||||
<sysContact>clixon@clicon.com</sysContact>
|
||||
<sysLocation>Clixon HQ</sysLocation>
|
||||
<sysDescr>System description</sysDescr>
|
||||
<sysUpTime>11223344</sysUpTime>
|
||||
<sysServices>72</sysServices>
|
||||
</system>
|
||||
<sysORTable>
|
||||
<sysOREntry>
|
||||
<sysORIndex>1</sysORIndex>
|
||||
<sysORID>1.3.6.1.2.1.4</sysORID>
|
||||
<sysORDescr>Entry 1 description</sysORDescr>
|
||||
<sysORUpTime>11223344</sysORUpTime>
|
||||
</sysOREntry>
|
||||
<sysOREntry>
|
||||
<sysORIndex>2</sysORIndex>
|
||||
<sysORID>1.3.6.1.2.1.2.2</sysORID>
|
||||
<sysORDescr>Entry 2 description</sysORDescr>
|
||||
<sysORUpTime>1122111111</sysORUpTime>
|
||||
</sysOREntry>
|
||||
</sysORTable>
|
||||
</SNMPv2-MIB>
|
||||
EOF
|
||||
|
||||
function testinit(){
|
||||
new "test params: -f $cfg -- -sS $fstate"
|
||||
if [ $BE -ne 0 ]; then
|
||||
# Kill old backend and start a new one
|
||||
new "kill old backend"
|
||||
sudo clixon_backend -zf $cfg
|
||||
if [ $? -ne 0 ]; then
|
||||
err "Failed to start backend"
|
||||
fi
|
||||
|
||||
sudo pkill -f clixon_backend
|
||||
|
||||
new "Starting backend"
|
||||
start_backend -s init -f $cfg -- -sS $fstate
|
||||
fi
|
||||
|
||||
new "wait backend"
|
||||
wait_backend
|
||||
|
||||
if [ $SN -ne 0 ]; then
|
||||
# Kill old clixon_snmp, if any
|
||||
new "Terminating any old clixon_snmp processes"
|
||||
sudo killall -q clixon_snmp
|
||||
|
||||
new "Starting clixon_snmp"
|
||||
start_snmp $cfg &
|
||||
fi
|
||||
|
||||
new "wait snmp"
|
||||
wait_snmp
|
||||
}
|
||||
|
||||
function testexit(){
|
||||
stop_snmp
|
||||
}
|
||||
|
||||
new "SNMP tests"
|
||||
testinit
|
||||
|
||||
OID_SYS=".1.3.6.1.2.1.1"
|
||||
OID_DESCR="${OID_SYS}.1"
|
||||
OID_UPTIME="${OID_SYS}.3"
|
||||
OID_CONTACT="${OID_SYS}.4"
|
||||
OID_SYSNAME="${OID_SYS}.5"
|
||||
OID_LOCATION="${OID_SYS}.6"
|
||||
OID_SERVICES="${OID_SYS}.7"
|
||||
OID_ORTABLE="${OID_SYS}.9"
|
||||
OID_ORTABLE1_IDX="${OID_SYS}.9.1.1.1"
|
||||
OID_ORTABLE2_IDX="${OID_SYS}.9.1.1.2"
|
||||
OID_ORTABLE1="${OID_SYS}.9.1.3.1"
|
||||
OID_ORTABLE2="${OID_SYS}.9.1.3.2"
|
||||
|
||||
NAME_DESCR="SNMPv2-MIB::sysDescr"
|
||||
NAME_UPTIME="SNMPv2-MIB::sysUpTime"
|
||||
NAME_CONTACT="SNMPv2-MIB::sysContact"
|
||||
NAME_SYSNAME="SNMPv2-MIB::sysName"
|
||||
NAME_LOCATION="SNMPv2-MIB::sysLocation"
|
||||
NAME_SERVICES="SNMPv2-MIB::sysServices"
|
||||
NAME_ORTABLE="SNMPv2-MIB::sysORTable"
|
||||
NAME_ORTABLE1_IDX="SNMPv2-MIB::sysORIndex.1"
|
||||
NAME_ORTABLE2_IDX="SNMPv2-MIB::sysORIndex.2"
|
||||
NAME_ORTABLE1="SNMPv2-MIB::sysORDescr.1"
|
||||
NAME_ORTABLE2="SNMPv2-MIB::sysORDescr.2"
|
||||
|
||||
new "Get description, $OID_DESCR"
|
||||
validate_oid $OID_DESCR $OID_DESCR "STRING" "System description"
|
||||
validate_oid $NAME_DESCR $NAME_DESCR "STRING" "System description"
|
||||
|
||||
new "Get next $OID_DESCR"
|
||||
validate_oid $OID_DESCR $OID_UPTIME "Timeticks" "(11223344) 1 day, 7:10:33.44"
|
||||
validate_oid $NAME_DESCR $NAME_UPTIME "Timeticks" "(11223344) 1 day, 7:10:33.44"
|
||||
|
||||
new "Get contact, $OID_CONTACT"
|
||||
validate_oid $OID_CONTACT $OID_CONTACT "STRING" "clixon@clicon.com"
|
||||
validate_oid $NAME_CONTACT $NAME_CONTACT "STRING" "clixon@clicon.com"
|
||||
|
||||
new "Get next OID after contact $OID_CONTACT"
|
||||
validate_oid $OID_CONTACT $OID_SYSNAME "STRING" "Test"
|
||||
validate_oid $NAME_CONTACT $NAME_SYSNAME "STRING" "Test"
|
||||
|
||||
new "Get sysName $OID_SYSNAME"
|
||||
validate_oid $OID_SYSNAME $OID_SYSNAME "STRING" "Test"
|
||||
validate_oid $NAME_SYSNAME $NAME_SYSNAME "STRING" "Test"
|
||||
|
||||
new "Get next OID after sysName $OID_SYSNAME"
|
||||
validate_oid $OID_SYSNAME $OID_LOCATION "STRING" "Clixon HQ"
|
||||
validate_oid $NAME_SYSNAME $NAME_LOCATION "STRING" "Clixon HQ"
|
||||
|
||||
new "Get sysLocation $OID_LOCATION"
|
||||
validate_oid $OID_LOCATION $OID_LOCATION "STRING" "Clixon HQ"
|
||||
validate_oid $NAME_LOCATION $NAME_LOCATION "STRING" "Clixon HQ"
|
||||
|
||||
new "Get next OID after sysLocation $OID_LOCATION"
|
||||
validate_oid $OID_LOCATION $OID_SERVICES "INTEGER" 72
|
||||
validate_oid $NAME_LOCATION $NAME_SERVICES "INTEGER" 72
|
||||
|
||||
new "Get sysServices $OID_SERVICES"
|
||||
validate_oid $OID_SERVICES $OID_SERVICES "INTEGER" "72"
|
||||
validate_oid $NAME_SERVICES $NAME_SERVICES "INTEGER" "72"
|
||||
|
||||
new "Get next OID after sysServices $OID_SERVICES"
|
||||
validate_oid $OID_SERVICES $OID_ORTABLE1_IDX "INTEGER" 1
|
||||
validate_oid $NAME_SERVICES $NAME_ORTABLE1_IDX "INTEGER" 1
|
||||
|
||||
new "Get first index of OR table $OID_ORTABLE1_IDX"
|
||||
validate_oid $OID_ORTABLE1_IDX $OID_ORTABLE1_IDX "INTEGER" 1
|
||||
validate_oid $NAME_ORTABLE1_IDX $NAME_ORTABLE1_IDX "INTEGER" 1
|
||||
|
||||
new "Get next OID after index $OID_ORTABLE1_IDX"
|
||||
validate_oid $OID_ORTABLE1_IDX $OID_ORTABLE2_IDX "INTEGER" 2
|
||||
validate_oid $NAME_ORTABLE1_IDX $NAME_ORTABLE2_IDX "INTEGER" 2
|
||||
|
||||
new "Get second index $OID_ORTABLE2_IDX"
|
||||
validate_oid $OID_ORTABLE2_IDX $OID_ORTABLE2_IDX "INTEGER" 2
|
||||
validate_oid $NAME_ORTABLE2_IDX $NAME_ORTABLE2_IDX "INTEGER" 2
|
||||
|
||||
new "Get sysORTable, entry 1 $OID_ORTABLE1"
|
||||
validate_oid $OID_ORTABLE1 $OID_ORTABLE1 "STRING" "Entry 1 description"
|
||||
validate_oid $NAME_ORTABLE1 $NAME_ORTABLE1 "STRING" "Entry 1 description"
|
||||
|
||||
new "Get sysORTable, entry 2 $OID_ORTABLE2"
|
||||
validate_oid $OID_ORTABLE2 $OID_ORTABLE2 "STRING" "Entry 2 description"
|
||||
validate_oid $NAME_ORTABLE2 $NAME_ORTABLE2 "STRING" "Entry 2 description"
|
||||
|
||||
new "Get table sysORTable $OID_ORTABLE"
|
||||
expectpart "$($snmptable $OID_ORTABLE)" 0 ".*Entry 1 description.*" "IP-MIB::ip" "1:7:10:33.44"
|
||||
expectpart "$($snmptable $OID_ORTABLE)" 0 ".*Entry 2 description.*" "IF-MIB::ifTable" "129:20:58:31.11"
|
||||
expectpart "$($snmptable $NAME_ORTABLE)" 0 ".*Entry 1 description.*" "IP-MIB::ip" "1:7:10:33.44"
|
||||
expectpart "$($snmptable $NAME_ORTABLE)" 0 ".*Entry 2 description.*" "IF-MIB::ifTable" "129:20:58:31.11"
|
||||
|
||||
new "Walk the tabbles..."
|
||||
expectpart "$($snmpwalkstr system)" 0 "SNMPv2-MIB::sysDescr = STRING: System description." \
|
||||
"SNMPv2-MIB::sysUpTime = Timeticks: (11223344) 1 day, 7:10:33.44" \
|
||||
"SNMPv2-MIB::sysContact = STRING: clixon@clicon.com." \
|
||||
"SNMPv2-MIB::sysName = STRING: Test." \
|
||||
"SNMPv2-MIB::sysLocation = STRING: Clixon HQ." \
|
||||
"SNMPv2-MIB::sysServices = INTEGER: 72" \
|
||||
"SNMPv2-MIB::sysORIndex.1 = INTEGER: 1" \
|
||||
"SNMPv2-MIB::sysORIndex.2 = INTEGER: 2" \
|
||||
"SNMPv2-MIB::sysORID.1 = OID: IP-MIB::ip" \
|
||||
"SNMPv2-MIB::sysORID.2 = OID: IF-MIB::ifTable" \
|
||||
"SNMPv2-MIB::sysORDescr.1 = STRING: Entry 1 description." \
|
||||
"SNMPv2-MIB::sysORDescr.2 = STRING: Entry 2 description." \
|
||||
"SNMPv2-MIB::sysORUpTime.1 = Timeticks: (11223344) 1 day, 7:10:33.44" \
|
||||
"SNMPv2-MIB::sysORUpTime.2 = Timeticks: (1122111111) 129 days, 20:58:31.11"
|
||||
|
||||
new "Cleaning up"
|
||||
testexit
|
||||
|
||||
new "endtest"
|
||||
endtest
|
||||
|
|
@ -1132,5 +1132,27 @@ module clixon-config {
|
|||
0 means no limit";
|
||||
|
||||
}
|
||||
leaf-list CLICON_SNMP_MIB {
|
||||
description
|
||||
"Names of MIBs that are used by clixon_snmp.
|
||||
For each MIB M, a YANG file M.yang is expected to be found.
|
||||
If not found, an error is genereated.
|
||||
The YANG file M.yang is typically generated from the source MIB but can also
|
||||
be handcrafted. An example of such a script is scripts/mib_to_yang.sh.
|
||||
A list of these options should be in the configuration.";
|
||||
type string;
|
||||
}
|
||||
leaf CLICON_SNMP_AGENT_SOCK {
|
||||
type string;
|
||||
default "unix:/tmp/clixon_snmp.sock";
|
||||
description
|
||||
"String description of AgentX socket that clixon_snmp listens to.
|
||||
For example, for net-snmpd, the socket is created by using the following:
|
||||
--agentXSocket=unix:<path>
|
||||
This string currently only supports UNIX socket path.
|
||||
Note also that the user should consider setting permissions appropriately
|
||||
XXX: This should be in later yang revision and documented as added when
|
||||
merged with master";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue