]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_snmp.c
Merge pull request #8531 from mjstapp/fix_backups_misc
[mirror_frr.git] / isisd / isis_snmp.c
CommitLineData
1ee746d9 1/*
2 * ISIS SNMP support
3 * Copyright (C) 2020 Volta Networks, Inc.
4 * Aleksey Romanov
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21/*
22 * This is minimal read-only implementations providing isisReadOnlyCompliance
23 */
24
25#include <zebra.h>
26
27#include <net-snmp/net-snmp-config.h>
28#include <net-snmp/net-snmp-includes.h>
29
30#include "vrf.h"
31#include "if.h"
32#include "log.h"
33#include "prefix.h"
34#include "table.h"
35#include "command.h"
36#include "memory.h"
37#include "smux.h"
38#include "libfrr.h"
09781197 39#include "lib/version.h"
1ee746d9 40
41#include "isisd/isis_constants.h"
42#include "isisd/isis_common.h"
43#include "isisd/isis_flags.h"
44#include "isisd/isis_circuit.h"
45#include "isisd/isis_lsp.h"
46#include "isisd/isis_pdu.h"
47#include "isisd/isis_network.h"
48#include "isisd/isis_misc.h"
49#include "isisd/isis_constants.h"
50#include "isisd/isis_adjacency.h"
51#include "isisd/isis_dynhn.h"
52#include "isisd/isis_te.h"
53#include "isisd/isis_dr.h"
54#include "isisd/isis_nb.h"
55#include "isisd/isisd.h"
56
57/* ISIS-MIB. */
58#define ISIS_MIB 1, 3, 6, 1, 2, 1, 138
59
60#define ISIS_OBJECTS 1
61#define ISIS_SYSTEM 1, 1
62#define ISIS_SYSLEVEL 1, 2
63#define ISIS_CIRC 1, 3
64#define ISIS_CIRC_LEVEL_VALUES 1, 4
65#define ISIS_COUNTERS 1, 5
66#define ISIS_ISADJ 1, 6
67
68/************************ isisSystemGroup ************************/
69
70/* isisSysObject */
71#define ISIS_SYS_OBJECT 1, 1, 1
72#define ISIS_SYS_VERSION 1
73#define ISIS_SYS_LEVELTYPE 2
74#define ISIS_SYS_ID 3
75#define ISIS_SYS_MAXPATHSPLITS 4
76#define ISIS_SYS_MAXLSPGENINT 5
77#define ISIS_SYS_POLLESHELLORATE 6
78#define ISIS_SYS_WAITTIME 7
79#define ISIS_SYS_ADMINSTATE 8
80#define ISIS_SYS_L2TOL1LEAKING 9
81#define ISIS_SYS_MAXAGE 10
82#define ISIS_SYS_RECEIVELSPBUFFERSIZE 11
83#define ISIS_SYS_PROTSUPPORTED 12
84#define ISIS_SYS_NOTIFICATIONENABLE 13
85
86/* isisManAreaAddrEntry */
87#define ISIS_MANAREA_ADDRENTRY 1, 1, 2, 1
88#define ISIS_MANAREA_ADDREXISTSTATE 2
89
90/* isisAreaAddrEntry */
91#define ISIS_AREA_ADDRENTRY 1, 1, 3, 1
92#define ISIS_AREA_ADDR 1
93
94/* isisSummAddrEntry */
95#define ISIS_SUMM_ADDRENTRY 1, 1, 4, 1
96#define ISIS_SUMM_ADDREXISTSTATE 4
97#define ISIS_SUMM_ADDRMETRIC 5
98#define ISIS_SUMM_ADDRFULLMETRIC 6
99
100/* isisRedistributeAddrEntry */
101#define ISIS_REDISTRIBUTE_ADDRENTRY 1, 1, 5, 1
102#define ISIS_REDISTRIBUTE_ADDREXISTSTATE 3
103
104/* isisRouterEntry */
105#define ISIS_ROUTER_ENTRY 1, 1, 6, 1
106#define ISIS_ROUTER_HOSTNAME 3
107#define ISIS_ROUTER_ID 4
108
109/* isisSysLevelTable */
110#define ISIS_SYSLEVEL_ENTRY 1, 2, 1, 1
111#define ISIS_SYSLEVEL_ORIGLSPBUFFSIZE 2
112#define ISIS_SYSLEVEL_MINLSPGENINT 3
113#define ISIS_SYSLEVEL_STATE 4
114#define ISIS_SYSLEVEL_SETOVERLOAD 5
115#define ISIS_SYSLEVEL_SETOVERLOADUNTIL 6
116#define ISIS_SYSLEVEL_METRICSTYLE 7
117#define ISIS_SYSLEVEL_SPFCONSIDERS 8
118#define ISIS_SYSLEVEL_TEENABLED 9
119
120
121/* isisSystemCounterEntry */
122#define ISIS_SYSTEM_COUNTER_ENTRY 1, 5, 1, 1
123#define ISIS_SYSSTAT_CORRLSPS 2
124#define ISIS_SYSSTAT_AUTHTYPEFAILS 3
125#define ISIS_SYSSTAT_AUTHFAILS 4
126#define ISIS_SYSSTAT_LSPDBASEOLOADS 5
127#define ISIS_SYSSTAT_MANADDRDROPFROMAREAS 6
128#define ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS 7
129#define ISIS_SYSSTAT_SEQNUMSKIPS 8
130#define ISIS_SYSSTAT_OWNLSPPURGES 9
131#define ISIS_SYSSTAT_IDFIELDLENMISMATCHES 10
132#define ISIS_SYSSTAT_PARTCHANGES 11
133#define ISIS_SYSSTAT_SPFRUNS 12
134#define ISIS_SYSSTAT_LSPERRORS 13
135
136
137/************************ isisCircuitGroup ************************/
138
139/* Scalar directly under isisCirc */
140#define ISIS_NEXTCIRC_INDEX 1
141
142/* isisCircEntry */
143#define ISIS_CIRC_ENTRY 1, 3, 2, 1
144#define ISIS_CIRC_IFINDEX 2
145#define ISIS_CIRC_ADMINSTATE 3
146#define ISIS_CIRC_EXISTSTATE 4
147#define ISIS_CIRC_TYPE 5
148#define ISIS_CIRC_EXTDOMAIN 6
149#define ISIS_CIRC_LEVELTYPE 7
150#define ISIS_CIRC_PASSIVECIRCUIT 8
151#define ISIS_CIRC_MESHGROUPENABLED 9
152#define ISIS_CIRC_MESHGROUP 10
153#define ISIS_CIRC_SMALLHELLOS 11
154#define ISIS_CIRC_LASTUPTIME 12
155#define ISIS_CIRC_3WAYENABLED 13
156#define ISIS_CIRC_EXTENDEDCIRCID 14
157
158/* isisCircLevelEntry */
159#define ISIS_CIRCLEVEL_ENTRY 1, 4, 1, 1
160#define ISIS_CIRCLEVEL_METRIC 2
161#define ISIS_CIRCLEVEL_WIDEMETRIC 3
162#define ISIS_CIRCLEVEL_ISPRIORITY 4
163#define ISIS_CIRCLEVEL_IDOCTET 5
164#define ISIS_CIRCLEVEL_ID 6
165#define ISIS_CIRCLEVEL_DESIS 7
166#define ISIS_CIRCLEVEL_HELLOMULTIPLIER 8
167#define ISIS_CIRCLEVEL_HELLOTIMER 9
168#define ISIS_CIRCLEVEL_DRHELLOTIMER 10
169#define ISIS_CIRCLEVEL_LSPTHROTTLE 11
170#define ISIS_CIRCLEVEL_MINLSPRETRANSINT 12
171#define ISIS_CIRCLEVEL_CSNPINTERVAL 13
172#define ISIS_CIRCLEVEL_PARTSNPINTERVAL 14
173
174/* isisCircuitCounterEntry */
175#define ISIS_CIRC_COUNTER_ENTRY 1, 5, 2, 1
176#define ISIS_CIRC_ADJCHANGES 2
177#define ISIS_CIRC_NUMADJ 3
178#define ISIS_CIRC_INITFAILS 4
179#define ISIS_CIRC_REJADJS 5
180#define ISIS_CIRC_IDFIELDLENMISMATCHES 6
181#define ISIS_CIRC_MAXAREAADDRMISMATCHES 7
182#define ISIS_CIRC_AUTHTYPEFAILS 8
183#define ISIS_CIRC_AUTHFAILS 9
184#define ISIS_CIRC_LANDESISCHANGES 10
185
186
187/************************ isisISAdjGroup ************************/
188
189/* isisISAdjEntry */
190#define ISIS_ISADJ_ENTRY 1, 6, 1, 1
191#define ISIS_ISADJ_STATE 2
192#define ISIS_ISADJ_3WAYSTATE 3
193#define ISIS_ISADJ_NEIGHSNPAADDRESS 4
194#define ISIS_ISADJ_NEIGHSYSTYPE 5
195#define ISIS_ISADJ_NEIGHSYSID 6
196#define ISIS_ISADJ_NBREXTENDEDCIRCID 7
197#define ISIS_ISADJ_USAGE 8
198#define ISIS_ISADJ_HOLDTIMER 9
199#define ISIS_ISADJ_NEIGHPRIORITY 10
200#define ISIS_ISADJ_LASTUPTIME 11
201
202/* isisISAdjAreadAddrEntry */
203#define ISIS_ISADJAREA_ADDRENTRY 1, 6, 2, 1
204#define ISIS_ISADJAREA_ADDRESS 2
205
206/* isisISAdjIPAddrEntry*/
207#define ISIS_ISADJIPADDR_ENTRY 1, 6, 3, 1
208#define ISIS_ISADJIPADDR_TYPE 2
209#define ISIS_ISADJIPADDR_ADDRESS 3
210
211
212/* isisISAdjProtSuppEntty */
213
214#define ISIS_ISADJPROTSUPP_ENTRY 1, 6, 4, 1
215#define ISIS_ISADJPROTSUPP_PROTOCOL 1
216
217
218/************************ Trap data variables ************************/
219#define ISIS_NOTIFICATION_ENTRY 1, 10, 1
220#define ISIS_NOTIF_SYLELVELINDEX 1
221#define ISIS_NOTIF_CIRCIFINDEX 2
222#define ISIS_PDU_LSPID 3
223#define ISIS_PDU_FRAGMENT 4
224#define ISIS_PDU_FIELDLEN 5
225#define ISIS_PDU_MAXAREAADDR 6
226#define ISIS_PDU_PROTOVER 7
227#define ISIS_PDU_LSPSIZE 8
228#define ISIS_PDU_ORIGBUFFERSIZE 9
229#define ISIS_PDU_BUFFERSIZE 10
230#define ISIS_PDU_PROTSUPP 11
231#define ISIS_ADJ_STATE 12
232#define ISIS_ERROR_OFFSET 13
233#define ISIS_ERROR_TLVTYPE 14
234#define ISIS_NOTIF_AREAADDR 15
235
236/************************ Traps ************************/
237#define ISIS_NOTIFICATIONS ISIS_MIB, 0
238#define ISIS_TRAP_DB_OVERLOAD 1
239#define ISIS_TRAP_MAN_ADDR_DROP 2
240#define ISIS_TRAP_CORRUPTED_LSP 3
241#define ISIS_TRAP_LSP_EXCEED_MAX 4
242#define ISIS_TRAP_ID_LEN_MISMATCH 5
243#define ISIS_TRAP_MAX_AREA_ADDR_MISMATCH 6
244#define ISIS_TRAP_OWN_LSP_PURGE 7
245#define ISIS_TRAP_SEQNO_SKIPPED 8
246#define ISIS_TRAP_AUTHEN_TYPE_FAILURE 9
247#define ISIS_TRAP_AUTHEN_FAILURE 10
248#define ISIS_TRAP_VERSION_SKEW 11
249#define ISIS_TRAP_AREA_MISMATCH 12
250#define ISIS_TRAP_REJ_ADJACENCY 13
251#define ISIS_TRAP_LSP_TOO_LARGE 14
252#define ISIS_TRAP_LSP_BUFFSIZE_MISMATCH 15
253#define ISIS_TRAP_PROTSUPP_MISMATCH 16
254#define ISIS_TRAP_ADJ_STATE_CHANGE 17
255#define ISIS_TRAP_LSP_ERROR 18
256
257/* Change this definition if number of traps changes */
e91a589b 258#define ISIS_TRAP_LAST_TRAP ISIS_TRAP_LSP_ERROR + 1
1ee746d9 259
260#define ISIS_SNMP_TRAP_VAR 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0
261
262
263/* SNMP value hack. */
264#define COUNTER32 ASN_COUNTER
265#define INTEGER ASN_INTEGER
266#define UNSIGNED32 ASN_GAUGE
267#define TIMESTAMP ASN_TIMETICKS
268#define TIMETICKS ASN_TIMETICKS
269#define STRING ASN_OCTET_STR
270
271/* Declare static local variables for convenience. */
272SNMP_LOCAL_VARIABLES
273
274/* If ARRAY_SIZE is not available use a primitive substitution */
275#ifndef ARRAY_SIZE
276#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
277#endif
278
279/*
280 * Define time function, it serves two purposes
281 * 1. Uses unint32_t for unix time and encapsulates
282 * sing extension issues in conversion from time_t
283 *
284 * 2. I could be replaced in unit test environment
285 */
286#ifndef ISIS_SNMP_HAVE_TIME_FUNC
287static uint32_t isis_snmp_time(void)
288{
289 return (uint32_t)time(NULL);
290}
291
292#endif
293
294/* ISIS-MIB instances. */
295static oid isis_oid[] = {ISIS_MIB};
296
297/* SNMP trap variable */
298static oid isis_snmp_trap_var[] = {ISIS_SNMP_TRAP_VAR};
299
300/* SNMP trap values (others are calculated on the fly */
301static oid isis_snmp_notifications[] = {ISIS_NOTIFICATIONS};
302static oid isis_snmp_trap_val_db_overload[] = {ISIS_NOTIFICATIONS,
303 ISIS_TRAP_DB_OVERLOAD};
304static oid isis_snmp_trap_val_lsp_exceed_max[] = {ISIS_NOTIFICATIONS,
305 ISIS_TRAP_LSP_EXCEED_MAX};
306static oid isis_snmp_trap_val_area_mismatch[] = {ISIS_NOTIFICATIONS,
307 ISIS_TRAP_AREA_MISMATCH};
308static oid isis_snmp_trap_val_lsp_error[] = {ISIS_NOTIFICATIONS,
309 ISIS_TRAP_LSP_ERROR};
310
311/*
312 * Trap vars under 'isisNotifications': note: we use full names of variables
313 * scalar index
314 */
315static oid isis_snmp_trap_data_var_sys_level_index[] = {
316 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_NOTIF_SYLELVELINDEX, 0};
317static oid isis_snmp_trap_data_var_circ_if_index[] = {
318 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_NOTIF_CIRCIFINDEX, 0};
319static oid isis_snmp_trap_data_var_pdu_lsp_id[] = {
320 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_LSPID, 0};
321static oid isis_snmp_trap_data_var_pdu_fragment[] = {
322 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_FRAGMENT, 0};
323static oid isis_snmp_trap_data_var_pdu_field_len[] = {
324 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_FIELDLEN, 0};
325static oid isis_snmp_trap_data_var_pdu_max_area_addr[] = {
326 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_MAXAREAADDR, 0};
327static oid isis_snmp_trap_data_var_pdu_proto_ver[] = {
328 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_PROTOVER, 0};
329static oid isis_snmp_trap_data_var_pdu_lsp_size[] = {
330 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_PDU_LSPSIZE, 0};
331static oid isis_snmp_trap_data_var_adj_state[] = {
332 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ADJ_STATE, 0};
333static oid isis_snmp_trap_data_var_error_offset[] = {
334 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ERROR_OFFSET, 0};
335static oid isis_snmp_trap_data_var_error_tlv_type[] = {
336 ISIS_MIB, ISIS_NOTIFICATION_ENTRY, ISIS_ERROR_TLVTYPE, 0};
337
338/*
339 * Other variables used by traps: note we use full names of variables and
340 * reserve space for index
341 */
342static oid isis_snmp_trap_data_var_sys_level_state[] = {
343 ISIS_MIB, ISIS_SYSLEVEL_ENTRY, ISIS_SYSLEVEL_STATE, 0};
344
345/* Throttle time values for traps */
346static time_t isis_snmp_trap_timestamp[ISIS_TRAP_LAST_TRAP]; /* ?? 1 */
347
348/* Max len of raw-pdu in traps */
349#define ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN (64)
350
351/*
352 * Just to save on typing we have a shortcut structure
353 * to specify mib layout as prefix/leaf combination
354 */
355#define ISIS_SNMP_PREF_LEN_MAX 10
356struct isis_var_prefix {
357 FindVarMethod *findVar;
358 uint8_t ivd_pref_len;
359 oid ivd_pref[ISIS_SNMP_PREF_LEN_MAX];
360};
361
362
363/* Find-val functions */
364static uint8_t *isis_snmp_find_sys_object(struct variable *, oid *, size_t *,
365 int, size_t *, WriteMethod **);
366
367static uint8_t *isis_snmp_find_man_area(struct variable *, oid *, size_t *, int,
368 size_t *, WriteMethod **);
369
370static uint8_t *isis_snmp_find_area_addr(struct variable *, oid *, size_t *,
371 int, size_t *, WriteMethod **);
372
373static uint8_t *isis_snmp_find_summ_addr(struct variable *, oid *, size_t *,
374 int, size_t *, WriteMethod **);
375
376static uint8_t *isis_snmp_find_redistribute_addr(struct variable *, oid *,
377 size_t *, int, size_t *,
378 WriteMethod **);
379
380static uint8_t *isis_snmp_find_router(struct variable *, oid *, size_t *, int,
381 size_t *, WriteMethod **);
382
383static uint8_t *isis_snmp_find_sys_level(struct variable *, oid *, size_t *,
384 int, size_t *, WriteMethod **);
385
386static uint8_t *isis_snmp_find_system_counter(struct variable *, oid *,
387 size_t *, int, size_t *,
388 WriteMethod **);
389
390static uint8_t *isis_snmp_find_next_circ_index(struct variable *, oid *,
391 size_t *, int, size_t *,
392 WriteMethod **);
393
394static uint8_t *isis_snmp_find_circ(struct variable *, oid *, size_t *, int,
395 size_t *, WriteMethod **);
396
397static uint8_t *isis_snmp_find_circ_level(struct variable *, oid *, size_t *,
398 int, size_t *, WriteMethod **);
399
400static uint8_t *isis_snmp_find_circ_counter(struct variable *, oid *, size_t *,
401 int, size_t *, WriteMethod **);
402
403static uint8_t *isis_snmp_find_isadj(struct variable *, oid *, size_t *, int,
404 size_t *, WriteMethod **);
405
406static uint8_t *isis_snmp_find_isadj_area(struct variable *, oid *, size_t *,
407 int, size_t *, WriteMethod **);
408
409static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *, oid *, size_t *,
410 int, size_t *, WriteMethod **);
411
412static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *, oid *,
413 size_t *, int, size_t *,
414 WriteMethod **);
415
416/*
417 * Just to save on typing we have a shortcut structure
418 * to specify mib layout, we populate the rest of the data
419 * during initialization
420 */
421#define ISIS_PREF_LEN_MAX (6)
422
423struct isis_func_to_prefix {
424 FindVarMethod *ihtp_func;
425 oid ihtp_pref_oid[ISIS_PREF_LEN_MAX];
426 uint8_t ihtp_pref_len;
427};
428
429static struct isis_func_to_prefix isis_func_to_prefix_arr[] = {
430 {isis_snmp_find_sys_object, {ISIS_SYS_OBJECT}, 3},
431 {isis_snmp_find_man_area, {ISIS_MANAREA_ADDRENTRY}, 4},
432 {isis_snmp_find_area_addr, {ISIS_AREA_ADDRENTRY}, 4},
433 {isis_snmp_find_summ_addr, {ISIS_SUMM_ADDRENTRY}, 4},
434 {isis_snmp_find_redistribute_addr, {ISIS_REDISTRIBUTE_ADDRENTRY}, 4},
435 {isis_snmp_find_router, {ISIS_ROUTER_ENTRY}, 4},
436 {isis_snmp_find_sys_level, {ISIS_SYSLEVEL_ENTRY}, 4},
437 {isis_snmp_find_system_counter, {ISIS_SYSTEM_COUNTER_ENTRY}, 4},
438 {isis_snmp_find_next_circ_index, {ISIS_CIRC}, 2},
439 {isis_snmp_find_circ, {ISIS_CIRC_ENTRY}, 4},
440 {isis_snmp_find_circ_level, {ISIS_CIRCLEVEL_ENTRY}, 4},
441 {isis_snmp_find_circ_counter, {ISIS_CIRC_COUNTER_ENTRY}, 4},
442 {isis_snmp_find_isadj, {ISIS_ISADJ_ENTRY}, 4},
443 {isis_snmp_find_isadj_area, {ISIS_ISADJAREA_ADDRENTRY}, 4},
444 {isis_snmp_find_isadj_ipaddr, {ISIS_ISADJIPADDR_ENTRY}, 4},
445 {isis_snmp_find_isadj_prot_supp, {ISIS_ISADJPROTSUPP_ENTRY}, 4},
446};
447static size_t isis_func_to_prefix_count = ARRAY_SIZE(isis_func_to_prefix_arr);
448
449static struct variable isis_var_arr[] = {
450 {ISIS_SYS_VERSION, INTEGER, RONLY, isis_snmp_find_sys_object},
451 {ISIS_SYS_LEVELTYPE, INTEGER, RONLY, isis_snmp_find_sys_object},
452 {ISIS_SYS_ID, STRING, RONLY, isis_snmp_find_sys_object},
453 {ISIS_SYS_MAXPATHSPLITS, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
454 {ISIS_SYS_MAXLSPGENINT, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
455 {ISIS_SYS_POLLESHELLORATE, UNSIGNED32, RONLY,
456 isis_snmp_find_sys_object},
457 {ISIS_SYS_WAITTIME, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
458 {ISIS_SYS_ADMINSTATE, INTEGER, RONLY, isis_snmp_find_sys_object},
459 {ISIS_SYS_L2TOL1LEAKING, INTEGER, RONLY, isis_snmp_find_sys_object},
460 {ISIS_SYS_MAXAGE, UNSIGNED32, RONLY, isis_snmp_find_sys_object},
461 {ISIS_SYS_RECEIVELSPBUFFERSIZE, UNSIGNED32, RONLY,
462 isis_snmp_find_sys_object},
463 {ISIS_SYS_PROTSUPPORTED, STRING, RONLY, isis_snmp_find_sys_object},
464 {ISIS_SYS_NOTIFICATIONENABLE, INTEGER, RONLY,
465 isis_snmp_find_sys_object},
466 {ISIS_MANAREA_ADDREXISTSTATE, INTEGER, RONLY, isis_snmp_find_man_area},
467 {ISIS_AREA_ADDR, STRING, RONLY, isis_snmp_find_area_addr},
468 {ISIS_SUMM_ADDREXISTSTATE, INTEGER, RONLY, isis_snmp_find_summ_addr},
469 {ISIS_SUMM_ADDRMETRIC, UNSIGNED32, RONLY, isis_snmp_find_summ_addr},
470 {ISIS_SUMM_ADDRFULLMETRIC, UNSIGNED32, RONLY, isis_snmp_find_summ_addr},
471 {ISIS_REDISTRIBUTE_ADDREXISTSTATE, INTEGER, RONLY,
472 isis_snmp_find_redistribute_addr},
473 {ISIS_ROUTER_HOSTNAME, STRING, RONLY, isis_snmp_find_router},
474 {ISIS_ROUTER_ID, UNSIGNED32, RONLY, isis_snmp_find_router},
475 {ISIS_SYSLEVEL_ORIGLSPBUFFSIZE, UNSIGNED32, RONLY,
476 isis_snmp_find_sys_level},
477 {ISIS_SYSLEVEL_MINLSPGENINT, UNSIGNED32, RONLY,
478 isis_snmp_find_sys_level},
479 {ISIS_SYSLEVEL_STATE, INTEGER, RONLY, isis_snmp_find_sys_level},
480 {ISIS_SYSLEVEL_SETOVERLOAD, INTEGER, RONLY, isis_snmp_find_sys_level},
481 {ISIS_SYSLEVEL_SETOVERLOADUNTIL, UNSIGNED32, RONLY,
482 isis_snmp_find_sys_level},
483 {ISIS_SYSLEVEL_METRICSTYLE, INTEGER, RONLY, isis_snmp_find_sys_level},
484 {ISIS_SYSLEVEL_SPFCONSIDERS, INTEGER, RONLY, isis_snmp_find_sys_level},
485 {ISIS_SYSLEVEL_TEENABLED, INTEGER, RONLY, isis_snmp_find_sys_level},
486 {ISIS_SYSSTAT_CORRLSPS, COUNTER32, RONLY,
487 isis_snmp_find_system_counter},
488 {ISIS_SYSSTAT_AUTHTYPEFAILS, COUNTER32, RONLY,
489 isis_snmp_find_system_counter},
490 {ISIS_SYSSTAT_AUTHFAILS, COUNTER32, RONLY,
491 isis_snmp_find_system_counter},
492 {ISIS_SYSSTAT_LSPDBASEOLOADS, COUNTER32, RONLY,
493 isis_snmp_find_system_counter},
494 {ISIS_SYSSTAT_MANADDRDROPFROMAREAS, COUNTER32, RONLY,
495 isis_snmp_find_system_counter},
496 {ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS, COUNTER32, RONLY,
497 isis_snmp_find_system_counter},
498 {ISIS_SYSSTAT_SEQNUMSKIPS, COUNTER32, RONLY,
499 isis_snmp_find_system_counter},
500 {ISIS_SYSSTAT_OWNLSPPURGES, COUNTER32, RONLY,
501 isis_snmp_find_system_counter},
502 {ISIS_SYSSTAT_IDFIELDLENMISMATCHES, COUNTER32, RONLY,
503 isis_snmp_find_system_counter},
504 {ISIS_SYSSTAT_PARTCHANGES, COUNTER32, RONLY,
505 isis_snmp_find_system_counter},
506 {ISIS_SYSSTAT_SPFRUNS, COUNTER32, RONLY, isis_snmp_find_system_counter},
507 {ISIS_SYSSTAT_LSPERRORS, COUNTER32, RONLY,
508 isis_snmp_find_system_counter},
509 {ISIS_NEXTCIRC_INDEX, UNSIGNED32, RONLY,
510 isis_snmp_find_next_circ_index},
511 {ISIS_CIRC_IFINDEX, INTEGER, RONLY, isis_snmp_find_circ},
512 {ISIS_CIRC_ADMINSTATE, INTEGER, RONLY, isis_snmp_find_circ},
513 {ISIS_CIRC_EXISTSTATE, INTEGER, RONLY, isis_snmp_find_circ},
514 {ISIS_CIRC_TYPE, INTEGER, RONLY, isis_snmp_find_circ},
515 {ISIS_CIRC_EXTDOMAIN, INTEGER, RONLY, isis_snmp_find_circ},
516 {ISIS_CIRC_LEVELTYPE, INTEGER, RONLY, isis_snmp_find_circ},
517 {ISIS_CIRC_PASSIVECIRCUIT, INTEGER, RONLY, isis_snmp_find_circ},
518 {ISIS_CIRC_MESHGROUPENABLED, INTEGER, RONLY, isis_snmp_find_circ},
519 {ISIS_CIRC_MESHGROUP, UNSIGNED32, RONLY, isis_snmp_find_circ},
520 {ISIS_CIRC_SMALLHELLOS, INTEGER, RONLY, isis_snmp_find_circ},
521 {ISIS_CIRC_LASTUPTIME, TIMESTAMP, RONLY, isis_snmp_find_circ},
522 {ISIS_CIRC_3WAYENABLED, INTEGER, RONLY, isis_snmp_find_circ},
523 {ISIS_CIRC_EXTENDEDCIRCID, UNSIGNED32, RONLY, isis_snmp_find_circ},
524 {ISIS_CIRCLEVEL_METRIC, UNSIGNED32, RONLY, isis_snmp_find_circ_level},
525 {ISIS_CIRCLEVEL_WIDEMETRIC, UNSIGNED32, RONLY,
526 isis_snmp_find_circ_level},
527 {ISIS_CIRCLEVEL_ISPRIORITY, UNSIGNED32, RONLY,
528 isis_snmp_find_circ_level},
529 {ISIS_CIRCLEVEL_IDOCTET, UNSIGNED32, RONLY, isis_snmp_find_circ_level},
530 {ISIS_CIRCLEVEL_ID, STRING, RONLY, isis_snmp_find_circ_level},
531 {ISIS_CIRCLEVEL_DESIS, STRING, RONLY, isis_snmp_find_circ_level},
532 {ISIS_CIRCLEVEL_HELLOMULTIPLIER, UNSIGNED32, RONLY,
533 isis_snmp_find_circ_level},
534 {ISIS_CIRCLEVEL_HELLOTIMER, UNSIGNED32, RONLY,
535 isis_snmp_find_circ_level},
536 {ISIS_CIRCLEVEL_DRHELLOTIMER, UNSIGNED32, RONLY,
537 isis_snmp_find_circ_level},
538 {ISIS_CIRCLEVEL_LSPTHROTTLE, UNSIGNED32, RONLY,
539 isis_snmp_find_circ_level},
540 {ISIS_CIRCLEVEL_MINLSPRETRANSINT, UNSIGNED32, RONLY,
541 isis_snmp_find_circ_level},
542 {ISIS_CIRCLEVEL_CSNPINTERVAL, UNSIGNED32, RONLY,
543 isis_snmp_find_circ_level},
544 {ISIS_CIRCLEVEL_PARTSNPINTERVAL, UNSIGNED32, RONLY,
545 isis_snmp_find_circ_level},
546 {ISIS_CIRC_ADJCHANGES, COUNTER32, RONLY, isis_snmp_find_circ_counter},
547 {ISIS_CIRC_NUMADJ, UNSIGNED32, RONLY, isis_snmp_find_circ_counter},
548 {ISIS_CIRC_INITFAILS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
549 {ISIS_CIRC_REJADJS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
550 {ISIS_CIRC_IDFIELDLENMISMATCHES, COUNTER32, RONLY,
551 isis_snmp_find_circ_counter},
552 {ISIS_CIRC_MAXAREAADDRMISMATCHES, COUNTER32, RONLY,
553 isis_snmp_find_circ_counter},
554 {ISIS_CIRC_AUTHTYPEFAILS, COUNTER32, RONLY,
555 isis_snmp_find_circ_counter},
556 {ISIS_CIRC_AUTHFAILS, COUNTER32, RONLY, isis_snmp_find_circ_counter},
557 {ISIS_CIRC_LANDESISCHANGES, COUNTER32, RONLY,
558 isis_snmp_find_circ_counter},
559 {ISIS_ISADJ_STATE, INTEGER, RONLY, isis_snmp_find_isadj},
560 {ISIS_ISADJ_3WAYSTATE, INTEGER, RONLY, isis_snmp_find_isadj},
561 {ISIS_ISADJ_NEIGHSNPAADDRESS, STRING, RONLY, isis_snmp_find_isadj},
562 {ISIS_ISADJ_NEIGHSYSTYPE, INTEGER, RONLY, isis_snmp_find_isadj},
563 {ISIS_ISADJ_NEIGHSYSID, STRING, RONLY, isis_snmp_find_isadj},
564 {ISIS_ISADJ_NBREXTENDEDCIRCID, UNSIGNED32, RONLY, isis_snmp_find_isadj},
565 {ISIS_ISADJ_USAGE, INTEGER, RONLY, isis_snmp_find_isadj},
566 {ISIS_ISADJ_HOLDTIMER, UNSIGNED32, RONLY, isis_snmp_find_isadj},
567 {ISIS_ISADJ_NEIGHPRIORITY, UNSIGNED32, RONLY, isis_snmp_find_isadj},
568 {ISIS_ISADJ_LASTUPTIME, TIMESTAMP, RONLY, isis_snmp_find_isadj},
569 {ISIS_ISADJAREA_ADDRESS, STRING, RONLY, isis_snmp_find_isadj_area},
570 {ISIS_ISADJIPADDR_TYPE, INTEGER, RONLY, isis_snmp_find_isadj_ipaddr},
571 {ISIS_ISADJIPADDR_ADDRESS, STRING, RONLY, isis_snmp_find_isadj_ipaddr},
572 {ISIS_ISADJPROTSUPP_PROTOCOL, INTEGER, RONLY,
573 isis_snmp_find_isadj_prot_supp},
574};
575
576static const size_t isis_var_count = ARRAY_SIZE(isis_var_arr);
577
578/* Minimal set of hard-coded data */
579#define ISIS_VERSION (1)
580
581/* If sys-id is not set use this value */
582static uint8_t isis_null_sysid[ISIS_SYS_ID_LEN];
583
584/* OSI addr-len */
585#define ISIS_SNMP_OSI_ADDR_LEN_MAX (20)
586
587/*
588 * The implementation has a fixed max-path splits value
589 * of 64 (see ISIS_MAX_PATH_SPLITS), the max mib value
590 * is 32.
591 *
592 * FIXME(aromanov): should we return 32 or 64?
593 */
594#define ISIS_SNMP_MAX_PATH_SPLITS (32)
595
596#define ISIS_SNMP_ADMIN_STATE_ON (1)
597
598#define ISIS_SNMP_ROW_STATUS_ACTIVE (1)
599
600#define ISIS_SNMP_LEVEL_STATE_OFF (1)
601#define ISIS_SNMP_LEVEL_STATE_ON (2)
602#define ISIS_SNMP_LEVEL_STATE_WAITING (3)
603#define ISIS_SNMP_LEVEL_STATE_OVERLOADED (4)
604
605#define ISIS_SNMP_TRUTH_VALUE_TRUE (1)
606#define ISIS_SNMP_TRUTH_VALUE_FALSE (2)
607
608#define ISIS_SNMP_METRIC_STYLE_NARROW (1)
609#define ISIS_SNMP_METRIC_STYLE_WIDE (2)
610#define ISIS_SNMP_METRIC_STYLE_BOTH (3)
611
612#define ISIS_SNMP_MESH_GROUP_INACTIVE (1)
613
614#define ISIS_SNMP_ADJ_STATE_DOWN (1)
615#define ISIS_SNMP_ADJ_STATE_INITIALIZING (2)
616#define ISIS_SNMP_ADJ_STATE_UP (3)
617#define ISIS_SNMP_ADJ_STATE_FAILED (4)
618
619#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1 (1)
620#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2 (2)
621#define ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2 (3)
622#define ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN (4)
623
624#define ISIS_SNMP_INET_TYPE_V4 (1)
625#define ISIS_SNMP_INET_TYPE_V6 (2)
626
627#define ISIS_SNMP_P2P_CIRCUIT (3)
628
629/* Protocols supported value */
630static uint8_t isis_snmp_protocols_supported = 0x7; /* All: iso, ipv4, ipv6 */
631
632/*
633 * Convenience function to move to the next circuit,
634 */
635static struct isis_circuit *isis_snmp_circuit_next(struct isis_circuit *circuit)
636{
637 uint32_t start;
638 uint32_t off;
639 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
640
641 if (isis == NULL)
642 return NULL;
643
644 start = 1;
645
646 if (circuit != NULL)
647 start = circuit->snmp_id + 1;
648
649 for (off = start; off < SNMP_CIRCUITS_MAX; off++) {
650 circuit = isis->snmp_circuits[off];
651
652 if (circuit != NULL)
653 return circuit;
654 }
655
656 return NULL;
657}
658
659/*
660 * Convenience function to get the first matching level
661 */
662static int isis_snmp_circuit_get_level_lo(struct isis_circuit *circuit)
663{
664 if (circuit->is_type == IS_LEVEL_2)
665 return IS_LEVEL_2;
666
667 return IS_LEVEL_1;
668}
669
670/* Check level match */
671static int isis_snmp_get_level_match(int is_type, int level)
672{
673 if (is_type != IS_LEVEL_1 && is_type != IS_LEVEL_2
674 && is_type != IS_LEVEL_1_AND_2)
675 return 0;
676
677 if (level != IS_LEVEL_1 && level != IS_LEVEL_2)
678 return 0;
679
680
681 if (is_type == IS_LEVEL_1) {
682 if (level == IS_LEVEL_1)
683 return 1;
684
685 return 0;
686 }
687
688 if (is_type == IS_LEVEL_2) {
689 if (level == IS_LEVEL_2)
690 return 1;
691
692 return 0;
693 }
694
695 return 1;
696}
697/*
698 * Helper function to convert oid index representing
699 * octet-string index (e.g. isis-sys-id) to byte string
700 * representing the same index.
701 *
702 * Also we do not fail if idx is longer than max_len,
703 * so we can use the same function to check compound
704 * indexes.
705 */
706static int isis_snmp_conv_exact(uint8_t *buf, size_t max_len, size_t *out_len,
707 const oid *idx, size_t idx_len)
708{
709 size_t off;
710 size_t len;
711
712 /* Oid representation: length followed by bytes */
713 if (idx == NULL || idx_len == 0)
714 return 0;
715
716 len = idx[0];
717
718 if (len > max_len)
719 return 0;
720
721 if (idx_len < len + 1)
722 return 0;
723
724 for (off = 0; off < len; off++) {
725 if (idx[off + 1] > 0xff)
726 return 0;
727
728 buf[off] = (uint8_t)(idx[off + 1] & 0xff);
729 }
730
731 *out_len = len;
732
733 return 1;
734}
735
736static int isis_snmp_conv_next(uint8_t *buf, size_t max_len, size_t *out_len,
737 int *try_exact, const oid *idx, size_t idx_len)
738{
739 size_t off;
740 size_t len;
741 size_t cmp_len;
742
743 if (idx == NULL || idx_len == 0) {
744 *out_len = 0;
745 *try_exact = 1;
746 return 1;
747 }
748
749 len = idx[0];
750
751 if (len > max_len)
752 return 0;
753
754 cmp_len = len;
755
756 if ((idx_len - 1) < cmp_len)
757 cmp_len = idx_len - 1;
758
759 for (off = 0; off < cmp_len; off++) {
760 if (idx[off + 1] > 0xff) {
761 memset(buf + off, 0xff, len - off);
762 *out_len = len;
763 *try_exact = 1;
764 return 1;
765 }
766
767 buf[off] = (uint8_t)(idx[off + 1] & 0xff);
768 }
769
770 if (cmp_len < len)
771 memset(buf + cmp_len, 0, len - cmp_len);
772
773 *out_len = len;
774 *try_exact = cmp_len < len ? 1 : 0;
775 return 1;
776}
777
778/*
779 * Helper functions to find area address from snmp index
780 */
781static int isis_snmp_area_addr_lookup_exact(oid *oid_idx, size_t oid_idx_len,
782 struct isis_area **ret_area,
783 struct area_addr **ret_addr)
784{
785 uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX];
786 size_t addr_len;
787 struct isis_area *area = NULL;
788 struct area_addr *addr = NULL;
789 struct listnode *addr_node;
790 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
791
792 if (isis == NULL)
793 return 0;
794
795 if (list_isempty(isis->area_list)) {
796 /* Area is not configured yet */
797 return 0;
798 }
799
800 area = listgetdata(listhead(isis->area_list));
801
802 int res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &addr_len,
803 oid_idx, oid_idx_len);
804
805
806 if (!res || addr_len == 0 || oid_idx_len != (addr_len + 1)) {
807 /* Bad conversion, empty address or extra oids at the end */
808 return 0;
809 }
810
811 for (ALL_LIST_ELEMENTS_RO(area->area_addrs, addr_node, addr)) {
812 if (addr->addr_len != addr_len)
813 continue;
814
815 if (memcmp(addr->area_addr, cmp_buf, addr_len) == 0) {
816 if (ret_area != 0)
817 *ret_area = area;
818
819 if (ret_addr != 0)
820 *ret_addr = addr;
821
822 return 1;
823 }
824 }
825 return 0;
826}
827
828static int isis_snmp_area_addr_lookup_next(oid *oid_idx, size_t oid_idx_len,
829 struct isis_area **ret_area,
830 struct area_addr **ret_addr)
831{
832 uint8_t cmp_buf[ISIS_SNMP_OSI_ADDR_LEN_MAX];
833 size_t addr_len;
834 int try_exact = 0;
835 struct isis_area *found_area = NULL;
836 struct isis_area *area = NULL;
837 struct area_addr *found_addr = NULL;
838 struct area_addr *addr = NULL;
839 struct listnode *addr_node;
840 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
841
842 if (isis == NULL)
843 return 0;
844
845 if (list_isempty(isis->area_list)) {
846 /* Area is not configured yet */
847 return 0;
848 }
849
850 area = listgetdata(listhead(isis->area_list));
851
852 int res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &addr_len,
853 &try_exact, oid_idx, oid_idx_len);
854
855 if (!res)
856 return 0;
857
858 for (ALL_LIST_ELEMENTS_RO(area->area_addrs, addr_node, addr)) {
859 if (addr->addr_len < addr_len)
860 continue;
861
862 if (addr->addr_len == addr_len) {
863 if (addr_len == 0)
864 continue;
865
866 res = memcmp(addr->area_addr, cmp_buf, addr_len);
867
868 if (res < 0)
869 continue;
870
871 if (res == 0 && addr->addr_len == addr_len) {
872 if (try_exact) {
873 /*
874 * This is the best match no point
875 * to look further
876 */
877 found_area = area;
878 found_addr = addr;
879 break;
880 }
881 continue;
882 }
883 }
884
885 if (found_addr == NULL || addr->addr_len < found_addr->addr_len
886 || (addr->addr_len == found_addr->addr_len
887 && memcmp(addr->area_addr, found_addr->area_addr,
888 addr->addr_len)
889 < 0)) {
890 found_area = area;
891 found_addr = addr;
892 }
893 }
894
895 if (found_area == NULL)
896 return 0;
897
898 if (ret_area != 0)
899 *ret_area = found_area;
900
901 if (ret_addr != 0)
902 *ret_addr = found_addr;
903
904 return 1;
905}
906
907/*
908 * Helper functions to find circuit from
909 * snmp index
910 */
911static int isis_snmp_circuit_lookup_exact(oid *oid_idx, size_t oid_idx_len,
912 struct isis_circuit **ret_circuit)
913{
914 struct isis_circuit *circuit;
915 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
916
917 if (isis == NULL)
918 return 0;
919
920 if (oid_idx == NULL || oid_idx_len < 1
921 || oid_idx[0] > SNMP_CIRCUITS_MAX)
922 return 0;
923
924 circuit = isis->snmp_circuits[oid_idx[0]];
925 if (circuit == NULL)
926 return 0;
927
928 if (ret_circuit != NULL)
929 *ret_circuit = circuit;
930
931 return 1;
932}
933
934static int isis_snmp_circuit_lookup_next(oid *oid_idx, size_t oid_idx_len,
935 struct isis_circuit **ret_circuit)
936{
937 oid off;
938 oid start;
939 struct isis_circuit *circuit;
940 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
941
942 if (isis == NULL)
943 return 0;
944
945 start = 0;
946
e91a589b 947 if (oid_idx != NULL && oid_idx_len != 0) {
1ee746d9 948 if (oid_idx[0] > SNMP_CIRCUITS_MAX)
949 return 0;
950
951 start = oid_idx[0];
952 }
953
954 for (off = start; off < SNMP_CIRCUITS_MAX; ++off) {
955 circuit = isis->snmp_circuits[off];
956
957 if (circuit != NULL && off > start) {
958 if (ret_circuit != NULL)
959 *ret_circuit = circuit;
960
961 return 1;
962 }
963 }
964
965 return 0;
966}
967
968/*
969 * Helper functions to find circuit level
970 * combination from snmp index
971 */
972static int isis_snmp_circuit_level_lookup_exact(
973 oid *oid_idx, size_t oid_idx_len, int check_match,
974 struct isis_circuit **ret_circuit, int *ret_level)
975{
976 int level;
977 int res;
978 struct isis_circuit *circuit;
979
980 /* Minor optimization: check level first */
981 if (oid_idx == NULL || oid_idx_len < 2)
982 return 0;
983
984 if (oid_idx[1] < IS_LEVEL_1 || oid_idx[1] > IS_LEVEL_2)
985 return 0;
986
987 level = (int)oid_idx[1];
988
989 res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit);
990
991 if (!res)
992 return 0;
993
994 if (check_match && !isis_snmp_get_level_match(circuit->is_type, level))
995 return 0;
996
997 if (ret_circuit != NULL)
998 *ret_circuit = circuit;
999
1000 if (ret_level != NULL)
1001 *ret_level = level;
1002
1003 return 1;
1004}
1005
1006static int isis_snmp_circuit_level_lookup_next(
1007 oid *oid_idx, size_t oid_idx_len, int check_match,
1008 struct isis_circuit **ret_circuit, int *ret_level)
1009{
1010 oid off;
1011 oid start;
1012 struct isis_circuit *circuit;
1013 int level;
1014 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
1015
1016 if (isis == NULL)
1017 return 0;
1018
1019 start = 0;
1020
e91a589b 1021 if (oid_idx != NULL && oid_idx_len != 0) {
1ee746d9 1022 if (oid_idx[0] > SNMP_CIRCUITS_MAX)
1023 return 0;
1024
1025 start = oid_idx[0];
1026 }
1027
1028 for (off = start; off < SNMP_CIRCUITS_MAX; off++) {
1029 circuit = isis->snmp_circuits[off];
1030
1031 if (circuit == NULL)
1032 continue;
1033
1034 if (off > start || oid_idx_len < 2) {
1035 /* Found and can use level 1 */
1036 level = IS_LEVEL_1;
1037 break;
1038 }
1039
c33cb9fb
MS
1040 assert(oid_idx != NULL);
1041
1ee746d9 1042 /* We have to check level specified by index */
1043 if (oid_idx[1] < IS_LEVEL_1) {
1044 level = IS_LEVEL_1;
1045 break;
1046 }
1047
1048 if (oid_idx[1] < IS_LEVEL_2) {
1049 level = IS_LEVEL_2;
1050 break;
1051 }
1052
1053 /* Try next */
1054 circuit = NULL;
1055 }
1056
1057 if (circuit == NULL)
1058 return 0;
1059
1060 if (check_match
1061 && !isis_snmp_get_level_match(circuit->is_type, level)) {
1062 if (level == IS_LEVEL_1) {
1063 /*
1064 * We can simply advance level because
1065 * at least one level should match
1066 */
1067 level = IS_LEVEL_2;
1068 } else {
1069 /* We have to move to the next circuit */
1070 circuit = isis_snmp_circuit_next(circuit);
1071 if (circuit == NULL)
1072 return 0;
1073
1074 level = isis_snmp_circuit_get_level_lo(circuit);
1075 }
1076 }
1077
1078 if (ret_circuit != NULL)
1079 *ret_circuit = circuit;
1080
1081 if (ret_level != NULL)
1082 *ret_level = level;
1083
1084 return 1;
1085}
1086
1087/*
1088 * Helper functions to find adjacency
1089 * from snmp index.
1090 *
1091 * We have 4 tables related to adjacency
1092 * looking up adjacency is quite expensive
1093 * in case of bcast interfaces.
1094 *
1095 * It is pain to have 4 very similar functions
1096 * hence we pass in and out additional data
1097 * we are looking for.
1098 *
1099 * Note: we use data-len value to distinguish
1100 * between ipv4 and ipv6 addresses
1101 */
1102#define ISIS_SNMP_ADJ_DATA_NONE (1)
1103#define ISIS_SNMP_ADJ_DATA_AREA_ADDR (2)
1104#define ISIS_SNMP_ADJ_DATA_IP_ADDR (3)
1105#define ISIS_SNMP_ADJ_DATA_PROTO (4)
1106
1107/*
1108 * Helper function to process data associated
1109 * with adjacency
1110 */
1111static int isis_snmp_adj_helper(struct isis_adjacency *adj, int data_id,
1112 oid data_off, uint8_t **ret_data,
1113 size_t *ret_data_len)
1114{
1115 uint8_t *data = NULL;
1116 size_t data_len = 0;
1117
1118 switch (data_id) {
1119 case ISIS_SNMP_ADJ_DATA_NONE:
1120 break;
1121
1122 case ISIS_SNMP_ADJ_DATA_AREA_ADDR:
1123 if (data_off >= adj->area_address_count)
1124 return 0;
1125
1126 data = adj->area_addresses[data_off].area_addr;
1127 data_len = adj->area_addresses[data_off].addr_len;
1128 break;
1129
1130 case ISIS_SNMP_ADJ_DATA_IP_ADDR:
1131 if (data_off
1132 >= (adj->ipv4_address_count + adj->ipv6_address_count))
1133 return 0;
1134
1135 if (data_off >= adj->ipv4_address_count) {
1136 data = (uint8_t *)&adj->ipv6_addresses
1137 [data_off - adj->ipv4_address_count];
1138 data_len = sizeof(adj->ipv6_addresses[0]);
1139 } else {
1140 data = (uint8_t *)&adj->ipv4_addresses[data_off];
1141 data_len = sizeof(adj->ipv4_addresses[0]);
1142 }
1143
1144 break;
1145
1146
1147 case ISIS_SNMP_ADJ_DATA_PROTO:
1148 if (data_off >= adj->nlpids.count)
1149 return 0;
1150
1151 data = &adj->nlpids.nlpids[data_off];
1152 data_len = sizeof(adj->nlpids.nlpids[0]);
1153 break;
1154
1155 default:
1156 assert(0);
1157 return 0;
1158 }
1159
1160 if (ret_data != NULL)
1161 *ret_data = data;
1162
1163 if (ret_data_len != NULL)
1164 *ret_data_len = data_len;
1165
1166 return 1;
1167}
1168
1169static int isis_snmp_adj_lookup_exact(oid *oid_idx, size_t oid_idx_len,
1170 int data_id,
1171 struct isis_adjacency **ret_adj,
1172 oid *ret_data_idx, uint8_t **ret_data,
1173 size_t *ret_data_len)
1174{
1175 int res;
1176 struct listnode *node;
1177 struct isis_circuit *circuit;
1178 struct isis_adjacency *adj;
1179 struct isis_adjacency *tmp_adj;
1180 oid adj_idx;
1181 oid data_off;
1182 uint8_t *data;
1183 size_t data_len;
1184
1185 res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit);
1186
1187 if (!res)
1188 return 0;
1189
1190 if (oid_idx == NULL || oid_idx_len < 2
1191 || (data_id != ISIS_SNMP_ADJ_DATA_NONE && oid_idx_len < 3))
1192 return 0;
1193
1194 adj_idx = oid_idx[1];
1195
1196 if (data_id != ISIS_SNMP_ADJ_DATA_NONE) {
1197 if (oid_idx[2] == 0)
1198 return 0;
1199
1200 data_off = oid_idx[2] - 1;
1201 } else {
1202 /*
1203 * Data-off is not used if data-id is none
1204 * but we set it just for consistency
1205 */
1206 data_off = 0;
1207 }
1208
1209 adj = NULL;
1210 data = NULL;
1211 data_len = 0;
1212
1213 for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node, tmp_adj)) {
1214 if (tmp_adj->snmp_idx > adj_idx) {
1215 /*
1216 * Adjacencies are ordered in the list
1217 * no point to look further
1218 */
1219 break;
1220 }
1221
1222 if (tmp_adj->snmp_idx == adj_idx) {
1223 res = isis_snmp_adj_helper(tmp_adj, data_id, data_off,
1224 &data, &data_len);
1225 if (res)
1226 adj = tmp_adj;
1227
1228 break;
1229 }
1230 }
1231
1232 if (adj == NULL)
1233 return 0;
1234
1235 if (ret_adj != NULL)
1236 *ret_adj = adj;
1237
1238 if (ret_data_idx != NULL)
1239 *ret_data_idx = data_off + 1;
1240
1241 if (ret_data)
1242 *ret_data = data;
1243
1244 if (ret_data_len)
1245 *ret_data_len = data_len;
1246
1247 return 1;
1248}
1249
1250static int isis_snmp_adj_lookup_next(oid *oid_idx, size_t oid_idx_len,
1251 int data_id,
1252 struct isis_adjacency **ret_adj,
1253 oid *ret_data_idx, uint8_t **ret_data,
1254 size_t *ret_data_len)
1255{
1256 struct listnode *node;
1257 struct isis_circuit *circuit;
1258 struct isis_adjacency *adj;
1259 struct isis_adjacency *tmp_adj;
1260 oid circ_idx;
1261 oid adj_idx;
1262 oid data_idx;
1263 uint8_t *data;
1264 size_t data_len;
1265
1266 adj = NULL;
1267 data = NULL;
1268 data_len = 0;
1269
1270 /*
1271 * Note: we rely on the fact that data indexes are consequtive
1272 * starting from 1
1273 */
1274
1275 if (oid_idx == 0 || oid_idx_len == 0) {
1276 circ_idx = 0;
1277 adj_idx = 0;
1278 data_idx = 0;
1279 } else if (oid_idx_len == 1) {
1280 circ_idx = oid_idx[0];
1281 adj_idx = 0;
1282 data_idx = 0;
1283 } else if (oid_idx_len == 2) {
1284 circ_idx = oid_idx[0];
1285 adj_idx = oid_idx[1];
1286 data_idx = 0;
1287 } else {
1288 circ_idx = oid_idx[0];
1289 adj_idx = oid_idx[1];
1290
1291 if (data_id == ISIS_SNMP_ADJ_DATA_NONE)
1292 data_idx = 0;
1293 else
1294 data_idx = oid_idx[2];
1295 }
1296
1297 if (!isis_snmp_circuit_lookup_exact(&circ_idx, 1, &circuit)
1298 && !isis_snmp_circuit_lookup_next(&circ_idx, 1, &circuit))
1299 /* No circuit */
1300 return 0;
1301
1302 if (circuit->snmp_id != circ_idx) {
1303 /* Match is not exact */
1304 circ_idx = 0;
1305 adj_idx = 0;
1306 data_idx = 0;
1307 }
1308
1309 /*
1310 * Note: the simple loop below will work in all cases
1311 */
1312 while (circuit != NULL) {
1313 for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node,
1314 tmp_adj)) {
1315 if (tmp_adj->snmp_idx < adj_idx)
1316 continue;
1317
1318 if (tmp_adj->snmp_idx == adj_idx
1319 && data_id == ISIS_SNMP_ADJ_DATA_NONE)
1320 continue;
1321
1322 if (adj_idx != 0 && tmp_adj->snmp_idx > adj_idx)
1323 data_idx = 0;
1324
1325 if (isis_snmp_adj_helper(tmp_adj, data_id, data_idx,
1326 &data, &data_len)) {
1327 adj = tmp_adj;
1328 break;
1329 }
1330 }
1331
1332 if (adj != NULL)
1333 break;
1334
1335 circuit = isis_snmp_circuit_next(circuit);
1336 circ_idx = 0;
1337 adj_idx = 0;
1338 data_idx = 0;
1339 }
1340
1341 if (adj == NULL)
1342 return 0;
1343
1344 if (ret_adj != NULL)
1345 *ret_adj = adj;
1346
1347 if (ret_data_idx != 0) {
1348 if (data_id == ISIS_SNMP_ADJ_DATA_NONE)
1349 /*
1350 * Value does not matter but let us set
1351 * it to zero for consistency
1352 */
1353 *ret_data_idx = 0;
1354 else
1355 *ret_data_idx = data_idx + 1;
1356 }
1357
1358 if (ret_data != 0)
1359 *ret_data = data;
1360
1361 if (ret_data_len != 0)
1362 *ret_data_len = data_len;
1363
1364 return 1;
1365}
1366
1367static uint8_t *isis_snmp_find_sys_object(struct variable *v, oid *name,
1368 size_t *length, int exact,
1369 size_t *var_len,
1370 WriteMethod **write_method)
1371{
1372 struct isis_area *area = NULL;
1373 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
1374
1375 if (isis == NULL)
1376 return NULL;
1377
1378 if (!list_isempty(isis->area_list))
1379 area = listgetdata(listhead(isis->area_list));
1380
1381 /* Check whether the instance identifier is valid */
1382 if (smux_header_generic(v, name, length, exact, var_len, write_method)
1383 == MATCH_FAILED)
1384 return NULL;
1385
1386 switch (v->magic) {
1387 case ISIS_SYS_VERSION:
1388 return SNMP_INTEGER(ISIS_VERSION);
1389
1390 case ISIS_SYS_LEVELTYPE:
1391 /*
1392 * If we do not have areas use 1&2 otherwise use settings
1393 * from the first area in the list
1394 */
1395 if (area == NULL)
1396 return SNMP_INTEGER(IS_LEVEL_1_AND_2);
1397
1398 return SNMP_INTEGER(area->is_type);
1399
1400 case ISIS_SYS_ID:
1401 if (!isis->sysid_set) {
1402 *var_len = ISIS_SYS_ID_LEN;
1403 return isis_null_sysid;
1404 }
1405
1406 *var_len = ISIS_SYS_ID_LEN;
1407 return isis->sysid;
1408
1409 case ISIS_SYS_MAXPATHSPLITS:
1410 return SNMP_INTEGER(ISIS_SNMP_MAX_PATH_SPLITS);
1411
1412 case ISIS_SYS_MAXLSPGENINT:
1413 return SNMP_INTEGER(DEFAULT_MAX_LSP_GEN_INTERVAL);
1414
1415 case ISIS_SYS_POLLESHELLORATE:
1416 return SNMP_INTEGER(DEFAULT_HELLO_INTERVAL);
1417
1418 case ISIS_SYS_WAITTIME:
1419 /* Note: it seems that we have same fixed delay time */
1420 return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL);
1421
1422 case ISIS_SYS_ADMINSTATE:
1423 /* If daemon is running it admin state is on */
1424 return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON);
1425
1426
1427 case ISIS_SYS_L2TOL1LEAKING:
1428 /* We do not allow l2-to-l1 leaking */
1429 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
1430
1431 case ISIS_SYS_MAXAGE:
1432 return SNMP_INTEGER(MAX_AGE);
1433
1434 case ISIS_SYS_RECEIVELSPBUFFERSIZE:
1435 if (area == NULL)
1436 return SNMP_INTEGER(DEFAULT_LSP_MTU);
1437
1438 return SNMP_INTEGER(area->lsp_mtu);
1439
1440 case ISIS_SYS_PROTSUPPORTED:
1441 *var_len = 1;
1442 return &isis_snmp_protocols_supported;
1443
1444 case ISIS_SYS_NOTIFICATIONENABLE:
1445 if (isis->snmp_notifications)
1446 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
1447
1448 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
1449
1450 default:
1451 break;
1452 }
1453
1454 return NULL;
1455}
1456
1457
1458static uint8_t *isis_snmp_find_man_area(struct variable *v, oid *name,
1459 size_t *length, int exact,
1460 size_t *var_len,
1461 WriteMethod **write_method)
1462{
1463 int res;
1464 struct area_addr *area_addr = NULL;
1465 oid *oid_idx;
1466 size_t oid_idx_len;
1467 size_t off = 0;
1468
1469 *write_method = NULL;
1470
1471 if (*length <= v->namelen) {
1472 oid_idx = NULL;
1473 oid_idx_len = 0;
1474 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
1475 oid_idx = NULL;
1476 oid_idx_len = 0;
1477 } else {
1478 oid_idx = name + v->namelen;
1479 oid_idx_len = *length - v->namelen;
1480 }
1481
1482 if (exact) {
1483 res = isis_snmp_area_addr_lookup_exact(oid_idx, oid_idx_len,
1484 NULL, &area_addr);
1485
1486 if (!res)
1487 return NULL;
1488
1489 } else {
1490 res = isis_snmp_area_addr_lookup_next(oid_idx, oid_idx_len,
1491 NULL, &area_addr);
1492
1493 if (!res)
1494 return NULL;
1495
1496 /* Copy the name out */
1497 memcpy(name, v->name, v->namelen * sizeof(oid));
1498
1499 /* Append index */
1500 name[v->namelen] = area_addr->addr_len;
1501
1502 for (off = 0; off < area_addr->addr_len; off++)
1503 name[v->namelen + 1 + off] = area_addr->area_addr[off];
1504
1505 *length = v->namelen + 1 + area_addr->addr_len;
1506 }
1507
1508 switch (v->magic) {
1509 case ISIS_MANAREA_ADDREXISTSTATE:
1510 return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE);
1511
1512 default:
1513 break;
1514 }
1515
1516 return NULL;
1517}
1518
1519static uint8_t *isis_snmp_find_area_addr(struct variable *v, oid *name,
1520 size_t *length, int exact,
1521 size_t *var_len,
1522 WriteMethod **write_method)
1523{
1524 /*
1525 * Area addresses in sense of addresses reported by L1 lsps
1526 * are not supported yet.
1527 */
1528 (void)v;
1529 (void)name;
1530 (void)length;
1531 (void)exact;
1532 (void)var_len;
1533
1534
1535 *write_method = NULL;
1536
1537 return NULL;
1538}
1539
1540static uint8_t *isis_snmp_find_summ_addr(struct variable *v, oid *name,
1541 size_t *length, int exact,
1542 size_t *var_len,
1543 WriteMethod **write_method)
1544{
1545 /*
1546 * So far there is no way to set summary table values through cli
1547 * and snmp operations are read-only, hence there are no entries
1548 */
1549 (void)v;
1550 (void)name;
1551 (void)length;
1552 (void)exact;
1553 (void)var_len;
1554 *write_method = NULL;
1555
1556 return NULL;
1557}
1558
1559static uint8_t *isis_snmp_find_redistribute_addr(struct variable *v, oid *name,
1560 size_t *length, int exact,
1561 size_t *var_len,
1562 WriteMethod **write_method)
1563{
1564 /*
1565 * It is not clear at the point whether redist code in isis is actually
1566 * used for now we will consider that entries are not present
1567 */
1568 (void)v;
1569 (void)name;
1570 (void)length;
1571 (void)exact;
1572 (void)var_len;
1573 *write_method = NULL;
1574
1575 return NULL;
1576}
1577
1578static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
1579 size_t *length, int exact,
1580 size_t *var_len,
1581 WriteMethod **write_method)
1582{
1583 uint8_t cmp_buf[ISIS_SYS_ID_LEN];
1584 size_t cmp_len;
1585 int try_exact;
1586 int cmp_level;
1587 int res;
1588 struct isis_dynhn *dyn = NULL;
1589 oid *oid_idx;
1590 size_t oid_idx_len;
1591 size_t off = 0;
1592
1593 *write_method = NULL;
1594
1595 if (*length <= v->namelen) {
1596 oid_idx = NULL;
1597 oid_idx_len = 0;
1598 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
1599 oid_idx = NULL;
1600 oid_idx_len = 0;
1601 } else {
1602 oid_idx = name + v->namelen;
1603 oid_idx_len = *length - v->namelen;
1604 }
1605
1606 if (exact) {
1607 res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &cmp_len,
1608 oid_idx, oid_idx_len);
1609
1610 if (!res || cmp_len != ISIS_SYS_ID_LEN
1611 || oid_idx_len != (cmp_len + 2))
1612 /*
1613 * Bad conversion, or bad length,
1614 * or extra oids at the end
1615 */
1616 return NULL;
1617
1618 if (oid_idx[ISIS_SYS_ID_LEN + 1] < IS_LEVEL_1
1619 || oid_idx[ISIS_SYS_ID_LEN + 1] > IS_LEVEL_2)
1620 /* Level part of the index is out of range */
1621 return NULL;
1622
1623 cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
1624
1625 dyn = dynhn_find_by_id(cmp_buf);
1626
1627 if (dyn == NULL || dyn->level != cmp_level)
1628 return NULL;
1629
1630 switch (v->magic) {
1631 case ISIS_ROUTER_HOSTNAME:
1632 *var_len = strlen(dyn->hostname);
1633 return (uint8_t *)dyn->hostname;
1634
1635 case ISIS_ROUTER_ID:
1636 /* It seems that we do no know router-id in lsps */
1637 return SNMP_INTEGER(0);
1638
1639 default:
1640 break;
1641 }
1642
1643 return NULL;
1644 }
1645
1646 res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &cmp_len,
1647 &try_exact, oid_idx, oid_idx_len);
1648
1649
1650 if (!res)
1651 /* Bad conversion */
1652 return NULL;
1653
1654 if (cmp_len != ISIS_SYS_ID_LEN) {
1655 /* We do not have valid index oids */
1656 memset(cmp_buf, 0, sizeof(cmp_buf));
1657 cmp_level = 0;
1658 } else if (try_exact)
1659 /*
1660 * We have no valid level index.
1661 * Let start from non-existing level 0 and
1662 * hence not need to do exact match
1663 */
1664 cmp_level = 0;
1665 else if (oid_idx_len < (ISIS_SYS_ID_LEN + 2))
1666 cmp_level = 0;
1667 else if (oid_idx[ISIS_SYS_ID_LEN + 1] <= IS_LEVEL_2)
1668 cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
1669 else
1670 /*
1671 * Any value greater than 2 will have the same result
1672 * but we can have integer overflows, hence 3 is a reasonable
1673 * choice
1674 */
1675 cmp_level = (int)(IS_LEVEL_2 + 1);
1676
1677 dyn = dynhn_snmp_next(cmp_buf, cmp_level);
1678
1679 if (dyn == NULL)
1680 return NULL;
1681
1682 /* Copy the name out */
1683 memcpy(name, v->name, v->namelen * sizeof(oid));
1684
1685 /* Append index */
1686 name[v->namelen] = ISIS_SYS_ID_LEN;
1687
1688 for (off = 0; off < ISIS_SYS_ID_LEN; off++)
1689 name[v->namelen + 1 + off] = dyn->id[off];
1690
1691 name[v->namelen + 1 + ISIS_SYS_ID_LEN] = (oid)dyn->level;
1692
1693 /* Set length */
1694 *length = v->namelen + 1 + ISIS_SYS_ID_LEN + 1;
1695
1696 switch (v->magic) {
1697 case ISIS_ROUTER_HOSTNAME:
1698 *var_len = strlen(dyn->hostname);
1699 return (uint8_t *)dyn->hostname;
1700
1701 case ISIS_ROUTER_ID:
1702 /* It seems that we do no know router-id in lsps */
1703 return SNMP_INTEGER(0);
1704
1705 default:
1706 break;
1707 }
1708
1709 return NULL;
1710}
1711
1712static uint8_t *isis_snmp_find_sys_level(struct variable *v, oid *name,
1713 size_t *length, int exact,
1714 size_t *var_len,
1715 WriteMethod **write_method)
1716{
1717 oid *oid_idx;
1718 size_t oid_idx_len;
1719 int level;
1720 int level_match;
1721 struct isis_area *area = NULL;
1722 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
1723
1724 if (isis == NULL)
1725 return NULL;
1726
1727 *write_method = NULL;
1728
1729 if (*length <= v->namelen) {
1730 oid_idx = NULL;
1731 oid_idx_len = 0;
1732 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
1733 oid_idx = NULL;
1734 oid_idx_len = 0;
1735 } else {
1736 oid_idx = name + v->namelen;
1737 oid_idx_len = *length - v->namelen;
1738 }
1739
1740 if (exact) {
1741 if (oid_idx == NULL || oid_idx_len != 1)
1742 return NULL;
1743
1744 if (oid_idx[0] == IS_LEVEL_1)
1745 level = IS_LEVEL_1;
1746 else if (oid_idx[0] == IS_LEVEL_2)
1747 level = IS_LEVEL_2;
1748 else
1749 return NULL;
1750
1751 } else {
1752 if (oid_idx == NULL)
1753 level = IS_LEVEL_1;
1754 else if (oid_idx_len == 0)
1755 level = IS_LEVEL_1;
1756 else if (oid_idx[0] < IS_LEVEL_1)
1757 level = IS_LEVEL_1;
1758 else if (oid_idx[0] < IS_LEVEL_2)
1759 level = IS_LEVEL_2;
1760 else
1761 return NULL;
1762
1763 /* Copy the name out */
1764 memcpy(name, v->name, v->namelen * sizeof(oid));
1765
1766 /* Append index */
1767 name[v->namelen] = level;
1768
1769 /* Set length */
1770 *length = v->namelen + 1;
1771 }
1772
1773 area = NULL;
1774
1775 if (!list_isempty(isis->area_list))
1776 area = listgetdata(listhead(isis->area_list));
1777
1778 level_match = 0;
1779
1780 if (area != NULL)
1781 level_match = isis_snmp_get_level_match(area->is_type, level);
1782
1783 switch (v->magic) {
1784 case ISIS_SYSLEVEL_ORIGLSPBUFFSIZE:
1785 if (level_match)
1786 return SNMP_INTEGER(area->lsp_mtu);
1787
1788 return SNMP_INTEGER(DEFAULT_LSP_MTU);
1789
1790 case ISIS_SYSLEVEL_MINLSPGENINT:
1791 if (level_match)
1792 return SNMP_INTEGER(area->lsp_gen_interval[level - 1]);
1793 else
1794 return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL);
1795
1796 case ISIS_SYSLEVEL_STATE:
1797 if (level_match) {
1798 if (area->overload_bit)
1799 return SNMP_INTEGER(
1800 ISIS_SNMP_LEVEL_STATE_OVERLOADED);
1801
1802 return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_ON);
1803 }
1804 return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_OFF);
1805
1806 case ISIS_SYSLEVEL_SETOVERLOAD:
1807 if (level_match && area->overload_bit)
1808 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
1809
1810 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
1811
1812 case ISIS_SYSLEVEL_SETOVERLOADUNTIL:
1813 /* We do not have automatic cleanup of overload bit */
1814 return SNMP_INTEGER(0);
1815
1816 case ISIS_SYSLEVEL_METRICSTYLE:
1817 if (level_match) {
1818 if (area->newmetric && area->oldmetric)
1819 return SNMP_INTEGER(
1820 ISIS_SNMP_METRIC_STYLE_BOTH);
1821
1822 if (area->newmetric)
1823 return SNMP_INTEGER(
1824 ISIS_SNMP_METRIC_STYLE_WIDE);
1825
1826 return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW);
1827 }
1828 return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW);
1829
1830 case ISIS_SYSLEVEL_SPFCONSIDERS:
1831 return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_BOTH);
1832
1833 case ISIS_SYSLEVEL_TEENABLED:
1834 if (level_match && IS_MPLS_TE(area->mta))
1835 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
1836
1837 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
1838
1839 default:
1840 break;
1841 }
1842
1843 return NULL;
1844}
1845
1846static uint8_t *isis_snmp_find_system_counter(struct variable *v, oid *name,
1847 size_t *length, int exact,
1848 size_t *var_len,
1849 WriteMethod **write_method)
1850{
1851 oid *oid_idx;
1852 size_t oid_idx_len;
1853 int level;
1854 int level_match;
1855 struct isis_area *area = NULL;
1856 uint32_t val;
1857 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
1858
1859 if (isis == NULL)
1860 return NULL;
1861
1862 *write_method = NULL;
1863
1864 if (*length <= v->namelen) {
1865 oid_idx = NULL;
1866 oid_idx_len = 0;
1867 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
1868 oid_idx = NULL;
1869 oid_idx_len = 0;
1870 } else {
1871 oid_idx = name + v->namelen;
1872 oid_idx_len = *length - v->namelen;
1873 }
1874
1875 if (exact) {
1876 if (oid_idx == NULL || oid_idx_len != 1)
1877 return 0;
1878
1879 if (oid_idx[0] == IS_LEVEL_1)
1880 level = IS_LEVEL_1;
1881 else if (oid_idx[0] == IS_LEVEL_2)
1882 level = IS_LEVEL_2;
1883 else
1884 return NULL;
1885
1886 } else {
1887 if (oid_idx == NULL)
1888 level = IS_LEVEL_1;
1889 else if (oid_idx_len == 0)
1890 level = IS_LEVEL_1;
1891 else if (oid_idx[0] < IS_LEVEL_1)
1892 level = IS_LEVEL_1;
1893 else if (oid_idx[0] < IS_LEVEL_2)
1894 level = IS_LEVEL_2;
1895 else
1896 return NULL;
1897
1898 /* Copy the name out */
1899 memcpy(name, v->name, v->namelen * sizeof(oid));
1900
1901 /* Append index */
1902 name[v->namelen] = level;
1903
1904 /* Set length */
1905 *length = v->namelen + 1;
1906 }
1907
1908 area = NULL;
1909
1910 if (!list_isempty(isis->area_list))
1911 area = listgetdata(listhead(isis->area_list));
1912
1913 level_match = 0;
1914
1915 if (area != NULL)
1916 level_match = isis_snmp_get_level_match(area->is_type, level);
1917
1918 if (!level_match)
1919 /* If level does not match all counters are zeros */
1920 return SNMP_INTEGER(0);
1921
1922 val = 0;
1923
1924 switch (v->magic) {
1925 case ISIS_SYSSTAT_CORRLSPS:
1926 val = 0;
1927 break;
1928
1929 case ISIS_SYSSTAT_AUTHTYPEFAILS:
1930 val = (uint32_t)area->auth_type_failures[level - 1];
1931 break;
1932
1933 case ISIS_SYSSTAT_AUTHFAILS:
1934 val = (uint32_t)area->auth_failures[level - 1];
1935 break;
1936
1937 case ISIS_SYSSTAT_LSPDBASEOLOADS:
1938 val = area->overload_counter;
1939 break;
1940
1941 case ISIS_SYSSTAT_MANADDRDROPFROMAREAS:
1942 /* We do not support manual addresses */
1943 val = 0;
1944 break;
1945
1946 case ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS:
1947 val = area->lsp_exceeded_max_counter;
1948 break;
1949
1950 case ISIS_SYSSTAT_SEQNUMSKIPS:
1951 val = area->lsp_seqno_skipped_counter;
1952 break;
1953
1954 case ISIS_SYSSTAT_OWNLSPPURGES:
1955 if (!area->purge_originator)
1956 val = 0;
1957 else
1958 val = area->lsp_purge_count[level - 1];
1959 break;
1960
1961 case ISIS_SYSSTAT_IDFIELDLENMISMATCHES:
1962 val = (uint32_t)area->id_len_mismatches[level - 1];
1963 break;
1964
1965 case ISIS_SYSSTAT_PARTCHANGES:
1966 /* Not supported */
1967 val = 0;
1968 break;
1969
1970 case ISIS_SYSSTAT_SPFRUNS:
1971 val = (uint32_t)area->spf_run_count[level - 1];
1972 break;
1973
1974 case ISIS_SYSSTAT_LSPERRORS:
1975 val = (uint32_t)area->lsp_error_counter[level - 1];
1976 break;
1977
1978 default:
1979 return NULL;
1980 }
1981
1982 return SNMP_INTEGER(val);
1983}
1984
1985static uint8_t *isis_snmp_find_next_circ_index(struct variable *v, oid *name,
1986 size_t *length, int exact,
1987 size_t *var_len,
1988 WriteMethod **write_method)
1989{
1990 /* Check whether the instance identifier is valid */
1991 if (smux_header_generic(v, name, length, exact, var_len, write_method)
1992 == MATCH_FAILED)
1993 return NULL;
1994
1995 switch (v->magic) {
1996 case ISIS_NEXTCIRC_INDEX:
1997 /*
1998 * We do not support circuit creation through snmp
1999 */
2000 return SNMP_INTEGER(0);
2001
2002 default:
2003 break;
2004 }
2005
2006 return 0;
2007}
2008
2009static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
2010 size_t *length, int exact, size_t *var_len,
2011 WriteMethod **write_method)
2012{
2013 /* Index is circuit-id: 1-255 */
2014 oid *oid_idx;
2015 size_t oid_idx_len;
2016 struct isis_circuit *circuit;
e91a589b 2017 uint32_t up_ticks;
2018 uint32_t delta_ticks;
1ee746d9 2019 uint32_t now_time;
2020 int res;
2021
2022 *write_method = NULL;
2023
2024 if (*length <= v->namelen) {
2025 oid_idx = NULL;
2026 oid_idx_len = 0;
2027 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2028 oid_idx = NULL;
2029 oid_idx_len = 0;
2030 } else {
2031 oid_idx = name + v->namelen;
2032 oid_idx_len = *length - v->namelen;
2033 }
2034 if (exact) {
2035 res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len,
2036 &circuit);
2037
2038 if (!res || oid_idx_len != 1)
2039 return NULL;
2040
2041 } else {
2042 res = isis_snmp_circuit_lookup_next(oid_idx, oid_idx_len,
2043 &circuit);
2044
2045 if (!res)
2046 return NULL;
2047
2048 /* Copy the name out */
2049 memcpy(name, v->name, v->namelen * sizeof(oid));
2050
2051 /* Append index */
2052 name[v->namelen] = circuit->snmp_id;
2053
2054 /* Set length */
2055 *length = v->namelen + 1;
2056 }
2057
2058 switch (v->magic) {
2059 case ISIS_CIRC_IFINDEX:
2060 if (circuit->interface == 0)
2061 return SNMP_INTEGER(0);
2062
2063 return SNMP_INTEGER(circuit->interface->ifindex);
2064
2065 case ISIS_CIRC_ADMINSTATE:
2066 return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON);
2067
2068 case ISIS_CIRC_EXISTSTATE:
2069 return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE);
2070
2071 case ISIS_CIRC_TYPE:
2072 /*
2073 * Note: values do not match 100%:
2074 *
2075 * 1. From isis_circuit.h:
2076 * CIRCUIT_T_UNKNOWN 0
2077 * CIRCUIT_T_BROADCAST 1
2078 * CIRCUIT_T_P2P 2
2079 * CIRCUIT_T_LOOPBACK 3
2080 *
2081 * 2. From rfc:
2082 * broadcast(1),
2083 * ptToPt(2),
2084 * staticIn(3),
2085 * staticOut(4),
2086 */
2087
2088 return SNMP_INTEGER(circuit->circ_type);
2089
2090 case ISIS_CIRC_EXTDOMAIN:
2091 if (circuit->ext_domain)
2092 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
2093
2094 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
2095
2096 case ISIS_CIRC_LEVELTYPE:
2097 return SNMP_INTEGER(circuit->is_type);
2098
2099 case ISIS_CIRC_PASSIVECIRCUIT:
2100 if (circuit->is_passive)
2101 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
2102
2103 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
2104
2105 case ISIS_CIRC_MESHGROUPENABLED:
2106 /* Not supported */
2107 return SNMP_INTEGER(ISIS_SNMP_MESH_GROUP_INACTIVE);
2108
2109 case ISIS_CIRC_MESHGROUP:
2110 /* Not supported */
2111 return SNMP_INTEGER(0);
2112
2113 case ISIS_CIRC_SMALLHELLOS:
2114 /*
2115 * return false if lan hellos must be padded
2116 */
2117 if (circuit->pad_hellos)
2118 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
2119
2120 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
2121
2122 case ISIS_CIRC_LASTUPTIME:
2123 if (circuit->last_uptime == 0)
2124 return SNMP_INTEGER(0);
2125
e91a589b 2126 up_ticks = (uint32_t)netsnmp_get_agent_uptime();
1ee746d9 2127 now_time = isis_snmp_time();
2128
2129 if (circuit->last_uptime >= now_time)
2130 return SNMP_INTEGER(up_ticks);
2131
2132 delta_ticks = (now_time - circuit->last_uptime) * 10;
2133
2134 if (up_ticks < delta_ticks)
2135 return SNMP_INTEGER(up_ticks);
2136
e91a589b 2137 return SNMP_INTEGER(up_ticks - delta_ticks);
1ee746d9 2138
2139 case ISIS_CIRC_3WAYENABLED:
2140 /* Not supported */
2141 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
2142
2143 case ISIS_CIRC_EXTENDEDCIRCID:
2144 /* Used for 3-way hand shake only */
2145 return SNMP_INTEGER(0);
2146
2147 default:
2148 break;
2149 }
2150
2151 return NULL;
2152}
2153
2154static uint8_t *isis_snmp_find_circ_level(struct variable *v, oid *name,
2155 size_t *length, int exact,
2156 size_t *var_len,
2157 WriteMethod **write_method)
2158{
2159 static uint8_t circuit_id_val[ISIS_SYS_ID_LEN + 1];
2160 /* Index is circuit-id: 1-255 + level: 1-2 */
2161 oid *oid_idx;
2162 size_t oid_idx_len;
2163 int res;
2164 struct isis_circuit *circuit;
2165 int level;
2166 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
2167
2168 if (isis == NULL)
2169 return NULL;
2170
2171 *write_method = NULL;
2172
2173 if (*length <= v->namelen) {
2174 oid_idx = NULL;
2175 oid_idx_len = 0;
2176 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2177 oid_idx = NULL;
2178 oid_idx_len = 0;
2179 } else {
2180 oid_idx = name + v->namelen;
2181 oid_idx_len = *length - v->namelen;
2182 }
2183 if (exact) {
2184 res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len,
2185 1, &circuit, &level);
2186
2187 if (!res || oid_idx_len != 2)
2188 return NULL;
2189
2190 } else {
2191 res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len,
2192 1, &circuit, &level);
2193
2194 if (!res)
2195 return NULL;
2196
2197 /* Copy the name out */
2198 memcpy(name, v->name, v->namelen * sizeof(oid));
2199
2200 /* Append index */
2201 name[v->namelen] = circuit->snmp_id;
2202 name[v->namelen + 1] = level;
2203
2204 /* Set length */
2205 *length = v->namelen + 2;
2206 }
2207
2208 switch (v->magic) {
2209 case ISIS_CIRCLEVEL_METRIC:
2210 return SNMP_INTEGER(circuit->metric[level - 1]);
2211
2212 case ISIS_CIRCLEVEL_WIDEMETRIC:
2213 if (circuit->area == NULL || !circuit->area->newmetric) {
2214 /* What should we do if wide metric is not supported? */
2215 return SNMP_INTEGER(0);
2216 }
2217 return SNMP_INTEGER(circuit->te_metric[level - 1]);
2218
2219 case ISIS_CIRCLEVEL_ISPRIORITY:
2220 return SNMP_INTEGER(circuit->priority[level - 1]);
2221
2222 case ISIS_CIRCLEVEL_IDOCTET:
2223 return SNMP_INTEGER(circuit->circuit_id);
2224
2225 case ISIS_CIRCLEVEL_ID:
2226 if (circuit->circ_type != CIRCUIT_T_P2P) {
2227 /*
2228 * Unless it is point-to-point circuit, the value is and
2229 * empty octet string
2230 */
2231 *var_len = 0;
2232 return circuit_id_val;
2233 }
2234
2235 /* !!!!!! Circuit-id is zero for p2p links */
2236 if (circuit->u.p2p.neighbor == NULL
2237 || circuit->u.p2p.neighbor->adj_state != ISIS_ADJ_UP) {
2238 /* No adjacency or adjacency not fully up yet */
2239 memcpy(circuit_id_val, isis->sysid, ISIS_SYS_ID_LEN);
2240 circuit_id_val[ISIS_SYS_ID_LEN] = circuit->circuit_id;
2241 *var_len = ISIS_SYS_ID_LEN + 1;
2242 return circuit_id_val;
2243 }
2244
2245 /* Adjacency fully-up */
2246 memcpy(circuit_id_val, circuit->u.p2p.neighbor->sysid,
2247 ISIS_SYS_ID_LEN);
2248 circuit_id_val[ISIS_SYS_ID_LEN] = 0;
2249 *var_len = ISIS_SYS_ID_LEN + 1;
2250 return circuit_id_val;
2251
2252 case ISIS_CIRCLEVEL_DESIS:
2253 if (circuit->circ_type != CIRCUIT_T_BROADCAST
2254 || !circuit->u.bc.is_dr[level - 1]) {
2255 /*
2256 * Unless it is lan circuit participating in dis process
2257 * the value is an empty octet string
2258 */
2259 *var_len = 0;
2260 return circuit_id_val;
2261 }
2262
2263 *var_len = ISIS_SYS_ID_LEN + 1;
2264
2265 if (level == IS_LEVEL_1)
2266 return circuit->u.bc.l1_desig_is;
2267
2268 return circuit->u.bc.l2_desig_is;
2269
2270 case ISIS_CIRCLEVEL_HELLOMULTIPLIER:
2271 return SNMP_INTEGER(circuit->hello_multiplier[level - 1]);
2272
2273 case ISIS_CIRCLEVEL_HELLOTIMER:
2274 return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000);
2275
2276 case ISIS_CIRCLEVEL_DRHELLOTIMER:
2277 return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000);
2278
2279 case ISIS_CIRCLEVEL_LSPTHROTTLE:
2280 if (circuit->area)
2281 return SNMP_INTEGER(
2282 circuit->area->min_spf_interval[level - 1]
2283 * 1000);
2284 else
2285 return SNMP_INTEGER(0);
2286
2287 case ISIS_CIRCLEVEL_MINLSPRETRANSINT:
2288 if (circuit->area)
2289 return SNMP_INTEGER(
2290 circuit->area->min_spf_interval[level - 1]);
2291 else
2292 return SNMP_INTEGER(0);
2293
2294 case ISIS_CIRCLEVEL_CSNPINTERVAL:
2295 return SNMP_INTEGER(circuit->csnp_interval[level - 1]);
2296
2297 case ISIS_CIRCLEVEL_PARTSNPINTERVAL:
2298 return SNMP_INTEGER(circuit->psnp_interval[level - 1]);
2299
2300 default:
2301 break;
2302 }
2303
2304 return NULL;
2305}
2306
2307static uint8_t *isis_snmp_find_circ_counter(struct variable *v, oid *name,
2308 size_t *length, int exact,
2309 size_t *var_len,
2310 WriteMethod **write_method)
2311{
2312 /* Index circuit-id 1-255 + level */
2313 oid *oid_idx;
2314 size_t oid_idx_len;
2315 int res;
2316 struct isis_circuit *circuit;
2317 int level;
2318 uint32_t val = 0;
2319
2320 *write_method = NULL;
2321
2322 if (*length <= v->namelen) {
2323 oid_idx = NULL;
2324 oid_idx_len = 0;
2325 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2326 oid_idx = NULL;
2327 oid_idx_len = 0;
2328 } else {
2329 oid_idx = name + v->namelen;
2330 oid_idx_len = *length - v->namelen;
2331 }
2332 if (exact) {
2333 res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len,
2334 1, &circuit, &level);
2335
2336 if (!res || oid_idx_len != 2)
2337 return NULL;
2338
2339 } else {
2340 res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len,
2341 1, &circuit, &level);
2342
2343 if (!res)
2344 return NULL;
2345
2346 /* Copy the name out */
2347 memcpy(name, v->name, v->namelen * sizeof(oid));
2348
2349 /* Append index */
2350 name[v->namelen] = circuit->snmp_id;
2351 if (circuit->circ_type == CIRCUIT_T_P2P)
2352 name[v->namelen + 1] = ISIS_SNMP_P2P_CIRCUIT;
2353 else
2354 name[v->namelen + 1] = level;
2355
2356 /* Set length */
2357 *length = v->namelen + 2;
2358 }
2359
2360 switch (v->magic) {
2361 case ISIS_CIRC_ADJCHANGES:
2362 val = circuit->adj_state_changes;
2363 break;
2364
2365 case ISIS_CIRC_NUMADJ:
2366 if (circuit->circ_type == CIRCUIT_T_P2P) {
2367 val = circuit->u.p2p.neighbor == NULL ? 0 : 1;
2368 break;
2369 }
2370
2371 if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
2372 val = 0;
2373 break;
2374 }
2375
2376 if (level == IS_LEVEL_1) {
2377 if (circuit->u.bc.adjdb[0] == NULL)
2378 val = 0;
2379 else
2380 val = listcount(circuit->u.bc.adjdb[0]);
2381 break;
2382 }
2383
2384 if (circuit->u.bc.adjdb[1] == NULL)
2385 val = 0;
2386 else
2387 val = listcount(circuit->u.bc.adjdb[1]);
2388
2389 break;
2390
2391 case ISIS_CIRC_INITFAILS:
2392 val = circuit->init_failures; /* counter never incremented */
2393 break;
2394
2395 case ISIS_CIRC_REJADJS:
2396 val = circuit->rej_adjacencies;
2397 break;
2398
2399 case ISIS_CIRC_IDFIELDLENMISMATCHES:
2400 val = circuit->id_len_mismatches;
2401 break;
2402
2403 case ISIS_CIRC_MAXAREAADDRMISMATCHES:
2404 val = circuit->max_area_addr_mismatches;
2405 break;
2406
2407 case ISIS_CIRC_AUTHTYPEFAILS:
2408 val = circuit->auth_type_failures;
2409 break;
2410
2411 case ISIS_CIRC_AUTHFAILS:
2412 val = circuit->auth_failures;
2413 break;
2414
2415 case ISIS_CIRC_LANDESISCHANGES:
2416 if (circuit->circ_type == CIRCUIT_T_P2P)
2417 val = 0;
2418 else
2419 val = circuit->desig_changes[level - 1];
2420 break;
2421
2422 default:
2423 return NULL;
2424 }
2425
2426 return SNMP_INTEGER(val);
2427}
2428
2429static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
2430 size_t *length, int exact, size_t *var_len,
2431 WriteMethod **write_method)
2432{
2433 /* Index is circuit-id: 1-255 + adj-id: 1-... */
2434 oid *oid_idx;
2435 size_t oid_idx_len;
2436 int res;
2437 uint32_t val;
2438 struct isis_adjacency *adj;
e91a589b 2439 uint32_t up_ticks;
2440 uint32_t delta_ticks;
1ee746d9 2441 uint32_t now_time;
2442
2443 *write_method = NULL;
2444
2445 if (*length <= v->namelen) {
2446 oid_idx = NULL;
2447 oid_idx_len = 0;
2448 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2449 oid_idx = NULL;
2450 oid_idx_len = 0;
2451 } else {
2452 oid_idx = name + v->namelen;
2453 oid_idx_len = *length - v->namelen;
2454 }
2455 if (exact) {
2456 res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
2457 ISIS_SNMP_ADJ_DATA_NONE, &adj,
2458 NULL, NULL, NULL);
2459
2460 if (!res || oid_idx_len != 2)
2461 return NULL;
2462
2463 } else {
2464 res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len,
2465 ISIS_SNMP_ADJ_DATA_NONE, &adj,
2466 NULL, NULL, NULL);
2467 if (!res)
2468 return NULL;
2469
2470 /* Copy the name out */
2471 memcpy(name, v->name, v->namelen * sizeof(oid));
2472
2473 /* Append index */
2474 name[v->namelen] = adj->circuit->snmp_id;
2475 name[v->namelen + 1] = adj->snmp_idx;
2476
2477 /* Set length */
2478 *length = v->namelen + 2;
2479 }
2480
2481 switch (v->magic) {
2482 case ISIS_ISADJ_STATE:
2483 val = ISIS_SNMP_ADJ_STATE_DOWN;
2484
2485 switch (adj->adj_state) {
2486 case ISIS_ADJ_UNKNOWN:
2487 case ISIS_ADJ_DOWN:
2488 val = ISIS_SNMP_ADJ_STATE_DOWN;
2489 break;
2490
2491 case ISIS_ADJ_INITIALIZING:
2492 val = ISIS_SNMP_ADJ_STATE_INITIALIZING;
2493 break;
2494
2495 case ISIS_ADJ_UP:
2496 val = ISIS_SNMP_ADJ_STATE_UP;
2497 break;
2498 }
2499
2500 return SNMP_INTEGER(val);
2501
2502 case ISIS_ISADJ_3WAYSTATE:
2503 return SNMP_INTEGER(adj->threeway_state);
2504
2505 case ISIS_ISADJ_NEIGHSNPAADDRESS: {
2506 const char *snpa = (char *)snpa_print(adj->snpa);
2507 *var_len = strlen(snpa);
2508 return (uint8_t *)snpa;
2509 }
2510
2511 case ISIS_ISADJ_NEIGHSYSTYPE:
2512 val = ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN;
2513
2514 switch (adj->sys_type) {
2515 case ISIS_SYSTYPE_UNKNOWN:
2516 case ISIS_SYSTYPE_ES:
2517 val = ISIS_SNMP_ADJ_NEIGHTYPE_UNKNOWN;
2518 break;
2519
2520 case ISIS_SYSTYPE_IS:
2521 val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1_L2;
2522 break;
2523
2524 case ISIS_SYSTYPE_L1_IS:
2525 val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L1;
2526 break;
2527
2528 case ISIS_SYSTYPE_L2_IS:
2529 val = ISIS_SNMP_ADJ_NEIGHTYPE_IS_L2;
2530 break;
2531 }
2532
2533 return SNMP_INTEGER(val);
2534
2535 case ISIS_ISADJ_NEIGHSYSID:
2536 *var_len = sizeof(adj->sysid);
2537 return adj->sysid;
2538
2539 case ISIS_ISADJ_NBREXTENDEDCIRCID:
2540 return SNMP_INTEGER(adj->ext_circuit_id != 0 ? 1 : 0);
2541
2542 case ISIS_ISADJ_USAGE:
2543 /* It seems that no value conversion is required */
2544 return SNMP_INTEGER(adj->adj_usage);
2545
2546 case ISIS_ISADJ_HOLDTIMER:
2547 /*
2548 * It seems that we want remaining timer
2549 */
2550 if (adj->last_upd != 0) {
2551 val = isis_snmp_time();
2552 if (val < (adj->last_upd + adj->hold_time))
2553 return SNMP_INTEGER(adj->last_upd
2554 + adj->hold_time - val);
2555 }
2556 /* Not running or just expired */
2557 return SNMP_INTEGER(0);
2558
2559 case ISIS_ISADJ_NEIGHPRIORITY:
2560 return SNMP_INTEGER(adj->prio[adj->level - 1]);
2561
2562 case ISIS_ISADJ_LASTUPTIME:
2563 if (adj->flaps == 0)
2564 return SNMP_INTEGER(0);
2565
e91a589b 2566 up_ticks = (uint32_t)netsnmp_get_agent_uptime();
1ee746d9 2567
2568 now_time = isis_snmp_time();
2569
2570 if (adj->last_flap >= now_time)
2571 return SNMP_INTEGER(up_ticks);
2572
2573 delta_ticks = (now_time - adj->last_flap) * 10;
2574
2575 if (up_ticks < delta_ticks)
2576 return SNMP_INTEGER(up_ticks);
2577
e91a589b 2578 return SNMP_INTEGER(up_ticks - delta_ticks);
1ee746d9 2579
2580 default:
2581 break;
2582 }
2583
2584 return NULL;
2585}
2586
2587static uint8_t *isis_snmp_find_isadj_area(struct variable *v, oid *name,
2588 size_t *length, int exact,
2589 size_t *var_len,
2590 WriteMethod **write_method)
2591{
2592 /* Index circuit-id: 1-255 + adj-id: 1-... */
2593 oid *oid_idx;
2594 size_t oid_idx_len;
2595 int res;
2596 struct isis_adjacency *adj;
2597 oid data_idx;
2598 uint8_t *data;
2599 size_t data_len;
2600
2601 *write_method = NULL;
2602
2603 if (*length <= v->namelen) {
2604 oid_idx = NULL;
2605 oid_idx_len = 0;
2606 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2607 oid_idx = NULL;
2608 oid_idx_len = 0;
2609 } else {
2610 oid_idx = name + v->namelen;
2611 oid_idx_len = *length - v->namelen;
2612 }
2613 if (exact) {
2614 res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
2615 ISIS_SNMP_ADJ_DATA_AREA_ADDR,
2616 &adj, NULL, &data, &data_len);
2617
2618 if (!res || oid_idx_len != 3)
2619 return NULL;
2620
2621 } else {
2622 res = isis_snmp_adj_lookup_next(
2623 oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_AREA_ADDR,
2624 &adj, &data_idx, &data, &data_len);
2625 if (!res)
2626 return NULL;
2627
2628 /* Copy the name out */
2629 memcpy(name, v->name, v->namelen * sizeof(oid));
2630
2631 /* Append index */
2632 name[v->namelen] = adj->circuit->snmp_id;
2633 name[v->namelen + 1] = adj->snmp_idx;
2634 name[v->namelen + 2] = data_idx;
2635
2636 /* Set length */
2637 *length = v->namelen + 3;
2638 }
2639
2640 switch (v->magic) {
2641 case ISIS_ISADJAREA_ADDRESS:
2642 *var_len = data_len;
2643 return data;
2644
2645 default:
2646 break;
2647 }
2648
2649 return NULL;
2650}
2651
2652static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *v, oid *name,
2653 size_t *length, int exact,
2654 size_t *var_len,
2655 WriteMethod **write_method)
2656{
2657 /* Index circuit-id 1-255 + adj-id 1-... */
2658 oid *oid_idx;
2659 size_t oid_idx_len;
2660 int res;
2661 struct isis_adjacency *adj;
2662 oid data_idx;
2663 uint8_t *data;
2664 size_t data_len;
2665
2666 *write_method = NULL;
2667
2668 if (*length <= v->namelen) {
2669 oid_idx = NULL;
2670 oid_idx_len = 0;
2671 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2672 oid_idx = NULL;
2673 oid_idx_len = 0;
2674 } else {
2675 oid_idx = name + v->namelen;
2676 oid_idx_len = *length - v->namelen;
2677 }
2678 if (exact) {
2679 res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
2680 ISIS_SNMP_ADJ_DATA_IP_ADDR,
2681 &adj, NULL, &data, &data_len);
2682
2683 if (!res || oid_idx_len != 3)
2684 return NULL;
2685 } else {
2686 res = isis_snmp_adj_lookup_next(
2687 oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_IP_ADDR, &adj,
2688 &data_idx, &data, &data_len);
2689 if (!res)
2690 return NULL;
2691
2692 /* Copy the name out */
2693 memcpy(name, v->name, v->namelen * sizeof(oid));
2694
2695 /* Append index */
2696 name[v->namelen] = adj->circuit->snmp_id;
2697 name[v->namelen + 1] = adj->snmp_idx;
2698 name[v->namelen + 2] = data_idx;
2699
2700 /* Set length */
2701 *length = v->namelen + 3;
2702 }
2703
2704 switch (v->magic) {
2705 case ISIS_ISADJIPADDR_TYPE:
2706 if (data_len == 4)
2707 return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V4);
2708
2709 return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V6);
2710
2711 case ISIS_ISADJIPADDR_ADDRESS:
2712 *var_len = data_len;
2713 return data;
2714
2715 default:
2716 break;
2717 }
2718
2719 return NULL;
2720}
2721
2722static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *v, oid *name,
2723 size_t *length, int exact,
2724 size_t *var_len,
2725 WriteMethod **write_method)
2726{
2727 /* Index circuit-id 1-255 + adj-id 1-... */
2728 oid *oid_idx;
2729 size_t oid_idx_len;
2730 int res;
2731 struct isis_adjacency *adj;
2732 oid data_idx;
2733 uint8_t *data;
2734 size_t data_len;
2735
2736 *write_method = NULL;
2737
2738 if (*length <= v->namelen) {
2739 oid_idx = NULL;
2740 oid_idx_len = 0;
2741 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2742 oid_idx = NULL;
2743 oid_idx_len = 0;
2744 } else {
2745 oid_idx = name + v->namelen;
2746 oid_idx_len = *length - v->namelen;
2747 }
2748 if (exact) {
2749 res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
2750 ISIS_SNMP_ADJ_DATA_PROTO, &adj,
2751 NULL, &data, &data_len);
2752
2753 if (!res || oid_idx_len != 3)
2754 return NULL;
2755
2756 } else {
2757 res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len,
2758 ISIS_SNMP_ADJ_DATA_PROTO, &adj,
2759 &data_idx, &data, &data_len);
2760 if (!res)
2761 return NULL;
2762
2763 /* Copy the name out */
2764 memcpy(name, v->name, v->namelen * sizeof(oid));
2765
2766 /* Append index */
2767 name[v->namelen] = adj->circuit->snmp_id;
2768 name[v->namelen + 1] = adj->snmp_idx;
2769 name[v->namelen + 2] = data_idx;
2770
2771 /* Set length */
2772 *length = v->namelen + 3;
2773 }
2774
2775 switch (v->magic) {
2776 case ISIS_ISADJPROTSUPP_PROTOCOL:
2777 return SNMP_INTEGER(*data);
2778
2779 default:
2780 break;
2781 }
2782
2783 return NULL;
2784}
2785
2786
2787/* Register ISIS-MIB. */
2788static int isis_snmp_init(struct thread_master *tm)
2789{
2790 struct isis_func_to_prefix *h2f = isis_func_to_prefix_arr;
2791 struct variable *v;
2792
2793 for (size_t off = 0; off < isis_var_count; off++) {
2794 v = &isis_var_arr[off];
2795
2796 if (v->findVar != h2f->ihtp_func) {
2797 /* Next table */
2798 h2f++;
2799 assert(h2f < (isis_func_to_prefix_arr
2800 + isis_func_to_prefix_count));
2801 assert(v->findVar == h2f->ihtp_func);
2802 }
2803
2804 v->namelen = h2f->ihtp_pref_len + 1;
2805 memcpy(v->name, h2f->ihtp_pref_oid,
2806 h2f->ihtp_pref_len * sizeof(oid));
2807 v->name[h2f->ihtp_pref_len] = v->magic;
2808 }
2809
2810
2811 smux_init(tm);
2812 REGISTER_MIB("mibII/isis", isis_var_arr, variable, isis_oid);
2813 return 0;
2814}
2815
2816/*
2817 * ISIS notification functions: we have one function per notification
2818 */
2819static int isis_snmp_trap_throttle(oid trap_id)
2820{
2821 time_t time_now;
2822 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
2823
2824 if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
2825 return 0;
2826
2827 time_now = isis_snmp_time();
2828
2829 if ((isis_snmp_trap_timestamp[trap_id] + 5) > time_now)
2830 /* Throttle trap rate at 1 in 5 secs */
2831 return 0;
2832
2833 isis_snmp_trap_timestamp[trap_id] = time_now;
2834 return 1;
2835}
2836
2837static int isis_snmp_db_overload_update(const struct isis_area *area)
2838{
2839 netsnmp_variable_list *notification_vars;
2840 long val;
2841 uint32_t off;
2842
2843 if (!isis_snmp_trap_throttle(ISIS_TRAP_DB_OVERLOAD))
2844 return 0;
2845
2846 notification_vars = NULL;
2847
2848 /* Put in trap value */
2849 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
2850 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
2851 (uint8_t *)&isis_snmp_trap_val_db_overload,
2852 sizeof(isis_snmp_trap_val_db_overload));
2853
2854 /* Prepare data */
2855 val = area->is_type;
2856
2857 snmp_varlist_add_variable(
2858 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
2859 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
2860 (uint8_t *)&val, sizeof(val));
2861
2862 /* Patch sys_level_state with proper index */
2863 off = ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state) - 1;
2864 isis_snmp_trap_data_var_sys_level_state[off] = val;
2865
2866 /* Prepare data */
2867 if (area->overload_bit)
2868 val = ISIS_SNMP_LEVEL_STATE_OVERLOADED;
2869 else
2870 val = ISIS_SNMP_LEVEL_STATE_ON;
2871
2872 snmp_varlist_add_variable(
2873 &notification_vars, isis_snmp_trap_data_var_sys_level_state,
2874 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state), INTEGER,
2875 (uint8_t *)&val, sizeof(val));
2876
2877 send_v2trap(notification_vars);
2878 snmp_free_varbind(notification_vars);
2879 smux_events_update();
2880 return 0;
2881}
2882
2883static int isis_snmp_lsp_exceed_max_update(const struct isis_area *area,
2884 const uint8_t *lsp_id)
2885{
2886 netsnmp_variable_list *notification_vars;
2887 long val;
2888
2889 if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_EXCEED_MAX))
2890 return 0;
2891
2892 notification_vars = NULL;
2893
2894 /* Put in trap value */
2895 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
2896 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
2897 (uint8_t *)&isis_snmp_trap_val_lsp_exceed_max,
2898 sizeof(isis_snmp_trap_val_lsp_exceed_max));
2899
2900 /* Prepare data */
2901 val = area->is_type;
2902
2903 snmp_varlist_add_variable(
2904 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
2905 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
2906 (uint8_t *)&val, sizeof(val));
2907
2908 snmp_varlist_add_variable(
2909 &notification_vars, isis_snmp_trap_data_var_pdu_lsp_id,
2910 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
2911 ISIS_SYS_ID_LEN + 2);
2912
2913 send_v2trap(notification_vars);
2914 snmp_free_varbind(notification_vars);
2915 smux_events_update();
2916 return 0;
2917}
2918
2919
2920/*
2921 * A common function to handle popular combination of trap objects
2922 * isisNotificationSysLevelIndex,
2923 * optional-object-a
2924 * isisNotificationCircIfIndex,
2925 * optional-object-b
2926 */
2927static void isis_snmp_update_worker_a(const struct isis_circuit *circuit,
2928 oid trap_id, const oid *oid_a,
2929 size_t oid_a_len, uint8_t type_a,
2930 const void *data_a, size_t data_a_len,
2931 const oid *oid_b, size_t oid_b_len,
2932 uint8_t type_b, const void *data_b,
2933 size_t data_b_len)
2934{
2935 netsnmp_variable_list *notification_vars = NULL;
2936 oid var_name[MAX_OID_LEN];
2937 size_t var_count;
2938 long val;
2939
2940 /* Sanity */
2941 if (trap_id != ISIS_TRAP_ID_LEN_MISMATCH
2942 && trap_id != ISIS_TRAP_MAX_AREA_ADDR_MISMATCH
2943 && trap_id != ISIS_TRAP_OWN_LSP_PURGE
2944 && trap_id != ISIS_TRAP_SEQNO_SKIPPED
2945 && trap_id != ISIS_TRAP_AUTHEN_TYPE_FAILURE
2946 && trap_id != ISIS_TRAP_AUTHEN_FAILURE
2947 && trap_id != ISIS_TRAP_REJ_ADJACENCY)
2948 return;
2949
2950 /* Put in trap value */
2951 memcpy(var_name, isis_snmp_notifications,
2952 sizeof(isis_snmp_notifications));
2953 var_count = ARRAY_SIZE(isis_snmp_notifications);
2954 var_name[var_count++] = trap_id;
2955
2956 /* Put in trap value */
2957 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
2958 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
2959 (uint8_t *)var_name, var_count * sizeof(oid));
2960
2961 val = circuit->is_type;
2962 snmp_varlist_add_variable(
2963 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
2964 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
2965 (uint8_t *)&val, sizeof(val));
2966
2967 if (oid_a_len != 0) {
2968 if (oid_a == NULL || data_a == NULL || data_a_len == 0)
2969 return;
2970
2971 snmp_varlist_add_variable(&notification_vars, oid_a, oid_a_len,
2972 type_a, (uint8_t *)data_a,
2973 data_a_len);
2974 }
2975
2976 if (circuit->interface == NULL)
2977 val = 0;
2978 else
2979 val = circuit->interface->ifindex;
2980
2981 snmp_varlist_add_variable(
2982 &notification_vars, isis_snmp_trap_data_var_circ_if_index,
2983 ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
2984 (uint8_t *)&val, sizeof(val));
2985
2986
2987 if (oid_b_len != 0) {
2988 if (oid_b == NULL || data_b == NULL || data_b_len == 0)
2989 return;
2990
2991 snmp_varlist_add_variable(&notification_vars, oid_b, oid_b_len,
2992 type_b, (uint8_t *)data_b,
2993 data_b_len);
2994 }
2995
2996 send_v2trap(notification_vars);
2997 snmp_free_varbind(notification_vars);
2998 smux_events_update();
2999}
3000
3001/*
3002 * A common function to handle popular combination of trap objects
3003 * isisNotificationSysLevelIndex,
3004 * isisNotificationCircIfIndex,
3005 * optional-var-a
3006 * optional-var-b
3007 *
3008 * Note: the only difference with worker_a is order of circ-if-index vs
3009 * optional-var-a
3010 */
3011static void isis_snmp_update_worker_b(const struct isis_circuit *circuit,
3012 oid trap_id, const oid *oid_a,
3013 size_t oid_a_len, uint8_t type_a,
3014 const void *data_a, size_t data_a_len,
3015 const oid *oid_b, size_t oid_b_len,
3016 uint8_t type_b, const void *data_b,
3017 size_t data_b_len)
3018{
3019 netsnmp_variable_list *notification_vars = NULL;
3020 oid var_name[MAX_OID_LEN];
3021 size_t var_count;
3022 long val;
3023
3024 /* Sanity */
3025 if (trap_id != ISIS_TRAP_VERSION_SKEW
3026 && trap_id != ISIS_TRAP_LSP_TOO_LARGE
3027 && trap_id != ISIS_TRAP_ADJ_STATE_CHANGE)
3028 return;
3029
3030 /* Put in trap value */
3031 memcpy(var_name, isis_snmp_notifications,
3032 sizeof(isis_snmp_notifications));
3033 var_count = ARRAY_SIZE(isis_snmp_notifications);
3034 var_name[var_count++] = trap_id;
3035
3036 /* Put in trap value */
3037 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
3038 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
3039 (uint8_t *)var_name, var_count * sizeof(oid));
3040
3041 val = circuit->is_type;
3042 snmp_varlist_add_variable(
3043 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
3044 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
3045 (uint8_t *)&val, sizeof(val));
3046
3047 if (circuit->interface == NULL)
3048 val = 0;
3049 else
3050 val = circuit->interface->ifindex;
3051
3052 snmp_varlist_add_variable(
3053 &notification_vars, isis_snmp_trap_data_var_circ_if_index,
3054 ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
3055 (uint8_t *)&val, sizeof(val));
3056
3057
3058 if (oid_a_len != 0) {
3059 if (oid_a == NULL || data_a == NULL || data_a_len == 0)
3060 return;
3061
3062 snmp_varlist_add_variable(&notification_vars, oid_a, oid_a_len,
3063 type_a, (uint8_t *)data_a,
3064 data_a_len);
3065 }
3066
3067 if (oid_b_len != 0) {
3068 if (oid_b == NULL || data_b == NULL || data_b_len == 0)
3069 return;
3070
3071 snmp_varlist_add_variable(&notification_vars, oid_b, oid_b_len,
3072 type_b, (uint8_t *)data_b,
3073 data_b_len);
3074 }
3075
3076 send_v2trap(notification_vars);
3077 snmp_free_varbind(notification_vars);
3078 smux_events_update();
3079}
3080
3081
3082static int isis_snmp_id_len_mismatch_update(const struct isis_circuit *circuit,
3083 uint8_t rcv_id, const char *raw_pdu,
3084 size_t raw_pdu_len)
3085{
3086 long val;
3087
3088 if (!isis_snmp_trap_throttle(ISIS_TRAP_ID_LEN_MISMATCH))
3089 return 0;
3090
3091 val = rcv_id;
3092
3093 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3094 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3095
3096 isis_snmp_update_worker_a(
3097 circuit, ISIS_TRAP_ID_LEN_MISMATCH,
3098 isis_snmp_trap_data_var_pdu_field_len,
3099 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_field_len), UNSIGNED32,
3100 &val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment,
3101 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3102 raw_pdu, raw_pdu_len);
3103 return 0;
3104}
3105
3106static int
3107isis_snmp_max_area_addr_mismatch_update(const struct isis_circuit *circuit,
3108 uint8_t max_addrs, const char *raw_pdu,
3109 size_t raw_pdu_len)
3110{
3111 long val;
3112
3113 if (!isis_snmp_trap_throttle(ISIS_TRAP_MAX_AREA_ADDR_MISMATCH))
3114 return 0;
3115
3116 val = max_addrs;
3117
3118 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3119 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3120
3121 isis_snmp_update_worker_a(
3122 circuit, ISIS_TRAP_MAX_AREA_ADDR_MISMATCH,
3123 isis_snmp_trap_data_var_pdu_max_area_addr,
3124 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_max_area_addr),
3125 UNSIGNED32, &val, sizeof(val),
3126 isis_snmp_trap_data_var_pdu_fragment,
3127 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3128 raw_pdu, raw_pdu_len);
3129 return 0;
3130}
3131
3132static int isis_snmp_own_lsp_purge_update(const struct isis_circuit *circuit,
3133 const uint8_t *lsp_id)
3134{
3135 if (!isis_snmp_trap_throttle(ISIS_TRAP_OWN_LSP_PURGE))
3136 return 0;
3137
3138 isis_snmp_update_worker_a(
3139 circuit, ISIS_TRAP_OWN_LSP_PURGE, NULL, 0, STRING, NULL, 0,
3140 isis_snmp_trap_data_var_pdu_lsp_id,
3141 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3142 ISIS_SYS_ID_LEN + 2);
3143 return 0;
3144}
3145
3146static int isis_snmp_seqno_skipped_update(const struct isis_circuit *circuit,
3147 const uint8_t *lsp_id)
3148{
3149 if (!isis_snmp_trap_throttle(ISIS_TRAP_SEQNO_SKIPPED))
3150 return 0;
3151
3152 isis_snmp_update_worker_a(
3153 circuit, ISIS_TRAP_SEQNO_SKIPPED, NULL, 0, STRING, NULL, 0,
3154 isis_snmp_trap_data_var_pdu_lsp_id,
3155 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3156 ISIS_SYS_ID_LEN + 2);
3157 return 0;
3158}
3159
3160static int
3161isis_snmp_authentication_type_failure_update(const struct isis_circuit *circuit,
3162 const char *raw_pdu,
3163 size_t raw_pdu_len)
3164{
3165 if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_TYPE_FAILURE))
3166 return 0;
3167
3168 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3169 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3170
3171 isis_snmp_update_worker_a(
3172 circuit, ISIS_TRAP_AUTHEN_TYPE_FAILURE, NULL, 0, STRING, NULL,
3173 0, isis_snmp_trap_data_var_pdu_fragment,
3174 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3175 raw_pdu, raw_pdu_len);
3176 return 0;
3177}
3178
3179static int
3180isis_snmp_authentication_failure_update(const struct isis_circuit *circuit,
3181 char const *raw_pdu, size_t raw_pdu_len)
3182{
3183 if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_FAILURE))
3184 return 0;
3185
3186 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3187 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3188
3189 isis_snmp_update_worker_a(
3190 circuit, ISIS_TRAP_AUTHEN_FAILURE, NULL, 0, STRING, NULL, 0,
3191 isis_snmp_trap_data_var_pdu_fragment,
3192 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3193 raw_pdu, raw_pdu_len);
3194 return 0;
3195}
3196
3197static int isis_snmp_version_skew_update(const struct isis_circuit *circuit,
3198 uint8_t version, const char *raw_pdu,
3199 size_t raw_pdu_len)
3200{
3201 long val;
3202
3203 if (!isis_snmp_trap_throttle(ISIS_TRAP_VERSION_SKEW))
3204 return 0;
3205
3206 val = version;
3207
3208 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3209 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3210
3211 isis_snmp_update_worker_b(
3212 circuit, ISIS_TRAP_VERSION_SKEW,
3213 isis_snmp_trap_data_var_pdu_proto_ver,
3214 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_proto_ver), UNSIGNED32,
3215 &val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment,
3216 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3217 raw_pdu, raw_pdu_len);
3218 return 0;
3219}
3220
3221static int isis_snmp_area_mismatch_update(const struct isis_circuit *circuit,
3222 const char *raw_pdu,
3223 size_t raw_pdu_len)
3224{
3225 /*
3226 * This is a special case because
3227 * it does not include isisNotificationSysLevelIndex
3228 */
3229 netsnmp_variable_list *notification_vars;
3230 long val;
3231
3232 if (!isis_snmp_trap_throttle(ISIS_TRAP_AREA_MISMATCH))
3233 return 0;
3234
3235 notification_vars = NULL;
3236
3237 /* Put in trap value */
3238 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
3239 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
3240 (uint8_t *)&isis_snmp_trap_val_area_mismatch,
3241 sizeof(isis_snmp_trap_val_area_mismatch));
3242
3243
3244 if (circuit->interface == NULL)
3245 val = 0;
3246 else
3247 val = circuit->interface->ifindex;
3248
3249 snmp_varlist_add_variable(
3250 &notification_vars, isis_snmp_trap_data_var_circ_if_index,
3251 ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
3252 (uint8_t *)&val, sizeof(val));
3253
3254
3255 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3256 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3257
3258 snmp_varlist_add_variable(
3259 &notification_vars, isis_snmp_trap_data_var_pdu_fragment,
3260 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3261 raw_pdu, raw_pdu_len);
3262
3263 send_v2trap(notification_vars);
3264 snmp_free_varbind(notification_vars);
3265 smux_events_update();
3266
3267 return 0;
3268}
3269
3270static int isis_snmp_reject_adjacency_update(const struct isis_circuit *circuit,
3271 const char *raw_pdu,
3272 size_t raw_pdu_len)
3273{
3274 if (!isis_snmp_trap_throttle(ISIS_TRAP_REJ_ADJACENCY))
3275 return 0;
3276
3277 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3278 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3279
3280 isis_snmp_update_worker_a(
3281 circuit, ISIS_TRAP_REJ_ADJACENCY, NULL, 0, STRING, NULL, 0,
3282 isis_snmp_trap_data_var_pdu_fragment,
3283 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3284 raw_pdu, raw_pdu_len);
3285 return 0;
3286}
3287
3288static int isis_snmp_lsp_too_large_update(const struct isis_circuit *circuit,
3289 uint32_t pdu_size,
3290 const uint8_t *lsp_id)
3291{
3292 if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_TOO_LARGE))
3293 return 0;
3294
3295 isis_snmp_update_worker_b(
3296 circuit, ISIS_TRAP_LSP_TOO_LARGE,
3297 isis_snmp_trap_data_var_pdu_lsp_size,
3298 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_size), UNSIGNED32,
3299 &pdu_size, sizeof(pdu_size), isis_snmp_trap_data_var_pdu_lsp_id,
3300 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3301 ISIS_SYS_ID_LEN + 2);
3302 return 0;
3303}
3304
3305
3306static int isis_snmp_adj_state_change_update(const struct isis_adjacency *adj)
3307{
3308 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
3309 long val;
3310 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
3311
3312 if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
3313 return 0;
3314
3315 /* Prepare data */
3316 memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
3317 lsp_id[ISIS_SYS_ID_LEN] = 0;
3318 lsp_id[ISIS_SYS_ID_LEN + 1] = 0;
3319
3320 val = ISIS_SNMP_ADJ_STATE_DOWN;
3321
3322 switch (adj->adj_state) {
3323 case ISIS_ADJ_UNKNOWN:
3324 val = ISIS_SNMP_ADJ_STATE_DOWN;
3325 break;
3326
3327 case ISIS_ADJ_INITIALIZING:
3328 val = ISIS_SNMP_ADJ_STATE_INITIALIZING;
3329 break;
3330
3331 case ISIS_ADJ_UP:
3332 val = ISIS_SNMP_ADJ_STATE_UP;
3333 break;
3334
3335 case ISIS_ADJ_DOWN:
3336 val = ISIS_SNMP_ADJ_STATE_FAILED;
3337 break;
3338 }
3339
3340 isis_snmp_update_worker_b(
3341 adj->circuit, ISIS_TRAP_ADJ_STATE_CHANGE,
3342 isis_snmp_trap_data_var_pdu_lsp_id,
3343 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3344 ISIS_SYS_ID_LEN + 2, isis_snmp_trap_data_var_adj_state,
3345 ARRAY_SIZE(isis_snmp_trap_data_var_adj_state), INTEGER, &val,
3346 sizeof(val));
3347 return 0;
3348}
3349
3350static int isis_snmp_lsp_error_update(const struct isis_circuit *circuit,
3351 const uint8_t *lsp_id,
3352 char const *raw_pdu, size_t raw_pdu_len)
3353{
3354 /*
3355 * This is a special case because
3356 * it have more variables
3357 */
3358 netsnmp_variable_list *notification_vars;
3359 long val;
3360
3361 if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_ERROR))
3362 return 0;
3363
3364 notification_vars = NULL;
3365
3366 /* Put in trap value */
3367 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
3368 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
3369 (uint8_t *)&isis_snmp_trap_val_lsp_error,
3370 sizeof(isis_snmp_trap_val_lsp_error));
3371
3372 /* Prepare data */
3373 val = circuit->is_type;
3374
3375 snmp_varlist_add_variable(
3376 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
3377 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
3378 (uint8_t *)&val, sizeof(val));
3379
3380
3381 snmp_varlist_add_variable(
3382 &notification_vars, isis_snmp_trap_data_var_pdu_lsp_id,
3383 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3384 ISIS_SYS_ID_LEN + 2);
3385
3386 /* Prepare data */
3387 if (circuit->interface == NULL)
3388 val = 0;
3389 else
3390 val = circuit->interface->ifindex;
3391
3392 snmp_varlist_add_variable(
3393 &notification_vars, isis_snmp_trap_data_var_circ_if_index,
3394 ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
3395 (uint8_t *)&val, sizeof(val));
3396
3397 /* Prepare data */
3398 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3399 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3400
3401 snmp_varlist_add_variable(
3402 &notification_vars, isis_snmp_trap_data_var_pdu_fragment,
3403 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3404 raw_pdu, raw_pdu_len);
3405
3406 /* Prepare data */
3407 val = 0;
3408
3409 snmp_varlist_add_variable(
3410 &notification_vars, isis_snmp_trap_data_var_error_offset,
3411 ARRAY_SIZE(isis_snmp_trap_data_var_error_offset), UNSIGNED32,
3412 (uint8_t *)&val, sizeof(val));
3413
3414 /* Prepare data */
3415 val = 0;
3416
3417 snmp_varlist_add_variable(
3418 &notification_vars, isis_snmp_trap_data_var_error_tlv_type,
3419 ARRAY_SIZE(isis_snmp_trap_data_var_error_tlv_type), UNSIGNED32,
3420 (uint8_t *)&val, sizeof(val));
3421
3422 send_v2trap(notification_vars);
3423 snmp_free_varbind(notification_vars);
3424 smux_events_update();
3425 return 0;
3426}
3427
3428
3429static int isis_snmp_module_init(void)
3430{
3431 hook_register(isis_hook_db_overload, isis_snmp_db_overload_update);
3432 hook_register(isis_hook_lsp_exceed_max,
3433 isis_snmp_lsp_exceed_max_update);
3434 hook_register(isis_hook_id_len_mismatch,
3435 isis_snmp_id_len_mismatch_update);
3436 hook_register(isis_hook_max_area_addr_mismatch,
3437 isis_snmp_max_area_addr_mismatch_update);
3438 hook_register(isis_hook_own_lsp_purge, isis_snmp_own_lsp_purge_update);
3439 hook_register(isis_hook_seqno_skipped, isis_snmp_seqno_skipped_update);
3440 hook_register(isis_hook_authentication_type_failure,
3441 isis_snmp_authentication_type_failure_update);
3442 hook_register(isis_hook_authentication_failure,
3443 isis_snmp_authentication_failure_update);
3444 hook_register(isis_hook_version_skew, isis_snmp_version_skew_update);
3445 hook_register(isis_hook_area_mismatch, isis_snmp_area_mismatch_update);
3446 hook_register(isis_hook_reject_adjacency,
3447 isis_snmp_reject_adjacency_update);
3448 hook_register(isis_hook_lsp_too_large, isis_snmp_lsp_too_large_update);
3449 hook_register(isis_hook_adj_state_change,
3450 isis_snmp_adj_state_change_update);
3451 hook_register(isis_hook_lsp_error, isis_snmp_lsp_error_update);
3452
3453 hook_register(frr_late_init, isis_snmp_init);
3454 return 0;
3455}
3456
80413c20
DL
3457FRR_MODULE_SETUP(
3458 .name = "isis_snmp",
3459 .version = FRR_VERSION,
3460 .description = "isis AgentX SNMP module",
3461 .init = isis_snmp_module_init,
3462);