back to topotato report
topotato coverage report
Current view: top level - ospfd - ospf_ism.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 199 224 88.8 %
Date: 2023-02-24 14:41:08 Functions: 17 19 89.5 %

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

Generated by: LCOV version v1.16-topotato