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