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