Coverage Report

Created: 2026-07-16 06:42

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
495
{
36
495
  struct pim_interface *pim_ifp;
37
495
  struct listnode *node;
38
495
  struct pim_neighbor *neigh;
39
40
495
  pim_ifp = ifp->info;
41
495
  assert(pim_ifp);
42
43
495
  pim_ifp->pim_dr_addr = pim_ifp->primary_address;
44
45
495
  if (PIM_DEBUG_PIM_TRACE) {
46
0
    zlog_debug("%s: on interface %s", __func__, ifp->name);
47
0
  }
48
49
89.4k
  for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
50
89.4k
    if (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) > 0)
51
1.26k
      pim_ifp->pim_dr_addr = neigh->source_addr;
52
89.4k
  }
53
495
}
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
495
{
98
495
  struct pim_interface *pim_ifp = ifp->info;
99
495
  pim_addr old_dr_addr;
100
101
495
  ++pim_ifp->pim_dr_election_count;
102
103
495
  old_dr_addr = pim_ifp->pim_dr_addr;
104
105
495
  if (pim_ifp->pim_dr_num_nondrpri_neighbors) {
106
495
    dr_election_by_addr(ifp);
107
495
  } else {
108
0
    dr_election_by_pri(ifp);
109
0
  }
110
111
  /* DR changed ? */
112
495
  if (pim_addr_cmp(old_dr_addr, pim_ifp->pim_dr_addr)) {
113
114
3
    if (PIM_DEBUG_PIM_EVENTS)
115
0
      zlog_debug(
116
3
        "%s: DR was %pPA now is %pPA on interface %s",
117
3
        __func__, &old_dr_addr, &pim_ifp->pim_dr_addr,
118
3
        ifp->name);
119
120
3
    pim_ifp->pim_dr_election_last =
121
3
      pim_time_monotonic_sec(); /* timestamp */
122
3
    ++pim_ifp->pim_dr_election_changes;
123
3
    pim_if_update_join_desired(pim_ifp);
124
3
    pim_if_update_could_assert(ifp);
125
3
    pim_if_update_assert_tracking_desired(ifp);
126
127
3
    if (PIM_I_am_DR(pim_ifp)) {
128
0
      pim_ifp->am_i_dr = true;
129
0
      pim_clear_nocache_state(pim_ifp);
130
3
    } else {
131
3
      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
3
    }
136
137
3
    return 1;
138
3
  }
139
140
492
  return 0;
141
495
}
142
143
static void update_dr_priority(struct pim_neighbor *neigh,
144
             pim_hello_options hello_options,
145
             uint32_t dr_priority)
146
108
{
147
108
  pim_hello_options will_set_pri; /* boolean */
148
108
  pim_hello_options bit_flip;     /* boolean */
149
108
  pim_hello_options pri_change;   /* boolean */
150
151
108
  will_set_pri =
152
108
    PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY);
153
154
108
  bit_flip = (will_set_pri
155
108
        != PIM_OPTION_IS_SET(neigh->hello_options,
156
108
           PIM_OPTION_MASK_DR_PRIORITY));
157
158
108
  if (bit_flip) {
159
3
    struct pim_interface *pim_ifp = neigh->interface->info;
160
161
    /* update num. of neighbors without dr_pri */
162
163
3
    if (will_set_pri) {
164
0
      --pim_ifp->pim_dr_num_nondrpri_neighbors;
165
3
    } else {
166
3
      ++pim_ifp->pim_dr_num_nondrpri_neighbors;
167
3
    }
168
3
  }
169
170
108
  pri_change = (bit_flip || (neigh->dr_priority != dr_priority));
171
172
108
  if (will_set_pri) {
173
22
    neigh->dr_priority = dr_priority;
174
86
  } else {
175
86
    neigh->dr_priority = 0; /* cosmetic unset */
176
86
  }
177
178
108
  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
23
    pim_if_dr_election(
189
23
      neigh->interface); // router's own DR Priority changes
190
23
  }
