// SPDX-License-Identifier: GPL-2.0-or-later /* * ISIS SNMP support * Copyright (C) 2020 Volta Networks, Inc. * Aleksey Romanov */ /* * This is minimal read-only implementations providing isisReadOnlyCompliance */ #include #include #include #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 "lib/zclient.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 /* * 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 */ /* 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 iso_address **ret_addr) { uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX]; size_t addr_len; struct isis_area *area = NULL; struct iso_address *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 iso_address **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 iso_address *found_addr = NULL; struct iso_address *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->ll_ipv6_count)) return 0; if (data_off >= adj->ipv4_address_count) { data = (uint8_t *)&adj->ll_ipv6_addrs [data_off - adj->ipv4_address_count]; data_len = sizeof(adj->ll_ipv6_addrs[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 iso_address *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; time_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 == NULL) 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 == ISIS_HELLO_PADDING_ALWAYS || (circuit->pad_hellos == ISIS_HELLO_PADDING_DURING_ADJACENCY_FORMATION && circuit->upadjcount[0] + circuit->upadjcount[1] == 0)) 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 = time(NULL); 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; time_t val; struct isis_adjacency *adj; uint32_t up_ticks; uint32_t delta_ticks; time_t now_time; /* Ring buffer to print SNPA */ #define FORMAT_BUF_COUNT 4 static char snpa[FORMAT_BUF_COUNT][ISO_SYSID_STRLEN]; static size_t cur_buf = 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_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: { cur_buf = (cur_buf + 1) % FORMAT_BUF_COUNT; snprintfrr(snpa[cur_buf], ISO_SYSID_STRLEN, "%pSY", adj->snpa); *var_len = strlen(snpa[cur_buf]); return (uint8_t *)snpa[cur_buf]; } 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 = time(NULL); 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 = time(NULL); 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 event_loop *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 = time(NULL); 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(¬ification_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( ¬ification_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( ¬ification_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(¬ification_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( ¬ification_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( ¬ification_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(¬ification_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( ¬ification_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(¬ification_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( ¬ification_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(¬ification_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(¬ification_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( ¬ification_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( ¬ification_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(¬ification_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(¬ification_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(¬ification_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( ¬ification_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( ¬ification_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(¬ification_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( ¬ification_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( ¬ification_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( ¬ification_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( ¬ification_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( ¬ification_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( ¬ification_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, );