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

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