Coverage Report

Created: 2025-12-05 06:31

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