back to topotato report
topotato coverage report
Current view: top level - pimd - pim_neighbor.c (source / functions) Hit Total Coverage
Test: test_pim_cbsr.py::PIMCandidateBSRTest Lines: 238 316 75.3 %
Date: 2023-02-16 02:09:14 Functions: 16 21 76.2 %

          Line data    Source code
       1             : /*
       2             :  * PIM for Quagga
       3             :  * Copyright (C) 2008  Everton da Silva Marques
       4             :  *
       5             :  * This program is free software; you can redistribute it and/or modify
       6             :  * it under the terms of the GNU General Public License as published by
       7             :  * the Free Software Foundation; either version 2 of the License, or
       8             :  * (at your option) any later version.
       9             :  *
      10             :  * This program is distributed in the hope that it will be useful, but
      11             :  * WITHOUT ANY WARRANTY; without even the implied warranty of
      12             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      13             :  * General Public License for more details.
      14             :  *
      15             :  * You should have received a copy of the GNU General Public License along
      16             :  * with this program; see the file COPYING; if not, write to the Free Software
      17             :  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
      18             :  */
      19             : 
      20             : #include <zebra.h>
      21             : 
      22             : #include "log.h"
      23             : #include "prefix.h"
      24             : #include "memory.h"
      25             : #include "if.h"
      26             : #include "vty.h"
      27             : #include "plist.h"
      28             : #include "lib_errors.h"
      29             : 
      30             : #include "pimd.h"
      31             : #include "pim_instance.h"
      32             : #include "pim_neighbor.h"
      33             : #include "pim_time.h"
      34             : #include "pim_str.h"
      35             : #include "pim_iface.h"
      36             : #include "pim_pim.h"
      37             : #include "pim_upstream.h"
      38             : #include "pim_ifchannel.h"
      39             : #include "pim_rp.h"
      40             : #include "pim_zebra.h"
      41             : #include "pim_join.h"
      42             : #include "pim_jp_agg.h"
      43             : #include "pim_bfd.h"
      44             : #include "pim_register.h"
      45             : 
      46           0 : static void dr_election_by_addr(struct interface *ifp)
      47             : {
      48           0 :         struct pim_interface *pim_ifp;
      49           0 :         struct listnode *node;
      50           0 :         struct pim_neighbor *neigh;
      51             : 
      52           0 :         pim_ifp = ifp->info;
      53           0 :         assert(pim_ifp);
      54             : 
      55           0 :         pim_ifp->pim_dr_addr = pim_ifp->primary_address;
      56             : 
      57           0 :         if (PIM_DEBUG_PIM_TRACE) {
      58           0 :                 zlog_debug("%s: on interface %s", __func__, ifp->name);
      59             :         }
      60             : 
      61           0 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
      62           0 :                 if (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) > 0)
      63           0 :                         pim_ifp->pim_dr_addr = neigh->source_addr;
      64             :         }
      65           0 : }
      66             : 
      67          21 : static void dr_election_by_pri(struct interface *ifp)
      68             : {
      69          21 :         struct pim_interface *pim_ifp;
      70          21 :         struct listnode *node;
      71          21 :         struct pim_neighbor *neigh;
      72          21 :         uint32_t dr_pri;
      73             : 
      74          21 :         pim_ifp = ifp->info;
      75          21 :         assert(pim_ifp);
      76             : 
      77          21 :         pim_ifp->pim_dr_addr = pim_ifp->primary_address;
      78          21 :         dr_pri = pim_ifp->pim_dr_priority;
      79             : 
      80          21 :         if (PIM_DEBUG_PIM_TRACE) {
      81           0 :                 zlog_debug("%s: dr pri %u on interface %s", __func__, dr_pri,
      82             :                            ifp->name);
      83             :         }
      84             : 
      85          53 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
      86          11 :                 if (PIM_DEBUG_PIM_TRACE) {
      87           0 :                         zlog_info("%s: neigh pri %u addr %pPA if dr addr %pPA",
      88             :                                   __func__, neigh->dr_priority,
      89             :                                   &neigh->source_addr, &pim_ifp->pim_dr_addr);
      90             :                 }
      91          11 :                 if ((neigh->dr_priority > dr_pri) ||
      92          11 :                     ((neigh->dr_priority == dr_pri) &&
      93          11 :                      (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) >
      94             :                       0))) {
      95           5 :                         pim_ifp->pim_dr_addr = neigh->source_addr;
      96           5 :                         dr_pri = neigh->dr_priority;
      97             :                 }
      98             :         }
      99          21 : }
     100             : 
     101             : /*
     102             :   RFC 4601: 4.3.2.  DR Election
     103             : 
     104             :   A router's idea of the current DR on an interface can change when a
     105             :   PIM Hello message is received, when a neighbor times out, or when a
     106             :   router's own DR Priority changes.
     107             :  */
     108          21 : int pim_if_dr_election(struct interface *ifp)
     109             : {
     110          21 :         struct pim_interface *pim_ifp = ifp->info;
     111          21 :         pim_addr old_dr_addr;
     112             : 
     113          21 :         ++pim_ifp->pim_dr_election_count;
     114             : 
     115          21 :         old_dr_addr = pim_ifp->pim_dr_addr;
     116             : 
     117          21 :         if (pim_ifp->pim_dr_num_nondrpri_neighbors) {
     118           0 :                 dr_election_by_addr(ifp);
     119             :         } else {
     120          21 :                 dr_election_by_pri(ifp);
     121             :         }
     122             : 
     123             :         /* DR changed ? */
     124          21 :         if (pim_addr_cmp(old_dr_addr, pim_ifp->pim_dr_addr)) {
     125             : 
     126          14 :                 if (PIM_DEBUG_PIM_EVENTS)
     127           0 :                         zlog_debug(
     128             :                                 "%s: DR was %pPA now is %pPA on interface %s",
     129             :                                 __func__, &old_dr_addr, &pim_ifp->pim_dr_addr,
     130             :                                 ifp->name);
     131             : 
     132          28 :                 pim_ifp->pim_dr_election_last =
     133          14 :                         pim_time_monotonic_sec(); /* timestamp */
     134          14 :                 ++pim_ifp->pim_dr_election_changes;
     135          14 :                 pim_if_update_join_desired(pim_ifp);
     136          14 :                 pim_if_update_could_assert(ifp);
     137          14 :                 pim_if_update_assert_tracking_desired(ifp);
     138             : 
     139          14 :                 if (PIM_I_am_DR(pim_ifp))
     140          12 :                         pim_ifp->am_i_dr = true;
     141             :                 else {
     142           2 :                         if (pim_ifp->am_i_dr == true) {
     143           2 :                                 pim_reg_del_on_couldreg_fail(ifp);
     144           2 :                                 pim_ifp->am_i_dr = false;
     145             :                         }
     146             :                 }
     147             : 
     148          14 :                 return 1;
     149             :         }
     150             : 
     151             :         return 0;
     152             : }
     153             : 
     154          98 : static void update_dr_priority(struct pim_neighbor *neigh,
     155             :                                pim_hello_options hello_options,
     156             :                                uint32_t dr_priority)
     157             : {
     158          98 :         pim_hello_options will_set_pri; /* boolean */
     159          98 :         pim_hello_options bit_flip;     /* boolean */
     160          98 :         pim_hello_options pri_change;   /* boolean */
     161             : 
     162          98 :         will_set_pri =
     163             :                 PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY);
     164             : 
     165          98 :         bit_flip = (will_set_pri
     166          98 :                     != PIM_OPTION_IS_SET(neigh->hello_options,
     167             :                                          PIM_OPTION_MASK_DR_PRIORITY));
     168             : 
     169          98 :         if (bit_flip) {
     170           0 :                 struct pim_interface *pim_ifp = neigh->interface->info;
     171             : 
     172             :                 /* update num. of neighbors without dr_pri */
     173             : 
     174           0 :                 if (will_set_pri) {
     175           0 :                         --pim_ifp->pim_dr_num_nondrpri_neighbors;
     176             :                 } else {
     177           0 :                         ++pim_ifp->pim_dr_num_nondrpri_neighbors;
     178             :                 }
     179             :         }
     180             : 
     181          98 :         pri_change = (bit_flip || (neigh->dr_priority != dr_priority));
     182             : 
     183          98 :         if (will_set_pri) {
     184          98 :                 neigh->dr_priority = dr_priority;
     185             :         } else {
     186           0 :                 neigh->dr_priority = 0; /* cosmetic unset */
     187             :         }
     188             : 
     189          98 :         if (pri_change) {
     190             :                 /*
     191             :                   RFC 4601: 4.3.2.  DR Election
     192             : 
     193             :                   A router's idea of the current DR on an interface can change
     194             :                   when a
     195             :                   PIM Hello message is received, when a neighbor times out, or
     196             :                   when a
     197             :                   router's own DR Priority changes.
     198             :                 */
     199           0 :                 pim_if_dr_election(
     200             :                         neigh->interface); // router's own DR Priority changes
     201             :         }
     202          98 : }
     203             : 
     204           3 : static void on_neighbor_timer(struct thread *t)
     205             : {
     206           3 :         struct pim_neighbor *neigh;
     207           3 :         struct interface *ifp;
     208           3 :         char msg[100];
     209             : 
     210           3 :         neigh = THREAD_ARG(t);
     211             : 
     212           3 :         ifp = neigh->interface;
     213             : 
     214           3 :         if (PIM_DEBUG_PIM_TRACE)
     215           0 :                 zlog_debug(
     216             :                         "Expired %d sec holdtime for neighbor %pPA on interface %s",
     217             :                         neigh->holdtime, &neigh->source_addr, ifp->name);
     218             : 
     219           3 :         snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
     220           3 :         pim_neighbor_delete(ifp, neigh, msg);
     221             : 
     222             :         /*
     223             :           RFC 4601: 4.3.2.  DR Election
     224             : 
     225             :           A router's idea of the current DR on an interface can change when a
     226             :           PIM Hello message is received, when a neighbor times out, or when a
     227             :           router's own DR Priority changes.
     228             :         */
     229           3 :         pim_if_dr_election(ifp); // neighbor times out
     230           3 : }
     231             : 
     232         104 : void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
     233             : {
     234         104 :         neigh->holdtime = holdtime;
     235             : 
     236         104 :         THREAD_OFF(neigh->t_expire_timer);
     237             : 
     238             :         /*
     239             :           0xFFFF is request for no holdtime
     240             :          */
     241         104 :         if (neigh->holdtime == 0xFFFF) {
     242             :                 return;
     243             :         }
     244             : 
     245         104 :         if (PIM_DEBUG_PIM_TRACE_DETAIL)
     246           0 :                 zlog_debug("%s: starting %u sec timer for neighbor %pPA on %s",
     247             :                            __func__, neigh->holdtime, &neigh->source_addr,
     248             :                            neigh->interface->name);
     249             : 
     250         104 :         thread_add_timer(router->master, on_neighbor_timer, neigh,
     251             :                          neigh->holdtime, &neigh->t_expire_timer);
     252             : }
     253             : 
     254           0 : static void on_neighbor_jp_timer(struct thread *t)
     255             : {
     256           0 :         struct pim_neighbor *neigh = THREAD_ARG(t);
     257           0 :         struct pim_rpf rpf;
     258             : 
     259           0 :         if (PIM_DEBUG_PIM_TRACE)
     260           0 :                 zlog_debug("%s:Sending JP Agg to %pPA on %s with %d groups",
     261             :                            __func__, &neigh->source_addr,
     262             :                            neigh->interface->name,
     263             :                            neigh->upstream_jp_agg->count);
     264             : 
     265           0 :         rpf.source_nexthop.interface = neigh->interface;
     266           0 :         rpf.rpf_addr = neigh->source_addr;
     267           0 :         pim_joinprune_send(&rpf, neigh->upstream_jp_agg);
     268             : 
     269           0 :         thread_add_timer(router->master, on_neighbor_jp_timer, neigh,
     270             :                          router->t_periodic, &neigh->jp_timer);
     271           0 : }
     272             : 
     273           6 : static void pim_neighbor_start_jp_timer(struct pim_neighbor *neigh)
     274             : {
     275           6 :         THREAD_OFF(neigh->jp_timer);
     276           6 :         thread_add_timer(router->master, on_neighbor_jp_timer, neigh,
     277             :                          router->t_periodic, &neigh->jp_timer);
     278           6 : }
     279             : 
     280             : static struct pim_neighbor *
     281           6 : pim_neighbor_new(struct interface *ifp, pim_addr source_addr,
     282             :                  pim_hello_options hello_options, uint16_t holdtime,
     283             :                  uint16_t propagation_delay, uint16_t override_interval,
     284             :                  uint32_t dr_priority, uint32_t generation_id,
     285             :                  struct list *addr_list)
     286             : {
     287           6 :         struct pim_interface *pim_ifp;
     288           6 :         struct pim_neighbor *neigh;
     289             : 
     290           6 :         assert(ifp);
     291           6 :         pim_ifp = ifp->info;
     292           6 :         assert(pim_ifp);
     293             : 
     294           6 :         neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
     295             : 
     296           6 :         neigh->creation = pim_time_monotonic_sec();
     297           6 :         neigh->source_addr = source_addr;
     298           6 :         neigh->hello_options = hello_options;
     299           6 :         neigh->propagation_delay_msec = propagation_delay;
     300           6 :         neigh->override_interval_msec = override_interval;
     301           6 :         neigh->dr_priority = dr_priority;
     302           6 :         neigh->generation_id = generation_id;
     303           6 :         neigh->prefix_list = addr_list;
     304           6 :         neigh->t_expire_timer = NULL;
     305           6 :         neigh->interface = ifp;
     306             : 
     307           6 :         neigh->upstream_jp_agg = list_new();
     308           6 :         neigh->upstream_jp_agg->cmp = pim_jp_agg_group_list_cmp;
     309           6 :         neigh->upstream_jp_agg->del =
     310             :                 (void (*)(void *))pim_jp_agg_group_list_free;
     311           6 :         pim_neighbor_start_jp_timer(neigh);
     312             : 
     313           6 :         pim_neighbor_timer_reset(neigh, holdtime);
     314             :         /*
     315             :          * The pim_ifstat_hello_sent variable is used to decide if
     316             :          * we should expedite a hello out the interface.  If we
     317             :          * establish a new neighbor, we unfortunately need to
     318             :          * reset the value so that we can know to hurry up and
     319             :          * hello
     320             :          */
     321           6 :         PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags);
     322             : 
     323           6 :         if (PIM_DEBUG_PIM_EVENTS)
     324           0 :                 zlog_debug("%s: creating PIM neighbor %pPA on interface %s",
     325             :                            __func__, &source_addr, ifp->name);
     326             : 
     327           6 :         zlog_notice("PIM NEIGHBOR UP: neighbor %pPA on interface %s",
     328             :                     &source_addr, ifp->name);
     329             : 
     330           6 :         if (neigh->propagation_delay_msec
     331           6 :             > pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
     332           3 :                 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
     333             :                         neigh->propagation_delay_msec;
     334             :         }
     335           6 :         if (neigh->override_interval_msec
     336           6 :             > pim_ifp->pim_neighbors_highest_override_interval_msec) {
     337           3 :                 pim_ifp->pim_neighbors_highest_override_interval_msec =
     338             :                         neigh->override_interval_msec;
     339             :         }
     340             : 
     341           6 :         if (!PIM_OPTION_IS_SET(neigh->hello_options,
     342             :                                PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
     343             :                 /* update num. of neighbors without hello option lan_delay */
     344           0 :                 ++pim_ifp->pim_number_of_nonlandelay_neighbors;
     345             :         }
     346             : 
     347           6 :         if (!PIM_OPTION_IS_SET(neigh->hello_options,
     348             :                                PIM_OPTION_MASK_DR_PRIORITY)) {
     349             :                 /* update num. of neighbors without hello option dr_pri */
     350           0 :                 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
     351             :         }
     352             : 
     353             :         // Register PIM Neighbor with BFD
     354           6 :         pim_bfd_info_nbr_create(pim_ifp, neigh);
     355             : 
     356           6 :         return neigh;
     357             : }
     358             : 
     359         104 : static void delete_prefix_list(struct pim_neighbor *neigh)
     360             : {
     361         104 :         if (neigh->prefix_list) {
     362             : 
     363             : #ifdef DUMP_PREFIX_LIST
     364             :                 struct listnode *p_node;
     365             :                 struct prefix *p;
     366             :                 int list_size = neigh->prefix_list
     367             :                                         ? (int)listcount(neigh->prefix_list)
     368             :                                         : -1;
     369             :                 int i = 0;
     370             :                 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) {
     371             :                         zlog_debug(
     372             :                                 "%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%pFXh [%d/%d]",
     373             :                                 __func__, (unsigned)neigh,
     374             :                                 (unsigned)neigh->prefix_list, (unsigned)p, p, i,
     375             :                                 list_size);
     376             :                         ++i;
     377             :                 }
     378             : #endif
     379             : 
     380         104 :                 list_delete(&neigh->prefix_list);
     381             :         }
     382             : }
     383             : 
     384           6 : void pim_neighbor_free(struct pim_neighbor *neigh)
     385             : {
     386           6 :         assert(!neigh->t_expire_timer);
     387             : 
     388           6 :         delete_prefix_list(neigh);
     389             : 
     390           6 :         list_delete(&neigh->upstream_jp_agg);
     391           6 :         THREAD_OFF(neigh->jp_timer);
     392             : 
     393           6 :         bfd_sess_free(&neigh->bfd_session);
     394             : 
     395           6 :         XFREE(MTYPE_PIM_NEIGHBOR, neigh);
     396           6 : }
     397             : 
     398           0 : struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp,
     399             :                                                     struct prefix *src)
     400             : {
     401           0 :         struct pim_interface *pim_ifp;
     402           0 :         struct listnode *node, *pnode;
     403           0 :         struct pim_neighbor *neigh;
     404           0 :         struct prefix *p;
     405             : 
     406           0 :         if (!ifp || !ifp->info)
     407             :                 return NULL;
     408             : 
     409           0 :         pim_ifp = ifp->info;
     410             : 
     411           0 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
     412           0 :                 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, pnode, p)) {
     413           0 :                         if (prefix_same(p, src))
     414           0 :                                 return neigh;
     415             :                 }
     416             :         }
     417             : 
     418             :         return NULL;
     419             : }
     420             : 
     421         116 : struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
     422             :                                        pim_addr source_addr)
     423             : {
     424         116 :         struct pim_interface *pim_ifp;
     425         116 :         struct listnode *node;
     426         116 :         struct pim_neighbor *neigh;
     427             : 
     428         116 :         if (!ifp)
     429             :                 return NULL;
     430             : 
     431         116 :         pim_ifp = ifp->info;
     432         116 :         if (!pim_ifp)
     433             :                 return NULL;
     434             : 
     435         292 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
     436         166 :                 if (!pim_addr_cmp(source_addr, neigh->source_addr)) {
     437         106 :                         return neigh;
     438             :                 }
     439             :         }
     440             : 
     441             :         return NULL;
     442             : }
     443             : 
     444             : /*
     445             :  * Find the *one* interface out
     446             :  * this interface.  If more than
     447             :  * one return NULL
     448             :  */
     449           0 : struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp)
     450             : {
     451           0 :         struct pim_interface *pim_ifp = ifp->info;
     452             : 
     453           0 :         if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
     454             :                 return NULL;
     455             : 
     456           0 :         return listnode_head(pim_ifp->pim_neighbor_list);
     457             : }
     458             : 
     459             : struct pim_neighbor *
     460           6 : pim_neighbor_add(struct interface *ifp, pim_addr source_addr,
     461             :                  pim_hello_options hello_options, uint16_t holdtime,
     462             :                  uint16_t propagation_delay, uint16_t override_interval,
     463             :                  uint32_t dr_priority, uint32_t generation_id,
     464             :                  struct list *addr_list, int send_hello_now)
     465             : {
     466           6 :         struct pim_interface *pim_ifp;
     467           6 :         struct pim_neighbor *neigh;
     468             : 
     469           6 :         neigh = pim_neighbor_new(ifp, source_addr, hello_options, holdtime,
     470             :                                  propagation_delay, override_interval,
     471             :                                  dr_priority, generation_id, addr_list);
     472           6 :         if (!neigh) {
     473             :                 return 0;
     474             :         }
     475             : 
     476           6 :         pim_ifp = ifp->info;
     477           6 :         assert(pim_ifp);
     478             : 
     479           6 :         listnode_add(pim_ifp->pim_neighbor_list, neigh);
     480             : 
     481           6 :         if (PIM_DEBUG_PIM_TRACE_DETAIL)
     482           0 :                 zlog_debug("%s: neighbor %pPA added ", __func__, &source_addr);
     483             :         /*
     484             :           RFC 4601: 4.3.2.  DR Election
     485             : 
     486             :           A router's idea of the current DR on an interface can change when a
     487             :           PIM Hello message is received, when a neighbor times out, or when a
     488             :           router's own DR Priority changes.
     489             :         */
     490           6 :         pim_if_dr_election(neigh->interface); // new neighbor -- should not
     491             :                                               // trigger dr election...
     492             : 
     493             :         /*
     494             :           RFC 4601: 4.3.1.  Sending Hello Messages
     495             : 
     496             :           To allow new or rebooting routers to learn of PIM neighbors quickly,
     497             :           when a Hello message is received from a new neighbor, or a Hello
     498             :           message with a new GenID is received from an existing neighbor, a
     499             :           new Hello message should be sent on this interface after a
     500             :           randomized delay between 0 and Triggered_Hello_Delay.
     501             : 
     502             :           This is a bit silly to do it that way.  If I get a new
     503             :           genid we need to send the hello *now* because we've
     504             :           lined up a bunch of join/prune messages to go out the
     505             :           interface.
     506             :         */
     507           6 :         if (send_hello_now)
     508           0 :                 pim_hello_restart_now(ifp);
     509             :         else
     510           6 :                 pim_hello_restart_triggered(neigh->interface);
     511             : 
     512           6 :         pim_upstream_find_new_rpf(pim_ifp->pim);
     513             : 
     514             :         /* RNH can send nexthop update prior to PIM neibhor UP
     515             :            in that case nexthop cache would not consider this neighbor
     516             :            as RPF.
     517             :            Upon PIM neighbor UP, iterate all RPs and update
     518             :            nexthop cache with this neighbor.
     519             :          */
     520           6 :         pim_resolve_rp_nh(pim_ifp->pim, neigh);
     521             : 
     522           6 :         pim_rp_setup(pim_ifp->pim);
     523             : 
     524           6 :         sched_rpf_cache_refresh(pim_ifp->pim);
     525           6 :         return neigh;
     526             : }
     527             : 
     528           6 : static uint16_t find_neighbors_next_highest_propagation_delay_msec(
     529             :         struct interface *ifp, struct pim_neighbor *highest_neigh)
     530             : {
     531           6 :         struct pim_interface *pim_ifp;
     532           6 :         struct listnode *neigh_node;
     533           6 :         struct pim_neighbor *neigh;
     534           6 :         uint16_t next_highest_delay_msec;
     535             : 
     536           6 :         pim_ifp = ifp->info;
     537           6 :         assert(pim_ifp);
     538             : 
     539           6 :         next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
     540             : 
     541          21 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
     542             :                                   neigh)) {
     543           9 :                 if (neigh == highest_neigh)
     544           6 :                         continue;
     545           3 :                 if (neigh->propagation_delay_msec > next_highest_delay_msec)
     546           9 :                         next_highest_delay_msec = neigh->propagation_delay_msec;
     547             :         }
     548             : 
     549           6 :         return next_highest_delay_msec;
     550             : }
     551             : 
     552           6 : static uint16_t find_neighbors_next_highest_override_interval_msec(
     553             :         struct interface *ifp, struct pim_neighbor *highest_neigh)
     554             : {
     555           6 :         struct pim_interface *pim_ifp;
     556           6 :         struct listnode *neigh_node;
     557           6 :         struct pim_neighbor *neigh;
     558           6 :         uint16_t next_highest_interval_msec;
     559             : 
     560           6 :         pim_ifp = ifp->info;
     561           6 :         assert(pim_ifp);
     562             : 
     563           6 :         next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
     564             : 
     565          21 :         for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
     566             :                                   neigh)) {
     567           9 :                 if (neigh == highest_neigh)
     568           6 :                         continue;
     569           3 :                 if (neigh->override_interval_msec > next_highest_interval_msec)
     570           9 :                         next_highest_interval_msec =
     571             :                                 neigh->override_interval_msec;
     572             :         }
     573             : 
     574           6 :         return next_highest_interval_msec;
     575             : }
     576             : 
     577           6 : void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh,
     578             :                          const char *delete_message)
     579             : {
     580           6 :         struct pim_interface *pim_ifp;
     581             : 
     582           6 :         pim_ifp = ifp->info;
     583           6 :         assert(pim_ifp);
     584             : 
     585           6 :         zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s",
     586             :                     &neigh->source_addr, ifp->name, delete_message);
     587             : 
     588           6 :         THREAD_OFF(neigh->t_expire_timer);
     589             : 
     590           6 :         pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
     591             : 
     592           6 :         if (!PIM_OPTION_IS_SET(neigh->hello_options,
     593             :                                PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
     594             :                 /* update num. of neighbors without hello option lan_delay */
     595             : 
     596           0 :                 --pim_ifp->pim_number_of_nonlandelay_neighbors;
     597             :         }
     598             : 
     599           6 :         if (!PIM_OPTION_IS_SET(neigh->hello_options,
     600             :                                PIM_OPTION_MASK_DR_PRIORITY)) {
     601             :                 /* update num. of neighbors without dr_pri */
     602             : 
     603           0 :                 --pim_ifp->pim_dr_num_nondrpri_neighbors;
     604             :         }
     605             : 
     606           6 :         assert(neigh->propagation_delay_msec
     607             :                <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
     608           6 :         assert(neigh->override_interval_msec
     609             :                <= pim_ifp->pim_neighbors_highest_override_interval_msec);
     610             : 
     611           6 :         if (pim_if_lan_delay_enabled(ifp)) {
     612             : 
     613             :                 /* will delete a neighbor with highest propagation delay? */
     614           6 :                 if (neigh->propagation_delay_msec
     615           6 :                     == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
     616             :                         /* then find the next highest propagation delay */
     617           6 :                         pim_ifp->pim_neighbors_highest_propagation_delay_msec =
     618           6 :                                 find_neighbors_next_highest_propagation_delay_msec(
     619             :                                         ifp, neigh);
     620             :                 }
     621             : 
     622             :                 /* will delete a neighbor with highest override interval? */
     623           6 :                 if (neigh->override_interval_msec
     624           6 :                     == pim_ifp->pim_neighbors_highest_override_interval_msec) {
     625             :                         /* then find the next highest propagation delay */
     626           6 :                         pim_ifp->pim_neighbors_highest_override_interval_msec =
     627           6 :                                 find_neighbors_next_highest_override_interval_msec(
     628             :                                         ifp, neigh);
     629             :                 }
     630             :         }
     631             : 
     632           6 :         if (PIM_DEBUG_PIM_TRACE) {
     633           0 :                 zlog_debug("%s: deleting PIM neighbor %pPA on interface %s",
     634             :                            __func__, &neigh->source_addr, ifp->name);
     635             :         }
     636             : 
     637           6 :         listnode_delete(pim_ifp->pim_neighbor_list, neigh);
     638             : 
     639           6 :         pim_neighbor_free(neigh);
     640             : 
     641           6 :         sched_rpf_cache_refresh(pim_ifp->pim);
     642           6 : }
     643             : 
     644          10 : void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message)
     645             : {
     646          10 :         struct pim_interface *pim_ifp;
     647          10 :         struct listnode *neigh_node;
     648          10 :         struct listnode *neigh_nextnode;
     649          10 :         struct pim_neighbor *neigh;
     650             : 
     651          10 :         pim_ifp = ifp->info;
     652          10 :         assert(pim_ifp);
     653             : 
     654          23 :         for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
     655             :                                neigh_nextnode, neigh)) {
     656           3 :                 pim_neighbor_delete(ifp, neigh, delete_message);
     657             :         }
     658          10 : }
     659             : 
     660           0 : struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
     661             :                                            struct prefix *addr)
     662             : {
     663           0 :         struct listnode *node;
     664           0 :         struct prefix *p;
     665             : 
     666           0 :         if (!neigh->prefix_list)
     667             :                 return 0;
     668             : 
     669           0 :         for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
     670           0 :                 if (prefix_same(p, addr))
     671           0 :                         return p;
     672             :         }
     673             : 
     674             :         return NULL;
     675             : }
     676             : 
     677             : /*
     678             :   RFC 4601: 4.3.4.  Maintaining Secondary Address Lists
     679             : 
     680             :   All the advertised secondary addresses in received Hello messages
     681             :   must be checked against those previously advertised by all other
     682             :   PIM neighbors on that interface.  If there is a conflict and the
     683             :   same secondary address was previously advertised by another
     684             :   neighbor, then only the most recently received mapping MUST be
     685             :   maintained, and an error message SHOULD be logged to the
     686             :   administrator in a rate-limited manner.
     687             : */
     688          98 : static void delete_from_neigh_addr(struct interface *ifp,
     689             :                                    struct list *addr_list, pim_addr neigh_addr)
     690             : {
     691          98 :         struct listnode *addr_node;
     692          98 :         struct prefix *addr;
     693          98 :         struct pim_interface *pim_ifp;
     694             : 
     695          98 :         pim_ifp = ifp->info;
     696          98 :         assert(pim_ifp);
     697             : 
     698          98 :         assert(addr_list);
     699             : 
     700             :         /*
     701             :           Scan secondary address list
     702             :         */
     703         392 :         for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, addr)) {
     704         196 :                 struct listnode *neigh_node;
     705         196 :                 struct pim_neighbor *neigh;
     706             : 
     707         196 :                 if (addr->family != PIM_AF)
     708         196 :                         continue;
     709             :                 /*
     710             :                   Scan neighbors
     711             :                 */
     712           0 :                 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
     713             :                                           neigh_node, neigh)) {
     714             :                         {
     715           0 :                                 struct prefix *p = pim_neighbor_find_secondary(
     716             :                                         neigh, addr);
     717           0 :                                 if (p) {
     718           0 :                                         zlog_info(
     719             :                                                 "secondary addr %pFXh recvd from neigh %pPA deleted from neigh %pPA on %s",
     720             :                                                 addr, &neigh_addr,
     721             :                                                 &neigh->source_addr, ifp->name);
     722             : 
     723           0 :                                         listnode_delete(neigh->prefix_list, p);
     724           0 :                                         prefix_free(&p);
     725             :                                 }
     726             :                         }
     727             : 
     728             :                 } /* scan neighbors */
     729             : 
     730             :         } /* scan addr list */
     731          98 : }
     732             : 
     733          98 : void pim_neighbor_update(struct pim_neighbor *neigh,
     734             :                          pim_hello_options hello_options, uint16_t holdtime,
     735             :                          uint32_t dr_priority, struct list *addr_list)
     736             : {
     737          98 :         struct pim_interface *pim_ifp = neigh->interface->info;
     738          98 :         uint32_t old, new;
     739             : 
     740             :         /* Received holdtime ? */
     741          98 :         if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
     742          98 :                 pim_neighbor_timer_reset(neigh, holdtime);
     743             :         } else {
     744           0 :                 pim_neighbor_timer_reset(neigh,
     745           0 :                                          PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
     746             :         }
     747             : 
     748             : #ifdef DUMP_PREFIX_LIST
     749             :         zlog_debug(
     750             :                 "%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
     751             :                 __func__, (unsigned)neigh->prefix_list,
     752             :                 neigh->prefix_list ? (int)listcount(neigh->prefix_list) : -1,
     753             :                 (unsigned)addr_list,
     754             :                 addr_list ? (int)listcount(addr_list) : -1);
     755             : #endif
     756             : 
     757          98 :         if (neigh->prefix_list == addr_list) {
     758           0 :                 if (addr_list) {
     759           0 :                         flog_err(
     760             :                                 EC_LIB_DEVELOPMENT,
     761             :                                 "%s: internal error: trying to replace same prefix list=%p",
     762             :                                 __func__, (void *)addr_list);
     763             :                 }
     764             :         } else {
     765             :                 /* Delete existing secondary address list */
     766          98 :                 delete_prefix_list(neigh);
     767             :         }
     768             : 
     769          98 :         if (addr_list) {
     770          98 :                 delete_from_neigh_addr(neigh->interface, addr_list,
     771             :                                        neigh->source_addr);
     772             :         }
     773             : 
     774             :         /* Replace secondary address list */
     775          98 :         neigh->prefix_list = addr_list;
     776             : 
     777          98 :         update_dr_priority(neigh, hello_options, dr_priority);
     778          98 :         new = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
     779          98 :         old = PIM_OPTION_IS_SET(neigh->hello_options,
     780             :                                 PIM_OPTION_MASK_LAN_PRUNE_DELAY);
     781             : 
     782          98 :         if (old != new) {
     783           0 :                 if (old)
     784           0 :                         ++pim_ifp->pim_number_of_nonlandelay_neighbors;
     785             :                 else
     786           0 :                         --pim_ifp->pim_number_of_nonlandelay_neighbors;
     787             :         }
     788             :         /*
     789             :           Copy flags
     790             :          */
     791          98 :         neigh->hello_options = hello_options;
     792          98 : }

Generated by: LCOV version v1.16-topotato