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