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