1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * IS-IS Rout(e)ing protocol - isis_misc.h
4 * Miscellanous routines
6 * Copyright (C) 2001,2002 Sampo Saaristo
7 * Tampere University of Technology
8 * Institute of Communications Engineering
21 #include "isisd/isis_constants.h"
22 #include "isisd/isis_common.h"
23 #include "isisd/isis_flags.h"
24 #include "isisd/isis_circuit.h"
25 #include "isisd/isis_csm.h"
26 #include "isisd/isisd.h"
27 #include "isisd/isis_misc.h"
29 #include "isisd/isis_lsp.h"
30 #include "isisd/isis_constants.h"
31 #include "isisd/isis_adjacency.h"
32 #include "isisd/isis_dynhn.h"
34 /* staticly assigned vars for printing purposes */
35 static char sys_hostname
[ISO_SYSID_STRLEN
];
36 struct in_addr new_prefix
;
37 /* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */
42 * Returns 0 on error, length of buff on ok
43 * extract dot from the dotted str, and insert all the number in a buff
45 int dotformat2buff(uint8_t *buff
, const char *dotted
)
48 const char *pos
= dotted
;
53 dotlen
= strlen(dotted
);
55 /* this can't be an iso net, its too long */
59 while ((pos
- dotted
) < dotlen
&& len
< 20) {
61 /* we expect the . at 2, and than every 5 */
62 if ((pos
- dotted
) != nextdotpos
) {
70 /* we must have at least two chars left here */
71 if (dotlen
- (pos
- dotted
) < 2) {
76 if ((isxdigit((unsigned char)*pos
)) &&
77 (isxdigit((unsigned char)*(pos
+ 1)))) {
78 memcpy(number
, pos
, 2);
85 *(buff
+ len
) = (char)strtol((char *)number
, NULL
, 16);
93 * conversion of XXXX.XXXX.XXXX to memory
95 int sysid2buff(uint8_t *buff
, const char *dotted
)
98 const char *pos
= dotted
;
102 // surely not a sysid_string if not 14 length
103 if (strlen(dotted
) != 14) {
107 while (len
< ISIS_SYS_ID_LEN
) {
109 /* the . is not positioned correctly */
110 if (((pos
- dotted
) != 4) && ((pos
- dotted
) != 9)) {
117 if ((isxdigit((unsigned char)*pos
)) &&
118 (isxdigit((unsigned char)*(pos
+ 1)))) {
119 memcpy(number
, pos
, 2);
126 *(buff
+ len
) = (char)strtol((char *)number
, NULL
, 16);
133 const char *nlpid2str(uint8_t nlpid
)
148 snprintf(buf
, sizeof(buf
), "%hhu", nlpid
);
154 * converts the nlpids struct (filled by TLV #129)
158 char *nlpid2string(struct nlpids
*nlpids
)
162 nlpidstring
[0] = '\0';
164 for (i
= 0; i
< nlpids
->count
; i
++) {
165 snprintf(tbuf
, sizeof(tbuf
), "%s",
166 nlpid2str(nlpids
->nlpids
[i
]));
167 strlcat(nlpidstring
, tbuf
, sizeof(nlpidstring
));
168 if (nlpids
->count
- i
> 1)
169 strlcat(nlpidstring
, ", ", sizeof(nlpidstring
));
176 * Returns 0 on error, IS-IS Circuit Type on ok
178 int string2circuit_t(const char *str
)
184 if (!strcmp(str
, "level-1"))
187 if (!strcmp(str
, "level-2-only") || !strcmp(str
, "level-2"))
190 if (!strcmp(str
, "level-1-2"))
191 return IS_LEVEL_1_AND_2
;
196 const char *circuit_state2string(int state
)
212 const char *circuit_type2string(int type
)
218 case CIRCUIT_T_BROADCAST
:
220 case CIRCUIT_T_LOOPBACK
:
228 const char *circuit_t2string(int circuit_t
)
235 case IS_LEVEL_1_AND_2
:
241 return NULL
; /* not reached */
244 const char *syst2string(int type
)
247 case ISIS_SYSTYPE_ES
:
249 case ISIS_SYSTYPE_IS
:
251 case ISIS_SYSTYPE_L1_IS
:
253 case ISIS_SYSTYPE_L2_IS
:
259 return NULL
; /* not reached */
262 const char *isis_hello_padding2string(int hello_padding_type
)
264 switch (hello_padding_type
) {
265 case ISIS_HELLO_PADDING_DISABLED
:
267 case ISIS_HELLO_PADDING_DURING_ADJACENCY_FORMATION
:
268 return "during-adjacency-formation";
269 case ISIS_HELLO_PADDING_ALWAYS
:
272 return NULL
; /* not reached */
275 const char *time2string(uint32_t time
)
279 datestring
[0] = '\0';
284 if (time
/ SECS_PER_YEAR
) {
285 snprintf(tbuf
, sizeof(tbuf
), "%uY", time
/ SECS_PER_YEAR
);
286 strlcat(datestring
, tbuf
, sizeof(datestring
));
288 rest
= time
% SECS_PER_YEAR
;
289 if (rest
/ SECS_PER_MONTH
) {
290 snprintf(tbuf
, sizeof(tbuf
), "%uM", rest
/ SECS_PER_MONTH
);
291 strlcat(datestring
, tbuf
, sizeof(datestring
));
293 rest
= rest
% SECS_PER_MONTH
;
294 if (rest
/ SECS_PER_WEEK
) {
295 snprintf(tbuf
, sizeof(tbuf
), "%uw", rest
/ SECS_PER_WEEK
);
296 strlcat(datestring
, tbuf
, sizeof(datestring
));
298 rest
= rest
% SECS_PER_WEEK
;
299 if (rest
/ SECS_PER_DAY
) {
300 snprintf(tbuf
, sizeof(tbuf
), "%ud", rest
/ SECS_PER_DAY
);
301 strlcat(datestring
, tbuf
, sizeof(datestring
));
303 rest
= rest
% SECS_PER_DAY
;
304 if (rest
/ SECS_PER_HOUR
) {
305 snprintf(tbuf
, sizeof(tbuf
), "%uh", rest
/ SECS_PER_HOUR
);
306 strlcat(datestring
, tbuf
, sizeof(datestring
));
308 rest
= rest
% SECS_PER_HOUR
;
309 if (rest
/ SECS_PER_MINUTE
) {
310 snprintf(tbuf
, sizeof(tbuf
), "%um", rest
/ SECS_PER_MINUTE
);
311 strlcat(datestring
, tbuf
, sizeof(datestring
));
313 rest
= rest
% SECS_PER_MINUTE
;
315 snprintf(tbuf
, sizeof(tbuf
), "%us", rest
);
316 strlcat(datestring
, tbuf
, sizeof(datestring
));
323 * routine to decrement a timer by a random
326 * first argument is the timer and the second is
329 unsigned long isis_jitter(unsigned long timer
, unsigned long jitter
)
339 * randomizing just the percent value provides
340 * no good random numbers - hence the spread
341 * to RANDOM_SPREAD (100000), which is ok as
342 * most IS-IS timers are no longer than 16 bit
345 j
= 1 + (int)((RANDOM_SPREAD
* frr_weak_random()) / (RAND_MAX
+ 1.0));
347 k
= timer
- (timer
* (100 - jitter
)) / 100;
349 timer
= timer
- (k
* j
/ RANDOM_SPREAD
);
354 struct in_addr
newprefix2inaddr(uint8_t *prefix_start
, uint8_t prefix_masklen
)
356 memset(&new_prefix
, 0, sizeof(new_prefix
));
357 memcpy(&new_prefix
, prefix_start
,
358 (prefix_masklen
& 0x3F)
359 ? ((((prefix_masklen
& 0x3F) - 1) >> 3) + 1)
365 * Returns the dynamic hostname associated with the passed system ID.
366 * If no dynamic hostname found then returns formatted system ID.
368 const char *print_sys_hostname(const uint8_t *sysid
)
370 struct isis_dynhn
*dyn
;
371 struct isis
*isis
= NULL
;
372 struct listnode
*node
;
377 /* For our system ID return our host name */
378 isis
= isis_lookup_by_sysid(sysid
);
379 if (isis
&& !CHECK_FLAG(im
->options
, F_ISIS_UNIT_TEST
))
380 return cmd_hostname_get();
382 for (ALL_LIST_ELEMENTS_RO(im
->isis
, node
, isis
)) {
383 dyn
= dynhn_find_by_id(isis
, sysid
);
385 return dyn
->hostname
;
388 snprintfrr(sys_hostname
, ISO_SYSID_STRLEN
, "%pSY", sysid
);
393 * This function is a generic utility that logs data of given length.
394 * Move this to a shared lib so that any protocol can use it.
396 void zlog_dump_data(void *data
, int len
)
403 char hexstr
[16 * 3 + 5];
404 char charstr
[16 * 1 + 5];
407 memset(bytestr
, 0, sizeof(bytestr
));
408 memset(addrstr
, 0, sizeof(addrstr
));
409 memset(hexstr
, 0, sizeof(hexstr
));
410 memset(charstr
, 0, sizeof(charstr
));
412 for (i
= 1; i
<= len
; i
++) {
417 /* store address for this line */
419 snprintf(addrstr
, sizeof(addrstr
), "%p", p
);
421 /* store hex str (for left side) */
422 snprintf(bytestr
, sizeof(bytestr
), "%02X ", *p
);
423 strlcat(hexstr
, bytestr
, sizeof(hexstr
) - strlen(hexstr
) - 1);
425 /* store char str (for right side) */
426 snprintf(bytestr
, sizeof(bytestr
), "%c", c
);
427 strlcat(charstr
, bytestr
,
428 sizeof(charstr
) - strlen(charstr
) - 1);
432 zlog_debug("[%8.8s] %-50.50s %s", addrstr
, hexstr
,
436 } else if ((i
% 8) == 0) {
437 /* half line: add whitespaces */
439 sizeof(hexstr
) - strlen(hexstr
) - 1);
440 strlcat(charstr
, " ",
441 sizeof(charstr
) - strlen(charstr
) - 1);
446 /* print rest of buffer if not empty */
447 if (strlen(hexstr
) > 0)
448 zlog_debug("[%8.8s] %-50.50s %s", addrstr
, hexstr
, charstr
);
452 void log_multiline(int priority
, const char *prefix
, const char *format
, ...)
458 va_start(ap
, format
);
459 p
= vasnprintfrr(MTYPE_TMP
, shortbuf
, sizeof(shortbuf
), format
, ap
);
465 char *saveptr
= NULL
;
466 for (char *line
= strtok_r(p
, "\n", &saveptr
); line
;
467 line
= strtok_r(NULL
, "\n", &saveptr
)) {
468 zlog(priority
, "%s%s", prefix
, line
);
475 char *log_uptime(time_t uptime
, char *buf
, size_t nbuf
)
478 time_t difftime
= time(NULL
);
480 tm
= gmtime(&difftime
);
482 if (difftime
< ONE_DAY_SECOND
)
483 snprintf(buf
, nbuf
, "%02d:%02d:%02d", tm
->tm_hour
, tm
->tm_min
,
485 else if (difftime
< ONE_WEEK_SECOND
)
486 snprintf(buf
, nbuf
, "%dd%02dh%02dm", tm
->tm_yday
, tm
->tm_hour
,
489 snprintf(buf
, nbuf
, "%02dw%dd%02dh", tm
->tm_yday
/ 7,
490 tm
->tm_yday
- ((tm
->tm_yday
/ 7) * 7), tm
->tm_hour
);
495 void vty_multiline(struct vty
*vty
, const char *prefix
, const char *format
, ...)
501 va_start(ap
, format
);
502 p
= vasnprintfrr(MTYPE_TMP
, shortbuf
, sizeof(shortbuf
), format
, ap
);
508 char *saveptr
= NULL
;
509 for (char *line
= strtok_r(p
, "\n", &saveptr
); line
;
510 line
= strtok_r(NULL
, "\n", &saveptr
)) {
511 vty_out(vty
, "%s%s\n", prefix
, line
);
518 void vty_out_timestr(struct vty
*vty
, time_t uptime
)
520 time_t difftime
= time(NULL
);
521 char buf
[MONOTIME_STRLEN
];
525 frrtime_to_interval(difftime
, buf
, sizeof(buf
));
527 vty_out(vty
, "%s ago", buf
);