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