]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_neighbor.c
pimd: Fix WG/SGRpt & WG J/P processing
[mirror_frr.git] / pimd / pim_neighbor.c
CommitLineData
12e41d03
DL
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
12e41d03
DL
19*/
20
21#include <zebra.h>
22
23#include "log.h"
24#include "prefix.h"
25#include "memory.h"
744d91b3 26#include "if.h"
e446de6a
DS
27#include "vty.h"
28#include "plist.h"
12e41d03
DL
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"
e446de6a 38#include "pim_rp.h"
da72c9fd 39#include "pim_zebra.h"
982bff89
DS
40#include "pim_join.h"
41#include "pim_jp_agg.h"
12e41d03
DL
42
43static 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
67static 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 */
dedccda6 114int pim_if_dr_election(struct interface *ifp)
12e41d03
DL
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
7adf0260 133 if (PIM_DEBUG_PIM_EVENTS) {
eaa54bdb
DW
134 char dr_old_str[INET_ADDRSTRLEN];
135 char dr_new_str[INET_ADDRSTRLEN];
12e41d03
DL
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);
dedccda6 148 return 1;
12e41d03 149 }
dedccda6
DS
150
151 return 0;
12e41d03
DL
152}
153
154static 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
210static int on_neighbor_timer(struct thread *t)
211{
212 struct pim_neighbor *neigh;
213 struct interface *ifp;
214 char msg[100];
215
12e41d03 216 neigh = THREAD_ARG(t);
12e41d03
DL
217
218 ifp = neigh->interface;
219
220 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 221 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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
59ba0ac3 227 neigh->t_expire_timer = NULL;
12e41d03
DL
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
12e41d03
DL
244void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
245{
246 neigh->holdtime = holdtime;
247
5a515ebe 248 THREAD_OFF(neigh->t_expire_timer);
12e41d03
DL
249
250 /*
251 0xFFFF is request for no holdtime
252 */
253 if (neigh->holdtime == 0xFFFF) {
254 return;
255 }
256
ce9a0643 257 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
eaa54bdb 258 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
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
982bff89
DS
270static int
271on_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
296static void
297pim_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
12e41d03
DL
305static 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;
eaa54bdb 317 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
318
319 zassert(ifp);
320 pim_ifp = ifp->info;
321 zassert(pim_ifp);
322
36d9e7dc 323 neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
12e41d03 324 if (!neigh) {
36d9e7dc 325 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03
DL
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;
59ba0ac3 338 neigh->t_expire_timer = NULL;
12e41d03
DL
339 neigh->interface = ifp;
340
982bff89
DS
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
12e41d03 346 pim_neighbor_timer_reset(neigh, holdtime);
86abfcb8
DS
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;
12e41d03
DL
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
12e41d03
DL
386 return neigh;
387}
388
389static 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
414void pim_neighbor_free(struct pim_neighbor *neigh)
415{
416 zassert(!neigh->t_expire_timer);
417
418 delete_prefix_list(neigh);
419
982bff89
DS
420 list_delete(neigh->upstream_jp_agg);
421 THREAD_OFF(neigh->jp_timer);
422
12e41d03
DL
423 XFREE(MTYPE_PIM_NEIGHBOR, neigh);
424}
425
426struct 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;
69719554
DS
434 if (!pim_ifp)
435 return NULL;
12e41d03
DL
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
69719554 443 return NULL;
12e41d03
DL
444}
445
99deb321
DS
446/*
447 * Find the *one* interface out
448 * this interface. If more than
449 * one return NULL
450 */
451struct pim_neighbor *
452pim_neighbor_find_if (struct interface *ifp)
453{
454 struct pim_interface *pim_ifp = ifp->info;
455
69719554 456 if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
99deb321
DS
457 return NULL;
458
459 return listnode_head (pim_ifp->pim_neighbor_list);
460}
461
da72c9fd 462/* rpf info associated with an upstream entry needs to be re-evaluated
463 * when an RPF neighbor comes or goes */
464static void
465pim_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
12e41d03
DL
474struct 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,
1148de0a
DS
482 struct list *addr_list,
483 int send_hello_now)
12e41d03
DL
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
633988a7
CS
505 if (PIM_DEBUG_PIM_TRACE_DETAIL)
506 {
507 char str[INET_ADDRSTRLEN];
508 pim_inet4_dump("<nht_nbr?>", source_addr, str, sizeof (str));
509 zlog_debug ("%s: neighbor %s added ", __PRETTY_FUNCTION__, str);
510 }
818a327c
DS
511 /*
512 RFC 4601: 4.3.2. DR Election
513
514 A router's idea of the current DR on an interface can change when a
515 PIM Hello message is received, when a neighbor times out, or when a
516 router's own DR Priority changes.
517 */
518 pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election...
519
520 /*
521 RFC 4601: 4.3.1. Sending Hello Messages
522
523 To allow new or rebooting routers to learn of PIM neighbors quickly,
524 when a Hello message is received from a new neighbor, or a Hello
525 message with a new GenID is received from an existing neighbor, a
526 new Hello message should be sent on this interface after a
527 randomized delay between 0 and Triggered_Hello_Delay.
1148de0a
DS
528
529 This is a bit silly to do it that way. If I get a new
530 genid we need to send the hello *now* because we've
531 lined up a bunch of join/prune messages to go out the
532 interface.
818a327c 533 */
1148de0a
DS
534 if (send_hello_now)
535 pim_hello_restart_now (ifp);
536 else
537 pim_hello_restart_triggered(neigh->interface);
818a327c 538
d3dd1804
DS
539 pim_upstream_find_new_rpf();
540
633988a7
CS
541 /* RNH can send nexthop update prior to PIM neibhor UP
542 in that case nexthop cache would not consider this neighbor
543 as RPF.
544 Upon PIM neighbor UP, iterate all RPs and update
545 nexthop cache with this neighbor.
546 */
547 pim_resolve_rp_nh ();
548
e446de6a 549 pim_rp_setup ();
da72c9fd 550
551 pim_neighbor_rpf_update();
12e41d03
DL
552 return neigh;
553}
554
555static uint16_t
556find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp,
557 struct pim_neighbor *highest_neigh)
558{
559 struct pim_interface *pim_ifp;
560 struct listnode *neigh_node;
561 struct pim_neighbor *neigh;
562 uint16_t next_highest_delay_msec;
563
564 pim_ifp = ifp->info;
565 zassert(pim_ifp);
566
567 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
568
569 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
570 if (neigh == highest_neigh)
571 continue;
572 if (neigh->propagation_delay_msec > next_highest_delay_msec)
573 next_highest_delay_msec = neigh->propagation_delay_msec;
574 }
575
576 return next_highest_delay_msec;
577}
578
579static uint16_t
580find_neighbors_next_highest_override_interval_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_interval_msec;
587
588 pim_ifp = ifp->info;
589 zassert(pim_ifp);
590
591 next_highest_interval_msec = pim_ifp->pim_override_interval_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->override_interval_msec > next_highest_interval_msec)
597 next_highest_interval_msec = neigh->override_interval_msec;
598 }
599
600 return next_highest_interval_msec;
601}
602
603void pim_neighbor_delete(struct interface *ifp,
604 struct pim_neighbor *neigh,
605 const char *delete_message)
606{
607 struct pim_interface *pim_ifp;
eaa54bdb 608 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
609
610 pim_ifp = ifp->info;
611 zassert(pim_ifp);
612
613 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
614 zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
615 src_str, ifp->name, delete_message);
616
5a515ebe 617 THREAD_OFF(neigh->t_expire_timer);
12e41d03
DL
618
619 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
620
621 if (!PIM_OPTION_IS_SET(neigh->hello_options,
622 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
623 /* update num. of neighbors without hello option lan_delay */
624
625 --pim_ifp->pim_number_of_nonlandelay_neighbors;
626 }
627
628 if (!PIM_OPTION_IS_SET(neigh->hello_options,
629 PIM_OPTION_MASK_DR_PRIORITY)) {
630 /* update num. of neighbors without dr_pri */
631
632 --pim_ifp->pim_dr_num_nondrpri_neighbors;
633 }
634
635 zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
636 zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec);
637
638 if (pim_if_lan_delay_enabled(ifp)) {
639
640 /* will delete a neighbor with highest propagation delay? */
641 if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
642 /* then find the next highest propagation delay */
643 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
644 find_neighbors_next_highest_propagation_delay_msec(ifp, neigh);
645 }
646
647 /* will delete a neighbor with highest override interval? */
648 if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) {
649 /* then find the next highest propagation delay */
650 pim_ifp->pim_neighbors_highest_override_interval_msec =
651 find_neighbors_next_highest_override_interval_msec(ifp, neigh);
652 }
653 }
654
655 if (PIM_DEBUG_PIM_TRACE) {
656 zlog_debug("%s: deleting PIM neighbor %s on interface %s",
657 __PRETTY_FUNCTION__,
658 src_str, ifp->name);
659 }
660
661 listnode_delete(pim_ifp->pim_neighbor_list, neigh);
662
663 pim_neighbor_free(neigh);
da72c9fd 664
665 pim_neighbor_rpf_update();
12e41d03
DL
666}
667
668void pim_neighbor_delete_all(struct interface *ifp,
669 const char *delete_message)
670{
671 struct pim_interface *pim_ifp;
672 struct listnode *neigh_node;
673 struct listnode *neigh_nextnode;
674 struct pim_neighbor *neigh;
675
676 pim_ifp = ifp->info;
677 zassert(pim_ifp);
678
679 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
680 neigh_nextnode, neigh)) {
681 pim_neighbor_delete(ifp, neigh, delete_message);
682 }
683}
684
685struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
686 struct in_addr addr)
687{
688 struct listnode *node;
689 struct prefix *p;
690
691 if (!neigh->prefix_list)
692 return 0;
693
694 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
695 if (p->family == AF_INET) {
696 if (addr.s_addr == p->u.prefix4.s_addr) {
697 return p;
698 }
699 }
700 }
701
702 return 0;
703}
704
705/*
706 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
707
708 All the advertised secondary addresses in received Hello messages
709 must be checked against those previously advertised by all other
710 PIM neighbors on that interface. If there is a conflict and the
711 same secondary address was previously advertised by another
712 neighbor, then only the most recently received mapping MUST be
713 maintained, and an error message SHOULD be logged to the
714 administrator in a rate-limited manner.
715*/
716static void delete_from_neigh_addr(struct interface *ifp,
717 struct list *addr_list,
718 struct in_addr neigh_addr)
719{
720 struct listnode *addr_node;
721 struct prefix *addr;
722 struct pim_interface *pim_ifp;
723
724 pim_ifp = ifp->info;
725 zassert(pim_ifp);
726
727 zassert(addr_list);
728
729 /*
730 Scan secondary address list
731 */
732 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node,
733 addr)) {
734 struct listnode *neigh_node;
735 struct pim_neighbor *neigh;
736
737 if (addr->family != AF_INET)
738 continue;
739
740 /*
741 Scan neighbors
742 */
743 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
744 neigh)) {
745 {
746 struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
747 if (p) {
eaa54bdb
DW
748 char addr_str[INET_ADDRSTRLEN];
749 char this_neigh_str[INET_ADDRSTRLEN];
750 char other_neigh_str[INET_ADDRSTRLEN];
12e41d03
DL
751
752 pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
753 pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));
754 pim_inet4_dump("<neigh2?>", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str));
755
756 zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s",
757 addr_str, this_neigh_str, other_neigh_str, ifp->name);
758
759 listnode_delete(neigh->prefix_list, p);
760 prefix_free(p);
761 }
762 }
763
764 } /* scan neighbors */
765
766 } /* scan addr list */
767
768}
769
770void pim_neighbor_update(struct pim_neighbor *neigh,
771 pim_hello_options hello_options,
772 uint16_t holdtime,
773 uint32_t dr_priority,
774 struct list *addr_list)
775{
776 struct pim_interface *pim_ifp = neigh->interface->info;
777
778 /* Received holdtime ? */
779 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
780 pim_neighbor_timer_reset(neigh, holdtime);
781 }
782 else {
783 pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
784 }
785
786#ifdef DUMP_PREFIX_LIST
787 zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
788 __PRETTY_FUNCTION__,
789 (unsigned) neigh->prefix_list,
790 neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1,
791 (unsigned) addr_list,
792 addr_list ? (int) listcount(addr_list) : -1);
793#endif
794
795 if (neigh->prefix_list == addr_list) {
796 if (addr_list) {
797 zlog_err("%s: internal error: trying to replace same prefix list=%p",
798 __PRETTY_FUNCTION__, (void *) addr_list);
799 }
800 }
801 else {
802 /* Delete existing secondary address list */
803 delete_prefix_list(neigh);
804 }
805
806 if (addr_list) {
807 delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr);
808 }
809
810 /* Replace secondary address list */
811 neigh->prefix_list = addr_list;
812
813 update_dr_priority(neigh,
814 hello_options,
815 dr_priority);
816 /*
817 Copy flags
818 */
819 neigh->hello_options = hello_options;
820}