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