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