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