back to topotato report
topotato coverage report
Current view: top level - ospfd - ospf_nsm.c (source / functions) Hit Total Coverage
Test: aggregated run ( view descriptions ) Lines: 198 283 70.0 %
Date: 2023-02-24 14:41:08 Functions: 18 21 85.7 %

          Line data    Source code
       1             : /*
       2             :  * OSPF version 2  Neighbor 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 "memory.h"
      27             : #include "hash.h"
      28             : #include "linklist.h"
      29             : #include "prefix.h"
      30             : #include "if.h"
      31             : #include "table.h"
      32             : #include "stream.h"
      33             : #include "table.h"
      34             : #include "log.h"
      35             : #include "command.h"
      36             : #include "network.h"
      37             : 
      38             : #include "ospfd/ospfd.h"
      39             : #include "ospfd/ospf_interface.h"
      40             : #include "ospfd/ospf_ism.h"
      41             : #include "ospfd/ospf_asbr.h"
      42             : #include "ospfd/ospf_lsa.h"
      43             : #include "ospfd/ospf_lsdb.h"
      44             : #include "ospfd/ospf_neighbor.h"
      45             : #include "ospfd/ospf_nsm.h"
      46             : #include "ospfd/ospf_network.h"
      47             : #include "ospfd/ospf_packet.h"
      48             : #include "ospfd/ospf_dump.h"
      49             : #include "ospfd/ospf_flood.h"
      50             : #include "ospfd/ospf_abr.h"
      51             : #include "ospfd/ospf_bfd.h"
      52             : #include "ospfd/ospf_gr.h"
      53             : #include "ospfd/ospf_errors.h"
      54             : 
      55          55 : DEFINE_HOOK(ospf_nsm_change,
      56             :             (struct ospf_neighbor * on, int state, int oldstate),
      57             :             (on, state, oldstate));
      58             : 
      59             : static void nsm_clear_adj(struct ospf_neighbor *);
      60             : 
      61             : /* OSPF NSM Timer functions. */
      62           2 : static void ospf_inactivity_timer(struct thread *thread)
      63             : {
      64           2 :         struct ospf_neighbor *nbr;
      65             : 
      66           2 :         nbr = THREAD_ARG(thread);
      67           2 :         nbr->t_inactivity = NULL;
      68             : 
      69           2 :         if (IS_DEBUG_OSPF(nsm, NSM_TIMERS))
      70           0 :                 zlog_debug("NSM[%s:%pI4:%s]: Timer (Inactivity timer expire)",
      71             :                            IF_NAME(nbr->oi), &nbr->router_id,
      72             :                            ospf_get_name(nbr->oi->ospf));
      73             : 
      74             :         /* Dont trigger NSM_InactivityTimer event , if the current
      75             :          * router acting as HELPER for this neighbour.
      76             :          */
      77           2 :         if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
      78           2 :                 OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_InactivityTimer);
      79             :         else {
      80           0 :                 if (IS_DEBUG_OSPF_GR)
      81           0 :                         zlog_debug(
      82             :                                 "%s, Acting as HELPER for this neighbour, So restart the dead timer",
      83             :                                 __func__);
      84           0 :                 OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
      85             :                                   nbr->v_inactivity);
      86             :         }
      87           2 : }
      88             : 
      89           0 : static void ospf_db_desc_timer(struct thread *thread)
      90             : {
      91           0 :         struct ospf_neighbor *nbr;
      92             : 
      93           0 :         nbr = THREAD_ARG(thread);
      94           0 :         nbr->t_db_desc = NULL;
      95             : 
      96           0 :         if (IS_DEBUG_OSPF(nsm, NSM_TIMERS))
      97           0 :                 zlog_debug("NSM[%s:%pI4:%s]: Timer (DD Retransmit timer expire)",
      98             :                            IF_NAME(nbr->oi), &nbr->src,
      99             :                            ospf_get_name(nbr->oi->ospf));
     100             : 
     101             :         /* resent last send DD packet. */
     102           0 :         assert(nbr->last_send);
     103           0 :         ospf_db_desc_resend(nbr);
     104             : 
     105             :         /* DD Retransmit timer set. */
     106           0 :         OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer, nbr->v_db_desc);
     107           0 : }
     108             : 
     109             : /* Hook function called after ospf NSM event is occurred.
     110             :  *
     111             :  * Set/clear any timers whose condition is implicit to the neighbour
     112             :  * state. There may be other timers which are set/unset according to other
     113             :  * state.
     114             :  *
     115             :  * We rely on this function to properly clear timers in lower states,
     116             :  * particularly before deleting a neighbour.
     117             :  */
     118         206 : static void nsm_timer_set(struct ospf_neighbor *nbr)
     119             : {
     120         206 :         switch (nbr->state) {
     121           8 :         case NSM_Deleted:
     122             :         case NSM_Down:
     123           8 :                 THREAD_OFF(nbr->t_inactivity);
     124           8 :                 THREAD_OFF(nbr->t_hello_reply);
     125             :         /* fallthru */
     126             :         case NSM_Attempt:
     127             :         case NSM_Init:
     128             :         case NSM_TwoWay:
     129          41 :                 THREAD_OFF(nbr->t_db_desc);
     130          41 :                 THREAD_OFF(nbr->t_ls_upd);
     131          41 :                 THREAD_OFF(nbr->t_ls_req);
     132             :                 break;
     133           8 :         case NSM_ExStart:
     134           8 :                 OSPF_NSM_TIMER_ON(nbr->t_db_desc, ospf_db_desc_timer,
     135             :                                   nbr->v_db_desc);
     136           8 :                 THREAD_OFF(nbr->t_ls_upd);
     137           8 :                 THREAD_OFF(nbr->t_ls_req);
     138             :                 break;
     139           8 :         case NSM_Exchange:
     140           8 :                 OSPF_NSM_TIMER_ON(nbr->t_ls_upd, ospf_ls_upd_timer,
     141             :                                   nbr->v_ls_upd);
     142           8 :                 if (!IS_SET_DD_MS(nbr->dd_flags))
     143           4 :                         THREAD_OFF(nbr->t_db_desc);
     144             :                 break;
     145         149 :         case NSM_Loading:
     146             :         case NSM_Full:
     147             :         default:
     148         149 :                 THREAD_OFF(nbr->t_db_desc);
     149             :                 break;
     150             :         }
     151         206 : }
     152             : 
     153             : /* 10.4 of RFC2328, indicate whether an adjacency is appropriate with
     154             :  * the given neighbour
     155             :  */
     156          24 : int nsm_should_adj(struct ospf_neighbor *nbr)
     157             : {
     158          24 :         struct ospf_interface *oi = nbr->oi;
     159             : 
     160             :         /* These network types must always form adjacencies. */
     161          24 :         if (oi->type == OSPF_IFTYPE_POINTOPOINT
     162          24 :             || oi->type == OSPF_IFTYPE_POINTOMULTIPOINT
     163          24 :             || oi->type == OSPF_IFTYPE_VIRTUALLINK
     164             :             /* Router itself is the DRouter or the BDRouter. */
     165          24 :             || IPV4_ADDR_SAME(&oi->address->u.prefix4, &DR(oi))
     166          20 :             || IPV4_ADDR_SAME(&oi->address->u.prefix4, &BDR(oi))
     167             :             /* Neighboring Router is the DRouter or the BDRouter. */
     168          16 :             || IPV4_ADDR_SAME(&nbr->address.u.prefix4, &DR(oi))
     169          11 :             || IPV4_ADDR_SAME(&nbr->address.u.prefix4, &BDR(oi)))
     170          14 :                 return 1;
     171             : 
     172             :         return 0;
     173             : }
     174             : 
     175             : /* OSPF NSM functions. */
     176          79 : static int nsm_hello_received(struct ospf_neighbor *nbr)
     177             : {
     178             :         /* Start or Restart Inactivity Timer. */
     179          79 :         THREAD_OFF(nbr->t_inactivity);
     180             : 
     181          79 :         OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
     182             :                           nbr->v_inactivity);
     183             : 
     184          79 :         if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma)
     185           0 :                 THREAD_OFF(nbr->nbr_nbma->t_poll);
     186             : 
     187             :         /* Send proactive ARP requests */
     188          79 :         if (nbr->state < NSM_Exchange)
     189          15 :                 ospf_proactively_arp(nbr);
     190             : 
     191          79 :         return 0;
     192             : }
     193             : 
     194           0 : static int nsm_start(struct ospf_neighbor *nbr)
     195             : {
     196           0 :         if (nbr->nbr_nbma)
     197           0 :                 THREAD_OFF(nbr->nbr_nbma->t_poll);
     198             : 
     199           0 :         THREAD_OFF(nbr->t_inactivity);
     200             : 
     201           0 :         OSPF_NSM_TIMER_ON(nbr->t_inactivity, ospf_inactivity_timer,
     202             :                           nbr->v_inactivity);
     203             : 
     204             :         /* Send proactive ARP requests */
     205           0 :         ospf_proactively_arp(nbr);
     206             : 
     207           0 :         return 0;
     208             : }
     209             : 
     210           8 : static int nsm_twoway_received(struct ospf_neighbor *nbr)
     211             : {
     212           8 :         int adj = nsm_should_adj(nbr);
     213             : 
     214             :         /* Send proactive ARP requests */
     215           8 :         if (adj)
     216           0 :                 ospf_proactively_arp(nbr);
     217             : 
     218           0 :         return (adj ? NSM_ExStart : NSM_TwoWay);
     219             : }
     220             : 
     221          51 : int ospf_db_summary_count(struct ospf_neighbor *nbr)
     222             : {
     223          51 :         return ospf_lsdb_count_all(&nbr->db_sum);
     224             : }
     225             : 
     226          36 : int ospf_db_summary_isempty(struct ospf_neighbor *nbr)
     227             : {
     228          28 :         return ospf_lsdb_isempty(&nbr->db_sum);
     229             : }
     230             : 
     231          36 : static int ospf_db_summary_add(struct ospf_neighbor *nbr, struct ospf_lsa *lsa)
     232             : {
     233          36 :         switch (lsa->data->type) {
     234           0 :         case OSPF_OPAQUE_LINK_LSA:
     235             :                 /* Exclude type-9 LSAs that does not have the same "oi" with
     236             :                  * "nbr". */
     237           0 :                 if (ospf_if_exists(lsa->oi) != nbr->oi)
     238             :                         return 0;
     239             :                 break;
     240             :         case OSPF_OPAQUE_AREA_LSA:
     241             :                 /*
     242             :                  * It is assured by the caller function "nsm_negotiation_done()"
     243             :                  * that every given LSA belongs to the same area with "nbr".
     244             :                  */
     245             :                 break;
     246             :         case OSPF_OPAQUE_AS_LSA:
     247             :         default:
     248             :                 break;
     249             :         }
     250             : 
     251             :         /* Stay away from any Local Translated Type-7 LSAs */
     252          36 :         if (CHECK_FLAG(lsa->flags, OSPF_LSA_LOCAL_XLT))
     253             :                 return 0;
     254             : 
     255          36 :         if (IS_LSA_MAXAGE(lsa))
     256           0 :                 ospf_ls_retransmit_add(nbr, lsa);
     257             :         else
     258          36 :                 ospf_lsdb_add(&nbr->db_sum, lsa);
     259             : 
     260             :         return 0;
     261             : }
     262             : 
     263           0 : void ospf_db_summary_clear(struct ospf_neighbor *nbr)
     264             : {
     265           0 :         struct ospf_lsdb *lsdb;
     266           0 :         int i;
     267             : 
     268           0 :         lsdb = &nbr->db_sum;
     269           0 :         for (i = OSPF_MIN_LSA; i < OSPF_MAX_LSA; i++) {
     270           0 :                 struct route_table *table = lsdb->type[i].db;
     271           0 :                 struct route_node *rn;
     272             : 
     273           0 :                 for (rn = route_top(table); rn; rn = route_next(rn))
     274           0 :                         if (rn->info)
     275           0 :                                 ospf_lsdb_delete(&nbr->db_sum, rn->info);
     276             :         }
     277           0 : }
     278             : 
     279             : 
     280             : /* The area link state database consists of the router-LSAs,
     281             :    network-LSAs and summary-LSAs contained in the area structure,
     282             :    along with the AS-external-LSAs contained in the global structure.
     283             :    AS-external-LSAs are omitted from a virtual neighbor's Database
     284             :    summary list.  AS-external-LSAs are omitted from the Database
     285             :    summary list if the area has been configured as a stub. */
     286           8 : static int nsm_negotiation_done(struct ospf_neighbor *nbr)
     287             : {
     288           8 :         struct ospf_area *area = nbr->oi->area;
     289           8 :         struct ospf_lsa *lsa;
     290           8 :         struct route_node *rn;
     291             : 
     292             :         /* Send proactive ARP requests */
     293           8 :         ospf_proactively_arp(nbr);
     294             : 
     295          24 :         LSDB_LOOP (ROUTER_LSDB(area), rn, lsa)
     296          12 :                 ospf_db_summary_add(nbr, lsa);
     297          10 :         LSDB_LOOP (NETWORK_LSDB(area), rn, lsa)
     298           2 :                 ospf_db_summary_add(nbr, lsa);
     299          15 :         LSDB_LOOP (SUMMARY_LSDB(area), rn, lsa)
     300           6 :                 ospf_db_summary_add(nbr, lsa);
     301             : 
     302             :         /* Process only if the neighbor is opaque capable. */
     303           8 :         if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)) {
     304           0 :                 LSDB_LOOP (OPAQUE_LINK_LSDB(area), rn, lsa)
     305           0 :                         ospf_db_summary_add(nbr, lsa);
     306           0 :                 LSDB_LOOP (OPAQUE_AREA_LSDB(area), rn, lsa)
     307           0 :                         ospf_db_summary_add(nbr, lsa);
     308             :         }
     309             : 
     310           8 :         if (CHECK_FLAG(nbr->options, OSPF_OPTION_NP)) {
     311           0 :                 LSDB_LOOP (NSSA_LSDB(area), rn, lsa)
     312           0 :                         ospf_db_summary_add(nbr, lsa);
     313             :         }
     314             : 
     315             :         /* For Stub/NSSA area, we should not send Type-4 and Type-5 LSAs */
     316           8 :         if (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
     317           8 :             && area->external_routing == OSPF_AREA_DEFAULT) {
     318           8 :                 LSDB_LOOP (ASBR_SUMMARY_LSDB(area), rn, lsa)
     319           0 :                         ospf_db_summary_add(nbr, lsa);
     320          32 :                 LSDB_LOOP (EXTERNAL_LSDB(nbr->oi->ospf), rn, lsa)
     321          16 :                         ospf_db_summary_add(nbr, lsa);
     322             :         }
     323             : 
     324           8 :         if (CHECK_FLAG(nbr->options, OSPF_OPTION_O)
     325           0 :             && (nbr->oi->type != OSPF_IFTYPE_VIRTUALLINK
     326           0 :                 && area->external_routing == OSPF_AREA_DEFAULT))
     327           0 :                 LSDB_LOOP (OPAQUE_AS_LSDB(nbr->oi->ospf), rn, lsa)
     328           0 :                         ospf_db_summary_add(nbr, lsa);
     329             : 
     330           8 :         return 0;
     331             : }
     332             : 
     333           8 : static int nsm_exchange_done(struct ospf_neighbor *nbr)
     334             : {
     335           8 :         if (ospf_ls_request_isempty(nbr))
     336             :                 return NSM_Full;
     337             : 
     338             :         /* Send Link State Request. */
     339           7 :         if (nbr->t_ls_req == NULL)
     340           0 :                 ospf_ls_req_send(nbr);
     341             : 
     342             :         return NSM_Loading;
     343             : }
     344             : 
     345          16 : static int nsm_adj_ok(struct ospf_neighbor *nbr)
     346             : {
     347          16 :         int next_state = nbr->state;
     348          16 :         int adj = nsm_should_adj(nbr);
     349             : 
     350          16 :         if (nbr->state == NSM_TwoWay && adj == 1) {
     351           8 :                 next_state = NSM_ExStart;
     352             : 
     353             :                 /* Send proactive ARP requests */
     354           8 :                 ospf_proactively_arp(nbr);
     355           8 :         } else if (nbr->state >= NSM_ExStart && adj == 0)
     356          16 :                 next_state = NSM_TwoWay;
     357             : 
     358          16 :         return next_state;
     359             : }
     360             : 
     361             : /* Clear adjacency related state for a neighbour, intended where nbr
     362             :  * transitions from > ExStart (i.e. a Full or forming adjacency)
     363             :  * to <= ExStart.
     364             :  */
     365           8 : static void nsm_clear_adj(struct ospf_neighbor *nbr)
     366             : {
     367             :         /* Clear Database Summary list. */
     368           8 :         if (!ospf_db_summary_isempty(nbr))
     369           0 :                 ospf_db_summary_clear(nbr);
     370             : 
     371             :         /* Clear Link State Request list. */
     372           8 :         if (!ospf_ls_request_isempty(nbr))
     373           0 :                 ospf_ls_request_delete_all(nbr);
     374             : 
     375             :         /* Clear Link State Retransmission list. */
     376           8 :         if (!ospf_ls_retransmit_isempty(nbr))
     377           5 :                 ospf_ls_retransmit_clear(nbr);
     378             : 
     379           8 :         if (CHECK_FLAG(nbr->options, OSPF_OPTION_O))
     380           0 :                 UNSET_FLAG(nbr->options, OSPF_OPTION_O);
     381           8 : }
     382             : 
     383           8 : static int nsm_kill_nbr(struct ospf_neighbor *nbr)
     384             : {
     385           8 :         struct ospf_interface *oi = nbr->oi;
     386           8 :         struct ospf_neighbor *on;
     387           8 :         struct route_node *rn;
     388             : 
     389             :         /* killing nbr_self is invalid */
     390           8 :         if (nbr == nbr->oi->nbr_self) {
     391           0 :                 assert(nbr != nbr->oi->nbr_self);
     392             :                 return 0;
     393             :         }
     394             : 
     395           8 :         if (nbr->oi->type == OSPF_IFTYPE_NBMA && nbr->nbr_nbma != NULL) {
     396           0 :                 struct ospf_nbr_nbma *nbr_nbma = nbr->nbr_nbma;
     397             : 
     398           0 :                 nbr_nbma->nbr = NULL;
     399           0 :                 nbr_nbma->state_change = nbr->state_change;
     400             : 
     401           0 :                 nbr->nbr_nbma = NULL;
     402             : 
     403           0 :                 OSPF_POLL_TIMER_ON(nbr_nbma->t_poll, ospf_poll_timer,
     404             :                                    nbr_nbma->v_poll);
     405             : 
     406           0 :                 if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
     407           0 :                         zlog_debug(
     408             :                                 "NSM[%s:%pI4:%s]: Down (PollIntervalTimer scheduled)",
     409             :                                 IF_NAME(nbr->oi),
     410             :                                 &nbr->address.u.prefix4,
     411             :                                 ospf_get_name(nbr->oi->ospf));
     412             :         }
     413             : 
     414             :         /*
     415             :          * Do we have any neighbors that are also operating
     416             :          * on this interface?
     417             :          */
     418          30 :         for (rn = route_top(oi->nbrs); rn; rn = route_next(rn)) {
     419          25 :                 on = rn->info;
     420             : 
     421          25 :                 if (!on)
     422          10 :                         continue;
     423             : 
     424          15 :                 if (on == nbr || on == oi->nbr_self)
     425          12 :                         continue;
     426             : 
     427             :                 /*
     428             :                  * on is in some state where we might be
     429             :                  * sending packets on this interface
     430             :                  */
     431           3 :                 if (on->state > NSM_Down) {
     432           3 :                         route_unlock_node(rn);
     433           3 :                         return 0;
     434             :                 }
     435             :         }
     436             :         /*
     437             :          * If we get here we know that this interface
     438             :          * has no neighbors in a state where we could
     439             :          * be sending packets.  Let's flush anything
     440             :          * we got.
     441             :          */
     442           5 :         ospf_interface_fifo_flush(oi);
     443           5 :         return 0;
     444             : }
     445             : 
     446             : /* Neighbor State Machine */
     447             : const struct {
     448             :         int (*func)(struct ospf_neighbor *);
     449             :         int next_state;
     450             : } NSM[OSPF_NSM_STATE_MAX][OSPF_NSM_EVENT_MAX] = {
     451             :         {
     452             :                 /* DependUpon: dummy state. */
     453             :                 {NULL, NSM_DependUpon}, /* NoEvent           */
     454             :                 {NULL, NSM_DependUpon}, /* HelloReceived     */
     455             :                 {NULL, NSM_DependUpon}, /* Start             */
     456             :                 {NULL, NSM_DependUpon}, /* 2-WayReceived     */
     457             :                 {NULL, NSM_DependUpon}, /* NegotiationDone   */
     458             :                 {NULL, NSM_DependUpon}, /* ExchangeDone      */
     459             :                 {NULL, NSM_DependUpon}, /* BadLSReq          */
     460             :                 {NULL, NSM_DependUpon}, /* LoadingDone       */
     461             :                 {NULL, NSM_DependUpon}, /* AdjOK?            */
     462             :                 {NULL, NSM_DependUpon}, /* SeqNumberMismatch */
     463             :                 {NULL, NSM_DependUpon}, /* 1-WayReceived     */
     464             :                 {NULL, NSM_DependUpon}, /* KillNbr           */
     465             :                 {NULL, NSM_DependUpon}, /* InactivityTimer   */
     466             :                 {NULL, NSM_DependUpon}, /* LLDown            */
     467             :         },
     468             :         {
     469             :                 /* Deleted: dummy state. */
     470             :                 {NULL, NSM_Deleted}, /* NoEvent           */
     471             :                 {NULL, NSM_Deleted}, /* HelloReceived     */
     472             :                 {NULL, NSM_Deleted}, /* Start             */
     473             :                 {NULL, NSM_Deleted}, /* 2-WayReceived     */
     474             :                 {NULL, NSM_Deleted}, /* NegotiationDone   */
     475             :                 {NULL, NSM_Deleted}, /* ExchangeDone      */
     476             :                 {NULL, NSM_Deleted}, /* BadLSReq          */
     477             :                 {NULL, NSM_Deleted}, /* LoadingDone       */
     478             :                 {NULL, NSM_Deleted}, /* AdjOK?            */
     479             :                 {NULL, NSM_Deleted}, /* SeqNumberMismatch */
     480             :                 {NULL, NSM_Deleted}, /* 1-WayReceived     */
     481             :                 {NULL, NSM_Deleted}, /* KillNbr           */
     482             :                 {NULL, NSM_Deleted}, /* InactivityTimer   */
     483             :                 {NULL, NSM_Deleted}, /* LLDown            */
     484             :         },
     485             :         {
     486             :                 /* Down: */
     487             :                 {NULL, NSM_DependUpon},          /* NoEvent           */
     488             :                 {nsm_hello_received, NSM_Init},  /* HelloReceived     */
     489             :                 {nsm_start, NSM_Attempt},        /* Start             */
     490             :                 {NULL, NSM_Down},                /* 2-WayReceived     */
     491             :                 {NULL, NSM_Down},                /* NegotiationDone   */
     492             :                 {NULL, NSM_Down},                /* ExchangeDone      */
     493             :                 {NULL, NSM_Down},                /* BadLSReq          */
     494             :                 {NULL, NSM_Down},                /* LoadingDone       */
     495             :                 {NULL, NSM_Down},                /* AdjOK?            */
     496             :                 {NULL, NSM_Down},                /* SeqNumberMismatch */
     497             :                 {NULL, NSM_Down},                /* 1-WayReceived     */
     498             :                 {nsm_kill_nbr, NSM_Deleted},     /* KillNbr           */
     499             :                 {nsm_kill_nbr, NSM_Deleted},     /* InactivityTimer   */
     500             :                 {nsm_kill_nbr, NSM_Deleted},     /* LLDown            */
     501             :         },
     502             :         {
     503             :                 /* Attempt: */
     504             :                 {NULL, NSM_DependUpon},          /* NoEvent           */
     505             :                 {nsm_hello_received, NSM_Init},  /* HelloReceived     */
     506             :                 {NULL, NSM_Attempt},             /* Start             */
     507             :                 {NULL, NSM_Attempt},             /* 2-WayReceived     */
     508             :                 {NULL, NSM_Attempt},             /* NegotiationDone   */
     509             :                 {NULL, NSM_Attempt},             /* ExchangeDone      */
     510             :                 {NULL, NSM_Attempt},             /* BadLSReq          */
     511             :                 {NULL, NSM_Attempt},             /* LoadingDone       */
     512             :                 {NULL, NSM_Attempt},             /* AdjOK?            */
     513             :                 {NULL, NSM_Attempt},             /* SeqNumberMismatch */
     514             :                 {NULL, NSM_Attempt},             /* 1-WayReceived     */
     515             :                 {nsm_kill_nbr, NSM_Deleted},     /* KillNbr           */
     516             :                 {nsm_kill_nbr, NSM_Deleted},     /* InactivityTimer   */
     517             :                 {nsm_kill_nbr, NSM_Deleted},     /* LLDown            */
     518             :         },
     519             :         {
     520             :                 /* Init: */
     521             :                 {NULL, NSM_DependUpon},                /* NoEvent           */
     522             :                 {nsm_hello_received, NSM_Init},        /* HelloReceived     */
     523             :                 {NULL, NSM_Init},                      /* Start             */
     524             :                 {nsm_twoway_received, NSM_DependUpon}, /* 2-WayReceived     */
     525             :                 {NULL, NSM_Init},                      /* NegotiationDone   */
     526             :                 {NULL, NSM_Init},                      /* ExchangeDone      */
     527             :                 {NULL, NSM_Init},                      /* BadLSReq          */
     528             :                 {NULL, NSM_Init},                      /* LoadingDone       */
     529             :                 {NULL, NSM_Init},                      /* AdjOK?            */
     530             :                 {NULL, NSM_Init},                      /* SeqNumberMismatch */
     531             :                 {NULL, NSM_Init},                      /* 1-WayReceived     */
     532             :                 {nsm_kill_nbr, NSM_Deleted},       /* KillNbr           */
     533             :                 {nsm_kill_nbr, NSM_Deleted},       /* InactivityTimer   */
     534             :                 {nsm_kill_nbr, NSM_Deleted},       /* LLDown            */
     535             :         },
     536             :         {
     537             :                 /* 2-Way: */
     538             :                 {NULL, NSM_DependUpon},            /* NoEvent           */
     539             :                 {nsm_hello_received, NSM_TwoWay},  /* HelloReceived     */
     540             :                 {NULL, NSM_TwoWay},                /* Start             */
     541             :                 {NULL, NSM_TwoWay},                /* 2-WayReceived     */
     542             :                 {NULL, NSM_TwoWay},                /* NegotiationDone   */
     543             :                 {NULL, NSM_TwoWay},                /* ExchangeDone      */
     544             :                 {NULL, NSM_TwoWay},                /* BadLSReq          */
     545             :                 {NULL, NSM_TwoWay},                /* LoadingDone       */
     546             :                 {nsm_adj_ok, NSM_DependUpon},      /* AdjOK?            */
     547             :                 {NULL, NSM_TwoWay},                /* SeqNumberMismatch */
     548             :                 {NULL, NSM_Init},                  /* 1-WayReceived     */
     549             :                 {nsm_kill_nbr, NSM_Deleted},       /* KillNbr           */
     550             :                 {nsm_kill_nbr, NSM_Deleted},       /* InactivityTimer   */
     551             :                 {nsm_kill_nbr, NSM_Deleted},       /* LLDown            */
     552             :         },
     553             :         {
     554             :                 /* ExStart: */
     555             :                 {NULL, NSM_DependUpon},               /* NoEvent           */
     556             :                 {nsm_hello_received, NSM_ExStart},    /* HelloReceived     */
     557             :                 {NULL, NSM_ExStart},                  /* Start             */
     558             :                 {NULL, NSM_ExStart},                  /* 2-WayReceived     */
     559             :                 {nsm_negotiation_done, NSM_Exchange}, /* NegotiationDone   */
     560             :                 {NULL, NSM_ExStart},                  /* ExchangeDone      */
     561             :                 {NULL, NSM_ExStart},                  /* BadLSReq          */
     562             :                 {NULL, NSM_ExStart},                  /* LoadingDone       */
     563             :                 {nsm_adj_ok, NSM_DependUpon},    /* AdjOK?            */
     564             :                 {NULL, NSM_ExStart},                  /* SeqNumberMismatch */
     565             :                 {NULL, NSM_Init},                     /* 1-WayReceived     */
     566             :                 {nsm_kill_nbr, NSM_Deleted},      /* KillNbr           */
     567             :                 {nsm_kill_nbr, NSM_Deleted},      /* InactivityTimer   */
     568             :                 {nsm_kill_nbr, NSM_Deleted},      /* LLDown            */
     569             :         },
     570             :         {
     571             :                 /* Exchange: */
     572             :                 {NULL, NSM_DependUpon},              /* NoEvent           */
     573             :                 {nsm_hello_received, NSM_Exchange},  /* HelloReceived     */
     574             :                 {NULL, NSM_Exchange},                /* Start             */
     575             :                 {NULL, NSM_Exchange},                /* 2-WayReceived     */
     576             :                 {NULL, NSM_Exchange},                /* NegotiationDone   */
     577             :                 {nsm_exchange_done, NSM_DependUpon}, /* ExchangeDone      */
     578             :                 {NULL, NSM_ExStart},                 /* BadLSReq          */
     579             :                 {NULL, NSM_Exchange},                /* LoadingDone       */
     580             :                 {nsm_adj_ok, NSM_DependUpon},   /* AdjOK?            */
     581             :                 {NULL, NSM_ExStart},                 /* SeqNumberMismatch */
     582             :                 {NULL, NSM_Init},                    /* 1-WayReceived     */
     583             :                 {nsm_kill_nbr, NSM_Deleted},     /* KillNbr           */
     584             :                 {nsm_kill_nbr, NSM_Deleted},     /* InactivityTimer   */
     585             :                 {nsm_kill_nbr, NSM_Deleted},     /* LLDown            */
     586             :         },
     587             :         {
     588             :                 /* Loading: */
     589             :                 {NULL, NSM_DependUpon},             /* NoEvent           */
     590             :                 {nsm_hello_received, NSM_Loading},  /* HelloReceived     */
     591             :                 {NULL, NSM_Loading},                /* Start             */
     592             :                 {NULL, NSM_Loading},                /* 2-WayReceived     */
     593             :                 {NULL, NSM_Loading},                /* NegotiationDone   */
     594             :                 {NULL, NSM_Loading},                /* ExchangeDone      */
     595             :                 {NULL, NSM_ExStart},                /* BadLSReq          */
     596             :                 {NULL, NSM_Full},                   /* LoadingDone       */
     597             :                 {nsm_adj_ok, NSM_DependUpon},       /* AdjOK?            */
     598             :                 {NULL, NSM_ExStart},                /* SeqNumberMismatch */
     599             :                 {NULL, NSM_Init},                   /* 1-WayReceived     */
     600             :                 {nsm_kill_nbr, NSM_Deleted},    /* KillNbr           */
     601             :                 {nsm_kill_nbr, NSM_Deleted},    /* InactivityTimer   */
     602             :                 {nsm_kill_nbr, NSM_Deleted},    /* LLDown            */
     603             :         },
     604             :         {
     605             :                 /* Full: */
     606             :                 {NULL, NSM_DependUpon},          /* NoEvent           */
     607             :                 {nsm_hello_received, NSM_Full},  /* HelloReceived     */
     608             :                 {NULL, NSM_Full},                /* Start             */
     609             :                 {NULL, NSM_Full},                /* 2-WayReceived     */
     610             :                 {NULL, NSM_Full},                /* NegotiationDone   */
     611             :                 {NULL, NSM_Full},                /* ExchangeDone      */
     612             :                 {NULL, NSM_ExStart},             /* BadLSReq          */
     613             :                 {NULL, NSM_Full},                /* LoadingDone       */
     614             :                 {nsm_adj_ok, NSM_DependUpon},    /* AdjOK?            */
     615             :                 {NULL, NSM_ExStart},             /* SeqNumberMismatch */
     616             :                 {NULL, NSM_Init},                /* 1-WayReceived     */
     617             :                 {nsm_kill_nbr, NSM_Deleted},     /* KillNbr           */
     618             :                 {nsm_kill_nbr, NSM_Deleted},     /* InactivityTimer   */
     619             :                 {nsm_kill_nbr, NSM_Deleted},     /* LLDown            */
     620             :         },
     621             : };
     622             : 
     623             : static const char *const ospf_nsm_event_str[] = {
     624             :         "NoEvent",       "HelloReceived",  "Start",
     625             :         "2-WayReceived",     "NegotiationDone", "ExchangeDone",
     626             :         "BadLSReq",     "LoadingDone",     "AdjOK?",
     627             :         "SeqNumberMismatch", "1-WayReceived",   "KillNbr",
     628             :         "InactivityTimer",   "LLDown",
     629             : };
     630             : 
     631          55 : static void nsm_notice_state_change(struct ospf_neighbor *nbr, int next_state,
     632             :                                     int event)
     633             : {
     634             :         /* Logging change of status. */
     635          55 :         if (IS_DEBUG_OSPF(nsm, NSM_STATUS))
     636           0 :                 zlog_debug("NSM[%s:%pI4:%s]: State change %s -> %s (%s)",
     637             :                            IF_NAME(nbr->oi), &nbr->router_id,
     638             :                            ospf_get_name(nbr->oi->ospf),
     639             :                            lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
     640             :                            lookup_msg(ospf_nsm_state_msg, next_state, NULL),
     641             :                            ospf_nsm_event_str[event]);
     642             : 
     643             :         /* Optionally notify about adjacency changes */
     644          55 :         if (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_CHANGES)
     645           0 :             && (CHECK_FLAG(nbr->oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL)
     646           0 :                 || (next_state == NSM_Full) || (next_state < nbr->state)))
     647           0 :                 zlog_notice("AdjChg: Nbr %pI4(%s) on %s: %s -> %s (%s)",
     648             :                             &nbr->router_id,
     649             :                             ospf_get_name(nbr->oi->ospf), IF_NAME(nbr->oi),
     650             :                             lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
     651             :                             lookup_msg(ospf_nsm_state_msg, next_state, NULL),
     652             :                             ospf_nsm_event_str[event]);
     653             : 
     654             :         /* Advance in NSM */
     655          55 :         if (next_state > nbr->state)
     656          47 :                 monotime(&nbr->ts_last_progress);
     657             :         else /* regression in NSM */
     658             :         {
     659           8 :                 monotime(&nbr->ts_last_regress);
     660           8 :                 nbr->last_regress_str = ospf_nsm_event_str[event];
     661             :         }
     662          55 : }
     663             : 
     664          55 : static void nsm_change_state(struct ospf_neighbor *nbr, int state)
     665             : {
     666          55 :         struct ospf_interface *oi = nbr->oi;
     667          55 :         struct ospf_area *vl_area = NULL;
     668          55 :         uint8_t old_state;
     669             : 
     670             :         /* Preserve old status. */
     671          55 :         old_state = nbr->state;
     672             : 
     673             :         /* Change to new status. */
     674          55 :         nbr->state = state;
     675             : 
     676             :         /* Statistics. */
     677          55 :         nbr->state_change++;
     678             : 
     679          55 :         if (oi->type == OSPF_IFTYPE_VIRTUALLINK)
     680           0 :                 vl_area = ospf_area_lookup_by_area_id(oi->ospf,
     681           0 :                                                       oi->vl_data->vl_area_id);
     682             : 
     683             :         /* Generate NeighborChange ISM event.
     684             :          *
     685             :          * In response to NeighborChange, DR election is rerun. The information
     686             :          * from the election process is required by the router-lsa construction.
     687             :          *
     688             :          * Therefore, trigger the event prior to refreshing the LSAs. */
     689          55 :         switch (oi->state) {
     690          39 :         case ISM_DROther:
     691             :         case ISM_Backup:
     692             :         case ISM_DR:
     693          39 :                 if ((old_state < NSM_TwoWay && state >= NSM_TwoWay)
     694          39 :                     || (old_state >= NSM_TwoWay && state < NSM_TwoWay))
     695           8 :                         OSPF_ISM_EVENT_EXECUTE(oi, ISM_NeighborChange);
     696             :                 break;
     697             :         default:
     698             :                 /* ISM_PointToPoint -> ISM_Down, ISM_Loopback -> ISM_Down, etc.
     699             :                  */
     700             :                 break;
     701             :         }
     702             : 
     703             :         /* One of the neighboring routers changes to/from the FULL state. */
     704          55 :         if ((old_state != NSM_Full && state == NSM_Full)
     705          55 :             || (old_state == NSM_Full && state != NSM_Full)) {
     706          16 :                 if (state == NSM_Full) {
     707           8 :                         oi->full_nbrs++;
     708           8 :                         oi->area->full_nbrs++;
     709             : 
     710           8 :                         ospf_check_abr_status(oi->ospf);
     711             : 
     712           8 :                         if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
     713           0 :                                 if (++vl_area->full_vls == 1)
     714           0 :                                         ospf_schedule_abr_task(oi->ospf);
     715             :                 } else {
     716           8 :                         oi->full_nbrs--;
     717           8 :                         oi->area->full_nbrs--;
     718             : 
     719           8 :                         ospf_check_abr_status(oi->ospf);
     720             : 
     721           8 :                         if (oi->type == OSPF_IFTYPE_VIRTUALLINK && vl_area)
     722           0 :                                 if (vl_area->full_vls > 0)
     723           0 :                                         if (--vl_area->full_vls == 0)
     724           0 :                                                 ospf_schedule_abr_task(
     725             :                                                         oi->ospf);
     726             :                 }
     727             : 
     728          16 :                 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
     729           0 :                         zlog_info(
     730             :                                 "%s:[%pI4:%s], %s -> %s): scheduling new router-LSA origination",
     731             :                                 __func__, &nbr->router_id,
     732             :                                 ospf_get_name(oi->ospf),
     733             :                                 lookup_msg(ospf_nsm_state_msg, old_state, NULL),
     734             :                                 lookup_msg(ospf_nsm_state_msg, state, NULL));
     735             : 
     736             :                 /* Dont originate router LSA if the current
     737             :                  * router is acting as a HELPER for this neighbour.
     738             :                  */
     739          16 :                 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr))
     740          16 :                         ospf_router_lsa_update_area(oi->area);
     741             : 
     742          16 :                 if (oi->type == OSPF_IFTYPE_VIRTUALLINK) {
     743           0 :                         vl_area = ospf_area_lookup_by_area_id(
     744           0 :                                 oi->ospf, oi->vl_data->vl_area_id);
     745             : 
     746           0 :                         if (vl_area)
     747           0 :                                 ospf_router_lsa_update_area(vl_area);
     748             :                 }
     749             : 
     750             :                 /* Dont originate/flush network LSA if the current
     751             :                  * router is acting as a HELPER for this neighbour.
     752             :                  */
     753          16 :                 if (!OSPF_GR_IS_ACTIVE_HELPER(nbr)) {
     754             :                         /* Originate network-LSA. */
     755          16 :                         if (oi->state == ISM_DR) {
     756          10 :                                 if (oi->network_lsa_self
     757           6 :                                     && oi->full_nbrs == 0) {
     758           3 :                                         ospf_lsa_flush_area(
     759             :                                                 oi->network_lsa_self, oi->area);
     760           3 :                                         ospf_lsa_unlock(&oi->network_lsa_self);
     761           3 :                                         oi->network_lsa_self = NULL;
     762             :                                 } else
     763           7 :                                         ospf_network_lsa_update(oi);
     764             :                         }
     765             :                 }
     766             : 
     767          16 :                 if (state == NSM_Full && oi->ospf->gr_info.restart_in_progress)
     768           0 :                         ospf_gr_check_adjs(oi->ospf);
     769             :         }
     770             : 
     771          55 :         ospf_opaque_nsm_change(nbr, old_state);
     772             : 
     773             :         /* State changes from > ExStart to <= ExStart should clear any Exchange
     774             :          * or Full/LSA Update related lists and state.
     775             :          * Potential causal events: BadLSReq, SeqNumberMismatch, AdjOK?
     776             :          */
     777          55 :         if ((old_state > NSM_ExStart) && (state <= NSM_ExStart))
     778           8 :                 nsm_clear_adj(nbr);
     779             : 
     780             :         /* Start DD exchange protocol */
     781          55 :         if (state == NSM_ExStart) {
     782           8 :                 if (nbr->dd_seqnum == 0)
     783           8 :                         nbr->dd_seqnum = (uint32_t)frr_weak_random();
     784             :                 else
     785           0 :                         nbr->dd_seqnum++;
     786             : 
     787           8 :                 nbr->dd_flags =
     788             :                         OSPF_DD_FLAG_I | OSPF_DD_FLAG_M | OSPF_DD_FLAG_MS;
     789           8 :                 if (CHECK_FLAG(oi->ospf->config, OSPF_LOG_ADJACENCY_DETAIL))
     790           0 :                         zlog_info(
     791             :                                 "%s: Initializing [DD]: %pI4 with seqnum:%x , flags:%x",
     792             :                                 ospf_get_name(oi->ospf), &nbr->router_id,
     793             :                                 nbr->dd_seqnum, nbr->dd_flags);
     794           8 :                 ospf_db_desc_send(nbr);
     795             :         }
     796             : 
     797             :         /* clear cryptographic sequence number */
     798          55 :         if (state == NSM_Down)
     799           0 :                 nbr->crypt_seqnum = 0;
     800             : 
     801          55 :         if (nbr->bfd_session)
     802           0 :                 ospf_bfd_trigger_event(nbr, old_state, state);
     803             : 
     804             :         /* Preserve old status? */
     805          55 : }
     806             : 
     807             : /* Execute NSM event process. */
     808         206 : void ospf_nsm_event(struct thread *thread)
     809             : {
     810         206 :         int event;
     811         206 :         int next_state;
     812         206 :         struct ospf_neighbor *nbr;
     813             : 
     814         206 :         nbr = THREAD_ARG(thread);
     815         206 :         event = THREAD_VAL(thread);
     816             : 
     817         206 :         if (IS_DEBUG_OSPF(nsm, NSM_EVENTS))
     818           0 :                 zlog_debug("NSM[%s:%pI4:%s]: %s (%s)", IF_NAME(nbr->oi),
     819             :                            &nbr->router_id,
     820             :                            ospf_get_name(nbr->oi->ospf),
     821             :                            lookup_msg(ospf_nsm_state_msg, nbr->state, NULL),
     822             :                            ospf_nsm_event_str[event]);
     823             : 
     824         206 :         next_state = NSM[nbr->state][event].next_state;
     825             : 
     826             :         /* Call function. */
     827         206 :         if (NSM[nbr->state][event].func != NULL) {
     828         127 :                 int func_state = (*(NSM[nbr->state][event].func))(nbr);
     829             : 
     830         127 :                 if (NSM[nbr->state][event].next_state == NSM_DependUpon)
     831             :                         next_state = func_state;
     832          95 :                 else if (func_state) {
     833             :                         /* There's a mismatch between the FSM tables and what an
     834             :                          * FSM
     835             :                          * action/state-change function returned. State changes
     836             :                          * which
     837             :                          * do not have conditional/DependUpon next-states should
     838             :                          * not
     839             :                          * try set next_state.
     840             :                          */
     841           0 :                         flog_err(
     842             :                                 EC_OSPF_FSM_INVALID_STATE,
     843             :                                 "NSM[%s:%pI4:%s]: %s (%s): Warning: action tried to change next_state to %s",
     844             :                                 IF_NAME(nbr->oi), &nbr->router_id,
     845             :                                 ospf_get_name(nbr->oi->ospf),
     846             :                                 lookup_msg(ospf_nsm_state_msg, nbr->state,
     847             :                                            NULL),
     848             :                                 ospf_nsm_event_str[event],
     849             :                                 lookup_msg(ospf_nsm_state_msg, func_state,
     850             :                                            NULL));
     851             :                 }
     852             :         }
     853             : 
     854         206 :         assert(next_state != NSM_DependUpon);
     855             : 
     856             :         /* If state is changed. */
     857         206 :         if (next_state != nbr->state) {
     858          55 :                 int old_state = nbr->state;
     859             : 
     860          55 :                 nsm_notice_state_change(nbr, next_state, event);
     861          55 :                 nsm_change_state(nbr, next_state);
     862             : 
     863          55 :                 hook_call(ospf_nsm_change, nbr, next_state, old_state);
     864             :         }
     865             : 
     866             :         /* Make sure timer is set. */
     867         206 :         nsm_timer_set(nbr);
     868             : 
     869             :         /* When event is NSM_KillNbr, InactivityTimer or LLDown, the neighbor
     870             :          * is deleted.
     871             :          *
     872             :          * Rather than encode knowledge here of which events lead to NBR
     873             :          * delete, we take our cue from the NSM table, via the dummy
     874             :          * 'Deleted' neighbour state.
     875             :          */
     876         206 :         if (nbr->state == NSM_Deleted)
     877           8 :                 ospf_nbr_delete(nbr);
     878         206 : }
     879             : 
     880             : /* Check loading state. */
     881          20 : void ospf_check_nbr_loading(struct ospf_neighbor *nbr)
     882             : {
     883          20 :         if (nbr->state == NSM_Loading) {
     884          18 :                 if (ospf_ls_request_isempty(nbr))
     885           7 :                         OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_LoadingDone);
     886          11 :                 else if (nbr->ls_req_last == NULL)
     887           0 :                         ospf_ls_req_event(nbr);
     888             :         }
     889          20 : }

Generated by: LCOV version v1.16-topotato