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