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