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