Annotation of embedaddon/quagga/ospfd/ospf_nsm.c, revision 1.1.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>