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

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

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