]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_neighbor.c
pim6d: Handle rpf_addr in pim_if_addr_add()
[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;
9bb93fa0 266 pim_addr_to_prefix(&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
9bb93fa0
DL
444struct pim_neighbor *pim_neighbor_find_prefix(struct interface *ifp,
445 const struct prefix *src_prefix)
446{
447 pim_addr addr;
448
449 addr = pim_addr_from_prefix(src_prefix);
450 return pim_neighbor_find(ifp, addr);
451}
452
99deb321
DS
453/*
454 * Find the *one* interface out
455 * this interface. If more than
456 * one return NULL
457 */
d62a17ae 458struct pim_neighbor *pim_neighbor_find_if(struct interface *ifp)
99deb321 459{
d62a17ae 460 struct pim_interface *pim_ifp = ifp->info;
99deb321 461
d62a17ae 462 if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
463 return NULL;
99deb321 464
d62a17ae 465 return listnode_head(pim_ifp->pim_neighbor_list);
99deb321
DS
466}
467
d62a17ae 468struct pim_neighbor *
9bb93fa0 469pim_neighbor_add(struct interface *ifp, pim_addr source_addr,
d62a17ae 470 pim_hello_options hello_options, uint16_t holdtime,
471 uint16_t propagation_delay, uint16_t override_interval,
472 uint32_t dr_priority, uint32_t generation_id,
473 struct list *addr_list, int send_hello_now)
12e41d03 474{
d62a17ae 475 struct pim_interface *pim_ifp;
476 struct pim_neighbor *neigh;
477
478 neigh = pim_neighbor_new(ifp, source_addr, hello_options, holdtime,
479 propagation_delay, override_interval,
480 dr_priority, generation_id, addr_list);
481 if (!neigh) {
482 return 0;
483 }
12e41d03 484
d62a17ae 485 pim_ifp = ifp->info;
df5dfb77 486 assert(pim_ifp);
12e41d03 487
d62a17ae 488 listnode_add(pim_ifp->pim_neighbor_list, neigh);
12e41d03 489
9bb93fa0
DL
490 if (PIM_DEBUG_PIM_TRACE_DETAIL)
491 zlog_debug("%s: neighbor %pPA added ", __func__, &source_addr);
d62a17ae 492 /*
493 RFC 4601: 4.3.2. DR Election
494
495 A router's idea of the current DR on an interface can change when a
496 PIM Hello message is received, when a neighbor times out, or when a
497 router's own DR Priority changes.
498 */
499 pim_if_dr_election(neigh->interface); // new neighbor -- should not
500 // trigger dr election...
501
502 /*
503 RFC 4601: 4.3.1. Sending Hello Messages
504
505 To allow new or rebooting routers to learn of PIM neighbors quickly,
506 when a Hello message is received from a new neighbor, or a Hello
507 message with a new GenID is received from an existing neighbor, a
508 new Hello message should be sent on this interface after a
509 randomized delay between 0 and Triggered_Hello_Delay.
510
511 This is a bit silly to do it that way. If I get a new
512 genid we need to send the hello *now* because we've
513 lined up a bunch of join/prune messages to go out the
514 interface.
515 */
516 if (send_hello_now)
517 pim_hello_restart_now(ifp);
518 else
519 pim_hello_restart_triggered(neigh->interface);
520
9b29ea95 521 pim_upstream_find_new_rpf(pim_ifp->pim);
d62a17ae 522
523 /* RNH can send nexthop update prior to PIM neibhor UP
524 in that case nexthop cache would not consider this neighbor
525 as RPF.
526 Upon PIM neighbor UP, iterate all RPs and update
527 nexthop cache with this neighbor.
528 */
c9cd7fbc 529 pim_resolve_rp_nh(pim_ifp->pim, neigh);
d62a17ae 530
fec883d9 531 pim_rp_setup(pim_ifp->pim);
d62a17ae 532
da11e325 533 sched_rpf_cache_refresh(pim_ifp->pim);
d62a17ae 534 return neigh;
12e41d03
DL
535}
536
d62a17ae 537static uint16_t find_neighbors_next_highest_propagation_delay_msec(
538 struct interface *ifp, struct pim_neighbor *highest_neigh)
12e41d03 539{
d62a17ae 540 struct pim_interface *pim_ifp;
541 struct listnode *neigh_node;
542 struct pim_neighbor *neigh;
543 uint16_t next_highest_delay_msec;
544
545 pim_ifp = ifp->info;
df5dfb77 546 assert(pim_ifp);
d62a17ae 547
548 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
549
550 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
551 neigh)) {
552 if (neigh == highest_neigh)
553 continue;
554 if (neigh->propagation_delay_msec > next_highest_delay_msec)
555 next_highest_delay_msec = neigh->propagation_delay_msec;
556 }
12e41d03 557
d62a17ae 558 return next_highest_delay_msec;
559}
12e41d03 560
d62a17ae 561static uint16_t find_neighbors_next_highest_override_interval_msec(
562 struct interface *ifp, struct pim_neighbor *highest_neigh)
563{
564 struct pim_interface *pim_ifp;
565 struct listnode *neigh_node;
566 struct pim_neighbor *neigh;
567 uint16_t next_highest_interval_msec;
568
569 pim_ifp = ifp->info;
df5dfb77 570 assert(pim_ifp);
d62a17ae 571
572 next_highest_interval_msec = pim_ifp->pim_override_interval_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->override_interval_msec > next_highest_interval_msec)
579 next_highest_interval_msec =
580 neigh->override_interval_msec;
581 }
12e41d03 582
d62a17ae 583 return next_highest_interval_msec;
12e41d03
DL
584}
585
d62a17ae 586void pim_neighbor_delete(struct interface *ifp, struct pim_neighbor *neigh,
12e41d03
DL
587 const char *delete_message)
588{
d62a17ae 589 struct pim_interface *pim_ifp;
12e41d03 590
d62a17ae 591 pim_ifp = ifp->info;
df5dfb77 592 assert(pim_ifp);
12e41d03 593
9bb93fa0
DL
594 zlog_notice("PIM NEIGHBOR DOWN: neighbor %pPA on interface %s: %s",
595 &neigh->source_addr, ifp->name, delete_message);
12e41d03 596
d62a17ae 597 THREAD_OFF(neigh->t_expire_timer);
12e41d03 598
d62a17ae 599 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
12e41d03 600
d62a17ae 601 if (!PIM_OPTION_IS_SET(neigh->hello_options,
602 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
603 /* update num. of neighbors without hello option lan_delay */
12e41d03 604
d62a17ae 605 --pim_ifp->pim_number_of_nonlandelay_neighbors;
606 }
12e41d03 607
d62a17ae 608 if (!PIM_OPTION_IS_SET(neigh->hello_options,
609 PIM_OPTION_MASK_DR_PRIORITY)) {
610 /* update num. of neighbors without dr_pri */
12e41d03 611
d62a17ae 612 --pim_ifp->pim_dr_num_nondrpri_neighbors;
613 }
12e41d03 614
df5dfb77
DL
615 assert(neigh->propagation_delay_msec
616 <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
617 assert(neigh->override_interval_msec
618 <= pim_ifp->pim_neighbors_highest_override_interval_msec);
d62a17ae 619
620 if (pim_if_lan_delay_enabled(ifp)) {
621
622 /* will delete a neighbor with highest propagation delay? */
623 if (neigh->propagation_delay_msec
624 == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
625 /* then find the next highest propagation delay */
626 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
627 find_neighbors_next_highest_propagation_delay_msec(
628 ifp, neigh);
629 }
630
631 /* will delete a neighbor with highest override interval? */
632 if (neigh->override_interval_msec
633 == pim_ifp->pim_neighbors_highest_override_interval_msec) {
634 /* then find the next highest propagation delay */
635 pim_ifp->pim_neighbors_highest_override_interval_msec =
636 find_neighbors_next_highest_override_interval_msec(
637 ifp, neigh);
638 }
639 }
12e41d03 640
d62a17ae 641 if (PIM_DEBUG_PIM_TRACE) {
9bb93fa0
DL
642 zlog_debug("%s: deleting PIM neighbor %pPA on interface %s",
643 __func__, &neigh->source_addr, ifp->name);
d62a17ae 644 }
12e41d03 645
d62a17ae 646 listnode_delete(pim_ifp->pim_neighbor_list, neigh);
12e41d03 647
d62a17ae 648 pim_neighbor_free(neigh);
da72c9fd 649
da11e325 650 sched_rpf_cache_refresh(pim_ifp->pim);
12e41d03
DL
651}
652
d62a17ae 653void pim_neighbor_delete_all(struct interface *ifp, const char *delete_message)
12e41d03 654{
d62a17ae 655 struct pim_interface *pim_ifp;
656 struct listnode *neigh_node;
657 struct listnode *neigh_nextnode;
658 struct pim_neighbor *neigh;
659
660 pim_ifp = ifp->info;
df5dfb77 661 assert(pim_ifp);
d62a17ae 662
663 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
664 neigh_nextnode, neigh)) {
665 pim_neighbor_delete(ifp, neigh, delete_message);
666 }
12e41d03
DL
667}
668
669struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
07b17d59 670 struct prefix *addr)
12e41d03 671{
d62a17ae 672 struct listnode *node;
673 struct prefix *p;
12e41d03 674
d62a17ae 675 if (!neigh->prefix_list)
676 return 0;
12e41d03 677
d62a17ae 678 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
679 if (prefix_same(p, addr))
680 return p;
681 }
12e41d03 682
d62a17ae 683 return NULL;
12e41d03
DL
684}
685
686/*
687 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
d62a17ae 688
12e41d03
DL
689 All the advertised secondary addresses in received Hello messages
690 must be checked against those previously advertised by all other
691 PIM neighbors on that interface. If there is a conflict and the
692 same secondary address was previously advertised by another
693 neighbor, then only the most recently received mapping MUST be
694 maintained, and an error message SHOULD be logged to the
695 administrator in a rate-limited manner.
696*/
697static void delete_from_neigh_addr(struct interface *ifp,
9bb93fa0 698 struct list *addr_list, pim_addr neigh_addr)
12e41d03 699{
d62a17ae 700 struct listnode *addr_node;
701 struct prefix *addr;
702 struct pim_interface *pim_ifp;
703
704 pim_ifp = ifp->info;
df5dfb77 705 assert(pim_ifp);
d62a17ae 706
df5dfb77 707 assert(addr_list);
d62a17ae 708
709 /*
710 Scan secondary address list
711 */
712 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node, addr)) {
713 struct listnode *neigh_node;
714 struct pim_neighbor *neigh;
715
d58395d1 716 if (addr->family != PIM_AF)
d62a17ae 717 continue;
d62a17ae 718 /*
719 Scan neighbors
720 */
721 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list,
722 neigh_node, neigh)) {
723 {
724 struct prefix *p = pim_neighbor_find_secondary(
725 neigh, addr);
726 if (p) {
d62a17ae 727 zlog_info(
53749ba7 728 "secondary addr %pFXh recvd from neigh %pPA deleted from neigh %pPA on %s",
729 addr, &neigh_addr,
9bb93fa0 730 &neigh->source_addr, ifp->name);
d62a17ae 731
732 listnode_delete(neigh->prefix_list, p);
63265b5c 733 prefix_free(&p);
d62a17ae 734 }
735 }
736
737 } /* scan neighbors */
738
739 } /* scan addr list */
12e41d03
DL
740}
741
742void pim_neighbor_update(struct pim_neighbor *neigh,
d62a17ae 743 pim_hello_options hello_options, uint16_t holdtime,
744 uint32_t dr_priority, struct list *addr_list)
12e41d03 745{
d62a17ae 746 struct pim_interface *pim_ifp = neigh->interface->info;
b3a474d8 747 uint32_t old, new;
d62a17ae 748
749 /* Received holdtime ? */
750 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
751 pim_neighbor_timer_reset(neigh, holdtime);
752 } else {
753 pim_neighbor_timer_reset(neigh,
754 PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
755 }
12e41d03
DL
756
757#ifdef DUMP_PREFIX_LIST
d62a17ae 758 zlog_debug(
759 "%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
15569c58 760 __func__, (unsigned)neigh->prefix_list,
d62a17ae 761 neigh->prefix_list ? (int)listcount(neigh->prefix_list) : -1,
762 (unsigned)addr_list,
763 addr_list ? (int)listcount(addr_list) : -1);
12e41d03
DL
764#endif
765
d62a17ae 766 if (neigh->prefix_list == addr_list) {
767 if (addr_list) {
af4c2728 768 flog_err(
450971aa 769 EC_LIB_DEVELOPMENT,
d62a17ae 770 "%s: internal error: trying to replace same prefix list=%p",
15569c58 771 __func__, (void *)addr_list);
d62a17ae 772 }
773 } else {
774 /* Delete existing secondary address list */
775 delete_prefix_list(neigh);
776 }
777
778 if (addr_list) {
779 delete_from_neigh_addr(neigh->interface, addr_list,
780 neigh->source_addr);
781 }
782
783 /* Replace secondary address list */
784 neigh->prefix_list = addr_list;
785
786 update_dr_priority(neigh, hello_options, dr_priority);
b3a474d8 787 new = PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_LAN_PRUNE_DELAY);
788 old = PIM_OPTION_IS_SET(neigh->hello_options,
789 PIM_OPTION_MASK_LAN_PRUNE_DELAY);
790
791 if (old != new) {
792 if (old)
793 ++pim_ifp->pim_number_of_nonlandelay_neighbors;
794 else
795 --pim_ifp->pim_number_of_nonlandelay_neighbors;
796 }
d62a17ae 797 /*
798 Copy flags
799 */
800 neigh->hello_options = hello_options;
12e41d03 801}