]> git.proxmox.com Git - mirror_frr.git/blame - isisd/isis_misc.c
bgpd: fix dereference of null pointer in bgp_attr_aspath
[mirror_frr.git] / isisd / isis_misc.c
CommitLineData
eb5d44eb 1/*
2 * IS-IS Rout(e)ing protocol - isis_misc.h
3 * Miscellanous routines
4 *
5 * Copyright (C) 2001,2002 Sampo Saaristo
d62a17ae 6 * Tampere University of Technology
eb5d44eb 7 * Institute of Communications Engineering
8 *
d62a17ae 9 * This program is free software; you can redistribute it and/or modify it
10 * under the terms of the GNU General Public Licenseas published by the Free
11 * Software Foundation; either version 2 of the License, or (at your option)
eb5d44eb 12 * any later version.
13 *
d62a17ae 14 * This program is distributed in the hope that it will be useful,but WITHOUT
15 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
16 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
eb5d44eb 17 * more details.
896014f4
DL
18 *
19 * You should have received a copy of the GNU General Public License along
20 * with this program; see the file COPYING; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
eb5d44eb 22 */
23
eb5d44eb 24#include <zebra.h>
eb5d44eb 25
c7179009 26#include "printfrr.h"
eb5d44eb 27#include "stream.h"
28#include "vty.h"
29#include "hash.h"
30#include "if.h"
9e867fe6 31#include "command.h"
5920b3eb 32#include "network.h"
eb5d44eb 33
eb5d44eb 34#include "isisd/isis_constants.h"
35#include "isisd/isis_common.h"
3f045a08 36#include "isisd/isis_flags.h"
eb5d44eb 37#include "isisd/isis_circuit.h"
3f045a08 38#include "isisd/isis_csm.h"
eb5d44eb 39#include "isisd/isisd.h"
40#include "isisd/isis_misc.h"
41
eb5d44eb 42#include "isisd/isis_lsp.h"
43#include "isisd/isis_constants.h"
44#include "isisd/isis_adjacency.h"
3f045a08 45#include "isisd/isis_dynhn.h"
eb5d44eb 46
73d1aead 47/* staticly assigned vars for printing purposes */
48struct in_addr new_prefix;
73d1aead 49/* len of xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx */
73d1aead 50/* + place for #0 termination */
9879e291 51char isonet[51];
73d1aead 52/* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */
53char datestring[20];
54char nlpidstring[30];
55
eb5d44eb 56/*
57 * This converts the isonet to its printable format
58 */
d7c0a89a 59const char *isonet_print(const uint8_t *from, int len)
f390d2c7 60{
d62a17ae 61 int i = 0;
7533cad7
QY
62 char tbuf[4];
63 isonet[0] = '\0';
d62a17ae 64
65 if (!from)
66 return "unknown";
67
68 while (i < len) {
69 if (i & 1) {
7533cad7
QY
70 snprintf(tbuf, sizeof(tbuf), "%02x", *(from + i));
71 strlcat(isonet, tbuf, sizeof(isonet));
d62a17ae 72 } else {
73 if (i == (len - 1)) { /* No dot at the end of address */
7533cad7
QY
74 snprintf(tbuf, sizeof(tbuf), "%02x",
75 *(from + i));
76 strlcat(isonet, tbuf, sizeof(isonet));
d62a17ae 77 } else {
7533cad7
QY
78 snprintf(tbuf, sizeof(tbuf), "%02x.",
79 *(from + i));
80 strlcat(isonet, tbuf, sizeof(isonet));
d62a17ae 81 }
82 }
83 i++;
f390d2c7 84 }
7533cad7 85
d62a17ae 86 return isonet;
eb5d44eb 87}
88
89/*
90 * Returns 0 on error, length of buff on ok
d62a17ae 91 * extract dot from the dotted str, and insert all the number in a buff
eb5d44eb 92 */
d7c0a89a 93int dotformat2buff(uint8_t *buff, const char *dotted)
eb5d44eb 94{
d62a17ae 95 int dotlen, len = 0;
96 const char *pos = dotted;
d7c0a89a 97 uint8_t number[3];
d62a17ae 98 int nextdotpos = 2;
99
100 number[2] = '\0';
101 dotlen = strlen(dotted);
102 if (dotlen > 50) {
103 /* this can't be an iso net, its too long */
104 return 0;
f390d2c7 105 }
106
d62a17ae 107 while ((pos - dotted) < dotlen && len < 20) {
108 if (*pos == '.') {
109 /* we expect the . at 2, and than every 5 */
110 if ((pos - dotted) != nextdotpos) {
111 len = 0;
112 break;
113 }
114 nextdotpos += 5;
115 pos++;
116 continue;
117 }
118 /* we must have at least two chars left here */
119 if (dotlen - (pos - dotted) < 2) {
120 len = 0;
121 break;
122 }
123
fefa5e0f
DL
124 if ((isxdigit((unsigned char)*pos)) &&
125 (isxdigit((unsigned char)*(pos + 1)))) {
d62a17ae 126 memcpy(number, pos, 2);
127 pos += 2;
128 } else {
129 len = 0;
130 break;
131 }
132
133 *(buff + len) = (char)strtol((char *)number, NULL, 16);
134 len++;
f390d2c7 135 }
eb5d44eb 136
d62a17ae 137 return len;
eb5d44eb 138}
f390d2c7 139
eb5d44eb 140/*
141 * conversion of XXXX.XXXX.XXXX to memory
142 */
d7c0a89a 143int sysid2buff(uint8_t *buff, const char *dotted)
f390d2c7 144{
d62a17ae 145 int len = 0;
146 const char *pos = dotted;
d7c0a89a 147 uint8_t number[3];
d62a17ae 148
149 number[2] = '\0';
150 // surely not a sysid_string if not 14 length
151 if (strlen(dotted) != 14) {
152 return 0;
f390d2c7 153 }
154
d62a17ae 155 while (len < ISIS_SYS_ID_LEN) {
156 if (*pos == '.') {
157 /* the . is not positioned correctly */
158 if (((pos - dotted) != 4) && ((pos - dotted) != 9)) {
159 len = 0;
160 break;
161 }
162 pos++;
163 continue;
164 }
fefa5e0f
DL
165 if ((isxdigit((unsigned char)*pos)) &&
166 (isxdigit((unsigned char)*(pos + 1)))) {
d62a17ae 167 memcpy(number, pos, 2);
168 pos += 2;
169 } else {
170 len = 0;
171 break;
172 }
173
174 *(buff + len) = (char)strtol((char *)number, NULL, 16);
175 len++;
176 }
eb5d44eb 177
d62a17ae 178 return len;
eb5d44eb 179}
180
9879e291
CF
181const char *nlpid2str(uint8_t nlpid)
182{
183 static char buf[4];
184 switch (nlpid) {
185 case NLPID_IP:
186 return "IPv4";
187 case NLPID_IPV6:
188 return "IPv6";
189 case NLPID_SNAP:
190 return "SNAP";
191 case NLPID_CLNP:
192 return "CLNP";
193 case NLPID_ESIS:
194 return "ES-IS";
195 default:
6cde4b45 196 snprintf(buf, sizeof(buf), "%hhu", nlpid);
9879e291
CF
197 return buf;
198 }
199}
200
eb5d44eb 201/*
202 * converts the nlpids struct (filled by TLV #129)
203 * into a string
204 */
205
d62a17ae 206char *nlpid2string(struct nlpids *nlpids)
f390d2c7 207{
d62a17ae 208 int i;
7533cad7
QY
209 char tbuf[256];
210 nlpidstring[0] = '\0';
d62a17ae 211
212 for (i = 0; i < nlpids->count; i++) {
7533cad7
QY
213 snprintf(tbuf, sizeof(tbuf), "%s",
214 nlpid2str(nlpids->nlpids[i]));
215 strlcat(nlpidstring, tbuf, sizeof(nlpidstring));
d62a17ae 216 if (nlpids->count - i > 1)
7533cad7 217 strlcat(nlpidstring, ", ", sizeof(nlpidstring));
f390d2c7 218 }
eb5d44eb 219
d62a17ae 220 return nlpidstring;
eb5d44eb 221}
222
eb5d44eb 223/*
224 * Returns 0 on error, IS-IS Circuit Type on ok
225 */
d62a17ae 226int string2circuit_t(const char *str)
eb5d44eb 227{
f390d2c7 228
d62a17ae 229 if (!str)
230 return 0;
f390d2c7 231
d62a17ae 232 if (!strcmp(str, "level-1"))
233 return IS_LEVEL_1;
eb5d44eb 234
d62a17ae 235 if (!strcmp(str, "level-2-only") || !strcmp(str, "level-2"))
236 return IS_LEVEL_2;
f390d2c7 237
d62a17ae 238 if (!strcmp(str, "level-1-2"))
239 return IS_LEVEL_1_AND_2;
eb5d44eb 240
d62a17ae 241 return 0;
eb5d44eb 242}
243
d62a17ae 244const char *circuit_state2string(int state)
3f045a08
JB
245{
246
d62a17ae 247 switch (state) {
248 case C_STATE_INIT:
249 return "Init";
250 case C_STATE_CONF:
251 return "Config";
252 case C_STATE_UP:
253 return "Up";
254 default:
255 return "Unknown";
256 }
257 return NULL;
3f045a08
JB
258}
259
d62a17ae 260const char *circuit_type2string(int type)
3f045a08
JB
261{
262
d62a17ae 263 switch (type) {
264 case CIRCUIT_T_P2P:
265 return "p2p";
266 case CIRCUIT_T_BROADCAST:
267 return "lan";
268 case CIRCUIT_T_LOOPBACK:
269 return "loopback";
270 default:
271 return "Unknown";
272 }
273 return NULL;
3f045a08
JB
274}
275
d62a17ae 276const char *circuit_t2string(int circuit_t)
eb5d44eb 277{
d62a17ae 278 switch (circuit_t) {
279 case IS_LEVEL_1:
280 return "L1";
281 case IS_LEVEL_2:
282 return "L2";
283 case IS_LEVEL_1_AND_2:
284 return "L1L2";
285 default:
286 return "??";
287 }
288
289 return NULL; /* not reached */
eb5d44eb 290}
291
d62a17ae 292const char *syst2string(int type)
eb5d44eb 293{
d62a17ae 294 switch (type) {
295 case ISIS_SYSTYPE_ES:
296 return "ES";
297 case ISIS_SYSTYPE_IS:
298 return "IS";
299 case ISIS_SYSTYPE_L1_IS:
300 return "1";
301 case ISIS_SYSTYPE_L2_IS:
302 return "2";
303 default:
304 return "??";
305 }
306
307 return NULL; /* not reached */
eb5d44eb 308}
309
310/*
311 * Print functions - we print to static vars
312 */
d7c0a89a 313const char *snpa_print(const uint8_t *from)
eb5d44eb 314{
9879e291
CF
315 return isis_format_id(from, ISIS_SYS_ID_LEN);
316}
f390d2c7 317
d7c0a89a 318const char *sysid_print(const uint8_t *from)
9879e291
CF
319{
320 return isis_format_id(from, ISIS_SYS_ID_LEN);
321}
eb5d44eb 322
d7c0a89a 323const char *rawlspid_print(const uint8_t *from)
9879e291
CF
324{
325 return isis_format_id(from, 8);
eb5d44eb 326}
327
9879e291
CF
328#define FORMAT_ID_SIZE sizeof("0000.0000.0000.00-00")
329const char *isis_format_id(const uint8_t *id, size_t len)
eb5d44eb 330{
9879e291
CF
331#define FORMAT_BUF_COUNT 4
332 static char buf_ring[FORMAT_BUF_COUNT][FORMAT_ID_SIZE];
333 static size_t cur_buf = 0;
d62a17ae 334
9879e291 335 char *rv;
d62a17ae 336
9879e291
CF
337 cur_buf++;
338 if (cur_buf >= FORMAT_BUF_COUNT)
339 cur_buf = 0;
eb5d44eb 340
9879e291 341 rv = buf_ring[cur_buf];
f390d2c7 342
9879e291
CF
343 if (!id) {
344 snprintf(rv, FORMAT_ID_SIZE, "unknown");
345 return rv;
346 }
eb5d44eb 347
9879e291
CF
348 if (len < 6) {
349 snprintf(rv, FORMAT_ID_SIZE, "Short ID");
350 return rv;
351 }
d62a17ae 352
9879e291
CF
353 snprintf(rv, FORMAT_ID_SIZE, "%02x%02x.%02x%02x.%02x%02x", id[0], id[1],
354 id[2], id[3], id[4], id[5]);
355
356 if (len > 6)
357 snprintf(rv + 14, FORMAT_ID_SIZE - 14, ".%02x", id[6]);
358 if (len > 7)
359 snprintf(rv + 17, FORMAT_ID_SIZE - 17, "-%02x", id[7]);
d62a17ae 360
9879e291 361 return rv;
eb5d44eb 362}
363
d7c0a89a 364const char *time2string(uint32_t time)
f390d2c7 365{
d7c0a89a 366 uint32_t rest;
7533cad7
QY
367 char tbuf[32];
368 datestring[0] = '\0';
d62a17ae 369
370 if (time == 0)
371 return "-";
372
7533cad7
QY
373 if (time / SECS_PER_YEAR) {
374 snprintf(tbuf, sizeof(tbuf), "%uY", time / SECS_PER_YEAR);
375 strlcat(datestring, tbuf, sizeof(datestring));
376 }
d62a17ae 377 rest = time % SECS_PER_YEAR;
7533cad7
QY
378 if (rest / SECS_PER_MONTH) {
379 snprintf(tbuf, sizeof(tbuf), "%uM", rest / SECS_PER_MONTH);
380 strlcat(datestring, tbuf, sizeof(datestring));
381 }
d62a17ae 382 rest = rest % SECS_PER_MONTH;
7533cad7
QY
383 if (rest / SECS_PER_WEEK) {
384 snprintf(tbuf, sizeof(tbuf), "%uw", rest / SECS_PER_WEEK);
385 strlcat(datestring, tbuf, sizeof(datestring));
386 }
d62a17ae 387 rest = rest % SECS_PER_WEEK;
7533cad7
QY
388 if (rest / SECS_PER_DAY) {
389 snprintf(tbuf, sizeof(tbuf), "%ud", rest / SECS_PER_DAY);
390 strlcat(datestring, tbuf, sizeof(datestring));
391 }
d62a17ae 392 rest = rest % SECS_PER_DAY;
7533cad7
QY
393 if (rest / SECS_PER_HOUR) {
394 snprintf(tbuf, sizeof(tbuf), "%uh", rest / SECS_PER_HOUR);
395 strlcat(datestring, tbuf, sizeof(datestring));
396 }
d62a17ae 397 rest = rest % SECS_PER_HOUR;
7533cad7
QY
398 if (rest / SECS_PER_MINUTE) {
399 snprintf(tbuf, sizeof(tbuf), "%um", rest / SECS_PER_MINUTE);
400 strlcat(datestring, tbuf, sizeof(datestring));
401 }
d62a17ae 402 rest = rest % SECS_PER_MINUTE;
7533cad7
QY
403 if (rest) {
404 snprintf(tbuf, sizeof(tbuf), "%us", rest);
405 strlcat(datestring, tbuf, sizeof(datestring));
406 }
d62a17ae 407
408 return datestring;
eb5d44eb 409}
410
411/*
412 * routine to decrement a timer by a random
413 * number
414 *
415 * first argument is the timer and the second is
416 * the jitter
417 */
d62a17ae 418unsigned long isis_jitter(unsigned long timer, unsigned long jitter)
eb5d44eb 419{
d62a17ae 420 int j, k;
eb5d44eb 421
d62a17ae 422 if (jitter >= 100)
423 return timer;
eb5d44eb 424
d62a17ae 425 if (timer == 1)
426 return timer;
427 /*
428 * randomizing just the percent value provides
429 * no good random numbers - hence the spread
430 * to RANDOM_SPREAD (100000), which is ok as
431 * most IS-IS timers are no longer than 16 bit
432 */
eb5d44eb 433
5920b3eb 434 j = 1 + (int)((RANDOM_SPREAD * frr_weak_random()) / (RAND_MAX + 1.0));
eb5d44eb 435
d62a17ae 436 k = timer - (timer * (100 - jitter)) / 100;
eb5d44eb 437
d62a17ae 438 timer = timer - (k * j / RANDOM_SPREAD);
eb5d44eb 439
d62a17ae 440 return timer;
eb5d44eb 441}
442
d7c0a89a 443struct in_addr newprefix2inaddr(uint8_t *prefix_start, uint8_t prefix_masklen)
eb5d44eb 444{
d62a17ae 445 memset(&new_prefix, 0, sizeof(new_prefix));
446 memcpy(&new_prefix, prefix_start,
447 (prefix_masklen & 0x3F)
448 ? ((((prefix_masklen & 0x3F) - 1) >> 3) + 1)
449 : 0);
450 return new_prefix;
eb5d44eb 451}
452
3f045a08
JB
453/*
454 * Returns the dynamic hostname associated with the passed system ID.
455 * If no dynamic hostname found then returns formatted system ID.
456 */
36944791 457const char *print_sys_hostname(const uint8_t *sysid)
3f045a08 458{
d62a17ae 459 struct isis_dynhn *dyn;
eab88f36 460 struct isis *isis = NULL;
240f48b3 461 struct listnode *node;
3f045a08 462
d62a17ae 463 if (!sysid)
464 return "nullsysid";
3f045a08 465
d62a17ae 466 /* For our system ID return our host name */
eab88f36 467 isis = isis_lookup_by_sysid(sysid);
52a7c25e 468 if (isis && !CHECK_FLAG(im->options, F_ISIS_UNIT_TEST))
6b3ee3a0 469 return cmd_hostname_get();
3f045a08 470
240f48b3
IR
471 for (ALL_LIST_ELEMENTS_RO(im->isis, node, isis)) {
472 dyn = dynhn_find_by_id(isis, sysid);
473 if (dyn)
474 return dyn->hostname;
475 }
3f045a08 476
d62a17ae 477 return sysid_print(sysid);
3f045a08
JB
478}
479
480/*
481 * This function is a generic utility that logs data of given length.
482 * Move this to a shared lib so that any protocol can use it.
483 */
d62a17ae 484void zlog_dump_data(void *data, int len)
3f045a08 485{
d62a17ae 486 int i;
487 unsigned char *p;
488 unsigned char c;
489 char bytestr[4];
490 char addrstr[10];
491 char hexstr[16 * 3 + 5];
492 char charstr[16 * 1 + 5];
493
494 p = data;
495 memset(bytestr, 0, sizeof(bytestr));
496 memset(addrstr, 0, sizeof(addrstr));
497 memset(hexstr, 0, sizeof(hexstr));
498 memset(charstr, 0, sizeof(charstr));
499
500 for (i = 1; i <= len; i++) {
501 c = *p;
502 if (isalnum(c) == 0)
503 c = '.';
504
505 /* store address for this line */
506 if ((i % 16) == 1)
507 snprintf(addrstr, sizeof(addrstr), "%p", p);
508
509 /* store hex str (for left side) */
510 snprintf(bytestr, sizeof(bytestr), "%02X ", *p);
511 strncat(hexstr, bytestr, sizeof(hexstr) - strlen(hexstr) - 1);
512
513 /* store char str (for right side) */
514 snprintf(bytestr, sizeof(bytestr), "%c", c);
515 strncat(charstr, bytestr,
516 sizeof(charstr) - strlen(charstr) - 1);
517
518 if ((i % 16) == 0) {
519 /* line completed */
520 zlog_debug("[%8.8s] %-50.50s %s", addrstr, hexstr,
521 charstr);
522 hexstr[0] = 0;
523 charstr[0] = 0;
524 } else if ((i % 8) == 0) {
525 /* half line: add whitespaces */
526 strncat(hexstr, " ",
527 sizeof(hexstr) - strlen(hexstr) - 1);
528 strncat(charstr, " ",
529 sizeof(charstr) - strlen(charstr) - 1);
530 }
531 p++; /* next byte */
532 }
533
534 /* print rest of buffer if not empty */
535 if (strlen(hexstr) > 0)
536 zlog_debug("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr);
537 return;
3f045a08 538}
9879e291 539
9879e291
CF
540void log_multiline(int priority, const char *prefix, const char *format, ...)
541{
c7179009 542 char shortbuf[256];
9879e291
CF
543 va_list ap;
544 char *p;
545
546 va_start(ap, format);
94c4f72d 547 p = vasnprintfrr(MTYPE_TMP, shortbuf, sizeof(shortbuf), format, ap);
9879e291
CF
548 va_end(ap);
549
550 if (!p)
551 return;
552
553 char *saveptr = NULL;
554 for (char *line = strtok_r(p, "\n", &saveptr); line;
555 line = strtok_r(NULL, "\n", &saveptr)) {
556 zlog(priority, "%s%s", prefix, line);
557 }
558
c7179009
DL
559 if (p != shortbuf)
560 XFREE(MTYPE_TMP, p);
9879e291
CF
561}
562
9cd06cd7
RW
563char *log_uptime(time_t uptime, char *buf, size_t nbuf)
564{
565 struct tm *tm;
566 time_t difftime = time(NULL);
567 difftime -= uptime;
568 tm = gmtime(&difftime);
569
570 if (difftime < ONE_DAY_SECOND)
571 snprintf(buf, nbuf, "%02d:%02d:%02d", tm->tm_hour, tm->tm_min,
572 tm->tm_sec);
573 else if (difftime < ONE_WEEK_SECOND)
574 snprintf(buf, nbuf, "%dd%02dh%02dm", tm->tm_yday, tm->tm_hour,
575 tm->tm_min);
576 else
577 snprintf(buf, nbuf, "%02dw%dd%02dh", tm->tm_yday / 7,
578 tm->tm_yday - ((tm->tm_yday / 7) * 7), tm->tm_hour);
579
580 return buf;
581}
582
9879e291
CF
583void vty_multiline(struct vty *vty, const char *prefix, const char *format, ...)
584{
c7179009 585 char shortbuf[256];
9879e291
CF
586 va_list ap;
587 char *p;
588
589 va_start(ap, format);
94c4f72d 590 p = vasnprintfrr(MTYPE_TMP, shortbuf, sizeof(shortbuf), format, ap);
9879e291
CF
591 va_end(ap);
592
593 if (!p)
594 return;
595
596 char *saveptr = NULL;
597 for (char *line = strtok_r(p, "\n", &saveptr); line;
598 line = strtok_r(NULL, "\n", &saveptr)) {
599 vty_out(vty, "%s%s\n", prefix, line);
600 }
601
c7179009
DL
602 if (p != shortbuf)
603 XFREE(MTYPE_TMP, p);
9879e291 604}
02cd317e
CF
605
606void vty_out_timestr(struct vty *vty, time_t uptime)
607{
02cd317e 608 time_t difftime = time(NULL);
d0636ead
MS
609 char buf[MONOTIME_STRLEN];
610
02cd317e 611 difftime -= uptime;
a2700b50 612
d0636ead
MS
613 frrtime_to_interval(difftime, buf, sizeof(buf));
614
615 vty_out(vty, "%s ago", buf);
02cd317e 616}