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