File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_misc.c
Revision 1.1.1.3 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:10 2016 UTC (7 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>