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