File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / isisd / isis_adjacency.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:11 2012 UTC (12 years, 5 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_20_1, v0_99_20, HEAD
quagga

    1: /*
    2:  * IS-IS Rout(e)ing protocol - isis_adjacency.c   
    3:  *                             handling of IS-IS adjacencies
    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 "log.h"
   27: #include "memory.h"
   28: #include "hash.h"
   29: #include "vty.h"
   30: #include "linklist.h"
   31: #include "thread.h"
   32: #include "if.h"
   33: #include "stream.h"
   34: 
   35: #include "isisd/dict.h"
   36: #include "isisd/include-netbsd/iso.h"
   37: #include "isisd/isis_constants.h"
   38: #include "isisd/isis_common.h"
   39: #include "isisd/isisd.h"
   40: #include "isisd/isis_circuit.h"
   41: #include "isisd/isis_adjacency.h"
   42: #include "isisd/isis_misc.h"
   43: #include "isisd/isis_dr.h"
   44: #include "isisd/isis_dynhn.h"
   45: #include "isisd/isis_pdu.h"
   46: 
   47: extern struct isis *isis;
   48: 
   49: static struct isis_adjacency *
   50: adj_alloc (u_char * id)
   51: {
   52:   struct isis_adjacency *adj;
   53: 
   54:   adj = XCALLOC (MTYPE_ISIS_ADJACENCY, sizeof (struct isis_adjacency));
   55:   memcpy (adj->sysid, id, ISIS_SYS_ID_LEN);
   56: 
   57:   return adj;
   58: }
   59: 
   60: struct isis_adjacency *
   61: isis_new_adj (u_char * id, u_char * snpa, int level,
   62: 	      struct isis_circuit *circuit)
   63: {
   64:   struct isis_adjacency *adj;
   65:   int i;
   66: 
   67:   adj = adj_alloc (id);		/* P2P kludge */
   68: 
   69:   if (adj == NULL)
   70:     {
   71:       zlog_err ("Out of memory!");
   72:       return NULL;
   73:     }
   74: 
   75:   if (snpa) {
   76:   memcpy (adj->snpa, snpa, 6);
   77:   } else {
   78:       memset (adj->snpa, ' ', 6);
   79:   }
   80: 
   81:   adj->circuit = circuit;
   82:   adj->level = level;
   83:   adj->flaps = 0;
   84:   adj->last_flap = time (NULL);
   85:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
   86:     {
   87:       listnode_add (circuit->u.bc.adjdb[level - 1], adj);
   88:       adj->dischanges[level - 1] = 0;
   89:       for (i = 0; i < DIS_RECORDS; i++)	/* clear N DIS state change records */
   90: 	{
   91: 	  adj->dis_record[(i * ISIS_LEVELS) + level - 1].dis
   92: 	    = ISIS_UNKNOWN_DIS;
   93: 	  adj->dis_record[(i * ISIS_LEVELS) + level - 1].last_dis_change
   94: 	    = time (NULL);
   95: 	}
   96:     }
   97: 
   98:   return adj;
   99: }
  100: 
  101: struct isis_adjacency *
  102: isis_adj_lookup (u_char * sysid, struct list *adjdb)
  103: {
  104:   struct isis_adjacency *adj;
  105:   struct listnode *node;
  106: 
  107:   for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
  108:     if (memcmp (adj->sysid, sysid, ISIS_SYS_ID_LEN) == 0)
  109:       return adj;
  110: 
  111:   return NULL;
  112: }
  113: 
  114: struct isis_adjacency *
  115: isis_adj_lookup_snpa (u_char * ssnpa, struct list *adjdb)
  116: {
  117:   struct listnode *node;
  118:   struct isis_adjacency *adj;
  119: 
  120:   for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
  121:     if (memcmp (adj->snpa, ssnpa, ETH_ALEN) == 0)
  122:       return adj;
  123: 
  124:   return NULL;
  125: }
  126: 
  127: void
  128: isis_delete_adj (struct isis_adjacency *adj, struct list *adjdb)
  129: {
  130:   if (!adj)
  131:     return;
  132:   /* When we recieve a NULL list, we will know its p2p. */
  133:   if (adjdb)
  134:     listnode_delete (adjdb, adj);
  135: 
  136:   THREAD_OFF (adj->t_expire);
  137: 
  138:   if (adj->ipv4_addrs)
  139:     list_delete (adj->ipv4_addrs);
  140: #ifdef HAVE_IPV6
  141:   if (adj->ipv6_addrs)
  142:     list_delete (adj->ipv6_addrs);
  143: #endif
  144:   
  145:   XFREE (MTYPE_ISIS_ADJACENCY, adj);
  146:   return;
  147: }
  148: 
  149: void
  150: isis_adj_state_change (struct isis_adjacency *adj, enum isis_adj_state state,
  151: 		       const char *reason)
  152: {
  153:   int old_state;
  154:   int level = adj->level;
  155:   struct isis_circuit *circuit;
  156: 
  157:   old_state = adj->adj_state;
  158:   adj->adj_state = state;
  159: 
  160:   circuit = adj->circuit;
  161: 
  162:   if (isis->debugs & DEBUG_ADJ_PACKETS)
  163:     {
  164:       zlog_debug ("ISIS-Adj (%s): Adjacency state change %d->%d: %s",
  165: 		 circuit->area->area_tag,
  166: 		 old_state, state, reason ? reason : "unspecified");
  167:     }
  168: 
  169:   if (circuit->circ_type == CIRCUIT_T_BROADCAST)
  170:     {
  171:       if (state == ISIS_ADJ_UP)
  172: 	circuit->upadjcount[level - 1]++;
  173:       if (state == ISIS_ADJ_DOWN)
  174: 	{
  175: 	  isis_delete_adj (adj, adj->circuit->u.bc.adjdb[level - 1]);
  176: 	  circuit->upadjcount[level - 1]--;
  177: 	}
  178: 
  179:       list_delete_all_node (circuit->u.bc.lan_neighs[level - 1]);
  180:       isis_adj_build_neigh_list (circuit->u.bc.adjdb[level - 1],
  181: 				 circuit->u.bc.lan_neighs[level - 1]);
  182:     }
  183:   else if (state == ISIS_ADJ_UP)
  184:     {				/* p2p interface */
  185:       if (adj->sys_type == ISIS_SYSTYPE_UNKNOWN)
  186: 	send_hello (circuit, 1);
  187: 
  188:       /* update counter & timers for debugging purposes */
  189:       adj->last_flap = time (NULL);
  190:       adj->flaps++;
  191: 
  192:       /* 7.3.17 - going up on P2P -> send CSNP */
  193:       /* FIXME: yup, I know its wrong... but i will do it! (for now) */
  194:       send_csnp (circuit, 1);
  195:       send_csnp (circuit, 2);
  196:     }
  197:   else if (state == ISIS_ADJ_DOWN)
  198:     {				/* p2p interface */
  199:       adj->circuit->u.p2p.neighbor = NULL;
  200:       isis_delete_adj (adj, NULL);
  201:     }
  202:   return;
  203: }
  204: 
  205: 
  206: void
  207: isis_adj_print (struct isis_adjacency *adj)
  208: {
  209:   struct isis_dynhn *dyn;
  210:   struct listnode *node;
  211:   struct in_addr *ipv4_addr;
  212: #ifdef HAVE_IPV6
  213:   struct in6_addr *ipv6_addr;
  214:   u_char ip6[INET6_ADDRSTRLEN];
  215: #endif /* HAVE_IPV6 */
  216: 
  217:   if (!adj)
  218:     return;
  219:   dyn = dynhn_find_by_id (adj->sysid);
  220:   if (dyn)
  221:     zlog_debug ("%s", dyn->name.name);
  222: 
  223:   zlog_debug ("SystemId %20s SNPA %s, level %d\nHolding Time %d",
  224: 	      adj->sysid ? sysid_print (adj->sysid) : "unknown",
  225: 	      snpa_print (adj->snpa), adj->level, adj->hold_time);
  226:   if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
  227:     {
  228:       zlog_debug ("IPv4 Addresses:");
  229: 
  230:       for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ipv4_addr))
  231:         zlog_debug ("%s", inet_ntoa (*ipv4_addr));
  232:     }
  233: 
  234: #ifdef HAVE_IPV6
  235:   if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
  236:     {
  237:       zlog_debug ("IPv6 Addresses:");
  238:       for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
  239: 	{
  240: 	  inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
  241: 	  zlog_debug ("%s", ip6);
  242: 	}
  243:     }
  244: #endif /* HAVE_IPV6 */
  245:   zlog_debug ("Speaks: %s", nlpid2string (&adj->nlpids));
  246: 
  247:   return;
  248: }
  249: 
  250: int
  251: isis_adj_expire (struct thread *thread)
  252: {
  253:   struct isis_adjacency *adj;
  254:   int level;
  255: 
  256:   /*
  257:    * Get the adjacency
  258:    */
  259:   adj = THREAD_ARG (thread);
  260:   assert (adj);
  261:   level = adj->level;
  262:   adj->t_expire = NULL;
  263: 
  264:   /* trigger the adj expire event */
  265:   isis_adj_state_change (adj, ISIS_ADJ_DOWN, "holding time expired");
  266: 
  267:   return 0;
  268: }
  269: 
  270: static const char *
  271: adj_state2string (int state)
  272: {
  273: 
  274:   switch (state)
  275:     {
  276:     case ISIS_ADJ_INITIALIZING:
  277:       return "Initializing";
  278:     case ISIS_ADJ_UP:
  279:       return "Up";
  280:     case ISIS_ADJ_DOWN:
  281:       return "Down";
  282:     default:
  283:       return "Unknown";
  284:     }
  285: 
  286:   return NULL;			/* not reached */
  287: }
  288: 
  289: /*
  290:  * show clns/isis neighbor (detail)
  291:  */
  292: static void
  293: isis_adj_print_vty2 (struct isis_adjacency *adj, struct vty *vty, char detail)
  294: {
  295: 
  296: #ifdef HAVE_IPV6
  297:   struct in6_addr *ipv6_addr;
  298:   u_char ip6[INET6_ADDRSTRLEN];
  299: #endif /* HAVE_IPV6 */
  300:   struct in_addr *ip_addr;
  301:   time_t now;
  302:   struct isis_dynhn *dyn;
  303:   int level;
  304:   struct listnode *node;
  305: 
  306:   dyn = dynhn_find_by_id (adj->sysid);
  307:   if (dyn)
  308:     vty_out (vty, "  %-20s", dyn->name.name);
  309:   else if (adj->sysid)
  310:     {
  311:       vty_out (vty, "  %-20s", sysid_print (adj->sysid));
  312:     }
  313:   else
  314:     {
  315:       vty_out (vty, "  unknown ");
  316:     }
  317: 
  318:   if (detail == ISIS_UI_LEVEL_BRIEF)
  319:     {
  320:       if (adj->circuit)
  321: 	vty_out (vty, "%-12s", adj->circuit->interface->name);
  322:       else
  323: 	vty_out (vty, "NULL circuit!");
  324:       vty_out (vty, "%-3u", adj->level);	/* level */
  325:       vty_out (vty, "%-13s", adj_state2string (adj->adj_state));
  326:       now = time (NULL);
  327:       if (adj->last_upd)
  328: 	vty_out (vty, "%-9lu", adj->last_upd + adj->hold_time - now);
  329:       else
  330: 	vty_out (vty, "-        ");
  331:       vty_out (vty, "%-10s", snpa_print (adj->snpa));
  332:       vty_out (vty, "%s", VTY_NEWLINE);
  333:     }
  334: 
  335:   if (detail == ISIS_UI_LEVEL_DETAIL)
  336:     {
  337:       level = adj->level;
  338:       if (adj->circuit)
  339: 	vty_out (vty, "%s    Interface: %s", VTY_NEWLINE, adj->circuit->interface->name);	/* interface name */
  340:       else
  341: 	vty_out (vty, "NULL circuit!%s", VTY_NEWLINE);
  342:       vty_out (vty, ", Level: %u", adj->level);	/* level */
  343:       vty_out (vty, ", State: %s", adj_state2string (adj->adj_state));
  344:       now = time (NULL);
  345:       if (adj->last_upd)
  346: 	vty_out (vty, ", Expires in %s",
  347: 		 time2string (adj->last_upd + adj->hold_time - now));
  348:       else
  349: 	vty_out (vty, ", Expires in %s", time2string (adj->hold_time));
  350:       vty_out (vty, "%s    Adjacency flaps: %u", VTY_NEWLINE, adj->flaps);
  351:       vty_out (vty, ", Last: %s ago", time2string (now - adj->last_flap));
  352:       vty_out (vty, "%s    Circuit type: %s",
  353: 	       VTY_NEWLINE, circuit_t2string (adj->circuit_t));
  354:       vty_out (vty, ", Speaks: %s", nlpid2string (&adj->nlpids));
  355:       vty_out (vty, "%s    SNPA: %s", VTY_NEWLINE, snpa_print (adj->snpa));
  356:       dyn = dynhn_find_by_id (adj->lanid);
  357:       if (dyn)
  358: 	vty_out (vty, ", LAN id: %s.%02x",
  359: 		 dyn->name.name, adj->lanid[ISIS_SYS_ID_LEN]);
  360:       else
  361: 	vty_out (vty, ", LAN id: %s.%02x",
  362: 		 sysid_print (adj->lanid), adj->lanid[ISIS_SYS_ID_LEN]);
  363: 
  364:       vty_out (vty, "%s    Priority: %u",
  365: 	       VTY_NEWLINE, adj->prio[adj->level - 1]);
  366: 
  367:       vty_out (vty, ", %s, DIS flaps: %u, Last: %s ago%s",
  368: 	       isis_disflag2string (adj->dis_record[ISIS_LEVELS + level - 1].
  369: 				    dis), adj->dischanges[level - 1],
  370: 	       time2string (now -
  371: 			    (adj->dis_record[ISIS_LEVELS + level - 1].
  372: 			     last_dis_change)), VTY_NEWLINE);
  373: 
  374:       if (adj->ipv4_addrs && listcount (adj->ipv4_addrs) > 0)
  375: 	{
  376: 	  vty_out (vty, "    IPv4 Addresses:%s", VTY_NEWLINE);
  377: 	  for (ALL_LIST_ELEMENTS_RO (adj->ipv4_addrs, node, ip_addr))
  378:             vty_out (vty, "      %s%s", inet_ntoa (*ip_addr), VTY_NEWLINE);
  379: 	}
  380: #ifdef HAVE_IPV6
  381:       if (adj->ipv6_addrs && listcount (adj->ipv6_addrs) > 0)
  382: 	{
  383: 	  vty_out (vty, "    IPv6 Addresses:%s", VTY_NEWLINE);
  384: 	  for (ALL_LIST_ELEMENTS_RO (adj->ipv6_addrs, node, ipv6_addr))
  385: 	    {
  386: 	      inet_ntop (AF_INET6, ipv6_addr, (char *)ip6, INET6_ADDRSTRLEN);
  387: 	      vty_out (vty, "      %s%s", ip6, VTY_NEWLINE);
  388: 	    }
  389: 	}
  390: #endif /* HAVE_IPV6 */
  391:       vty_out (vty, "%s", VTY_NEWLINE);
  392:     }
  393:   return;
  394: }
  395: 
  396: void
  397: isis_adj_print_vty (struct isis_adjacency *adj, struct vty *vty)
  398: {
  399:   isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
  400: }
  401: 
  402: void
  403: isis_adj_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
  404: {
  405:   isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
  406: }
  407: 
  408: void
  409: isis_adj_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
  410: {
  411:   isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
  412: }
  413: 
  414: void
  415: isis_adj_p2p_print_vty (struct isis_adjacency *adj, struct vty *vty)
  416: {
  417:   isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_BRIEF);
  418: }
  419: 
  420: void
  421: isis_adj_p2p_print_vty_detail (struct isis_adjacency *adj, struct vty *vty)
  422: {
  423:   isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_DETAIL);
  424: }
  425: 
  426: void
  427: isis_adj_p2p_print_vty_extensive (struct isis_adjacency *adj, struct vty *vty)
  428: {
  429:   isis_adj_print_vty2 (adj, vty, ISIS_UI_LEVEL_EXTENSIVE);
  430: }
  431: 
  432: void
  433: isis_adjdb_iterate (struct list *adjdb, void (*func) (struct isis_adjacency *,
  434: 						      void *), void *arg)
  435: {
  436:   struct listnode *node, *nnode;
  437:   struct isis_adjacency *adj;
  438: 
  439:   for (ALL_LIST_ELEMENTS (adjdb, node, nnode, adj))
  440:     (*func) (adj, arg);
  441: }
  442: 
  443: void
  444: isis_adj_build_neigh_list (struct list *adjdb, struct list *list)
  445: {
  446:   struct isis_adjacency *adj;
  447:   struct listnode *node;
  448: 
  449:   if (!list)
  450:     {
  451:       zlog_warn ("isis_adj_build_neigh_list(): NULL list");
  452:       return;
  453:     }
  454: 
  455:   for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
  456:     {
  457:       if (!adj)
  458: 	{
  459: 	  zlog_warn ("isis_adj_build_neigh_list(): NULL adj");
  460: 	  return;
  461: 	}
  462: 
  463:       if ((adj->adj_state == ISIS_ADJ_UP ||
  464: 	   adj->adj_state == ISIS_ADJ_INITIALIZING))
  465: 	listnode_add (list, adj->snpa);
  466:     }
  467:   return;
  468: }
  469: 
  470: void
  471: isis_adj_build_up_list (struct list *adjdb, struct list *list)
  472: {
  473:   struct isis_adjacency *adj;
  474:   struct listnode *node;
  475: 
  476:   if (!list)
  477:     {
  478:       zlog_warn ("isis_adj_build_up_list(): NULL list");
  479:       return;
  480:     }
  481: 
  482:   for (ALL_LIST_ELEMENTS_RO (adjdb, node, adj))
  483:     {
  484:       if (!adj)
  485: 	{
  486: 	  zlog_warn ("isis_adj_build_up_list(): NULL adj");
  487: 	  return;
  488: 	}
  489: 
  490:       if (adj->adj_state == ISIS_ADJ_UP)
  491: 	listnode_add (list, adj);
  492:     }
  493: 
  494:   return;
  495: }

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