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