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"
43 #include "pim_register.h"
45 static void dr_election_by_addr(struct interface
*ifp
)
47 struct pim_interface
*pim_ifp
;
48 struct listnode
*node
;
49 struct pim_neighbor
*neigh
;
54 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
56 if (PIM_DEBUG_PIM_TRACE
) {
57 zlog_debug("%s: on interface %s", __func__
, ifp
->name
);
60 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
61 if (pim_addr_cmp(neigh
->source_addr
, pim_ifp
->pim_dr_addr
) > 0)
62 pim_ifp
->pim_dr_addr
= neigh
->source_addr
;
66 static void dr_election_by_pri(struct interface
*ifp
)
68 struct pim_interface
*pim_ifp
;
69 struct listnode
*node
;
70 struct pim_neighbor
*neigh
;
76 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
77 dr_pri
= pim_ifp
->pim_dr_priority
;
79 if (PIM_DEBUG_PIM_TRACE
) {
80 zlog_debug("%s: dr pri %u on interface %s", __func__
, dr_pri
,
84 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
85 if (PIM_DEBUG_PIM_TRACE
) {
86 zlog_info("%s: neigh pri %u addr %pPA if dr addr %pPA",
87 __func__
, neigh
->dr_priority
,
88 &neigh
->source_addr
, &pim_ifp
->pim_dr_addr
);
90 if ((neigh
->dr_priority
> dr_pri
) ||
91 ((neigh
->dr_priority
== dr_pri
) &&
92 (pim_addr_cmp(neigh
->source_addr
, pim_ifp
->pim_dr_addr
) >
94 pim_ifp
->pim_dr_addr
= neigh
->source_addr
;
95 dr_pri
= neigh
->dr_priority
;
101 RFC 4601: 4.3.2. DR Election
103 A router's idea of the current DR on an interface can change when a
104 PIM Hello message is received, when a neighbor times out, or when a
105 router's own DR Priority changes.
107 int pim_if_dr_election(struct interface
*ifp
)
109 struct pim_interface
*pim_ifp
= ifp
->info
;
110 pim_addr old_dr_addr
;
112 ++pim_ifp
->pim_dr_election_count
;
114 old_dr_addr
= pim_ifp
->pim_dr_addr
;
116 if (pim_ifp
->pim_dr_num_nondrpri_neighbors
) {
117 dr_election_by_addr(ifp
);
119 dr_election_by_pri(ifp
);
123 if (pim_addr_cmp(old_dr_addr
, pim_ifp
->pim_dr_addr
)) {
125 if (PIM_DEBUG_PIM_EVENTS
)
127 "%s: DR was %pPA now is %pPA on interface %s",
128 __func__
, &old_dr_addr
, &pim_ifp
->pim_dr_addr
,
131 pim_ifp
->pim_dr_election_last
=
132 pim_time_monotonic_sec(); /* timestamp */
133 ++pim_ifp
->pim_dr_election_changes
;
134 pim_if_update_join_desired(pim_ifp
);
135 pim_if_update_could_assert(ifp
);
136 pim_if_update_assert_tracking_desired(ifp
);
138 if (PIM_I_am_DR(pim_ifp
))
139 pim_ifp
->am_i_dr
= true;
141 if (pim_ifp
->am_i_dr
== true) {
142 pim_reg_del_on_couldreg_fail(ifp
);
143 pim_ifp
->am_i_dr
= false;
153 static void update_dr_priority(struct pim_neighbor
*neigh
,
154 pim_hello_options hello_options
,
155 uint32_t dr_priority
)
157 pim_hello_options will_set_pri
; /* boolean */
158 pim_hello_options bit_flip
; /* boolean */
159 pim_hello_options pri_change
; /* boolean */
162 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
164 bit_flip
= (will_set_pri
165 != PIM_OPTION_IS_SET(neigh
->hello_options
,
166 PIM_OPTION_MASK_DR_PRIORITY
));
169 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
171 /* update num. of neighbors without dr_pri */
174 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
176 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
180 pri_change
= (bit_flip
|| (neigh
->dr_priority
!= dr_priority
));
183 neigh
->dr_priority
= dr_priority
;
185 neigh
->dr_priority
= 0; /* cosmetic unset */
190 RFC 4601: 4.3.2. DR Election
192 A router's idea of the current DR on an interface can change
194 PIM Hello message is received, when a neighbor times out, or
196 router's own DR Priority changes.
199 neigh
->interface
); // router's own DR Priority changes
203 static void on_neighbor_timer(struct thread
*t
)
205 struct pim_neighbor
*neigh
;
206 struct interface
*ifp
;
209 neigh
= THREAD_ARG(t
);
211 ifp
= neigh
->interface
;
213 if (PIM_DEBUG_PIM_TRACE
)
215 "Expired %d sec holdtime for neighbor %pPA on interface %s",
216 neigh
->holdtime
, &neigh
->source_addr
, ifp
->name
);
218 snprintf(msg
, sizeof(msg
), "%d-sec holdtime expired", neigh
->holdtime
);
219 pim_neighbor_delete(ifp
, neigh
, msg
);
222 RFC 4601: 4.3.2. DR Election
224 A router's idea of the current DR on an interface can change when a
225 PIM Hello message is received, when a neighbor times out, or when a
226 router's own DR Priority changes.
228 pim_if_dr_election(ifp
); // neighbor times out
231 void pim_neighbor_timer_reset(struct pim_neighbor
*neigh
, uint16_t holdtime
)
233 neigh
->holdtime
= holdtime
;
235 THREAD_OFF(neigh
->t_expire_timer
);
238 0xFFFF is request for no holdtime
240 if (neigh
->holdtime
== 0xFFFF) {
244 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
245 zlog_debug("%s: starting %u sec timer for neighbor %pPA on %s",
246 __func__
, neigh
->holdtime
, &neigh
->source_addr
,
247 neigh
->interface
->name
);
249 thread_add_timer(router
->master
, on_neighbor_timer
, neigh
,
250 neigh
->holdtime
, &neigh
->t_expire_timer
);
253 static void on_neighbor_jp_timer(struct thread
*t
)
255 struct pim_neighbor
*neigh
= THREAD_ARG(t
);
258 if (PIM_DEBUG_PIM_TRACE
)
259 zlog_debug("%s:Sending JP Agg to %pPA on %s with %d groups",
260 __func__
, &neigh
->source_addr
,
261 neigh
->interface
->name
,
262 neigh
->upstream_jp_agg
->count
);
264 rpf
.source_nexthop
.interface
= neigh
->interface
;
265 pim_addr_to_prefix(&rpf
.rpf_addr
, neigh
->source_addr
);
266 pim_joinprune_send(&rpf
, neigh
->upstream_jp_agg
);
268 thread_add_timer(router
->master
, on_neighbor_jp_timer
, neigh
,
269 router
->t_periodic
, &neigh
->jp_timer
);
272 static void pim_neighbor_start_jp_timer(struct pim_neighbor
*neigh
)
274 THREAD_OFF(neigh
->jp_timer
);
275 thread_add_timer(router
->master
, on_neighbor_jp_timer
, neigh
,
276 router
->t_periodic
, &neigh
->jp_timer
);
279 static struct pim_neighbor
*
280 pim_neighbor_new(struct interface
*ifp
, pim_addr source_addr
,
281 pim_hello_options hello_options
, uint16_t holdtime
,
282 uint16_t propagation_delay
, uint16_t override_interval
,
283 uint32_t dr_priority
, uint32_t generation_id
,
284 struct list
*addr_list
)
286 struct pim_interface
*pim_ifp
;
287 struct pim_neighbor
*neigh
;
293 neigh
= XCALLOC(MTYPE_PIM_NEIGHBOR
, sizeof(*neigh
));
295 neigh
->creation
= pim_time_monotonic_sec();
296 neigh
->source_addr
= source_addr
;
297 neigh
->hello_options
= hello_options
;
298 neigh
->propagation_delay_msec
= propagation_delay
;
299 neigh
->override_interval_msec
= override_interval
;
300 neigh
->dr_priority
= dr_priority
;
301 neigh
->generation_id
= generation_id
;
302 neigh
->prefix_list
= addr_list
;
303 neigh
->t_expire_timer
= NULL
;
304 neigh
->interface
= ifp
;
306 neigh
->upstream_jp_agg
= list_new();
307 neigh
->upstream_jp_agg
->cmp
= pim_jp_agg_group_list_cmp
;
308 neigh
->upstream_jp_agg
->del
=
309 (void (*)(void *))pim_jp_agg_group_list_free
;
310 pim_neighbor_start_jp_timer(neigh
);
312 pim_neighbor_timer_reset(neigh
, holdtime
);
314 * The pim_ifstat_hello_sent variable is used to decide if
315 * we should expedite a hello out the interface. If we
316 * establish a new neighbor, we unfortunately need to
317 * reset the value so that we can know to hurry up and
320 PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp
->flags
);
322 if (PIM_DEBUG_PIM_EVENTS
)
323 zlog_debug("%s: creating PIM neighbor %pPA on interface %s",
324 __func__
, &source_addr
, ifp
->name
);
326 zlog_notice("PIM NEIGHBOR UP: neighbor %pPA on interface %s",
327 &source_addr
, ifp
->name
);
329 if (neigh
->propagation_delay_msec
330 > pim_ifp
->pim_neighbors_highest_propagation_delay_msec
) {
331 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
=
332 neigh
->propagation_delay_msec
;
334 if (neigh
->override_interval_msec
335 > pim_ifp
->pim_neighbors_highest_override_interval_msec
) {
336 pim_ifp
->pim_neighbors_highest_override_interval_msec
=
337 neigh
->override_interval_msec
;
340 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
341 PIM_OPTION_MASK_LAN_PRUNE_DELAY
)) {
342 /* update num. of neighbors without hello option lan_delay */
343 ++pim_ifp
->pim_number_of_nonlandelay_neighbors
;
346 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
347 PIM_OPTION_MASK_DR_PRIORITY
)) {
348 /* update num. of neighbors without hello option dr_pri */
349 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
352 // Register PIM Neighbor with BFD
353 pim_bfd_info_nbr_create(pim_ifp
, neigh
);
358 static void delete_prefix_list(struct pim_neighbor
*neigh
)
360 if (neigh
->prefix_list
) {
362 #ifdef DUMP_PREFIX_LIST
363 struct listnode
*p_node
;
366 int list_size
= neigh
->prefix_list
367 ? (int)listcount(neigh
->prefix_list
)
370 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, p_node
, p
)) {
371 pim_inet4_dump("<addr?>", p
->u
.prefix4
, addr_str
,
374 "%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]",
375 __func__
, (unsigned)neigh
,
376 (unsigned)neigh
->prefix_list
, (unsigned)p
,
377 addr_str
, i
, list_size
);
382 list_delete(&neigh
->prefix_list
);
386 void pim_neighbor_free(struct pim_neighbor
*neigh
)
388 assert(!neigh
->t_expire_timer
);
390 delete_prefix_list(neigh
);
392 list_delete(&neigh
->upstream_jp_agg
);
393 THREAD_OFF(neigh
->jp_timer
);
395 bfd_sess_free(&neigh
->bfd_session
);
397 XFREE(MTYPE_PIM_NEIGHBOR
, neigh
);
400 struct pim_neighbor
*pim_neighbor_find_by_secondary(struct interface
*ifp
,
403 struct pim_interface
*pim_ifp
;
404 struct listnode
*node
, *pnode
;
405 struct pim_neighbor
*neigh
;
408 if (!ifp
|| !ifp
->info
)
413 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
414 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, pnode
, p
)) {
415 if (prefix_same(p
, src
))
423 struct pim_neighbor
*pim_neighbor_find(struct interface
*ifp
,
424 pim_addr source_addr
)
426 struct pim_interface
*pim_ifp
;
427 struct listnode
*node
;
428 struct pim_neighbor
*neigh
;
437 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
438 if (!pim_addr_cmp(source_addr
, neigh
->source_addr
)) {
446 struct pim_neighbor
*pim_neighbor_find_prefix(struct interface
*ifp
,
447 const struct prefix
*src_prefix
)
451 addr
= pim_addr_from_prefix(src_prefix
);
452 return pim_neighbor_find(ifp
, addr
);
456 * Find the *one* interface out
457 * this interface. If more than
460 struct pim_neighbor
*pim_neighbor_find_if(struct interface
*ifp
)
462 struct pim_interface
*pim_ifp
= ifp
->info
;
464 if (!pim_ifp
|| pim_ifp
->pim_neighbor_list
->count
!= 1)
467 return listnode_head(pim_ifp
->pim_neighbor_list
);
470 struct pim_neighbor
*
471 pim_neighbor_add(struct interface
*ifp
, pim_addr source_addr
,
472 pim_hello_options hello_options
, uint16_t holdtime
,
473 uint16_t propagation_delay
, uint16_t override_interval
,
474 uint32_t dr_priority
, uint32_t generation_id
,
475 struct list
*addr_list
, int send_hello_now
)
477 struct pim_interface
*pim_ifp
;
478 struct pim_neighbor
*neigh
;
480 neigh
= pim_neighbor_new(ifp
, source_addr
, hello_options
, holdtime
,
481 propagation_delay
, override_interval
,
482 dr_priority
, generation_id
, addr_list
);
490 listnode_add(pim_ifp
->pim_neighbor_list
, neigh
);
492 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
493 zlog_debug("%s: neighbor %pPA added ", __func__
, &source_addr
);
495 RFC 4601: 4.3.2. DR Election
497 A router's idea of the current DR on an interface can change when a
498 PIM Hello message is received, when a neighbor times out, or when a
499 router's own DR Priority changes.
501 pim_if_dr_election(neigh
->interface
); // new neighbor -- should not
502 // trigger dr election...
505 RFC 4601: 4.3.1. Sending Hello Messages
507 To allow new or rebooting routers to learn of PIM neighbors quickly,
508 when a Hello message is received from a new neighbor, or a Hello
509 message with a new GenID is received from an existing neighbor, a
510 new Hello message should be sent on this interface after a
511 randomized delay between 0 and Triggered_Hello_Delay.
513 This is a bit silly to do it that way. If I get a new
514 genid we need to send the hello *now* because we've
515 lined up a bunch of join/prune messages to go out the
519 pim_hello_restart_now(ifp
);
521 pim_hello_restart_triggered(neigh
->interface
);
523 pim_upstream_find_new_rpf(pim_ifp
->pim
);
525 /* RNH can send nexthop update prior to PIM neibhor UP
526 in that case nexthop cache would not consider this neighbor
528 Upon PIM neighbor UP, iterate all RPs and update
529 nexthop cache with this neighbor.
531 pim_resolve_rp_nh(pim_ifp
->pim
, neigh
);
533 pim_rp_setup(pim_ifp
->pim
);
535 sched_rpf_cache_refresh(pim_ifp
->pim
);
539 static uint16_t find_neighbors_next_highest_propagation_delay_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_delay_msec
;
550 next_highest_delay_msec
= pim_ifp
->pim_propagation_delay_msec
;
552 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
554 if (neigh
== highest_neigh
)
556 if (neigh
->propagation_delay_msec
> next_highest_delay_msec
)
557 next_highest_delay_msec
= neigh
->propagation_delay_msec
;
560 return next_highest_delay_msec
;
563 static uint16_t find_neighbors_next_highest_override_interval_msec(
564 struct interface
*ifp
, struct pim_neighbor
*highest_neigh
)
566 struct pim_interface
*pim_ifp
;
567 struct listnode
*neigh_node
;
568 struct pim_neighbor
*neigh
;
569 uint16_t next_highest_interval_msec
;
574 next_highest_interval_msec
= pim_ifp
->pim_override_interval_msec
;
576 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
578 if (neigh
== highest_neigh
)
580 if (neigh
->override_interval_msec
> next_highest_interval_msec
)
581 next_highest_interval_msec
=
582 neigh
->override_interval_msec
;
585 return next_highest_interval_msec
;
588 void pim_neighbor_delete(struct interface
*ifp
, struct pim_neighbor
*neigh
,
589 const char *delete_message
)
591 struct pim_interface
*pim_ifp
;
596 zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s",
597 &neigh
->source_addr
, ifp
->name
, delete_message
);
599 THREAD_OFF(neigh
->t_expire_timer
);
601 pim_if_assert_on_neighbor_down(ifp
, neigh
->source_addr
);
603 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
604 PIM_OPTION_MASK_LAN_PRUNE_DELAY
)) {
605 /* update num. of neighbors without hello option lan_delay */
607 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
610 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
611 PIM_OPTION_MASK_DR_PRIORITY
)) {
612 /* update num. of neighbors without dr_pri */
614 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
617 assert(neigh
->propagation_delay_msec
618 <= pim_ifp
->pim_neighbors_highest_propagation_delay_msec
);
619 assert(neigh
->override_interval_msec
620 <= pim_ifp
->pim_neighbors_highest_override_interval_msec
);
622 if (pim_if_lan_delay_enabled(ifp
)) {
624 /* will delete a neighbor with highest propagation delay? */
625 if (neigh
->propagation_delay_msec
626 == pim_ifp
->pim_neighbors_highest_propagation_delay_msec
) {
627 /* then find the next highest propagation delay */
628 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
=
629 find_neighbors_next_highest_propagation_delay_msec(
633 /* will delete a neighbor with highest override interval? */
634 if (neigh
->override_interval_msec
635 == pim_ifp
->pim_neighbors_highest_override_interval_msec
) {
636 /* then find the next highest propagation delay */
637 pim_ifp
->pim_neighbors_highest_override_interval_msec
=
638 find_neighbors_next_highest_override_interval_msec(
643 if (PIM_DEBUG_PIM_TRACE
) {
644 zlog_debug("%s: deleting PIM neighbor %pPA on interface %s",
645 __func__
, &neigh
->source_addr
, ifp
->name
);
648 listnode_delete(pim_ifp
->pim_neighbor_list
, neigh
);
650 pim_neighbor_free(neigh
);
652 sched_rpf_cache_refresh(pim_ifp
->pim
);
655 void pim_neighbor_delete_all(struct interface
*ifp
, const char *delete_message
)
657 struct pim_interface
*pim_ifp
;
658 struct listnode
*neigh_node
;
659 struct listnode
*neigh_nextnode
;
660 struct pim_neighbor
*neigh
;
665 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
, neigh_node
,
666 neigh_nextnode
, neigh
)) {
667 pim_neighbor_delete(ifp
, neigh
, delete_message
);
671 struct prefix
*pim_neighbor_find_secondary(struct pim_neighbor
*neigh
,
674 struct listnode
*node
;
677 if (!neigh
->prefix_list
)
680 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, node
, p
)) {
681 if (prefix_same(p
, addr
))
689 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
691 All the advertised secondary addresses in received Hello messages
692 must be checked against those previously advertised by all other
693 PIM neighbors on that interface. If there is a conflict and the
694 same secondary address was previously advertised by another
695 neighbor, then only the most recently received mapping MUST be
696 maintained, and an error message SHOULD be logged to the
697 administrator in a rate-limited manner.
699 static void delete_from_neigh_addr(struct interface
*ifp
,
700 struct list
*addr_list
, pim_addr neigh_addr
)
702 struct listnode
*addr_node
;
704 struct pim_interface
*pim_ifp
;
712 Scan secondary address list
714 for (ALL_LIST_ELEMENTS_RO(addr_list
, addr_node
, addr
)) {
715 struct listnode
*neigh_node
;
716 struct pim_neighbor
*neigh
;
718 if (addr
->family
!= AF_INET
)
724 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
,
725 neigh_node
, neigh
)) {
727 struct prefix
*p
= pim_neighbor_find_secondary(
730 char addr_str
[INET_ADDRSTRLEN
];
733 "<addr?>", addr
->u
.prefix4
,
734 addr_str
, sizeof(addr_str
));
737 "secondary addr %s recvd from neigh %pPA deleted from neigh %pPA on %s",
738 addr_str
, &neigh_addr
,
739 &neigh
->source_addr
, ifp
->name
);
741 listnode_delete(neigh
->prefix_list
, p
);
746 } /* scan neighbors */
748 } /* scan addr list */
751 void pim_neighbor_update(struct pim_neighbor
*neigh
,
752 pim_hello_options hello_options
, uint16_t holdtime
,
753 uint32_t dr_priority
, struct list
*addr_list
)
755 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
758 /* Received holdtime ? */
759 if (PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
)) {
760 pim_neighbor_timer_reset(neigh
, holdtime
);
762 pim_neighbor_timer_reset(neigh
,
763 PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
766 #ifdef DUMP_PREFIX_LIST
768 "%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
769 __func__
, (unsigned)neigh
->prefix_list
,
770 neigh
->prefix_list
? (int)listcount(neigh
->prefix_list
) : -1,
772 addr_list
? (int)listcount(addr_list
) : -1);
775 if (neigh
->prefix_list
== addr_list
) {
779 "%s: internal error: trying to replace same prefix list=%p",
780 __func__
, (void *)addr_list
);
783 /* Delete existing secondary address list */
784 delete_prefix_list(neigh
);
788 delete_from_neigh_addr(neigh
->interface
, addr_list
,
792 /* Replace secondary address list */
793 neigh
->prefix_list
= addr_list
;
795 update_dr_priority(neigh
, hello_options
, dr_priority
);
796 new = PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
797 old
= PIM_OPTION_IS_SET(neigh
->hello_options
,
798 PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
802 ++pim_ifp
->pim_number_of_nonlandelay_neighbors
;
804 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
809 neigh
->hello_options
= hello_options
;