Coverage Report

Created: 2026-10-17 07:02

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