1 // SPDX-License-Identifier: GPL-2.0-or-later
4 * Copyright (C) 2008 Everton da Silva Marques
15 #include "lib_errors.h"
18 #include "pim_instance.h"
19 #include "pim_neighbor.h"
22 #include "pim_iface.h"
24 #include "pim_upstream.h"
25 #include "pim_ifchannel.h"
27 #include "pim_zebra.h"
29 #include "pim_jp_agg.h"
31 #include "pim_register.h"
33 static void dr_election_by_addr(struct interface
*ifp
)
35 struct pim_interface
*pim_ifp
;
36 struct listnode
*node
;
37 struct pim_neighbor
*neigh
;
42 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
44 if (PIM_DEBUG_PIM_TRACE
) {
45 zlog_debug("%s: on interface %s", __func__
, ifp
->name
);
48 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
49 if (pim_addr_cmp(neigh
->source_addr
, pim_ifp
->pim_dr_addr
) > 0)
50 pim_ifp
->pim_dr_addr
= neigh
->source_addr
;
54 static void dr_election_by_pri(struct interface
*ifp
)
56 struct pim_interface
*pim_ifp
;
57 struct listnode
*node
;
58 struct pim_neighbor
*neigh
;
64 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
65 dr_pri
= pim_ifp
->pim_dr_priority
;
67 if (PIM_DEBUG_PIM_TRACE
) {
68 zlog_debug("%s: dr pri %u on interface %s", __func__
, dr_pri
,
72 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
73 if (PIM_DEBUG_PIM_TRACE
) {
74 zlog_info("%s: neigh pri %u addr %pPA if dr addr %pPA",
75 __func__
, neigh
->dr_priority
,
76 &neigh
->source_addr
, &pim_ifp
->pim_dr_addr
);
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
) >
82 pim_ifp
->pim_dr_addr
= neigh
->source_addr
;
83 dr_pri
= neigh
->dr_priority
;
89 RFC 4601: 4.3.2. DR Election
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.
95 int pim_if_dr_election(struct interface
*ifp
)
97 struct pim_interface
*pim_ifp
= ifp
->info
;
100 ++pim_ifp
->pim_dr_election_count
;
102 old_dr_addr
= pim_ifp
->pim_dr_addr
;
104 if (pim_ifp
->pim_dr_num_nondrpri_neighbors
) {
105 dr_election_by_addr(ifp
);
107 dr_election_by_pri(ifp
);
111 if (pim_addr_cmp(old_dr_addr
, pim_ifp
->pim_dr_addr
)) {
113 if (PIM_DEBUG_PIM_EVENTS
)
115 "%s: DR was %pPA now is %pPA on interface %s",
116 __func__
, &old_dr_addr
, &pim_ifp
->pim_dr_addr
,
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
);
126 if (PIM_I_am_DR(pim_ifp
))
127 pim_ifp
->am_i_dr
= true;
129 if (pim_ifp
->am_i_dr
== true) {
130 pim_reg_del_on_couldreg_fail(ifp
);
131 pim_ifp
->am_i_dr
= false;
141 static void update_dr_priority(struct pim_neighbor
*neigh
,
142 pim_hello_options hello_options
,
143 uint32_t dr_priority
)
145 pim_hello_options will_set_pri
; /* boolean */
146 pim_hello_options bit_flip
; /* boolean */
147 pim_hello_options pri_change
; /* boolean */
150 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
152 bit_flip
= (will_set_pri
153 != PIM_OPTION_IS_SET(neigh
->hello_options
,
154 PIM_OPTION_MASK_DR_PRIORITY
));
157 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
159 /* update num. of neighbors without dr_pri */
162 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
164 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
168 pri_change
= (bit_flip
|| (neigh
->dr_priority
!= dr_priority
));
171 neigh
->dr_priority
= dr_priority
;
173 neigh
->dr_priority
= 0; /* cosmetic unset */
178 RFC 4601: 4.3.2. DR Election
180 A router's idea of the current DR on an interface can change
182 PIM Hello message is received, when a neighbor times out, or
184 router's own DR Priority changes.
187 neigh
->interface
); // router's own DR Priority changes
191 static void on_neighbor_timer(struct thread
*t
)
193 struct pim_neighbor
*neigh
;
194 struct interface
*ifp
;
197 neigh
= THREAD_ARG(t
);
199 ifp
= neigh
->interface
;
201 if (PIM_DEBUG_PIM_TRACE
)
203 "Expired %d sec holdtime for neighbor %pPA on interface %s",
204 neigh
->holdtime
, &neigh
->source_addr
, ifp
->name
);
206 snprintf(msg
, sizeof(msg
), "%d-sec holdtime expired", neigh
->holdtime
);
207 pim_neighbor_delete(ifp
, neigh
, msg
);
210 RFC 4601: 4.3.2. DR Election
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.
216 pim_if_dr_election(ifp
); // neighbor times out
219 void pim_neighbor_timer_reset(struct pim_neighbor
*neigh
, uint16_t holdtime
)
221 neigh
->holdtime
= holdtime
;
223 THREAD_OFF(neigh
->t_expire_timer
);
226 0xFFFF is request for no holdtime
228 if (neigh
->holdtime
== 0xFFFF) {
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
,
235 neigh
->interface
->name
);
237 thread_add_timer(router
->master
, on_neighbor_timer
, neigh
,
238 neigh
->holdtime
, &neigh
->t_expire_timer
);
241 static void on_neighbor_jp_timer(struct thread
*t
)
243 struct pim_neighbor
*neigh
= THREAD_ARG(t
);
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
,
250 neigh
->upstream_jp_agg
->count
);
252 rpf
.source_nexthop
.interface
= neigh
->interface
;
253 rpf
.rpf_addr
= neigh
->source_addr
;
254 pim_joinprune_send(&rpf
, neigh
->upstream_jp_agg
);
256 thread_add_timer(router
->master
, on_neighbor_jp_timer
, neigh
,
257 router
->t_periodic
, &neigh
->jp_timer
);
260 static void pim_neighbor_start_jp_timer(struct pim_neighbor
*neigh
)
262 THREAD_OFF(neigh
->jp_timer
);
263 thread_add_timer(router
->master
, on_neighbor_jp_timer
, neigh
,
264 router
->t_periodic
, &neigh
->jp_timer
);
267 static struct pim_neighbor
*
268 pim_neighbor_new(struct interface
*ifp
, pim_addr source_addr
,
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
)
274 struct pim_interface
*pim_ifp
;
275 struct pim_neighbor
*neigh
;
281 neigh
= XCALLOC(MTYPE_PIM_NEIGHBOR
, sizeof(*neigh
));
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
;
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
);
300 pim_neighbor_timer_reset(neigh
, holdtime
);
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
308 PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp
->flags
);
310 if (PIM_DEBUG_PIM_EVENTS
)
311 zlog_debug("%s: creating PIM neighbor %pPA on interface %s",
312 __func__
, &source_addr
, ifp
->name
);
314 zlog_notice("PIM NEIGHBOR UP: neighbor %pPA on interface %s",
315 &source_addr
, ifp
->name
);
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
;
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
;
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
;
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
;
340 // Register PIM Neighbor with BFD
341 pim_bfd_info_nbr_create(pim_ifp
, neigh
);
346 static void delete_prefix_list(struct pim_neighbor
*neigh
)
348 if (neigh
->prefix_list
) {
350 #ifdef DUMP_PREFIX_LIST
351 struct listnode
*p_node
;
353 int list_size
= neigh
->prefix_list
354 ? (int)listcount(neigh
->prefix_list
)
357 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, p_node
, p
)) {
359 "%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%pFXh [%d/%d]",
360 __func__
, (unsigned)neigh
,
361 (unsigned)neigh
->prefix_list
, (unsigned)p
, p
, i
,
367 list_delete(&neigh
->prefix_list
);
371 void pim_neighbor_free(struct pim_neighbor
*neigh
)
373 assert(!neigh
->t_expire_timer
);
375 delete_prefix_list(neigh
);
377 list_delete(&neigh
->upstream_jp_agg
);
378 THREAD_OFF(neigh
->jp_timer
);
380 bfd_sess_free(&neigh
->bfd_session
);
382 XFREE(MTYPE_PIM_NEIGHBOR
, neigh
);
385 struct pim_neighbor
*pim_neighbor_find_by_secondary(struct interface
*ifp
,
388 struct pim_interface
*pim_ifp
;
389 struct listnode
*node
, *pnode
;
390 struct pim_neighbor
*neigh
;
393 if (!ifp
|| !ifp
->info
)
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
))
408 struct pim_neighbor
*pim_neighbor_find(struct interface
*ifp
,
409 pim_addr source_addr
)
411 struct pim_interface
*pim_ifp
;
412 struct listnode
*node
;
413 struct pim_neighbor
*neigh
;
422 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
423 if (!pim_addr_cmp(source_addr
, neigh
->source_addr
)) {
432 * Find the *one* interface out
433 * this interface. If more than
436 struct pim_neighbor
*pim_neighbor_find_if(struct interface
*ifp
)
438 struct pim_interface
*pim_ifp
= ifp
->info
;
440 if (!pim_ifp
|| pim_ifp
->pim_neighbor_list
->count
!= 1)
443 return listnode_head(pim_ifp
->pim_neighbor_list
);
446 struct pim_neighbor
*
447 pim_neighbor_add(struct interface
*ifp
, pim_addr source_addr
,
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
)
453 struct pim_interface
*pim_ifp
;
454 struct pim_neighbor
*neigh
;
456 neigh
= pim_neighbor_new(ifp
, source_addr
, hello_options
, holdtime
,
457 propagation_delay
, override_interval
,
458 dr_priority
, generation_id
, addr_list
);
466 listnode_add(pim_ifp
->pim_neighbor_list
, neigh
);
468 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
469 zlog_debug("%s: neighbor %pPA added ", __func__
, &source_addr
);
471 RFC 4601: 4.3.2. DR Election
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.
477 pim_if_dr_election(neigh
->interface
); // new neighbor -- should not
478 // trigger dr election...
481 RFC 4601: 4.3.1. Sending Hello Messages
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.
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
495 pim_hello_restart_now(ifp
);
497 pim_hello_restart_triggered(neigh
->interface
);
499 pim_upstream_find_new_rpf(pim_ifp
->pim
);
501 /* RNH can send nexthop update prior to PIM neibhor UP
502 in that case nexthop cache would not consider this neighbor
504 Upon PIM neighbor UP, iterate all RPs and update
505 nexthop cache with this neighbor.
507 pim_resolve_rp_nh(pim_ifp
->pim
, neigh
);
509 pim_rp_setup(pim_ifp
->pim
);
511 sched_rpf_cache_refresh(pim_ifp
->pim
);
515 static uint16_t find_neighbors_next_highest_propagation_delay_msec(
516 struct interface
*ifp
, struct pim_neighbor
*highest_neigh
)
518 struct pim_interface
*pim_ifp
;
519 struct listnode
*neigh_node
;
520 struct pim_neighbor
*neigh
;
521 uint16_t next_highest_delay_msec
;
526 next_highest_delay_msec
= pim_ifp
->pim_propagation_delay_msec
;
528 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
530 if (neigh
== highest_neigh
)
532 if (neigh
->propagation_delay_msec
> next_highest_delay_msec
)
533 next_highest_delay_msec
= neigh
->propagation_delay_msec
;
536 return next_highest_delay_msec
;
539 static uint16_t find_neighbors_next_highest_override_interval_msec(
540 struct interface
*ifp
, struct pim_neighbor
*highest_neigh
)
542 struct pim_interface
*pim_ifp
;
543 struct listnode
*neigh_node
;
544 struct pim_neighbor
*neigh
;
545 uint16_t next_highest_interval_msec
;
550 next_highest_interval_msec
= pim_ifp
->pim_override_interval_msec
;
552 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
554 if (neigh
== highest_neigh
)
556 if (neigh
->override_interval_msec
> next_highest_interval_msec
)
557 next_highest_interval_msec
=
558 neigh
->override_interval_msec
;
561 return next_highest_interval_msec
;
564 void pim_neighbor_delete(struct interface
*ifp
, struct pim_neighbor
*neigh
,
565 const char *delete_message
)
567 struct pim_interface
*pim_ifp
;
572 zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s",
573 &neigh
->source_addr
, ifp
->name
, delete_message
);
575 THREAD_OFF(neigh
->t_expire_timer
);
577 pim_if_assert_on_neighbor_down(ifp
, neigh
->source_addr
);
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 */
583 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
586 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
587 PIM_OPTION_MASK_DR_PRIORITY
)) {
588 /* update num. of neighbors without dr_pri */
590 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
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
);
598 if (pim_if_lan_delay_enabled(ifp
)) {
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(
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(
619 if (PIM_DEBUG_PIM_TRACE
) {
620 zlog_debug("%s: deleting PIM neighbor %pPA on interface %s",
621 __func__
, &neigh
->source_addr
, ifp
->name
);
624 listnode_delete(pim_ifp
->pim_neighbor_list
, neigh
);
626 pim_neighbor_free(neigh
);
628 sched_rpf_cache_refresh(pim_ifp
->pim
);
631 void pim_neighbor_delete_all(struct interface
*ifp
, const char *delete_message
)
633 struct pim_interface
*pim_ifp
;
634 struct listnode
*neigh_node
;
635 struct listnode
*neigh_nextnode
;
636 struct pim_neighbor
*neigh
;
641 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
, neigh_node
,
642 neigh_nextnode
, neigh
)) {
643 pim_neighbor_delete(ifp
, neigh
, delete_message
);
647 struct prefix
*pim_neighbor_find_secondary(struct pim_neighbor
*neigh
,
650 struct listnode
*node
;
653 if (!neigh
->prefix_list
)
656 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, node
, p
)) {
657 if (prefix_same(p
, addr
))
665 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
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.
675 static void delete_from_neigh_addr(struct interface
*ifp
,
676 struct list
*addr_list
, pim_addr neigh_addr
)
678 struct listnode
*addr_node
;
680 struct pim_interface
*pim_ifp
;
688 Scan secondary address list
690 for (ALL_LIST_ELEMENTS_RO(addr_list
, addr_node
, addr
)) {
691 struct listnode
*neigh_node
;
692 struct pim_neighbor
*neigh
;
694 if (addr
->family
!= PIM_AF
)
699 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
,
700 neigh_node
, neigh
)) {
702 struct prefix
*p
= pim_neighbor_find_secondary(
706 "secondary addr %pFXh recvd from neigh %pPA deleted from neigh %pPA on %s",
708 &neigh
->source_addr
, ifp
->name
);
710 listnode_delete(neigh
->prefix_list
, p
);
715 } /* scan neighbors */
717 } /* scan addr list */
720 void pim_neighbor_update(struct pim_neighbor
*neigh
,
721 pim_hello_options hello_options
, uint16_t holdtime
,
722 uint32_t dr_priority
, struct list
*addr_list
)
724 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
727 /* Received holdtime ? */
728 if (PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
)) {
729 pim_neighbor_timer_reset(neigh
, holdtime
);
731 pim_neighbor_timer_reset(neigh
,
732 PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
735 #ifdef DUMP_PREFIX_LIST
737 "%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
738 __func__
, (unsigned)neigh
->prefix_list
,
739 neigh
->prefix_list
? (int)listcount(neigh
->prefix_list
) : -1,
741 addr_list
? (int)listcount(addr_list
) : -1);
744 if (neigh
->prefix_list
== addr_list
) {
748 "%s: internal error: trying to replace same prefix list=%p",
749 __func__
, (void *)addr_list
);
752 /* Delete existing secondary address list */
753 delete_prefix_list(neigh
);
757 delete_from_neigh_addr(neigh
->interface
, addr_list
,
761 /* Replace secondary address list */
762 neigh
->prefix_list
= addr_list
;
764 update_dr_priority(neigh
, hello_options
, dr_priority
);
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
);
771 ++pim_ifp
->pim_number_of_nonlandelay_neighbors
;
773 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
778 neigh
->hello_options
= hello_options
;