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