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