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_instance.h"
32 #include "pim_neighbor.h"
35 #include "pim_iface.h"
37 #include "pim_upstream.h"
38 #include "pim_ifchannel.h"
40 #include "pim_zebra.h"
42 #include "pim_jp_agg.h"
44 #include "pim_register.h"
46 static void dr_election_by_addr(struct interface
*ifp
)
48 struct pim_interface
*pim_ifp
;
49 struct listnode
*node
;
50 struct pim_neighbor
*neigh
;
55 pim_ifp
->pim_dr_addr
= pim_ifp
->primary_address
;
57 if (PIM_DEBUG_PIM_TRACE
) {
58 zlog_debug("%s: on interface %s", __func__
, ifp
->name
);
61 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
62 if (pim_addr_cmp(neigh
->source_addr
, pim_ifp
->pim_dr_addr
) > 0)
63 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 %pPA if dr addr %pPA",
88 __func__
, neigh
->dr_priority
,
89 &neigh
->source_addr
, &pim_ifp
->pim_dr_addr
);
91 if ((neigh
->dr_priority
> dr_pri
) ||
92 ((neigh
->dr_priority
== dr_pri
) &&
93 (pim_addr_cmp(neigh
->source_addr
, pim_ifp
->pim_dr_addr
) >
95 pim_ifp
->pim_dr_addr
= neigh
->source_addr
;
96 dr_pri
= neigh
->dr_priority
;
102 RFC 4601: 4.3.2. DR Election
104 A router's idea of the current DR on an interface can change when a
105 PIM Hello message is received, when a neighbor times out, or when a
106 router's own DR Priority changes.
108 int pim_if_dr_election(struct interface
*ifp
)
110 struct pim_interface
*pim_ifp
= ifp
->info
;
111 pim_addr old_dr_addr
;
113 ++pim_ifp
->pim_dr_election_count
;
115 old_dr_addr
= pim_ifp
->pim_dr_addr
;
117 if (pim_ifp
->pim_dr_num_nondrpri_neighbors
) {
118 dr_election_by_addr(ifp
);
120 dr_election_by_pri(ifp
);
124 if (pim_addr_cmp(old_dr_addr
, pim_ifp
->pim_dr_addr
)) {
126 if (PIM_DEBUG_PIM_EVENTS
)
128 "%s: DR was %pPA now is %pPA on interface %s",
129 __func__
, &old_dr_addr
, &pim_ifp
->pim_dr_addr
,
132 pim_ifp
->pim_dr_election_last
=
133 pim_time_monotonic_sec(); /* timestamp */
134 ++pim_ifp
->pim_dr_election_changes
;
135 pim_if_update_join_desired(pim_ifp
);
136 pim_if_update_could_assert(ifp
);
137 pim_if_update_assert_tracking_desired(ifp
);
139 if (PIM_I_am_DR(pim_ifp
))
140 pim_ifp
->am_i_dr
= true;
142 if (pim_ifp
->am_i_dr
== true) {
143 pim_reg_del_on_couldreg_fail(ifp
);
144 pim_ifp
->am_i_dr
= false;
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 */
163 PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_DR_PRIORITY
);
165 bit_flip
= (will_set_pri
166 != PIM_OPTION_IS_SET(neigh
->hello_options
,
167 PIM_OPTION_MASK_DR_PRIORITY
));
170 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
172 /* update num. of neighbors without dr_pri */
175 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
177 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
181 pri_change
= (bit_flip
|| (neigh
->dr_priority
!= dr_priority
));
184 neigh
->dr_priority
= dr_priority
;
186 neigh
->dr_priority
= 0; /* cosmetic unset */
191 RFC 4601: 4.3.2. DR Election
193 A router's idea of the current DR on an interface can change
195 PIM Hello message is received, when a neighbor times out, or
197 router's own DR Priority changes.
200 neigh
->interface
); // router's own DR Priority changes
204 static void on_neighbor_timer(struct thread
*t
)
206 struct pim_neighbor
*neigh
;
207 struct interface
*ifp
;
210 neigh
= THREAD_ARG(t
);
212 ifp
= neigh
->interface
;
214 if (PIM_DEBUG_PIM_TRACE
)
216 "Expired %d sec holdtime for neighbor %pPA on interface %s",
217 neigh
->holdtime
, &neigh
->source_addr
, 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
232 void pim_neighbor_timer_reset(struct pim_neighbor
*neigh
, uint16_t holdtime
)
234 neigh
->holdtime
= holdtime
;
236 THREAD_OFF(neigh
->t_expire_timer
);
239 0xFFFF is request for no holdtime
241 if (neigh
->holdtime
== 0xFFFF) {
245 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
246 zlog_debug("%s: starting %u sec timer for neighbor %pPA on %s",
247 __func__
, neigh
->holdtime
, &neigh
->source_addr
,
248 neigh
->interface
->name
);
250 thread_add_timer(router
->master
, on_neighbor_timer
, neigh
,
251 neigh
->holdtime
, &neigh
->t_expire_timer
);
254 static void on_neighbor_jp_timer(struct thread
*t
)
256 struct pim_neighbor
*neigh
= THREAD_ARG(t
);
259 if (PIM_DEBUG_PIM_TRACE
)
260 zlog_debug("%s:Sending JP Agg to %pPA on %s with %d groups",
261 __func__
, &neigh
->source_addr
,
262 neigh
->interface
->name
,
263 neigh
->upstream_jp_agg
->count
);
265 rpf
.source_nexthop
.interface
= neigh
->interface
;
266 rpf
.rpf_addr
= neigh
->source_addr
;
267 pim_joinprune_send(&rpf
, neigh
->upstream_jp_agg
);
269 thread_add_timer(router
->master
, on_neighbor_jp_timer
, neigh
,
270 router
->t_periodic
, &neigh
->jp_timer
);
273 static void pim_neighbor_start_jp_timer(struct pim_neighbor
*neigh
)
275 THREAD_OFF(neigh
->jp_timer
);
276 thread_add_timer(router
->master
, on_neighbor_jp_timer
, neigh
,
277 router
->t_periodic
, &neigh
->jp_timer
);
280 static struct pim_neighbor
*
281 pim_neighbor_new(struct interface
*ifp
, pim_addr source_addr
,
282 pim_hello_options hello_options
, uint16_t holdtime
,
283 uint16_t propagation_delay
, uint16_t override_interval
,
284 uint32_t dr_priority
, uint32_t generation_id
,
285 struct list
*addr_list
)
287 struct pim_interface
*pim_ifp
;
288 struct pim_neighbor
*neigh
;
294 neigh
= XCALLOC(MTYPE_PIM_NEIGHBOR
, sizeof(*neigh
));
296 neigh
->creation
= pim_time_monotonic_sec();
297 neigh
->source_addr
= source_addr
;
298 neigh
->hello_options
= hello_options
;
299 neigh
->propagation_delay_msec
= propagation_delay
;
300 neigh
->override_interval_msec
= override_interval
;
301 neigh
->dr_priority
= dr_priority
;
302 neigh
->generation_id
= generation_id
;
303 neigh
->prefix_list
= addr_list
;
304 neigh
->t_expire_timer
= NULL
;
305 neigh
->interface
= ifp
;
307 neigh
->upstream_jp_agg
= list_new();
308 neigh
->upstream_jp_agg
->cmp
= pim_jp_agg_group_list_cmp
;
309 neigh
->upstream_jp_agg
->del
=
310 (void (*)(void *))pim_jp_agg_group_list_free
;
311 pim_neighbor_start_jp_timer(neigh
);
313 pim_neighbor_timer_reset(neigh
, holdtime
);
315 * The pim_ifstat_hello_sent variable is used to decide if
316 * we should expedite a hello out the interface. If we
317 * establish a new neighbor, we unfortunately need to
318 * reset the value so that we can know to hurry up and
321 PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp
->flags
);
323 if (PIM_DEBUG_PIM_EVENTS
)
324 zlog_debug("%s: creating PIM neighbor %pPA on interface %s",
325 __func__
, &source_addr
, ifp
->name
);
327 zlog_notice("PIM NEIGHBOR UP: neighbor %pPA on interface %s",
328 &source_addr
, ifp
->name
);
330 if (neigh
->propagation_delay_msec
331 > pim_ifp
->pim_neighbors_highest_propagation_delay_msec
) {
332 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
=
333 neigh
->propagation_delay_msec
;
335 if (neigh
->override_interval_msec
336 > pim_ifp
->pim_neighbors_highest_override_interval_msec
) {
337 pim_ifp
->pim_neighbors_highest_override_interval_msec
=
338 neigh
->override_interval_msec
;
341 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
342 PIM_OPTION_MASK_LAN_PRUNE_DELAY
)) {
343 /* update num. of neighbors without hello option lan_delay */
344 ++pim_ifp
->pim_number_of_nonlandelay_neighbors
;
347 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
348 PIM_OPTION_MASK_DR_PRIORITY
)) {
349 /* update num. of neighbors without hello option dr_pri */
350 ++pim_ifp
->pim_dr_num_nondrpri_neighbors
;
353 // Register PIM Neighbor with BFD
354 pim_bfd_info_nbr_create(pim_ifp
, neigh
);
359 static void delete_prefix_list(struct pim_neighbor
*neigh
)
361 if (neigh
->prefix_list
) {
363 #ifdef DUMP_PREFIX_LIST
364 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
)) {
372 "%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%pFXh [%d/%d]",
373 __func__
, (unsigned)neigh
,
374 (unsigned)neigh
->prefix_list
, (unsigned)p
, p
, i
,
380 list_delete(&neigh
->prefix_list
);
384 void pim_neighbor_free(struct pim_neighbor
*neigh
)
386 assert(!neigh
->t_expire_timer
);
388 delete_prefix_list(neigh
);
390 list_delete(&neigh
->upstream_jp_agg
);
391 THREAD_OFF(neigh
->jp_timer
);
393 bfd_sess_free(&neigh
->bfd_session
);
395 XFREE(MTYPE_PIM_NEIGHBOR
, neigh
);
398 struct pim_neighbor
*pim_neighbor_find_by_secondary(struct interface
*ifp
,
401 struct pim_interface
*pim_ifp
;
402 struct listnode
*node
, *pnode
;
403 struct pim_neighbor
*neigh
;
406 if (!ifp
|| !ifp
->info
)
411 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
412 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, pnode
, p
)) {
413 if (prefix_same(p
, src
))
421 struct pim_neighbor
*pim_neighbor_find(struct interface
*ifp
,
422 pim_addr source_addr
)
424 struct pim_interface
*pim_ifp
;
425 struct listnode
*node
;
426 struct pim_neighbor
*neigh
;
435 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, node
, neigh
)) {
436 if (!pim_addr_cmp(source_addr
, neigh
->source_addr
)) {
445 * Find the *one* interface out
446 * this interface. If more than
449 struct pim_neighbor
*pim_neighbor_find_if(struct interface
*ifp
)
451 struct pim_interface
*pim_ifp
= ifp
->info
;
453 if (!pim_ifp
|| pim_ifp
->pim_neighbor_list
->count
!= 1)
456 return listnode_head(pim_ifp
->pim_neighbor_list
);
459 struct pim_neighbor
*
460 pim_neighbor_add(struct interface
*ifp
, pim_addr source_addr
,
461 pim_hello_options hello_options
, uint16_t holdtime
,
462 uint16_t propagation_delay
, uint16_t override_interval
,
463 uint32_t dr_priority
, uint32_t generation_id
,
464 struct list
*addr_list
, int send_hello_now
)
466 struct pim_interface
*pim_ifp
;
467 struct pim_neighbor
*neigh
;
469 neigh
= pim_neighbor_new(ifp
, source_addr
, hello_options
, holdtime
,
470 propagation_delay
, override_interval
,
471 dr_priority
, generation_id
, addr_list
);
479 listnode_add(pim_ifp
->pim_neighbor_list
, neigh
);
481 if (PIM_DEBUG_PIM_TRACE_DETAIL
)
482 zlog_debug("%s: neighbor %pPA added ", __func__
, &source_addr
);
484 RFC 4601: 4.3.2. DR Election
486 A router's idea of the current DR on an interface can change when a
487 PIM Hello message is received, when a neighbor times out, or when a
488 router's own DR Priority changes.
490 pim_if_dr_election(neigh
->interface
); // new neighbor -- should not
491 // trigger dr election...
494 RFC 4601: 4.3.1. Sending Hello Messages
496 To allow new or rebooting routers to learn of PIM neighbors quickly,
497 when a Hello message is received from a new neighbor, or a Hello
498 message with a new GenID is received from an existing neighbor, a
499 new Hello message should be sent on this interface after a
500 randomized delay between 0 and Triggered_Hello_Delay.
502 This is a bit silly to do it that way. If I get a new
503 genid we need to send the hello *now* because we've
504 lined up a bunch of join/prune messages to go out the
508 pim_hello_restart_now(ifp
);
510 pim_hello_restart_triggered(neigh
->interface
);
512 pim_upstream_find_new_rpf(pim_ifp
->pim
);
514 /* RNH can send nexthop update prior to PIM neibhor UP
515 in that case nexthop cache would not consider this neighbor
517 Upon PIM neighbor UP, iterate all RPs and update
518 nexthop cache with this neighbor.
520 pim_resolve_rp_nh(pim_ifp
->pim
, neigh
);
522 pim_rp_setup(pim_ifp
->pim
);
524 sched_rpf_cache_refresh(pim_ifp
->pim
);
528 static uint16_t find_neighbors_next_highest_propagation_delay_msec(
529 struct interface
*ifp
, struct pim_neighbor
*highest_neigh
)
531 struct pim_interface
*pim_ifp
;
532 struct listnode
*neigh_node
;
533 struct pim_neighbor
*neigh
;
534 uint16_t next_highest_delay_msec
;
539 next_highest_delay_msec
= pim_ifp
->pim_propagation_delay_msec
;
541 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
543 if (neigh
== highest_neigh
)
545 if (neigh
->propagation_delay_msec
> next_highest_delay_msec
)
546 next_highest_delay_msec
= neigh
->propagation_delay_msec
;
549 return next_highest_delay_msec
;
552 static uint16_t find_neighbors_next_highest_override_interval_msec(
553 struct interface
*ifp
, struct pim_neighbor
*highest_neigh
)
555 struct pim_interface
*pim_ifp
;
556 struct listnode
*neigh_node
;
557 struct pim_neighbor
*neigh
;
558 uint16_t next_highest_interval_msec
;
563 next_highest_interval_msec
= pim_ifp
->pim_override_interval_msec
;
565 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neigh_node
,
567 if (neigh
== highest_neigh
)
569 if (neigh
->override_interval_msec
> next_highest_interval_msec
)
570 next_highest_interval_msec
=
571 neigh
->override_interval_msec
;
574 return next_highest_interval_msec
;
577 void pim_neighbor_delete(struct interface
*ifp
, struct pim_neighbor
*neigh
,
578 const char *delete_message
)
580 struct pim_interface
*pim_ifp
;
585 zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s",
586 &neigh
->source_addr
, ifp
->name
, delete_message
);
588 THREAD_OFF(neigh
->t_expire_timer
);
590 pim_if_assert_on_neighbor_down(ifp
, neigh
->source_addr
);
592 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
593 PIM_OPTION_MASK_LAN_PRUNE_DELAY
)) {
594 /* update num. of neighbors without hello option lan_delay */
596 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
599 if (!PIM_OPTION_IS_SET(neigh
->hello_options
,
600 PIM_OPTION_MASK_DR_PRIORITY
)) {
601 /* update num. of neighbors without dr_pri */
603 --pim_ifp
->pim_dr_num_nondrpri_neighbors
;
606 assert(neigh
->propagation_delay_msec
607 <= pim_ifp
->pim_neighbors_highest_propagation_delay_msec
);
608 assert(neigh
->override_interval_msec
609 <= pim_ifp
->pim_neighbors_highest_override_interval_msec
);
611 if (pim_if_lan_delay_enabled(ifp
)) {
613 /* will delete a neighbor with highest propagation delay? */
614 if (neigh
->propagation_delay_msec
615 == pim_ifp
->pim_neighbors_highest_propagation_delay_msec
) {
616 /* then find the next highest propagation delay */
617 pim_ifp
->pim_neighbors_highest_propagation_delay_msec
=
618 find_neighbors_next_highest_propagation_delay_msec(
622 /* will delete a neighbor with highest override interval? */
623 if (neigh
->override_interval_msec
624 == pim_ifp
->pim_neighbors_highest_override_interval_msec
) {
625 /* then find the next highest propagation delay */
626 pim_ifp
->pim_neighbors_highest_override_interval_msec
=
627 find_neighbors_next_highest_override_interval_msec(
632 if (PIM_DEBUG_PIM_TRACE
) {
633 zlog_debug("%s: deleting PIM neighbor %pPA on interface %s",
634 __func__
, &neigh
->source_addr
, ifp
->name
);
637 listnode_delete(pim_ifp
->pim_neighbor_list
, neigh
);
639 pim_neighbor_free(neigh
);
641 sched_rpf_cache_refresh(pim_ifp
->pim
);
644 void pim_neighbor_delete_all(struct interface
*ifp
, const char *delete_message
)
646 struct pim_interface
*pim_ifp
;
647 struct listnode
*neigh_node
;
648 struct listnode
*neigh_nextnode
;
649 struct pim_neighbor
*neigh
;
654 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_neighbor_list
, neigh_node
,
655 neigh_nextnode
, neigh
)) {
656 pim_neighbor_delete(ifp
, neigh
, delete_message
);
660 struct prefix
*pim_neighbor_find_secondary(struct pim_neighbor
*neigh
,
663 struct listnode
*node
;
666 if (!neigh
->prefix_list
)
669 for (ALL_LIST_ELEMENTS_RO(neigh
->prefix_list
, node
, p
)) {
670 if (prefix_same(p
, addr
))
678 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
680 All the advertised secondary addresses in received Hello messages
681 must be checked against those previously advertised by all other
682 PIM neighbors on that interface. If there is a conflict and the
683 same secondary address was previously advertised by another
684 neighbor, then only the most recently received mapping MUST be
685 maintained, and an error message SHOULD be logged to the
686 administrator in a rate-limited manner.
688 static void delete_from_neigh_addr(struct interface
*ifp
,
689 struct list
*addr_list
, pim_addr neigh_addr
)
691 struct listnode
*addr_node
;
693 struct pim_interface
*pim_ifp
;
701 Scan secondary address list
703 for (ALL_LIST_ELEMENTS_RO(addr_list
, addr_node
, addr
)) {
704 struct listnode
*neigh_node
;
705 struct pim_neighbor
*neigh
;
707 if (addr
->family
!= PIM_AF
)
712 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
,
713 neigh_node
, neigh
)) {
715 struct prefix
*p
= pim_neighbor_find_secondary(
719 "secondary addr %pFXh recvd from neigh %pPA deleted from neigh %pPA on %s",
721 &neigh
->source_addr
, ifp
->name
);
723 listnode_delete(neigh
->prefix_list
, p
);
728 } /* scan neighbors */
730 } /* scan addr list */
733 void pim_neighbor_update(struct pim_neighbor
*neigh
,
734 pim_hello_options hello_options
, uint16_t holdtime
,
735 uint32_t dr_priority
, struct list
*addr_list
)
737 struct pim_interface
*pim_ifp
= neigh
->interface
->info
;
740 /* Received holdtime ? */
741 if (PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_HOLDTIME
)) {
742 pim_neighbor_timer_reset(neigh
, holdtime
);
744 pim_neighbor_timer_reset(neigh
,
745 PIM_IF_DEFAULT_HOLDTIME(pim_ifp
));
748 #ifdef DUMP_PREFIX_LIST
750 "%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
751 __func__
, (unsigned)neigh
->prefix_list
,
752 neigh
->prefix_list
? (int)listcount(neigh
->prefix_list
) : -1,
754 addr_list
? (int)listcount(addr_list
) : -1);
757 if (neigh
->prefix_list
== addr_list
) {
761 "%s: internal error: trying to replace same prefix list=%p",
762 __func__
, (void *)addr_list
);
765 /* Delete existing secondary address list */
766 delete_prefix_list(neigh
);
770 delete_from_neigh_addr(neigh
->interface
, addr_list
,
774 /* Replace secondary address list */
775 neigh
->prefix_list
= addr_list
;
777 update_dr_priority(neigh
, hello_options
, dr_priority
);
778 new = PIM_OPTION_IS_SET(hello_options
, PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
779 old
= PIM_OPTION_IS_SET(neigh
->hello_options
,
780 PIM_OPTION_MASK_LAN_PRUNE_DELAY
);
784 ++pim_ifp
->pim_number_of_nonlandelay_neighbors
;
786 --pim_ifp
->pim_number_of_nonlandelay_neighbors
;
791 neigh
->hello_options
= hello_options
;