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