]> git.sommitrealweird.co.uk Git - quagga-debian.git/blob - pimd/pim_neighbor.c
New upstream version 1.2.4
[quagga-debian.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
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
38 static 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
62 static 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  */
109 int pim_if_dr_election(struct interface *ifp)
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
128     if (PIM_DEBUG_PIM_EVENTS) {
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);
143     return 1;
144   }
145
146   return 0;
147 }
148
149 static 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
205 static 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
241 static 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
256 void 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
282 static 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
350   return neigh;
351 }
352
353 static 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
378 void 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
387 struct 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
406 struct 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
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
456   return neigh;
457 }
458
459 static uint16_t
460 find_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
483 static uint16_t
484 find_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
507 void 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
570 void 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
587 struct 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 */
618 static 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
672 void 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 }