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