191
108
}
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.87k
{
223
1.87k
  neigh->holdtime = holdtime;
224
225
1.87k
  EVENT_OFF(neigh->t_expire_timer);
226
227
  /*
228
    0xFFFF is request for no holdtime
229
   */
230
1.87k
  if (neigh->holdtime == 0xFFFF) {
231
0
    return;
232
0
  }
233
234
1.87k
  if (PIM_DEBUG_PIM_TRACE_DETAIL)
235
0
    zlog_debug("%s: starting %u sec timer for neighbor %pPA on %s",
236
1.87k
         __func__, neigh->holdtime, &neigh->source_addr,
237
1.87k
         neigh->interface->name);
238
239
1.87k
  event_add_timer(router->master, on_neighbor_timer, neigh,
240
1.87k
      neigh->holdtime, &neigh->t_expire_timer);
241
1.87k
}
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
472
{
264
472
  EVENT_OFF(neigh->jp_timer);
265
472
  event_add_timer(router->master, on_neighbor_jp_timer, neigh,
266
472
      router->t_periodic, &neigh->jp_timer);
267
472
}
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
472
{
276
472
  struct pim_interface *pim_ifp;
277
472
  struct pim_neighbor *neigh;
278
279
472
  assert(ifp);
280
472
  pim_ifp = ifp->info;
281
472
  assert(pim_ifp);
282
283
472
  neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
284
285
472
  neigh->creation = pim_time_monotonic_sec();
286
472
  neigh->source_addr = source_addr;
287
472
  neigh->hello_options = hello_options;
288
472
  neigh->propagation_delay_msec = propagation_delay;
289
472
  neigh->override_interval_msec = override_interval;
290
472
  neigh->dr_priority = dr_priority;
291
472
  neigh->generation_id = generation_id;
292
472
  neigh->prefix_list = addr_list;
293
472
  neigh->t_expire_timer = NULL;
294
472
  neigh->interface = ifp;
295
296
472
  neigh->upstream_jp_agg = list_new();
297
472
  neigh->upstream_jp_agg->cmp = pim_jp_agg_group_list_cmp;
298
472
  neigh->upstream_jp_agg->del =
299
472
    (void (*)(void *))pim_jp_agg_group_list_free;
300
472
  pim_neighbor_start_jp_timer(neigh);
301
302
472
  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
472
  PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags);
311
312
472
  if (PIM_DEBUG_PIM_EVENTS)
313
0
    zlog_debug("%s: creating PIM neighbor %pPA on interface %s",
314
472
         __func__, &source_addr, ifp->name);
315
316
472
  zlog_notice("PIM NEIGHBOR UP: neighbor %pPA on interface %s",
317
472
        &source_addr, ifp->name);
318
319
472
  if (neigh->propagation_delay_msec
320
472
      > pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
321
3
    pim_ifp->pim_neighbors_highest_propagation_delay_msec =
322
3
      neigh->propagation_delay_msec;
323
3
  }
324
472
  if (neigh->override_interval_msec
325
472
      > pim_ifp->pim_neighbors_highest_override_interval_msec) {
326
5
    pim_ifp->pim_neighbors_highest_override_interval_msec =
327
5
      neigh->override_interval_msec;
328
5
  }
329
330
472
  if (!PIM_OPTION_IS_SET(neigh->hello_options,
331
472
             PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
332
    /* update num. of neighbors without hello option lan_delay */
333
415
    ++pim_ifp->pim_number_of_nonlandelay_neighbors;
334
415
  }
335
336
472
  if (!PIM_OPTION_IS_SET(neigh->hello_options,
337
472
             PIM_OPTION_MASK_DR_PRIORITY)) {
338
    /* update num. of neighbors without hello option dr_pri */
339
434
    ++pim_ifp->pim_dr_num_nondrpri_neighbors;
340
434
  }
341
342
  // Register PIM Neighbor with BFD
343
472
  pim_bfd_info_nbr_create(pim_ifp, neigh);
344
345
472
  return neigh;
346
472
}
347
348
static void delete_prefix_list(struct pim_neighbor *neigh)
349
181
{
350
181
  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
64
    list_delete(&neigh->prefix_list);
370
64
  }
371
181
}
372
373
void pim_neighbor_free(struct pim_neighbor *neigh)
374
112
{
375
112
  assert(!neigh->t_expire_timer);
376
377
112
  delete_prefix_list(neigh);
378
379
112
  list_delete(&neigh->upstream_jp_agg);
380
112
  EVENT_OFF(neigh->jp_timer);
381
382
112
  bfd_sess_free(&neigh->bfd_session);
383
384
112
  XFREE(MTYPE_PIM_NEIGHBOR, neigh);
385
112
}
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.87k
{
413
1.87k
  struct pim_interface *pim_ifp;
414
1.87k
  struct listnode *node;
415
1.87k
  struct pim_neighbor *neigh;
416
417
1.87k
  if (!ifp)
418
0
    return NULL;
419
420
1.87k
  pim_ifp = ifp->info;
421
1.87k
  if (!pim_ifp)
422
0
    return NULL;
423
424
458k
  for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
425
458k
    if (!pim_addr_cmp(source_addr, neigh->source_addr)) {
426
1.51k
      return neigh;
427
1.51k
    }
428
458k
  }
429
430
361
  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
361
  return NULL;
438
361
}
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
472
{
462
472
  struct pim_interface *pim_ifp;
463
472
  struct pim_neighbor *neigh;
464
465
472
  neigh = pim_neighbor_new(ifp, source_addr, hello_options, holdtime,
466
472
         propagation_delay, override_interval,
467
472
         dr_priority, generation_id, addr_list);
468
472
  if (!neigh) {
469
0
    return 0;
470
0
  }
471
472
472
  pim_ifp = ifp->info;
473
472
  assert(pim_ifp);
474
475
472
  listnode_add(pim_ifp->pim_neighbor_list, neigh);
476
477
472
  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
472
  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
472
  if (send_hello_now)
504
112
    pim_hello_restart_now(ifp);
505
360
  else
506
360
    pim_hello_restart_triggered(neigh->interface);
507
508
472
  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
472
  pim_resolve_rp_nh(pim_ifp->pim, neigh);
517
518
472
  pim_rp_setup(pim_ifp->pim);
519
520
472
  sched_rpf_cache_refresh(pim_ifp->pim);
521
472
  return neigh;
522
472
}
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
112
{
576
112
  struct pim_interface *pim_ifp;
577
578
112
  pim_ifp = ifp->info;
579
112
  assert(pim_ifp);
580
581
112
  zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s",
582
112
        &neigh->source_addr, ifp->name, delete_message);
