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