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