]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_neighbor.c
doc: Add `show ipv6 rpf X:X::X:X` command to docs
[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 along
16 * with this program; see the file COPYING; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 #include <zebra.h>
21
22 #include "log.h"
23 #include "prefix.h"
24 #include "memory.h"
25 #include "if.h"
26 #include "vty.h"
27 #include "plist.h"
28 #include "lib_errors.h"
29
30 #include "pimd.h"
31 #include "pim_instance.h"
32 #include "pim_neighbor.h"
33 #include "pim_time.h"
34 #include "pim_str.h"
35 #include "pim_iface.h"
36 #include "pim_pim.h"
37 #include "pim_upstream.h"
38 #include "pim_ifchannel.h"
39 #include "pim_rp.h"
40 #include "pim_zebra.h"
41 #include "pim_join.h"
42 #include "pim_jp_agg.h"
43 #include "pim_bfd.h"
44 #include "pim_register.h"
45
46 static void dr_election_by_addr(struct interface *ifp)
47 {
48 struct pim_interface *pim_ifp;
49 struct listnode *node;
50 struct pim_neighbor *neigh;
51
52 pim_ifp = ifp->info;
53 assert(pim_ifp);
54
55 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
56
57 if (PIM_DEBUG_PIM_TRACE) {
58 zlog_debug("%s: on interface %s", __func__, ifp->name);
59 }
60
61 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
62 if (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) > 0)
63 pim_ifp->pim_dr_addr = neigh->source_addr;
64 }
65 }
66
67 static void dr_election_by_pri(struct interface *ifp)
68 {
69 struct pim_interface *pim_ifp;
70 struct listnode *node;
71 struct pim_neighbor *neigh;
72 uint32_t dr_pri;
73
74 pim_ifp = ifp->info;
75 assert(pim_ifp);
76
77 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
78 dr_pri = pim_ifp->pim_dr_priority;
79
80 if (PIM_DEBUG_PIM_TRACE) {
81 zlog_debug("%s: dr pri %u on interface %s", __func__, dr_pri,
82 ifp->name);
83 }
84
85 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
86 if (PIM_DEBUG_PIM_TRACE) {
87 zlog_info("%s: neigh pri %u addr %pPA if dr addr %pPA",
88 __func__, neigh->dr_priority,
89 &neigh->source_addr, &pim_ifp->pim_dr_addr);
90 }
91 if ((neigh->dr_priority > dr_pri) ||
92 ((neigh->dr_priority == dr_pri) &&
93 (pim_addr_cmp(neigh->source_addr, pim_ifp->pim_dr_addr) >
94 0))) {
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 pim_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 } else {
120 dr_election_by_pri(ifp);
121 }
122
123 /* DR changed ? */
124 if (pim_addr_cmp(old_dr_addr, pim_ifp->pim_dr_addr)) {
125
126 if (PIM_DEBUG_PIM_EVENTS)
127 zlog_debug(
128 "%s: DR was %pPA now is %pPA on interface %s",
129 __func__, &old_dr_addr, &pim_ifp->pim_dr_addr,
130 ifp->name);
131
132 pim_ifp->pim_dr_election_last =
133 pim_time_monotonic_sec(); /* timestamp */
134 ++pim_ifp->pim_dr_election_changes;
135 pim_if_update_join_desired(pim_ifp);
136 pim_if_update_could_assert(ifp);
137 pim_if_update_assert_tracking_desired(ifp);
138
139 if (PIM_I_am_DR(pim_ifp))
140 pim_ifp->am_i_dr = true;
141 else {
142 if (pim_ifp->am_i_dr == true) {
143 pim_reg_del_on_couldreg_fail(ifp);
144 pim_ifp->am_i_dr = false;
145 }
146 }
147
148 return 1;
149 }
150
151 return 0;
152 }
153
154 static void update_dr_priority(struct pim_neighbor *neigh,
155 pim_hello_options hello_options,
156 uint32_t dr_priority)
157 {
158 pim_hello_options will_set_pri; /* boolean */
159 pim_hello_options bit_flip; /* boolean */
160 pim_hello_options pri_change; /* boolean */
161
162 will_set_pri =
163 PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_DR_PRIORITY);
164
165 bit_flip = (will_set_pri
166 != PIM_OPTION_IS_SET(neigh->hello_options,
167 PIM_OPTION_MASK_DR_PRIORITY));
168
169 if (bit_flip) {
170 struct pim_interface *pim_ifp = neigh->interface->info;
171
172 /* update num. of neighbors without dr_pri */
173
174 if (will_set_pri) {
175 --pim_ifp->pim_dr_num_nondrpri_neighbors;
176 } else {
177 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
178 }
179 }
180
181 pri_change = (bit_flip || (neigh->dr_priority != dr_priority));
182
183 if (will_set_pri) {
184 neigh->dr_priority = dr_priority;
185 } else {
186 neigh->dr_priority = 0; /* cosmetic unset */
187 }
188
189 if (pri_change) {
190 /*
191 RFC 4601: 4.3.2. DR Election
192
193 A router's idea of the current DR on an interface can change
194 when a
195 PIM Hello message is received, when a neighbor times out, or
196 when a
197 router's own DR Priority changes.
198 */
199 pim_if_dr_election(
200 neigh->interface); // router's own DR Priority changes
201 }
202 }
203
204 static void on_neighbor_timer(struct thread *t)
205 {
206 struct pim_neighbor *neigh;
207 struct interface *ifp;
208 char msg[100];
209
210 neigh = THREAD_ARG(t);
211
212 ifp = neigh->interface;
213
214 if (PIM_DEBUG_PIM_TRACE)
215 zlog_debug(
216 "Expired %d sec holdtime for neighbor %pPA on interface %s",
217 neigh->holdtime, &neigh->source_addr, ifp->name);
218
219 snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
220 pim_neighbor_delete(ifp, neigh, msg);
221
222 /*
223 RFC 4601: 4.3.2. DR Election
224
225 A router's idea of the current DR on an interface can change when a
226 PIM Hello message is received, when a neighbor times out, or when a
227 router's own DR Priority changes.
228 */
229 pim_if_dr_election(ifp); // neighbor times out
230 }
231
232 void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
233 {
234 neigh->holdtime = holdtime;
235
236 THREAD_OFF(neigh->t_expire_timer);
237
238 /*
239 0xFFFF is request for no holdtime
240 */
241 if (neigh->holdtime == 0xFFFF) {
242 return;
243 }
244
245 if (PIM_DEBUG_PIM_TRACE_DETAIL)
246 zlog_debug("%s: starting %u sec timer for neighbor %pPA on %s",
247 __func__, neigh->holdtime, &neigh->source_addr,
248 neigh->interface->name);
249
250 thread_add_timer(router->master, on_neighbor_timer, neigh,
251 neigh->holdtime, &neigh->t_expire_timer);
252 }
253
254 static void on_neighbor_jp_timer(struct thread *t)
255 {
256 struct pim_neighbor *neigh = THREAD_ARG(t);
257 struct pim_rpf rpf;
258
259 if (PIM_DEBUG_PIM_TRACE)
260 zlog_debug("%s:Sending JP Agg to %pPA on %s with %d groups",
261 __func__, &neigh->source_addr,
262 neigh->interface->name,
263 neigh->upstream_jp_agg->count);
264
265 rpf.source_nexthop.interface = neigh->interface;
266 rpf.rpf_addr = neigh->source_addr;
267 pim_joinprune_send(&rpf, neigh->upstream_jp_agg);
268
269 thread_add_timer(router->master, on_neighbor_jp_timer, neigh,
270 router->t_periodic, &neigh->jp_timer);
271 }
272
273 static void pim_neighbor_start_jp_timer(struct pim_neighbor *neigh)
274 {
275 THREAD_OFF(neigh->jp_timer);
276 thread_add_timer(router->master, on_neighbor_jp_timer, neigh,
277 router->t_periodic, &neigh->jp_timer);
278 }
279
280 static struct pim_neighbor *
281 pim_neighbor_new(struct interface *ifp, pim_addr source_addr,
282 pim_hello_options hello_options, uint16_t holdtime,
283 uint16_t propagation_delay, uint16_t override_interval,
284 uint32_t dr_priority, uint32_t generation_id,
285 struct list *addr_list)
286 {
287 struct pim_interface *pim_ifp;
288 struct pim_neighbor *neigh;
289
290 assert(ifp);
291 pim_ifp = ifp->info;
292 assert(pim_ifp);
293
294 neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
295
296 neigh->creation = pim_time_monotonic_sec();
297 neigh->source_addr = source_addr;
298 neigh->hello_options = hello_options;
299 neigh->propagation_delay_msec = propagation_delay;
300 neigh->override_interval_msec = override_interval;
301 neigh->dr_priority = dr_priority;
302 neigh->generation_id = generation_id;
303 neigh->prefix_list = addr_list;
304 neigh->t_expire_timer = NULL;
305 neigh->interface = ifp;
306
307 neigh->upstream_jp_agg = list_new();
308 neigh->upstream_jp_agg->cmp = pim_jp_agg_group_list_cmp;
309 neigh->upstream_jp_agg->del =
310 (void (*)(void *))pim_jp_agg_group_list_free;
311 pim_neighbor_start_jp_timer(neigh);
312
313 pim_neighbor_timer_reset(neigh, holdtime);
314 /*
315 * The pim_ifstat_hello_sent variable is used to decide if
316 * we should expedite a hello out the interface. If we
317 * establish a new neighbor, we unfortunately need to
318 * reset the value so that we can know to hurry up and
319 * hello
320 */
321 PIM_IF_FLAG_UNSET_HELLO_SENT(pim_ifp->flags);
322
323 if (PIM_DEBUG_PIM_EVENTS)
324 zlog_debug("%s: creating PIM neighbor %pPA on interface %s",
325 __func__, &source_addr, ifp->name);
326
327 zlog_notice("PIM NEIGHBOR UP: neighbor %pPA on interface %s",
328 &source_addr, ifp->name);
329
330 if (neigh->propagation_delay_msec
331 > pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
332 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
333 neigh->propagation_delay_msec;
334 }
335 if (neigh->override_interval_msec
336 > pim_ifp->pim_neighbors_highest_override_interval_msec) {
337 pim_ifp->pim_neighbors_highest_override_interval_msec =
338 neigh->override_interval_msec;
339 }
340
341 if (!PIM_OPTION_IS_SET(neigh->hello_options,
342 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
343 /* update num. of neighbors without hello option lan_delay */
344 ++pim_ifp->pim_number_of_nonlandelay_neighbors;
345 }
346
347 if (!PIM_OPTION_IS_SET(neigh->hello_options,
348 PIM_OPTION_MASK_DR_PRIORITY)) {
349 /* update num. of neighbors without hello option dr_pri */
350 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
351 }
352
353 // Register PIM Neighbor with BFD
354 pim_bfd_info_nbr_create(pim_ifp, neigh);
355
356 return neigh;
357 }
358
359 static void delete_prefix_list(struct pim_neighbor *neigh)
360 {
361 if (neigh->prefix_list) {
362
363 #ifdef DUMP_PREFIX_LIST
364 struct listnode *p_node;
365 struct prefix *p;
366 int list_size = neigh->prefix_list
367 ? (int)listcount(neigh->prefix_list)
368 : -1;
369 int i = 0;
370 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) {
371 zlog_debug(
372 "%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%pFXh [%d/%d]",
373 __func__, (unsigned)neigh,
374 (unsigned)neigh->prefix_list, (unsigned)p, p, i,
375 list_size);
376 ++i;
377 }
378 #endif
379
380 list_delete(&neigh->prefix_list);
381 }
382 }
383
384 void pim_neighbor_free(struct pim_neighbor *neigh)
385 {
386 assert(!neigh->t_expire_timer);
387
388 delete_prefix_list(neigh);
389
390 list_delete(&neigh->upstream_jp_agg);
391 THREAD_OFF(neigh->jp_timer);
392
393 bfd_sess_free(&neigh->bfd_session);
394
395 XFREE(MTYPE_PIM_NEIGHBOR, neigh);
396 }
397
398 struct pim_neighbor *pim_neighbor_find_by_secondary(struct interface *ifp,
399 struct prefix *src)
400 {
401 struct pim_interface *pim_ifp;
402 struct listnode *node, *pnode;
403 struct pim_neighbor *neigh;
404 struct prefix *p;
405
406 if (!ifp || !ifp->info)
407 return NULL;
408
409 pim_ifp = ifp->info;
410
411 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
412 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, pnode, p)) {
413 if (prefix_same(p, src))
414 return neigh;
415 }
416 }
417
418 return NULL;
419 }
420
421 struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
422 pim_addr source_addr)
423 {
424 struct pim_interface *pim_ifp;
425 struct listnode *node;
426 struct pim_neighbor *neigh;
427
428 if (!ifp)
429 return NULL;
430
431 pim_ifp = ifp->info;
432 if (!pim_ifp)
433 return NULL;
434
435 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
436 if (!pim_addr_cmp(source_addr, neigh->source_addr)) {
437 return neigh;
438 }
439 }
440
441 return NULL;
442 }
443
444 /*
445 * Find the *one* interface out
446 * this interface. If more than
447 * one return NULL
448 */
449 struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp)
450 {
451 struct pim_interface *pim_ifp = ifp->info;
452
453 if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
454 return NULL;
455
456 return listnode_head(pim_ifp->pim_neighbor_list);
457 }
458
459 struct pim_neighbor *
460 pim_neighbor_add(struct interface *ifp, pim_addr source_addr,
461 pim_hello_options hello_options, uint16_t holdtime,
462 uint16_t propagation_delay, uint16_t override_interval,
463 uint32_t dr_priority, uint32_t generation_id,
464 struct list *addr_list, int send_hello_now)
465 {
466 struct pim_interface *pim_ifp;
467 struct pim_neighbor *neigh;
468
469 neigh = pim_neighbor_new(ifp, source_addr, hello_options, holdtime,
470 propagation_delay, override_interval,
471 dr_priority, generation_id, addr_list);
472 if (!neigh) {
473 return 0;
474 }
475
476 pim_ifp = ifp->info;
477 assert(pim_ifp);
478
479 listnode_add(pim_ifp->pim_neighbor_list, neigh);
480
481 if (PIM_DEBUG_PIM_TRACE_DETAIL)
482 zlog_debug("%s: neighbor %pPA added ", __func__, &source_addr);
483 /*
484 RFC 4601: 4.3.2. DR Election
485
486 A router's idea of the current DR on an interface can change when a
487 PIM Hello message is received, when a neighbor times out, or when a
488 router's own DR Priority changes.
489 */
490 pim_if_dr_election(neigh->interface); // new neighbor -- should not
491 // trigger dr election...
492
493 /*
494 RFC 4601: 4.3.1. Sending Hello Messages
495
496 To allow new or rebooting routers to learn of PIM neighbors quickly,
497 when a Hello message is received from a new neighbor, or a Hello
498 message with a new GenID is received from an existing neighbor, a
499 new Hello message should be sent on this interface after a
500 randomized delay between 0 and Triggered_Hello_Delay.
501
502 This is a bit silly to do it that way. If I get a new
503 genid we need to send the hello *now* because we've
504 lined up a bunch of join/prune messages to go out the
505 interface.
506 */
507 if (send_hello_now)
508 pim_hello_restart_now(ifp);
509 else
510 pim_hello_restart_triggered(neigh->interface);
511
512 pim_upstream_find_new_rpf(pim_ifp->pim);
513
514 /* RNH can send nexthop update prior to PIM neibhor UP
515 in that case nexthop cache would not consider this neighbor
516 as RPF.
517 Upon PIM neighbor UP, iterate all RPs and update
518 nexthop cache with this neighbor.
519 */
520 pim_resolve_rp_nh(pim_ifp->pim, neigh);
521
522 pim_rp_setup(pim_ifp->pim);
523
524 sched_rpf_cache_refresh(pim_ifp->pim);
525 return neigh;
526 }
527
528 static uint16_t find_neighbors_next_highest_propagation_delay_msec(
529 struct interface *ifp, struct pim_neighbor *highest_neigh)
530 {
531 struct pim_interface *pim_ifp;
532 struct listnode *neigh_node;
533 struct pim_neighbor *neigh;
534 uint16_t next_highest_delay_msec;
535
536 pim_ifp = ifp->info;
537 assert(pim_ifp);
538
539 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
540
541 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
542 neigh)) {
543 if (neigh == highest_neigh)
544 continue;
545 if (neigh->propagation_delay_msec > next_highest_delay_msec)
546 next_highest_delay_msec = neigh->propagation_delay_msec;
547 }
548
549 return next_highest_delay_msec;
550 }
551
552 static uint16_t find_neighbors_next_highest_override_interval_msec(
553 struct interface *ifp, struct pim_neighbor *highest_neigh)
554 {
555 struct pim_interface *pim_ifp;
556 struct listnode *neigh_node;
557 struct pim_neighbor *neigh;
558 uint16_t next_highest_interval_msec;
559
560 pim_ifp = ifp->info;
561 assert(pim_ifp);
562
563 next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
564
565 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
566 neigh)) {
567 if (neigh == highest_neigh)
568 continue;
569 if (neigh->override_interval_msec > next_highest_interval_msec)
570 next_highest_interval_msec =
571 neigh->override_interval_msec;
572 }
573
574 return next_highest_interval_msec;
575 }
576
577 void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh,
578 const char *delete_message)
579 {
580 struct pim_interface *pim_ifp;
581
582 pim_ifp = ifp->info;
583 assert(pim_ifp);
584
585 zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s",
586 &neigh->source_addr, ifp->name, delete_message);
587
588 THREAD_OFF(neigh->t_expire_timer);
589
590 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
591
592 if (!PIM_OPTION_IS_SET(neigh->hello_options,
593 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
594 /* update num. of neighbors without hello option lan_delay */
595
596 --pim_ifp->pim_number_of_nonlandelay_neighbors;
597 }
598
599 if (!PIM_OPTION_IS_SET(neigh->hello_options,
600 PIM_OPTION_MASK_DR_PRIORITY)) {
601 /* update num. of neighbors without dr_pri */
602
603 --pim_ifp->pim_dr_num_nondrpri_neighbors;
604 }
605
606 assert(neigh->propagation_delay_msec
607 <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
608 assert(neigh->override_interval_msec
609 <= pim_ifp->pim_neighbors_highest_override_interval_msec);
610
611 if (pim_if_lan_delay_enabled(ifp)) {
612
613 /* will delete a neighbor with highest propagation delay? */
614 if (neigh->propagation_delay_msec
615 == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
616 /* then find the next highest propagation delay */
617 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
618 find_neighbors_next_highest_propagation_delay_msec(
619 ifp, neigh);
620 }
621
622 /* will delete a neighbor with highest override interval? */
623 if (neigh->override_interval_msec
624 == pim_ifp->pim_neighbors_highest_override_interval_msec) {
625 /* then find the next highest propagation delay */
626 pim_ifp->pim_neighbors_highest_override_interval_msec =
627 find_neighbors_next_highest_override_interval_msec(
628 ifp, neigh);
629 }
630 }
631
632 if (PIM_DEBUG_PIM_TRACE) {
633 zlog_debug("%s: deleting PIM neighbor %pPA on interface %s",
634 __func__, &neigh->source_addr, ifp->name);
635 }
636
637 listnode_delete(pim_ifp->pim_neighbor_list, neigh);
638
639 pim_neighbor_free(neigh);
640
641 sched_rpf_cache_refresh(pim_ifp->pim);
642 }
643
644 void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message)
645 {
646 struct pim_interface *pim_ifp;
647 struct listnode *neigh_node;
648 struct listnode *neigh_nextnode;
649 struct pim_neighbor *neigh;
650
651 pim_ifp = ifp->info;
652 assert(pim_ifp);
653
654 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
655 neigh_nextnode, neigh)) {
656 pim_neighbor_delete(ifp, neigh, delete_message);
657 }
658 }
659
660 struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
661 struct prefix *addr)
662 {
663 struct listnode *node;
664 struct prefix *p;
665
666 if (!neigh->prefix_list)
667 return 0;
668
669 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
670 if (prefix_same(p, addr))
671 return p;
672 }
673
674 return NULL;
675 }
676
677 /*
678 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
679
680 All the advertised secondary addresses in received Hello messages
681 must be checked against those previously advertised by all other
682 PIM neighbors on that interface. If there is a conflict and the
683 same secondary address was previously advertised by another
684 neighbor, then only the most recently received mapping MUST be
685 maintained, and an error message SHOULD be logged to the
686 administrator in a rate-limited manner.
687 */
688 static void delete_from_neigh_addr(struct interface *ifp,
689 struct list *addr_list, pim_addr neigh_addr)
690 {
691 struct listnode *addr_node;
692 struct prefix *addr;
693 struct pim_interface *pim_ifp;
694
695 pim_ifp = ifp->info;
696 assert(pim_ifp);
697
698 assert(addr_list);
699
700 /*
701 Scan secondary address list
702 */
703 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, addr)) {
704 struct listnode *neigh_node;
705 struct pim_neighbor *neigh;
706
707 if (addr->family != PIM_AF)
708 continue;
709 /*
710 Scan neighbors
711 */
712 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
713 neigh_node, neigh)) {
714 {
715 struct prefix *p = pim_neighbor_find_secondary(
716 neigh, addr);
717 if (p) {
718 zlog_info(
719 "secondary addr %pFXh recvd from neigh %pPA deleted from neigh %pPA on %s",
720 addr, &neigh_addr,
721 &neigh->source_addr, ifp->name);
722
723 listnode_delete(neigh->prefix_list, p);
724 prefix_free(&p);
725 }
726 }
727
728 } /* scan neighbors */
729
730 } /* scan addr list */
731 }
732
733 void pim_neighbor_update(struct pim_neighbor *neigh,
734 pim_hello_options hello_options, uint16_t holdtime,
735 uint32_t dr_priority, struct list *addr_list)
736 {
737 struct pim_interface *pim_ifp = neigh->interface->info;
738 uint32_t old, new;
739
740 /* Received holdtime ? */
741 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
742 pim_neighbor_timer_reset(neigh, holdtime);
743 } else {
744 pim_neighbor_timer_reset(neigh,
745 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
746 }
747
748 #ifdef DUMP_PREFIX_LIST
749 zlog_debug(
750 "%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
751 __func__, (unsigned)neigh->prefix_list,
752 neigh->prefix_list ? (int)listcount(neigh->prefix_list) : -1,
753 (unsigned)addr_list,
754 addr_list ? (int)listcount(addr_list) : -1);
755 #endif
756
757 if (neigh->prefix_list == addr_list) {
758 if (addr_list) {
759 flog_err(
760 EC_LIB_DEVELOPMENT,
761 "%s: internal error: trying to replace same prefix list=%p",
762 __func__, (void *)addr_list);
763 }
764 } else {
765 /* Delete existing secondary address list */
766 delete_prefix_list(neigh);
767 }
768
769 if (addr_list) {
770 delete_from_neigh_addr(neigh->interface, addr_list,
771 neigh->source_addr);
772 }
773
774 /* Replace secondary address list */
775 neigh->prefix_list = addr_list;
776
777 update_dr_priority(neigh, hello_options, dr_priority);
778 new = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
779 old = PIM_OPTION_IS_SET(neigh->hello_options,
780 PIM_OPTION_MASK_LAN_PRUNE_DELAY);
781
782 if (old != new) {
783 if (old)
784 ++pim_ifp->pim_number_of_nonlandelay_neighbors;
785 else
786 --pim_ifp->pim_number_of_nonlandelay_neighbors;
787 }
788 /*
789 Copy flags
790 */
791 neigh->hello_options = hello_options;
792 }