blob: 9013b50c6cc48f6a034c6b3d61e69757d31fa28f [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4
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.
9
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.
14
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,
18 MA 02110-1301 USA
19
20 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "log.h"
26#include "prefix.h"
27#include "memory.h"
28
29#include "pimd.h"
30#include "pim_neighbor.h"
31#include "pim_time.h"
32#include "pim_str.h"
33#include "pim_iface.h"
34#include "pim_pim.h"
35#include "pim_upstream.h"
36#include "pim_ifchannel.h"
37
38static void dr_election_by_addr(struct interface *ifp)
39{
40 struct pim_interface *pim_ifp;
41 struct listnode *node;
42 struct pim_neighbor *neigh;
43
44 pim_ifp = ifp->info;
45 zassert(pim_ifp);
46
47 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
48
Everton Marquese0b8b9b2009-11-17 10:17:21 -020049 if (PIM_DEBUG_PIM_TRACE) {
50 zlog_debug("%s: on interface %s",
51 __PRETTY_FUNCTION__,
52 ifp->name);
53 }
Leonard Herve236b0152009-08-11 15:51:52 -030054
Everton Marques871dbcf2009-08-11 15:43:05 -030055 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
56 if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) {
57 pim_ifp->pim_dr_addr = neigh->source_addr;
58 }
59 }
60}
61
62static void dr_election_by_pri(struct interface *ifp)
63{
64 struct pim_interface *pim_ifp;
65 struct listnode *node;
66 struct pim_neighbor *neigh;
67 uint32_t dr_pri;
68
69 pim_ifp = ifp->info;
70 zassert(pim_ifp);
71
72 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
73 dr_pri = pim_ifp->pim_dr_priority;
74
Everton Marquese0b8b9b2009-11-17 10:17:21 -020075 if (PIM_DEBUG_PIM_TRACE) {
76 zlog_debug("%s: dr pri %u on interface %s",
77 __PRETTY_FUNCTION__,
78 dr_pri, ifp->name);
79 }
Leonard Herve236b0152009-08-11 15:51:52 -030080
Everton Marques871dbcf2009-08-11 15:43:05 -030081 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
Everton Marquese0b8b9b2009-11-17 10:17:21 -020082 if (PIM_DEBUG_PIM_TRACE) {
83 zlog_info("%s: neigh pri %u addr %x if dr addr %x",
84 __PRETTY_FUNCTION__,
85 neigh->dr_priority,
86 ntohl(neigh->source_addr.s_addr),
87 ntohl(pim_ifp->pim_dr_addr.s_addr));
88 }
Everton Marques871dbcf2009-08-11 15:43:05 -030089 if (
90 (neigh->dr_priority > dr_pri) ||
91 (
92 (neigh->dr_priority == dr_pri) &&
93 (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr))
94 )
95 ) {
96 pim_ifp->pim_dr_addr = neigh->source_addr;
97 dr_pri = neigh->dr_priority;
98 }
99 }
100}
101
102/*
103 RFC 4601: 4.3.2. DR Election
104
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.
108 */
109void pim_if_dr_election(struct interface *ifp)
110{
111 struct pim_interface *pim_ifp = ifp->info;
112 struct in_addr old_dr_addr;
113
114 pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */
115 ++pim_ifp->pim_dr_election_count;
116
117 old_dr_addr = pim_ifp->pim_dr_addr;
118
119 if (pim_ifp->pim_dr_num_nondrpri_neighbors) {
120 dr_election_by_addr(ifp);
121 }
122 else {
123 dr_election_by_pri(ifp);
124 }
125
Leonard Herve236b0152009-08-11 15:51:52 -0300126 /* DR changed ? */
127 if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) {
Everton Marquese0b8b9b2009-11-17 10:17:21 -0200128 char dr_old_str[100];
129 char dr_new_str[100];
130 pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str));
131 pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str));
132 zlog_info("%s: DR was %s now is %s on interface %s",
133 __PRETTY_FUNCTION__,
134 dr_old_str, dr_new_str, ifp->name);
135
Everton Marques871dbcf2009-08-11 15:43:05 -0300136 pim_if_update_join_desired(pim_ifp);
137 pim_if_update_could_assert(ifp);
138 pim_if_update_assert_tracking_desired(ifp);
139 }
140}
141
142static void update_dr_priority(struct pim_neighbor *neigh,
143 pim_hello_options hello_options,
144 uint32_t dr_priority)
145{
146 pim_hello_options will_set_pri; /* boolean */
147 pim_hello_options bit_flip; /* boolean */
148 pim_hello_options pri_change; /* boolean */
149
150 will_set_pri = PIM_OPTION_IS_SET(hello_options,
151 PIM_OPTION_MASK_DR_PRIORITY);
152
153 bit_flip =
154 (
155 will_set_pri !=
156 PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)
157 );
158
159 if (bit_flip) {
160 struct pim_interface *pim_ifp = neigh->interface->info;
161
162 /* update num. of neighbors without dr_pri */
163
164 if (will_set_pri) {
165 --pim_ifp->pim_dr_num_nondrpri_neighbors;
166 }
167 else {
168 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
169 }
170 }
171
172 pri_change =
173 (
174 bit_flip
175 ||
176 (neigh->dr_priority != dr_priority)
177 );
178
179 if (will_set_pri) {
180 neigh->dr_priority = dr_priority;
181 }
182 else {
183 neigh->dr_priority = 0; /* cosmetic unset */
184 }
185
186 if (pri_change) {
187 /*
188 RFC 4601: 4.3.2. DR Election
189
190 A router's idea of the current DR on an interface can change when a
191 PIM Hello message is received, when a neighbor times out, or when a
192 router's own DR Priority changes.
193 */
194 pim_if_dr_election(neigh->interface);
195 }
196}
197
198static int on_neighbor_timer(struct thread *t)
199{
200 struct pim_neighbor *neigh;
201 struct interface *ifp;
202 char msg[100];
203
204 zassert(t);
205 neigh = THREAD_ARG(t);
206 zassert(neigh);
207
208 ifp = neigh->interface;
209
210 if (PIM_DEBUG_PIM_TRACE) {
211 char src_str[100];
212 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
213 zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
214 neigh->holdtime, src_str, ifp->name);
215 }
216
217 neigh->t_expire_timer = 0;
218
219 snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
220 pim_neighbor_delete(ifp, neigh, msg);
221
222 /*
223 RFC 4601: 4.3.2. DR Election
224
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.
228 */
229 pim_if_dr_election(ifp);
230
231 return 0;
232}
233
234static void neighbor_timer_off(struct pim_neighbor *neigh)
235{
236 if (PIM_DEBUG_PIM_TRACE) {
237 if (neigh->t_expire_timer) {
238 char src_str[100];
239 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
240 zlog_debug("%s: cancelling timer for neighbor %s on %s",
241 __PRETTY_FUNCTION__,
242 src_str, neigh->interface->name);
243 }
244 }
245 THREAD_OFF(neigh->t_expire_timer);
246 zassert(!neigh->t_expire_timer);
247}
248
249void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
250{
251 neigh->holdtime = holdtime;
252
253 neighbor_timer_off(neigh);
254
255 /*
256 0xFFFF is request for no holdtime
257 */
258 if (neigh->holdtime == 0xFFFF) {
259 return;
260 }
261
262 if (PIM_DEBUG_PIM_TRACE) {
263 char src_str[100];
264 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
265 zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
266 __PRETTY_FUNCTION__,
267 neigh->holdtime, src_str, neigh->interface->name);
268 }
269
270 THREAD_TIMER_ON(master, neigh->t_expire_timer,
271 on_neighbor_timer,
272 neigh, neigh->holdtime);
273}
274
275static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
276 struct in_addr source_addr,
277 pim_hello_options hello_options,
278 uint16_t holdtime,
279 uint16_t propagation_delay,
280 uint16_t override_interval,
281 uint32_t dr_priority,
282 uint32_t generation_id,
283 struct list *addr_list)
284{
285 struct pim_interface *pim_ifp;
286 struct pim_neighbor *neigh;
287 char src_str[100];
288
289 zassert(ifp);
290 pim_ifp = ifp->info;
291 zassert(pim_ifp);
292
293 neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
294 if (!neigh) {
295 zlog_err("%s: PIM XMALLOC(%d) failure",
296 __PRETTY_FUNCTION__, sizeof(*neigh));
297 return 0;
298 }
299
300 neigh->creation = pim_time_monotonic_sec();
301 neigh->source_addr = source_addr;
302 neigh->hello_options = hello_options;
303 neigh->propagation_delay_msec = propagation_delay;
304 neigh->override_interval_msec = override_interval;
305 neigh->dr_priority = dr_priority;
306 neigh->generation_id = generation_id;
307 neigh->prefix_list = addr_list;
308 neigh->t_expire_timer = 0;
309 neigh->interface = ifp;
310
311 pim_neighbor_timer_reset(neigh, holdtime);
312
313 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
314
315 if (PIM_DEBUG_PIM_EVENTS) {
316 zlog_debug("%s: creating PIM neighbor %s on interface %s",
317 __PRETTY_FUNCTION__,
318 src_str, ifp->name);
319 }
320
321 zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s",
322 src_str, ifp->name);
323
324 if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
325 pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec;
326 }
327 if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) {
328 pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec;
329 }
330
331 if (!PIM_OPTION_IS_SET(neigh->hello_options,
332 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
333 /* update num. of neighbors without hello option lan_delay */
334 ++pim_ifp->pim_number_of_nonlandelay_neighbors;
335 }
336
337 if (!PIM_OPTION_IS_SET(neigh->hello_options,
338 PIM_OPTION_MASK_DR_PRIORITY)) {
339 /* update num. of neighbors without hello option dr_pri */
340 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
341 }
342
343 /*
344 RFC 4601: 4.3.2. DR Election
345
346 A router's idea of the current DR on an interface can change when a
347 PIM Hello message is received, when a neighbor times out, or when a
348 router's own DR Priority changes.
349 */
350 pim_if_dr_election(neigh->interface);
351
352 /*
353 RFC 4601: 4.3.1. Sending Hello Messages
354
355 To allow new or rebooting routers to learn of PIM neighbors quickly,
356 when a Hello message is received from a new neighbor, or a Hello
357 message with a new GenID is received from an existing neighbor, a
358 new Hello message should be sent on this interface after a
359 randomized delay between 0 and Triggered_Hello_Delay.
360 */
361 pim_hello_restart_triggered(neigh->interface);
362
363 return neigh;
364}
365
366static void delete_prefix_list(struct pim_neighbor *neigh)
367{
368 if (neigh->prefix_list) {
369
370#ifdef DUMP_PREFIX_LIST
371 struct listnode *p_node;
372 struct prefix *p;
373 char addr_str[10];
374 int list_size = neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1;
375 int i = 0;
376 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) {
377 pim_inet4_dump("<addr?>", p->u.prefix4, addr_str, sizeof(addr_str));
378 zlog_debug("%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]",
379 __PRETTY_FUNCTION__,
380 (unsigned) neigh, (unsigned) neigh->prefix_list, (unsigned) p,
381 addr_str, i, list_size);
382 ++i;
383 }
384#endif
385
386 list_delete(neigh->prefix_list);
387 neigh->prefix_list = 0;
388 }
389}
390
391void pim_neighbor_free(struct pim_neighbor *neigh)
392{
393 zassert(!neigh->t_expire_timer);
394
395 delete_prefix_list(neigh);
396
397 XFREE(MTYPE_PIM_NEIGHBOR, neigh);
398}
399
400struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
401 struct in_addr source_addr)
402{
403 struct pim_interface *pim_ifp;
404 struct listnode *node;
405 struct pim_neighbor *neigh;
406
407 pim_ifp = ifp->info;
408 zassert(pim_ifp);
409
410 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
411 if (source_addr.s_addr == neigh->source_addr.s_addr) {
412 return neigh;
413 }
414 }
415
416 return 0;
417}
418
419struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
420 struct in_addr source_addr,
421 pim_hello_options hello_options,
422 uint16_t holdtime,
423 uint16_t propagation_delay,
424 uint16_t override_interval,
425 uint32_t dr_priority,
426 uint32_t generation_id,
427 struct list *addr_list)
428{
429 struct pim_interface *pim_ifp;
430 struct pim_neighbor *neigh;
431
432 neigh = pim_neighbor_new(ifp, source_addr,
433 hello_options,
434 holdtime,
435 propagation_delay,
436 override_interval,
437 dr_priority,
438 generation_id,
439 addr_list);
440 if (!neigh) {
441 return 0;
442 }
443
444 pim_ifp = ifp->info;
445 zassert(pim_ifp);
446
447 listnode_add(pim_ifp->pim_neighbor_list, neigh);
448
449 return neigh;
450}
451
452static uint16_t
453find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp,
454 struct pim_neighbor *highest_neigh)
455{
456 struct pim_interface *pim_ifp;
457 struct listnode *neigh_node;
458 struct pim_neighbor *neigh;
459 uint16_t next_highest_delay_msec;
460
461 pim_ifp = ifp->info;
462 zassert(pim_ifp);
463
464 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
465
466 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
467 if (neigh == highest_neigh)
468 continue;
469 if (neigh->propagation_delay_msec > next_highest_delay_msec)
470 next_highest_delay_msec = neigh->propagation_delay_msec;
471 }
472
473 return next_highest_delay_msec;
474}
475
476static uint16_t
477find_neighbors_next_highest_override_interval_msec(struct interface *ifp,
478 struct pim_neighbor *highest_neigh)
479{
480 struct pim_interface *pim_ifp;
481 struct listnode *neigh_node;
482 struct pim_neighbor *neigh;
483 uint16_t next_highest_interval_msec;
484
485 pim_ifp = ifp->info;
486 zassert(pim_ifp);
487
488 next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
489
490 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
491 if (neigh == highest_neigh)
492 continue;
493 if (neigh->override_interval_msec > next_highest_interval_msec)
494 next_highest_interval_msec = neigh->override_interval_msec;
495 }
496
497 return next_highest_interval_msec;
498}
499
500void pim_neighbor_delete(struct interface *ifp,
501 struct pim_neighbor *neigh,
502 const char *delete_message)
503{
504 struct pim_interface *pim_ifp;
505 char src_str[100];
506
507 pim_ifp = ifp->info;
508 zassert(pim_ifp);
509
510 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
511 zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
512 src_str, ifp->name, delete_message);
513
514 neighbor_timer_off(neigh);
515
516 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
517
518 if (!PIM_OPTION_IS_SET(neigh->hello_options,
519 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
520 /* update num. of neighbors without hello option lan_delay */
521
522 --pim_ifp->pim_number_of_nonlandelay_neighbors;
523 }
524
525 if (!PIM_OPTION_IS_SET(neigh->hello_options,
526 PIM_OPTION_MASK_DR_PRIORITY)) {
527 /* update num. of neighbors without dr_pri */
528
529 --pim_ifp->pim_dr_num_nondrpri_neighbors;
530 }
531
532 zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
533 zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec);
534
535 if (pim_if_lan_delay_enabled(ifp)) {
536
537 /* will delete a neighbor with highest propagation delay? */
538 if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
539 /* then find the next highest propagation delay */
540 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
541 find_neighbors_next_highest_propagation_delay_msec(ifp, neigh);
542 }
543
544 /* will delete a neighbor with highest override interval? */
545 if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) {
546 /* then find the next highest propagation delay */
547 pim_ifp->pim_neighbors_highest_override_interval_msec =
548 find_neighbors_next_highest_override_interval_msec(ifp, neigh);
549 }
550 }
551
552 if (PIM_DEBUG_PIM_TRACE) {
553 zlog_debug("%s: deleting PIM neighbor %s on interface %s",
554 __PRETTY_FUNCTION__,
555 src_str, ifp->name);
556 }
557
558 listnode_delete(pim_ifp->pim_neighbor_list, neigh);
559
560 pim_neighbor_free(neigh);
561}
562
563void pim_neighbor_delete_all(struct interface *ifp,
564 const char *delete_message)
565{
566 struct pim_interface *pim_ifp;
567 struct listnode *neigh_node;
568 struct listnode *neigh_nextnode;
569 struct pim_neighbor *neigh;
570
571 pim_ifp = ifp->info;
572 zassert(pim_ifp);
573
574 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
575 neigh_nextnode, neigh)) {
576 pim_neighbor_delete(ifp, neigh, delete_message);
577 }
578}
579
580struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
581 struct in_addr addr)
582{
583 struct listnode *node;
584 struct prefix *p;
585
586 if (!neigh->prefix_list)
587 return 0;
588
589 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
590 if (p->family == AF_INET) {
591 if (addr.s_addr == p->u.prefix4.s_addr) {
592 return p;
593 }
594 }
595 }
596
597 return 0;
598}
599
600/*
601 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
602
603 All the advertised secondary addresses in received Hello messages
604 must be checked against those previously advertised by all other
605 PIM neighbors on that interface. If there is a conflict and the
606 same secondary address was previously advertised by another
607 neighbor, then only the most recently received mapping MUST be
608 maintained, and an error message SHOULD be logged to the
609 administrator in a rate-limited manner.
610*/
611static void delete_from_neigh_addr(struct interface *ifp,
612 struct list *addr_list,
613 struct in_addr neigh_addr)
614{
615 struct listnode *addr_node;
616 struct prefix *addr;
617 struct pim_interface *pim_ifp;
618
619 pim_ifp = ifp->info;
620 zassert(pim_ifp);
621
622 zassert(addr_list);
623
624 /*
625 Scan secondary address list
626 */
627 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node,
628 addr)) {
629 struct listnode *neigh_node;
630 struct pim_neighbor *neigh;
631
632 if (addr->family != AF_INET)
633 continue;
634
635 /*
636 Scan neighbors
637 */
638 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
639 neigh)) {
640 {
641 struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
642 if (p) {
643 char addr_str[100];
644 char this_neigh_str[100];
645 char other_neigh_str[100];
646
647 pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
648 pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));
649 pim_inet4_dump("<neigh2?>", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str));
650
651 zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s",
652 addr_str, this_neigh_str, other_neigh_str, ifp->name);
653
654 listnode_delete(neigh->prefix_list, p);
655 prefix_free(p);
656 }
657 }
658
659 } /* scan neighbors */
660
661 } /* scan addr list */
662
663}
664
665void pim_neighbor_update(struct pim_neighbor *neigh,
666 pim_hello_options hello_options,
667 uint16_t holdtime,
668 uint32_t dr_priority,
669 struct list *addr_list)
670{
671 struct pim_interface *pim_ifp = neigh->interface->info;
672
673 /* Received holdtime ? */
674 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
675 pim_neighbor_timer_reset(neigh, holdtime);
676 }
677 else {
678 pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
679 }
680
681#ifdef DUMP_PREFIX_LIST
682 zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
683 __PRETTY_FUNCTION__,
684 (unsigned) neigh->prefix_list,
685 neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1,
686 (unsigned) addr_list,
687 addr_list ? (int) listcount(addr_list) : -1);
688#endif
689
690 if (neigh->prefix_list == addr_list) {
691 if (addr_list) {
692 zlog_err("%s: internal error: trying to replace same prefix list=%u",
693 __PRETTY_FUNCTION__, (unsigned) addr_list);
694 }
695 }
696 else {
697 /* Delete existing secondary address list */
698 delete_prefix_list(neigh);
699 }
700
701 if (addr_list) {
702 delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr);
703 }
704
705 /* Replace secondary address list */
706 neigh->prefix_list = addr_list;
707
708 update_dr_priority(neigh,
709 hello_options,
710 dr_priority);
711 /*
712 Copy flags
713 */
714 neigh->hello_options = hello_options;
715}