Coverage Report

Created: 2026-03-12 06:41

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