mirror_frr/isisd/isis_snmp.c
Igor Ryzhov 240f48b36b isisd: per-instance dynamic hostname cache
Currently, the dynamic hostname cache is global. It is incorrect because
neighbors in different VRFs may have the same system ID and different
hostnames.

This also fixes a memory leak - when the instance is deleted, the cache
must be cleaned up and the cleanup thread must be cancelled.

Fixes #8832.

Signed-off-by: Igor Ryzhov <iryzhov@nfware.com>
2021-06-11 18:30:47 +03:00

3476 lines
86 KiB
C

/*
* ISIS SNMP support
* Copyright (C) 2020 Volta Networks, Inc.
* Aleksey Romanov
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; see the file COPYING; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* This is minimal read-only implementations providing isisReadOnlyCompliance
*/
#include <zebra.h>
#include <net-snmp/net-snmp-config.h>
#include <net-snmp/net-snmp-includes.h>
#include "vrf.h"
#include "if.h"
#include "log.h"
#include "prefix.h"
#include "table.h"
#include "command.h"
#include "memory.h"
#include "smux.h"
#include "libfrr.h"
#include "lib/version.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_pdu.h"
#include "isisd/isis_network.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_dynhn.h"
#include "isisd/isis_te.h"
#include "isisd/isis_dr.h"
#include "isisd/isis_nb.h"
#include "isisd/isisd.h"
/* ISIS-MIB. */
#define ISIS_MIB 1, 3, 6, 1, 2, 1, 138
#define ISIS_OBJECTS 1
#define ISIS_SYSTEM 1, 1
#define ISIS_SYSLEVEL 1, 2
#define ISIS_CIRC 1, 3
#define ISIS_CIRC_LEVEL_VALUES 1, 4
#define ISIS_COUNTERS 1, 5
#define ISIS_ISADJ 1, 6
/************************ isisSystemGroup ************************/
/* isisSysObject */
#define ISIS_SYS_OBJECT 1, 1, 1
#define ISIS_SYS_VERSION 1
#define ISIS_SYS_LEVELTYPE 2
#define ISIS_SYS_ID 3
#define ISIS_SYS_MAXPATHSPLITS 4
#define ISIS_SYS_MAXLSPGENINT 5
#define ISIS_SYS_POLLESHELLORATE 6
#define ISIS_SYS_WAITTIME 7
#define ISIS_SYS_ADMINSTATE 8
#define ISIS_SYS_L2TOL1LEAKING 9
#define ISIS_SYS_MAXAGE 10
#define ISIS_SYS_RECEIVELSPBUFFERSIZE 11
#define ISIS_SYS_PROTSUPPORTED 12
#define ISIS_SYS_NOTIFICATIONENABLE 13
/* isisManAreaAddrEntry */
#define ISIS_MANAREA_ADDRENTRY 1, 1, 2, 1
#define ISIS_MANAREA_ADDREXISTSTATE 2
/* isisAreaAddrEntry */
#define ISIS_AREA_ADDRENTRY 1, 1, 3, 1
#define ISIS_AREA_ADDR 1
/* isisSummAddrEntry */
#define ISIS_SUMM_ADDRENTRY 1, 1, 4, 1
#define ISIS_SUMM_ADDREXISTSTATE 4
#define ISIS_SUMM_ADDRMETRIC 5
#define ISIS_SUMM_ADDRFULLMETRIC 6
/* isisRedistributeAddrEntry */
#define ISIS_REDISTRIBUTE_ADDRENTRY 1, 1, 5, 1
#define ISIS_REDISTRIBUTE_ADDREXISTSTATE 3
/* isisRouterEntry */
#define ISIS_ROUTER_ENTRY 1, 1, 6, 1
#define ISIS_ROUTER_HOSTNAME 3
#define ISIS_ROUTER_ID 4
/* isisSysLevelTable */
#define ISIS_SYSLEVEL_ENTRY 1, 2, 1, 1
#define ISIS_SYSLEVEL_ORIGLSPBUFFSIZE 2
#define ISIS_SYSLEVEL_MINLSPGENINT 3
#define ISIS_SYSLEVEL_STATE 4
#define ISIS_SYSLEVEL_SETOVERLOAD 5
#define ISIS_SYSLEVEL_SETOVERLOADUNTIL 6
#define ISIS_SYSLEVEL_METRICSTYLE 7
#define ISIS_SYSLEVEL_SPFCONSIDERS 8
#define ISIS_SYSLEVEL_TEENABLED 9
/* isisSystemCounterEntry */
#define ISIS_SYSTEM_COUNTER_ENTRY 1, 5, 1, 1
#define ISIS_SYSSTAT_CORRLSPS 2
#define ISIS_SYSSTAT_AUTHTYPEFAILS 3
#define ISIS_SYSSTAT_AUTHFAILS 4
#define ISIS_SYSSTAT_LSPDBASEOLOADS 5
#define ISIS_SYSSTAT_MANADDRDROPFROMAREAS 6
#define ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS 7
#define ISIS_SYSSTAT_SEQNUMSKIPS 8
#define ISIS_SYSSTAT_OWNLSPPURGES 9
#define ISIS_SYSSTAT_IDFIELDLENMISMATCHES 10
#define ISIS_SYSSTAT_PARTCHANGES 11
#define ISIS_SYSSTAT_SPFRUNS 12
#define ISIS_SYSSTAT_LSPERRORS 13
/************************ isisCircuitGroup ************************/
/* Scalar directly under isisCirc */
#define ISIS_NEXTCIRC_INDEX 1
/* isisCircEntry */
#define ISIS_CIRC_ENTRY 1, 3, 2, 1
#define ISIS_CIRC_IFINDEX 2
#define ISIS_CIRC_ADMINSTATE 3
#define ISIS_CIRC_EXISTSTATE 4
#define ISIS_CIRC_TYPE 5
#define ISIS_CIRC_EXTDOMAIN 6
#define ISIS_CIRC_LEVELTYPE 7
#define ISIS_CIRC_PASSIVECIRCUIT 8
#define ISIS_CIRC_MESHGROUPENABLED 9
#define ISIS_CIRC_MESHGROUP 10
#define ISIS_CIRC_SMALLHELLOS 11
#define ISIS_CIRC_LASTUPTIME 12
#define ISIS_CIRC_3WAYENABLED 13
#define ISIS_CIRC_EXTENDEDCIRCID 14
/* isisCircLevelEntry */
#define ISIS_CIRCLEVEL_ENTRY 1, 4, 1, 1
#define ISIS_CIRCLEVEL_METRIC 2
#define ISIS_CIRCLEVEL_WIDEMETRIC 3
#define ISIS_CIRCLEVEL_ISPRIORITY 4
#define ISIS_CIRCLEVEL_IDOCTET 5
#define ISIS_CIRCLEVEL_ID 6
#define ISIS_CIRCLEVEL_DESIS 7
#define ISIS_CIRCLEVEL_HELLOMULTIPLIER 8
#define ISIS_CIRCLEVEL_HELLOTIMER 9
#define ISIS_CIRCLEVEL_DRHELLOTIMER 10
#define ISIS_CIRCLEVEL_LSPTHROTTLE 11
#define ISIS_CIRCLEVEL_MINLSPRETRANSINT 12
#define ISIS_CIRCLEVEL_CSNPINTERVAL 13
#define ISIS_CIRCLEVEL_PARTSNPINTERVAL 14
/* isisCircuitCounterEntry */
#define ISIS_CIRC_COUNTER_ENTRY 1, 5, 2, 1
#define ISIS_CIRC_ADJCHANGES 2
#define ISIS_CIRC_NUMADJ 3
#define ISIS_CIRC_INITFAILS 4
#define ISIS_CIRC_REJADJS 5
#define ISIS_CIRC_IDFIELDLENMISMATCHES 6
#define ISIS_CIRC_MAXAREAADDRMISMATCHES 7
#define ISIS_CIRC_AUTHTYPEFAILS 8
#define ISIS_CIRC_AUTHFAILS 9
#define ISIS_CIRC_LANDESISCHANGES 10
/************************ isisISAdjGroup ************************/
/* isisISAdjEntry */
#define ISIS_ISADJ_ENTRY 1, 6, 1, 1
#define ISIS_ISADJ_STATE 2
#define ISIS_ISADJ_3WAYSTATE 3
#define ISIS_ISADJ_NEIGHSNPAADDRESS 4
#define ISIS_ISADJ_NEIGHSYSTYPE 5
#define ISIS_ISADJ_NEIGHSYSID 6
#define ISIS_ISADJ_NBREXTENDEDCIRCID 7
#define ISIS_ISADJ_USAGE 8
#define ISIS_ISADJ_HOLDTIMER 9
#define ISIS_ISADJ_NEIGHPRIORITY 10
#define ISIS_ISADJ_LASTUPTIME 11
/* isisISAdjAreadAddrEntry */
#define ISIS_ISADJAREA_ADDRENTRY 1, 6, 2, 1
#define ISIS_ISADJAREA_ADDRESS 2
/* isisISAdjIPAddrEntry*/
#define ISIS_ISADJIPADDR_ENTRY 1, 6, 3, 1
#define ISIS_ISADJIPADDR_TYPE 2
#define ISIS_ISADJIPADDR_ADDRESS 3
/* isisISAdjProtSuppEntty */
#define ISIS_ISADJPROTSUPP_ENTRY 1, 6, 4, 1
#define ISIS_ISADJPROTSUPP_PROTOCOL 1
/************************ Trap data variables ************************/
#define ISIS_NOTIFICATION_ENTRY 1, 10, 1
#define ISIS_NOTIF_SYLELVELINDEX 1
#define ISIS_NOTIF_CIRCIFINDEX 2
#define ISIS_PDU_LSPID 3
#define ISIS_PDU_FRAGMENT 4
#define ISIS_PDU_FIELDLEN 5
#define ISIS_PDU_MAXAREAADDR 6
#define ISIS_PDU_PROTOVER 7
#define ISIS_PDU_LSPSIZE 8
#define ISIS_PDU_ORIGBUFFERSIZE 9
#define ISIS_PDU_BUFFERSIZE 10
#define ISIS_PDU_PROTSUPP 11
#define ISIS_ADJ_STATE 12
#define ISIS_ERROR_OFFSET 13
#define ISIS_ERROR_TLVTYPE 14
#define ISIS_NOTIF_AREAADDR 15
/************************ Traps ************************/
#define ISIS_NOTIFICATIONS ISIS_MIB, 0
#define ISIS_TRAP_DB_OVERLOAD 1
#define ISIS_TRAP_MAN_ADDR_DROP 2
#define ISIS_TRAP_CORRUPTED_LSP 3
#define ISIS_TRAP_LSP_EXCEED_MAX 4
#define ISIS_TRAP_ID_LEN_MISMATCH 5
#define ISIS_TRAP_MAX_AREA_ADDR_MISMATCH 6
#define ISIS_TRAP_OWN_LSP_PURGE 7
#define ISIS_TRAP_SEQNO_SKIPPED 8
#define ISIS_TRAP_AUTHEN_TYPE_FAILURE 9
#define ISIS_TRAP_AUTHEN_FAILURE 10
#define ISIS_TRAP_VERSION_SKEW 11
#define ISIS_TRAP_AREA_MISMATCH 12
#define ISIS_TRAP_REJ_ADJACENCY 13
#define ISIS_TRAP_LSP_TOO_LARGE 14
#define ISIS_TRAP_LSP_BUFFSIZE_MISMATCH 15
#define ISIS_TRAP_PROTSUPP_MISMATCH 16
#define ISIS_TRAP_ADJ_STATE_CHANGE 17
#define ISIS_TRAP_LSP_ERROR 18
/* Change this definition if number of traps changes */
#define ISIS_TRAP_LAST_TRAP ISIS_TRAP_LSP_ERROR + 1
#define ISIS_SNMP_TRAP_VAR 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0
/* SNMP value hack. */
#define COUNTER32 ASN_COUNTER
#define INTEGER ASN_INTEGER
#define UNSIGNED32 ASN_GAUGE
#define TIMESTAMP ASN_TIMETICKS
#define TIMETICKS ASN_TIMETICKS
#define STRING ASN_OCTET_STR
/* Declare static local variables for convenience. */
SNMP_LOCAL_VARIABLES
/* If ARRAY_SIZE is not available use a primitive substitution */
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
#endif
/*
* Define time function, it serves two purposes
* 1. Uses unint32_t for unix time and encapsulates
* sing extension issues in conversion from time_t
*
* 2. I could be replaced in unit test environment
*/
#ifndef ISIS_SNMP_HAVE_TIME_FUNC
static uint32_t isis_snmp_time(void)
{
return (uint32_t)time(NULL);
}
#endif
/* ISIS-MIB instances. */
static oid isis_oid[] = {ISIS_MIB};
/* SNMP trap variable */
static oid isis_snmp_trap_var[] = {ISIS_SNMP_TRAP_VAR};
/* SNMP trap values (others are calculated on the fly */
static oid isis_snmp_notifications[] = {ISIS_NOTIFICATIONS};
static oid isis_snmp_trap_val_db_overload[] = {ISIS_NOTIFICATIONS,
ISIS_TRAP_DB_OVERLOAD};
static oid isis_snmp_trap_val_lsp_exceed_max[] = {ISIS_NOTIFICATIONS,
ISIS_TRAP_LSP_EXCEED_MAX};
static oid isis_snmp_trap_val_area_mismatch[] = {ISIS_NOTIFICATIONS,
ISIS_TRAP_AREA_MISMATCH};
static oid isis_snmp_trap_val_lsp_error[] = {ISIS_NOTIFICATIONS,
ISIS_TRAP_LSP_ERROR};
/*
* Trap vars under 'isisNotifications': note: we use full names of variables
* scalar index
*/
static oid isis_snmp_trap_data_var_sys_level_index[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_NOTIF_SYLELVELINDEX, 0};
static oid isis_snmp_trap_data_var_circ_if_index[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_NOTIF_CIRCIFINDEX, 0};
static oid isis_snmp_trap_data_var_pdu_lsp_id[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_LSPID, 0};
static oid isis_snmp_trap_data_var_pdu_fragment[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_FRAGMENT, 0};
static oid isis_snmp_trap_data_var_pdu_field_len[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_FIELDLEN, 0};
static oid isis_snmp_trap_data_var_pdu_max_area_addr[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_MAXAREAADDR, 0};
static oid isis_snmp_trap_data_var_pdu_proto_ver[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_PROTOVER, 0};
static oid isis_snmp_trap_data_var_pdu_lsp_size[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_LSPSIZE, 0};
static oid isis_snmp_trap_data_var_adj_state[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ADJ_STATE, 0};
static oid isis_snmp_trap_data_var_error_offset[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ERROR_OFFSET, 0};
static oid isis_snmp_trap_data_var_error_tlv_type[] = {
ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ERROR_TLVTYPE, 0};
/*
* Other variables used by traps: note we use full names of variables and
* reserve space for index
*/
static oid isis_snmp_trap_data_var_sys_level_state[] = {
ISIS_MIB, ISIS_SYSLEVEL_ENTRY, ISIS_SYSLEVEL_STATE, 0};
/* Throttle time values for traps */
static time_t isis_snmp_trap_timestamp[ISIS_TRAP_LAST_TRAP]; /* ?? 1 */
/* Max len of raw-pdu in traps */
#define ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN (64)
/*
* Just to save on typing we have a shortcut structure
* to specify mib layout as prefix/leaf combination
*/
#define ISIS_SNMP_PREF_LEN_MAX 10
struct isis_var_prefix {
FindVarMethod *findVar;
uint8_t ivd_pref_len;
oid ivd_pref[ISIS_SNMP_PREF_LEN_MAX];
};
/* Find-val functions */
static uint8_t *isis_snmp_find_sys_object(struct variable *, oid *, size_t *,
int, size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_man_area(struct variable *, oid *, size_t *, int,
size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_area_addr(struct variable *, oid *, size_t *,
int, size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_summ_addr(struct variable *, oid *, size_t *,
int, size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_redistribute_addr(struct variable *, oid *,
size_t *, int, size_t *,
WriteMethod **);
static uint8_t *isis_snmp_find_router(struct variable *, oid *, size_t *, int,
size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_sys_level(struct variable *, oid *, size_t *,
int, size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_system_counter(struct variable *, oid *,
size_t *, int, size_t *,
WriteMethod **);
static uint8_t *isis_snmp_find_next_circ_index(struct variable *, oid *,
size_t *, int, size_t *,
WriteMethod **);
static uint8_t *isis_snmp_find_circ(struct variable *, oid *, size_t *, int,
size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_circ_level(struct variable *, oid *, size_t *,
int, size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_circ_counter(struct variable *, oid *, size_t *,
int, size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_isadj(struct variable *, oid *, size_t *, int,
size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_isadj_area(struct variable *, oid *, size_t *,
int, size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *, oid *, size_t *,
int, size_t *, WriteMethod **);
static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *, oid *,
size_t *, int, size_t *,
WriteMethod **);
/*
* Just to save on typing we have a shortcut structure
* to specify mib layout, we populate the rest of the data
* during initialization
*/
#define ISIS_PREF_LEN_MAX (6)
struct isis_func_to_prefix {
FindVarMethod *ihtp_func;
oid ihtp_pref_oid[ISIS_PREF_LEN_MAX];
uint8_t ihtp_pref_len;
};
static struct isis_func_to_prefix isis_func_to_prefix_arr[] = {
{isis_snmp_find_sys_object, {ISIS_SYS_OBJECT}, 3},
{isis_snmp_find_man_area, {ISIS_MANAREA_ADDRENTRY}, 4},
{isis_snmp_find_area_addr, {ISIS_AREA_ADDRENTRY}, 4},
{isis_snmp_find_summ_addr, {ISIS_SUMM_ADDRENTRY}, 4},
{isis_snmp_find_redistribute_addr, {ISIS_REDISTRIBUTE_ADDRENTRY}, 4},
{isis_snmp_find_router, {ISIS_ROUTER_ENTRY}, 4},
{isis_snmp_find_sys_level, {ISIS_SYSLEVEL_ENTRY}, 4},
{isis_snmp_find_system_counter, {ISIS_SYSTEM_COUNTER_ENTRY}, 4},
{isis_snmp_find_next_circ_index, {ISIS_CIRC}, 2},
{isis_snmp_find_circ, {ISIS_CIRC_ENTRY}, 4},
{isis_snmp_find_circ_level, {ISIS_CIRCLEVEL_ENTRY}, 4},
{isis_snmp_find_circ_counter, {ISIS_CIRC_COUNTER_ENTRY}, 4},
{isis_snmp_find_isadj, {ISIS_ISADJ_ENTRY}, 4},
{isis_snmp_find_isadj_area, {ISIS_ISADJAREA_ADDRENTRY}, 4},
{isis_snmp_find_isadj_ipaddr, {ISIS_ISADJIPADDR_ENTRY}, 4},
{isis_snmp_find_isadj_prot_supp, {ISIS_ISADJPROTSUPP_ENTRY}, 4},
};
static size_t isis_func_to_prefix_count = ARRAY_SIZE(isis_func_to_prefix_arr);
static struct variable isis_var_arr[] = {
{ISIS_SYS_VERSION, INTEGER, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_LEVELTYPE, INTEGER, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_ID, STRING, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_MAXPATHSPLITS, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_MAXLSPGENINT, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_POLLESHELLORATE, UNSIGNED32, RONLY,
isis_snmp_find_sys_object},
{ISIS_SYS_WAITTIME, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_ADMINSTATE, INTEGER, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_L2TOL1LEAKING, INTEGER, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_MAXAGE, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_RECEIVELSPBUFFERSIZE, UNSIGNED32, RONLY,
isis_snmp_find_sys_object},
{ISIS_SYS_PROTSUPPORTED, STRING, RONLY, isis_snmp_find_sys_object},
{ISIS_SYS_NOTIFICATIONENABLE, INTEGER, RONLY,
isis_snmp_find_sys_object},
{ISIS_MANAREA_ADDREXISTSTATE, INTEGER, RONLY, isis_snmp_find_man_area},
{ISIS_AREA_ADDR, STRING, RONLY, isis_snmp_find_area_addr},
{ISIS_SUMM_ADDREXISTSTATE, INTEGER, RONLY, isis_snmp_find_summ_addr},
{ISIS_SUMM_ADDRMETRIC, UNSIGNED32, RONLY, isis_snmp_find_summ_addr},
{ISIS_SUMM_ADDRFULLMETRIC, UNSIGNED32, RONLY, isis_snmp_find_summ_addr},
{ISIS_REDISTRIBUTE_ADDREXISTSTATE, INTEGER, RONLY,
isis_snmp_find_redistribute_addr},
{ISIS_ROUTER_HOSTNAME, STRING, RONLY, isis_snmp_find_router},
{ISIS_ROUTER_ID, UNSIGNED32, RONLY, isis_snmp_find_router},
{ISIS_SYSLEVEL_ORIGLSPBUFFSIZE, UNSIGNED32, RONLY,
isis_snmp_find_sys_level},
{ISIS_SYSLEVEL_MINLSPGENINT, UNSIGNED32, RONLY,
isis_snmp_find_sys_level},
{ISIS_SYSLEVEL_STATE, INTEGER, RONLY, isis_snmp_find_sys_level},
{ISIS_SYSLEVEL_SETOVERLOAD, INTEGER, RONLY, isis_snmp_find_sys_level},
{ISIS_SYSLEVEL_SETOVERLOADUNTIL, UNSIGNED32, RONLY,
isis_snmp_find_sys_level},
{ISIS_SYSLEVEL_METRICSTYLE, INTEGER, RONLY, isis_snmp_find_sys_level},
{ISIS_SYSLEVEL_SPFCONSIDERS, INTEGER, RONLY, isis_snmp_find_sys_level},
{ISIS_SYSLEVEL_TEENABLED, INTEGER, RONLY, isis_snmp_find_sys_level},
{ISIS_SYSSTAT_CORRLSPS, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_AUTHTYPEFAILS, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_AUTHFAILS, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_LSPDBASEOLOADS, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_MANADDRDROPFROMAREAS, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_SEQNUMSKIPS, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_OWNLSPPURGES, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_IDFIELDLENMISMATCHES, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_PARTCHANGES, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_SYSSTAT_SPFRUNS, COUNTER32, RONLY, isis_snmp_find_system_counter},
{ISIS_SYSSTAT_LSPERRORS, COUNTER32, RONLY,
isis_snmp_find_system_counter},
{ISIS_NEXTCIRC_INDEX, UNSIGNED32, RONLY,
isis_snmp_find_next_circ_index},
{ISIS_CIRC_IFINDEX, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_ADMINSTATE, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_EXISTSTATE, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_TYPE, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_EXTDOMAIN, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_LEVELTYPE, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_PASSIVECIRCUIT, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_MESHGROUPENABLED, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_MESHGROUP, UNSIGNED32, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_SMALLHELLOS, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_LASTUPTIME, TIMESTAMP, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_3WAYENABLED, INTEGER, RONLY, isis_snmp_find_circ},
{ISIS_CIRC_EXTENDEDCIRCID, UNSIGNED32, RONLY, isis_snmp_find_circ},
{ISIS_CIRCLEVEL_METRIC, UNSIGNED32, RONLY, isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_WIDEMETRIC, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_ISPRIORITY, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_IDOCTET, UNSIGNED32, RONLY, isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_ID, STRING, RONLY, isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_DESIS, STRING, RONLY, isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_HELLOMULTIPLIER, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_HELLOTIMER, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_DRHELLOTIMER, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_LSPTHROTTLE, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_MINLSPRETRANSINT, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_CSNPINTERVAL, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRCLEVEL_PARTSNPINTERVAL, UNSIGNED32, RONLY,
isis_snmp_find_circ_level},
{ISIS_CIRC_ADJCHANGES, COUNTER32, RONLY, isis_snmp_find_circ_counter},
{ISIS_CIRC_NUMADJ, UNSIGNED32, RONLY, isis_snmp_find_circ_counter},
{ISIS_CIRC_INITFAILS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
{ISIS_CIRC_REJADJS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
{ISIS_CIRC_IDFIELDLENMISMATCHES, COUNTER32, RONLY,
isis_snmp_find_circ_counter},
{ISIS_CIRC_MAXAREAADDRMISMATCHES, COUNTER32, RONLY,
isis_snmp_find_circ_counter},
{ISIS_CIRC_AUTHTYPEFAILS, COUNTER32, RONLY,
isis_snmp_find_circ_counter},
{ISIS_CIRC_AUTHFAILS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
{ISIS_CIRC_LANDESISCHANGES, COUNTER32, RONLY,
isis_snmp_find_circ_counter},
{ISIS_ISADJ_STATE, INTEGER, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_3WAYSTATE, INTEGER, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_NEIGHSNPAADDRESS, STRING, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_NEIGHSYSTYPE, INTEGER, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_NEIGHSYSID, STRING, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_NBREXTENDEDCIRCID, UNSIGNED32, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_USAGE, INTEGER, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_HOLDTIMER, UNSIGNED32, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_NEIGHPRIORITY, UNSIGNED32, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJ_LASTUPTIME, TIMESTAMP, RONLY, isis_snmp_find_isadj},
{ISIS_ISADJAREA_ADDRESS, STRING, RONLY, isis_snmp_find_isadj_area},
{ISIS_ISADJIPADDR_TYPE, INTEGER, RONLY, isis_snmp_find_isadj_ipaddr},
{ISIS_ISADJIPADDR_ADDRESS, STRING, RONLY, isis_snmp_find_isadj_ipaddr},
{ISIS_ISADJPROTSUPP_PROTOCOL, INTEGER, RONLY,
isis_snmp_find_isadj_prot_supp},
};
static const size_t isis_var_count = ARRAY_SIZE(isis_var_arr);
/* Minimal set of hard-coded data */
#define ISIS_VERSION (1)
/* If sys-id is not set use this value */
static uint8_t isis_null_sysid[ISIS_SYS_ID_LEN];
/* OSI addr-len */
#define ISIS_SNMP_OSI_ADDR_LEN_MAX (20)
/*
* The implementation has a fixed max-path splits value
* of 64 (see ISIS_MAX_PATH_SPLITS), the max mib value
* is 32.
*
* FIXME(aromanov): should we return 32 or 64?
*/
#define ISIS_SNMP_MAX_PATH_SPLITS (32)
#define ISIS_SNMP_ADMIN_STATE_ON (1)
#define ISIS_SNMP_ROW_STATUS_ACTIVE (1)
#define ISIS_SNMP_LEVEL_STATE_OFF (1)
#define ISIS_SNMP_LEVEL_STATE_ON (2)
#define ISIS_SNMP_LEVEL_STATE_WAITING (3)
#define ISIS_SNMP_LEVEL_STATE_OVERLOADED (4)
#define ISIS_SNMP_TRUTH_VALUE_TRUE (1)
#define ISIS_SNMP_TRUTH_VALUE_FALSE (2)
#define ISIS_SNMP_METRIC_STYLE_NARROW (1)
#define ISIS_SNMP_METRIC_STYLE_WIDE (2)
#define ISIS_SNMP_METRIC_STYLE_BOTH (3)
#define ISIS_SNMP_MESH_GROUP_INACTIVE (1)
#define ISIS_SNMP_ADJ_STATE_DOWN (1)
#define ISIS_SNMP_ADJ_STATE_INITIALIZING (2)
#define ISIS_SNMP_ADJ_STATE_UP (3)
#define ISIS_SNMP_ADJ_STATE_FAILED (4)
static inline uint32_t isis_snmp_adj_state(enum isis_adj_state state)
{
switch (state) {
case ISIS_ADJ_UNKNOWN:
return ISIS_SNMP_ADJ_STATE_DOWN;
case ISIS_ADJ_INITIALIZING:
return ISIS_SNMP_ADJ_STATE_INITIALIZING;
case ISIS_ADJ_UP:
return ISIS_SNMP_ADJ_STATE_UP;
case ISIS_ADJ_DOWN:
return ISIS_SNMP_ADJ_STATE_FAILED;
}
return 0; /* not reached */
}
#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1 (1)
#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2 (2)
#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2 (3)
#define ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN (4)
static inline uint32_t isis_snmp_adj_neightype(enum isis_system_type type)
{
switch (type) {
case ISIS_SYSTYPE_UNKNOWN:
case ISIS_SYSTYPE_ES:
return ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN;
case ISIS_SYSTYPE_IS:
return ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2;
case ISIS_SYSTYPE_L1_IS:
return ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1;
case ISIS_SYSTYPE_L2_IS:
return ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2;
}
return 0; /* not reached */
}
#define ISIS_SNMP_INET_TYPE_V4 (1)
#define ISIS_SNMP_INET_TYPE_V6 (2)
#define ISIS_SNMP_P2P_CIRCUIT (3)
/* Protocols supported value */
static uint8_t isis_snmp_protocols_supported = 0x7; /* All: iso, ipv4, ipv6 */
#define SNMP_CIRCUITS_MAX (512)
static struct isis_circuit *snmp_circuits[SNMP_CIRCUITS_MAX];
static uint32_t snmp_circuit_id_last;
static int isis_circuit_snmp_id_gen(struct isis_circuit *circuit)
{
uint32_t id;
uint32_t i;
id = snmp_circuit_id_last;
id++;
/* find next unused entry */
for (i = 0; i < SNMP_CIRCUITS_MAX; i++) {
if (id >= SNMP_CIRCUITS_MAX) {
id = 0;
continue;
}
if (id == 0)
continue;
if (snmp_circuits[id] == NULL)
break;
id++;
}
if (i == SNMP_CIRCUITS_MAX) {
zlog_warn("Could not allocate a smmp-circuit-id");
return 0;
}
snmp_circuits[id] = circuit;
snmp_circuit_id_last = id;
circuit->snmp_id = id;
return 0;
}
static int isis_circuit_snmp_id_free(struct isis_circuit *circuit)
{
snmp_circuits[circuit->snmp_id] = NULL;
circuit->snmp_id = 0;
return 0;
}
/*
* Convenience function to move to the next circuit,
*/
static struct isis_circuit *isis_snmp_circuit_next(struct isis_circuit *circuit)
{
uint32_t start;
uint32_t off;
start = 1;
if (circuit != NULL)
start = circuit->snmp_id + 1;
for (off = start; off < SNMP_CIRCUITS_MAX; off++) {
circuit = snmp_circuits[off];
if (circuit != NULL)
return circuit;
}
return NULL;
}
/*
* Convenience function to get the first matching level
*/
static int isis_snmp_circuit_get_level_lo(struct isis_circuit *circuit)
{
if (circuit->is_type == IS_LEVEL_2)
return IS_LEVEL_2;
return IS_LEVEL_1;
}
/* Check level match */
static int isis_snmp_get_level_match(int is_type, int level)
{
if (is_type != IS_LEVEL_1 && is_type != IS_LEVEL_2
&& is_type != IS_LEVEL_1_AND_2)
return 0;
if (level != IS_LEVEL_1 && level != IS_LEVEL_2)
return 0;
if (is_type == IS_LEVEL_1) {
if (level == IS_LEVEL_1)
return 1;
return 0;
}
if (is_type == IS_LEVEL_2) {
if (level == IS_LEVEL_2)
return 1;
return 0;
}
return 1;
}
/*
* Helper function to convert oid index representing
* octet-string index (e.g. isis-sys-id) to byte string
* representing the same index.
*
* Also we do not fail if idx is longer than max_len,
* so we can use the same function to check compound
* indexes.
*/
static int isis_snmp_conv_exact(uint8_t *buf, size_t max_len, size_t *out_len,
const oid *idx, size_t idx_len)
{
size_t off;
size_t len;
/* Oid representation: length followed by bytes */
if (idx == NULL || idx_len == 0)
return 0;
len = idx[0];
if (len > max_len)
return 0;
if (idx_len < len + 1)
return 0;
for (off = 0; off < len; off++) {
if (idx[off + 1] > 0xff)
return 0;
buf[off] = (uint8_t)(idx[off + 1] & 0xff);
}
*out_len = len;
return 1;
}
static int isis_snmp_conv_next(uint8_t *buf, size_t max_len, size_t *out_len,
int *try_exact, const oid *idx, size_t idx_len)
{
size_t off;
size_t len;
size_t cmp_len;
if (idx == NULL || idx_len == 0) {
*out_len = 0;
*try_exact = 1;
return 1;
}
len = idx[0];
if (len > max_len)
return 0;
cmp_len = len;
if ((idx_len - 1) < cmp_len)
cmp_len = idx_len - 1;
for (off = 0; off < cmp_len; off++) {
if (idx[off + 1] > 0xff) {
memset(buf + off, 0xff, len - off);
*out_len = len;
*try_exact = 1;
return 1;
}
buf[off] = (uint8_t)(idx[off + 1] & 0xff);
}
if (cmp_len < len)
memset(buf + cmp_len, 0, len - cmp_len);
*out_len = len;
*try_exact = cmp_len < len ? 1 : 0;
return 1;
}
/*
* Helper functions to find area address from snmp index
*/
static int isis_snmp_area_addr_lookup_exact(oid *oid_idx, size_t oid_idx_len,
struct isis_area **ret_area,
struct area_addr **ret_addr)
{
uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX];
size_t addr_len;
struct isis_area *area = NULL;
struct area_addr *addr = NULL;
struct listnode *addr_node;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL)
return 0;
if (list_isempty(isis->area_list)) {
/* Area is not configured yet */
return 0;
}
area = listgetdata(listhead(isis->area_list));
int res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &addr_len,
oid_idx, oid_idx_len);
if (!res || addr_len == 0 || oid_idx_len != (addr_len + 1)) {
/* Bad conversion, empty address or extra oids at the end */
return 0;
}
for (ALL_LIST_ELEMENTS_RO(area->area_addrs, addr_node, addr)) {
if (addr->addr_len != addr_len)
continue;
if (memcmp(addr->area_addr, cmp_buf, addr_len) == 0) {
if (ret_area != 0)
*ret_area = area;
if (ret_addr != 0)
*ret_addr = addr;
return 1;
}
}
return 0;
}
static int isis_snmp_area_addr_lookup_next(oid *oid_idx, size_t oid_idx_len,
struct isis_area **ret_area,
struct area_addr **ret_addr)
{
uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX];
size_t addr_len;
int try_exact = 0;
struct isis_area *found_area = NULL;
struct isis_area *area = NULL;
struct area_addr *found_addr = NULL;
struct area_addr *addr = NULL;
struct listnode *addr_node;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL)
return 0;
if (list_isempty(isis->area_list)) {
/* Area is not configured yet */
return 0;
}
area = listgetdata(listhead(isis->area_list));
int res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &addr_len,
&try_exact, oid_idx, oid_idx_len);
if (!res)
return 0;
for (ALL_LIST_ELEMENTS_RO(area->area_addrs, addr_node, addr)) {
if (addr->addr_len < addr_len)
continue;
if (addr->addr_len == addr_len) {
if (addr_len == 0)
continue;
res = memcmp(addr->area_addr, cmp_buf, addr_len);
if (res < 0)
continue;
if (res == 0 && addr->addr_len == addr_len) {
if (try_exact) {
/*
* This is the best match no point
* to look further
*/
found_area = area;
found_addr = addr;
break;
}
continue;
}
}
if (found_addr == NULL || addr->addr_len < found_addr->addr_len
|| (addr->addr_len == found_addr->addr_len
&& memcmp(addr->area_addr, found_addr->area_addr,
addr->addr_len)
< 0)) {
found_area = area;
found_addr = addr;
}
}
if (found_area == NULL)
return 0;
if (ret_area != 0)
*ret_area = found_area;
if (ret_addr != 0)
*ret_addr = found_addr;
return 1;
}
/*
* Helper functions to find circuit from
* snmp index
*/
static int isis_snmp_circuit_lookup_exact(oid *oid_idx, size_t oid_idx_len,
struct isis_circuit **ret_circuit)
{
struct isis_circuit *circuit;
if (oid_idx == NULL || oid_idx_len < 1
|| oid_idx[0] > SNMP_CIRCUITS_MAX)
return 0;
circuit = snmp_circuits[oid_idx[0]];
if (circuit == NULL)
return 0;
if (ret_circuit != NULL)
*ret_circuit = circuit;
return 1;
}
static int isis_snmp_circuit_lookup_next(oid *oid_idx, size_t oid_idx_len,
struct isis_circuit **ret_circuit)
{
oid off;
oid start;
struct isis_circuit *circuit;
start = 0;
if (oid_idx != NULL && oid_idx_len != 0) {
if (oid_idx[0] > SNMP_CIRCUITS_MAX)
return 0;
start = oid_idx[0];
}
for (off = start; off < SNMP_CIRCUITS_MAX; ++off) {
circuit = snmp_circuits[off];
if (circuit != NULL && off > start) {
if (ret_circuit != NULL)
*ret_circuit = circuit;
return 1;
}
}
return 0;
}
/*
* Helper functions to find circuit level
* combination from snmp index
*/
static int isis_snmp_circuit_level_lookup_exact(
oid *oid_idx, size_t oid_idx_len, int check_match,
struct isis_circuit **ret_circuit, int *ret_level)
{
int level;
int res;
struct isis_circuit *circuit;
/* Minor optimization: check level first */
if (oid_idx == NULL || oid_idx_len < 2)
return 0;
if (oid_idx[1] < IS_LEVEL_1 || oid_idx[1] > IS_LEVEL_2)
return 0;
level = (int)oid_idx[1];
res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit);
if (!res)
return 0;
if (check_match && !isis_snmp_get_level_match(circuit->is_type, level))
return 0;
if (ret_circuit != NULL)
*ret_circuit = circuit;
if (ret_level != NULL)
*ret_level = level;
return 1;
}
static int isis_snmp_circuit_level_lookup_next(
oid *oid_idx, size_t oid_idx_len, int check_match,
struct isis_circuit **ret_circuit, int *ret_level)
{
oid off;
oid start;
struct isis_circuit *circuit = NULL;
int level;
start = 0;
if (oid_idx != NULL && oid_idx_len != 0) {
if (oid_idx[0] > SNMP_CIRCUITS_MAX)
return 0;
start = oid_idx[0];
}
for (off = start; off < SNMP_CIRCUITS_MAX; off++) {
circuit = snmp_circuits[off];
if (circuit == NULL)
continue;
if (off > start || oid_idx_len < 2) {
/* Found and can use level 1 */
level = IS_LEVEL_1;
break;
}
assert(oid_idx != NULL);
/* We have to check level specified by index */
if (oid_idx[1] < IS_LEVEL_1) {
level = IS_LEVEL_1;
break;
}
if (oid_idx[1] < IS_LEVEL_2) {
level = IS_LEVEL_2;
break;
}
/* Try next */
circuit = NULL;
}
if (circuit == NULL)
return 0;
if (check_match
&& !isis_snmp_get_level_match(circuit->is_type, level)) {
if (level == IS_LEVEL_1) {
/*
* We can simply advance level because
* at least one level should match
*/
level = IS_LEVEL_2;
} else {
/* We have to move to the next circuit */
circuit = isis_snmp_circuit_next(circuit);
if (circuit == NULL)
return 0;
level = isis_snmp_circuit_get_level_lo(circuit);
}
}
if (ret_circuit != NULL)
*ret_circuit = circuit;
if (ret_level != NULL)
*ret_level = level;
return 1;
}
/*
* Helper functions to find adjacency
* from snmp index.
*
* We have 4 tables related to adjacency
* looking up adjacency is quite expensive
* in case of bcast interfaces.
*
* It is pain to have 4 very similar functions
* hence we pass in and out additional data
* we are looking for.
*
* Note: we use data-len value to distinguish
* between ipv4 and ipv6 addresses
*/
#define ISIS_SNMP_ADJ_DATA_NONE (1)
#define ISIS_SNMP_ADJ_DATA_AREA_ADDR (2)
#define ISIS_SNMP_ADJ_DATA_IP_ADDR (3)
#define ISIS_SNMP_ADJ_DATA_PROTO (4)
/*
* Helper function to process data associated
* with adjacency
*/
static int isis_snmp_adj_helper(struct isis_adjacency *adj, int data_id,
oid data_off, uint8_t **ret_data,
size_t *ret_data_len)
{
uint8_t *data = NULL;
size_t data_len = 0;
switch (data_id) {
case ISIS_SNMP_ADJ_DATA_NONE:
break;
case ISIS_SNMP_ADJ_DATA_AREA_ADDR:
if (data_off >= adj->area_address_count)
return 0;
data = adj->area_addresses[data_off].area_addr;
data_len = adj->area_addresses[data_off].addr_len;
break;
case ISIS_SNMP_ADJ_DATA_IP_ADDR:
if (data_off
>= (adj->ipv4_address_count + adj->ipv6_address_count))
return 0;
if (data_off >= adj->ipv4_address_count) {
data = (uint8_t *)&adj->ipv6_addresses
[data_off - adj->ipv4_address_count];
data_len = sizeof(adj->ipv6_addresses[0]);
} else {
data = (uint8_t *)&adj->ipv4_addresses[data_off];
data_len = sizeof(adj->ipv4_addresses[0]);
}
break;
case ISIS_SNMP_ADJ_DATA_PROTO:
if (data_off >= adj->nlpids.count)
return 0;
data = &adj->nlpids.nlpids[data_off];
data_len = sizeof(adj->nlpids.nlpids[0]);
break;
default:
assert(0);
return 0;
}
if (ret_data != NULL)
*ret_data = data;
if (ret_data_len != NULL)
*ret_data_len = data_len;
return 1;
}
static int isis_snmp_adj_lookup_exact(oid *oid_idx, size_t oid_idx_len,
int data_id,
struct isis_adjacency **ret_adj,
oid *ret_data_idx, uint8_t **ret_data,
size_t *ret_data_len)
{
int res;
struct listnode *node;
struct isis_circuit *circuit;
struct isis_adjacency *adj;
struct isis_adjacency *tmp_adj;
oid adj_idx;
oid data_off;
uint8_t *data;
size_t data_len;
res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit);
if (!res)
return 0;
if (oid_idx == NULL || oid_idx_len < 2
|| (data_id != ISIS_SNMP_ADJ_DATA_NONE && oid_idx_len < 3))
return 0;
adj_idx = oid_idx[1];
if (data_id != ISIS_SNMP_ADJ_DATA_NONE) {
if (oid_idx[2] == 0)
return 0;
data_off = oid_idx[2] - 1;
} else {
/*
* Data-off is not used if data-id is none
* but we set it just for consistency
*/
data_off = 0;
}
adj = NULL;
data = NULL;
data_len = 0;
for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node, tmp_adj)) {
if (tmp_adj->snmp_idx > adj_idx) {
/*
* Adjacencies are ordered in the list
* no point to look further
*/
break;
}
if (tmp_adj->snmp_idx == adj_idx) {
res = isis_snmp_adj_helper(tmp_adj, data_id, data_off,
&data, &data_len);
if (res)
adj = tmp_adj;
break;
}
}
if (adj == NULL)
return 0;
if (ret_adj != NULL)
*ret_adj = adj;
if (ret_data_idx != NULL)
*ret_data_idx = data_off + 1;
if (ret_data)
*ret_data = data;
if (ret_data_len)
*ret_data_len = data_len;
return 1;
}
static int isis_snmp_adj_lookup_next(oid *oid_idx, size_t oid_idx_len,
int data_id,
struct isis_adjacency **ret_adj,
oid *ret_data_idx, uint8_t **ret_data,
size_t *ret_data_len)
{
struct listnode *node;
struct isis_circuit *circuit;
struct isis_adjacency *adj;
struct isis_adjacency *tmp_adj;
oid circ_idx;
oid adj_idx;
oid data_idx;
uint8_t *data;
size_t data_len;
adj = NULL;
data = NULL;
data_len = 0;
/*
* Note: we rely on the fact that data indexes are consequtive
* starting from 1
*/
if (oid_idx == 0 || oid_idx_len == 0) {
circ_idx = 0;
adj_idx = 0;
data_idx = 0;
} else if (oid_idx_len == 1) {
circ_idx = oid_idx[0];
adj_idx = 0;
data_idx = 0;
} else if (oid_idx_len == 2) {
circ_idx = oid_idx[0];
adj_idx = oid_idx[1];
data_idx = 0;
} else {
circ_idx = oid_idx[0];
adj_idx = oid_idx[1];
if (data_id == ISIS_SNMP_ADJ_DATA_NONE)
data_idx = 0;
else
data_idx = oid_idx[2];
}
if (!isis_snmp_circuit_lookup_exact(&circ_idx, 1, &circuit)
&& !isis_snmp_circuit_lookup_next(&circ_idx, 1, &circuit))
/* No circuit */
return 0;
if (circuit->snmp_id != circ_idx) {
/* Match is not exact */
circ_idx = 0;
adj_idx = 0;
data_idx = 0;
}
/*
* Note: the simple loop below will work in all cases
*/
while (circuit != NULL) {
for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node,
tmp_adj)) {
if (tmp_adj->snmp_idx < adj_idx)
continue;
if (tmp_adj->snmp_idx == adj_idx
&& data_id == ISIS_SNMP_ADJ_DATA_NONE)
continue;
if (adj_idx != 0 && tmp_adj->snmp_idx > adj_idx)
data_idx = 0;
if (isis_snmp_adj_helper(tmp_adj, data_id, data_idx,
&data, &data_len)) {
adj = tmp_adj;
break;
}
}
if (adj != NULL)
break;
circuit = isis_snmp_circuit_next(circuit);
circ_idx = 0;
adj_idx = 0;
data_idx = 0;
}
if (adj == NULL)
return 0;
if (ret_adj != NULL)
*ret_adj = adj;
if (ret_data_idx != 0) {
if (data_id == ISIS_SNMP_ADJ_DATA_NONE)
/*
* Value does not matter but let us set
* it to zero for consistency
*/
*ret_data_idx = 0;
else
*ret_data_idx = data_idx + 1;
}
if (ret_data != 0)
*ret_data = data;
if (ret_data_len != 0)
*ret_data_len = data_len;
return 1;
}
static uint8_t *isis_snmp_find_sys_object(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
struct isis_area *area = NULL;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL)
return NULL;
if (!list_isempty(isis->area_list))
area = listgetdata(listhead(isis->area_list));
/* Check whether the instance identifier is valid */
if (smux_header_generic(v, name, length, exact, var_len, write_method)
== MATCH_FAILED)
return NULL;
switch (v->magic) {
case ISIS_SYS_VERSION:
return SNMP_INTEGER(ISIS_VERSION);
case ISIS_SYS_LEVELTYPE:
/*
* If we do not have areas use 1&2 otherwise use settings
* from the first area in the list
*/
if (area == NULL)
return SNMP_INTEGER(IS_LEVEL_1_AND_2);
return SNMP_INTEGER(area->is_type);
case ISIS_SYS_ID:
if (!isis->sysid_set) {
*var_len = ISIS_SYS_ID_LEN;
return isis_null_sysid;
}
*var_len = ISIS_SYS_ID_LEN;
return isis->sysid;
case ISIS_SYS_MAXPATHSPLITS:
return SNMP_INTEGER(ISIS_SNMP_MAX_PATH_SPLITS);
case ISIS_SYS_MAXLSPGENINT:
return SNMP_INTEGER(DEFAULT_MAX_LSP_GEN_INTERVAL);
case ISIS_SYS_POLLESHELLORATE:
return SNMP_INTEGER(DEFAULT_HELLO_INTERVAL);
case ISIS_SYS_WAITTIME:
/* Note: it seems that we have same fixed delay time */
return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL);
case ISIS_SYS_ADMINSTATE:
/* If daemon is running it admin state is on */
return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON);
case ISIS_SYS_L2TOL1LEAKING:
/* We do not allow l2-to-l1 leaking */
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
case ISIS_SYS_MAXAGE:
return SNMP_INTEGER(MAX_AGE);
case ISIS_SYS_RECEIVELSPBUFFERSIZE:
if (area == NULL)
return SNMP_INTEGER(DEFAULT_LSP_MTU);
return SNMP_INTEGER(area->lsp_mtu);
case ISIS_SYS_PROTSUPPORTED:
*var_len = 1;
return &isis_snmp_protocols_supported;
case ISIS_SYS_NOTIFICATIONENABLE:
if (isis->snmp_notifications)
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_man_area(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
int res;
struct area_addr *area_addr = NULL;
oid *oid_idx;
size_t oid_idx_len;
size_t off = 0;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_area_addr_lookup_exact(oid_idx, oid_idx_len,
NULL, &area_addr);
if (!res)
return NULL;
} else {
res = isis_snmp_area_addr_lookup_next(oid_idx, oid_idx_len,
NULL, &area_addr);
if (!res)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = area_addr->addr_len;
for (off = 0; off < area_addr->addr_len; off++)
name[v->namelen + 1 + off] = area_addr->area_addr[off];
*length = v->namelen + 1 + area_addr->addr_len;
}
switch (v->magic) {
case ISIS_MANAREA_ADDREXISTSTATE:
return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE);
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_area_addr(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
/*
* Area addresses in sense of addresses reported by L1 lsps
* are not supported yet.
*/
(void)v;
(void)name;
(void)length;
(void)exact;
(void)var_len;
*write_method = NULL;
return NULL;
}
static uint8_t *isis_snmp_find_summ_addr(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
/*
* So far there is no way to set summary table values through cli
* and snmp operations are read-only, hence there are no entries
*/
(void)v;
(void)name;
(void)length;
(void)exact;
(void)var_len;
*write_method = NULL;
return NULL;
}
static uint8_t *isis_snmp_find_redistribute_addr(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
/*
* It is not clear at the point whether redist code in isis is actually
* used for now we will consider that entries are not present
*/
(void)v;
(void)name;
(void)length;
(void)exact;
(void)var_len;
*write_method = NULL;
return NULL;
}
static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
uint8_t cmp_buf[ISIS_SYS_ID_LEN];
size_t cmp_len;
int try_exact;
int cmp_level;
int res;
struct isis_dynhn *dyn = NULL;
oid *oid_idx;
size_t oid_idx_len;
size_t off = 0;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL)
return NULL;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &cmp_len,
oid_idx, oid_idx_len);
if (!res || cmp_len != ISIS_SYS_ID_LEN
|| oid_idx_len != (cmp_len + 2))
/*
* Bad conversion, or bad length,
* or extra oids at the end
*/
return NULL;
if (oid_idx[ISIS_SYS_ID_LEN + 1] < IS_LEVEL_1
|| oid_idx[ISIS_SYS_ID_LEN + 1] > IS_LEVEL_2)
/* Level part of the index is out of range */
return NULL;
cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
dyn = dynhn_find_by_id(isis, cmp_buf);
if (dyn == NULL || dyn->level != cmp_level)
return NULL;
switch (v->magic) {
case ISIS_ROUTER_HOSTNAME:
*var_len = strlen(dyn->hostname);
return (uint8_t *)dyn->hostname;
case ISIS_ROUTER_ID:
/* It seems that we do no know router-id in lsps */
return SNMP_INTEGER(0);
default:
break;
}
return NULL;
}
res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &cmp_len,
&try_exact, oid_idx, oid_idx_len);
if (!res)
/* Bad conversion */
return NULL;
if (cmp_len != ISIS_SYS_ID_LEN) {
/* We do not have valid index oids */
memset(cmp_buf, 0, sizeof(cmp_buf));
cmp_level = 0;
} else if (try_exact)
/*
* We have no valid level index.
* Let start from non-existing level 0 and
* hence not need to do exact match
*/
cmp_level = 0;
else if (oid_idx_len < (ISIS_SYS_ID_LEN + 2))
cmp_level = 0;
else if (oid_idx[ISIS_SYS_ID_LEN + 1] <= IS_LEVEL_2)
cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
else
/*
* Any value greater than 2 will have the same result
* but we can have integer overflows, hence 3 is a reasonable
* choice
*/
cmp_level = (int)(IS_LEVEL_2 + 1);
dyn = dynhn_snmp_next(isis, cmp_buf, cmp_level);
if (dyn == NULL)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = ISIS_SYS_ID_LEN;
for (off = 0; off < ISIS_SYS_ID_LEN; off++)
name[v->namelen + 1 + off] = dyn->id[off];
name[v->namelen + 1 + ISIS_SYS_ID_LEN] = (oid)dyn->level;
/* Set length */
*length = v->namelen + 1 + ISIS_SYS_ID_LEN + 1;
switch (v->magic) {
case ISIS_ROUTER_HOSTNAME:
*var_len = strlen(dyn->hostname);
return (uint8_t *)dyn->hostname;
case ISIS_ROUTER_ID:
/* It seems that we do no know router-id in lsps */
return SNMP_INTEGER(0);
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_sys_level(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
oid *oid_idx;
size_t oid_idx_len;
int level;
int level_match;
struct isis_area *area = NULL;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL)
return NULL;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
if (oid_idx == NULL || oid_idx_len != 1)
return NULL;
if (oid_idx[0] == IS_LEVEL_1)
level = IS_LEVEL_1;
else if (oid_idx[0] == IS_LEVEL_2)
level = IS_LEVEL_2;
else
return NULL;
} else {
if (oid_idx == NULL)
level = IS_LEVEL_1;
else if (oid_idx_len == 0)
level = IS_LEVEL_1;
else if (oid_idx[0] < IS_LEVEL_1)
level = IS_LEVEL_1;
else if (oid_idx[0] < IS_LEVEL_2)
level = IS_LEVEL_2;
else
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = level;
/* Set length */
*length = v->namelen + 1;
}
area = NULL;
if (!list_isempty(isis->area_list))
area = listgetdata(listhead(isis->area_list));
level_match = 0;
if (area != NULL)
level_match = isis_snmp_get_level_match(area->is_type, level);
switch (v->magic) {
case ISIS_SYSLEVEL_ORIGLSPBUFFSIZE:
if (level_match)
return SNMP_INTEGER(area->lsp_mtu);
return SNMP_INTEGER(DEFAULT_LSP_MTU);
case ISIS_SYSLEVEL_MINLSPGENINT:
if (level_match)
return SNMP_INTEGER(area->lsp_gen_interval[level - 1]);
else
return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL);
case ISIS_SYSLEVEL_STATE:
if (level_match) {
if (area->overload_bit)
return SNMP_INTEGER(
ISIS_SNMP_LEVEL_STATE_OVERLOADED);
return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_ON);
}
return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_OFF);
case ISIS_SYSLEVEL_SETOVERLOAD:
if (level_match && area->overload_bit)
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
case ISIS_SYSLEVEL_SETOVERLOADUNTIL:
/* We do not have automatic cleanup of overload bit */
return SNMP_INTEGER(0);
case ISIS_SYSLEVEL_METRICSTYLE:
if (level_match) {
if (area->newmetric && area->oldmetric)
return SNMP_INTEGER(
ISIS_SNMP_METRIC_STYLE_BOTH);
if (area->newmetric)
return SNMP_INTEGER(
ISIS_SNMP_METRIC_STYLE_WIDE);
return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW);
}
return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW);
case ISIS_SYSLEVEL_SPFCONSIDERS:
return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_BOTH);
case ISIS_SYSLEVEL_TEENABLED:
if (level_match && IS_MPLS_TE(area->mta))
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_system_counter(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
oid *oid_idx;
size_t oid_idx_len;
int level;
int level_match;
struct isis_area *area = NULL;
uint32_t val;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL)
return NULL;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
if (oid_idx == NULL || oid_idx_len != 1)
return 0;
if (oid_idx[0] == IS_LEVEL_1)
level = IS_LEVEL_1;
else if (oid_idx[0] == IS_LEVEL_2)
level = IS_LEVEL_2;
else
return NULL;
} else {
if (oid_idx == NULL)
level = IS_LEVEL_1;
else if (oid_idx_len == 0)
level = IS_LEVEL_1;
else if (oid_idx[0] < IS_LEVEL_1)
level = IS_LEVEL_1;
else if (oid_idx[0] < IS_LEVEL_2)
level = IS_LEVEL_2;
else
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = level;
/* Set length */
*length = v->namelen + 1;
}
area = NULL;
if (!list_isempty(isis->area_list))
area = listgetdata(listhead(isis->area_list));
level_match = 0;
if (area != NULL)
level_match = isis_snmp_get_level_match(area->is_type, level);
if (!level_match)
/* If level does not match all counters are zeros */
return SNMP_INTEGER(0);
switch (v->magic) {
case ISIS_SYSSTAT_CORRLSPS:
val = 0;
break;
case ISIS_SYSSTAT_AUTHTYPEFAILS:
val = (uint32_t)area->auth_type_failures[level - 1];
break;
case ISIS_SYSSTAT_AUTHFAILS:
val = (uint32_t)area->auth_failures[level - 1];
break;
case ISIS_SYSSTAT_LSPDBASEOLOADS:
val = area->overload_counter;
break;
case ISIS_SYSSTAT_MANADDRDROPFROMAREAS:
/* We do not support manual addresses */
val = 0;
break;
case ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS:
val = area->lsp_exceeded_max_counter;
break;
case ISIS_SYSSTAT_SEQNUMSKIPS:
val = area->lsp_seqno_skipped_counter;
break;
case ISIS_SYSSTAT_OWNLSPPURGES:
if (!area->purge_originator)
val = 0;
else
val = area->lsp_purge_count[level - 1];
break;
case ISIS_SYSSTAT_IDFIELDLENMISMATCHES:
val = (uint32_t)area->id_len_mismatches[level - 1];
break;
case ISIS_SYSSTAT_PARTCHANGES:
/* Not supported */
val = 0;
break;
case ISIS_SYSSTAT_SPFRUNS:
val = (uint32_t)area->spf_run_count[level - 1];
break;
case ISIS_SYSSTAT_LSPERRORS:
val = (uint32_t)area->lsp_error_counter[level - 1];
break;
default:
return NULL;
}
return SNMP_INTEGER(val);
}
static uint8_t *isis_snmp_find_next_circ_index(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
/* Check whether the instance identifier is valid */
if (smux_header_generic(v, name, length, exact, var_len, write_method)
== MATCH_FAILED)
return NULL;
switch (v->magic) {
case ISIS_NEXTCIRC_INDEX:
/*
* We do not support circuit creation through snmp
*/
return SNMP_INTEGER(0);
default:
break;
}
return 0;
}
static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
size_t *length, int exact, size_t *var_len,
WriteMethod **write_method)
{
/* Index is circuit-id: 1-255 */
oid *oid_idx;
size_t oid_idx_len;
struct isis_circuit *circuit;
uint32_t up_ticks;
uint32_t delta_ticks;
uint32_t now_time;
int res;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len,
&circuit);
if (!res || oid_idx_len != 1)
return NULL;
} else {
res = isis_snmp_circuit_lookup_next(oid_idx, oid_idx_len,
&circuit);
if (!res)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = circuit->snmp_id;
/* Set length */
*length = v->namelen + 1;
}
switch (v->magic) {
case ISIS_CIRC_IFINDEX:
if (circuit->interface == 0)
return SNMP_INTEGER(0);
return SNMP_INTEGER(circuit->interface->ifindex);
case ISIS_CIRC_ADMINSTATE:
return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON);
case ISIS_CIRC_EXISTSTATE:
return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE);
case ISIS_CIRC_TYPE:
/*
* Note: values do not match 100%:
*
* 1. From isis_circuit.h:
* CIRCUIT_T_UNKNOWN 0
* CIRCUIT_T_BROADCAST 1
* CIRCUIT_T_P2P 2
* CIRCUIT_T_LOOPBACK 3
*
* 2. From rfc:
* broadcast(1),
* ptToPt(2),
* staticIn(3),
* staticOut(4),
*/
return SNMP_INTEGER(circuit->circ_type);
case ISIS_CIRC_EXTDOMAIN:
if (circuit->ext_domain)
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
case ISIS_CIRC_LEVELTYPE:
return SNMP_INTEGER(circuit->is_type);
case ISIS_CIRC_PASSIVECIRCUIT:
if (circuit->is_passive)
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
case ISIS_CIRC_MESHGROUPENABLED:
/* Not supported */
return SNMP_INTEGER(ISIS_SNMP_MESH_GROUP_INACTIVE);
case ISIS_CIRC_MESHGROUP:
/* Not supported */
return SNMP_INTEGER(0);
case ISIS_CIRC_SMALLHELLOS:
/*
* return false if lan hellos must be padded
*/
if (circuit->pad_hellos)
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
case ISIS_CIRC_LASTUPTIME:
if (circuit->last_uptime == 0)
return SNMP_INTEGER(0);
up_ticks = (uint32_t)netsnmp_get_agent_uptime();
now_time = isis_snmp_time();
if (circuit->last_uptime >= now_time)
return SNMP_INTEGER(up_ticks);
delta_ticks = (now_time - circuit->last_uptime) * 10;
if (up_ticks < delta_ticks)
return SNMP_INTEGER(up_ticks);
return SNMP_INTEGER(up_ticks - delta_ticks);
case ISIS_CIRC_3WAYENABLED:
/* Not supported */
return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
case ISIS_CIRC_EXTENDEDCIRCID:
/* Used for 3-way hand shake only */
return SNMP_INTEGER(0);
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_circ_level(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
static uint8_t circuit_id_val[ISIS_SYS_ID_LEN + 1];
/* Index is circuit-id: 1-255 + level: 1-2 */
oid *oid_idx;
size_t oid_idx_len;
int res;
struct isis_circuit *circuit;
int level;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL)
return NULL;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len,
1, &circuit, &level);
if (!res || oid_idx_len != 2)
return NULL;
} else {
res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len,
1, &circuit, &level);
if (!res)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = circuit->snmp_id;
name[v->namelen + 1] = level;
/* Set length */
*length = v->namelen + 2;
}
switch (v->magic) {
case ISIS_CIRCLEVEL_METRIC:
return SNMP_INTEGER(circuit->metric[level - 1]);
case ISIS_CIRCLEVEL_WIDEMETRIC:
if (circuit->area == NULL || !circuit->area->newmetric) {
/* What should we do if wide metric is not supported? */
return SNMP_INTEGER(0);
}
return SNMP_INTEGER(circuit->te_metric[level - 1]);
case ISIS_CIRCLEVEL_ISPRIORITY:
return SNMP_INTEGER(circuit->priority[level - 1]);
case ISIS_CIRCLEVEL_IDOCTET:
return SNMP_INTEGER(circuit->circuit_id);
case ISIS_CIRCLEVEL_ID:
if (circuit->circ_type != CIRCUIT_T_P2P) {
/*
* Unless it is point-to-point circuit, the value is and
* empty octet string
*/
*var_len = 0;
return circuit_id_val;
}
/* !!!!!! Circuit-id is zero for p2p links */
if (circuit->u.p2p.neighbor == NULL
|| circuit->u.p2p.neighbor->adj_state != ISIS_ADJ_UP) {
/* No adjacency or adjacency not fully up yet */
memcpy(circuit_id_val, isis->sysid, ISIS_SYS_ID_LEN);
circuit_id_val[ISIS_SYS_ID_LEN] = circuit->circuit_id;
*var_len = ISIS_SYS_ID_LEN + 1;
return circuit_id_val;
}
/* Adjacency fully-up */
memcpy(circuit_id_val, circuit->u.p2p.neighbor->sysid,
ISIS_SYS_ID_LEN);
circuit_id_val[ISIS_SYS_ID_LEN] = 0;
*var_len = ISIS_SYS_ID_LEN + 1;
return circuit_id_val;
case ISIS_CIRCLEVEL_DESIS:
if (circuit->circ_type != CIRCUIT_T_BROADCAST
|| !circuit->u.bc.is_dr[level - 1]) {
/*
* Unless it is lan circuit participating in dis process
* the value is an empty octet string
*/
*var_len = 0;
return circuit_id_val;
}
*var_len = ISIS_SYS_ID_LEN + 1;
if (level == IS_LEVEL_1)
return circuit->u.bc.l1_desig_is;
return circuit->u.bc.l2_desig_is;
case ISIS_CIRCLEVEL_HELLOMULTIPLIER:
return SNMP_INTEGER(circuit->hello_multiplier[level - 1]);
case ISIS_CIRCLEVEL_HELLOTIMER:
return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000);
case ISIS_CIRCLEVEL_DRHELLOTIMER:
return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000);
case ISIS_CIRCLEVEL_LSPTHROTTLE:
if (circuit->area)
return SNMP_INTEGER(
circuit->area->min_spf_interval[level - 1]
* 1000);
else
return SNMP_INTEGER(0);
case ISIS_CIRCLEVEL_MINLSPRETRANSINT:
if (circuit->area)
return SNMP_INTEGER(
circuit->area->min_spf_interval[level - 1]);
else
return SNMP_INTEGER(0);
case ISIS_CIRCLEVEL_CSNPINTERVAL:
return SNMP_INTEGER(circuit->csnp_interval[level - 1]);
case ISIS_CIRCLEVEL_PARTSNPINTERVAL:
return SNMP_INTEGER(circuit->psnp_interval[level - 1]);
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_circ_counter(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
/* Index circuit-id 1-255 + level */
oid *oid_idx;
size_t oid_idx_len;
int res;
struct isis_circuit *circuit;
int level;
uint32_t val = 0;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len,
1, &circuit, &level);
if (!res || oid_idx_len != 2)
return NULL;
} else {
res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len,
1, &circuit, &level);
if (!res)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = circuit->snmp_id;
if (circuit->circ_type == CIRCUIT_T_P2P)
name[v->namelen + 1] = ISIS_SNMP_P2P_CIRCUIT;
else
name[v->namelen + 1] = level;
/* Set length */
*length = v->namelen + 2;
}
switch (v->magic) {
case ISIS_CIRC_ADJCHANGES:
val = circuit->adj_state_changes;
break;
case ISIS_CIRC_NUMADJ:
if (circuit->circ_type == CIRCUIT_T_P2P) {
val = circuit->u.p2p.neighbor == NULL ? 0 : 1;
break;
}
if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
val = 0;
break;
}
if (level == IS_LEVEL_1) {
if (circuit->u.bc.adjdb[0] == NULL)
val = 0;
else
val = listcount(circuit->u.bc.adjdb[0]);
break;
}
if (circuit->u.bc.adjdb[1] == NULL)
val = 0;
else
val = listcount(circuit->u.bc.adjdb[1]);
break;
case ISIS_CIRC_INITFAILS:
val = circuit->init_failures; /* counter never incremented */
break;
case ISIS_CIRC_REJADJS:
val = circuit->rej_adjacencies;
break;
case ISIS_CIRC_IDFIELDLENMISMATCHES:
val = circuit->id_len_mismatches;
break;
case ISIS_CIRC_MAXAREAADDRMISMATCHES:
val = circuit->max_area_addr_mismatches;
break;
case ISIS_CIRC_AUTHTYPEFAILS:
val = circuit->auth_type_failures;
break;
case ISIS_CIRC_AUTHFAILS:
val = circuit->auth_failures;
break;
case ISIS_CIRC_LANDESISCHANGES:
if (circuit->circ_type == CIRCUIT_T_P2P)
val = 0;
else
val = circuit->desig_changes[level - 1];
break;
default:
return NULL;
}
return SNMP_INTEGER(val);
}
static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
size_t *length, int exact, size_t *var_len,
WriteMethod **write_method)
{
/* Index is circuit-id: 1-255 + adj-id: 1-... */
oid *oid_idx;
size_t oid_idx_len;
int res;
uint32_t val;
struct isis_adjacency *adj;
uint32_t up_ticks;
uint32_t delta_ticks;
uint32_t now_time;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
ISIS_SNMP_ADJ_DATA_NONE, &adj,
NULL, NULL, NULL);
if (!res || oid_idx_len != 2)
return NULL;
} else {
res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len,
ISIS_SNMP_ADJ_DATA_NONE, &adj,
NULL, NULL, NULL);
if (!res)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = adj->circuit->snmp_id;
name[v->namelen + 1] = adj->snmp_idx;
/* Set length */
*length = v->namelen + 2;
}
switch (v->magic) {
case ISIS_ISADJ_STATE:
return SNMP_INTEGER(isis_snmp_adj_state(adj->adj_state));
case ISIS_ISADJ_3WAYSTATE:
return SNMP_INTEGER(adj->threeway_state);
case ISIS_ISADJ_NEIGHSNPAADDRESS: {
const char *snpa = (char *)snpa_print(adj->snpa);
*var_len = strlen(snpa);
return (uint8_t *)snpa;
}
case ISIS_ISADJ_NEIGHSYSTYPE:
return SNMP_INTEGER(isis_snmp_adj_neightype(adj->sys_type));
case ISIS_ISADJ_NEIGHSYSID:
*var_len = sizeof(adj->sysid);
return adj->sysid;
case ISIS_ISADJ_NBREXTENDEDCIRCID:
return SNMP_INTEGER(adj->ext_circuit_id != 0 ? 1 : 0);
case ISIS_ISADJ_USAGE:
/* It seems that no value conversion is required */
return SNMP_INTEGER(adj->adj_usage);
case ISIS_ISADJ_HOLDTIMER:
/*
* It seems that we want remaining timer
*/
if (adj->last_upd != 0) {
val = isis_snmp_time();
if (val < (adj->last_upd + adj->hold_time))
return SNMP_INTEGER(adj->last_upd
+ adj->hold_time - val);
}
/* Not running or just expired */
return SNMP_INTEGER(0);
case ISIS_ISADJ_NEIGHPRIORITY:
return SNMP_INTEGER(adj->prio[adj->level - 1]);
case ISIS_ISADJ_LASTUPTIME:
if (adj->flaps == 0)
return SNMP_INTEGER(0);
up_ticks = (uint32_t)netsnmp_get_agent_uptime();
now_time = isis_snmp_time();
if (adj->last_flap >= now_time)
return SNMP_INTEGER(up_ticks);
delta_ticks = (now_time - adj->last_flap) * 10;
if (up_ticks < delta_ticks)
return SNMP_INTEGER(up_ticks);
return SNMP_INTEGER(up_ticks - delta_ticks);
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_isadj_area(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
/* Index circuit-id: 1-255 + adj-id: 1-... */
oid *oid_idx;
size_t oid_idx_len;
int res;
struct isis_adjacency *adj;
oid data_idx;
uint8_t *data;
size_t data_len;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
ISIS_SNMP_ADJ_DATA_AREA_ADDR,
&adj, NULL, &data, &data_len);
if (!res || oid_idx_len != 3)
return NULL;
} else {
res = isis_snmp_adj_lookup_next(
oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_AREA_ADDR,
&adj, &data_idx, &data, &data_len);
if (!res)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = adj->circuit->snmp_id;
name[v->namelen + 1] = adj->snmp_idx;
name[v->namelen + 2] = data_idx;
/* Set length */
*length = v->namelen + 3;
}
switch (v->magic) {
case ISIS_ISADJAREA_ADDRESS:
*var_len = data_len;
return data;
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
/* Index circuit-id 1-255 + adj-id 1-... */
oid *oid_idx;
size_t oid_idx_len;
int res;
struct isis_adjacency *adj;
oid data_idx;
uint8_t *data;
size_t data_len;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
ISIS_SNMP_ADJ_DATA_IP_ADDR,
&adj, NULL, &data, &data_len);
if (!res || oid_idx_len != 3)
return NULL;
} else {
res = isis_snmp_adj_lookup_next(
oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_IP_ADDR, &adj,
&data_idx, &data, &data_len);
if (!res)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = adj->circuit->snmp_id;
name[v->namelen + 1] = adj->snmp_idx;
name[v->namelen + 2] = data_idx;
/* Set length */
*length = v->namelen + 3;
}
switch (v->magic) {
case ISIS_ISADJIPADDR_TYPE:
if (data_len == 4)
return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V4);
return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V6);
case ISIS_ISADJIPADDR_ADDRESS:
*var_len = data_len;
return data;
default:
break;
}
return NULL;
}
static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *v, oid *name,
size_t *length, int exact,
size_t *var_len,
WriteMethod **write_method)
{
/* Index circuit-id 1-255 + adj-id 1-... */
oid *oid_idx;
size_t oid_idx_len;
int res;
struct isis_adjacency *adj;
oid data_idx;
uint8_t *data;
size_t data_len;
*write_method = NULL;
if (*length <= v->namelen) {
oid_idx = NULL;
oid_idx_len = 0;
} else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
oid_idx = NULL;
oid_idx_len = 0;
} else {
oid_idx = name + v->namelen;
oid_idx_len = *length - v->namelen;
}
if (exact) {
res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
ISIS_SNMP_ADJ_DATA_PROTO, &adj,
NULL, &data, &data_len);
if (!res || oid_idx_len != 3)
return NULL;
} else {
res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len,
ISIS_SNMP_ADJ_DATA_PROTO, &adj,
&data_idx, &data, &data_len);
if (!res)
return NULL;
/* Copy the name out */
memcpy(name, v->name, v->namelen * sizeof(oid));
/* Append index */
name[v->namelen] = adj->circuit->snmp_id;
name[v->namelen + 1] = adj->snmp_idx;
name[v->namelen + 2] = data_idx;
/* Set length */
*length = v->namelen + 3;
}
switch (v->magic) {
case ISIS_ISADJPROTSUPP_PROTOCOL:
return SNMP_INTEGER(*data);
default:
break;
}
return NULL;
}
/* Register ISIS-MIB. */
static int isis_snmp_init(struct thread_master *tm)
{
struct isis_func_to_prefix *h2f = isis_func_to_prefix_arr;
struct variable *v;
for (size_t off = 0; off < isis_var_count; off++) {
v = &isis_var_arr[off];
if (v->findVar != h2f->ihtp_func) {
/* Next table */
h2f++;
assert(h2f < (isis_func_to_prefix_arr
+ isis_func_to_prefix_count));
assert(v->findVar == h2f->ihtp_func);
}
v->namelen = h2f->ihtp_pref_len + 1;
memcpy(v->name, h2f->ihtp_pref_oid,
h2f->ihtp_pref_len * sizeof(oid));
v->name[h2f->ihtp_pref_len] = v->magic;
}
smux_init(tm);
REGISTER_MIB("mibII/isis", isis_var_arr, variable, isis_oid);
return 0;
}
/*
* ISIS notification functions: we have one function per notification
*/
static int isis_snmp_trap_throttle(oid trap_id)
{
time_t time_now;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
return 0;
time_now = isis_snmp_time();
if ((isis_snmp_trap_timestamp[trap_id] + 5) > time_now)
/* Throttle trap rate at 1 in 5 secs */
return 0;
isis_snmp_trap_timestamp[trap_id] = time_now;
return 1;
}
static int isis_snmp_db_overload_update(const struct isis_area *area)
{
netsnmp_variable_list *notification_vars;
long val;
uint32_t off;
if (!isis_snmp_trap_throttle(ISIS_TRAP_DB_OVERLOAD))
return 0;
notification_vars = NULL;
/* Put in trap value */
snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
(uint8_t *)&isis_snmp_trap_val_db_overload,
sizeof(isis_snmp_trap_val_db_overload));
/* Prepare data */
val = area->is_type;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_sys_level_index,
ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
(uint8_t *)&val, sizeof(val));
/* Patch sys_level_state with proper index */
off = ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state) - 1;
isis_snmp_trap_data_var_sys_level_state[off] = val;
/* Prepare data */
if (area->overload_bit)
val = ISIS_SNMP_LEVEL_STATE_OVERLOADED;
else
val = ISIS_SNMP_LEVEL_STATE_ON;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_sys_level_state,
ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state), INTEGER,
(uint8_t *)&val, sizeof(val));
send_v2trap(notification_vars);
snmp_free_varbind(notification_vars);
smux_events_update();
return 0;
}
static int isis_snmp_lsp_exceed_max_update(const struct isis_area *area,
const uint8_t *lsp_id)
{
netsnmp_variable_list *notification_vars;
long val;
if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_EXCEED_MAX))
return 0;
notification_vars = NULL;
/* Put in trap value */
snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
(uint8_t *)&isis_snmp_trap_val_lsp_exceed_max,
sizeof(isis_snmp_trap_val_lsp_exceed_max));
/* Prepare data */
val = area->is_type;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_sys_level_index,
ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
(uint8_t *)&val, sizeof(val));
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_pdu_lsp_id,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
ISIS_SYS_ID_LEN + 2);
send_v2trap(notification_vars);
snmp_free_varbind(notification_vars);
smux_events_update();
return 0;
}
/*
* A common function to handle popular combination of trap objects
* isisNotificationSysLevelIndex,
* optional-object-a
* isisNotificationCircIfIndex,
* optional-object-b
*/
static void isis_snmp_update_worker_a(const struct isis_circuit *circuit,
oid trap_id, const oid *oid_a,
size_t oid_a_len, uint8_t type_a,
const void *data_a, size_t data_a_len,
const oid *oid_b, size_t oid_b_len,
uint8_t type_b, const void *data_b,
size_t data_b_len)
{
netsnmp_variable_list *notification_vars = NULL;
oid var_name[MAX_OID_LEN];
size_t var_count;
long val;
/* Sanity */
if (trap_id != ISIS_TRAP_ID_LEN_MISMATCH
&& trap_id != ISIS_TRAP_MAX_AREA_ADDR_MISMATCH
&& trap_id != ISIS_TRAP_OWN_LSP_PURGE
&& trap_id != ISIS_TRAP_SEQNO_SKIPPED
&& trap_id != ISIS_TRAP_AUTHEN_TYPE_FAILURE
&& trap_id != ISIS_TRAP_AUTHEN_FAILURE
&& trap_id != ISIS_TRAP_REJ_ADJACENCY)
return;
/* Put in trap value */
memcpy(var_name, isis_snmp_notifications,
sizeof(isis_snmp_notifications));
var_count = ARRAY_SIZE(isis_snmp_notifications);
var_name[var_count++] = trap_id;
/* Put in trap value */
snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
(uint8_t *)var_name, var_count * sizeof(oid));
val = circuit->is_type;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_sys_level_index,
ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
(uint8_t *)&val, sizeof(val));
if (oid_a_len != 0) {
if (oid_a == NULL || data_a == NULL || data_a_len == 0)
return;
snmp_varlist_add_variable(&notification_vars, oid_a, oid_a_len,
type_a, (uint8_t *)data_a,
data_a_len);
}
if (circuit->interface == NULL)
val = 0;
else
val = circuit->interface->ifindex;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_circ_if_index,
ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
(uint8_t *)&val, sizeof(val));
if (oid_b_len != 0) {
if (oid_b == NULL || data_b == NULL || data_b_len == 0)
return;
snmp_varlist_add_variable(&notification_vars, oid_b, oid_b_len,
type_b, (uint8_t *)data_b,
data_b_len);
}
send_v2trap(notification_vars);
snmp_free_varbind(notification_vars);
smux_events_update();
}
/*
* A common function to handle popular combination of trap objects
* isisNotificationSysLevelIndex,
* isisNotificationCircIfIndex,
* optional-var-a
* optional-var-b
*
* Note: the only difference with worker_a is order of circ-if-index vs
* optional-var-a
*/
static void isis_snmp_update_worker_b(const struct isis_circuit *circuit,
oid trap_id, const oid *oid_a,
size_t oid_a_len, uint8_t type_a,
const void *data_a, size_t data_a_len,
const oid *oid_b, size_t oid_b_len,
uint8_t type_b, const void *data_b,
size_t data_b_len)
{
netsnmp_variable_list *notification_vars = NULL;
oid var_name[MAX_OID_LEN];
size_t var_count;
long val;
/* Sanity */
if (trap_id != ISIS_TRAP_VERSION_SKEW
&& trap_id != ISIS_TRAP_LSP_TOO_LARGE
&& trap_id != ISIS_TRAP_ADJ_STATE_CHANGE)
return;
/* Put in trap value */
memcpy(var_name, isis_snmp_notifications,
sizeof(isis_snmp_notifications));
var_count = ARRAY_SIZE(isis_snmp_notifications);
var_name[var_count++] = trap_id;
/* Put in trap value */
snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
(uint8_t *)var_name, var_count * sizeof(oid));
val = circuit->is_type;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_sys_level_index,
ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
(uint8_t *)&val, sizeof(val));
if (circuit->interface == NULL)
val = 0;
else
val = circuit->interface->ifindex;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_circ_if_index,
ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
(uint8_t *)&val, sizeof(val));
if (oid_a_len != 0) {
if (oid_a == NULL || data_a == NULL || data_a_len == 0)
return;
snmp_varlist_add_variable(&notification_vars, oid_a, oid_a_len,
type_a, (uint8_t *)data_a,
data_a_len);
}
if (oid_b_len != 0) {
if (oid_b == NULL || data_b == NULL || data_b_len == 0)
return;
snmp_varlist_add_variable(&notification_vars, oid_b, oid_b_len,
type_b, (uint8_t *)data_b,
data_b_len);
}
send_v2trap(notification_vars);
snmp_free_varbind(notification_vars);
smux_events_update();
}
static int isis_snmp_id_len_mismatch_update(const struct isis_circuit *circuit,
uint8_t rcv_id, const char *raw_pdu,
size_t raw_pdu_len)
{
long val;
if (!isis_snmp_trap_throttle(ISIS_TRAP_ID_LEN_MISMATCH))
return 0;
val = rcv_id;
if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
isis_snmp_update_worker_a(
circuit, ISIS_TRAP_ID_LEN_MISMATCH,
isis_snmp_trap_data_var_pdu_field_len,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_field_len), UNSIGNED32,
&val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
raw_pdu, raw_pdu_len);
return 0;
}
static int
isis_snmp_max_area_addr_mismatch_update(const struct isis_circuit *circuit,
uint8_t max_addrs, const char *raw_pdu,
size_t raw_pdu_len)
{
long val;
if (!isis_snmp_trap_throttle(ISIS_TRAP_MAX_AREA_ADDR_MISMATCH))
return 0;
val = max_addrs;
if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
isis_snmp_update_worker_a(
circuit, ISIS_TRAP_MAX_AREA_ADDR_MISMATCH,
isis_snmp_trap_data_var_pdu_max_area_addr,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_max_area_addr),
UNSIGNED32, &val, sizeof(val),
isis_snmp_trap_data_var_pdu_fragment,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
raw_pdu, raw_pdu_len);
return 0;
}
static int isis_snmp_own_lsp_purge_update(const struct isis_circuit *circuit,
const uint8_t *lsp_id)
{
if (!isis_snmp_trap_throttle(ISIS_TRAP_OWN_LSP_PURGE))
return 0;
isis_snmp_update_worker_a(
circuit, ISIS_TRAP_OWN_LSP_PURGE, NULL, 0, STRING, NULL, 0,
isis_snmp_trap_data_var_pdu_lsp_id,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
ISIS_SYS_ID_LEN + 2);
return 0;
}
static int isis_snmp_seqno_skipped_update(const struct isis_circuit *circuit,
const uint8_t *lsp_id)
{
if (!isis_snmp_trap_throttle(ISIS_TRAP_SEQNO_SKIPPED))
return 0;
isis_snmp_update_worker_a(
circuit, ISIS_TRAP_SEQNO_SKIPPED, NULL, 0, STRING, NULL, 0,
isis_snmp_trap_data_var_pdu_lsp_id,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
ISIS_SYS_ID_LEN + 2);
return 0;
}
static int
isis_snmp_authentication_type_failure_update(const struct isis_circuit *circuit,
const char *raw_pdu,
size_t raw_pdu_len)
{
if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_TYPE_FAILURE))
return 0;
if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
isis_snmp_update_worker_a(
circuit, ISIS_TRAP_AUTHEN_TYPE_FAILURE, NULL, 0, STRING, NULL,
0, isis_snmp_trap_data_var_pdu_fragment,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
raw_pdu, raw_pdu_len);
return 0;
}
static int
isis_snmp_authentication_failure_update(const struct isis_circuit *circuit,
char const *raw_pdu, size_t raw_pdu_len)
{
if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_FAILURE))
return 0;
if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
isis_snmp_update_worker_a(
circuit, ISIS_TRAP_AUTHEN_FAILURE, NULL, 0, STRING, NULL, 0,
isis_snmp_trap_data_var_pdu_fragment,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
raw_pdu, raw_pdu_len);
return 0;
}
static int isis_snmp_version_skew_update(const struct isis_circuit *circuit,
uint8_t version, const char *raw_pdu,
size_t raw_pdu_len)
{
long val;
if (!isis_snmp_trap_throttle(ISIS_TRAP_VERSION_SKEW))
return 0;
val = version;
if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
isis_snmp_update_worker_b(
circuit, ISIS_TRAP_VERSION_SKEW,
isis_snmp_trap_data_var_pdu_proto_ver,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_proto_ver), UNSIGNED32,
&val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
raw_pdu, raw_pdu_len);
return 0;
}
static int isis_snmp_area_mismatch_update(const struct isis_circuit *circuit,
const char *raw_pdu,
size_t raw_pdu_len)
{
/*
* This is a special case because
* it does not include isisNotificationSysLevelIndex
*/
netsnmp_variable_list *notification_vars;
long val;
if (!isis_snmp_trap_throttle(ISIS_TRAP_AREA_MISMATCH))
return 0;
notification_vars = NULL;
/* Put in trap value */
snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
(uint8_t *)&isis_snmp_trap_val_area_mismatch,
sizeof(isis_snmp_trap_val_area_mismatch));
if (circuit->interface == NULL)
val = 0;
else
val = circuit->interface->ifindex;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_circ_if_index,
ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
(uint8_t *)&val, sizeof(val));
if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_pdu_fragment,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
raw_pdu, raw_pdu_len);
send_v2trap(notification_vars);
snmp_free_varbind(notification_vars);
smux_events_update();
return 0;
}
static int isis_snmp_reject_adjacency_update(const struct isis_circuit *circuit,
const char *raw_pdu,
size_t raw_pdu_len)
{
if (!isis_snmp_trap_throttle(ISIS_TRAP_REJ_ADJACENCY))
return 0;
if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
isis_snmp_update_worker_a(
circuit, ISIS_TRAP_REJ_ADJACENCY, NULL, 0, STRING, NULL, 0,
isis_snmp_trap_data_var_pdu_fragment,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
raw_pdu, raw_pdu_len);
return 0;
}
static int isis_snmp_lsp_too_large_update(const struct isis_circuit *circuit,
uint32_t pdu_size,
const uint8_t *lsp_id)
{
if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_TOO_LARGE))
return 0;
isis_snmp_update_worker_b(
circuit, ISIS_TRAP_LSP_TOO_LARGE,
isis_snmp_trap_data_var_pdu_lsp_size,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_size), UNSIGNED32,
&pdu_size, sizeof(pdu_size), isis_snmp_trap_data_var_pdu_lsp_id,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
ISIS_SYS_ID_LEN + 2);
return 0;
}
static int isis_snmp_adj_state_change_update(const struct isis_adjacency *adj)
{
uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
long val;
struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
return 0;
/* Prepare data */
memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
lsp_id[ISIS_SYS_ID_LEN] = 0;
lsp_id[ISIS_SYS_ID_LEN + 1] = 0;
val = isis_snmp_adj_state(adj->adj_state);
isis_snmp_update_worker_b(
adj->circuit, ISIS_TRAP_ADJ_STATE_CHANGE,
isis_snmp_trap_data_var_pdu_lsp_id,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
ISIS_SYS_ID_LEN + 2, isis_snmp_trap_data_var_adj_state,
ARRAY_SIZE(isis_snmp_trap_data_var_adj_state), INTEGER, &val,
sizeof(val));
return 0;
}
static int isis_snmp_lsp_error_update(const struct isis_circuit *circuit,
const uint8_t *lsp_id,
char const *raw_pdu, size_t raw_pdu_len)
{
/*
* This is a special case because
* it have more variables
*/
netsnmp_variable_list *notification_vars;
long val;
if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_ERROR))
return 0;
notification_vars = NULL;
/* Put in trap value */
snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
(uint8_t *)&isis_snmp_trap_val_lsp_error,
sizeof(isis_snmp_trap_val_lsp_error));
/* Prepare data */
val = circuit->is_type;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_sys_level_index,
ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
(uint8_t *)&val, sizeof(val));
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_pdu_lsp_id,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
ISIS_SYS_ID_LEN + 2);
/* Prepare data */
if (circuit->interface == NULL)
val = 0;
else
val = circuit->interface->ifindex;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_circ_if_index,
ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
(uint8_t *)&val, sizeof(val));
/* Prepare data */
if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_pdu_fragment,
ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
raw_pdu, raw_pdu_len);
/* Prepare data */
val = 0;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_error_offset,
ARRAY_SIZE(isis_snmp_trap_data_var_error_offset), UNSIGNED32,
(uint8_t *)&val, sizeof(val));
/* Prepare data */
val = 0;
snmp_varlist_add_variable(
&notification_vars, isis_snmp_trap_data_var_error_tlv_type,
ARRAY_SIZE(isis_snmp_trap_data_var_error_tlv_type), UNSIGNED32,
(uint8_t *)&val, sizeof(val));
send_v2trap(notification_vars);
snmp_free_varbind(notification_vars);
smux_events_update();
return 0;
}
static int isis_snmp_module_init(void)
{
hook_register(isis_hook_db_overload, isis_snmp_db_overload_update);
hook_register(isis_hook_lsp_exceed_max,
isis_snmp_lsp_exceed_max_update);
hook_register(isis_hook_id_len_mismatch,
isis_snmp_id_len_mismatch_update);
hook_register(isis_hook_max_area_addr_mismatch,
isis_snmp_max_area_addr_mismatch_update);
hook_register(isis_hook_own_lsp_purge, isis_snmp_own_lsp_purge_update);
hook_register(isis_hook_seqno_skipped, isis_snmp_seqno_skipped_update);
hook_register(isis_hook_authentication_type_failure,
isis_snmp_authentication_type_failure_update);
hook_register(isis_hook_authentication_failure,
isis_snmp_authentication_failure_update);
hook_register(isis_hook_version_skew, isis_snmp_version_skew_update);
hook_register(isis_hook_area_mismatch, isis_snmp_area_mismatch_update);
hook_register(isis_hook_reject_adjacency,
isis_snmp_reject_adjacency_update);
hook_register(isis_hook_lsp_too_large, isis_snmp_lsp_too_large_update);
hook_register(isis_hook_adj_state_change,
isis_snmp_adj_state_change_update);
hook_register(isis_hook_lsp_error, isis_snmp_lsp_error_update);
hook_register(isis_circuit_new_hook, isis_circuit_snmp_id_gen);
hook_register(isis_circuit_del_hook, isis_circuit_snmp_id_free);
hook_register(frr_late_init, isis_snmp_init);
return 0;
}
FRR_MODULE_SETUP(
.name = "isis_snmp",
.version = FRR_VERSION,
.description = "isis AgentX SNMP module",
.init = isis_snmp_module_init,
);