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