]>
Commit | Line | Data |
---|---|---|
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 | |
32 | #include "isisd/dict.h" | |
33 | #include "isisd/isis_constants.h" | |
34 | #include "isisd/isis_common.h" | |
3f045a08 | 35 | #include "isisd/isis_flags.h" |
eb5d44eb | 36 | #include "isisd/isis_circuit.h" |
3f045a08 | 37 | #include "isisd/isis_csm.h" |
eb5d44eb | 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" | |
3f045a08 | 45 | #include "isisd/isis_dynhn.h" |
eb5d44eb | 46 | |
73d1aead | 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 | ||
eb5d44eb | 62 | /* |
63 | * This converts the isonet to its printable format | |
64 | */ | |
d62a17ae | 65 | const char *isonet_print(const u_char *from, int len) |
f390d2c7 | 66 | { |
d62a17ae | 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++; | |
f390d2c7 | 87 | } |
d62a17ae | 88 | *(pos) = '\0'; |
89 | return isonet; | |
eb5d44eb | 90 | } |
91 | ||
92 | /* | |
93 | * Returns 0 on error, length of buff on ok | |
d62a17ae | 94 | * extract dot from the dotted str, and insert all the number in a buff |
eb5d44eb | 95 | */ |
d62a17ae | 96 | int dotformat2buff(u_char *buff, const char *dotted) |
eb5d44eb | 97 | { |
d62a17ae | 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; | |
f390d2c7 | 108 | } |
109 | ||
d62a17ae | 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++; | |
f390d2c7 | 137 | } |
eb5d44eb | 138 | |
d62a17ae | 139 | return len; |
eb5d44eb | 140 | } |
f390d2c7 | 141 | |
eb5d44eb | 142 | /* |
143 | * conversion of XXXX.XXXX.XXXX to memory | |
144 | */ | |
d62a17ae | 145 | int sysid2buff(u_char *buff, const char *dotted) |
f390d2c7 | 146 | { |
d62a17ae | 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; | |
f390d2c7 | 155 | } |
156 | ||
d62a17ae | 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 | } | |
eb5d44eb | 178 | |
d62a17ae | 179 | return len; |
eb5d44eb | 180 | } |
181 | ||
182 | /* | |
183 | * converts the nlpids struct (filled by TLV #129) | |
184 | * into a string | |
185 | */ | |
186 | ||
d62a17ae | 187 | char *nlpid2string(struct nlpids *nlpids) |
f390d2c7 | 188 | { |
d62a17ae | 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, ", "); | |
f390d2c7 | 215 | } |
eb5d44eb | 216 | |
d62a17ae | 217 | *(pos) = '\0'; |
f390d2c7 | 218 | |
d62a17ae | 219 | return nlpidstring; |
eb5d44eb | 220 | } |
221 | ||
222 | /* | |
223 | * supports the given af ? | |
224 | */ | |
d62a17ae | 225 | int speaks(struct nlpids *nlpids, int family) |
eb5d44eb | 226 | { |
d62a17ae | 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; | |
eb5d44eb | 239 | } |
240 | ||
eb5d44eb | 241 | /* |
242 | * Returns 0 on error, IS-IS Circuit Type on ok | |
243 | */ | |
d62a17ae | 244 | int string2circuit_t(const char *str) |
eb5d44eb | 245 | { |
f390d2c7 | 246 | |
d62a17ae | 247 | if (!str) |
248 | return 0; | |
f390d2c7 | 249 | |
d62a17ae | 250 | if (!strcmp(str, "level-1")) |
251 | return IS_LEVEL_1; | |
eb5d44eb | 252 | |
d62a17ae | 253 | if (!strcmp(str, "level-2-only") || !strcmp(str, "level-2")) |
254 | return IS_LEVEL_2; | |
f390d2c7 | 255 | |
d62a17ae | 256 | if (!strcmp(str, "level-1-2")) |
257 | return IS_LEVEL_1_AND_2; | |
eb5d44eb | 258 | |
d62a17ae | 259 | return 0; |
eb5d44eb | 260 | } |
261 | ||
d62a17ae | 262 | const char *circuit_state2string(int state) |
3f045a08 JB |
263 | { |
264 | ||
d62a17ae | 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; | |
3f045a08 JB |
276 | } |
277 | ||
d62a17ae | 278 | const char *circuit_type2string(int type) |
3f045a08 JB |
279 | { |
280 | ||
d62a17ae | 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; | |
3f045a08 JB |
292 | } |
293 | ||
d62a17ae | 294 | const char *circuit_t2string(int circuit_t) |
eb5d44eb | 295 | { |
d62a17ae | 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 */ | |
eb5d44eb | 308 | } |
309 | ||
d62a17ae | 310 | const char *syst2string(int type) |
eb5d44eb | 311 | { |
d62a17ae | 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 */ | |
eb5d44eb | 326 | } |
327 | ||
328 | /* | |
329 | * Print functions - we print to static vars | |
330 | */ | |
d62a17ae | 331 | const char *snpa_print(const u_char *from) |
eb5d44eb | 332 | { |
d62a17ae | 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++; | |
f390d2c7 | 348 | } |
f390d2c7 | 349 | |
d62a17ae | 350 | sprintf((char *)pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); |
351 | pos += 2; | |
352 | *(pos) = '\0'; | |
eb5d44eb | 353 | |
d62a17ae | 354 | return snpa; |
eb5d44eb | 355 | } |
356 | ||
d62a17ae | 357 | const char *sysid_print(const u_char *from) |
eb5d44eb | 358 | { |
d62a17ae | 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++; | |
f390d2c7 | 374 | } |
eb5d44eb | 375 | |
d62a17ae | 376 | sprintf(pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1))); |
377 | pos += 2; | |
378 | *(pos) = '\0'; | |
f390d2c7 | 379 | |
d62a17ae | 380 | return sysid; |
eb5d44eb | 381 | } |
382 | ||
d62a17ae | 383 | const char *rawlspid_print(const u_char *from) |
eb5d44eb | 384 | { |
d62a17ae | 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; | |
eb5d44eb | 398 | } |
399 | ||
d62a17ae | 400 | const char *time2string(u_int32_t time) |
f390d2c7 | 401 | { |
d62a17ae | 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; | |
eb5d44eb | 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 | */ | |
d62a17ae | 441 | unsigned long isis_jitter(unsigned long timer, unsigned long jitter) |
eb5d44eb | 442 | { |
d62a17ae | 443 | int j, k; |
eb5d44eb | 444 | |
d62a17ae | 445 | if (jitter >= 100) |
446 | return timer; | |
eb5d44eb | 447 | |
d62a17ae | 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 | */ | |
eb5d44eb | 456 | |
d62a17ae | 457 | j = 1 + (int)((RANDOM_SPREAD * random()) / (RAND_MAX + 1.0)); |
eb5d44eb | 458 | |
d62a17ae | 459 | k = timer - (timer * (100 - jitter)) / 100; |
eb5d44eb | 460 | |
d62a17ae | 461 | timer = timer - (k * j / RANDOM_SPREAD); |
eb5d44eb | 462 | |
d62a17ae | 463 | return timer; |
eb5d44eb | 464 | } |
465 | ||
d62a17ae | 466 | struct in_addr newprefix2inaddr(u_char *prefix_start, u_char prefix_masklen) |
eb5d44eb | 467 | { |
d62a17ae | 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; | |
eb5d44eb | 474 | } |
475 | ||
9e867fe6 | 476 | /* |
477 | * Returns host.name if any, otherwise | |
478 | * it returns the system hostname. | |
479 | */ | |
d62a17ae | 480 | const char *unix_hostname(void) |
9e867fe6 | 481 | { |
d62a17ae | 482 | static struct utsname names; |
483 | const char *hostname; | |
9e867fe6 | 484 | |
d62a17ae | 485 | hostname = host.name; |
486 | if (!hostname) { | |
487 | uname(&names); | |
488 | hostname = names.nodename; | |
489 | } | |
eb5d44eb | 490 | |
d62a17ae | 491 | return hostname; |
9e867fe6 | 492 | } |
3f045a08 JB |
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 | */ | |
d62a17ae | 498 | const char *print_sys_hostname(const u_char *sysid) |
3f045a08 | 499 | { |
d62a17ae | 500 | struct isis_dynhn *dyn; |
3f045a08 | 501 | |
d62a17ae | 502 | if (!sysid) |
503 | return "nullsysid"; | |
3f045a08 | 504 | |
d62a17ae | 505 | /* For our system ID return our host name */ |
506 | if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0) | |
507 | return unix_hostname(); | |
3f045a08 | 508 | |
d62a17ae | 509 | dyn = dynhn_find_by_id(sysid); |
510 | if (dyn) | |
511 | return (const char *)dyn->name.name; | |
3f045a08 | 512 | |
d62a17ae | 513 | return sysid_print(sysid); |
3f045a08 JB |
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 | */ | |
d62a17ae | 520 | void zlog_dump_data(void *data, int len) |
3f045a08 | 521 | { |
d62a17ae | 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; | |
3f045a08 | 574 | } |