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