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