Annotation of embedaddon/quagga/ospfd/ospf_nsm.c, revision 1.1

1.1     ! misho       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>