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