blob: 2dfd7cca394f37e7fd5119a7e26c840037320503 [file] [log] [blame]
/*
* IS-IS Rout(e)ing protocol - isis_misc.h
* Miscellanous routines
*
* Copyright (C) 2001,2002 Sampo Saaristo
* Tampere University of Technology
* Institute of Communications Engineering
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public Licenseas published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include <zebra.h>
#include "stream.h"
#include "vty.h"
#include "hash.h"
#include "if.h"
#include "command.h"
#include "isisd/dict.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_common.h"
#include "isisd/isis_flags.h"
#include "isisd/isis_circuit.h"
#include "isisd/isis_csm.h"
#include "isisd/isisd.h"
#include "isisd/isis_misc.h"
#include "isisd/isis_tlv.h"
#include "isisd/isis_lsp.h"
#include "isisd/isis_constants.h"
#include "isisd/isis_adjacency.h"
#include "isisd/isis_dynhn.h"
/* staticly assigned vars for printing purposes */
struct in_addr new_prefix;
/* len of xxxx.xxxx.xxxx + place for #0 termination */
char sysid[15];
/* len of xxxx.xxxx.xxxx + place for #0 termination */
char snpa[15];
/* len of xx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xxxx.xx */
char isonet[51];
/* + place for #0 termination */
/* len of xxxx.xxxx.xxxx.xx.xx + place for #0 termination */
char lspid[21];
/* len of xxYxxMxWxdxxhxxmxxs + place for #0 termination */
char datestring[20];
char nlpidstring[30];
/*
* This converts the isonet to its printable format
*/
const char *
isonet_print (u_char * from, int len)
{
int i = 0;
char *pos = isonet;
if (!from)
return "unknown";
while (i < len)
{
if (i & 1)
{
sprintf (pos, "%02x", *(from + i));
pos += 2;
}
else
{
if (i == (len - 1))
{ /* No dot at the end of address */
sprintf (pos, "%02x", *(from + i));
pos += 2;
}
else
{
sprintf (pos, "%02x.", *(from + i));
pos += 3;
}
}
i++;
}
*(pos) = '\0';
return isonet;
}
/*
* Returns 0 on error, length of buff on ok
* extract dot from the dotted str, and insert all the number in a buff
*/
int
dotformat2buff (u_char * buff, const char * dotted)
{
int dotlen, len = 0;
const char *pos = dotted;
u_char number[3];
int nextdotpos = 2;
number[2] = '\0';
dotlen = strlen(dotted);
if (dotlen > 50)
{
/* this can't be an iso net, its too long */
return 0;
}
while ((pos - dotted) < dotlen && len < 20)
{
if (*pos == '.')
{
/* we expect the . at 2, and than every 5 */
if ((pos - dotted) != nextdotpos)
{
len = 0;
break;
}
nextdotpos += 5;
pos++;
continue;
}
/* we must have at least two chars left here */
if (dotlen - (pos - dotted) < 2)
{
len = 0;
break;
}
if ((isxdigit ((int) *pos)) && (isxdigit ((int) *(pos + 1))))
{
memcpy (number, pos, 2);
pos += 2;
}
else
{
len = 0;
break;
}
*(buff + len) = (char) strtol ((char *)number, NULL, 16);
len++;
}
return len;
}
/*
* conversion of XXXX.XXXX.XXXX to memory
*/
int
sysid2buff (u_char * buff, const char * dotted)
{
int len = 0;
const char *pos = dotted;
u_char number[3];
number[2] = '\0';
// surely not a sysid_string if not 14 length
if (strlen (dotted) != 14)
{
return 0;
}
while (len < ISIS_SYS_ID_LEN)
{
if (*pos == '.')
{
/* the . is not positioned correctly */
if (((pos - dotted) != 4) && ((pos - dotted) != 9))
{
len = 0;
break;
}
pos++;
continue;
}
if ((isxdigit ((int) *pos)) && (isxdigit ((int) *(pos + 1))))
{
memcpy (number, pos, 2);
pos += 2;
}
else
{
len = 0;
break;
}
*(buff + len) = (char) strtol ((char *)number, NULL, 16);
len++;
}
return len;
}
/*
* converts the nlpids struct (filled by TLV #129)
* into a string
*/
char *
nlpid2string (struct nlpids *nlpids)
{
char *pos = nlpidstring;
int i;
for (i = 0; i < nlpids->count; i++)
{
switch (nlpids->nlpids[i])
{
case NLPID_IP:
pos += sprintf (pos, "IPv4");
break;
case NLPID_IPV6:
pos += sprintf (pos, "IPv6");
break;
case NLPID_SNAP:
pos += sprintf (pos, "SNAP");
break;
case NLPID_CLNP:
pos += sprintf (pos, "CLNP");
break;
case NLPID_ESIS:
pos += sprintf (pos, "ES-IS");
break;
default:
pos += sprintf (pos, "unknown");
break;
}
if (nlpids->count - i > 1)
pos += sprintf (pos, ", ");
}
*(pos) = '\0';
return nlpidstring;
}
/*
* supports the given af ?
*/
int
speaks (struct nlpids *nlpids, int family)
{
int i, speaks = 0;
if (nlpids == (struct nlpids *) NULL)
return speaks;
for (i = 0; i < nlpids->count; i++)
{
if (family == AF_INET && nlpids->nlpids[i] == NLPID_IP)
speaks = 1;
if (family == AF_INET6 && nlpids->nlpids[i] == NLPID_IPV6)
speaks = 1;
}
return speaks;
}
/*
* Returns 0 on error, IS-IS Circuit Type on ok
*/
int
string2circuit_t (const char * str)
{
if (!str)
return 0;
if (!strcmp (str, "level-1"))
return IS_LEVEL_1;
if (!strcmp (str, "level-2-only") || !strcmp (str, "level-2"))
return IS_LEVEL_2;
if (!strcmp (str, "level-1-2"))
return IS_LEVEL_1_AND_2;
return 0;
}
const char *
circuit_state2string (int state)
{
switch (state)
{
case C_STATE_INIT:
return "Init";
case C_STATE_CONF:
return "Config";
case C_STATE_UP:
return "Up";
default:
return "Unknown";
}
return NULL;
}
const char *
circuit_type2string (int type)
{
switch (type)
{
case CIRCUIT_T_P2P:
return "p2p";
case CIRCUIT_T_BROADCAST:
return "lan";
case CIRCUIT_T_LOOPBACK:
return "loopback";
default:
return "Unknown";
}
return NULL;
}
const char *
circuit_t2string (int circuit_t)
{
switch (circuit_t)
{
case IS_LEVEL_1:
return "L1";
case IS_LEVEL_2:
return "L2";
case IS_LEVEL_1_AND_2:
return "L1L2";
default:
return "??";
}
return NULL; /* not reached */
}
const char *
syst2string (int type)
{
switch (type)
{
case ISIS_SYSTYPE_ES:
return "ES";
case ISIS_SYSTYPE_IS:
return "IS";
case ISIS_SYSTYPE_L1_IS:
return "1";
case ISIS_SYSTYPE_L2_IS:
return "2";
default:
return "??";
}
return NULL; /* not reached */
}
/*
* Print functions - we print to static vars
*/
const char *
snpa_print (u_char * from)
{
int i = 0;
u_char *pos = (u_char *)snpa;
if (!from)
return "unknown";
while (i < ETH_ALEN - 1)
{
if (i & 1)
{
sprintf ((char *)pos, "%02x.", *(from + i));
pos += 3;
}
else
{
sprintf ((char *)pos, "%02x", *(from + i));
pos += 2;
}
i++;
}
sprintf ((char *)pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1)));
pos += 2;
*(pos) = '\0';
return snpa;
}
const char *
sysid_print (u_char * from)
{
int i = 0;
char *pos = sysid;
if (!from)
return "unknown";
while (i < ISIS_SYS_ID_LEN - 1)
{
if (i & 1)
{
sprintf (pos, "%02x.", *(from + i));
pos += 3;
}
else
{
sprintf (pos, "%02x", *(from + i));
pos += 2;
}
i++;
}
sprintf (pos, "%02x", *(from + (ISIS_SYS_ID_LEN - 1)));
pos += 2;
*(pos) = '\0';
return sysid;
}
const char *
rawlspid_print (u_char * from)
{
char *pos = lspid;
if (!from)
return "unknown";
memcpy (pos, sysid_print (from), 15);
pos += 14;
sprintf (pos, ".%02x", LSP_PSEUDO_ID (from));
pos += 3;
sprintf (pos, "-%02x", LSP_FRAGMENT (from));
pos += 3;
*(pos) = '\0';
return lspid;
}
const char *
time2string (u_int32_t time)
{
char *pos = datestring;
u_int32_t rest;
if (time == 0)
return "-";
if (time / SECS_PER_YEAR)
pos += sprintf (pos, "%uY", time / SECS_PER_YEAR);
rest = time % SECS_PER_YEAR;
if (rest / SECS_PER_MONTH)
pos += sprintf (pos, "%uM", rest / SECS_PER_MONTH);
rest = rest % SECS_PER_MONTH;
if (rest / SECS_PER_WEEK)
pos += sprintf (pos, "%uw", rest / SECS_PER_WEEK);
rest = rest % SECS_PER_WEEK;
if (rest / SECS_PER_DAY)
pos += sprintf (pos, "%ud", rest / SECS_PER_DAY);
rest = rest % SECS_PER_DAY;
if (rest / SECS_PER_HOUR)
pos += sprintf (pos, "%uh", rest / SECS_PER_HOUR);
rest = rest % SECS_PER_HOUR;
if (rest / SECS_PER_MINUTE)
pos += sprintf (pos, "%um", rest / SECS_PER_MINUTE);
rest = rest % SECS_PER_MINUTE;
if (rest)
pos += sprintf (pos, "%us", rest);
*(pos) = 0;
return datestring;
}
/*
* routine to decrement a timer by a random
* number
*
* first argument is the timer and the second is
* the jitter
*/
unsigned long
isis_jitter (unsigned long timer, unsigned long jitter)
{
int j, k;
if (jitter >= 100)
return timer;
if (timer == 1)
return timer;
/*
* randomizing just the percent value provides
* no good random numbers - hence the spread
* to RANDOM_SPREAD (100000), which is ok as
* most IS-IS timers are no longer than 16 bit
*/
j = 1 + (int) ((RANDOM_SPREAD * random ()) / (RAND_MAX + 1.0));
k = timer - (timer * (100 - jitter)) / 100;
timer = timer - (k * j / RANDOM_SPREAD);
return timer;
}
struct in_addr
newprefix2inaddr (u_char * prefix_start, u_char prefix_masklen)
{
memset (&new_prefix, 0, sizeof (new_prefix));
memcpy (&new_prefix, prefix_start, (prefix_masklen & 0x3F) ?
((((prefix_masklen & 0x3F) - 1) >> 3) + 1) : 0);
return new_prefix;
}
/*
* Returns host.name if any, otherwise
* it returns the system hostname.
*/
const char *
unix_hostname (void)
{
static struct utsname names;
const char *hostname;
hostname = host.name;
if (!hostname)
{
uname (&names);
hostname = names.nodename;
}
return hostname;
}
/*
* Returns the dynamic hostname associated with the passed system ID.
* If no dynamic hostname found then returns formatted system ID.
*/
const char *
print_sys_hostname (u_char *sysid)
{
struct isis_dynhn *dyn;
if (!sysid)
return "nullsysid";
/* For our system ID return our host name */
if (memcmp(sysid, isis->sysid, ISIS_SYS_ID_LEN) == 0)
return unix_hostname();
dyn = dynhn_find_by_id (sysid);
if (dyn)
return (const char *)dyn->name.name;
return sysid_print (sysid);
}
/*
* This function is a generic utility that logs data of given length.
* Move this to a shared lib so that any protocol can use it.
*/
void
zlog_dump_data (void *data, int len)
{
int i;
unsigned char *p;
unsigned char c;
char bytestr[4];
char addrstr[10];
char hexstr[ 16*3 + 5];
char charstr[16*1 + 5];
p = data;
memset (bytestr, 0, sizeof(bytestr));
memset (addrstr, 0, sizeof(addrstr));
memset (hexstr, 0, sizeof(hexstr));
memset (charstr, 0, sizeof(charstr));
for (i = 1; i <= len; i++)
{
c = *p;
if (isalnum (c) == 0)
c = '.';
/* store address for this line */
if ((i % 16) == 1)
snprintf (addrstr, sizeof(addrstr), "%p", p);
/* store hex str (for left side) */
snprintf (bytestr, sizeof (bytestr), "%02X ", *p);
strncat (hexstr, bytestr, sizeof (hexstr) - strlen (hexstr) - 1);
/* store char str (for right side) */
snprintf (bytestr, sizeof (bytestr), "%c", c);
strncat (charstr, bytestr, sizeof (charstr) - strlen (charstr) - 1);
if ((i % 16) == 0)
{
/* line completed */
zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr);
hexstr[0] = 0;
charstr[0] = 0;
}
else if ((i % 8) == 0)
{
/* half line: add whitespaces */
strncat (hexstr, " ", sizeof (hexstr) - strlen (hexstr) - 1);
strncat (charstr, " ", sizeof (charstr) - strlen (charstr) - 1);
}
p++; /* next byte */
}
/* print rest of buffer if not empty */
if (strlen (hexstr) > 0)
zlog_debug ("[%8.8s] %-50.50s %s", addrstr, hexstr, charstr);
return;
}