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