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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
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"
43 static void dr_election_by_addr(struct interface
*ifp
)
45 struct pim_interface
*pim_ifp
;
46 struct listnode
*node
;
47 struct pim_neighbor
*neigh
;
52 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
54 if (PIM_DEBUG_PIM_TRACE
) {
55 zlog_debug("%s: on interface %s",
60 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
61 if (ntohl(neigh
->source_addr
.s_addr
) > 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",
86 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
87 if (PIM_DEBUG_PIM_TRACE
) {
88 zlog_info("%s: neigh pri %u addr %x if dr addr %x",
91 ntohl(neigh
->source_addr
.s_addr
),
92 ntohl(pim_ifp
->pim_dr_addr
.s_addr
));
95 (neigh
->dr_priority
> dr_pri
) ||
97 (neigh
->dr_priority
== dr_pri
) &&
98 (ntohl(neigh
->source_addr
.s_addr
) > ntohl(pim_ifp
->pim_dr_addr
.s_addr
))
101 pim_ifp
->pim_dr_addr
= neigh
->source_addr
;
102 dr_pri
= neigh
->dr_priority
;
108 RFC 4601: 4.3.2. DR Election
110 A router's idea of the current DR on an interface can change when a
111 PIM Hello message is received, when a neighbor times out, or when a
112 router's own DR Priority changes.
114 int pim_if_dr_election(struct interface
*ifp
)
116 struct pim_interface
*pim_ifp
= ifp
->info
;
117 struct in_addr old_dr_addr
;
119 ++pim_ifp
->pim_dr_election_count
;
121 old_dr_addr
= pim_ifp
->pim_dr_addr
;
123 if (pim_ifp
->pim_dr_num_nondrpri_neighbors
) {
124 dr_election_by_addr(ifp
);
127 dr_election_by_pri(ifp
);
131 if (old_dr_addr
.s_addr
!= pim_ifp
->pim_dr_addr
.s_addr
) {
133 if (PIM_DEBUG_PIM_EVENTS
) {
134 char dr_old_str
[INET_ADDRSTRLEN
];
135 char dr_new_str
[INET_ADDRSTRLEN
];
136 pim_inet4_dump("<old_dr?>", old_dr_addr
, dr_old_str
, sizeof(dr_old_str
));
137 pim_inet4_dump("<new_dr?>", pim_ifp
->pim_dr_addr
, dr_new_str
, sizeof(dr_new_str
));
138 zlog_debug("%s: DR was %s now is %s on interface %s",
140 dr_old_str
, dr_new_str
, ifp
->name
);
143 pim_ifp
->pim_dr_election_last
= pim_time_monotonic_sec(); /* timestamp */
144 ++pim_ifp
->pim_dr_election_changes
;
145 pim_if_update_join_desired(pim_ifp
);
146 pim_if_update_could_assert(ifp
);
147 pim_if_update_assert_tracking_desired(ifp
);
154 static void update_dr_priority(struct pim_neighbor
*neigh
,
155 pim_hello_options hello_options
,
156 uint32_t dr_priority
)
158 pim_hello_options will_set_pri
; /* boolean */
159 pim_hello_options bit_flip
; /* boolean */
160 pim_hello_options pri_change
; /* boolean */
162 will_set_pri
= PIM_OPTION_IS_SET(hello_options
,
163 PIM_OPTION_MASK_DR_PRIORITY
);
168 PIM_OPTION_IS_SET(neigh
->hello_options
, PIM_OPTION_MASK_DR_PRIORITY
)
172 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
174 /* update num. of neighbors without dr_pri */
177 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
180 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
188 (neigh
->dr_priority
!= dr_priority
)
192 neigh
->dr_priority
= dr_priority
;
195 neigh
->dr_priority
= 0; /* cosmetic unset */
200 RFC 4601: 4.3.2. DR Election
202 A router's idea of the current DR on an interface can change when a
203 PIM Hello message is received, when a neighbor times out, or when a
204 router's own DR Priority changes.
206 pim_if_dr_election(neigh
->interface
); // router's own DR Priority changes
210 static int on_neighbor_timer(struct thread
*t
)
212 struct pim_neighbor
*neigh
;
213 struct interface
*ifp
;
216 neigh
= THREAD_ARG(t
);
218 ifp
= neigh
->interface
;
220 if (PIM_DEBUG_PIM_TRACE
) {
221 char src_str
[INET_ADDRSTRLEN
];
222 pim_inet4_dump("<src?>", neigh
->source_addr
, src_str
, sizeof(src_str
));
223 zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
224 neigh
->holdtime
, src_str
, ifp
->name
);
227 neigh
->t_expire_timer
= NULL
;
229 snprintf(msg
, sizeof(msg
), "%d-sec holdtime expired", neigh
->holdtime
);
230 pim_neighbor_delete(ifp
, neigh
, msg
);
233 RFC 4601: 4.3.2. DR Election
235 A router's idea of the current DR on an interface can change when a
236 PIM Hello message is received, when a neighbor times out, or when a
237 router's own DR Priority changes.
239 pim_if_dr_election(ifp
); // neighbor times out
244 void pim_neighbor_timer_reset(struct pim_neighbor
*neigh
, uint16_t holdtime
)
246 neigh
->holdtime
= holdtime
;
248 THREAD_OFF(neigh
->t_expire_timer
);
251 0xFFFF is request for no holdtime
253 if (neigh
->holdtime
== 0xFFFF) {
257 if (PIM_DEBUG_PIM_TRACE_DETAIL
) {
258 char src_str
[INET_ADDRSTRLEN
];
259 pim_inet4_dump("<src?>", neigh
->source_addr
, src_str
, sizeof(src_str
));
260 zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
262 neigh
->holdtime
, src_str
, neigh
->interface
->name
);
265 thread_add_timer(master
, on_neighbor_timer
, neigh
, neigh
->holdtime
,
266 &neigh
->t_expire_timer
);
270 on_neighbor_jp_timer (struct thread
*t
)
272 struct pim_neighbor
*neigh
= THREAD_ARG(t
);
275 if (PIM_DEBUG_PIM_TRACE
)
277 char src_str
[INET_ADDRSTRLEN
];
278 pim_inet4_dump("<src?>", neigh
->source_addr
, src_str
, sizeof(src_str
));
279 zlog_debug("%s:Sending JP Agg to %s on %s with %d groups", __PRETTY_FUNCTION__
,
280 src_str
, neigh
->interface
->name
, neigh
->upstream_jp_agg
->count
);
282 neigh
->jp_timer
= NULL
;
284 rpf
.source_nexthop
.interface
= neigh
->interface
;
285 rpf
.rpf_addr
.u
.prefix4
= neigh
->source_addr
;
286 pim_joinprune_send(&rpf
, neigh
->upstream_jp_agg
);
288 thread_add_timer(master
, on_neighbor_jp_timer
, neigh
, qpim_t_periodic
,
295 pim_neighbor_start_jp_timer (struct pim_neighbor
*neigh
)
297 THREAD_TIMER_OFF(neigh
->jp_timer
);
298 thread_add_timer(master
, on_neighbor_jp_timer
, neigh
, qpim_t_periodic
,
302 static struct pim_neighbor
*pim_neighbor_new(struct interface
*ifp
,
303 struct in_addr source_addr
,
304 pim_hello_options hello_options
,
306 uint16_t propagation_delay
,
307 uint16_t override_interval
,
308 uint32_t dr_priority
,
309 uint32_t generation_id
,
310 struct list
*addr_list
)
312 struct pim_interface
*pim_ifp
;
313 struct pim_neighbor
*neigh
;
314 char src_str
[INET_ADDRSTRLEN
];
320 neigh
= XCALLOC(MTYPE_PIM_NEIGHBOR
, sizeof(*neigh
));
322 zlog_err("%s: PIM XCALLOC(%zu) failure",
323 __PRETTY_FUNCTION__
, sizeof(*neigh
));
327 neigh
->creation
= pim_time_monotonic_sec();
328 neigh
->source_addr
= source_addr
;
329 neigh
->hello_options
= hello_options
;
330 neigh
->propagation_delay_msec
= propagation_delay
;
331 neigh
->override_interval_msec
= override_interval
;
332 neigh
->dr_priority
= dr_priority
;
333 neigh
->generation_id
= generation_id
;
334 neigh
->prefix_list
= addr_list
;
335 neigh
->t_expire_timer
= NULL
;
336 neigh
->interface
= ifp
;
338 neigh
->upstream_jp_agg
= list_new();
339 neigh
->upstream_jp_agg
->cmp
= pim_jp_agg_group_list_cmp
;
340 neigh
->upstream_jp_agg
->del
= (void (*)(void *))pim_jp_agg_group_list_free
;
341 pim_neighbor_start_jp_timer(neigh
);
343 pim_neighbor_timer_reset(neigh
, holdtime
);
345 * The pim_ifstat_hello_sent variable is used to decide if
346 * we should expedite a hello out the interface. If we
347 * establish a new neighbor, we unfortunately need to
348 * reset the value so that we can know to hurry up and
351 pim_ifp
->pim_ifstat_hello_sent
= 0;
353 pim_inet4_dump("<src?>", source_addr
, src_str
, sizeof(src_str
));
355 if (PIM_DEBUG_PIM_EVENTS
) {
356 zlog_debug("%s: creating PIM neighbor %s on interface %s",
361 zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s",
364 if (neigh
->propagation_delay_msec
> pim_ifp
->pim_neighbors_highest_propagation_delay_msec
) {
365 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
= neigh
->propagation_delay_msec
;
367 if (neigh
->override_interval_msec
> pim_ifp
->pim_neighbors_highest_override_interval_msec
) {
368 pim_ifp
->pim_neighbors_highest_override_interval_msec
= neigh
->override_interval_msec
;
371 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
372 PIM_OPTION_MASK_LAN_PRUNE_DELAY
)) {
373 /* update num. of neighbors without hello option lan_delay */
374 ++pim_ifp
->pim_number_of_nonlandelay_neighbors
;
377 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
378 PIM_OPTION_MASK_DR_PRIORITY
)) {
379 /* update num. of neighbors without hello option dr_pri */
380 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
386 static void delete_prefix_list(struct pim_neighbor
*neigh
)
388 if (neigh
->prefix_list
) {
390 #ifdef DUMP_PREFIX_LIST
391 struct listnode
*p_node
;
394 int list_size
= neigh
->prefix_list
? (int) listcount(neigh
->prefix_list
) : -1;
396 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, p_node
, p
)) {
397 pim_inet4_dump("<addr?>", p
->u
.prefix4
, addr_str
, sizeof(addr_str
));
398 zlog_debug("%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]",
400 (unsigned) neigh
, (unsigned) neigh
->prefix_list
, (unsigned) p
,
401 addr_str
, i
, list_size
);
406 list_delete(neigh
->prefix_list
);
407 neigh
->prefix_list
= 0;
411 void pim_neighbor_free(struct pim_neighbor
*neigh
)
413 zassert(!neigh
->t_expire_timer
);
415 delete_prefix_list(neigh
);
417 list_delete(neigh
->upstream_jp_agg
);
418 THREAD_OFF(neigh
->jp_timer
);
420 XFREE(MTYPE_PIM_NEIGHBOR
, neigh
);
423 struct pim_neighbor
*
424 pim_neighbor_find_by_secondary (struct interface
*ifp
,
427 struct pim_interface
*pim_ifp
;
428 struct listnode
*node
, *pnode
;
429 struct pim_neighbor
*neigh
;
436 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
))
438 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, pnode
, p
))
440 if (prefix_same (p
, src
))
448 struct pim_neighbor
*pim_neighbor_find(struct interface
*ifp
,
449 struct in_addr source_addr
)
451 struct pim_interface
*pim_ifp
;
452 struct listnode
*node
;
453 struct pim_neighbor
*neigh
;
462 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
463 if (source_addr
.s_addr
== neigh
->source_addr
.s_addr
) {
472 * Find the *one* interface out
473 * this interface. If more than
476 struct pim_neighbor
*
477 pim_neighbor_find_if (struct interface
*ifp
)
479 struct pim_interface
*pim_ifp
= ifp
->info
;
481 if (!pim_ifp
|| pim_ifp
->pim_neighbor_list
->count
!= 1)
484 return listnode_head (pim_ifp
->pim_neighbor_list
);
487 /* rpf info associated with an upstream entry needs to be re-evaluated
488 * when an RPF neighbor comes or goes */
490 pim_neighbor_rpf_update(void)
492 /* XXX: for the time being piggyback on the timer used on rib changes
493 * to scan and update the rpf nexthop. This is expensive processing
494 * and we should be able to optimize neighbor changes differently than
495 * nexthop changes. */
496 sched_rpf_cache_refresh();
499 struct pim_neighbor
*pim_neighbor_add(struct interface
*ifp
,
500 struct in_addr source_addr
,
501 pim_hello_options hello_options
,
503 uint16_t propagation_delay
,
504 uint16_t override_interval
,
505 uint32_t dr_priority
,
506 uint32_t generation_id
,
507 struct list
*addr_list
,
510 struct pim_interface
*pim_ifp
;
511 struct pim_neighbor
*neigh
;
513 neigh
= pim_neighbor_new(ifp
, source_addr
,
528 listnode_add(pim_ifp
->pim_neighbor_list
, neigh
);
530 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
532 char str
[INET_ADDRSTRLEN
];
533 pim_inet4_dump("<nht_nbr?>", source_addr
, str
, sizeof (str
));
534 zlog_debug ("%s: neighbor %s added ", __PRETTY_FUNCTION__
, str
);
537 RFC 4601: 4.3.2. DR Election
539 A router's idea of the current DR on an interface can change when a
540 PIM Hello message is received, when a neighbor times out, or when a
541 router's own DR Priority changes.
543 pim_if_dr_election(neigh
->interface
); // new neighbor -- should not trigger dr election...
546 RFC 4601: 4.3.1. Sending Hello Messages
548 To allow new or rebooting routers to learn of PIM neighbors quickly,
549 when a Hello message is received from a new neighbor, or a Hello
550 message with a new GenID is received from an existing neighbor, a
551 new Hello message should be sent on this interface after a
552 randomized delay between 0 and Triggered_Hello_Delay.
554 This is a bit silly to do it that way. If I get a new
555 genid we need to send the hello *now* because we've
556 lined up a bunch of join/prune messages to go out the
560 pim_hello_restart_now (ifp
);
562 pim_hello_restart_triggered(neigh
->interface
);
564 pim_upstream_find_new_rpf();
566 /* RNH can send nexthop update prior to PIM neibhor UP
567 in that case nexthop cache would not consider this neighbor
569 Upon PIM neighbor UP, iterate all RPs and update
570 nexthop cache with this neighbor.
572 pim_resolve_rp_nh ();
576 pim_neighbor_rpf_update();
581 find_neighbors_next_highest_propagation_delay_msec(struct interface
*ifp
,
582 struct pim_neighbor
*highest_neigh
)
584 struct pim_interface
*pim_ifp
;
585 struct listnode
*neigh_node
;
586 struct pim_neighbor
*neigh
;
587 uint16_t next_highest_delay_msec
;
592 next_highest_delay_msec
= pim_ifp
->pim_propagation_delay_msec
;
594 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
, neigh
)) {
595 if (neigh
== highest_neigh
)
597 if (neigh
->propagation_delay_msec
> next_highest_delay_msec
)
598 next_highest_delay_msec
= neigh
->propagation_delay_msec
;
601 return next_highest_delay_msec
;
605 find_neighbors_next_highest_override_interval_msec(struct interface
*ifp
,
606 struct pim_neighbor
*highest_neigh
)
608 struct pim_interface
*pim_ifp
;
609 struct listnode
*neigh_node
;
610 struct pim_neighbor
*neigh
;
611 uint16_t next_highest_interval_msec
;
616 next_highest_interval_msec
= pim_ifp
->pim_override_interval_msec
;
618 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
, neigh
)) {
619 if (neigh
== highest_neigh
)
621 if (neigh
->override_interval_msec
> next_highest_interval_msec
)
622 next_highest_interval_msec
= neigh
->override_interval_msec
;
625 return next_highest_interval_msec
;
628 void pim_neighbor_delete(struct interface
*ifp
,
629 struct pim_neighbor
*neigh
,
630 const char *delete_message
)
632 struct pim_interface
*pim_ifp
;
633 char src_str
[INET_ADDRSTRLEN
];
638 pim_inet4_dump("<src?>", neigh
->source_addr
, src_str
, sizeof(src_str
));
639 zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
640 src_str
, ifp
->name
, delete_message
);
642 THREAD_OFF(neigh
->t_expire_timer
);
644 pim_if_assert_on_neighbor_down(ifp
, neigh
->source_addr
);
646 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
647 PIM_OPTION_MASK_LAN_PRUNE_DELAY
)) {
648 /* update num. of neighbors without hello option lan_delay */
650 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
653 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
654 PIM_OPTION_MASK_DR_PRIORITY
)) {
655 /* update num. of neighbors without dr_pri */
657 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
660 zassert(neigh
->propagation_delay_msec
<= pim_ifp
->pim_neighbors_highest_propagation_delay_msec
);
661 zassert(neigh
->override_interval_msec
<= pim_ifp
->pim_neighbors_highest_override_interval_msec
);
663 if (pim_if_lan_delay_enabled(ifp
)) {
665 /* will delete a neighbor with highest propagation delay? */
666 if (neigh
->propagation_delay_msec
== pim_ifp
->pim_neighbors_highest_propagation_delay_msec
) {
667 /* then find the next highest propagation delay */
668 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
=
669 find_neighbors_next_highest_propagation_delay_msec(ifp
, neigh
);
672 /* will delete a neighbor with highest override interval? */
673 if (neigh
->override_interval_msec
== pim_ifp
->pim_neighbors_highest_override_interval_msec
) {
674 /* then find the next highest propagation delay */
675 pim_ifp
->pim_neighbors_highest_override_interval_msec
=
676 find_neighbors_next_highest_override_interval_msec(ifp
, neigh
);
680 if (PIM_DEBUG_PIM_TRACE
) {
681 zlog_debug("%s: deleting PIM neighbor %s on interface %s",
686 listnode_delete(pim_ifp
->pim_neighbor_list
, neigh
);
688 pim_neighbor_free(neigh
);
690 pim_neighbor_rpf_update();
693 void pim_neighbor_delete_all(struct interface
*ifp
,
694 const char *delete_message
)
696 struct pim_interface
*pim_ifp
;
697 struct listnode
*neigh_node
;
698 struct listnode
*neigh_nextnode
;
699 struct pim_neighbor
*neigh
;
704 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
, neigh_node
,
705 neigh_nextnode
, neigh
)) {
706 pim_neighbor_delete(ifp
, neigh
, delete_message
);
710 struct prefix
*pim_neighbor_find_secondary(struct pim_neighbor
*neigh
,
713 struct listnode
*node
;
716 if (!neigh
->prefix_list
)
719 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, node
, p
)) {
720 if (prefix_same (p
, addr
))
728 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
730 All the advertised secondary addresses in received Hello messages
731 must be checked against those previously advertised by all other
732 PIM neighbors on that interface. If there is a conflict and the
733 same secondary address was previously advertised by another
734 neighbor, then only the most recently received mapping MUST be
735 maintained, and an error message SHOULD be logged to the
736 administrator in a rate-limited manner.
738 static void delete_from_neigh_addr(struct interface
*ifp
,
739 struct list
*addr_list
,
740 struct in_addr neigh_addr
)
742 struct listnode
*addr_node
;
744 struct pim_interface
*pim_ifp
;
752 Scan secondary address list
754 for (ALL_LIST_ELEMENTS_RO(addr_list
, addr_node
,
756 struct listnode
*neigh_node
;
757 struct pim_neighbor
*neigh
;
759 if (addr
->family
!= AF_INET
)
765 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
768 struct prefix
*p
= pim_neighbor_find_secondary(neigh
, addr
);
770 char addr_str
[INET_ADDRSTRLEN
];
771 char this_neigh_str
[INET_ADDRSTRLEN
];
772 char other_neigh_str
[INET_ADDRSTRLEN
];
774 pim_inet4_dump("<addr?>", addr
->u
.prefix4
, addr_str
, sizeof(addr_str
));
775 pim_inet4_dump("<neigh1?>", neigh_addr
, this_neigh_str
, sizeof(this_neigh_str
));
776 pim_inet4_dump("<neigh2?>", neigh
->source_addr
, other_neigh_str
, sizeof(other_neigh_str
));
778 zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s",
779 addr_str
, this_neigh_str
, other_neigh_str
, ifp
->name
);
781 listnode_delete(neigh
->prefix_list
, p
);
786 } /* scan neighbors */
788 } /* scan addr list */
792 void pim_neighbor_update(struct pim_neighbor
*neigh
,
793 pim_hello_options hello_options
,
795 uint32_t dr_priority
,
796 struct list
*addr_list
)
798 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
800 /* Received holdtime ? */
801 if (PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
)) {
802 pim_neighbor_timer_reset(neigh
, holdtime
);
805 pim_neighbor_timer_reset(neigh
, PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
808 #ifdef DUMP_PREFIX_LIST
809 zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
811 (unsigned) neigh
->prefix_list
,
812 neigh
->prefix_list
? (int) listcount(neigh
->prefix_list
) : -1,
813 (unsigned) addr_list
,
814 addr_list
? (int) listcount(addr_list
) : -1);
817 if (neigh
->prefix_list
== addr_list
) {
819 zlog_err("%s: internal error: trying to replace same prefix list=%p",
820 __PRETTY_FUNCTION__
, (void *) addr_list
);
824 /* Delete existing secondary address list */
825 delete_prefix_list(neigh
);
829 delete_from_neigh_addr(neigh
->interface
, addr_list
, neigh
->source_addr
);
832 /* Replace secondary address list */
833 neigh
->prefix_list
= addr_list
;
835 update_dr_priority(neigh
,
841 neigh
->hello_options
= hello_options
;