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