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