]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_snmp.c
Merge pull request #10355 from opensourcerouting/noisy-startup
[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 >= (adj->ipv4_address_count + adj->ll_ipv6_count))
1190 return 0;
1191
1192 if (data_off >= adj->ipv4_address_count) {
1193 data = (uint8_t *)&adj->ll_ipv6_addrs
1194 [data_off - adj->ipv4_address_count];
1195 data_len = sizeof(adj->ll_ipv6_addrs[0]);
1196 } else {
1197 data = (uint8_t *)&adj->ipv4_addresses[data_off];
1198 data_len = sizeof(adj->ipv4_addresses[0]);
1199 }
1200
1201 break;
1202
1203
1204 case ISIS_SNMP_ADJ_DATA_PROTO:
1205 if (data_off >= adj->nlpids.count)
1206 return 0;
1207
1208 data = &adj->nlpids.nlpids[data_off];
1209 data_len = sizeof(adj->nlpids.nlpids[0]);
1210 break;
1211
1212 default:
1213 assert(0);
1214 return 0;
1215 }
1216
1217 if (ret_data != NULL)
1218 *ret_data = data;
1219
1220 if (ret_data_len != NULL)
1221 *ret_data_len = data_len;
1222
1223 return 1;
1224 }
1225
1226 static int isis_snmp_adj_lookup_exact(oid *oid_idx, size_t oid_idx_len,
1227 int data_id,
1228 struct isis_adjacency **ret_adj,
1229 oid *ret_data_idx, uint8_t **ret_data,
1230 size_t *ret_data_len)
1231 {
1232 int res;
1233 struct listnode *node;
1234 struct isis_circuit *circuit;
1235 struct isis_adjacency *adj;
1236 struct isis_adjacency *tmp_adj;
1237 oid adj_idx;
1238 oid data_off;
1239 uint8_t *data;
1240 size_t data_len;
1241
1242 res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len, &circuit);
1243
1244 if (!res)
1245 return 0;
1246
1247 if (oid_idx == NULL || oid_idx_len < 2
1248 || (data_id != ISIS_SNMP_ADJ_DATA_NONE && oid_idx_len < 3))
1249 return 0;
1250
1251 adj_idx = oid_idx[1];
1252
1253 if (data_id != ISIS_SNMP_ADJ_DATA_NONE) {
1254 if (oid_idx[2] == 0)
1255 return 0;
1256
1257 data_off = oid_idx[2] - 1;
1258 } else {
1259 /*
1260 * Data-off is not used if data-id is none
1261 * but we set it just for consistency
1262 */
1263 data_off = 0;
1264 }
1265
1266 adj = NULL;
1267 data = NULL;
1268 data_len = 0;
1269
1270 for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node, tmp_adj)) {
1271 if (tmp_adj->snmp_idx > adj_idx) {
1272 /*
1273 * Adjacencies are ordered in the list
1274 * no point to look further
1275 */
1276 break;
1277 }
1278
1279 if (tmp_adj->snmp_idx == adj_idx) {
1280 res = isis_snmp_adj_helper(tmp_adj, data_id, data_off,
1281 &data, &data_len);
1282 if (res)
1283 adj = tmp_adj;
1284
1285 break;
1286 }
1287 }
1288
1289 if (adj == NULL)
1290 return 0;
1291
1292 if (ret_adj != NULL)
1293 *ret_adj = adj;
1294
1295 if (ret_data_idx != NULL)
1296 *ret_data_idx = data_off + 1;
1297
1298 if (ret_data)
1299 *ret_data = data;
1300
1301 if (ret_data_len)
1302 *ret_data_len = data_len;
1303
1304 return 1;
1305 }
1306
1307 static int isis_snmp_adj_lookup_next(oid *oid_idx, size_t oid_idx_len,
1308 int data_id,
1309 struct isis_adjacency **ret_adj,
1310 oid *ret_data_idx, uint8_t **ret_data,
1311 size_t *ret_data_len)
1312 {
1313 struct listnode *node;
1314 struct isis_circuit *circuit;
1315 struct isis_adjacency *adj;
1316 struct isis_adjacency *tmp_adj;
1317 oid circ_idx;
1318 oid adj_idx;
1319 oid data_idx;
1320 uint8_t *data;
1321 size_t data_len;
1322
1323 adj = NULL;
1324 data = NULL;
1325 data_len = 0;
1326
1327 /*
1328 * Note: we rely on the fact that data indexes are consequtive
1329 * starting from 1
1330 */
1331
1332 if (oid_idx == 0 || oid_idx_len == 0) {
1333 circ_idx = 0;
1334 adj_idx = 0;
1335 data_idx = 0;
1336 } else if (oid_idx_len == 1) {
1337 circ_idx = oid_idx[0];
1338 adj_idx = 0;
1339 data_idx = 0;
1340 } else if (oid_idx_len == 2) {
1341 circ_idx = oid_idx[0];
1342 adj_idx = oid_idx[1];
1343 data_idx = 0;
1344 } else {
1345 circ_idx = oid_idx[0];
1346 adj_idx = oid_idx[1];
1347
1348 if (data_id == ISIS_SNMP_ADJ_DATA_NONE)
1349 data_idx = 0;
1350 else
1351 data_idx = oid_idx[2];
1352 }
1353
1354 if (!isis_snmp_circuit_lookup_exact(&circ_idx, 1, &circuit)
1355 && !isis_snmp_circuit_lookup_next(&circ_idx, 1, &circuit))
1356 /* No circuit */
1357 return 0;
1358
1359 if (circuit->snmp_id != circ_idx) {
1360 /* Match is not exact */
1361 circ_idx = 0;
1362 adj_idx = 0;
1363 data_idx = 0;
1364 }
1365
1366 /*
1367 * Note: the simple loop below will work in all cases
1368 */
1369 while (circuit != NULL) {
1370 for (ALL_LIST_ELEMENTS_RO(circuit->snmp_adj_list, node,
1371 tmp_adj)) {
1372 if (tmp_adj->snmp_idx < adj_idx)
1373 continue;
1374
1375 if (tmp_adj->snmp_idx == adj_idx
1376 && data_id == ISIS_SNMP_ADJ_DATA_NONE)
1377 continue;
1378
1379 if (adj_idx != 0 && tmp_adj->snmp_idx > adj_idx)
1380 data_idx = 0;
1381
1382 if (isis_snmp_adj_helper(tmp_adj, data_id, data_idx,
1383 &data, &data_len)) {
1384 adj = tmp_adj;
1385 break;
1386 }
1387 }
1388
1389 if (adj != NULL)
1390 break;
1391
1392 circuit = isis_snmp_circuit_next(circuit);
1393 circ_idx = 0;
1394 adj_idx = 0;
1395 data_idx = 0;
1396 }
1397
1398 if (adj == NULL)
1399 return 0;
1400
1401 if (ret_adj != NULL)
1402 *ret_adj = adj;
1403
1404 if (ret_data_idx != 0) {
1405 if (data_id == ISIS_SNMP_ADJ_DATA_NONE)
1406 /*
1407 * Value does not matter but let us set
1408 * it to zero for consistency
1409 */
1410 *ret_data_idx = 0;
1411 else
1412 *ret_data_idx = data_idx + 1;
1413 }
1414
1415 if (ret_data != 0)
1416 *ret_data = data;
1417
1418 if (ret_data_len != 0)
1419 *ret_data_len = data_len;
1420
1421 return 1;
1422 }
1423
1424 static uint8_t *isis_snmp_find_sys_object(struct variable *v, oid *name,
1425 size_t *length, int exact,
1426 size_t *var_len,
1427 WriteMethod **write_method)
1428 {
1429 struct isis_area *area = NULL;
1430 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
1431
1432 if (isis == NULL)
1433 return NULL;
1434
1435 if (!list_isempty(isis->area_list))
1436 area = listgetdata(listhead(isis->area_list));
1437
1438 /* Check whether the instance identifier is valid */
1439 if (smux_header_generic(v, name, length, exact, var_len, write_method)
1440 == MATCH_FAILED)
1441 return NULL;
1442
1443 switch (v->magic) {
1444 case ISIS_SYS_VERSION:
1445 return SNMP_INTEGER(ISIS_VERSION);
1446
1447 case ISIS_SYS_LEVELTYPE:
1448 /*
1449 * If we do not have areas use 1&2 otherwise use settings
1450 * from the first area in the list
1451 */
1452 if (area == NULL)
1453 return SNMP_INTEGER(IS_LEVEL_1_AND_2);
1454
1455 return SNMP_INTEGER(area->is_type);
1456
1457 case ISIS_SYS_ID:
1458 if (!isis->sysid_set) {
1459 *var_len = ISIS_SYS_ID_LEN;
1460 return isis_null_sysid;
1461 }
1462
1463 *var_len = ISIS_SYS_ID_LEN;
1464 return isis->sysid;
1465
1466 case ISIS_SYS_MAXPATHSPLITS:
1467 return SNMP_INTEGER(ISIS_SNMP_MAX_PATH_SPLITS);
1468
1469 case ISIS_SYS_MAXLSPGENINT:
1470 return SNMP_INTEGER(DEFAULT_MAX_LSP_GEN_INTERVAL);
1471
1472 case ISIS_SYS_POLLESHELLORATE:
1473 return SNMP_INTEGER(DEFAULT_HELLO_INTERVAL);
1474
1475 case ISIS_SYS_WAITTIME:
1476 /* Note: it seems that we have same fixed delay time */
1477 return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL);
1478
1479 case ISIS_SYS_ADMINSTATE:
1480 /* If daemon is running it admin state is on */
1481 return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON);
1482
1483
1484 case ISIS_SYS_L2TOL1LEAKING:
1485 /* We do not allow l2-to-l1 leaking */
1486 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
1487
1488 case ISIS_SYS_MAXAGE:
1489 return SNMP_INTEGER(MAX_AGE);
1490
1491 case ISIS_SYS_RECEIVELSPBUFFERSIZE:
1492 if (area == NULL)
1493 return SNMP_INTEGER(DEFAULT_LSP_MTU);
1494
1495 return SNMP_INTEGER(area->lsp_mtu);
1496
1497 case ISIS_SYS_PROTSUPPORTED:
1498 *var_len = 1;
1499 return &isis_snmp_protocols_supported;
1500
1501 case ISIS_SYS_NOTIFICATIONENABLE:
1502 if (isis->snmp_notifications)
1503 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
1504
1505 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
1506
1507 default:
1508 break;
1509 }
1510
1511 return NULL;
1512 }
1513
1514
1515 static uint8_t *isis_snmp_find_man_area(struct variable *v, oid *name,
1516 size_t *length, int exact,
1517 size_t *var_len,
1518 WriteMethod **write_method)
1519 {
1520 int res;
1521 struct area_addr *area_addr = NULL;
1522 oid *oid_idx;
1523 size_t oid_idx_len;
1524 size_t off = 0;
1525
1526 *write_method = NULL;
1527
1528 if (*length <= v->namelen) {
1529 oid_idx = NULL;
1530 oid_idx_len = 0;
1531 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
1532 oid_idx = NULL;
1533 oid_idx_len = 0;
1534 } else {
1535 oid_idx = name + v->namelen;
1536 oid_idx_len = *length - v->namelen;
1537 }
1538
1539 if (exact) {
1540 res = isis_snmp_area_addr_lookup_exact(oid_idx, oid_idx_len,
1541 NULL, &area_addr);
1542
1543 if (!res)
1544 return NULL;
1545
1546 } else {
1547 res = isis_snmp_area_addr_lookup_next(oid_idx, oid_idx_len,
1548 NULL, &area_addr);
1549
1550 if (!res)
1551 return NULL;
1552
1553 /* Copy the name out */
1554 memcpy(name, v->name, v->namelen * sizeof(oid));
1555
1556 /* Append index */
1557 name[v->namelen] = area_addr->addr_len;
1558
1559 for (off = 0; off < area_addr->addr_len; off++)
1560 name[v->namelen + 1 + off] = area_addr->area_addr[off];
1561
1562 *length = v->namelen + 1 + area_addr->addr_len;
1563 }
1564
1565 switch (v->magic) {
1566 case ISIS_MANAREA_ADDREXISTSTATE:
1567 return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE);
1568
1569 default:
1570 break;
1571 }
1572
1573 return NULL;
1574 }
1575
1576 static uint8_t *isis_snmp_find_area_addr(struct variable *v, oid *name,
1577 size_t *length, int exact,
1578 size_t *var_len,
1579 WriteMethod **write_method)
1580 {
1581 /*
1582 * Area addresses in sense of addresses reported by L1 lsps
1583 * are not supported yet.
1584 */
1585 (void)v;
1586 (void)name;
1587 (void)length;
1588 (void)exact;
1589 (void)var_len;
1590
1591
1592 *write_method = NULL;
1593
1594 return NULL;
1595 }
1596
1597 static uint8_t *isis_snmp_find_summ_addr(struct variable *v, oid *name,
1598 size_t *length, int exact,
1599 size_t *var_len,
1600 WriteMethod **write_method)
1601 {
1602 /*
1603 * So far there is no way to set summary table values through cli
1604 * and snmp operations are read-only, hence there are no entries
1605 */
1606 (void)v;
1607 (void)name;
1608 (void)length;
1609 (void)exact;
1610 (void)var_len;
1611 *write_method = NULL;
1612
1613 return NULL;
1614 }
1615
1616 static uint8_t *isis_snmp_find_redistribute_addr(struct variable *v, oid *name,
1617 size_t *length, int exact,
1618 size_t *var_len,
1619 WriteMethod **write_method)
1620 {
1621 /*
1622 * It is not clear at the point whether redist code in isis is actually
1623 * used for now we will consider that entries are not present
1624 */
1625 (void)v;
1626 (void)name;
1627 (void)length;
1628 (void)exact;
1629 (void)var_len;
1630 *write_method = NULL;
1631
1632 return NULL;
1633 }
1634
1635 static uint8_t *isis_snmp_find_router(struct variable *v, oid *name,
1636 size_t *length, int exact,
1637 size_t *var_len,
1638 WriteMethod **write_method)
1639 {
1640 uint8_t cmp_buf[ISIS_SYS_ID_LEN];
1641 size_t cmp_len;
1642 int try_exact;
1643 int cmp_level;
1644 int res;
1645 struct isis_dynhn *dyn = NULL;
1646 oid *oid_idx;
1647 size_t oid_idx_len;
1648 size_t off = 0;
1649 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
1650
1651 if (isis == NULL)
1652 return NULL;
1653
1654 *write_method = NULL;
1655
1656 if (*length <= v->namelen) {
1657 oid_idx = NULL;
1658 oid_idx_len = 0;
1659 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
1660 oid_idx = NULL;
1661 oid_idx_len = 0;
1662 } else {
1663 oid_idx = name + v->namelen;
1664 oid_idx_len = *length - v->namelen;
1665 }
1666
1667 if (exact) {
1668 res = isis_snmp_conv_exact(cmp_buf, sizeof(cmp_buf), &cmp_len,
1669 oid_idx, oid_idx_len);
1670
1671 if (!res || cmp_len != ISIS_SYS_ID_LEN
1672 || oid_idx_len != (cmp_len + 2))
1673 /*
1674 * Bad conversion, or bad length,
1675 * or extra oids at the end
1676 */
1677 return NULL;
1678
1679 if (oid_idx[ISIS_SYS_ID_LEN + 1] < IS_LEVEL_1
1680 || oid_idx[ISIS_SYS_ID_LEN + 1] > IS_LEVEL_2)
1681 /* Level part of the index is out of range */
1682 return NULL;
1683
1684 cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
1685
1686 dyn = dynhn_find_by_id(isis, cmp_buf);
1687
1688 if (dyn == NULL || dyn->level != cmp_level)
1689 return NULL;
1690
1691 switch (v->magic) {
1692 case ISIS_ROUTER_HOSTNAME:
1693 *var_len = strlen(dyn->hostname);
1694 return (uint8_t *)dyn->hostname;
1695
1696 case ISIS_ROUTER_ID:
1697 /* It seems that we do no know router-id in lsps */
1698 return SNMP_INTEGER(0);
1699
1700 default:
1701 break;
1702 }
1703
1704 return NULL;
1705 }
1706
1707 res = isis_snmp_conv_next(cmp_buf, sizeof(cmp_buf), &cmp_len,
1708 &try_exact, oid_idx, oid_idx_len);
1709
1710
1711 if (!res)
1712 /* Bad conversion */
1713 return NULL;
1714
1715 if (cmp_len != ISIS_SYS_ID_LEN) {
1716 /* We do not have valid index oids */
1717 memset(cmp_buf, 0, sizeof(cmp_buf));
1718 cmp_level = 0;
1719 } else if (try_exact)
1720 /*
1721 * We have no valid level index.
1722 * Let start from non-existing level 0 and
1723 * hence not need to do exact match
1724 */
1725 cmp_level = 0;
1726 else if (oid_idx_len < (ISIS_SYS_ID_LEN + 2))
1727 cmp_level = 0;
1728 else if (oid_idx[ISIS_SYS_ID_LEN + 1] <= IS_LEVEL_2)
1729 cmp_level = (int)oid_idx[ISIS_SYS_ID_LEN + 1];
1730 else
1731 /*
1732 * Any value greater than 2 will have the same result
1733 * but we can have integer overflows, hence 3 is a reasonable
1734 * choice
1735 */
1736 cmp_level = (int)(IS_LEVEL_2 + 1);
1737
1738 dyn = dynhn_snmp_next(isis, cmp_buf, cmp_level);
1739
1740 if (dyn == NULL)
1741 return NULL;
1742
1743 /* Copy the name out */
1744 memcpy(name, v->name, v->namelen * sizeof(oid));
1745
1746 /* Append index */
1747 name[v->namelen] = ISIS_SYS_ID_LEN;
1748
1749 for (off = 0; off < ISIS_SYS_ID_LEN; off++)
1750 name[v->namelen + 1 + off] = dyn->id[off];
1751
1752 name[v->namelen + 1 + ISIS_SYS_ID_LEN] = (oid)dyn->level;
1753
1754 /* Set length */
1755 *length = v->namelen + 1 + ISIS_SYS_ID_LEN + 1;
1756
1757 switch (v->magic) {
1758 case ISIS_ROUTER_HOSTNAME:
1759 *var_len = strlen(dyn->hostname);
1760 return (uint8_t *)dyn->hostname;
1761
1762 case ISIS_ROUTER_ID:
1763 /* It seems that we do no know router-id in lsps */
1764 return SNMP_INTEGER(0);
1765
1766 default:
1767 break;
1768 }
1769
1770 return NULL;
1771 }
1772
1773 static uint8_t *isis_snmp_find_sys_level(struct variable *v, oid *name,
1774 size_t *length, int exact,
1775 size_t *var_len,
1776 WriteMethod **write_method)
1777 {
1778 oid *oid_idx;
1779 size_t oid_idx_len;
1780 int level;
1781 int level_match;
1782 struct isis_area *area = NULL;
1783 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
1784
1785 if (isis == NULL)
1786 return NULL;
1787
1788 *write_method = NULL;
1789
1790 if (*length <= v->namelen) {
1791 oid_idx = NULL;
1792 oid_idx_len = 0;
1793 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
1794 oid_idx = NULL;
1795 oid_idx_len = 0;
1796 } else {
1797 oid_idx = name + v->namelen;
1798 oid_idx_len = *length - v->namelen;
1799 }
1800
1801 if (exact) {
1802 if (oid_idx == NULL || oid_idx_len != 1)
1803 return NULL;
1804
1805 if (oid_idx[0] == IS_LEVEL_1)
1806 level = IS_LEVEL_1;
1807 else if (oid_idx[0] == IS_LEVEL_2)
1808 level = IS_LEVEL_2;
1809 else
1810 return NULL;
1811
1812 } else {
1813 if (oid_idx == NULL)
1814 level = IS_LEVEL_1;
1815 else if (oid_idx_len == 0)
1816 level = IS_LEVEL_1;
1817 else if (oid_idx[0] < IS_LEVEL_1)
1818 level = IS_LEVEL_1;
1819 else if (oid_idx[0] < IS_LEVEL_2)
1820 level = IS_LEVEL_2;
1821 else
1822 return NULL;
1823
1824 /* Copy the name out */
1825 memcpy(name, v->name, v->namelen * sizeof(oid));
1826
1827 /* Append index */
1828 name[v->namelen] = level;
1829
1830 /* Set length */
1831 *length = v->namelen + 1;
1832 }
1833
1834 area = NULL;
1835
1836 if (!list_isempty(isis->area_list))
1837 area = listgetdata(listhead(isis->area_list));
1838
1839 level_match = 0;
1840
1841 if (area != NULL)
1842 level_match = isis_snmp_get_level_match(area->is_type, level);
1843
1844 switch (v->magic) {
1845 case ISIS_SYSLEVEL_ORIGLSPBUFFSIZE:
1846 if (level_match)
1847 return SNMP_INTEGER(area->lsp_mtu);
1848
1849 return SNMP_INTEGER(DEFAULT_LSP_MTU);
1850
1851 case ISIS_SYSLEVEL_MINLSPGENINT:
1852 if (level_match)
1853 return SNMP_INTEGER(area->lsp_gen_interval[level - 1]);
1854 else
1855 return SNMP_INTEGER(DEFAULT_MIN_LSP_GEN_INTERVAL);
1856
1857 case ISIS_SYSLEVEL_STATE:
1858 if (level_match) {
1859 if (area->overload_bit)
1860 return SNMP_INTEGER(
1861 ISIS_SNMP_LEVEL_STATE_OVERLOADED);
1862
1863 return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_ON);
1864 }
1865 return SNMP_INTEGER(ISIS_SNMP_LEVEL_STATE_OFF);
1866
1867 case ISIS_SYSLEVEL_SETOVERLOAD:
1868 if (level_match && area->overload_bit)
1869 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
1870
1871 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
1872
1873 case ISIS_SYSLEVEL_SETOVERLOADUNTIL:
1874 /* We do not have automatic cleanup of overload bit */
1875 return SNMP_INTEGER(0);
1876
1877 case ISIS_SYSLEVEL_METRICSTYLE:
1878 if (level_match) {
1879 if (area->newmetric && area->oldmetric)
1880 return SNMP_INTEGER(
1881 ISIS_SNMP_METRIC_STYLE_BOTH);
1882
1883 if (area->newmetric)
1884 return SNMP_INTEGER(
1885 ISIS_SNMP_METRIC_STYLE_WIDE);
1886
1887 return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW);
1888 }
1889 return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_NARROW);
1890
1891 case ISIS_SYSLEVEL_SPFCONSIDERS:
1892 return SNMP_INTEGER(ISIS_SNMP_METRIC_STYLE_BOTH);
1893
1894 case ISIS_SYSLEVEL_TEENABLED:
1895 if (level_match && IS_MPLS_TE(area->mta))
1896 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
1897
1898 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
1899
1900 default:
1901 break;
1902 }
1903
1904 return NULL;
1905 }
1906
1907 static uint8_t *isis_snmp_find_system_counter(struct variable *v, oid *name,
1908 size_t *length, int exact,
1909 size_t *var_len,
1910 WriteMethod **write_method)
1911 {
1912 oid *oid_idx;
1913 size_t oid_idx_len;
1914 int level;
1915 int level_match;
1916 struct isis_area *area = NULL;
1917 uint32_t val;
1918 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
1919
1920 if (isis == NULL)
1921 return NULL;
1922
1923 *write_method = NULL;
1924
1925 if (*length <= v->namelen) {
1926 oid_idx = NULL;
1927 oid_idx_len = 0;
1928 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
1929 oid_idx = NULL;
1930 oid_idx_len = 0;
1931 } else {
1932 oid_idx = name + v->namelen;
1933 oid_idx_len = *length - v->namelen;
1934 }
1935
1936 if (exact) {
1937 if (oid_idx == NULL || oid_idx_len != 1)
1938 return 0;
1939
1940 if (oid_idx[0] == IS_LEVEL_1)
1941 level = IS_LEVEL_1;
1942 else if (oid_idx[0] == IS_LEVEL_2)
1943 level = IS_LEVEL_2;
1944 else
1945 return NULL;
1946
1947 } else {
1948 if (oid_idx == NULL)
1949 level = IS_LEVEL_1;
1950 else if (oid_idx_len == 0)
1951 level = IS_LEVEL_1;
1952 else if (oid_idx[0] < IS_LEVEL_1)
1953 level = IS_LEVEL_1;
1954 else if (oid_idx[0] < IS_LEVEL_2)
1955 level = IS_LEVEL_2;
1956 else
1957 return NULL;
1958
1959 /* Copy the name out */
1960 memcpy(name, v->name, v->namelen * sizeof(oid));
1961
1962 /* Append index */
1963 name[v->namelen] = level;
1964
1965 /* Set length */
1966 *length = v->namelen + 1;
1967 }
1968
1969 area = NULL;
1970
1971 if (!list_isempty(isis->area_list))
1972 area = listgetdata(listhead(isis->area_list));
1973
1974 level_match = 0;
1975
1976 if (area != NULL)
1977 level_match = isis_snmp_get_level_match(area->is_type, level);
1978
1979 if (!level_match)
1980 /* If level does not match all counters are zeros */
1981 return SNMP_INTEGER(0);
1982
1983 switch (v->magic) {
1984 case ISIS_SYSSTAT_CORRLSPS:
1985 val = 0;
1986 break;
1987
1988 case ISIS_SYSSTAT_AUTHTYPEFAILS:
1989 val = (uint32_t)area->auth_type_failures[level - 1];
1990 break;
1991
1992 case ISIS_SYSSTAT_AUTHFAILS:
1993 val = (uint32_t)area->auth_failures[level - 1];
1994 break;
1995
1996 case ISIS_SYSSTAT_LSPDBASEOLOADS:
1997 val = area->overload_counter;
1998 break;
1999
2000 case ISIS_SYSSTAT_MANADDRDROPFROMAREAS:
2001 /* We do not support manual addresses */
2002 val = 0;
2003 break;
2004
2005 case ISIS_SYSSTAT_ATTMPTTOEXMAXSEQNUMS:
2006 val = area->lsp_exceeded_max_counter;
2007 break;
2008
2009 case ISIS_SYSSTAT_SEQNUMSKIPS:
2010 val = area->lsp_seqno_skipped_counter;
2011 break;
2012
2013 case ISIS_SYSSTAT_OWNLSPPURGES:
2014 if (!area->purge_originator)
2015 val = 0;
2016 else
2017 val = area->lsp_purge_count[level - 1];
2018 break;
2019
2020 case ISIS_SYSSTAT_IDFIELDLENMISMATCHES:
2021 val = (uint32_t)area->id_len_mismatches[level - 1];
2022 break;
2023
2024 case ISIS_SYSSTAT_PARTCHANGES:
2025 /* Not supported */
2026 val = 0;
2027 break;
2028
2029 case ISIS_SYSSTAT_SPFRUNS:
2030 val = (uint32_t)area->spf_run_count[level - 1];
2031 break;
2032
2033 case ISIS_SYSSTAT_LSPERRORS:
2034 val = (uint32_t)area->lsp_error_counter[level - 1];
2035 break;
2036
2037 default:
2038 return NULL;
2039 }
2040
2041 return SNMP_INTEGER(val);
2042 }
2043
2044 static uint8_t *isis_snmp_find_next_circ_index(struct variable *v, oid *name,
2045 size_t *length, int exact,
2046 size_t *var_len,
2047 WriteMethod **write_method)
2048 {
2049 /* Check whether the instance identifier is valid */
2050 if (smux_header_generic(v, name, length, exact, var_len, write_method)
2051 == MATCH_FAILED)
2052 return NULL;
2053
2054 switch (v->magic) {
2055 case ISIS_NEXTCIRC_INDEX:
2056 /*
2057 * We do not support circuit creation through snmp
2058 */
2059 return SNMP_INTEGER(0);
2060
2061 default:
2062 break;
2063 }
2064
2065 return 0;
2066 }
2067
2068 static uint8_t *isis_snmp_find_circ(struct variable *v, oid *name,
2069 size_t *length, int exact, size_t *var_len,
2070 WriteMethod **write_method)
2071 {
2072 /* Index is circuit-id: 1-255 */
2073 oid *oid_idx;
2074 size_t oid_idx_len;
2075 struct isis_circuit *circuit;
2076 uint32_t up_ticks;
2077 uint32_t delta_ticks;
2078 time_t now_time;
2079 int res;
2080
2081 *write_method = NULL;
2082
2083 if (*length <= v->namelen) {
2084 oid_idx = NULL;
2085 oid_idx_len = 0;
2086 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2087 oid_idx = NULL;
2088 oid_idx_len = 0;
2089 } else {
2090 oid_idx = name + v->namelen;
2091 oid_idx_len = *length - v->namelen;
2092 }
2093 if (exact) {
2094 res = isis_snmp_circuit_lookup_exact(oid_idx, oid_idx_len,
2095 &circuit);
2096
2097 if (!res || oid_idx_len != 1)
2098 return NULL;
2099
2100 } else {
2101 res = isis_snmp_circuit_lookup_next(oid_idx, oid_idx_len,
2102 &circuit);
2103
2104 if (!res)
2105 return NULL;
2106
2107 /* Copy the name out */
2108 memcpy(name, v->name, v->namelen * sizeof(oid));
2109
2110 /* Append index */
2111 name[v->namelen] = circuit->snmp_id;
2112
2113 /* Set length */
2114 *length = v->namelen + 1;
2115 }
2116
2117 switch (v->magic) {
2118 case ISIS_CIRC_IFINDEX:
2119 if (circuit->interface == 0)
2120 return SNMP_INTEGER(0);
2121
2122 return SNMP_INTEGER(circuit->interface->ifindex);
2123
2124 case ISIS_CIRC_ADMINSTATE:
2125 return SNMP_INTEGER(ISIS_SNMP_ADMIN_STATE_ON);
2126
2127 case ISIS_CIRC_EXISTSTATE:
2128 return SNMP_INTEGER(ISIS_SNMP_ROW_STATUS_ACTIVE);
2129
2130 case ISIS_CIRC_TYPE:
2131 /*
2132 * Note: values do not match 100%:
2133 *
2134 * 1. From isis_circuit.h:
2135 * CIRCUIT_T_UNKNOWN 0
2136 * CIRCUIT_T_BROADCAST 1
2137 * CIRCUIT_T_P2P 2
2138 * CIRCUIT_T_LOOPBACK 3
2139 *
2140 * 2. From rfc:
2141 * broadcast(1),
2142 * ptToPt(2),
2143 * staticIn(3),
2144 * staticOut(4),
2145 */
2146
2147 return SNMP_INTEGER(circuit->circ_type);
2148
2149 case ISIS_CIRC_EXTDOMAIN:
2150 if (circuit->ext_domain)
2151 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
2152
2153 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
2154
2155 case ISIS_CIRC_LEVELTYPE:
2156 return SNMP_INTEGER(circuit->is_type);
2157
2158 case ISIS_CIRC_PASSIVECIRCUIT:
2159 if (circuit->is_passive)
2160 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
2161
2162 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
2163
2164 case ISIS_CIRC_MESHGROUPENABLED:
2165 /* Not supported */
2166 return SNMP_INTEGER(ISIS_SNMP_MESH_GROUP_INACTIVE);
2167
2168 case ISIS_CIRC_MESHGROUP:
2169 /* Not supported */
2170 return SNMP_INTEGER(0);
2171
2172 case ISIS_CIRC_SMALLHELLOS:
2173 /*
2174 * return false if lan hellos must be padded
2175 */
2176 if (circuit->pad_hellos)
2177 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
2178
2179 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_TRUE);
2180
2181 case ISIS_CIRC_LASTUPTIME:
2182 if (circuit->last_uptime == 0)
2183 return SNMP_INTEGER(0);
2184
2185 up_ticks = (uint32_t)netsnmp_get_agent_uptime();
2186 now_time = time(NULL);
2187
2188 if (circuit->last_uptime >= now_time)
2189 return SNMP_INTEGER(up_ticks);
2190
2191 delta_ticks = (now_time - circuit->last_uptime) * 10;
2192
2193 if (up_ticks < delta_ticks)
2194 return SNMP_INTEGER(up_ticks);
2195
2196 return SNMP_INTEGER(up_ticks - delta_ticks);
2197
2198 case ISIS_CIRC_3WAYENABLED:
2199 /* Not supported */
2200 return SNMP_INTEGER(ISIS_SNMP_TRUTH_VALUE_FALSE);
2201
2202 case ISIS_CIRC_EXTENDEDCIRCID:
2203 /* Used for 3-way hand shake only */
2204 return SNMP_INTEGER(0);
2205
2206 default:
2207 break;
2208 }
2209
2210 return NULL;
2211 }
2212
2213 static uint8_t *isis_snmp_find_circ_level(struct variable *v, oid *name,
2214 size_t *length, int exact,
2215 size_t *var_len,
2216 WriteMethod **write_method)
2217 {
2218 static uint8_t circuit_id_val[ISIS_SYS_ID_LEN + 1];
2219 /* Index is circuit-id: 1-255 + level: 1-2 */
2220 oid *oid_idx;
2221 size_t oid_idx_len;
2222 int res;
2223 struct isis_circuit *circuit;
2224 int level;
2225 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
2226
2227 if (isis == NULL)
2228 return NULL;
2229
2230 *write_method = NULL;
2231
2232 if (*length <= v->namelen) {
2233 oid_idx = NULL;
2234 oid_idx_len = 0;
2235 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2236 oid_idx = NULL;
2237 oid_idx_len = 0;
2238 } else {
2239 oid_idx = name + v->namelen;
2240 oid_idx_len = *length - v->namelen;
2241 }
2242 if (exact) {
2243 res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len,
2244 1, &circuit, &level);
2245
2246 if (!res || oid_idx_len != 2)
2247 return NULL;
2248
2249 } else {
2250 res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len,
2251 1, &circuit, &level);
2252
2253 if (!res)
2254 return NULL;
2255
2256 /* Copy the name out */
2257 memcpy(name, v->name, v->namelen * sizeof(oid));
2258
2259 /* Append index */
2260 name[v->namelen] = circuit->snmp_id;
2261 name[v->namelen + 1] = level;
2262
2263 /* Set length */
2264 *length = v->namelen + 2;
2265 }
2266
2267 switch (v->magic) {
2268 case ISIS_CIRCLEVEL_METRIC:
2269 return SNMP_INTEGER(circuit->metric[level - 1]);
2270
2271 case ISIS_CIRCLEVEL_WIDEMETRIC:
2272 if (circuit->area == NULL || !circuit->area->newmetric) {
2273 /* What should we do if wide metric is not supported? */
2274 return SNMP_INTEGER(0);
2275 }
2276 return SNMP_INTEGER(circuit->te_metric[level - 1]);
2277
2278 case ISIS_CIRCLEVEL_ISPRIORITY:
2279 return SNMP_INTEGER(circuit->priority[level - 1]);
2280
2281 case ISIS_CIRCLEVEL_IDOCTET:
2282 return SNMP_INTEGER(circuit->circuit_id);
2283
2284 case ISIS_CIRCLEVEL_ID:
2285 if (circuit->circ_type != CIRCUIT_T_P2P) {
2286 /*
2287 * Unless it is point-to-point circuit, the value is and
2288 * empty octet string
2289 */
2290 *var_len = 0;
2291 return circuit_id_val;
2292 }
2293
2294 /* !!!!!! Circuit-id is zero for p2p links */
2295 if (circuit->u.p2p.neighbor == NULL
2296 || circuit->u.p2p.neighbor->adj_state != ISIS_ADJ_UP) {
2297 /* No adjacency or adjacency not fully up yet */
2298 memcpy(circuit_id_val, isis->sysid, ISIS_SYS_ID_LEN);
2299 circuit_id_val[ISIS_SYS_ID_LEN] = circuit->circuit_id;
2300 *var_len = ISIS_SYS_ID_LEN + 1;
2301 return circuit_id_val;
2302 }
2303
2304 /* Adjacency fully-up */
2305 memcpy(circuit_id_val, circuit->u.p2p.neighbor->sysid,
2306 ISIS_SYS_ID_LEN);
2307 circuit_id_val[ISIS_SYS_ID_LEN] = 0;
2308 *var_len = ISIS_SYS_ID_LEN + 1;
2309 return circuit_id_val;
2310
2311 case ISIS_CIRCLEVEL_DESIS:
2312 if (circuit->circ_type != CIRCUIT_T_BROADCAST
2313 || !circuit->u.bc.is_dr[level - 1]) {
2314 /*
2315 * Unless it is lan circuit participating in dis process
2316 * the value is an empty octet string
2317 */
2318 *var_len = 0;
2319 return circuit_id_val;
2320 }
2321
2322 *var_len = ISIS_SYS_ID_LEN + 1;
2323
2324 if (level == IS_LEVEL_1)
2325 return circuit->u.bc.l1_desig_is;
2326
2327 return circuit->u.bc.l2_desig_is;
2328
2329 case ISIS_CIRCLEVEL_HELLOMULTIPLIER:
2330 return SNMP_INTEGER(circuit->hello_multiplier[level - 1]);
2331
2332 case ISIS_CIRCLEVEL_HELLOTIMER:
2333 return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000);
2334
2335 case ISIS_CIRCLEVEL_DRHELLOTIMER:
2336 return SNMP_INTEGER(circuit->hello_interval[level - 1] * 1000);
2337
2338 case ISIS_CIRCLEVEL_LSPTHROTTLE:
2339 if (circuit->area)
2340 return SNMP_INTEGER(
2341 circuit->area->min_spf_interval[level - 1]
2342 * 1000);
2343 else
2344 return SNMP_INTEGER(0);
2345
2346 case ISIS_CIRCLEVEL_MINLSPRETRANSINT:
2347 if (circuit->area)
2348 return SNMP_INTEGER(
2349 circuit->area->min_spf_interval[level - 1]);
2350 else
2351 return SNMP_INTEGER(0);
2352
2353 case ISIS_CIRCLEVEL_CSNPINTERVAL:
2354 return SNMP_INTEGER(circuit->csnp_interval[level - 1]);
2355
2356 case ISIS_CIRCLEVEL_PARTSNPINTERVAL:
2357 return SNMP_INTEGER(circuit->psnp_interval[level - 1]);
2358
2359 default:
2360 break;
2361 }
2362
2363 return NULL;
2364 }
2365
2366 static uint8_t *isis_snmp_find_circ_counter(struct variable *v, oid *name,
2367 size_t *length, int exact,
2368 size_t *var_len,
2369 WriteMethod **write_method)
2370 {
2371 /* Index circuit-id 1-255 + level */
2372 oid *oid_idx;
2373 size_t oid_idx_len;
2374 int res;
2375 struct isis_circuit *circuit;
2376 int level;
2377 uint32_t val = 0;
2378
2379 *write_method = NULL;
2380
2381 if (*length <= v->namelen) {
2382 oid_idx = NULL;
2383 oid_idx_len = 0;
2384 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2385 oid_idx = NULL;
2386 oid_idx_len = 0;
2387 } else {
2388 oid_idx = name + v->namelen;
2389 oid_idx_len = *length - v->namelen;
2390 }
2391 if (exact) {
2392 res = isis_snmp_circuit_level_lookup_exact(oid_idx, oid_idx_len,
2393 1, &circuit, &level);
2394
2395 if (!res || oid_idx_len != 2)
2396 return NULL;
2397
2398 } else {
2399 res = isis_snmp_circuit_level_lookup_next(oid_idx, oid_idx_len,
2400 1, &circuit, &level);
2401
2402 if (!res)
2403 return NULL;
2404
2405 /* Copy the name out */
2406 memcpy(name, v->name, v->namelen * sizeof(oid));
2407
2408 /* Append index */
2409 name[v->namelen] = circuit->snmp_id;
2410 if (circuit->circ_type == CIRCUIT_T_P2P)
2411 name[v->namelen + 1] = ISIS_SNMP_P2P_CIRCUIT;
2412 else
2413 name[v->namelen + 1] = level;
2414
2415 /* Set length */
2416 *length = v->namelen + 2;
2417 }
2418
2419 switch (v->magic) {
2420 case ISIS_CIRC_ADJCHANGES:
2421 val = circuit->adj_state_changes;
2422 break;
2423
2424 case ISIS_CIRC_NUMADJ:
2425 if (circuit->circ_type == CIRCUIT_T_P2P) {
2426 val = circuit->u.p2p.neighbor == NULL ? 0 : 1;
2427 break;
2428 }
2429
2430 if (circuit->circ_type != CIRCUIT_T_BROADCAST) {
2431 val = 0;
2432 break;
2433 }
2434
2435 if (level == IS_LEVEL_1) {
2436 if (circuit->u.bc.adjdb[0] == NULL)
2437 val = 0;
2438 else
2439 val = listcount(circuit->u.bc.adjdb[0]);
2440 break;
2441 }
2442
2443 if (circuit->u.bc.adjdb[1] == NULL)
2444 val = 0;
2445 else
2446 val = listcount(circuit->u.bc.adjdb[1]);
2447
2448 break;
2449
2450 case ISIS_CIRC_INITFAILS:
2451 val = circuit->init_failures; /* counter never incremented */
2452 break;
2453
2454 case ISIS_CIRC_REJADJS:
2455 val = circuit->rej_adjacencies;
2456 break;
2457
2458 case ISIS_CIRC_IDFIELDLENMISMATCHES:
2459 val = circuit->id_len_mismatches;
2460 break;
2461
2462 case ISIS_CIRC_MAXAREAADDRMISMATCHES:
2463 val = circuit->max_area_addr_mismatches;
2464 break;
2465
2466 case ISIS_CIRC_AUTHTYPEFAILS:
2467 val = circuit->auth_type_failures;
2468 break;
2469
2470 case ISIS_CIRC_AUTHFAILS:
2471 val = circuit->auth_failures;
2472 break;
2473
2474 case ISIS_CIRC_LANDESISCHANGES:
2475 if (circuit->circ_type == CIRCUIT_T_P2P)
2476 val = 0;
2477 else
2478 val = circuit->desig_changes[level - 1];
2479 break;
2480
2481 default:
2482 return NULL;
2483 }
2484
2485 return SNMP_INTEGER(val);
2486 }
2487
2488 static uint8_t *isis_snmp_find_isadj(struct variable *v, oid *name,
2489 size_t *length, int exact, size_t *var_len,
2490 WriteMethod **write_method)
2491 {
2492 /* Index is circuit-id: 1-255 + adj-id: 1-... */
2493 oid *oid_idx;
2494 size_t oid_idx_len;
2495 int res;
2496 time_t val;
2497 struct isis_adjacency *adj;
2498 uint32_t up_ticks;
2499 uint32_t delta_ticks;
2500 time_t now_time;
2501
2502 *write_method = NULL;
2503
2504 if (*length <= v->namelen) {
2505 oid_idx = NULL;
2506 oid_idx_len = 0;
2507 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2508 oid_idx = NULL;
2509 oid_idx_len = 0;
2510 } else {
2511 oid_idx = name + v->namelen;
2512 oid_idx_len = *length - v->namelen;
2513 }
2514 if (exact) {
2515 res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
2516 ISIS_SNMP_ADJ_DATA_NONE, &adj,
2517 NULL, NULL, NULL);
2518
2519 if (!res || oid_idx_len != 2)
2520 return NULL;
2521
2522 } else {
2523 res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len,
2524 ISIS_SNMP_ADJ_DATA_NONE, &adj,
2525 NULL, NULL, NULL);
2526 if (!res)
2527 return NULL;
2528
2529 /* Copy the name out */
2530 memcpy(name, v->name, v->namelen * sizeof(oid));
2531
2532 /* Append index */
2533 name[v->namelen] = adj->circuit->snmp_id;
2534 name[v->namelen + 1] = adj->snmp_idx;
2535
2536 /* Set length */
2537 *length = v->namelen + 2;
2538 }
2539
2540 switch (v->magic) {
2541 case ISIS_ISADJ_STATE:
2542 return SNMP_INTEGER(isis_snmp_adj_state(adj->adj_state));
2543
2544 case ISIS_ISADJ_3WAYSTATE:
2545 return SNMP_INTEGER(adj->threeway_state);
2546
2547 case ISIS_ISADJ_NEIGHSNPAADDRESS: {
2548 const char *snpa = (char *)snpa_print(adj->snpa);
2549 *var_len = strlen(snpa);
2550 return (uint8_t *)snpa;
2551 }
2552
2553 case ISIS_ISADJ_NEIGHSYSTYPE:
2554 return SNMP_INTEGER(isis_snmp_adj_neightype(adj->sys_type));
2555
2556 case ISIS_ISADJ_NEIGHSYSID:
2557 *var_len = sizeof(adj->sysid);
2558 return adj->sysid;
2559
2560 case ISIS_ISADJ_NBREXTENDEDCIRCID:
2561 return SNMP_INTEGER(adj->ext_circuit_id != 0 ? 1 : 0);
2562
2563 case ISIS_ISADJ_USAGE:
2564 /* It seems that no value conversion is required */
2565 return SNMP_INTEGER(adj->adj_usage);
2566
2567 case ISIS_ISADJ_HOLDTIMER:
2568 /*
2569 * It seems that we want remaining timer
2570 */
2571 if (adj->last_upd != 0) {
2572 val = time(NULL);
2573 if (val < (adj->last_upd + adj->hold_time))
2574 return SNMP_INTEGER(adj->last_upd
2575 + adj->hold_time - val);
2576 }
2577 /* Not running or just expired */
2578 return SNMP_INTEGER(0);
2579
2580 case ISIS_ISADJ_NEIGHPRIORITY:
2581 return SNMP_INTEGER(adj->prio[adj->level - 1]);
2582
2583 case ISIS_ISADJ_LASTUPTIME:
2584 if (adj->flaps == 0)
2585 return SNMP_INTEGER(0);
2586
2587 up_ticks = (uint32_t)netsnmp_get_agent_uptime();
2588
2589 now_time = time(NULL);
2590
2591 if (adj->last_flap >= now_time)
2592 return SNMP_INTEGER(up_ticks);
2593
2594 delta_ticks = (now_time - adj->last_flap) * 10;
2595
2596 if (up_ticks < delta_ticks)
2597 return SNMP_INTEGER(up_ticks);
2598
2599 return SNMP_INTEGER(up_ticks - delta_ticks);
2600
2601 default:
2602 break;
2603 }
2604
2605 return NULL;
2606 }
2607
2608 static uint8_t *isis_snmp_find_isadj_area(struct variable *v, oid *name,
2609 size_t *length, int exact,
2610 size_t *var_len,
2611 WriteMethod **write_method)
2612 {
2613 /* Index circuit-id: 1-255 + adj-id: 1-... */
2614 oid *oid_idx;
2615 size_t oid_idx_len;
2616 int res;
2617 struct isis_adjacency *adj;
2618 oid data_idx;
2619 uint8_t *data;
2620 size_t data_len;
2621
2622 *write_method = NULL;
2623
2624 if (*length <= v->namelen) {
2625 oid_idx = NULL;
2626 oid_idx_len = 0;
2627 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2628 oid_idx = NULL;
2629 oid_idx_len = 0;
2630 } else {
2631 oid_idx = name + v->namelen;
2632 oid_idx_len = *length - v->namelen;
2633 }
2634 if (exact) {
2635 res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
2636 ISIS_SNMP_ADJ_DATA_AREA_ADDR,
2637 &adj, NULL, &data, &data_len);
2638
2639 if (!res || oid_idx_len != 3)
2640 return NULL;
2641
2642 } else {
2643 res = isis_snmp_adj_lookup_next(
2644 oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_AREA_ADDR,
2645 &adj, &data_idx, &data, &data_len);
2646 if (!res)
2647 return NULL;
2648
2649 /* Copy the name out */
2650 memcpy(name, v->name, v->namelen * sizeof(oid));
2651
2652 /* Append index */
2653 name[v->namelen] = adj->circuit->snmp_id;
2654 name[v->namelen + 1] = adj->snmp_idx;
2655 name[v->namelen + 2] = data_idx;
2656
2657 /* Set length */
2658 *length = v->namelen + 3;
2659 }
2660
2661 switch (v->magic) {
2662 case ISIS_ISADJAREA_ADDRESS:
2663 *var_len = data_len;
2664 return data;
2665
2666 default:
2667 break;
2668 }
2669
2670 return NULL;
2671 }
2672
2673 static uint8_t *isis_snmp_find_isadj_ipaddr(struct variable *v, oid *name,
2674 size_t *length, int exact,
2675 size_t *var_len,
2676 WriteMethod **write_method)
2677 {
2678 /* Index circuit-id 1-255 + adj-id 1-... */
2679 oid *oid_idx;
2680 size_t oid_idx_len;
2681 int res;
2682 struct isis_adjacency *adj;
2683 oid data_idx;
2684 uint8_t *data;
2685 size_t data_len;
2686
2687 *write_method = NULL;
2688
2689 if (*length <= v->namelen) {
2690 oid_idx = NULL;
2691 oid_idx_len = 0;
2692 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2693 oid_idx = NULL;
2694 oid_idx_len = 0;
2695 } else {
2696 oid_idx = name + v->namelen;
2697 oid_idx_len = *length - v->namelen;
2698 }
2699 if (exact) {
2700 res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
2701 ISIS_SNMP_ADJ_DATA_IP_ADDR,
2702 &adj, NULL, &data, &data_len);
2703
2704 if (!res || oid_idx_len != 3)
2705 return NULL;
2706 } else {
2707 res = isis_snmp_adj_lookup_next(
2708 oid_idx, oid_idx_len, ISIS_SNMP_ADJ_DATA_IP_ADDR, &adj,
2709 &data_idx, &data, &data_len);
2710 if (!res)
2711 return NULL;
2712
2713 /* Copy the name out */
2714 memcpy(name, v->name, v->namelen * sizeof(oid));
2715
2716 /* Append index */
2717 name[v->namelen] = adj->circuit->snmp_id;
2718 name[v->namelen + 1] = adj->snmp_idx;
2719 name[v->namelen + 2] = data_idx;
2720
2721 /* Set length */
2722 *length = v->namelen + 3;
2723 }
2724
2725 switch (v->magic) {
2726 case ISIS_ISADJIPADDR_TYPE:
2727 if (data_len == 4)
2728 return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V4);
2729
2730 return SNMP_INTEGER(ISIS_SNMP_INET_TYPE_V6);
2731
2732 case ISIS_ISADJIPADDR_ADDRESS:
2733 *var_len = data_len;
2734 return data;
2735
2736 default:
2737 break;
2738 }
2739
2740 return NULL;
2741 }
2742
2743 static uint8_t *isis_snmp_find_isadj_prot_supp(struct variable *v, oid *name,
2744 size_t *length, int exact,
2745 size_t *var_len,
2746 WriteMethod **write_method)
2747 {
2748 /* Index circuit-id 1-255 + adj-id 1-... */
2749 oid *oid_idx;
2750 size_t oid_idx_len;
2751 int res;
2752 struct isis_adjacency *adj;
2753 oid data_idx;
2754 uint8_t *data;
2755 size_t data_len;
2756
2757 *write_method = NULL;
2758
2759 if (*length <= v->namelen) {
2760 oid_idx = NULL;
2761 oid_idx_len = 0;
2762 } else if (memcmp(name, v->name, v->namelen * sizeof(oid)) != 0) {
2763 oid_idx = NULL;
2764 oid_idx_len = 0;
2765 } else {
2766 oid_idx = name + v->namelen;
2767 oid_idx_len = *length - v->namelen;
2768 }
2769 if (exact) {
2770 res = isis_snmp_adj_lookup_exact(oid_idx, oid_idx_len,
2771 ISIS_SNMP_ADJ_DATA_PROTO, &adj,
2772 NULL, &data, &data_len);
2773
2774 if (!res || oid_idx_len != 3)
2775 return NULL;
2776
2777 } else {
2778 res = isis_snmp_adj_lookup_next(oid_idx, oid_idx_len,
2779 ISIS_SNMP_ADJ_DATA_PROTO, &adj,
2780 &data_idx, &data, &data_len);
2781 if (!res)
2782 return NULL;
2783
2784 /* Copy the name out */
2785 memcpy(name, v->name, v->namelen * sizeof(oid));
2786
2787 /* Append index */
2788 name[v->namelen] = adj->circuit->snmp_id;
2789 name[v->namelen + 1] = adj->snmp_idx;
2790 name[v->namelen + 2] = data_idx;
2791
2792 /* Set length */
2793 *length = v->namelen + 3;
2794 }
2795
2796 switch (v->magic) {
2797 case ISIS_ISADJPROTSUPP_PROTOCOL:
2798 return SNMP_INTEGER(*data);
2799
2800 default:
2801 break;
2802 }
2803
2804 return NULL;
2805 }
2806
2807
2808 /* Register ISIS-MIB. */
2809 static int isis_snmp_init(struct thread_master *tm)
2810 {
2811 struct isis_func_to_prefix *h2f = isis_func_to_prefix_arr;
2812 struct variable *v;
2813
2814 for (size_t off = 0; off < isis_var_count; off++) {
2815 v = &isis_var_arr[off];
2816
2817 if (v->findVar != h2f->ihtp_func) {
2818 /* Next table */
2819 h2f++;
2820 assert(h2f < (isis_func_to_prefix_arr
2821 + isis_func_to_prefix_count));
2822 assert(v->findVar == h2f->ihtp_func);
2823 }
2824
2825 v->namelen = h2f->ihtp_pref_len + 1;
2826 memcpy(v->name, h2f->ihtp_pref_oid,
2827 h2f->ihtp_pref_len * sizeof(oid));
2828 v->name[h2f->ihtp_pref_len] = v->magic;
2829 }
2830
2831
2832 smux_init(tm);
2833 REGISTER_MIB("mibII/isis", isis_var_arr, variable, isis_oid);
2834 return 0;
2835 }
2836
2837 /*
2838 * ISIS notification functions: we have one function per notification
2839 */
2840 static int isis_snmp_trap_throttle(oid trap_id)
2841 {
2842 time_t time_now;
2843 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
2844
2845 if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
2846 return 0;
2847
2848 time_now = time(NULL);
2849
2850 if ((isis_snmp_trap_timestamp[trap_id] + 5) > time_now)
2851 /* Throttle trap rate at 1 in 5 secs */
2852 return 0;
2853
2854 isis_snmp_trap_timestamp[trap_id] = time_now;
2855 return 1;
2856 }
2857
2858 static int isis_snmp_db_overload_update(const struct isis_area *area)
2859 {
2860 netsnmp_variable_list *notification_vars;
2861 long val;
2862 uint32_t off;
2863
2864 if (!isis_snmp_trap_throttle(ISIS_TRAP_DB_OVERLOAD))
2865 return 0;
2866
2867 notification_vars = NULL;
2868
2869 /* Put in trap value */
2870 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
2871 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
2872 (uint8_t *)&isis_snmp_trap_val_db_overload,
2873 sizeof(isis_snmp_trap_val_db_overload));
2874
2875 /* Prepare data */
2876 val = area->is_type;
2877
2878 snmp_varlist_add_variable(
2879 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
2880 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
2881 (uint8_t *)&val, sizeof(val));
2882
2883 /* Patch sys_level_state with proper index */
2884 off = ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state) - 1;
2885 isis_snmp_trap_data_var_sys_level_state[off] = val;
2886
2887 /* Prepare data */
2888 if (area->overload_bit)
2889 val = ISIS_SNMP_LEVEL_STATE_OVERLOADED;
2890 else
2891 val = ISIS_SNMP_LEVEL_STATE_ON;
2892
2893 snmp_varlist_add_variable(
2894 &notification_vars, isis_snmp_trap_data_var_sys_level_state,
2895 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_state), INTEGER,
2896 (uint8_t *)&val, sizeof(val));
2897
2898 send_v2trap(notification_vars);
2899 snmp_free_varbind(notification_vars);
2900 smux_events_update();
2901 return 0;
2902 }
2903
2904 static int isis_snmp_lsp_exceed_max_update(const struct isis_area *area,
2905 const uint8_t *lsp_id)
2906 {
2907 netsnmp_variable_list *notification_vars;
2908 long val;
2909
2910 if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_EXCEED_MAX))
2911 return 0;
2912
2913 notification_vars = NULL;
2914
2915 /* Put in trap value */
2916 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
2917 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
2918 (uint8_t *)&isis_snmp_trap_val_lsp_exceed_max,
2919 sizeof(isis_snmp_trap_val_lsp_exceed_max));
2920
2921 /* Prepare data */
2922 val = area->is_type;
2923
2924 snmp_varlist_add_variable(
2925 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
2926 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
2927 (uint8_t *)&val, sizeof(val));
2928
2929 snmp_varlist_add_variable(
2930 &notification_vars, isis_snmp_trap_data_var_pdu_lsp_id,
2931 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
2932 ISIS_SYS_ID_LEN + 2);
2933
2934 send_v2trap(notification_vars);
2935 snmp_free_varbind(notification_vars);
2936 smux_events_update();
2937 return 0;
2938 }
2939
2940
2941 /*
2942 * A common function to handle popular combination of trap objects
2943 * isisNotificationSysLevelIndex,
2944 * optional-object-a
2945 * isisNotificationCircIfIndex,
2946 * optional-object-b
2947 */
2948 static void isis_snmp_update_worker_a(const struct isis_circuit *circuit,
2949 oid trap_id, const oid *oid_a,
2950 size_t oid_a_len, uint8_t type_a,
2951 const void *data_a, size_t data_a_len,
2952 const oid *oid_b, size_t oid_b_len,
2953 uint8_t type_b, const void *data_b,
2954 size_t data_b_len)
2955 {
2956 netsnmp_variable_list *notification_vars = NULL;
2957 oid var_name[MAX_OID_LEN];
2958 size_t var_count;
2959 long val;
2960
2961 /* Sanity */
2962 if (trap_id != ISIS_TRAP_ID_LEN_MISMATCH
2963 && trap_id != ISIS_TRAP_MAX_AREA_ADDR_MISMATCH
2964 && trap_id != ISIS_TRAP_OWN_LSP_PURGE
2965 && trap_id != ISIS_TRAP_SEQNO_SKIPPED
2966 && trap_id != ISIS_TRAP_AUTHEN_TYPE_FAILURE
2967 && trap_id != ISIS_TRAP_AUTHEN_FAILURE
2968 && trap_id != ISIS_TRAP_REJ_ADJACENCY)
2969 return;
2970
2971 /* Put in trap value */
2972 memcpy(var_name, isis_snmp_notifications,
2973 sizeof(isis_snmp_notifications));
2974 var_count = ARRAY_SIZE(isis_snmp_notifications);
2975 var_name[var_count++] = trap_id;
2976
2977 /* Put in trap value */
2978 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
2979 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
2980 (uint8_t *)var_name, var_count * sizeof(oid));
2981
2982 val = circuit->is_type;
2983 snmp_varlist_add_variable(
2984 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
2985 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
2986 (uint8_t *)&val, sizeof(val));
2987
2988 if (oid_a_len != 0) {
2989 if (oid_a == NULL || data_a == NULL || data_a_len == 0)
2990 return;
2991
2992 snmp_varlist_add_variable(&notification_vars, oid_a, oid_a_len,
2993 type_a, (uint8_t *)data_a,
2994 data_a_len);
2995 }
2996
2997 if (circuit->interface == NULL)
2998 val = 0;
2999 else
3000 val = circuit->interface->ifindex;
3001
3002 snmp_varlist_add_variable(
3003 &notification_vars, isis_snmp_trap_data_var_circ_if_index,
3004 ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
3005 (uint8_t *)&val, sizeof(val));
3006
3007
3008 if (oid_b_len != 0) {
3009 if (oid_b == NULL || data_b == NULL || data_b_len == 0)
3010 return;
3011
3012 snmp_varlist_add_variable(&notification_vars, oid_b, oid_b_len,
3013 type_b, (uint8_t *)data_b,
3014 data_b_len);
3015 }
3016
3017 send_v2trap(notification_vars);
3018 snmp_free_varbind(notification_vars);
3019 smux_events_update();
3020 }
3021
3022 /*
3023 * A common function to handle popular combination of trap objects
3024 * isisNotificationSysLevelIndex,
3025 * isisNotificationCircIfIndex,
3026 * optional-var-a
3027 * optional-var-b
3028 *
3029 * Note: the only difference with worker_a is order of circ-if-index vs
3030 * optional-var-a
3031 */
3032 static void isis_snmp_update_worker_b(const struct isis_circuit *circuit,
3033 oid trap_id, const oid *oid_a,
3034 size_t oid_a_len, uint8_t type_a,
3035 const void *data_a, size_t data_a_len,
3036 const oid *oid_b, size_t oid_b_len,
3037 uint8_t type_b, const void *data_b,
3038 size_t data_b_len)
3039 {
3040 netsnmp_variable_list *notification_vars = NULL;
3041 oid var_name[MAX_OID_LEN];
3042 size_t var_count;
3043 long val;
3044
3045 /* Sanity */
3046 if (trap_id != ISIS_TRAP_VERSION_SKEW
3047 && trap_id != ISIS_TRAP_LSP_TOO_LARGE
3048 && trap_id != ISIS_TRAP_ADJ_STATE_CHANGE)
3049 return;
3050
3051 /* Put in trap value */
3052 memcpy(var_name, isis_snmp_notifications,
3053 sizeof(isis_snmp_notifications));
3054 var_count = ARRAY_SIZE(isis_snmp_notifications);
3055 var_name[var_count++] = trap_id;
3056
3057 /* Put in trap value */
3058 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
3059 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
3060 (uint8_t *)var_name, var_count * sizeof(oid));
3061
3062 val = circuit->is_type;
3063 snmp_varlist_add_variable(
3064 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
3065 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
3066 (uint8_t *)&val, sizeof(val));
3067
3068 if (circuit->interface == NULL)
3069 val = 0;
3070 else
3071 val = circuit->interface->ifindex;
3072
3073 snmp_varlist_add_variable(
3074 &notification_vars, isis_snmp_trap_data_var_circ_if_index,
3075 ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
3076 (uint8_t *)&val, sizeof(val));
3077
3078
3079 if (oid_a_len != 0) {
3080 if (oid_a == NULL || data_a == NULL || data_a_len == 0)
3081 return;
3082
3083 snmp_varlist_add_variable(&notification_vars, oid_a, oid_a_len,
3084 type_a, (uint8_t *)data_a,
3085 data_a_len);
3086 }
3087
3088 if (oid_b_len != 0) {
3089 if (oid_b == NULL || data_b == NULL || data_b_len == 0)
3090 return;
3091
3092 snmp_varlist_add_variable(&notification_vars, oid_b, oid_b_len,
3093 type_b, (uint8_t *)data_b,
3094 data_b_len);
3095 }
3096
3097 send_v2trap(notification_vars);
3098 snmp_free_varbind(notification_vars);
3099 smux_events_update();
3100 }
3101
3102
3103 static int isis_snmp_id_len_mismatch_update(const struct isis_circuit *circuit,
3104 uint8_t rcv_id, const char *raw_pdu,
3105 size_t raw_pdu_len)
3106 {
3107 long val;
3108
3109 if (!isis_snmp_trap_throttle(ISIS_TRAP_ID_LEN_MISMATCH))
3110 return 0;
3111
3112 val = rcv_id;
3113
3114 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3115 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3116
3117 isis_snmp_update_worker_a(
3118 circuit, ISIS_TRAP_ID_LEN_MISMATCH,
3119 isis_snmp_trap_data_var_pdu_field_len,
3120 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_field_len), UNSIGNED32,
3121 &val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment,
3122 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3123 raw_pdu, raw_pdu_len);
3124 return 0;
3125 }
3126
3127 static int
3128 isis_snmp_max_area_addr_mismatch_update(const struct isis_circuit *circuit,
3129 uint8_t max_addrs, const char *raw_pdu,
3130 size_t raw_pdu_len)
3131 {
3132 long val;
3133
3134 if (!isis_snmp_trap_throttle(ISIS_TRAP_MAX_AREA_ADDR_MISMATCH))
3135 return 0;
3136
3137 val = max_addrs;
3138
3139 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3140 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3141
3142 isis_snmp_update_worker_a(
3143 circuit, ISIS_TRAP_MAX_AREA_ADDR_MISMATCH,
3144 isis_snmp_trap_data_var_pdu_max_area_addr,
3145 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_max_area_addr),
3146 UNSIGNED32, &val, sizeof(val),
3147 isis_snmp_trap_data_var_pdu_fragment,
3148 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3149 raw_pdu, raw_pdu_len);
3150 return 0;
3151 }
3152
3153 static int isis_snmp_own_lsp_purge_update(const struct isis_circuit *circuit,
3154 const uint8_t *lsp_id)
3155 {
3156 if (!isis_snmp_trap_throttle(ISIS_TRAP_OWN_LSP_PURGE))
3157 return 0;
3158
3159 isis_snmp_update_worker_a(
3160 circuit, ISIS_TRAP_OWN_LSP_PURGE, NULL, 0, STRING, NULL, 0,
3161 isis_snmp_trap_data_var_pdu_lsp_id,
3162 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3163 ISIS_SYS_ID_LEN + 2);
3164 return 0;
3165 }
3166
3167 static int isis_snmp_seqno_skipped_update(const struct isis_circuit *circuit,
3168 const uint8_t *lsp_id)
3169 {
3170 if (!isis_snmp_trap_throttle(ISIS_TRAP_SEQNO_SKIPPED))
3171 return 0;
3172
3173 isis_snmp_update_worker_a(
3174 circuit, ISIS_TRAP_SEQNO_SKIPPED, NULL, 0, STRING, NULL, 0,
3175 isis_snmp_trap_data_var_pdu_lsp_id,
3176 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3177 ISIS_SYS_ID_LEN + 2);
3178 return 0;
3179 }
3180
3181 static int
3182 isis_snmp_authentication_type_failure_update(const struct isis_circuit *circuit,
3183 const char *raw_pdu,
3184 size_t raw_pdu_len)
3185 {
3186 if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_TYPE_FAILURE))
3187 return 0;
3188
3189 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3190 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3191
3192 isis_snmp_update_worker_a(
3193 circuit, ISIS_TRAP_AUTHEN_TYPE_FAILURE, NULL, 0, STRING, NULL,
3194 0, isis_snmp_trap_data_var_pdu_fragment,
3195 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3196 raw_pdu, raw_pdu_len);
3197 return 0;
3198 }
3199
3200 static int
3201 isis_snmp_authentication_failure_update(const struct isis_circuit *circuit,
3202 char const *raw_pdu, size_t raw_pdu_len)
3203 {
3204 if (!isis_snmp_trap_throttle(ISIS_TRAP_AUTHEN_FAILURE))
3205 return 0;
3206
3207 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3208 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3209
3210 isis_snmp_update_worker_a(
3211 circuit, ISIS_TRAP_AUTHEN_FAILURE, NULL, 0, STRING, NULL, 0,
3212 isis_snmp_trap_data_var_pdu_fragment,
3213 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3214 raw_pdu, raw_pdu_len);
3215 return 0;
3216 }
3217
3218 static int isis_snmp_version_skew_update(const struct isis_circuit *circuit,
3219 uint8_t version, const char *raw_pdu,
3220 size_t raw_pdu_len)
3221 {
3222 long val;
3223
3224 if (!isis_snmp_trap_throttle(ISIS_TRAP_VERSION_SKEW))
3225 return 0;
3226
3227 val = version;
3228
3229 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3230 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3231
3232 isis_snmp_update_worker_b(
3233 circuit, ISIS_TRAP_VERSION_SKEW,
3234 isis_snmp_trap_data_var_pdu_proto_ver,
3235 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_proto_ver), UNSIGNED32,
3236 &val, sizeof(val), isis_snmp_trap_data_var_pdu_fragment,
3237 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3238 raw_pdu, raw_pdu_len);
3239 return 0;
3240 }
3241
3242 static int isis_snmp_area_mismatch_update(const struct isis_circuit *circuit,
3243 const char *raw_pdu,
3244 size_t raw_pdu_len)
3245 {
3246 /*
3247 * This is a special case because
3248 * it does not include isisNotificationSysLevelIndex
3249 */
3250 netsnmp_variable_list *notification_vars;
3251 long val;
3252
3253 if (!isis_snmp_trap_throttle(ISIS_TRAP_AREA_MISMATCH))
3254 return 0;
3255
3256 notification_vars = NULL;
3257
3258 /* Put in trap value */
3259 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
3260 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
3261 (uint8_t *)&isis_snmp_trap_val_area_mismatch,
3262 sizeof(isis_snmp_trap_val_area_mismatch));
3263
3264
3265 if (circuit->interface == NULL)
3266 val = 0;
3267 else
3268 val = circuit->interface->ifindex;
3269
3270 snmp_varlist_add_variable(
3271 &notification_vars, isis_snmp_trap_data_var_circ_if_index,
3272 ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
3273 (uint8_t *)&val, sizeof(val));
3274
3275
3276 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3277 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3278
3279 snmp_varlist_add_variable(
3280 &notification_vars, isis_snmp_trap_data_var_pdu_fragment,
3281 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3282 raw_pdu, raw_pdu_len);
3283
3284 send_v2trap(notification_vars);
3285 snmp_free_varbind(notification_vars);
3286 smux_events_update();
3287
3288 return 0;
3289 }
3290
3291 static int isis_snmp_reject_adjacency_update(const struct isis_circuit *circuit,
3292 const char *raw_pdu,
3293 size_t raw_pdu_len)
3294 {
3295 if (!isis_snmp_trap_throttle(ISIS_TRAP_REJ_ADJACENCY))
3296 return 0;
3297
3298 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3299 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3300
3301 isis_snmp_update_worker_a(
3302 circuit, ISIS_TRAP_REJ_ADJACENCY, NULL, 0, STRING, NULL, 0,
3303 isis_snmp_trap_data_var_pdu_fragment,
3304 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3305 raw_pdu, raw_pdu_len);
3306 return 0;
3307 }
3308
3309 static int isis_snmp_lsp_too_large_update(const struct isis_circuit *circuit,
3310 uint32_t pdu_size,
3311 const uint8_t *lsp_id)
3312 {
3313 if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_TOO_LARGE))
3314 return 0;
3315
3316 isis_snmp_update_worker_b(
3317 circuit, ISIS_TRAP_LSP_TOO_LARGE,
3318 isis_snmp_trap_data_var_pdu_lsp_size,
3319 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_size), UNSIGNED32,
3320 &pdu_size, sizeof(pdu_size), isis_snmp_trap_data_var_pdu_lsp_id,
3321 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3322 ISIS_SYS_ID_LEN + 2);
3323 return 0;
3324 }
3325
3326
3327 static int isis_snmp_adj_state_change_update(const struct isis_adjacency *adj)
3328 {
3329 uint8_t lsp_id[ISIS_SYS_ID_LEN + 2];
3330 long val;
3331 struct isis *isis = isis_lookup_by_vrfid(VRF_DEFAULT);
3332
3333 if (isis == NULL || !isis->snmp_notifications || !smux_enabled())
3334 return 0;
3335
3336 /* Prepare data */
3337 memcpy(lsp_id, adj->sysid, ISIS_SYS_ID_LEN);
3338 lsp_id[ISIS_SYS_ID_LEN] = 0;
3339 lsp_id[ISIS_SYS_ID_LEN + 1] = 0;
3340
3341 val = isis_snmp_adj_state(adj->adj_state);
3342
3343 isis_snmp_update_worker_b(
3344 adj->circuit, ISIS_TRAP_ADJ_STATE_CHANGE,
3345 isis_snmp_trap_data_var_pdu_lsp_id,
3346 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3347 ISIS_SYS_ID_LEN + 2, isis_snmp_trap_data_var_adj_state,
3348 ARRAY_SIZE(isis_snmp_trap_data_var_adj_state), INTEGER, &val,
3349 sizeof(val));
3350 return 0;
3351 }
3352
3353 static int isis_snmp_lsp_error_update(const struct isis_circuit *circuit,
3354 const uint8_t *lsp_id,
3355 char const *raw_pdu, size_t raw_pdu_len)
3356 {
3357 /*
3358 * This is a special case because
3359 * it have more variables
3360 */
3361 netsnmp_variable_list *notification_vars;
3362 long val;
3363
3364 if (!isis_snmp_trap_throttle(ISIS_TRAP_LSP_ERROR))
3365 return 0;
3366
3367 notification_vars = NULL;
3368
3369 /* Put in trap value */
3370 snmp_varlist_add_variable(&notification_vars, isis_snmp_trap_var,
3371 ARRAY_SIZE(isis_snmp_trap_var), ASN_OBJECT_ID,
3372 (uint8_t *)&isis_snmp_trap_val_lsp_error,
3373 sizeof(isis_snmp_trap_val_lsp_error));
3374
3375 /* Prepare data */
3376 val = circuit->is_type;
3377
3378 snmp_varlist_add_variable(
3379 &notification_vars, isis_snmp_trap_data_var_sys_level_index,
3380 ARRAY_SIZE(isis_snmp_trap_data_var_sys_level_index), INTEGER,
3381 (uint8_t *)&val, sizeof(val));
3382
3383
3384 snmp_varlist_add_variable(
3385 &notification_vars, isis_snmp_trap_data_var_pdu_lsp_id,
3386 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_lsp_id), STRING, lsp_id,
3387 ISIS_SYS_ID_LEN + 2);
3388
3389 /* Prepare data */
3390 if (circuit->interface == NULL)
3391 val = 0;
3392 else
3393 val = circuit->interface->ifindex;
3394
3395 snmp_varlist_add_variable(
3396 &notification_vars, isis_snmp_trap_data_var_circ_if_index,
3397 ARRAY_SIZE(isis_snmp_trap_data_var_circ_if_index), UNSIGNED32,
3398 (uint8_t *)&val, sizeof(val));
3399
3400 /* Prepare data */
3401 if (raw_pdu_len > ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN)
3402 raw_pdu_len = ISIS_SNMP_TRAP_PDU_FRAGMENT_MAX_LEN;
3403
3404 snmp_varlist_add_variable(
3405 &notification_vars, isis_snmp_trap_data_var_pdu_fragment,
3406 ARRAY_SIZE(isis_snmp_trap_data_var_pdu_fragment), STRING,
3407 raw_pdu, raw_pdu_len);
3408
3409 /* Prepare data */
3410 val = 0;
3411
3412 snmp_varlist_add_variable(
3413 &notification_vars, isis_snmp_trap_data_var_error_offset,
3414 ARRAY_SIZE(isis_snmp_trap_data_var_error_offset), UNSIGNED32,
3415 (uint8_t *)&val, sizeof(val));
3416
3417 /* Prepare data */
3418 val = 0;
3419
3420 snmp_varlist_add_variable(
3421 &notification_vars, isis_snmp_trap_data_var_error_tlv_type,
3422 ARRAY_SIZE(isis_snmp_trap_data_var_error_tlv_type), UNSIGNED32,
3423 (uint8_t *)&val, sizeof(val));
3424
3425 send_v2trap(notification_vars);
3426 snmp_free_varbind(notification_vars);
3427 smux_events_update();
3428 return 0;
3429 }
3430
3431
3432 static int isis_snmp_module_init(void)
3433 {
3434 hook_register(isis_hook_db_overload, isis_snmp_db_overload_update);
3435 hook_register(isis_hook_lsp_exceed_max,
3436 isis_snmp_lsp_exceed_max_update);
3437 hook_register(isis_hook_id_len_mismatch,
3438 isis_snmp_id_len_mismatch_update);
3439 hook_register(isis_hook_max_area_addr_mismatch,
3440 isis_snmp_max_area_addr_mismatch_update);
3441 hook_register(isis_hook_own_lsp_purge, isis_snmp_own_lsp_purge_update);
3442 hook_register(isis_hook_seqno_skipped, isis_snmp_seqno_skipped_update);
3443 hook_register(isis_hook_authentication_type_failure,
3444 isis_snmp_authentication_type_failure_update);
3445 hook_register(isis_hook_authentication_failure,
3446 isis_snmp_authentication_failure_update);
3447 hook_register(isis_hook_version_skew, isis_snmp_version_skew_update);
3448 hook_register(isis_hook_area_mismatch, isis_snmp_area_mismatch_update);
3449 hook_register(isis_hook_reject_adjacency,
3450 isis_snmp_reject_adjacency_update);
3451 hook_register(isis_hook_lsp_too_large, isis_snmp_lsp_too_large_update);
3452 hook_register(isis_hook_adj_state_change,
3453 isis_snmp_adj_state_change_update);
3454 hook_register(isis_hook_lsp_error, isis_snmp_lsp_error_update);
3455 hook_register(isis_circuit_new_hook, isis_circuit_snmp_id_gen);
3456 hook_register(isis_circuit_del_hook, isis_circuit_snmp_id_free);
3457
3458 hook_register(frr_late_init, isis_snmp_init);
3459 return 0;
3460 }
3461
3462 FRR_MODULE_SETUP(
3463 .name = "isis_snmp",
3464 .version = FRR_VERSION,
3465 .description = "isis AgentX SNMP module",
3466 .init = isis_snmp_module_init,
3467 );