Coverage Report

Created: 2026-08-26 06:54

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