ospf_ism.c
上传用户:xiaozhuqw
上传日期:2009-11-15
资源大小:1338k
文件大小:18k
源码类别:

网络

开发平台:

Unix_Linux

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