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