]> git.proxmox.com Git - mirror_frr.git/blob - isisd/isis_misc.c
mgmtd: fix cleanup of cleanup in FE adapter code
[mirror_frr.git] / isisd / isis_misc.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * IS-IS Rout(e)ing protocol - isis_misc.h
4 * Miscellanous routines
5 *
6 * Copyright (C) 2001,2002 Sampo Saaristo
7 * Tampere University of Technology
8 * Institute of Communications Engineering
9 */
10
11 #include <zebra.h>
12
13 #include "printfrr.h"
14 #include "stream.h"
15 #include "vty.h"
16 #include "hash.h"
17 #include "if.h"
18 #include "command.h"
19 #include "network.h"
20
21 #include "isisd/isis_constants.h"
22 #include "isisd/isis_common.h"
23 #include "isisd/isis_flags.h"
24 #include "isisd/isis_circuit.h"
25 #include "isisd/isis_csm.h"
26 #include "isisd/isisd.h"
27 #include "isisd/isis_misc.h"
28
29 #include "isisd/isis_lsp.h"
30 #include "isisd/isis_constants.h"
31 #include "isisd/isis_adjacency.h"
32 #include "isisd/isis_dynhn.h"
33
34 /* staticly assigned vars for printing purposes */
35 static char sys_hostname[ISO_SYSID_STRLEN];
36 struct in_addr new_prefix;
37 /* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */
38 char datestring[20];
39 char nlpidstring[30];
40
41 /*
42 * Returns 0 on error, length of buff on ok
43 * extract dot from the dotted str, and insert all the number in a buff
44 */
45 int dotformat2buff(uint8_t *buff, const char *dotted)
46 {
47 int dotlen, len = 0;
48 const char *pos = dotted;
49 uint8_t number[3];
50 int nextdotpos = 2;
51
52 number[2] = '\0';
53 dotlen = strlen(dotted);
54 if (dotlen > 50) {
55 /* this can't be an iso net, its too long */
56 return 0;
57 }
58
59 while ((pos - dotted) < dotlen && len < 20) {
60 if (*pos == '.') {
61 /* we expect the . at 2, and than every 5 */
62 if ((pos - dotted) != nextdotpos) {
63 len = 0;
64 break;
65 }
66 nextdotpos += 5;
67 pos++;
68 continue;
69 }
70 /* we must have at least two chars left here */
71 if (dotlen - (pos - dotted) < 2) {
72 len = 0;
73 break;
74 }
75
76 if ((isxdigit((unsigned char)*pos)) &&
77 (isxdigit((unsigned char)*(pos + 1)))) {
78 memcpy(number, pos, 2);
79 pos += 2;
80 } else {
81 len = 0;
82 break;
83 }
84
85 *(buff + len) = (char)strtol((char *)number, NULL, 16);
86 len++;
87 }
88
89 return len;
90 }
91
92 /*
93 * conversion of XXXX.XXXX.XXXX to memory
94 */
95 int sysid2buff(uint8_t *buff, const char *dotted)
96 {
97 int len = 0;
98 const char *pos = dotted;
99 uint8_t number[3];
100
101 number[2] = '\0';
102 // surely not a sysid_string if not 14 length
103 if (strlen(dotted) != 14) {
104 return 0;
105 }
106
107 while (len < ISIS_SYS_ID_LEN) {
108 if (*pos == '.') {
109 /* the . is not positioned correctly */
110 if (((pos - dotted) != 4) && ((pos - dotted) != 9)) {
111 len = 0;
112 break;
113 }
114 pos++;
115 continue;
116 }
117 if ((isxdigit((unsigned char)*pos)) &&
118 (isxdigit((unsigned char)*(pos + 1)))) {
119 memcpy(number, pos, 2);
120 pos += 2;
121 } else {
122 len = 0;
123 break;
124 }
125
126 *(buff + len) = (char)strtol((char *)number, NULL, 16);
127 len++;
128 }
129
130 return len;
131 }
132
133 const char *nlpid2str(uint8_t nlpid)
134 {
135 static char buf[4];
136 switch (nlpid) {
137 case NLPID_IP:
138 return "IPv4";
139 case NLPID_IPV6:
140 return "IPv6";
141 case NLPID_SNAP:
142 return "SNAP";
143 case NLPID_CLNP:
144 return "CLNP";
145 case NLPID_ESIS:
146 return "ES-IS";
147 default:
148 snprintf(buf, sizeof(buf), "%hhu", nlpid);
149 return buf;
150 }
151 }
152
153 /*
154 * converts the nlpids struct (filled by TLV #129)
155 * into a string
156 */
157
158 char *nlpid2string(struct nlpids *nlpids)
159 {
160 int i;
161 char tbuf[256];
162 nlpidstring[0] = '\0';
163
164 for (i = 0; i < nlpids->count; i++) {
165 snprintf(tbuf, sizeof(tbuf), "%s",
166 nlpid2str(nlpids->nlpids[i]));
167 strlcat(nlpidstring, tbuf, sizeof(nlpidstring));
168 if (nlpids->count - i > 1)
169 strlcat(nlpidstring, ", ", sizeof(nlpidstring));
170 }
171
172 return nlpidstring;
173 }
174
175 /*
176 * Returns 0 on error, IS-IS Circuit Type on ok
177 */
178 int string2circuit_t(const char *str)
179 {
180
181 if (!str)
182 return 0;
183
184 if (!strcmp(str, "level-1"))
185 return IS_LEVEL_1;
186
187 if (!strcmp(str, "level-2-only") || !strcmp(str, "level-2"))
188 return IS_LEVEL_2;
189
190 if (!strcmp(str, "level-1-2"))
191 return IS_LEVEL_1_AND_2;
192
193 return 0;
194 }
195
196 const char *circuit_state2string(int state)
197 {
198
199 switch (state) {
200 case C_STATE_INIT:
201 return "Init";
202 case C_STATE_CONF:
203 return "Config";
204 case C_STATE_UP:
205 return "Up";
206 default:
207 return "Unknown";
208 }
209 return NULL;
210 }
211
212 const char *circuit_type2string(int type)
213 {
214
215 switch (type) {
216 case CIRCUIT_T_P2P:
217 return "p2p";
218 case CIRCUIT_T_BROADCAST:
219 return "lan";
220 case CIRCUIT_T_LOOPBACK:
221 return "loopback";
222 default:
223 return "Unknown";
224 }
225 return NULL;
226 }
227
228 const char *circuit_t2string(int circuit_t)
229 {
230 switch (circuit_t) {
231 case IS_LEVEL_1:
232 return "L1";
233 case IS_LEVEL_2:
234 return "L2";
235 case IS_LEVEL_1_AND_2:
236 return "L1L2";
237 default:
238 return "??";
239 }
240
241 return NULL; /* not reached */
242 }
243
244 const char *syst2string(int type)
245 {
246 switch (type) {
247 case ISIS_SYSTYPE_ES:
248 return "ES";
249 case ISIS_SYSTYPE_IS:
250 return "IS";
251 case ISIS_SYSTYPE_L1_IS:
252 return "1";
253 case ISIS_SYSTYPE_L2_IS:
254 return "2";
255 default:
256 return "??";
257 }
258
259 return NULL; /* not reached */
260 }
261
262 const char *isis_hello_padding2string(int hello_padding_type)
263 {
264 switch (hello_padding_type) {
265 case ISIS_HELLO_PADDING_DISABLED:
266 return "no";
267 case ISIS_HELLO_PADDING_DURING_ADJACENCY_FORMATION:
268 return "during-adjacency-formation";
269 case ISIS_HELLO_PADDING_ALWAYS:
270 return "yes";
271 }
272 return NULL; /* not reached */
273 }
274
275 const char *time2string(uint32_t time)
276 {
277 uint32_t rest;
278 char tbuf[32];
279 datestring[0] = '\0';
280
281 if (time == 0)
282 return "-";
283
284 if (time / SECS_PER_YEAR) {
285 snprintf(tbuf, sizeof(tbuf), "%uY", time / SECS_PER_YEAR);
286 strlcat(datestring, tbuf, sizeof(datestring));
287 }
288 rest = time % SECS_PER_YEAR;
289 if (rest / SECS_PER_MONTH) {
290 snprintf(tbuf, sizeof(tbuf), "%uM", rest / SECS_PER_MONTH);
291 strlcat(datestring, tbuf, sizeof(datestring));
292 }
293 rest = rest % SECS_PER_MONTH;
294 if (rest / SECS_PER_WEEK) {
295 snprintf(tbuf, sizeof(tbuf), "%uw", rest / SECS_PER_WEEK);
296 strlcat(datestring, tbuf, sizeof(datestring));
297 }
298 rest = rest % SECS_PER_WEEK;
299 if (rest / SECS_PER_DAY) {
300 snprintf(tbuf, sizeof(tbuf), "%ud", rest / SECS_PER_DAY);
301 strlcat(datestring, tbuf, sizeof(datestring));
302 }
303 rest = rest % SECS_PER_DAY;
304 if (rest / SECS_PER_HOUR) {
305 snprintf(tbuf, sizeof(tbuf), "%uh", rest / SECS_PER_HOUR);
306 strlcat(datestring, tbuf, sizeof(datestring));
307 }
308 rest = rest % SECS_PER_HOUR;
309 if (rest / SECS_PER_MINUTE) {
310 snprintf(tbuf, sizeof(tbuf), "%um", rest / SECS_PER_MINUTE);
311 strlcat(datestring, tbuf, sizeof(datestring));
312 }
313 rest = rest % SECS_PER_MINUTE;
314 if (rest) {
315 snprintf(tbuf, sizeof(tbuf), "%us", rest);
316 strlcat(datestring, tbuf, sizeof(datestring));
317 }
318
319 return datestring;
320 }
321
322 /*
323 * routine to decrement a timer by a random
324 * number
325 *
326 * first argument is the timer and the second is
327 * the jitter
328 */
329 unsigned long isis_jitter(unsigned long timer, unsigned long jitter)
330 {
331 int j, k;
332
333 if (jitter >= 100)
334 return timer;
335
336 if (timer == 1)
337 return timer;
338 /*
339 * randomizing just the percent value provides
340 * no good random numbers - hence the spread
341 * to RANDOM_SPREAD (100000), which is ok as
342 * most IS-IS timers are no longer than 16 bit
343 */
344
345 j = 1 + (int)((RANDOM_SPREAD * frr_weak_random()) / (RAND_MAX + 1.0));
346
347 k = timer - (timer * (100 - jitter)) / 100;
348
349 timer = timer - (k * j / RANDOM_SPREAD);
350
351 return timer;
352 }
353
354 struct in_addr newprefix2inaddr(uint8_t *prefix_start, uint8_t prefix_masklen)
355 {
356 memset(&new_prefix, 0, sizeof(new_prefix));
357 memcpy(&new_prefix, prefix_start,
358 (prefix_masklen & 0x3F)
359 ? ((((prefix_masklen & 0x3F) - 1) >> 3) + 1)
360 : 0);
361 return new_prefix;
362 }
363
364 /*
365 * Returns the dynamic hostname associated with the passed system ID.
366 * If no dynamic hostname found then returns formatted system ID.
367 */
368 const char *print_sys_hostname(const uint8_t *sysid)
369 {
370 struct isis_dynhn *dyn;
371 struct isis *isis = NULL;
372 struct listnode *node;
373
374 if (!sysid)
375 return "nullsysid";
376
377 /* For our system ID return our host name */
378 isis = isis_lookup_by_sysid(sysid);
379 if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
380 return cmd_hostname_get();
381
382 for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
383 dyn = dynhn_find_by_id(isis, sysid);
384 if (dyn)
385 return dyn->hostname;
386 }
387
388 snprintfrr(sys_hostname, ISO_SYSID_STRLEN, "%pSY", sysid);
389 return sys_hostname;
390 }
391
392 /*
393 * This function is a generic utility that logs data of given length.
394 * Move this to a shared lib so that any protocol can use it.
395 */
396 void zlog_dump_data(void *data, int len)
397 {
398 int i;
399 unsigned char *p;
400 unsigned char c;
401 char bytestr[4];
402 char addrstr[10];
403 char hexstr[16 * 3 + 5];
404 char charstr[16 * 1 + 5];
405
406 p = data;
407 memset(bytestr, 0, sizeof(bytestr));
408 memset(addrstr, 0, sizeof(addrstr));
409 memset(hexstr, 0, sizeof(hexstr));
410 memset(charstr, 0, sizeof(charstr));
411
412 for (i = 1; i <= len; i++) {
413 c = *p;
414 if (isalnum(c) == 0)
415 c = '.';
416
417 /* store address for this line */
418 if ((i % 16) == 1)
419 snprintf(addrstr, sizeof(addrstr), "%p", p);
420
421 /* store hex str (for left side) */
422 snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
423 strlcat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1);
424
425 /* store char str (for right side) */
426 snprintf(bytestr, sizeof(bytestr), "%c", c);
427 strlcat(charstr, bytestr,
428 sizeof(charstr) - strlen(charstr) - 1);
429
430 if ((i % 16) == 0) {
431 /* line completed */
432 zlog_debug("[%8.8s] %-50.50s %s", addrstr, hexstr,
433 charstr);
434 hexstr[0] = 0;
435 charstr[0] = 0;
436 } else if ((i % 8) == 0) {
437 /* half line: add whitespaces */
438 strlcat(hexstr, " ",
439 sizeof(hexstr) - strlen(hexstr) - 1);
440 strlcat(charstr, " ",
441 sizeof(charstr) - strlen(charstr) - 1);
442 }
443 p++; /* next byte */
444 }
445
446 /* print rest of buffer if not empty */
447 if (strlen(hexstr) > 0)
448 zlog_debug("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr);
449 return;
450 }
451
452 void log_multiline(int priority, const char *prefix, const char *format, ...)
453 {
454 char shortbuf[256];
455 va_list ap;
456 char *p;
457
458 va_start(ap, format);
459 p = vasnprintfrr(MTYPE_TMP, shortbuf, sizeof(shortbuf), format, ap);
460 va_end(ap);
461
462 if (!p)
463 return;
464
465 char *saveptr = NULL;
466 for (char *line = strtok_r(p, "\n", &saveptr); line;
467 line = strtok_r(NULL, "\n", &saveptr)) {
468 zlog(priority, "%s%s", prefix, line);
469 }
470
471 if (p != shortbuf)
472 XFREE(MTYPE_TMP, p);
473 }
474
475 char *log_uptime(time_t uptime, char *buf, size_t nbuf)
476 {
477 struct tm *tm;
478 time_t difftime = time(NULL);
479 difftime -= uptime;
480 tm = gmtime(&difftime);
481
482 if (difftime < ONE_DAY_SECOND)
483 snprintf(buf, nbuf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
484 tm->tm_sec);
485 else if (difftime < ONE_WEEK_SECOND)
486 snprintf(buf, nbuf, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
487 tm->tm_min);
488 else
489 snprintf(buf, nbuf, "%02dw%dd%02dh", tm->tm_yday / 7,
490 tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
491
492 return buf;
493 }
494
495 void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
496 {
497 char shortbuf[256];
498 va_list ap;
499 char *p;
500
501 va_start(ap, format);
502 p = vasnprintfrr(MTYPE_TMP, shortbuf, sizeof(shortbuf), format, ap);
503 va_end(ap);
504
505 if (!p)
506 return;
507
508 char *saveptr = NULL;
509 for (char *line = strtok_r(p, "\n", &saveptr); line;
510 line = strtok_r(NULL, "\n", &saveptr)) {
511 vty_out(vty, "%s%s\n", prefix, line);
512 }
513
514 if (p != shortbuf)
515 XFREE(MTYPE_TMP, p);
516 }
517
518 void vty_out_timestr(struct vty *vty, time_t uptime)
519 {
520 time_t difftime = time(NULL);
521 char buf[MONOTIME_STRLEN];
522
523 difftime -= uptime;
524
525 frrtime_to_interval(difftime, buf, sizeof(buf));
526
527 vty_out(vty, "%s ago", buf);
528 }