583
584
112
  EVENT_OFF(neigh->t_expire_timer);
585
586
112
  pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
587
588
112
  if (!PIM_OPTION_IS_SET(neigh->hello_options,
589
112
             PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
590
    /* update num. of neighbors without hello option lan_delay */
591
592
103
    pim_ifp->pim_number_of_nonlandelay_neighbors = MAX(
593
103
      pim_ifp->pim_number_of_nonlandelay_neighbors - 1, 0);
594
103
  }
595
596
112
  if (!PIM_OPTION_IS_SET(neigh->hello_options,
597
112
             PIM_OPTION_MASK_DR_PRIORITY)) {
598
    /* update num. of neighbors without dr_pri */
599
600
110
    pim_ifp->pim_dr_num_nondrpri_neighbors =
601
110
      MAX(pim_ifp->pim_dr_num_nondrpri_neighbors - 1, 0);
602
110
  }
603
604
112
  assert(neigh->propagation_delay_msec
605
112
         <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
606
112
  assert(neigh->override_interval_msec
607
112
         <= pim_ifp->pim_neighbors_highest_override_interval_msec);
608
609
112
  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
112
  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
112
  listnode_delete(pim_ifp->pim_neighbor_list, neigh);
636
637
112
  pim_neighbor_free(neigh);
638
639
112
  sched_rpf_cache_refresh(pim_ifp->pim);
640
112
}
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
407k
{
661
407k
  struct listnode *node;
662
407k
  struct prefix *p;
663
664
407k
  if (!neigh->prefix_list)
665
291k
    return 0;
666
667
478k
  for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
668
478k
    if (prefix_same(p, addr))
669
451
      return p;
670
478k
  }
671
672
115k
  return NULL;
673
115k
}
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
65
{
689
65
  struct listnode *addr_node;
690
65
  struct prefix *addr;
691
65
  struct pim_interface *pim_ifp;
692
693
65
  pim_ifp = ifp->info;
694
65
  assert(pim_ifp);
695
696
65
  assert(addr_list);
697
698
  /*
699
    Scan secondary address list
700
  */
701
1.43k
  for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, addr)) {
702
1.43k
    struct listnode *neigh_node;
703
1.43k
    struct pim_neighbor *neigh;
704
705
1.43k
    if (addr->family != PIM_AF)
706
255
      continue;
707
    /*
708
      Scan neighbors
709
    */
710
1.17k
    for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
711
407k
            neigh_node, neigh)) {
712
407k
      {
713
407k
        struct prefix *p = pim_neighbor_find_secondary(
714
407k
          neigh, addr);
715
407k
        if (p) {
716
451
          zlog_info(
717
451
            "secondary addr %pFXh recvd from neigh %pPA deleted from neigh %pPA on %s",
718
451
            addr, &neigh_addr,
719
451
            &neigh->source_addr, ifp->name);
720
721
451
          listnode_delete(neigh->prefix_list, p);
722
451
          prefix_free(&p);
723
451
        }
724
407k
      }
725
726
407k
    } /* scan neighbors */
727
728
1.17k
  } /* scan addr list */
729
65
}
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
108
{
735
108
  struct pim_interface *pim_ifp = neigh->interface->info;
736
108
  uint32_t old, new;
737
738
  /* Received holdtime ? */
739
108
  if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
740
0
    pim_neighbor_timer_reset(neigh, holdtime);
741
108
  } else {
742
108
    pim_neighbor_timer_reset(neigh,
743
108
           PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
744
108
  }
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
108
  if (neigh->prefix_list == addr_list) {
756
39
    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
69
  } else {
763
    /* Delete existing secondary address list */
764
69
    delete_prefix_list(neigh);
765
69
  }
766
767
108
  if (addr_list) {
768
65
    delete_from_neigh_addr(neigh->interface, addr_list,
769
65
               neigh->source_addr);
770
65
  }
771
772
  /* Replace secondary address list */
773
108
  neigh->prefix_list = addr_list;
774
775
108
  update_dr_priority(neigh, hello_options, dr_priority);
776
108
  new = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
777
108
  old = PIM_OPTION_IS_SET(neigh->hello_options,
778
108
        PIM_OPTION_MASK_LAN_PRUNE_DELAY);
779
780
108
  if (old != new) {
781
7
    if (old)
782
2
      ++pim_ifp->pim_number_of_nonlandelay_neighbors;
783
5
    else
784
5
      --pim_ifp->pim_number_of_nonlandelay_neighbors;
785
7
  }
786
  /*
787
    Copy flags
788
   */
789
108
  neigh->hello_options = hello_options;
790
108
}