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

    1: /*
    2:  * OSPF version 2  Neighbor State Machine
    3:  * From RFC2328 [OSPF Version 2]
    4:  * Copyright (C) 1999, 2000 Toshiaki Takada
    5:  *
    6:  * This file is part of GNU Zebra.
    7:  *
    8:  * GNU Zebra is free software; you can redistribute it and/or modify it
    9:  * under the terms of the GNU General Public License as published by the
   10:  * Free Software Foundation; either version 2, or (at your option) any
   11:  * later version.
   12:  *
   13:  * GNU Zebra is distributed in the hope that it will be useful, but
   14:  * WITHOUT ANY WARRANTY; without even the implied warranty of
   15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   16:  * General Public License for more details.
   17:  *
   18:  * You should have received a copy of the GNU General Public License
   19:  * along with GNU Zebra; see the file COPYING.  If not, write to the Free
   20:  * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
   21:  * 02111-1307, USA.
   22:  */
   23: 
   24: #include <zebra.h>
   25: 
   26: #include "thread.h"
   27: #include "memory.h"
   28: #include "hash.h"
   29: #include "linklist.h"
   30: #include "prefix.h"
   31: #include "if.h"
   32: #include "table.h"
   33: #include "stream.h"
   34: #include "table.h"
   35: #include "log.h"
   36: 
   37: #include "ospfd/ospfd.h"
   38: #include "ospfd/ospf_interface.h"
   39: #include "ospfd/ospf_ism.h"
   40: #include "ospfd/ospf_asbr.h"
   41: #include "ospfd/ospf_lsa.h"
   42: #include "ospfd/ospf_lsdb.h"
   43: #include "ospfd/ospf_neighbor.h"
   44: #include "ospfd/ospf_nsm.h"
   45: #include "ospfd/ospf_network.h"
   46: #include "ospfd/ospf_packet.h"
   47: #include "ospfd/ospf_dump.h"
   48: #include "ospfd/ospf_flood.h"
   49: #include "ospfd/ospf_abr.h"
   50: #include "ospfd/ospf_snmp.h"
   51: 
   52: static void nsm_clear_adj (struct ospf_neighbor *);
   53: 
   54: /* OSPF NSM Timer functions. */
   55: static int
   56: ospf_inactivity_timer (struct thread *thread)
   57: {
   58:   struct ospf_neighbor *nbr;
   59: 
   60:   nbr = THREAD_ARG (thread);
   61:   nbr->t_inactivity = NULL;
   62: 
   63:   if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
   64:     zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (Inactivity timer expire)",
   65: 	  IF_NAME (nbr->oi), inet_ntoa (nbr->router_id));
   66: 
   67:   OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_InactivityTimer);
   68: 
   69:   return 0;
   70: }
   71: 
   72: static int
   73: ospf_db_desc_timer (struct thread *thread)
   74: {
   75:   struct ospf_interface *oi;
   76:   struct ospf_neighbor *nbr;
   77: 
   78:   nbr = THREAD_ARG (thread);
   79:   nbr->t_db_desc = NULL;
   80: 
   81:   oi = nbr->oi;
   82: 
   83:   if (IS_DEBUG_OSPF (nsm, NSM_TIMERS))
   84:     zlog (NULL, LOG_DEBUG, "NSM[%s:%s]: Timer (DD Retransmit timer expire)",
   85: 	  IF_NAME (nbr->oi), inet_ntoa (nbr->src));
   86: 
   87:   /* resent last send DD packet. */
   88:   assert (nbr->last_send);
   89:   ospf_db_desc_resend (nbr);
   90: 
   91:   /* DD Retransmit timer set. */
   92:   OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
   93: 
   94:   return 0;
   95: }
   96: 
   97: /* Hook function called after ospf NSM event is occured.
   98:  *
   99:  * Set/clear any timers whose condition is implicit to the neighbour
  100:  * state. There may be other timers which are set/unset according to other
  101:  * state.
  102:  *
  103:  * We rely on this function to properly clear timers in lower states,
  104:  * particularly before deleting a neighbour.
  105:  */
  106: static void
  107: nsm_timer_set (struct ospf_neighbor *nbr)
  108: {
  109:   switch (nbr->state)
  110:     {
  111:     case NSM_Deleted:
  112:     case NSM_Down:
  113:       OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
  114:       OSPF_NSM_TIMER_OFF (nbr->t_hello_reply);
  115:     case NSM_Attempt:
  116:     case NSM_Init:
  117:     case NSM_TwoWay:
  118:       OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
  119:       OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
  120:       OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
  121:       break;
  122:     case NSM_ExStart:
  123:       OSPF_NSM_TIMER_ON (nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
  124:       OSPF_NSM_TIMER_OFF (nbr->t_ls_upd);
  125:       OSPF_NSM_TIMER_OFF (nbr->t_ls_req);
  126:       break;
  127:     case NSM_Exchange:
  128:       OSPF_NSM_TIMER_ON (nbr->t_ls_upd, ospf_ls_upd_timer, nbr->v_ls_upd);
  129:       if (!IS_SET_DD_MS (nbr->dd_flags))      
  130: 	OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
  131:       break;
  132:     case NSM_Loading:
  133:     case NSM_Full:
  134:     default:
  135:       OSPF_NSM_TIMER_OFF (nbr->t_db_desc);
  136:       break;
  137:     }
  138: }
  139: 
  140: /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
  141:  * the given neighbour
  142:  */
  143: static int
  144: nsm_should_adj (struct ospf_neighbor *nbr)
  145: {
  146:   struct ospf_interface *oi = nbr->oi;
  147: 
  148:       /* These network types must always form adjacencies. */
  149:   if (oi->type == OSPF_IFTYPE_POINTOPOINT
  150:       || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
  151:       || oi->type == OSPF_IFTYPE_VIRTUALLINK
  152:       /* Router itself is the DRouter or the BDRouter. */
  153:       || IPV4_ADDR_SAME (&oi->address->u.prefix4, &DR (oi))
  154:       || IPV4_ADDR_SAME (&oi->address->u.prefix4, &BDR (oi))
  155:       /* Neighboring Router is the DRouter or the BDRouter. */
  156:       || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &DR (oi))
  157:       || IPV4_ADDR_SAME (&nbr->address.u.prefix4, &BDR (oi)))
  158:     return 1;
  159: 
  160:   return 0;
  161: }
  162: 
  163: /* OSPF NSM functions. */
  164: static int
  165: nsm_packet_received (struct ospf_neighbor *nbr)
  166: {
  167:   /* Start or Restart Inactivity Timer. */
  168:   OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
  169:   
  170:   OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
  171: 		     nbr->v_inactivity);
  172: 
  173:   if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
  174:     OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
  175: 
  176:   return 0;
  177: }
  178: 
  179: static int
  180: nsm_start (struct ospf_neighbor *nbr)
  181: {
  182:   if (nbr->nbr_nbma)
  183:       OSPF_POLL_TIMER_OFF (nbr->nbr_nbma->t_poll);
  184: 
  185:   OSPF_NSM_TIMER_OFF (nbr->t_inactivity);
  186:   
  187:   OSPF_NSM_TIMER_ON (nbr->t_inactivity, ospf_inactivity_timer,
  188:                      nbr->v_inactivity);
  189: 
  190:   return 0;
  191: }
  192: 
  193: static int
  194: nsm_twoway_received (struct ospf_neighbor *nbr)
  195: {
  196:   return (nsm_should_adj (nbr) ? NSM_ExStart : NSM_TwoWay);
  197: }
  198: 
  199: int
  200: ospf_db_summary_count (struct ospf_neighbor *nbr)
  201: {
  202:   return ospf_lsdb_count_all (&nbr->db_sum);
  203: }
  204: 
  205: int
  206: ospf_db_summary_isempty (struct ospf_neighbor *nbr)
  207: {
  208:   return ospf_lsdb_isempty (&nbr->db_sum);
  209: }
  210: 
  211: static int
  212: ospf_db_summary_add (struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
  213: {
  214: #ifdef HAVE_OPAQUE_LSA
  215:   switch (lsa->data->type)
  216:     {
  217:     case OSPF_OPAQUE_LINK_LSA:
  218:       /* Exclude type-9 LSAs that does not have the same "oi" with "nbr". */
  219:       if (nbr->oi && ospf_if_exists (lsa->oi) != nbr->oi)
  220:           return 0;
  221:       break;
  222:     case OSPF_OPAQUE_AREA_LSA:
  223:       /*
  224:        * It is assured by the caller function "nsm_negotiation_done()"
  225:        * that every given LSA belongs to the same area with "nbr".
  226:        */
  227:       break;
  228:     case OSPF_OPAQUE_AS_LSA:
  229:     default:
  230:       break;
  231:     }
  232: #endif /* HAVE_OPAQUE_LSA */
  233: 
  234:   /* Stay away from any Local Translated Type-7 LSAs */
  235:   if (CHECK_FLAG (lsa->flags, OSPF_LSA_LOCAL_XLT))
  236:     return 0;
  237: 
  238:   if (IS_LSA_MAXAGE (lsa))
  239:     ospf_ls_retransmit_add (nbr, lsa);                      
  240:   else 
  241:     ospf_lsdb_add (&nbr->db_sum, lsa);
  242: 
  243:   return 0;
  244: }
  245: 
  246: void
  247: ospf_db_summary_clear (struct ospf_neighbor *nbr)
  248: {
  249:   struct ospf_lsdb *lsdb;
  250:   int i;
  251: 
  252:   lsdb = &nbr->db_sum;
  253:   for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++)
  254:     {
  255:       struct route_table *table = lsdb->type[i].db;
  256:       struct route_node *rn;
  257: 
  258:       for (rn = route_top (table); rn; rn = route_next (rn))
  259: 	if (rn->info)
  260: 	  ospf_lsdb_delete (&nbr->db_sum, rn->info);
  261:     }
  262: }
  263: 
  264: 
  265: 
  266: /* The area link state database consists of the router-LSAs,
  267:    network-LSAs and summary-LSAs contained in the area structure,
  268:    along with the AS-external-LSAs contained in the global structure.
  269:    AS-external-LSAs are omitted from a virtual neighbor's Database
  270:    summary list.  AS-external-LSAs are omitted from the Database
  271:    summary list if the area has been configured as a stub. */
  272: static int
  273: nsm_negotiation_done (struct ospf_neighbor *nbr)
  274: {
  275:   struct ospf_area *area = nbr->oi->area;
  276:   struct ospf_lsa *lsa;
  277:   struct route_node *rn;
  278: 
  279:   LSDB_LOOP (ROUTER_LSDB (area), rn, lsa)
  280:     ospf_db_summary_add (nbr, lsa);
  281:   LSDB_LOOP (NETWORK_LSDB (area), rn, lsa)
  282:     ospf_db_summary_add (nbr, lsa);
  283:   LSDB_LOOP (SUMMARY_LSDB (area), rn, lsa)
  284:     ospf_db_summary_add (nbr, lsa);
  285:   LSDB_LOOP (ASBR_SUMMARY_LSDB (area), rn, lsa)
  286:     ospf_db_summary_add (nbr, lsa);
  287: 
  288: #ifdef HAVE_OPAQUE_LSA
  289:   /* Process only if the neighbor is opaque capable. */
  290:   if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
  291:     {
  292:       LSDB_LOOP (OPAQUE_LINK_LSDB (area), rn, lsa)
  293: 	ospf_db_summary_add (nbr, lsa);
  294:       LSDB_LOOP (OPAQUE_AREA_LSDB (area), rn, lsa)
  295: 	ospf_db_summary_add (nbr, lsa);
  296:     }
  297: #endif /* HAVE_OPAQUE_LSA */
  298: 
  299:   if (CHECK_FLAG (nbr->options, OSPF_OPTION_NP))
  300:     {
  301:       LSDB_LOOP (NSSA_LSDB (area), rn, lsa)
  302: 	ospf_db_summary_add (nbr, lsa);
  303:     }
  304: 
  305:   if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
  306:       && area->external_routing == OSPF_AREA_DEFAULT)
  307:     LSDB_LOOP (EXTERNAL_LSDB (nbr->oi->ospf), rn, lsa)
  308:       ospf_db_summary_add (nbr, lsa);
  309: 
  310: #ifdef HAVE_OPAQUE_LSA
  311:   if (CHECK_FLAG (nbr->options, OSPF_OPTION_O)
  312:       && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
  313: 	  && area->external_routing == OSPF_AREA_DEFAULT))
  314:     LSDB_LOOP (OPAQUE_AS_LSDB (nbr->oi->ospf), rn, lsa)
  315:       ospf_db_summary_add (nbr, lsa);
  316: #endif /* HAVE_OPAQUE_LSA */
  317: 
  318:   return 0;
  319: }
  320: 
  321: static int
  322: nsm_exchange_done (struct ospf_neighbor *nbr)
  323: {
  324:   if (ospf_ls_request_isempty (nbr))
  325:     return NSM_Full;
  326: 
  327:   /* Send Link State Request. */
  328:   ospf_ls_req_send (nbr);
  329: 
  330:   return NSM_Loading;
  331: }
  332: 
  333: static int
  334: nsm_adj_ok (struct ospf_neighbor *nbr)
  335: {
  336:   int next_state = nbr->state;
  337:   int adj = nsm_should_adj (nbr);
  338: 
  339:   if (nbr->state == NSM_TwoWay && adj == 1)
  340:     next_state = NSM_ExStart;
  341:   else if (nbr->state >= NSM_ExStart && adj == 0)
  342:     next_state = NSM_TwoWay;
  343: 
  344:   return next_state;
  345: }
  346: 
  347: /* Clear adjacency related state for a neighbour, intended where nbr
  348:  * transitions from > ExStart (i.e. a Full or forming adjacency)
  349:  * to <= ExStart.
  350:  */
  351: static void
  352: nsm_clear_adj (struct ospf_neighbor *nbr)
  353: {
  354:   /* Clear Database Summary list. */
  355:   if (!ospf_db_summary_isempty (nbr))
  356:     ospf_db_summary_clear (nbr);
  357: 
  358:   /* Clear Link State Request list. */
  359:   if (!ospf_ls_request_isempty (nbr))
  360:     ospf_ls_request_delete_all (nbr);
  361: 
  362:   /* Clear Link State Retransmission list. */
  363:   if (!ospf_ls_retransmit_isempty (nbr))
  364:     ospf_ls_retransmit_clear (nbr);
  365: 
  366: #ifdef HAVE_OPAQUE_LSA
  367:   if (CHECK_FLAG (nbr->options, OSPF_OPTION_O))
  368:     UNSET_FLAG (nbr->options, OSPF_OPTION_O);
  369: #endif /* HAVE_OPAQUE_LSA */
  370: }
  371: 
  372: static int
  373: nsm_kill_nbr (struct ospf_neighbor *nbr)
  374: {
  375:   /* killing nbr_self is invalid */
  376:   if (nbr == nbr->oi->nbr_self)
  377:     {
  378:       assert (nbr != nbr->oi->nbr_self);
  379:       return 0;
  380:     }
  381:   
  382:   if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL)
  383:     {
  384:       struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
  385: 
  386:       nbr_nbma->nbr = NULL;
  387:       nbr_nbma->state_change = nbr->state_change;
  388: 
  389:       nbr->nbr_nbma = NULL;
  390: 
  391:       OSPF_POLL_TIMER_ON (nbr_nbma->t_poll, ospf_poll_timer,
  392: 			  nbr_nbma->v_poll);
  393: 
  394:       if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
  395: 	zlog_debug ("NSM[%s:%s]: Down (PollIntervalTimer scheduled)",
  396: 		   IF_NAME (nbr->oi), inet_ntoa (nbr->address.u.prefix4));  
  397:     }
  398: 
  399:   return 0;
  400: }
  401: 
  402: /* Neighbor State Machine */
  403: struct {
  404:   int (*func) (struct ospf_neighbor *);
  405:   int next_state;
  406: } NSM [OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] =
  407: {
  408:   {
  409:     /* DependUpon: dummy state. */
  410:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  411:     { NULL,                    NSM_DependUpon }, /* PacketReceived    */
  412:     { NULL,                    NSM_DependUpon }, /* Start             */
  413:     { NULL,                    NSM_DependUpon }, /* 2-WayReceived     */
  414:     { NULL,                    NSM_DependUpon }, /* NegotiationDone   */
  415:     { NULL,                    NSM_DependUpon }, /* ExchangeDone      */
  416:     { NULL,                    NSM_DependUpon }, /* BadLSReq          */
  417:     { NULL,                    NSM_DependUpon }, /* LoadingDone       */
  418:     { NULL,                    NSM_DependUpon }, /* AdjOK?            */
  419:     { NULL,                    NSM_DependUpon }, /* SeqNumberMismatch */
  420:     { NULL,                    NSM_DependUpon }, /* 1-WayReceived     */
  421:     { NULL,                    NSM_DependUpon }, /* KillNbr           */
  422:     { NULL,                    NSM_DependUpon }, /* InactivityTimer   */
  423:     { NULL,                    NSM_DependUpon }, /* LLDown            */
  424:   },
  425:   {
  426:     /* Deleted: dummy state. */
  427:     { NULL,                    NSM_Deleted    }, /* NoEvent           */
  428:     { NULL,                    NSM_Deleted    }, /* PacketReceived    */
  429:     { NULL,                    NSM_Deleted    }, /* Start             */
  430:     { NULL,                    NSM_Deleted    }, /* 2-WayReceived     */
  431:     { NULL,                    NSM_Deleted    }, /* NegotiationDone   */
  432:     { NULL,                    NSM_Deleted    }, /* ExchangeDone      */
  433:     { NULL,                    NSM_Deleted    }, /* BadLSReq          */
  434:     { NULL,                    NSM_Deleted    }, /* LoadingDone       */
  435:     { NULL,                    NSM_Deleted    }, /* AdjOK?            */
  436:     { NULL,                    NSM_Deleted    }, /* SeqNumberMismatch */
  437:     { NULL,                    NSM_Deleted    }, /* 1-WayReceived     */
  438:     { NULL,                    NSM_Deleted    }, /* KillNbr           */
  439:     { NULL,                    NSM_Deleted    }, /* InactivityTimer   */
  440:     { NULL,                    NSM_Deleted    }, /* LLDown            */
  441:   },
  442:   {
  443:     /* Down: */
  444:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  445:     { nsm_packet_received,     NSM_Init       }, /* PacketReceived    */
  446:     { nsm_start,               NSM_Attempt    }, /* Start             */
  447:     { NULL,                    NSM_Down       }, /* 2-WayReceived     */
  448:     { NULL,                    NSM_Down       }, /* NegotiationDone   */
  449:     { NULL,                    NSM_Down       }, /* ExchangeDone      */
  450:     { NULL,                    NSM_Down       }, /* BadLSReq          */
  451:     { NULL,                    NSM_Down       }, /* LoadingDone       */
  452:     { NULL,                    NSM_Down       }, /* AdjOK?            */
  453:     { NULL,                    NSM_Down       }, /* SeqNumberMismatch */
  454:     { NULL,                    NSM_Down       }, /* 1-WayReceived     */
  455:     { nsm_kill_nbr,            NSM_Deleted    }, /* KillNbr           */
  456:     { nsm_kill_nbr,            NSM_Deleted    }, /* InactivityTimer   */
  457:     { nsm_kill_nbr,            NSM_Deleted    }, /* LLDown            */
  458:   },
  459:   {
  460:     /* Attempt: */
  461:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  462:     { nsm_packet_received,     NSM_Init       }, /* PacketReceived    */
  463:     { NULL,                    NSM_Attempt    }, /* Start             */
  464:     { NULL,                    NSM_Attempt    }, /* 2-WayReceived     */
  465:     { NULL,                    NSM_Attempt    }, /* NegotiationDone   */
  466:     { NULL,                    NSM_Attempt    }, /* ExchangeDone      */
  467:     { NULL,                    NSM_Attempt    }, /* BadLSReq          */
  468:     { NULL,                    NSM_Attempt    }, /* LoadingDone       */
  469:     { NULL,                    NSM_Attempt    }, /* AdjOK?            */
  470:     { NULL,                    NSM_Attempt    }, /* SeqNumberMismatch */
  471:     { NULL,                    NSM_Attempt    }, /* 1-WayReceived     */
  472:     { nsm_kill_nbr,            NSM_Deleted    }, /* KillNbr           */
  473:     { nsm_kill_nbr,            NSM_Deleted    }, /* InactivityTimer   */
  474:     { nsm_kill_nbr,            NSM_Deleted    }, /* LLDown            */
  475:   },
  476:   {
  477:     /* Init: */
  478:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  479:     { nsm_packet_received,     NSM_Init      }, /* PacketReceived    */
  480:     { NULL,                    NSM_Init       }, /* Start             */
  481:     { nsm_twoway_received,     NSM_DependUpon }, /* 2-WayReceived     */
  482:     { NULL,                    NSM_Init       }, /* NegotiationDone   */
  483:     { NULL,                    NSM_Init       }, /* ExchangeDone      */
  484:     { NULL,                    NSM_Init       }, /* BadLSReq          */
  485:     { NULL,                    NSM_Init       }, /* LoadingDone       */
  486:     { NULL,                    NSM_Init       }, /* AdjOK?            */
  487:     { NULL,                    NSM_Init       }, /* SeqNumberMismatch */
  488:     { NULL,                    NSM_Init       }, /* 1-WayReceived     */
  489:     { nsm_kill_nbr,            NSM_Deleted    }, /* KillNbr           */
  490:     { nsm_kill_nbr,            NSM_Deleted    }, /* InactivityTimer   */
  491:     { nsm_kill_nbr,            NSM_Deleted    }, /* LLDown            */
  492:   },
  493:   {
  494:     /* 2-Way: */
  495:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  496:     { nsm_packet_received,     NSM_TwoWay     }, /* HelloReceived     */
  497:     { NULL,                    NSM_TwoWay     }, /* Start             */
  498:     { NULL,                    NSM_TwoWay     }, /* 2-WayReceived     */
  499:     { NULL,                    NSM_TwoWay     }, /* NegotiationDone   */
  500:     { NULL,                    NSM_TwoWay     }, /* ExchangeDone      */
  501:     { NULL,                    NSM_TwoWay     }, /* BadLSReq          */
  502:     { NULL,                    NSM_TwoWay     }, /* LoadingDone       */
  503:     { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
  504:     { NULL,                    NSM_TwoWay     }, /* SeqNumberMismatch */
  505:     { NULL,                    NSM_Init       }, /* 1-WayReceived     */
  506:     { nsm_kill_nbr,            NSM_Deleted    }, /* KillNbr           */
  507:     { nsm_kill_nbr,            NSM_Deleted    }, /* InactivityTimer   */
  508:     { nsm_kill_nbr,            NSM_Deleted    }, /* LLDown            */
  509:   },
  510:   {
  511:     /* ExStart: */
  512:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  513:     { nsm_packet_received,     NSM_ExStart    }, /* PacaketReceived   */
  514:     { NULL,                    NSM_ExStart    }, /* Start             */
  515:     { NULL,                    NSM_ExStart    }, /* 2-WayReceived     */
  516:     { nsm_negotiation_done,    NSM_Exchange   }, /* NegotiationDone   */
  517:     { NULL,                    NSM_ExStart    }, /* ExchangeDone      */
  518:     { NULL,                    NSM_ExStart    }, /* BadLSReq          */
  519:     { NULL,                    NSM_ExStart    }, /* LoadingDone       */
  520:     { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
  521:     { NULL,                    NSM_ExStart    }, /* SeqNumberMismatch */
  522:     { NULL,                    NSM_Init       }, /* 1-WayReceived     */
  523:     { nsm_kill_nbr,            NSM_Deleted    }, /* KillNbr           */
  524:     { nsm_kill_nbr,            NSM_Deleted    }, /* InactivityTimer   */
  525:     { nsm_kill_nbr,            NSM_Deleted    }, /* LLDown            */
  526:   },
  527:   {
  528:     /* Exchange: */
  529:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  530:     { nsm_packet_received,     NSM_Exchange   }, /* PacketReceived    */
  531:     { NULL,                    NSM_Exchange   }, /* Start             */
  532:     { NULL,                    NSM_Exchange   }, /* 2-WayReceived     */
  533:     { NULL,                    NSM_Exchange   }, /* NegotiationDone   */
  534:     { nsm_exchange_done,       NSM_DependUpon }, /* ExchangeDone      */
  535:     { NULL,                    NSM_ExStart    }, /* BadLSReq          */
  536:     { NULL,                    NSM_Exchange   }, /* LoadingDone       */
  537:     { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
  538:     { NULL,                    NSM_ExStart    }, /* SeqNumberMismatch */
  539:     { NULL,                    NSM_Init       }, /* 1-WayReceived     */
  540:     { nsm_kill_nbr,            NSM_Deleted    }, /* KillNbr           */
  541:     { nsm_kill_nbr,            NSM_Deleted    }, /* InactivityTimer   */
  542:     { nsm_kill_nbr,            NSM_Deleted    }, /* LLDown            */
  543:   },
  544:   {
  545:     /* Loading: */
  546:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  547:     { nsm_packet_received,     NSM_Loading    }, /* PacketReceived    */
  548:     { NULL,                    NSM_Loading    }, /* Start             */
  549:     { NULL,                    NSM_Loading    }, /* 2-WayReceived     */
  550:     { NULL,                    NSM_Loading    }, /* NegotiationDone   */
  551:     { NULL,                    NSM_Loading    }, /* ExchangeDone      */
  552:     { NULL,                    NSM_ExStart    }, /* BadLSReq          */
  553:     { NULL,                    NSM_Full       }, /* LoadingDone       */
  554:     { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
  555:     { NULL,                    NSM_ExStart    }, /* SeqNumberMismatch */
  556:     { NULL,                    NSM_Init       }, /* 1-WayReceived     */
  557:     { nsm_kill_nbr,            NSM_Deleted    }, /* KillNbr           */
  558:     { nsm_kill_nbr,            NSM_Deleted    }, /* InactivityTimer   */
  559:     { nsm_kill_nbr,            NSM_Deleted    }, /* LLDown            */
  560:   },
  561:   { /* Full: */
  562:     { NULL,                    NSM_DependUpon }, /* NoEvent           */
  563:     { nsm_packet_received,     NSM_Full       }, /* PacketReceived    */
  564:     { NULL,                    NSM_Full       }, /* Start             */
  565:     { NULL,                    NSM_Full       }, /* 2-WayReceived     */
  566:     { NULL,                    NSM_Full       }, /* NegotiationDone   */
  567:     { NULL,                    NSM_Full       }, /* ExchangeDone      */
  568:     { NULL,                    NSM_ExStart    }, /* BadLSReq          */
  569:     { NULL,                    NSM_Full       }, /* LoadingDone       */
  570:     { nsm_adj_ok,              NSM_DependUpon }, /* AdjOK?            */
  571:     { NULL,                    NSM_ExStart    }, /* SeqNumberMismatch */
  572:     { NULL,                    NSM_Init       }, /* 1-WayReceived     */
  573:     { nsm_kill_nbr,            NSM_Deleted    }, /* KillNbr           */
  574:     { nsm_kill_nbr,            NSM_Deleted    }, /* InactivityTimer   */
  575:     { nsm_kill_nbr,            NSM_Deleted    }, /* LLDown            */
  576:   },
  577: };
  578: 
  579: static const char *ospf_nsm_event_str[] =
  580: {
  581:   "NoEvent",
  582:   "PacketReceived",
  583:   "Start",
  584:   "2-WayReceived",
  585:   "NegotiationDone",
  586:   "ExchangeDone",
  587:   "BadLSReq",
  588:   "LoadingDone",
  589:   "AdjOK?",
  590:   "SeqNumberMismatch",
  591:   "1-WayReceived",
  592:   "KillNbr",
  593:   "InactivityTimer",
  594:   "LLDown",
  595: };
  596: 
  597: static void
  598: nsm_notice_state_change (struct ospf_neighbor *nbr, int next_state, int event)
  599: {
  600:   /* Logging change of status. */
  601:   if (IS_DEBUG_OSPF (nsm, NSM_STATUS))
  602:     zlog_debug ("NSM[%s:%s]: State change %s -> %s (%s)",
  603:                IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
  604:                LOOKUP (ospf_nsm_state_msg, nbr->state),
  605:                LOOKUP (ospf_nsm_state_msg, next_state),
  606:                ospf_nsm_event_str [event]);
  607: 
  608:   /* Optionally notify about adjacency changes */
  609:   if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES) &&
  610:       (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL) ||
  611:        (next_state == NSM_Full) || (next_state < nbr->state)))
  612:     zlog_notice("AdjChg: Nbr %s on %s: %s -> %s (%s)",
  613:                 inet_ntoa (nbr->router_id), IF_NAME (nbr->oi),
  614:                 LOOKUP (ospf_nsm_state_msg, nbr->state),
  615:                 LOOKUP (ospf_nsm_state_msg, next_state),
  616:                 ospf_nsm_event_str [event]);
  617: 
  618:   /* Advance in NSM */
  619:   if (next_state > nbr->state)
  620:     nbr->ts_last_progress = recent_relative_time ();
  621:   else /* regression in NSM */
  622:     {
  623:       nbr->ts_last_regress = recent_relative_time ();
  624:       nbr->last_regress_str = ospf_nsm_event_str [event];
  625:     }
  626: 
  627: #ifdef HAVE_SNMP
  628:   /* Terminal state or regression */ 
  629:   if ((next_state == NSM_Full) 
  630:       || (next_state == NSM_TwoWay)
  631:       || (next_state < nbr->state))
  632:     {
  633:       /* ospfVirtNbrStateChange */
  634:       if (nbr->oi->type == OSPF_IFTYPE_VIRTUALLINK)
  635:         ospfTrapVirtNbrStateChange(nbr);
  636:       /* ospfNbrStateChange trap  */
  637:       else	
  638:         /* To/From FULL, only managed by DR */
  639:         if (((next_state != NSM_Full) && (nbr->state != NSM_Full)) 
  640:             || (nbr->oi->state == ISM_DR))
  641:           ospfTrapNbrStateChange(nbr);
  642:     }
  643: #endif
  644: }
  645: 
  646: void
  647: nsm_change_state (struct ospf_neighbor *nbr, int state)
  648: {
  649:   struct ospf_interface *oi = nbr->oi;
  650:   struct ospf_area *vl_area = NULL;
  651:   u_char old_state;
  652:   int x;
  653:   int force = 1;
  654:   
  655:   /* Preserve old status. */
  656:   old_state = nbr->state;
  657: 
  658:   /* Change to new status. */
  659:   nbr->state = state;
  660: 
  661:   /* Statistics. */
  662:   nbr->state_change++;
  663: 
  664:   if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
  665:     vl_area = ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
  666: 
  667:   /* One of the neighboring routers changes to/from the FULL state. */
  668:   if ((old_state != NSM_Full && state == NSM_Full) ||
  669:       (old_state == NSM_Full && state != NSM_Full))
  670:     {
  671:       if (state == NSM_Full)
  672: 	{
  673: 	  oi->full_nbrs++;
  674: 	  oi->area->full_nbrs++;
  675: 
  676:           ospf_check_abr_status (oi->ospf);
  677: 
  678: 	  if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
  679:             if (++vl_area->full_vls == 1)
  680: 	      ospf_schedule_abr_task (oi->ospf);
  681: 
  682: 	  /* kevinm: refresh any redistributions */
  683: 	  for (x = ZEBRA_ROUTE_SYSTEM; x < ZEBRA_ROUTE_MAX; x++)
  684: 	    {
  685: 	      if (x == ZEBRA_ROUTE_OSPF || x == ZEBRA_ROUTE_OSPF6)
  686: 		continue;
  687: 	      ospf_external_lsa_refresh_type (oi->ospf, x, force);
  688: 	    }
  689:           /* XXX: Clearly some thing is wrong with refresh of external LSAs
  690:            * this added to hack around defaults not refreshing after a timer
  691:            * jump.
  692:            */
  693:           ospf_external_lsa_refresh_default (oi->ospf);
  694: 	}
  695:       else
  696: 	{
  697: 	  oi->full_nbrs--;
  698: 	  oi->area->full_nbrs--;
  699: 
  700:           ospf_check_abr_status (oi->ospf);
  701: 
  702: 	  if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
  703: 	    if (vl_area->full_vls > 0)
  704: 	      if (--vl_area->full_vls == 0)
  705: 		ospf_schedule_abr_task (oi->ospf);
  706: 	}
  707: 
  708:       zlog_info ("nsm_change_state(%s, %s -> %s): "
  709: 		 "scheduling new router-LSA origination",
  710: 		 inet_ntoa (nbr->router_id),
  711: 		 LOOKUP(ospf_nsm_state_msg, old_state),
  712: 		 LOOKUP(ospf_nsm_state_msg, state));
  713: 
  714:       ospf_router_lsa_update_area (oi->area);
  715: 
  716:       if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
  717: 	{
  718: 	  struct ospf_area *vl_area =
  719: 	    ospf_area_lookup_by_area_id (oi->ospf, oi->vl_data->vl_area_id);
  720: 	  
  721: 	  if (vl_area)
  722: 	    ospf_router_lsa_update_area (vl_area);
  723: 	}
  724: 
  725:       /* Originate network-LSA. */
  726:       if (oi->state == ISM_DR)
  727: 	{
  728: 	  if (oi->network_lsa_self && oi->full_nbrs == 0)
  729: 	    {
  730: 	      ospf_lsa_flush_area (oi->network_lsa_self, oi->area);
  731: 	      ospf_lsa_unlock (&oi->network_lsa_self);
  732: 	      oi->network_lsa_self = NULL;
  733: 	    }
  734: 	  else
  735: 	    ospf_network_lsa_update (oi);
  736: 	}
  737:     }
  738: 
  739: #ifdef HAVE_OPAQUE_LSA
  740:   ospf_opaque_nsm_change (nbr, old_state);
  741: #endif /* HAVE_OPAQUE_LSA */
  742: 
  743:   /* State changes from > ExStart to <= ExStart should clear any Exchange
  744:    * or Full/LSA Update related lists and state.
  745:    * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
  746:    */
  747:   if ((old_state > NSM_ExStart) && (state <= NSM_ExStart))
  748:     nsm_clear_adj (nbr);
  749: 
  750:   /* Start DD exchange protocol */
  751:   if (state == NSM_ExStart)
  752:     {
  753:       if (nbr->dd_seqnum == 0)
  754: 	nbr->dd_seqnum = quagga_time (NULL);
  755:       else
  756: 	nbr->dd_seqnum++;
  757: 
  758:       nbr->dd_flags = OSPF_DD_FLAG_I|OSPF_DD_FLAG_M|OSPF_DD_FLAG_MS;
  759:       ospf_db_desc_send (nbr);
  760:     }
  761: 
  762:   /* clear cryptographic sequence number */
  763:   if (state == NSM_Down)
  764:     nbr->crypt_seqnum = 0;
  765:   
  766:   /* Generete NeighborChange ISM event. */
  767:   switch (oi->state) {
  768:   case ISM_DROther:
  769:   case ISM_Backup:
  770:   case ISM_DR:
  771:     if ((old_state < NSM_TwoWay && state >= NSM_TwoWay) ||
  772:         (old_state >= NSM_TwoWay && state < NSM_TwoWay))
  773:       OSPF_ISM_EVENT_EXECUTE (oi, ISM_NeighborChange);
  774:     break;
  775:   default:
  776:     /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc. */
  777:     break;
  778:   }
  779: 
  780:   /* Preserve old status? */
  781: }
  782: 
  783: /* Execute NSM event process. */
  784: int
  785: ospf_nsm_event (struct thread *thread)
  786: {
  787:   int event;
  788:   int next_state;
  789:   struct ospf_neighbor *nbr;
  790:   struct in_addr router_id;
  791: 
  792:   nbr = THREAD_ARG (thread);
  793:   event = THREAD_VAL (thread);
  794:   router_id = nbr->router_id;
  795: 
  796:   if (IS_DEBUG_OSPF (nsm, NSM_EVENTS))
  797:     zlog_debug ("NSM[%s:%s]: %s (%s)", IF_NAME (nbr->oi),
  798: 	       inet_ntoa (nbr->router_id),
  799: 	       LOOKUP (ospf_nsm_state_msg, nbr->state),
  800: 	       ospf_nsm_event_str [event]);
  801:   
  802:   next_state = NSM [nbr->state][event].next_state;
  803: 
  804:   /* Call function. */
  805:   if (NSM [nbr->state][event].func != NULL)
  806:     {
  807:       int func_state = (*(NSM [nbr->state][event].func))(nbr);
  808:       
  809:       if (NSM [nbr->state][event].next_state == NSM_DependUpon)
  810:         next_state = func_state;
  811:       else if (func_state)
  812:         {
  813:           /* There's a mismatch between the FSM tables and what an FSM
  814:            * action/state-change function returned. State changes which
  815:            * do not have conditional/DependUpon next-states should not
  816:            * try set next_state.
  817:            */
  818:           zlog_warn ("NSM[%s:%s]: %s (%s): "
  819:                      "Warning: action tried to change next_state to %s",
  820:                      IF_NAME (nbr->oi), inet_ntoa (nbr->router_id),
  821:                      LOOKUP (ospf_nsm_state_msg, nbr->state),
  822:                      ospf_nsm_event_str [event],
  823:                      LOOKUP (ospf_nsm_state_msg, func_state));
  824:         }
  825:     }
  826: 
  827:   assert (next_state != NSM_DependUpon);
  828:   
  829:   /* If state is changed. */
  830:   if (next_state != nbr->state)
  831:     {
  832:       nsm_notice_state_change (nbr, next_state, event);
  833:       nsm_change_state (nbr, next_state);
  834:     }
  835: 
  836:   /* Make sure timer is set. */
  837:   nsm_timer_set (nbr);
  838: 
  839:   /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
  840:    * is deleted.
  841:    *
  842:    * Rather than encode knowledge here of which events lead to NBR
  843:    * delete, we take our cue from the NSM table, via the dummy
  844:    * 'Deleted' neighbour state.
  845:    */
  846:   if (nbr->state == NSM_Deleted)
  847:     ospf_nbr_delete (nbr);
  848: 
  849:   return 0;
  850: }
  851: 
  852: /* Check loading state. */
  853: void
  854: ospf_check_nbr_loading (struct ospf_neighbor *nbr)
  855: {
  856:   if (nbr->state == NSM_Loading)
  857:     {
  858:       if (ospf_ls_request_isempty (nbr))
  859: 	OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_LoadingDone);
  860:       else if (nbr->ls_req_last == NULL)
  861: 	ospf_ls_req_event (nbr);
  862:     }
  863: }

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