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

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