]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_neighbor.c
pimd: trigger on nbr up to look at rpf cache
[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
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "log.h"
25#include "prefix.h"
26#include "memory.h"
744d91b3 27#include "if.h"
12e41d03
DL
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
59ba0ac3 224 neigh->t_expire_timer = NULL;
12e41d03
DL
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{
169edb7f 243 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
12e41d03
DL
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
ce9a0643 269 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
12e41d03
DL
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
36d9e7dc 300 neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
12e41d03 301 if (!neigh) {
36d9e7dc 302 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03
DL
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;
59ba0ac3 315 neigh->t_expire_timer = NULL;
12e41d03
DL
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,
1148de0a
DS
414 struct list *addr_list,
415 int send_hello_now)
12e41d03
DL
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
818a327c
DS
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.
1148de0a
DS
454
455 This is a bit silly to do it that way. If I get a new
456 genid we need to send the hello *now* because we've
457 lined up a bunch of join/prune messages to go out the
458 interface.
818a327c 459 */
1148de0a
DS
460 if (send_hello_now)
461 pim_hello_restart_now (ifp);
462 else
463 pim_hello_restart_triggered(neigh->interface);
818a327c 464
d3dd1804
DS
465 pim_upstream_find_new_rpf();
466
12e41d03
DL
467 return neigh;
468}
469
470static uint16_t
471find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp,
472 struct pim_neighbor *highest_neigh)
473{
474 struct pim_interface *pim_ifp;
475 struct listnode *neigh_node;
476 struct pim_neighbor *neigh;
477 uint16_t next_highest_delay_msec;
478
479 pim_ifp = ifp->info;
480 zassert(pim_ifp);
481
482 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
483
484 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
485 if (neigh == highest_neigh)
486 continue;
487 if (neigh->propagation_delay_msec > next_highest_delay_msec)
488 next_highest_delay_msec = neigh->propagation_delay_msec;
489 }
490
491 return next_highest_delay_msec;
492}
493
494static uint16_t
495find_neighbors_next_highest_override_interval_msec(struct interface *ifp,
496 struct pim_neighbor *highest_neigh)
497{
498 struct pim_interface *pim_ifp;
499 struct listnode *neigh_node;
500 struct pim_neighbor *neigh;
501 uint16_t next_highest_interval_msec;
502
503 pim_ifp = ifp->info;
504 zassert(pim_ifp);
505
506 next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
507
508 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
509 if (neigh == highest_neigh)
510 continue;
511 if (neigh->override_interval_msec > next_highest_interval_msec)
512 next_highest_interval_msec = neigh->override_interval_msec;
513 }
514
515 return next_highest_interval_msec;
516}
517
518void pim_neighbor_delete(struct interface *ifp,
519 struct pim_neighbor *neigh,
520 const char *delete_message)
521{
522 struct pim_interface *pim_ifp;
523 char src_str[100];
524
525 pim_ifp = ifp->info;
526 zassert(pim_ifp);
527
528 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
529 zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
530 src_str, ifp->name, delete_message);
531
532 neighbor_timer_off(neigh);
533
534 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
535
536 if (!PIM_OPTION_IS_SET(neigh->hello_options,
537 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
538 /* update num. of neighbors without hello option lan_delay */
539
540 --pim_ifp->pim_number_of_nonlandelay_neighbors;
541 }
542
543 if (!PIM_OPTION_IS_SET(neigh->hello_options,
544 PIM_OPTION_MASK_DR_PRIORITY)) {
545 /* update num. of neighbors without dr_pri */
546
547 --pim_ifp->pim_dr_num_nondrpri_neighbors;
548 }
549
550 zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
551 zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec);
552
553 if (pim_if_lan_delay_enabled(ifp)) {
554
555 /* will delete a neighbor with highest propagation delay? */
556 if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
557 /* then find the next highest propagation delay */
558 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
559 find_neighbors_next_highest_propagation_delay_msec(ifp, neigh);
560 }
561
562 /* will delete a neighbor with highest override interval? */
563 if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) {
564 /* then find the next highest propagation delay */
565 pim_ifp->pim_neighbors_highest_override_interval_msec =
566 find_neighbors_next_highest_override_interval_msec(ifp, neigh);
567 }
568 }
569
570 if (PIM_DEBUG_PIM_TRACE) {
571 zlog_debug("%s: deleting PIM neighbor %s on interface %s",
572 __PRETTY_FUNCTION__,
573 src_str, ifp->name);
574 }
575
576 listnode_delete(pim_ifp->pim_neighbor_list, neigh);
577
578 pim_neighbor_free(neigh);
579}
580
581void pim_neighbor_delete_all(struct interface *ifp,
582 const char *delete_message)
583{
584 struct pim_interface *pim_ifp;
585 struct listnode *neigh_node;
586 struct listnode *neigh_nextnode;
587 struct pim_neighbor *neigh;
588
589 pim_ifp = ifp->info;
590 zassert(pim_ifp);
591
592 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
593 neigh_nextnode, neigh)) {
594 pim_neighbor_delete(ifp, neigh, delete_message);
595 }
596}
597
598struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
599 struct in_addr addr)
600{
601 struct listnode *node;
602 struct prefix *p;
603
604 if (!neigh->prefix_list)
605 return 0;
606
607 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
608 if (p->family == AF_INET) {
609 if (addr.s_addr == p->u.prefix4.s_addr) {
610 return p;
611 }
612 }
613 }
614
615 return 0;
616}
617
618/*
619 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
620
621 All the advertised secondary addresses in received Hello messages
622 must be checked against those previously advertised by all other
623 PIM neighbors on that interface. If there is a conflict and the
624 same secondary address was previously advertised by another
625 neighbor, then only the most recently received mapping MUST be
626 maintained, and an error message SHOULD be logged to the
627 administrator in a rate-limited manner.
628*/
629static void delete_from_neigh_addr(struct interface *ifp,
630 struct list *addr_list,
631 struct in_addr neigh_addr)
632{
633 struct listnode *addr_node;
634 struct prefix *addr;
635 struct pim_interface *pim_ifp;
636
637 pim_ifp = ifp->info;
638 zassert(pim_ifp);
639
640 zassert(addr_list);
641
642 /*
643 Scan secondary address list
644 */
645 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node,
646 addr)) {
647 struct listnode *neigh_node;
648 struct pim_neighbor *neigh;
649
650 if (addr->family != AF_INET)
651 continue;
652
653 /*
654 Scan neighbors
655 */
656 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
657 neigh)) {
658 {
659 struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
660 if (p) {
661 char addr_str[100];
662 char this_neigh_str[100];
663 char other_neigh_str[100];
664
665 pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
666 pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));
667 pim_inet4_dump("<neigh2?>", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str));
668
669 zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s",
670 addr_str, this_neigh_str, other_neigh_str, ifp->name);
671
672 listnode_delete(neigh->prefix_list, p);
673 prefix_free(p);
674 }
675 }
676
677 } /* scan neighbors */
678
679 } /* scan addr list */
680
681}
682
683void pim_neighbor_update(struct pim_neighbor *neigh,
684 pim_hello_options hello_options,
685 uint16_t holdtime,
686 uint32_t dr_priority,
687 struct list *addr_list)
688{
689 struct pim_interface *pim_ifp = neigh->interface->info;
690
691 /* Received holdtime ? */
692 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
693 pim_neighbor_timer_reset(neigh, holdtime);
694 }
695 else {
696 pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
697 }
698
699#ifdef DUMP_PREFIX_LIST
700 zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
701 __PRETTY_FUNCTION__,
702 (unsigned) neigh->prefix_list,
703 neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1,
704 (unsigned) addr_list,
705 addr_list ? (int) listcount(addr_list) : -1);
706#endif
707
708 if (neigh->prefix_list == addr_list) {
709 if (addr_list) {
710 zlog_err("%s: internal error: trying to replace same prefix list=%p",
711 __PRETTY_FUNCTION__, (void *) addr_list);
712 }
713 }
714 else {
715 /* Delete existing secondary address list */
716 delete_prefix_list(neigh);
717 }
718
719 if (addr_list) {
720 delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr);
721 }
722
723 /* Replace secondary address list */
724 neigh->prefix_list = addr_list;
725
726 update_dr_priority(neigh,
727 hello_options,
728 dr_priority);
729 /*
730 Copy flags
731 */
732 neigh->hello_options = hello_options;
733}