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