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