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

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