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