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