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