Annotation of embedaddon/quagga/ospfd/ospf_ism.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * OSPF version 2  Interface 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 "linklist.h"
                     28: #include "prefix.h"
                     29: #include "if.h"
                     30: #include "table.h"
                     31: #include "log.h"
                     32: 
                     33: #include "ospfd/ospfd.h"
                     34: #include "ospfd/ospf_interface.h"
                     35: #include "ospfd/ospf_ism.h"
                     36: #include "ospfd/ospf_asbr.h"
                     37: #include "ospfd/ospf_lsa.h"
                     38: #include "ospfd/ospf_lsdb.h"
                     39: #include "ospfd/ospf_neighbor.h"
                     40: #include "ospfd/ospf_nsm.h"
                     41: #include "ospfd/ospf_network.h"
                     42: #include "ospfd/ospf_dump.h"
                     43: #include "ospfd/ospf_packet.h"
                     44: #include "ospfd/ospf_flood.h"
                     45: #include "ospfd/ospf_abr.h"
                     46: #include "ospfd/ospf_snmp.h"
                     47: 
                     48: /* elect DR and BDR. Refer to RFC2319 section 9.4 */
                     49: static struct ospf_neighbor *
                     50: ospf_dr_election_sub (struct list *routers)
                     51: {
                     52:   struct listnode *node;
                     53:   struct ospf_neighbor *nbr, *max = NULL;
                     54: 
                     55:   /* Choose highest router priority.
                     56:      In case of tie, choose highest Router ID. */
                     57:   for (ALL_LIST_ELEMENTS_RO (routers, node, nbr))
                     58:     {
                     59:       if (max == NULL)
                     60:        max = nbr;
                     61:       else
                     62:        {
                     63:          if (max->priority < nbr->priority)
                     64:            max = nbr;
                     65:          else if (max->priority == nbr->priority)
                     66:            if (IPV4_ADDR_CMP (&max->router_id, &nbr->router_id) < 0)
                     67:              max = nbr;
                     68:        }
                     69:     }
                     70: 
                     71:   return max;
                     72: }
                     73: 
                     74: static struct ospf_neighbor *
                     75: ospf_elect_dr (struct ospf_interface *oi, struct list *el_list)
                     76: {
                     77:   struct list *dr_list;
                     78:   struct listnode *node;
                     79:   struct ospf_neighbor *nbr, *dr = NULL, *bdr = NULL;
                     80: 
                     81:   dr_list = list_new ();
                     82: 
                     83:   /* Add neighbors to the list. */
                     84:   for (ALL_LIST_ELEMENTS_RO (el_list, node, nbr))
                     85:     {
                     86:       /* neighbor declared to be DR. */
                     87:       if (NBR_IS_DR (nbr))
                     88:        listnode_add (dr_list, nbr);
                     89: 
                     90:       /* Preserve neighbor BDR. */
                     91:       if (IPV4_ADDR_SAME (&BDR (oi), &nbr->address.u.prefix4))
                     92:        bdr = nbr;
                     93:     }
                     94: 
                     95:   /* Elect Designated Router. */
                     96:   if (listcount (dr_list) > 0)
                     97:     dr = ospf_dr_election_sub (dr_list);
                     98:   else
                     99:     dr = bdr;
                    100: 
                    101:   /* Set DR to interface. */
                    102:   if (dr)
                    103:     DR (oi) = dr->address.u.prefix4;
                    104:   else
                    105:     DR (oi).s_addr = 0;
                    106: 
                    107:   list_delete (dr_list);
                    108: 
                    109:   return dr;
                    110: }
                    111: 
                    112: static struct ospf_neighbor *
                    113: ospf_elect_bdr (struct ospf_interface *oi, struct list *el_list)
                    114: {
                    115:   struct list *bdr_list, *no_dr_list;
                    116:   struct listnode *node;
                    117:   struct ospf_neighbor *nbr, *bdr = NULL;
                    118: 
                    119:   bdr_list = list_new ();
                    120:   no_dr_list = list_new ();
                    121: 
                    122:   /* Add neighbors to the list. */
                    123:   for (ALL_LIST_ELEMENTS_RO (el_list, node, nbr))
                    124:     {
                    125:       /* neighbor declared to be DR. */
                    126:       if (NBR_IS_DR (nbr))
                    127:        continue;
                    128: 
                    129:       /* neighbor declared to be BDR. */
                    130:       if (NBR_IS_BDR (nbr))
                    131:        listnode_add (bdr_list, nbr);
                    132: 
                    133:       listnode_add (no_dr_list, nbr);
                    134:     }
                    135: 
                    136:   /* Elect Backup Designated Router. */
                    137:   if (listcount (bdr_list) > 0)
                    138:     bdr = ospf_dr_election_sub (bdr_list);
                    139:   else
                    140:     bdr = ospf_dr_election_sub (no_dr_list);
                    141: 
                    142:   /* Set BDR to interface. */
                    143:   if (bdr)
                    144:     BDR (oi) = bdr->address.u.prefix4;
                    145:   else
                    146:     BDR (oi).s_addr = 0;
                    147: 
                    148:   list_delete (bdr_list);
                    149:   list_delete (no_dr_list);
                    150: 
                    151:   return bdr;
                    152: }
                    153: 
                    154: static int
                    155: ospf_ism_state (struct ospf_interface *oi)
                    156: {
                    157:   if (IPV4_ADDR_SAME (&DR (oi), &oi->address->u.prefix4))
                    158:     return ISM_DR;
                    159:   else if (IPV4_ADDR_SAME (&BDR (oi), &oi->address->u.prefix4))
                    160:     return ISM_Backup;
                    161:   else
                    162:     return ISM_DROther;
                    163: }
                    164: 
                    165: static void
                    166: ospf_dr_eligible_routers (struct route_table *nbrs, struct list *el_list)
                    167: {
                    168:   struct route_node *rn;
                    169:   struct ospf_neighbor *nbr;
                    170: 
                    171:   for (rn = route_top (nbrs); rn; rn = route_next (rn))
                    172:     if ((nbr = rn->info) != NULL)
                    173:       /* Ignore 0.0.0.0 node*/
                    174:       if (nbr->router_id.s_addr != 0)
                    175:        /* Is neighbor eligible? */
                    176:        if (nbr->priority > 0)
                    177:          /* Is neighbor upper 2-Way? */
                    178:          if (nbr->state >= NSM_TwoWay)
                    179:            listnode_add (el_list, nbr);
                    180: }
                    181: 
                    182: /* Generate AdjOK? NSM event. */
                    183: static void
                    184: ospf_dr_change (struct ospf *ospf, struct route_table *nbrs)
                    185: {
                    186:   struct route_node *rn;
                    187:   struct ospf_neighbor *nbr;
                    188: 
                    189:   for (rn = route_top (nbrs); rn; rn = route_next (rn))
                    190:     if ((nbr = rn->info) != NULL)
                    191:       /* Ignore 0.0.0.0 node*/
                    192:       if (nbr->router_id.s_addr != 0)
                    193:        /* Is neighbor upper 2-Way? */
                    194:        if (nbr->state >= NSM_TwoWay)
                    195:          /* Ignore myself. */
                    196:          if (!IPV4_ADDR_SAME (&nbr->router_id, &ospf->router_id))
                    197:            OSPF_NSM_EVENT_SCHEDULE (nbr, NSM_AdjOK);
                    198: }
                    199: 
                    200: static int
                    201: ospf_dr_election (struct ospf_interface *oi)
                    202: {
                    203:   struct in_addr old_dr, old_bdr;
                    204:   int old_state, new_state;
                    205:   struct list *el_list;
                    206:   struct ospf_neighbor *dr, *bdr;
                    207: 
                    208:   /* backup current values. */
                    209:   old_dr = DR (oi);
                    210:   old_bdr = BDR (oi);
                    211:   old_state = oi->state;
                    212: 
                    213:   el_list = list_new ();
                    214: 
                    215:   /* List eligible routers. */
                    216:   ospf_dr_eligible_routers (oi->nbrs, el_list);
                    217: 
                    218:   /* First election of DR and BDR. */
                    219:   bdr = ospf_elect_bdr (oi, el_list);
                    220:   dr = ospf_elect_dr (oi, el_list);
                    221: 
                    222:   new_state = ospf_ism_state (oi);
                    223: 
                    224:   zlog_debug ("DR-Election[1st]: Backup %s", inet_ntoa (BDR (oi)));
                    225:   zlog_debug ("DR-Election[1st]: DR     %s", inet_ntoa (DR (oi)));
                    226: 
                    227:   if (new_state != old_state &&
                    228:       !(new_state == ISM_DROther && old_state < ISM_DROther))
                    229:     {
                    230:       ospf_elect_bdr (oi, el_list);
                    231:       ospf_elect_dr (oi, el_list); 
                    232: 
                    233:       new_state = ospf_ism_state (oi);
                    234: 
                    235:       zlog_debug ("DR-Election[2nd]: Backup %s", inet_ntoa (BDR (oi)));
                    236:       zlog_debug ("DR-Election[2nd]: DR     %s", inet_ntoa (DR (oi)));
                    237:     }
                    238: 
                    239:   list_delete (el_list);
                    240: 
                    241:   /* if DR or BDR changes, cause AdjOK? neighbor event. */
                    242:   if (!IPV4_ADDR_SAME (&old_dr, &DR (oi)) ||
                    243:       !IPV4_ADDR_SAME (&old_bdr, &BDR (oi)))
                    244:     ospf_dr_change (oi->ospf, oi->nbrs);
                    245: 
                    246:   return new_state;
                    247: }
                    248: 
                    249: 
                    250: int
                    251: ospf_hello_timer (struct thread *thread)
                    252: {
                    253:   struct ospf_interface *oi;
                    254: 
                    255:   oi = THREAD_ARG (thread);
                    256:   oi->t_hello = NULL;
                    257: 
                    258:   if (IS_DEBUG_OSPF (ism, ISM_TIMERS))
                    259:     zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Hello timer expire)",
                    260:          IF_NAME (oi));
                    261: 
                    262:   /* Sending hello packet. */
                    263:   ospf_hello_send (oi);
                    264: 
                    265:   /* Hello timer set. */
                    266:   OSPF_HELLO_TIMER_ON (oi);
                    267:   
                    268:   return 0;
                    269: }
                    270: 
                    271: static int
                    272: ospf_wait_timer (struct thread *thread)
                    273: {
                    274:   struct ospf_interface *oi;
                    275: 
                    276:   oi = THREAD_ARG (thread);
                    277:   oi->t_wait = NULL;
                    278: 
                    279:   if (IS_DEBUG_OSPF (ism, ISM_TIMERS))
                    280:     zlog (NULL, LOG_DEBUG, "ISM[%s]: Timer (Wait timer expire)",
                    281:          IF_NAME (oi));
                    282: 
                    283:   OSPF_ISM_EVENT_SCHEDULE (oi, ISM_WaitTimer);
                    284: 
                    285:   return 0;
                    286: }
                    287: 
                    288: /* Hook function called after ospf ISM event is occured. And vty's
                    289:    network command invoke this function after making interface
                    290:    structure. */
                    291: static void
                    292: ism_timer_set (struct ospf_interface *oi)
                    293: {
                    294:   switch (oi->state)
                    295:     {
                    296:     case ISM_Down:
                    297:       /* First entry point of ospf interface state machine. In this state
                    298:         interface parameters must be set to initial values, and timers are
                    299:         reset also. */
                    300:       OSPF_ISM_TIMER_OFF (oi->t_hello);
                    301:       OSPF_ISM_TIMER_OFF (oi->t_wait);
                    302:       OSPF_ISM_TIMER_OFF (oi->t_ls_ack);
                    303:       break;
                    304:     case ISM_Loopback:
                    305:       /* In this state, the interface may be looped back and will be
                    306:         unavailable for regular data traffic. */
                    307:       OSPF_ISM_TIMER_OFF (oi->t_hello);
                    308:       OSPF_ISM_TIMER_OFF (oi->t_wait);
                    309:       OSPF_ISM_TIMER_OFF (oi->t_ls_ack);
                    310:       break;
                    311:     case ISM_Waiting:
                    312:       /* The router is trying to determine the identity of DRouter and
                    313:         BDRouter. The router begin to receive and send Hello Packets. */
                    314:       /* send first hello immediately */
                    315:       OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1);
                    316:       OSPF_ISM_TIMER_ON (oi->t_wait, ospf_wait_timer,
                    317:                         OSPF_IF_PARAM (oi, v_wait));
                    318:       OSPF_ISM_TIMER_OFF (oi->t_ls_ack);
                    319:       break;
                    320:     case ISM_PointToPoint:
                    321:       /* The interface connects to a physical Point-to-point network or
                    322:         virtual link. The router attempts to form an adjacency with
                    323:         neighboring router. Hello packets are also sent. */
                    324:       /* send first hello immediately */
                    325:       OSPF_ISM_TIMER_MSEC_ON (oi->t_hello, ospf_hello_timer, 1);      
                    326:       OSPF_ISM_TIMER_OFF (oi->t_wait);
                    327:       OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
                    328:       break;
                    329:     case ISM_DROther:
                    330:       /* The network type of the interface is broadcast or NBMA network,
                    331:         and the router itself is neither Designated Router nor
                    332:         Backup Designated Router. */
                    333:       OSPF_HELLO_TIMER_ON (oi);
                    334:       OSPF_ISM_TIMER_OFF (oi->t_wait);
                    335:       OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
                    336:       break;
                    337:     case ISM_Backup:
                    338:       /* The network type of the interface is broadcast os NBMA network,
                    339:         and the router is Backup Designated Router. */
                    340:       OSPF_HELLO_TIMER_ON (oi);
                    341:       OSPF_ISM_TIMER_OFF (oi->t_wait);
                    342:       OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
                    343:       break;
                    344:     case ISM_DR:
                    345:       /* The network type of the interface is broadcast or NBMA network,
                    346:         and the router is Designated Router. */
                    347:       OSPF_HELLO_TIMER_ON (oi);
                    348:       OSPF_ISM_TIMER_OFF (oi->t_wait);
                    349:       OSPF_ISM_TIMER_ON (oi->t_ls_ack, ospf_ls_ack_timer, oi->v_ls_ack);
                    350:       break;
                    351:     }
                    352: }
                    353: 
                    354: static int
                    355: ism_interface_up (struct ospf_interface *oi)
                    356: {
                    357:   int next_state = 0;
                    358: 
                    359:   /* if network type is point-to-point, Point-to-MultiPoint or virtual link,
                    360:      the state transitions to Point-to-Point. */
                    361:   if (oi->type == OSPF_IFTYPE_POINTOPOINT ||
                    362:       oi->type == OSPF_IFTYPE_POINTOMULTIPOINT ||
                    363:       oi->type == OSPF_IFTYPE_VIRTUALLINK)
                    364:     next_state = ISM_PointToPoint;
                    365:   /* Else if the router is not eligible to DR, the state transitions to
                    366:      DROther. */
                    367:   else if (PRIORITY (oi) == 0) /* router is eligible? */
                    368:     next_state = ISM_DROther;
                    369:   else
                    370:     /* Otherwise, the state transitions to Waiting. */
                    371:     next_state = ISM_Waiting;
                    372: 
                    373:   if (oi->type == OSPF_IFTYPE_NBMA)
                    374:     ospf_nbr_nbma_if_update (oi->ospf, oi);
                    375: 
                    376:   /*  ospf_ism_event (t); */
                    377:   return next_state;
                    378: }
                    379: 
                    380: static int
                    381: ism_loop_ind (struct ospf_interface *oi)
                    382: {
                    383:   int ret = 0;
                    384: 
                    385:   /* call ism_interface_down. */
                    386:   /* ret = ism_interface_down (oi); */
                    387: 
                    388:   return ret;
                    389: }
                    390: 
                    391: /* Interface down event handler. */
                    392: static int
                    393: ism_interface_down (struct ospf_interface *oi)
                    394: {
                    395:   ospf_if_cleanup (oi);
                    396:   return 0;
                    397: }
                    398: 
                    399: 
                    400: static int
                    401: ism_backup_seen (struct ospf_interface *oi)
                    402: {
                    403:   return ospf_dr_election (oi);
                    404: }
                    405: 
                    406: static int
                    407: ism_wait_timer (struct ospf_interface *oi)
                    408: {
                    409:   return ospf_dr_election (oi);
                    410: }
                    411: 
                    412: static int
                    413: ism_neighbor_change (struct ospf_interface *oi)
                    414: {
                    415:   return ospf_dr_election (oi);
                    416: }
                    417: 
                    418: static int
                    419: ism_ignore (struct ospf_interface *oi)
                    420: {
                    421:   if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
                    422:     zlog (NULL, LOG_DEBUG, "ISM[%s]: ism_ignore called", IF_NAME (oi));
                    423: 
                    424:   return 0;
                    425: }
                    426: 
                    427: /* Interface State Machine */
                    428: struct {
                    429:   int (*func) (struct ospf_interface *);
                    430:   int next_state;
                    431: } ISM [OSPF_ISM_STATE_MAX][OSPF_ISM_EVENT_MAX] =
                    432: {
                    433:   {
                    434:     /* DependUpon: dummy state. */
                    435:     { ism_ignore,          ISM_DependUpon },    /* NoEvent        */
                    436:     { ism_ignore,          ISM_DependUpon },    /* InterfaceUp    */
                    437:     { ism_ignore,          ISM_DependUpon },    /* WaitTimer      */
                    438:     { ism_ignore,          ISM_DependUpon },    /* BackupSeen     */
                    439:     { ism_ignore,          ISM_DependUpon },    /* NeighborChange */
                    440:     { ism_ignore,          ISM_DependUpon },    /* LoopInd        */
                    441:     { ism_ignore,          ISM_DependUpon },    /* UnloopInd      */
                    442:     { ism_ignore,          ISM_DependUpon },    /* InterfaceDown  */
                    443:   },
                    444:   {
                    445:     /* Down:*/
                    446:     { ism_ignore,          ISM_DependUpon },    /* NoEvent        */
                    447:     { ism_interface_up,    ISM_DependUpon },    /* InterfaceUp    */
                    448:     { ism_ignore,          ISM_Down },          /* WaitTimer      */
                    449:     { ism_ignore,          ISM_Down },          /* BackupSeen     */
                    450:     { ism_ignore,          ISM_Down },          /* NeighborChange */
                    451:     { ism_loop_ind,        ISM_Loopback },      /* LoopInd        */
                    452:     { ism_ignore,          ISM_Down },          /* UnloopInd      */
                    453:     { ism_interface_down,  ISM_Down },          /* InterfaceDown  */
                    454:   },
                    455:   {
                    456:     /* Loopback: */
                    457:     { ism_ignore,          ISM_DependUpon },    /* NoEvent        */
                    458:     { ism_ignore,          ISM_Loopback },      /* InterfaceUp    */
                    459:     { ism_ignore,          ISM_Loopback },      /* WaitTimer      */
                    460:     { ism_ignore,          ISM_Loopback },      /* BackupSeen     */
                    461:     { ism_ignore,          ISM_Loopback },      /* NeighborChange */
                    462:     { ism_ignore,          ISM_Loopback },      /* LoopInd        */
                    463:     { ism_ignore,          ISM_Down },          /* UnloopInd      */
                    464:     { ism_interface_down,  ISM_Down },          /* InterfaceDown  */
                    465:   },
                    466:   {
                    467:     /* Waiting: */
                    468:     { ism_ignore,          ISM_DependUpon },    /* NoEvent        */
                    469:     { ism_ignore,          ISM_Waiting },       /* InterfaceUp    */
                    470:     { ism_wait_timer,     ISM_DependUpon },    /* WaitTimer      */
                    471:     { ism_backup_seen,     ISM_DependUpon },    /* BackupSeen     */
                    472:     { ism_ignore,          ISM_Waiting },       /* NeighborChange */
                    473:     { ism_loop_ind,       ISM_Loopback },      /* LoopInd        */
                    474:     { ism_ignore,          ISM_Waiting },       /* UnloopInd      */
                    475:     { ism_interface_down,  ISM_Down },          /* InterfaceDown  */
                    476:   },
                    477:   {
                    478:     /* Point-to-Point: */
                    479:     { ism_ignore,          ISM_DependUpon },    /* NoEvent        */
                    480:     { ism_ignore,          ISM_PointToPoint },  /* InterfaceUp    */
                    481:     { ism_ignore,          ISM_PointToPoint },  /* WaitTimer      */
                    482:     { ism_ignore,          ISM_PointToPoint },  /* BackupSeen     */
                    483:     { ism_ignore,          ISM_PointToPoint },  /* NeighborChange */
                    484:     { ism_loop_ind,       ISM_Loopback },      /* LoopInd        */
                    485:     { ism_ignore,          ISM_PointToPoint },  /* UnloopInd      */
                    486:     { ism_interface_down,  ISM_Down },          /* InterfaceDown  */
                    487:   },
                    488:   {
                    489:     /* DROther: */
                    490:     { ism_ignore,          ISM_DependUpon },    /* NoEvent        */
                    491:     { ism_ignore,          ISM_DROther },       /* InterfaceUp    */
                    492:     { ism_ignore,          ISM_DROther },       /* WaitTimer      */
                    493:     { ism_ignore,          ISM_DROther },       /* BackupSeen     */
                    494:     { ism_neighbor_change, ISM_DependUpon },    /* NeighborChange */
                    495:     { ism_loop_ind,        ISM_Loopback },      /* LoopInd        */
                    496:     { ism_ignore,          ISM_DROther },       /* UnloopInd      */
                    497:     { ism_interface_down,  ISM_Down },          /* InterfaceDown  */
                    498:   },
                    499:   {
                    500:     /* Backup: */
                    501:     { ism_ignore,          ISM_DependUpon },    /* NoEvent        */
                    502:     { ism_ignore,          ISM_Backup },        /* InterfaceUp    */
                    503:     { ism_ignore,          ISM_Backup },        /* WaitTimer      */
                    504:     { ism_ignore,          ISM_Backup },        /* BackupSeen     */
                    505:     { ism_neighbor_change, ISM_DependUpon },    /* NeighborChange */
                    506:     { ism_loop_ind,        ISM_Loopback },      /* LoopInd        */
                    507:     { ism_ignore,          ISM_Backup },        /* UnloopInd      */
                    508:     { ism_interface_down,  ISM_Down },          /* InterfaceDown  */
                    509:   },
                    510:   {
                    511:     /* DR: */
                    512:     { ism_ignore,          ISM_DependUpon },    /* NoEvent        */
                    513:     { ism_ignore,          ISM_DR },            /* InterfaceUp    */
                    514:     { ism_ignore,          ISM_DR },            /* WaitTimer      */
                    515:     { ism_ignore,          ISM_DR },            /* BackupSeen     */
                    516:     { ism_neighbor_change, ISM_DependUpon },    /* NeighborChange */
                    517:     { ism_loop_ind,        ISM_Loopback },      /* LoopInd        */
                    518:     { ism_ignore,          ISM_DR },            /* UnloopInd      */
                    519:     { ism_interface_down,  ISM_Down },          /* InterfaceDown  */
                    520:   },
                    521: };  
                    522: 
                    523: static const char *ospf_ism_event_str[] =
                    524: {
                    525:   "NoEvent",
                    526:   "InterfaceUp",
                    527:   "WaitTimer",
                    528:   "BackupSeen",
                    529:   "NeighborChange",
                    530:   "LoopInd",
                    531:   "UnLoopInd",
                    532:   "InterfaceDown",
                    533: };
                    534: 
                    535: static void
                    536: ism_change_state (struct ospf_interface *oi, int state)
                    537: {
                    538:   int old_state;
                    539:   struct ospf_lsa *lsa;
                    540: 
                    541:   /* Logging change of state. */
                    542:   if (IS_DEBUG_OSPF (ism, ISM_STATUS))
                    543:     zlog (NULL, LOG_DEBUG, "ISM[%s]: State change %s -> %s", IF_NAME (oi),
                    544:          LOOKUP (ospf_ism_state_msg, oi->state),
                    545:          LOOKUP (ospf_ism_state_msg, state));
                    546: 
                    547:   old_state = oi->state;
                    548:   oi->state = state;
                    549:   oi->state_change++;
                    550: 
                    551: #ifdef HAVE_SNMP
                    552:   /* Terminal state or regression */ 
                    553:   if ((state == ISM_DR) || (state == ISM_Backup) || (state == ISM_DROther) ||
                    554:       (state == ISM_PointToPoint) || (state < old_state))
                    555:     {
                    556:       /* ospfVirtIfStateChange */
                    557:       if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
                    558:         ospfTrapVirtIfStateChange (oi);
                    559:       /* ospfIfStateChange */
                    560:       else
                    561:         ospfTrapIfStateChange (oi);
                    562:     }
                    563: #endif
                    564: 
                    565:   /* Set multicast memberships appropriately for new state. */
                    566:   ospf_if_set_multicast(oi);
                    567: 
                    568:   if (old_state == ISM_Down || state == ISM_Down)
                    569:     ospf_check_abr_status (oi->ospf);
                    570: 
                    571:   /* Originate router-LSA. */
                    572:   if (state == ISM_Down)
                    573:     {
                    574:       if (oi->area->act_ints > 0)
                    575:         oi->area->act_ints--;
                    576:     }
                    577:   else if (old_state == ISM_Down)
                    578:     oi->area->act_ints++;
                    579: 
                    580:   /* schedule router-LSA originate. */
                    581:   ospf_router_lsa_update_area (oi->area);
                    582: 
                    583:   /* Originate network-LSA. */
                    584:   if (old_state != ISM_DR && state == ISM_DR)
                    585:     ospf_network_lsa_update (oi);
                    586:   else if (old_state == ISM_DR && state != ISM_DR)
                    587:     {
                    588:       /* Free self originated network LSA. */
                    589:       lsa = oi->network_lsa_self;
                    590:       if (lsa)
                    591:         ospf_lsa_flush_area (lsa, oi->area);
                    592: 
                    593:       ospf_lsa_unlock (&oi->network_lsa_self);
                    594:       oi->network_lsa_self = NULL;
                    595:     }
                    596: 
                    597: #ifdef HAVE_OPAQUE_LSA
                    598:   ospf_opaque_ism_change (oi, old_state);
                    599: #endif /* HAVE_OPAQUE_LSA */
                    600: 
                    601:   /* Check area border status.  */
                    602:   ospf_check_abr_status (oi->ospf);
                    603: }
                    604: 
                    605: /* Execute ISM event process. */
                    606: int
                    607: ospf_ism_event (struct thread *thread)
                    608: {
                    609:   int event;
                    610:   int next_state;
                    611:   struct ospf_interface *oi;
                    612: 
                    613:   oi = THREAD_ARG (thread);
                    614:   event = THREAD_VAL (thread);
                    615: 
                    616:   /* Call function. */
                    617:   next_state = (*(ISM [oi->state][event].func))(oi);
                    618: 
                    619:   if (! next_state)
                    620:     next_state = ISM [oi->state][event].next_state;
                    621: 
                    622:   if (IS_DEBUG_OSPF (ism, ISM_EVENTS))
                    623:     zlog (NULL, LOG_DEBUG, "ISM[%s]: %s (%s)", IF_NAME (oi),
                    624:          LOOKUP (ospf_ism_state_msg, oi->state),
                    625:          ospf_ism_event_str[event]);
                    626: 
                    627:   /* If state is changed. */
                    628:   if (next_state != oi->state)
                    629:     ism_change_state (oi, next_state);
                    630: 
                    631:   /* Make sure timer is set. */
                    632:   ism_timer_set (oi);
                    633: 
                    634:   return 0;
                    635: }
                    636: 

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