]> git.proxmox.com Git - mirror_frr.git/blob - pimd/pim_neighbor.c
*: Rename `struct thread` to `struct event`
[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 event *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 event *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, bool secondary)
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 if (secondary) {
429 struct prefix p;
430
431 pim_addr_to_prefix(&p, source_addr);
432 return pim_neighbor_find_by_secondary(ifp, &p);
433 }
434
435 return NULL;
436 }
437
438 /*
439 * Find the *one* interface out
440 * this interface. If more than
441 * one return NULL
442 */
443 struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp)
444 {
445 struct pim_interface *pim_ifp = ifp->info;
446
447 if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
448 return NULL;
449
450 return listnode_head(pim_ifp->pim_neighbor_list);
451 }
452
453 struct pim_neighbor *
454 pim_neighbor_add(struct interface *ifp, pim_addr source_addr,
455 pim_hello_options hello_options, uint16_t holdtime,
456 uint16_t propagation_delay, uint16_t override_interval,
457 uint32_t dr_priority, uint32_t generation_id,
458 struct list *addr_list, int send_hello_now)
459 {
460 struct pim_interface *pim_ifp;
461 struct pim_neighbor *neigh;
462
463 neigh = pim_neighbor_new(ifp, source_addr, hello_options, holdtime,
464 propagation_delay, override_interval,
465 dr_priority, generation_id, addr_list);
466 if (!neigh) {
467 return 0;
468 }
469
470 pim_ifp = ifp->info;
471 assert(pim_ifp);
472
473 listnode_add(pim_ifp->pim_neighbor_list, neigh);
474
475 if (PIM_DEBUG_PIM_TRACE_DETAIL)
476 zlog_debug("%s: neighbor %pPA added ", __func__, &source_addr);
477 /*
478 RFC 4601: 4.3.2. DR Election
479
480 A router's idea of the current DR on an interface can change when a
481 PIM Hello message is received, when a neighbor times out, or when a
482 router's own DR Priority changes.
483 */
484 pim_if_dr_election(neigh->interface); // new neighbor -- should not
485 // trigger dr election...
486
487 /*
488 RFC 4601: 4.3.1. Sending Hello Messages
489
490 To allow new or rebooting routers to learn of PIM neighbors quickly,
491 when a Hello message is received from a new neighbor, or a Hello
492 message with a new GenID is received from an existing neighbor, a
493 new Hello message should be sent on this interface after a
494 randomized delay between 0 and Triggered_Hello_Delay.
495
496 This is a bit silly to do it that way. If I get a new
497 genid we need to send the hello *now* because we've
498 lined up a bunch of join/prune messages to go out the
499 interface.
500 */
501 if (send_hello_now)
502 pim_hello_restart_now(ifp);
503 else
504 pim_hello_restart_triggered(neigh->interface);
505
506 pim_upstream_find_new_rpf(pim_ifp->pim);
507
508 /* RNH can send nexthop update prior to PIM neibhor UP
509 in that case nexthop cache would not consider this neighbor
510 as RPF.
511 Upon PIM neighbor UP, iterate all RPs and update
512 nexthop cache with this neighbor.
513 */
514 pim_resolve_rp_nh(pim_ifp->pim, neigh);
515
516 pim_rp_setup(pim_ifp->pim);
517
518 sched_rpf_cache_refresh(pim_ifp->pim);
519 return neigh;
520 }
521
522 static uint16_t find_neighbors_next_highest_propagation_delay_msec(
523 struct interface *ifp, struct pim_neighbor *highest_neigh)
524 {
525 struct pim_interface *pim_ifp;
526 struct listnode *neigh_node;
527 struct pim_neighbor *neigh;
528 uint16_t next_highest_delay_msec;
529
530 pim_ifp = ifp->info;
531 assert(pim_ifp);
532
533 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
534
535 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
536 neigh)) {
537 if (neigh == highest_neigh)
538 continue;
539 if (neigh->propagation_delay_msec > next_highest_delay_msec)
540 next_highest_delay_msec = neigh->propagation_delay_msec;
541 }
542
543 return next_highest_delay_msec;
544 }
545
546 static uint16_t find_neighbors_next_highest_override_interval_msec(
547 struct interface *ifp, struct pim_neighbor *highest_neigh)
548 {
549 struct pim_interface *pim_ifp;
550 struct listnode *neigh_node;
551 struct pim_neighbor *neigh;
552 uint16_t next_highest_interval_msec;
553
554 pim_ifp = ifp->info;
555 assert(pim_ifp);
556
557 next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
558
559 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
560 neigh)) {
561 if (neigh == highest_neigh)
562 continue;
563 if (neigh->override_interval_msec > next_highest_interval_msec)
564 next_highest_interval_msec =
565 neigh->override_interval_msec;
566 }
567
568 return next_highest_interval_msec;
569 }
570
571 void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh,
572 const char *delete_message)
573 {
574 struct pim_interface *pim_ifp;
575
576 pim_ifp = ifp->info;
577 assert(pim_ifp);
578
579 zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s",
580 &neigh->source_addr, ifp->name, delete_message);
581
582 THREAD_OFF(neigh->t_expire_timer);
583
584 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
585
586 if (!PIM_OPTION_IS_SET(neigh->hello_options,
587 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
588 /* update num. of neighbors without hello option lan_delay */
589
590 --pim_ifp->pim_number_of_nonlandelay_neighbors;
591 }
592
593 if (!PIM_OPTION_IS_SET(neigh->hello_options,
594 PIM_OPTION_MASK_DR_PRIORITY)) {
595 /* update num. of neighbors without dr_pri */
596
597 --pim_ifp->pim_dr_num_nondrpri_neighbors;
598 }
599
600 assert(neigh->propagation_delay_msec
601 <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
602 assert(neigh->override_interval_msec
603 <= pim_ifp->pim_neighbors_highest_override_interval_msec);
604
605 if (pim_if_lan_delay_enabled(ifp)) {
606
607 /* will delete a neighbor with highest propagation delay? */
608 if (neigh->propagation_delay_msec
609 == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
610 /* then find the next highest propagation delay */
611 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
612 find_neighbors_next_highest_propagation_delay_msec(
613 ifp, neigh);
614 }
615
616 /* will delete a neighbor with highest override interval? */
617 if (neigh->override_interval_msec
618 == pim_ifp->pim_neighbors_highest_override_interval_msec) {
619 /* then find the next highest propagation delay */
620 pim_ifp->pim_neighbors_highest_override_interval_msec =
621 find_neighbors_next_highest_override_interval_msec(
622 ifp, neigh);
623 }
624 }
625
626 if (PIM_DEBUG_PIM_TRACE) {
627 zlog_debug("%s: deleting PIM neighbor %pPA on interface %s",
628 __func__, &neigh->source_addr, ifp->name);
629 }
630
631 listnode_delete(pim_ifp->pim_neighbor_list, neigh);
632
633 pim_neighbor_free(neigh);
634
635 sched_rpf_cache_refresh(pim_ifp->pim);
636 }
637
638 void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message)
639 {
640 struct pim_interface *pim_ifp;
641 struct listnode *neigh_node;
642 struct listnode *neigh_nextnode;
643 struct pim_neighbor *neigh;
644
645 pim_ifp = ifp->info;
646 assert(pim_ifp);
647
648 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
649 neigh_nextnode, neigh)) {
650 pim_neighbor_delete(ifp, neigh, delete_message);
651 }
652 }
653
654 struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
655 struct prefix *addr)
656 {
657 struct listnode *node;
658 struct prefix *p;
659
660 if (!neigh->prefix_list)
661 return 0;
662
663 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
664 if (prefix_same(p, addr))
665 return p;
666 }
667
668 return NULL;
669 }
670
671 /*
672 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
673
674 All the advertised secondary addresses in received Hello messages
675 must be checked against those previously advertised by all other
676 PIM neighbors on that interface. If there is a conflict and the
677 same secondary address was previously advertised by another
678 neighbor, then only the most recently received mapping MUST be
679 maintained, and an error message SHOULD be logged to the
680 administrator in a rate-limited manner.
681 */
682 static void delete_from_neigh_addr(struct interface *ifp,
683 struct list *addr_list, pim_addr neigh_addr)
684 {
685 struct listnode *addr_node;
686 struct prefix *addr;
687 struct pim_interface *pim_ifp;
688
689 pim_ifp = ifp->info;
690 assert(pim_ifp);
691
692 assert(addr_list);
693
694 /*
695 Scan secondary address list
696 */
697 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, addr)) {
698 struct listnode *neigh_node;
699 struct pim_neighbor *neigh;
700
701 if (addr->family != PIM_AF)
702 continue;
703 /*
704 Scan neighbors
705 */
706 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
707 neigh_node, neigh)) {
708 {
709 struct prefix *p = pim_neighbor_find_secondary(
710 neigh, addr);
711 if (p) {
712 zlog_info(
713 "secondary addr %pFXh recvd from neigh %pPA deleted from neigh %pPA on %s",
714 addr, &neigh_addr,
715 &neigh->source_addr, ifp->name);
716
717 listnode_delete(neigh->prefix_list, p);
718 prefix_free(&p);
719 }
720 }
721
722 } /* scan neighbors */
723
724 } /* scan addr list */
725 }
726
727 void pim_neighbor_update(struct pim_neighbor *neigh,
728 pim_hello_options hello_options, uint16_t holdtime,
729 uint32_t dr_priority, struct list *addr_list)
730 {
731 struct pim_interface *pim_ifp = neigh->interface->info;
732 uint32_t old, new;
733
734 /* Received holdtime ? */
735 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
736 pim_neighbor_timer_reset(neigh, holdtime);
737 } else {
738 pim_neighbor_timer_reset(neigh,
739 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
740 }
741
742 #ifdef DUMP_PREFIX_LIST
743 zlog_debug(
744 "%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
745 __func__, (unsigned)neigh->prefix_list,
746 neigh->prefix_list ? (int)listcount(neigh->prefix_list) : -1,
747 (unsigned)addr_list,
748 addr_list ? (int)listcount(addr_list) : -1);
749 #endif
750
751 if (neigh->prefix_list == addr_list) {
752 if (addr_list) {
753 flog_err(
754 EC_LIB_DEVELOPMENT,
755 "%s: internal error: trying to replace same prefix list=%p",
756 __func__, (void *)addr_list);
757 }
758 } else {
759 /* Delete existing secondary address list */
760 delete_prefix_list(neigh);
761 }
762
763 if (addr_list) {
764 delete_from_neigh_addr(neigh->interface, addr_list,
765 neigh->source_addr);
766 }
767
768 /* Replace secondary address list */
769 neigh->prefix_list = addr_list;
770
771 update_dr_priority(neigh, hello_options, dr_priority);
772 new = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
773 old = PIM_OPTION_IS_SET(neigh->hello_options,
774 PIM_OPTION_MASK_LAN_PRUNE_DELAY);
775
776 if (old != new) {
777 if (old)
778 ++pim_ifp->pim_number_of_nonlandelay_neighbors;
779 else
780 --pim_ifp->pim_number_of_nonlandelay_neighbors;
781 }
782 /*
783 Copy flags
784 */
785 neigh->hello_options = hello_options;
786 }