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