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