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