back to topotato report
topotato coverage report
Current view: top level - ospfd - ospf_neighbor.c (source / functions) Hit Total Coverage
Test: test_ospf_topo1.py::OSPFTopo1Test Lines: 154 239 64.4 %
Date: 2023-02-24 18:38:32 Functions: 11 14 78.6 %

          Line data    Source code
       1             : /*
       2             :  * OSPF Neighbor functions.
       3             :  * Copyright (C) 1999, 2000 Toshiaki Takada
       4             :  *
       5             :  * This file is part of GNU Zebra.
       6             :  *
       7             :  * GNU Zebra is free software; you can redistribute it and/or modify
       8             :  * it under the terms of the GNU General Public License as published
       9             :  * by the Free Software Foundation; either version 2, or (at your
      10             :  * option) any later version.
      11             :  *
      12             :  * GNU Zebra is distributed in the hope that it will be useful, but
      13             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      14             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      15             :  * General Public License for more details.
      16             :  *
      17             :  * You should have received a copy of the GNU General Public License along
      18             :  * with this program; see the file COPYING; if not, write to the Free Software
      19             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      20             :  */
      21             : 
      22             : #include <zebra.h>
      23             : 
      24             : #include "lib/bfd.h"
      25             : #include "linklist.h"
      26             : #include "prefix.h"
      27             : #include "memory.h"
      28             : #include "command.h"
      29             : #include "thread.h"
      30             : #include "stream.h"
      31             : #include "table.h"
      32             : #include "log.h"
      33             : #include "json.h"
      34             : 
      35             : #include "ospfd/ospfd.h"
      36             : #include "ospfd/ospf_interface.h"
      37             : #include "ospfd/ospf_asbr.h"
      38             : #include "ospfd/ospf_lsa.h"
      39             : #include "ospfd/ospf_lsdb.h"
      40             : #include "ospfd/ospf_neighbor.h"
      41             : #include "ospfd/ospf_nsm.h"
      42             : #include "ospfd/ospf_packet.h"
      43             : #include "ospfd/ospf_network.h"
      44             : #include "ospfd/ospf_flood.h"
      45             : #include "ospfd/ospf_dump.h"
      46             : #include "ospfd/ospf_bfd.h"
      47             : #include "ospfd/ospf_gr.h"
      48             : 
      49             : /* Fill in the the 'key' as appropriate to retrieve the entry for nbr
      50             :  * from the ospf_interface's nbrs table. Indexed by interface address
      51             :  * for all cases except Virtual-link and PointToPoint interfaces, where
      52             :  * neighbours are indexed by router-ID instead.
      53             :  */
      54         100 : static void ospf_nbr_key(struct ospf_interface *oi, struct ospf_neighbor *nbr,
      55             :                          struct prefix *key)
      56             : {
      57         100 :         key->family = AF_INET;
      58         100 :         key->prefixlen = IPV4_MAX_BITLEN;
      59             : 
      60             :         /* vlinks are indexed by router-id */
      61         100 :         if (oi->type == OSPF_IFTYPE_VIRTUALLINK
      62         100 :             || oi->type == OSPF_IFTYPE_POINTOPOINT)
      63           0 :                 key->u.prefix4 = nbr->router_id;
      64             :         else
      65         100 :                 key->u.prefix4 = nbr->src;
      66         100 :         return;
      67             : }
      68             : 
      69          54 : struct ospf_neighbor *ospf_nbr_new(struct ospf_interface *oi)
      70             : {
      71          54 :         struct ospf_neighbor *nbr;
      72             : 
      73             :         /* Allcate new neighbor. */
      74          54 :         nbr = XCALLOC(MTYPE_OSPF_NEIGHBOR, sizeof(struct ospf_neighbor));
      75             : 
      76             :         /* Relate neighbor to the interface. */
      77          54 :         nbr->oi = oi;
      78             : 
      79             :         /* Set default values. */
      80          54 :         nbr->state = NSM_Down;
      81             : 
      82             :         /* Set inheritance values. */
      83          54 :         nbr->v_inactivity = OSPF_IF_PARAM(oi, v_wait);
      84          54 :         nbr->v_db_desc = OSPF_IF_PARAM(oi, retransmit_interval);
      85          54 :         nbr->v_ls_req = OSPF_IF_PARAM(oi, retransmit_interval);
      86          54 :         nbr->v_ls_upd = OSPF_IF_PARAM(oi, retransmit_interval);
      87          54 :         nbr->priority = -1;
      88             : 
      89             :         /* DD flags. */
      90          54 :         nbr->dd_flags = OSPF_DD_FLAG_MS | OSPF_DD_FLAG_M | OSPF_DD_FLAG_I;
      91             : 
      92             :         /* Last received and sent DD. */
      93          54 :         nbr->last_send = NULL;
      94             : 
      95          54 :         nbr->nbr_nbma = NULL;
      96             : 
      97          54 :         ospf_lsdb_init(&nbr->db_sum);
      98          54 :         ospf_lsdb_init(&nbr->ls_rxmt);
      99          54 :         ospf_lsdb_init(&nbr->ls_req);
     100             : 
     101          54 :         nbr->crypt_seqnum = 0;
     102             : 
     103             :         /* Initialize GR Helper info*/
     104          54 :         nbr->gr_helper_info.recvd_grace_period = 0;
     105          54 :         nbr->gr_helper_info.actual_grace_period = 0;
     106          54 :         nbr->gr_helper_info.gr_helper_status = OSPF_GR_NOT_HELPER;
     107          54 :         nbr->gr_helper_info.helper_exit_reason = OSPF_GR_HELPER_EXIT_NONE;
     108          54 :         nbr->gr_helper_info.gr_restart_reason = OSPF_GR_UNKNOWN_RESTART;
     109             : 
     110          54 :         return nbr;
     111             : }
     112             : 
     113          54 : void ospf_nbr_free(struct ospf_neighbor *nbr)
     114             : {
     115             :         /* Free DB summary list. */
     116          54 :         if (ospf_db_summary_count(nbr))
     117           0 :                 ospf_db_summary_clear(nbr);
     118             :         /* ospf_db_summary_delete_all (nbr); */
     119             : 
     120             :         /* Free ls request list. */
     121          54 :         if (ospf_ls_request_count(nbr))
     122           0 :                 ospf_ls_request_delete_all(nbr);
     123             : 
     124             :         /* Free retransmit list. */
     125          54 :         if (ospf_ls_retransmit_count(nbr))
     126           0 :                 ospf_ls_retransmit_clear(nbr);
     127             : 
     128             :         /* Cleanup LSDBs. */
     129          54 :         ospf_lsdb_cleanup(&nbr->db_sum);
     130          54 :         ospf_lsdb_cleanup(&nbr->ls_req);
     131          54 :         ospf_lsdb_cleanup(&nbr->ls_rxmt);
     132             : 
     133             :         /* Clear last send packet. */
     134          54 :         if (nbr->last_send)
     135           8 :                 ospf_packet_free(nbr->last_send);
     136             : 
     137          54 :         if (nbr->nbr_nbma) {
     138           0 :                 nbr->nbr_nbma->nbr = NULL;
     139           0 :                 nbr->nbr_nbma = NULL;
     140             :         }
     141             : 
     142             :         /* Cancel all timers. */
     143          54 :         THREAD_OFF(nbr->t_inactivity);
     144          54 :         THREAD_OFF(nbr->t_db_desc);
     145          54 :         THREAD_OFF(nbr->t_ls_req);
     146          54 :         THREAD_OFF(nbr->t_ls_upd);
     147             : 
     148             :         /* Cancel all events. */ /* Thread lookup cost would be negligible. */
     149          54 :         thread_cancel_event(master, nbr);
     150             : 
     151          54 :         bfd_sess_free(&nbr->bfd_session);
     152             : 
     153          54 :         THREAD_OFF(nbr->gr_helper_info.t_grace_timer);
     154             : 
     155          54 :         nbr->oi = NULL;
     156          54 :         XFREE(MTYPE_OSPF_NEIGHBOR, nbr);
     157          54 : }
     158             : 
     159             : /* Delete specified OSPF neighbor from interface. */
     160          54 : void ospf_nbr_delete(struct ospf_neighbor *nbr)
     161             : {
     162          54 :         struct ospf_interface *oi;
     163          54 :         struct route_node *rn;
     164          54 :         struct prefix p;
     165             : 
     166          54 :         oi = nbr->oi;
     167             : 
     168             :         /* get appropriate prefix 'key' */
     169          54 :         ospf_nbr_key(oi, nbr, &p);
     170             : 
     171          54 :         rn = route_node_lookup(oi->nbrs, &p);
     172          54 :         if (rn) {
     173             :                 /* If lookup for a NBR succeeds, the leaf route_node could
     174             :                  * only exist because there is (or was) a nbr there.
     175             :                  * If the nbr was deleted, the leaf route_node should have
     176             :                  * lost its last refcount too, and be deleted.
     177             :                  * Therefore a looked-up leaf route_node in nbrs table
     178             :                  * should never have NULL info.
     179             :                  */
     180          54 :                 assert(rn->info);
     181             : 
     182          54 :                 if (rn->info) {
     183          54 :                         rn->info = NULL;
     184          54 :                         route_unlock_node(rn);
     185             :                 } else
     186           0 :                         zlog_info("Can't find neighbor %pI4 in the interface %s",
     187             :                                   &nbr->src, IF_NAME(oi));
     188             : 
     189          54 :                 route_unlock_node(rn);
     190             :         } else {
     191             :                 /*
     192             :                  * This neighbor was not found, but before we move on and
     193             :                  * free the neighbor structre, make sure that it was not
     194             :                  * indexed incorrectly and ended up in the "worng" place
     195             :                  */
     196             : 
     197             :                 /* Reverse the lookup rules */
     198           0 :                 if (oi->type == OSPF_IFTYPE_VIRTUALLINK
     199           0 :                     || oi->type == OSPF_IFTYPE_POINTOPOINT)
     200           0 :                         p.u.prefix4 = nbr->src;
     201             :                 else
     202           0 :                         p.u.prefix4 = nbr->router_id;
     203             : 
     204           0 :                 rn = route_node_lookup(oi->nbrs, &p);
     205           0 :                 if (rn) {
     206             :                         /* We found the neighbor!
     207             :                          * Now make sure it is not the exact same neighbor
     208             :                          * structure that we are about to free
     209             :                          */
     210           0 :                         if (nbr == rn->info) {
     211             :                                 /* Same neighbor, drop the reference to it */
     212           0 :                                 rn->info = NULL;
     213           0 :                                 route_unlock_node(rn);
     214             :                         }
     215           0 :                         route_unlock_node(rn);
     216             :                 }
     217             :         }
     218             : 
     219             :         /* Free ospf_neighbor structure. */
     220          54 :         ospf_nbr_free(nbr);
     221          54 : }
     222             : 
     223             : /* Check myself is in the neighbor list. */
     224          94 : int ospf_nbr_bidirectional(struct in_addr *router_id, struct in_addr *neighbors,
     225             :                            int size)
     226             : {
     227          94 :         int i;
     228          94 :         int max;
     229             : 
     230          94 :         max = size / sizeof(struct in_addr);
     231             : 
     232         120 :         for (i = 0; i < max; i++)
     233         116 :                 if (IPV4_ADDR_SAME(router_id, &neighbors[i]))
     234             :                         return 1;
     235             : 
     236             :         return 0;
     237             : }
     238             : 
     239             : /* reset nbr_self */
     240          46 : void ospf_nbr_self_reset(struct ospf_interface *oi, struct in_addr router_id)
     241             : {
     242          46 :         if (oi->nbr_self)
     243          28 :                 ospf_nbr_delete(oi->nbr_self);
     244             : 
     245          46 :         oi->nbr_self = ospf_nbr_new(oi);
     246          46 :         ospf_nbr_add_self(oi, router_id);
     247          46 : }
     248             : 
     249             : /* Add self to nbr list. */
     250          46 : void ospf_nbr_add_self(struct ospf_interface *oi, struct in_addr router_id)
     251             : {
     252          46 :         struct prefix p;
     253          46 :         struct route_node *rn;
     254             : 
     255          46 :         if (!oi->nbr_self)
     256           0 :                 oi->nbr_self = ospf_nbr_new(oi);
     257             : 
     258             :         /* Initial state */
     259          46 :         oi->nbr_self->address = *oi->address;
     260          46 :         oi->nbr_self->priority = OSPF_IF_PARAM(oi, priority);
     261          46 :         oi->nbr_self->router_id = router_id;
     262          46 :         oi->nbr_self->src = oi->address->u.prefix4;
     263          46 :         oi->nbr_self->state = NSM_TwoWay;
     264             : 
     265          46 :         switch (oi->area->external_routing) {
     266          46 :         case OSPF_AREA_DEFAULT:
     267          46 :                 SET_FLAG(oi->nbr_self->options, OSPF_OPTION_E);
     268          46 :                 break;
     269           0 :         case OSPF_AREA_STUB:
     270           0 :                 UNSET_FLAG(oi->nbr_self->options, OSPF_OPTION_E);
     271           0 :                 break;
     272           0 :         case OSPF_AREA_NSSA:
     273           0 :                 UNSET_FLAG(oi->nbr_self->options, OSPF_OPTION_E);
     274           0 :                 SET_FLAG(oi->nbr_self->options, OSPF_OPTION_NP);
     275           0 :                 break;
     276             :         }
     277             : 
     278             :         /* Add nbr_self to nbrs table */
     279          46 :         ospf_nbr_key(oi, oi->nbr_self, &p);
     280             : 
     281          46 :         rn = route_node_get(oi->nbrs, &p);
     282          46 :         if (rn->info) {
     283             :                 /* There is already pseudo neighbor. */
     284           0 :                 if (IS_DEBUG_OSPF_EVENT)
     285           0 :                         zlog_debug(
     286             :                                 "router_id %pI4 already present in neighbor table. node refcount %u",
     287             :                                 &router_id, route_node_get_lock_count(rn));
     288           0 :                 route_unlock_node(rn);
     289             :         } else
     290          46 :                 rn->info = oi->nbr_self;
     291          46 : }
     292             : 
     293             : /* Get neighbor count by status.
     294             :    Specify status = 0, get all neighbor other than myself. */
     295          51 : int ospf_nbr_count(struct ospf_interface *oi, int state)
     296             : {
     297          51 :         struct ospf_neighbor *nbr;
     298          51 :         struct route_node *rn;
     299          51 :         int count = 0;
     300             : 
     301         176 :         for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
     302         125 :                 if ((nbr = rn->info))
     303          88 :                         if (!IPV4_ADDR_SAME(&nbr->router_id,
     304             :                                             &oi->ospf->router_id))
     305          37 :                                 if (state == 0 || nbr->state == state)
     306          23 :                                         count++;
     307             : 
     308          51 :         return count;
     309             : }
     310             : 
     311           0 : int ospf_nbr_count_opaque_capable(struct ospf_interface *oi)
     312             : {
     313           0 :         struct ospf_neighbor *nbr;
     314           0 :         struct route_node *rn;
     315           0 :         int count = 0;
     316             : 
     317           0 :         for (rn = route_top(oi->nbrs); rn; rn = route_next(rn))
     318           0 :                 if ((nbr = rn->info))
     319           0 :                         if (!IPV4_ADDR_SAME(&nbr->router_id,
     320             :                                             &oi->ospf->router_id))
     321           0 :                                 if (nbr->state == NSM_Full)
     322           0 :                                         if (CHECK_FLAG(nbr->options,
     323             :                                                        OSPF_OPTION_O))
     324           0 :                                                 count++;
     325             : 
     326           0 :         return count;
     327             : }
     328             : 
     329             : /* lookup nbr by address - use this only if you know you must
     330             :  * otherwise use the ospf_nbr_lookup() wrapper, which deals
     331             :  * with virtual link and PointToPoint neighbours
     332             :  */
     333         166 : struct ospf_neighbor *ospf_nbr_lookup_by_addr(struct route_table *nbrs,
     334             :                                               struct in_addr *addr)
     335             : {
     336         166 :         struct prefix p;
     337         166 :         struct route_node *rn;
     338         166 :         struct ospf_neighbor *nbr;
     339             : 
     340         166 :         p.family = AF_INET;
     341         166 :         p.prefixlen = IPV4_MAX_BITLEN;
     342         166 :         p.u.prefix4 = *addr;
     343             : 
     344         166 :         rn = route_node_lookup(nbrs, &p);
     345         166 :         if (!rn)
     346             :                 return NULL;
     347             : 
     348             :         /* See comment in ospf_nbr_delete */
     349         166 :         assert(rn->info);
     350             : 
     351         166 :         if (rn->info == NULL) {
     352           0 :                 route_unlock_node(rn);
     353           0 :                 return NULL;
     354             :         }
     355             : 
     356         166 :         nbr = (struct ospf_neighbor *)rn->info;
     357         166 :         route_unlock_node(rn);
     358             : 
     359         166 :         return nbr;
     360             : }
     361             : 
     362           0 : struct ospf_neighbor *ospf_nbr_lookup_by_routerid(struct route_table *nbrs,
     363             :                                                   struct in_addr *id)
     364             : {
     365           0 :         struct route_node *rn;
     366           0 :         struct ospf_neighbor *nbr;
     367             : 
     368           0 :         for (rn = route_top(nbrs); rn; rn = route_next(rn))
     369           0 :                 if ((nbr = rn->info) != NULL)
     370           0 :                         if (IPV4_ADDR_SAME(&nbr->router_id, id)) {
     371           0 :                                 route_unlock_node(rn);
     372           0 :                                 return nbr;
     373             :                         }
     374             : 
     375             :         return NULL;
     376             : }
     377             : 
     378           0 : void ospf_renegotiate_optional_capabilities(struct ospf *top)
     379             : {
     380           0 :         struct listnode *node;
     381           0 :         struct ospf_interface *oi;
     382           0 :         struct route_table *nbrs;
     383           0 :         struct route_node *rn;
     384           0 :         struct ospf_neighbor *nbr;
     385           0 :         uint8_t shutdown_save = top->inst_shutdown;
     386             : 
     387             :         /* At first, flush self-originated LSAs from routing domain. */
     388           0 :         ospf_flush_self_originated_lsas_now(top);
     389             : 
     390             :         /* ospf_flush_self_originated_lsas_now is primarily intended for shut
     391             :          * down scenarios. Reset the inst_shutdown flag that it sets. We are
     392             :          * just changing configuration, and the flag can change the scheduling
     393             :          * of when maxage LSAs are sent. */
     394           0 :         top->inst_shutdown = shutdown_save;
     395             : 
     396             :         /* Revert all neighbor status to ExStart. */
     397           0 :         for (ALL_LIST_ELEMENTS_RO(top->oiflist, node, oi)) {
     398           0 :                 if ((nbrs = oi->nbrs) == NULL)
     399           0 :                         continue;
     400             : 
     401           0 :                 for (rn = route_top(nbrs); rn; rn = route_next(rn)) {
     402           0 :                         if ((nbr = rn->info) == NULL || nbr == oi->nbr_self)
     403           0 :                                 continue;
     404             : 
     405           0 :                         if (nbr->state < NSM_ExStart)
     406           0 :                                 continue;
     407             : 
     408           0 :                         if (IS_DEBUG_OSPF_EVENT)
     409           0 :                                 zlog_debug(
     410             :                                         "Renegotiate optional capabilities with neighbor(%pI4)",
     411             :                                         &nbr->router_id);
     412             : 
     413           0 :                         OSPF_NSM_EVENT_SCHEDULE(nbr, NSM_SeqNumberMismatch);
     414             :                 }
     415             :         }
     416             : 
     417             :         /* Refresh/Re-originate external LSAs (Type-7 and Type-5).*/
     418           0 :         ospf_external_lsa_rid_change(top);
     419             : 
     420           0 :         return;
     421             : }
     422             : 
     423             : 
     424         109 : struct ospf_neighbor *ospf_nbr_lookup(struct ospf_interface *oi, struct ip *iph,
     425             :                                       struct ospf_header *ospfh)
     426             : {
     427         109 :         struct in_addr srcaddr = iph->ip_src;
     428             : 
     429         109 :         if (oi->type == OSPF_IFTYPE_VIRTUALLINK
     430         109 :             || oi->type == OSPF_IFTYPE_POINTOPOINT)
     431           0 :                 return (ospf_nbr_lookup_by_routerid(oi->nbrs,
     432             :                                                     &ospfh->router_id));
     433             :         else
     434         109 :                 return (ospf_nbr_lookup_by_addr(oi->nbrs, &srcaddr));
     435             : }
     436             : 
     437           8 : static struct ospf_neighbor *ospf_nbr_add(struct ospf_interface *oi,
     438             :                                           struct ospf_header *ospfh,
     439             :                                           struct prefix *p)
     440             : {
     441           8 :         struct ospf_neighbor *nbr;
     442             : 
     443           8 :         nbr = ospf_nbr_new(oi);
     444           8 :         nbr->state = NSM_Down;
     445           8 :         nbr->src = p->u.prefix4;
     446           8 :         memcpy(&nbr->address, p, sizeof(struct prefix));
     447             : 
     448           8 :         nbr->nbr_nbma = NULL;
     449           8 :         if (oi->type == OSPF_IFTYPE_NBMA) {
     450           0 :                 struct ospf_nbr_nbma *nbr_nbma;
     451           0 :                 struct listnode *node;
     452             : 
     453           0 :                 for (ALL_LIST_ELEMENTS_RO(oi->nbr_nbma, node, nbr_nbma)) {
     454           0 :                         if (IPV4_ADDR_SAME(&nbr_nbma->addr, &nbr->src)) {
     455           0 :                                 nbr_nbma->nbr = nbr;
     456           0 :                                 nbr->nbr_nbma = nbr_nbma;
     457             : 
     458           0 :                                 if (nbr_nbma->t_poll)
     459           0 :                                         THREAD_OFF(nbr_nbma->t_poll);
     460             : 
     461           0 :                                 nbr->state_change = nbr_nbma->state_change + 1;
     462             :                         }
     463             :                 }
     464             :         }
     465             : 
     466             :         /* New nbr, save the crypto sequence number if necessary */
     467           8 :         if (ntohs(ospfh->auth_type) == OSPF_AUTH_CRYPTOGRAPHIC)
     468           0 :                 nbr->crypt_seqnum = ospfh->u.crypt.crypt_seqnum;
     469             : 
     470             :         /* Configure BFD if interface has it. */
     471           8 :         ospf_neighbor_bfd_apply(nbr);
     472             : 
     473           8 :         if (IS_DEBUG_OSPF_EVENT)
     474           8 :                 zlog_debug("NSM[%s:%pI4]: start", IF_NAME(oi),
     475             :                            &nbr->router_id);
     476             : 
     477           8 :         return nbr;
     478             : }
     479             : 
     480          94 : struct ospf_neighbor *ospf_nbr_get(struct ospf_interface *oi,
     481             :                                    struct ospf_header *ospfh, struct ip *iph,
     482             :                                    struct prefix *p)
     483             : {
     484          94 :         struct route_node *rn;
     485          94 :         struct prefix key;
     486          94 :         struct ospf_neighbor *nbr;
     487             : 
     488          94 :         key.family = AF_INET;
     489          94 :         key.prefixlen = IPV4_MAX_BITLEN;
     490             : 
     491          94 :         if (oi->type == OSPF_IFTYPE_VIRTUALLINK
     492          94 :             || oi->type == OSPF_IFTYPE_POINTOPOINT)
     493           0 :                 key.u.prefix4 = ospfh->router_id; /* index vlink and ptp nbrs by
     494             :                                                      router-id */
     495             :         else
     496          94 :                 key.u.prefix4 = iph->ip_src;
     497             : 
     498          94 :         rn = route_node_get(oi->nbrs, &key);
     499          94 :         if (rn->info) {
     500          86 :                 route_unlock_node(rn);
     501          86 :                 nbr = rn->info;
     502             : 
     503          86 :                 if (oi->type == OSPF_IFTYPE_NBMA && nbr->state == NSM_Attempt) {
     504           0 :                         nbr->src = iph->ip_src;
     505           0 :                         memcpy(&nbr->address, p, sizeof(struct prefix));
     506             :                 }
     507             :         } else {
     508           8 :                 rn->info = nbr = ospf_nbr_add(oi, ospfh, p);
     509             :         }
     510             : 
     511          94 :         nbr->router_id = ospfh->router_id;
     512             : 
     513          94 :         return nbr;
     514             : }

Generated by: LCOV version v1.16-topotato