3 * Copyright (C) 2008 Everton da Silva Marques
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "lib_errors.h"
31 #include "pim_neighbor.h"
34 #include "pim_iface.h"
36 #include "pim_upstream.h"
37 #include "pim_ifchannel.h"
39 #include "pim_zebra.h"
41 #include "pim_jp_agg.h"
44 static void dr_election_by_addr(struct interface
*ifp
)
46 struct pim_interface
*pim_ifp
;
47 struct listnode
*node
;
48 struct pim_neighbor
*neigh
;
53 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
55 if (PIM_DEBUG_PIM_TRACE
) {
56 zlog_debug("%s: on interface %s", __func__
, ifp
->name
);
59 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
60 if (ntohl(neigh
->source_addr
.s_addr
)
61 > ntohl(pim_ifp
->pim_dr_addr
.s_addr
)) {
62 pim_ifp
->pim_dr_addr
= neigh
->source_addr
;
67 static void dr_election_by_pri(struct interface
*ifp
)
69 struct pim_interface
*pim_ifp
;
70 struct listnode
*node
;
71 struct pim_neighbor
*neigh
;
77 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
78 dr_pri
= pim_ifp
->pim_dr_priority
;
80 if (PIM_DEBUG_PIM_TRACE
) {
81 zlog_debug("%s: dr pri %u on interface %s", __func__
, dr_pri
,
85 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
86 if (PIM_DEBUG_PIM_TRACE
) {
87 zlog_info("%s: neigh pri %u addr %x if dr addr %x",
88 __func__
, neigh
->dr_priority
,
89 ntohl(neigh
->source_addr
.s_addr
),
90 ntohl(pim_ifp
->pim_dr_addr
.s_addr
));
92 if ((neigh
->dr_priority
> dr_pri
)
93 || ((neigh
->dr_priority
== dr_pri
)
94 && (ntohl(neigh
->source_addr
.s_addr
)
95 > ntohl(pim_ifp
->pim_dr_addr
.s_addr
)))) {
96 pim_ifp
->pim_dr_addr
= neigh
->source_addr
;
97 dr_pri
= neigh
->dr_priority
;
103 RFC 4601: 4.3.2. DR Election
105 A router's idea of the current DR on an interface can change when a
106 PIM Hello message is received, when a neighbor times out, or when a
107 router's own DR Priority changes.
109 int pim_if_dr_election(struct interface
*ifp
)
111 struct pim_interface
*pim_ifp
= ifp
->info
;
112 struct in_addr old_dr_addr
;
114 ++pim_ifp
->pim_dr_election_count
;
116 old_dr_addr
= pim_ifp
->pim_dr_addr
;
118 if (pim_ifp
->pim_dr_num_nondrpri_neighbors
) {
119 dr_election_by_addr(ifp
);
121 dr_election_by_pri(ifp
);
125 if (old_dr_addr
.s_addr
!= pim_ifp
->pim_dr_addr
.s_addr
) {
127 if (PIM_DEBUG_PIM_EVENTS
) {
128 char dr_old_str
[INET_ADDRSTRLEN
];
129 char dr_new_str
[INET_ADDRSTRLEN
];
130 pim_inet4_dump("<old_dr?>", old_dr_addr
, dr_old_str
,
132 pim_inet4_dump("<new_dr?>", pim_ifp
->pim_dr_addr
,
133 dr_new_str
, sizeof(dr_new_str
));
134 zlog_debug("%s: DR was %s now is %s on interface %s",
135 __func__
, dr_old_str
, dr_new_str
, ifp
->name
);
138 pim_ifp
->pim_dr_election_last
=
139 pim_time_monotonic_sec(); /* timestamp */
140 ++pim_ifp
->pim_dr_election_changes
;
141 pim_if_update_join_desired(pim_ifp
);
142 pim_if_update_could_assert(ifp
);
143 pim_if_update_assert_tracking_desired(ifp
);
150 static void update_dr_priority(struct pim_neighbor
*neigh
,
151 pim_hello_options hello_options
,
152 uint32_t dr_priority
)
154 pim_hello_options will_set_pri
; /* boolean */
155 pim_hello_options bit_flip
; /* boolean */
156 pim_hello_options pri_change
; /* boolean */
159 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
161 bit_flip
= (will_set_pri
162 != PIM_OPTION_IS_SET(neigh
->hello_options
,
163 PIM_OPTION_MASK_DR_PRIORITY
));
166 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
168 /* update num. of neighbors without dr_pri */
171 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
173 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
177 pri_change
= (bit_flip
|| (neigh
->dr_priority
!= dr_priority
));
180 neigh
->dr_priority
= dr_priority
;
182 neigh
->dr_priority
= 0; /* cosmetic unset */
187 RFC 4601: 4.3.2. DR Election
189 A router's idea of the current DR on an interface can change
191 PIM Hello message is received, when a neighbor times out, or
193 router's own DR Priority changes.
196 neigh
->interface
); // router's own DR Priority changes
200 static int on_neighbor_timer(struct thread
*t
)
202 struct pim_neighbor
*neigh
;
203 struct interface
*ifp
;
206 neigh
= THREAD_ARG(t
);
208 ifp
= neigh
->interface
;
210 if (PIM_DEBUG_PIM_TRACE
) {
211 char src_str
[INET_ADDRSTRLEN
];
212 pim_inet4_dump("<src?>", neigh
->source_addr
, src_str
,
215 "Expired %d sec holdtime for neighbor %s on interface %s",
216 neigh
->holdtime
, src_str
, ifp
->name
);
219 snprintf(msg
, sizeof(msg
), "%d-sec holdtime expired", neigh
->holdtime
);
220 pim_neighbor_delete(ifp
, neigh
, msg
);
223 RFC 4601: 4.3.2. DR Election
225 A router's idea of the current DR on an interface can change when a
226 PIM Hello message is received, when a neighbor times out, or when a
227 router's own DR Priority changes.
229 pim_if_dr_election(ifp
); // neighbor times out
234 void pim_neighbor_timer_reset(struct pim_neighbor
*neigh
, uint16_t holdtime
)
236 neigh
->holdtime
= holdtime
;
238 THREAD_OFF(neigh
->t_expire_timer
);
241 0xFFFF is request for no holdtime
243 if (neigh
->holdtime
== 0xFFFF) {
247 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
248 char src_str
[INET_ADDRSTRLEN
];
249 pim_inet4_dump("<src?>", neigh
->source_addr
, src_str
,
251 zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
252 __func__
, neigh
->holdtime
, src_str
,
253 neigh
->interface
->name
);
256 thread_add_timer(router
->master
, on_neighbor_timer
, neigh
,
257 neigh
->holdtime
, &neigh
->t_expire_timer
);
260 static int on_neighbor_jp_timer(struct thread
*t
)
262 struct pim_neighbor
*neigh
= THREAD_ARG(t
);
265 if (PIM_DEBUG_PIM_TRACE
) {
266 char src_str
[INET_ADDRSTRLEN
];
267 pim_inet4_dump("<src?>", neigh
->source_addr
, src_str
,
269 zlog_debug("%s:Sending JP Agg to %s on %s with %d groups",
270 __func__
, src_str
, neigh
->interface
->name
,
271 neigh
->upstream_jp_agg
->count
);
274 rpf
.source_nexthop
.interface
= neigh
->interface
;
275 rpf
.rpf_addr
.u
.prefix4
= neigh
->source_addr
;
276 pim_joinprune_send(&rpf
, neigh
->upstream_jp_agg
);
278 thread_add_timer(router
->master
, on_neighbor_jp_timer
, neigh
,
279 router
->t_periodic
, &neigh
->jp_timer
);
284 static void pim_neighbor_start_jp_timer(struct pim_neighbor
*neigh
)
286 THREAD_TIMER_OFF(neigh
->jp_timer
);
287 thread_add_timer(router
->master
, on_neighbor_jp_timer
, neigh
,
288 router
->t_periodic
, &neigh
->jp_timer
);
291 static struct pim_neighbor
*
292 pim_neighbor_new(struct interface
*ifp
, struct in_addr source_addr
,
293 pim_hello_options hello_options
, uint16_t holdtime
,
294 uint16_t propagation_delay
, uint16_t override_interval
,
295 uint32_t dr_priority
, uint32_t generation_id
,
296 struct list
*addr_list
)
298 struct pim_interface
*pim_ifp
;
299 struct pim_neighbor
*neigh
;
300 char src_str
[INET_ADDRSTRLEN
];
306 neigh
= XCALLOC(MTYPE_PIM_NEIGHBOR
, sizeof(*neigh
));
308 neigh
->creation
= pim_time_monotonic_sec();
309 neigh
->source_addr
= source_addr
;
310 neigh
->hello_options
= hello_options
;
311 neigh
->propagation_delay_msec
= propagation_delay
;
312 neigh
->override_interval_msec
= override_interval
;
313 neigh
->dr_priority
= dr_priority
;
314 neigh
->generation_id
= generation_id
;
315 neigh
->prefix_list
= addr_list
;
316 neigh
->t_expire_timer
= NULL
;
317 neigh
->interface
= ifp
;
319 neigh
->upstream_jp_agg
= list_new();
320 neigh
->upstream_jp_agg
->cmp
= pim_jp_agg_group_list_cmp
;
321 neigh
->upstream_jp_agg
->del
=
322 (void (*)(void *))pim_jp_agg_group_list_free
;
323 pim_neighbor_start_jp_timer(neigh
);
325 pim_neighbor_timer_reset(neigh
, holdtime
);
327 * The pim_ifstat_hello_sent variable is used to decide if
328 * we should expedite a hello out the interface. If we
329 * establish a new neighbor, we unfortunately need to
330 * reset the value so that we can know to hurry up and
333 pim_ifp
->pim_ifstat_hello_sent
= 0;
335 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
337 if (PIM_DEBUG_PIM_EVENTS
) {
338 zlog_debug("%s: creating PIM neighbor %s on interface %s",
339 __func__
, src_str
, ifp
->name
);
342 zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s", src_str
,
345 if (neigh
->propagation_delay_msec
346 > pim_ifp
->pim_neighbors_highest_propagation_delay_msec
) {
347 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
=
348 neigh
->propagation_delay_msec
;
350 if (neigh
->override_interval_msec
351 > pim_ifp
->pim_neighbors_highest_override_interval_msec
) {
352 pim_ifp
->pim_neighbors_highest_override_interval_msec
=
353 neigh
->override_interval_msec
;
356 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
357 PIM_OPTION_MASK_LAN_PRUNE_DELAY
)) {
358 /* update num. of neighbors without hello option lan_delay */
359 ++pim_ifp
->pim_number_of_nonlandelay_neighbors
;
362 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
363 PIM_OPTION_MASK_DR_PRIORITY
)) {
364 /* update num. of neighbors without hello option dr_pri */
365 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
368 // Register PIM Neighbor with BFD
369 pim_bfd_trigger_event(pim_ifp
, neigh
, 1);
374 static void delete_prefix_list(struct pim_neighbor
*neigh
)
376 if (neigh
->prefix_list
) {
378 #ifdef DUMP_PREFIX_LIST
379 struct listnode
*p_node
;
382 int list_size
= neigh
->prefix_list
383 ? (int)listcount(neigh
->prefix_list
)
386 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, p_node
, p
)) {
387 pim_inet4_dump("<addr?>", p
->u
.prefix4
, addr_str
,
390 "%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]",
391 __func__
, (unsigned)neigh
,
392 (unsigned)neigh
->prefix_list
, (unsigned)p
,
393 addr_str
, i
, list_size
);
398 list_delete(&neigh
->prefix_list
);
402 void pim_neighbor_free(struct pim_neighbor
*neigh
)
404 zassert(!neigh
->t_expire_timer
);
406 delete_prefix_list(neigh
);
408 list_delete(&neigh
->upstream_jp_agg
);
409 THREAD_OFF(neigh
->jp_timer
);
412 pim_bfd_info_free(&neigh
->bfd_info
);
414 XFREE(MTYPE_PIM_NEIGHBOR
, neigh
);
417 struct pim_neighbor
*pim_neighbor_find_by_secondary(struct interface
*ifp
,
420 struct pim_interface
*pim_ifp
;
421 struct listnode
*node
, *pnode
;
422 struct pim_neighbor
*neigh
;
425 if (!ifp
|| !ifp
->info
)
430 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
431 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, pnode
, p
)) {
432 if (prefix_same(p
, src
))
440 struct pim_neighbor
*pim_neighbor_find(struct interface
*ifp
,
441 struct in_addr source_addr
)
443 struct pim_interface
*pim_ifp
;
444 struct listnode
*node
;
445 struct pim_neighbor
*neigh
;
454 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
455 if (source_addr
.s_addr
== neigh
->source_addr
.s_addr
) {
464 * Find the *one* interface out
465 * this interface. If more than
468 struct pim_neighbor
*pim_neighbor_find_if(struct interface
*ifp
)
470 struct pim_interface
*pim_ifp
= ifp
->info
;
472 if (!pim_ifp
|| pim_ifp
->pim_neighbor_list
->count
!= 1)
475 return listnode_head(pim_ifp
->pim_neighbor_list
);
478 struct pim_neighbor
*
479 pim_neighbor_add(struct interface
*ifp
, struct in_addr source_addr
,
480 pim_hello_options hello_options
, uint16_t holdtime
,
481 uint16_t propagation_delay
, uint16_t override_interval
,
482 uint32_t dr_priority
, uint32_t generation_id
,
483 struct list
*addr_list
, int send_hello_now
)
485 struct pim_interface
*pim_ifp
;
486 struct pim_neighbor
*neigh
;
488 neigh
= pim_neighbor_new(ifp
, source_addr
, hello_options
, holdtime
,
489 propagation_delay
, override_interval
,
490 dr_priority
, generation_id
, addr_list
);
498 listnode_add(pim_ifp
->pim_neighbor_list
, neigh
);
500 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
501 char str
[INET_ADDRSTRLEN
];
502 pim_inet4_dump("<nht_nbr?>", source_addr
, str
, sizeof(str
));
503 zlog_debug("%s: neighbor %s added ", __func__
, str
);
506 RFC 4601: 4.3.2. DR Election
508 A router's idea of the current DR on an interface can change when a
509 PIM Hello message is received, when a neighbor times out, or when a
510 router's own DR Priority changes.
512 pim_if_dr_election(neigh
->interface
); // new neighbor -- should not
513 // trigger dr election...
516 RFC 4601: 4.3.1. Sending Hello Messages
518 To allow new or rebooting routers to learn of PIM neighbors quickly,
519 when a Hello message is received from a new neighbor, or a Hello
520 message with a new GenID is received from an existing neighbor, a
521 new Hello message should be sent on this interface after a
522 randomized delay between 0 and Triggered_Hello_Delay.
524 This is a bit silly to do it that way. If I get a new
525 genid we need to send the hello *now* because we've
526 lined up a bunch of join/prune messages to go out the
530 pim_hello_restart_now(ifp
);
532 pim_hello_restart_triggered(neigh
->interface
);
534 pim_upstream_find_new_rpf(pim_ifp
->pim
);
536 /* RNH can send nexthop update prior to PIM neibhor UP
537 in that case nexthop cache would not consider this neighbor
539 Upon PIM neighbor UP, iterate all RPs and update
540 nexthop cache with this neighbor.
542 pim_resolve_rp_nh(pim_ifp
->pim
, neigh
);
544 pim_rp_setup(pim_ifp
->pim
);
546 sched_rpf_cache_refresh(pim_ifp
->pim
);
550 static uint16_t find_neighbors_next_highest_propagation_delay_msec(
551 struct interface
*ifp
, struct pim_neighbor
*highest_neigh
)
553 struct pim_interface
*pim_ifp
;
554 struct listnode
*neigh_node
;
555 struct pim_neighbor
*neigh
;
556 uint16_t next_highest_delay_msec
;
561 next_highest_delay_msec
= pim_ifp
->pim_propagation_delay_msec
;
563 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
565 if (neigh
== highest_neigh
)
567 if (neigh
->propagation_delay_msec
> next_highest_delay_msec
)
568 next_highest_delay_msec
= neigh
->propagation_delay_msec
;
571 return next_highest_delay_msec
;
574 static uint16_t find_neighbors_next_highest_override_interval_msec(
575 struct interface
*ifp
, struct pim_neighbor
*highest_neigh
)
577 struct pim_interface
*pim_ifp
;
578 struct listnode
*neigh_node
;
579 struct pim_neighbor
*neigh
;
580 uint16_t next_highest_interval_msec
;
585 next_highest_interval_msec
= pim_ifp
->pim_override_interval_msec
;
587 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
589 if (neigh
== highest_neigh
)
591 if (neigh
->override_interval_msec
> next_highest_interval_msec
)
592 next_highest_interval_msec
=
593 neigh
->override_interval_msec
;
596 return next_highest_interval_msec
;
599 void pim_neighbor_delete(struct interface
*ifp
, struct pim_neighbor
*neigh
,
600 const char *delete_message
)
602 struct pim_interface
*pim_ifp
;
603 char src_str
[INET_ADDRSTRLEN
];
608 pim_inet4_dump("<src?>", neigh
->source_addr
, src_str
, sizeof(src_str
));
609 zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s", src_str
,
610 ifp
->name
, delete_message
);
612 THREAD_OFF(neigh
->t_expire_timer
);
614 pim_if_assert_on_neighbor_down(ifp
, neigh
->source_addr
);
616 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
617 PIM_OPTION_MASK_LAN_PRUNE_DELAY
)) {
618 /* update num. of neighbors without hello option lan_delay */
620 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
623 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
624 PIM_OPTION_MASK_DR_PRIORITY
)) {
625 /* update num. of neighbors without dr_pri */
627 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
630 zassert(neigh
->propagation_delay_msec
631 <= pim_ifp
->pim_neighbors_highest_propagation_delay_msec
);
632 zassert(neigh
->override_interval_msec
633 <= pim_ifp
->pim_neighbors_highest_override_interval_msec
);
635 if (pim_if_lan_delay_enabled(ifp
)) {
637 /* will delete a neighbor with highest propagation delay? */
638 if (neigh
->propagation_delay_msec
639 == pim_ifp
->pim_neighbors_highest_propagation_delay_msec
) {
640 /* then find the next highest propagation delay */
641 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
=
642 find_neighbors_next_highest_propagation_delay_msec(
646 /* will delete a neighbor with highest override interval? */
647 if (neigh
->override_interval_msec
648 == pim_ifp
->pim_neighbors_highest_override_interval_msec
) {
649 /* then find the next highest propagation delay */
650 pim_ifp
->pim_neighbors_highest_override_interval_msec
=
651 find_neighbors_next_highest_override_interval_msec(
656 if (PIM_DEBUG_PIM_TRACE
) {
657 zlog_debug("%s: deleting PIM neighbor %s on interface %s",
658 __func__
, src_str
, ifp
->name
);
661 // De-Register PIM Neighbor with BFD
662 pim_bfd_trigger_event(pim_ifp
, neigh
, 0);
664 listnode_delete(pim_ifp
->pim_neighbor_list
, neigh
);
666 pim_neighbor_free(neigh
);
668 sched_rpf_cache_refresh(pim_ifp
->pim
);
671 void pim_neighbor_delete_all(struct interface
*ifp
, const char *delete_message
)
673 struct pim_interface
*pim_ifp
;
674 struct listnode
*neigh_node
;
675 struct listnode
*neigh_nextnode
;
676 struct pim_neighbor
*neigh
;
681 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
, neigh_node
,
682 neigh_nextnode
, neigh
)) {
683 pim_neighbor_delete(ifp
, neigh
, delete_message
);
687 struct prefix
*pim_neighbor_find_secondary(struct pim_neighbor
*neigh
,
690 struct listnode
*node
;
693 if (!neigh
->prefix_list
)
696 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, node
, p
)) {
697 if (prefix_same(p
, addr
))
705 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
707 All the advertised secondary addresses in received Hello messages
708 must be checked against those previously advertised by all other
709 PIM neighbors on that interface. If there is a conflict and the
710 same secondary address was previously advertised by another
711 neighbor, then only the most recently received mapping MUST be
712 maintained, and an error message SHOULD be logged to the
713 administrator in a rate-limited manner.
715 static void delete_from_neigh_addr(struct interface
*ifp
,
716 struct list
*addr_list
,
717 struct in_addr neigh_addr
)
719 struct listnode
*addr_node
;
721 struct pim_interface
*pim_ifp
;
729 Scan secondary address list
731 for (ALL_LIST_ELEMENTS_RO(addr_list
, addr_node
, addr
)) {
732 struct listnode
*neigh_node
;
733 struct pim_neighbor
*neigh
;
735 if (addr
->family
!= AF_INET
)
741 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
,
742 neigh_node
, neigh
)) {
744 struct prefix
*p
= pim_neighbor_find_secondary(
747 char addr_str
[INET_ADDRSTRLEN
];
748 char this_neigh_str
[INET_ADDRSTRLEN
];
749 char other_neigh_str
[INET_ADDRSTRLEN
];
752 "<addr?>", addr
->u
.prefix4
,
753 addr_str
, sizeof(addr_str
));
754 pim_inet4_dump("<neigh1?>", neigh_addr
,
756 sizeof(this_neigh_str
));
757 pim_inet4_dump("<neigh2?>",
760 sizeof(other_neigh_str
));
763 "secondary addr %s recvd from neigh %s deleted from neigh %s on %s",
764 addr_str
, this_neigh_str
,
765 other_neigh_str
, ifp
->name
);
767 listnode_delete(neigh
->prefix_list
, p
);
772 } /* scan neighbors */
774 } /* scan addr list */
777 void pim_neighbor_update(struct pim_neighbor
*neigh
,
778 pim_hello_options hello_options
, uint16_t holdtime
,
779 uint32_t dr_priority
, struct list
*addr_list
)
781 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
784 /* Received holdtime ? */
785 if (PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
)) {
786 pim_neighbor_timer_reset(neigh
, holdtime
);
788 pim_neighbor_timer_reset(neigh
,
789 PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
792 #ifdef DUMP_PREFIX_LIST
794 "%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
795 __func__
, (unsigned)neigh
->prefix_list
,
796 neigh
->prefix_list
? (int)listcount(neigh
->prefix_list
) : -1,
798 addr_list
? (int)listcount(addr_list
) : -1);
801 if (neigh
->prefix_list
== addr_list
) {
805 "%s: internal error: trying to replace same prefix list=%p",
806 __func__
, (void *)addr_list
);
809 /* Delete existing secondary address list */
810 delete_prefix_list(neigh
);
814 delete_from_neigh_addr(neigh
->interface
, addr_list
,
818 /* Replace secondary address list */
819 neigh
->prefix_list
= addr_list
;
821 update_dr_priority(neigh
, hello_options
, dr_priority
);
822 new = PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
823 old
= PIM_OPTION_IS_SET(neigh
->hello_options
,
824 PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
828 ++pim_ifp
->pim_number_of_nonlandelay_neighbors
;
830 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
835 neigh
->hello_options
= hello_options
;