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