File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / ospfd / ospf_ism.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 17:26:12 2012 UTC (12 years, 4 months ago) by misho
Branches: quagga, MAIN
CVS tags: v0_99_21, v0_99_20_1, v0_99_20, HEAD
quagga

    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>