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