]> git.proxmox.com Git - mirror_frr.git/blame - pimd/pim_neighbor.c
pimd: Reset neighbor hold time when we receive packet
[mirror_frr.git] / pimd / pim_neighbor.c
CommitLineData
12e41d03
DL
1/*
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
16 along with this program; see the file COPYING; if not, write to the
17 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
18 MA 02110-1301 USA
19
12e41d03
DL
20*/
21
22#include <zebra.h>
23
24#include "log.h"
25#include "prefix.h"
26#include "memory.h"
744d91b3 27#include "if.h"
e446de6a
DS
28#include "vty.h"
29#include "plist.h"
12e41d03
DL
30
31#include "pimd.h"
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"
12e41d03
DL
41
42static void dr_election_by_addr(struct interface *ifp)
43{
44 struct pim_interface *pim_ifp;
45 struct listnode *node;
46 struct pim_neighbor *neigh;
47
48 pim_ifp = ifp->info;
49 zassert(pim_ifp);
50
51 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
52
53 if (PIM_DEBUG_PIM_TRACE) {
54 zlog_debug("%s: on interface %s",
55 __PRETTY_FUNCTION__,
56 ifp->name);
57 }
58
59 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
60 if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) {
61 pim_ifp->pim_dr_addr = neigh->source_addr;
62 }
63 }
64}
65
66static void dr_election_by_pri(struct interface *ifp)
67{
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;
74 zassert(pim_ifp);
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) {
80 zlog_debug("%s: dr pri %u on interface %s",
81 __PRETTY_FUNCTION__,
82 dr_pri, ifp->name);
83 }
84
85 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
86 if (PIM_DEBUG_PIM_TRACE) {
87 zlog_info("%s: neigh pri %u addr %x if dr addr %x",
88 __PRETTY_FUNCTION__,
89 neigh->dr_priority,
90 ntohl(neigh->source_addr.s_addr),
91 ntohl(pim_ifp->pim_dr_addr.s_addr));
92 }
93 if (
94 (neigh->dr_priority > dr_pri) ||
95 (
96 (neigh->dr_priority == dr_pri) &&
97 (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr))
98 )
99 ) {
100 pim_ifp->pim_dr_addr = neigh->source_addr;
101 dr_pri = neigh->dr_priority;
102 }
103 }
104}
105
106/*
107 RFC 4601: 4.3.2. DR Election
108
109 A router's idea of the current DR on an interface can change when a
110 PIM Hello message is received, when a neighbor times out, or when a
111 router's own DR Priority changes.
112 */
dedccda6 113int pim_if_dr_election(struct interface *ifp)
12e41d03
DL
114{
115 struct pim_interface *pim_ifp = ifp->info;
116 struct in_addr old_dr_addr;
117
118 ++pim_ifp->pim_dr_election_count;
119
120 old_dr_addr = pim_ifp->pim_dr_addr;
121
122 if (pim_ifp->pim_dr_num_nondrpri_neighbors) {
123 dr_election_by_addr(ifp);
124 }
125 else {
126 dr_election_by_pri(ifp);
127 }
128
129 /* DR changed ? */
130 if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) {
131
7adf0260 132 if (PIM_DEBUG_PIM_EVENTS) {
eaa54bdb
DW
133 char dr_old_str[INET_ADDRSTRLEN];
134 char dr_new_str[INET_ADDRSTRLEN];
12e41d03
DL
135 pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str));
136 pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str));
137 zlog_debug("%s: DR was %s now is %s on interface %s",
138 __PRETTY_FUNCTION__,
139 dr_old_str, dr_new_str, ifp->name);
140 }
141
142 pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */
143 ++pim_ifp->pim_dr_election_changes;
144 pim_if_update_join_desired(pim_ifp);
145 pim_if_update_could_assert(ifp);
146 pim_if_update_assert_tracking_desired(ifp);
dedccda6 147 return 1;
12e41d03 148 }
dedccda6
DS
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{
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 = PIM_OPTION_IS_SET(hello_options,
162 PIM_OPTION_MASK_DR_PRIORITY);
163
164 bit_flip =
165 (
166 will_set_pri !=
167 PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)
168 );
169
170 if (bit_flip) {
171 struct pim_interface *pim_ifp = neigh->interface->info;
172
173 /* update num. of neighbors without dr_pri */
174
175 if (will_set_pri) {
176 --pim_ifp->pim_dr_num_nondrpri_neighbors;
177 }
178 else {
179 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
180 }
181 }
182
183 pri_change =
184 (
185 bit_flip
186 ||
187 (neigh->dr_priority != dr_priority)
188 );
189
190 if (will_set_pri) {
191 neigh->dr_priority = dr_priority;
192 }
193 else {
194 neigh->dr_priority = 0; /* cosmetic unset */
195 }
196
197 if (pri_change) {
198 /*
199 RFC 4601: 4.3.2. DR Election
200
201 A router's idea of the current DR on an interface can change when a
202 PIM Hello message is received, when a neighbor times out, or when a
203 router's own DR Priority changes.
204 */
205 pim_if_dr_election(neigh->interface); // router's own DR Priority changes
206 }
207}
208
209static int on_neighbor_timer(struct thread *t)
210{
211 struct pim_neighbor *neigh;
212 struct interface *ifp;
213 char msg[100];
214
12e41d03 215 neigh = THREAD_ARG(t);
12e41d03
DL
216
217 ifp = neigh->interface;
218
219 if (PIM_DEBUG_PIM_TRACE) {
eaa54bdb 220 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
221 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
222 zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
223 neigh->holdtime, src_str, ifp->name);
224 }
225
59ba0ac3 226 neigh->t_expire_timer = NULL;
12e41d03
DL
227
228 snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
229 pim_neighbor_delete(ifp, neigh, msg);
230
231 /*
232 RFC 4601: 4.3.2. DR Election
233
234 A router's idea of the current DR on an interface can change when a
235 PIM Hello message is received, when a neighbor times out, or when a
236 router's own DR Priority changes.
237 */
238 pim_if_dr_election(ifp); // neighbor times out
239
240 return 0;
241}
242
12e41d03
DL
243void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
244{
245 neigh->holdtime = holdtime;
246
5a515ebe 247 THREAD_OFF(neigh->t_expire_timer);
12e41d03
DL
248
249 /*
250 0xFFFF is request for no holdtime
251 */
252 if (neigh->holdtime == 0xFFFF) {
253 return;
254 }
255
ce9a0643 256 if (PIM_DEBUG_PIM_TRACE_DETAIL) {
eaa54bdb 257 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
258 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
259 zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
260 __PRETTY_FUNCTION__,
261 neigh->holdtime, src_str, neigh->interface->name);
262 }
263
264 THREAD_TIMER_ON(master, neigh->t_expire_timer,
265 on_neighbor_timer,
266 neigh, neigh->holdtime);
267}
268
269static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
270 struct in_addr source_addr,
271 pim_hello_options hello_options,
272 uint16_t holdtime,
273 uint16_t propagation_delay,
274 uint16_t override_interval,
275 uint32_t dr_priority,
276 uint32_t generation_id,
277 struct list *addr_list)
278{
279 struct pim_interface *pim_ifp;
280 struct pim_neighbor *neigh;
eaa54bdb 281 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
282
283 zassert(ifp);
284 pim_ifp = ifp->info;
285 zassert(pim_ifp);
286
36d9e7dc 287 neigh = XCALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
12e41d03 288 if (!neigh) {
36d9e7dc 289 zlog_err("%s: PIM XCALLOC(%zu) failure",
12e41d03
DL
290 __PRETTY_FUNCTION__, sizeof(*neigh));
291 return 0;
292 }
293
294 neigh->creation = pim_time_monotonic_sec();
295 neigh->source_addr = source_addr;
296 neigh->hello_options = hello_options;
297 neigh->propagation_delay_msec = propagation_delay;
298 neigh->override_interval_msec = override_interval;
299 neigh->dr_priority = dr_priority;
300 neigh->generation_id = generation_id;
301 neigh->prefix_list = addr_list;
59ba0ac3 302 neigh->t_expire_timer = NULL;
12e41d03
DL
303 neigh->interface = ifp;
304
305 pim_neighbor_timer_reset(neigh, holdtime);
86abfcb8
DS
306 /*
307 * The pim_ifstat_hello_sent variable is used to decide if
308 * we should expedite a hello out the interface. If we
309 * establish a new neighbor, we unfortunately need to
310 * reset the value so that we can know to hurry up and
311 * hello
312 */
313 pim_ifp->pim_ifstat_hello_sent = 0;
12e41d03
DL
314
315 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
316
317 if (PIM_DEBUG_PIM_EVENTS) {
318 zlog_debug("%s: creating PIM neighbor %s on interface %s",
319 __PRETTY_FUNCTION__,
320 src_str, ifp->name);
321 }
322
323 zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s",
324 src_str, ifp->name);
325
326 if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
327 pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec;
328 }
329 if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) {
330 pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec;
331 }
332
333 if (!PIM_OPTION_IS_SET(neigh->hello_options,
334 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
335 /* update num. of neighbors without hello option lan_delay */
336 ++pim_ifp->pim_number_of_nonlandelay_neighbors;
337 }
338
339 if (!PIM_OPTION_IS_SET(neigh->hello_options,
340 PIM_OPTION_MASK_DR_PRIORITY)) {
341 /* update num. of neighbors without hello option dr_pri */
342 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
343 }
344
12e41d03
DL
345 return neigh;
346}
347
348static void delete_prefix_list(struct pim_neighbor *neigh)
349{
350 if (neigh->prefix_list) {
351
352#ifdef DUMP_PREFIX_LIST
353 struct listnode *p_node;
354 struct prefix *p;
355 char addr_str[10];
356 int list_size = neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1;
357 int i = 0;
358 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, p_node, p)) {
359 pim_inet4_dump("<addr?>", p->u.prefix4, addr_str, sizeof(addr_str));
360 zlog_debug("%s: DUMP_PREFIX_LIST neigh=%x prefix_list=%x prefix=%x addr=%s [%d/%d]",
361 __PRETTY_FUNCTION__,
362 (unsigned) neigh, (unsigned) neigh->prefix_list, (unsigned) p,
363 addr_str, i, list_size);
364 ++i;
365 }
366#endif
367
368 list_delete(neigh->prefix_list);
369 neigh->prefix_list = 0;
370 }
371}
372
373void pim_neighbor_free(struct pim_neighbor *neigh)
374{
375 zassert(!neigh->t_expire_timer);
376
377 delete_prefix_list(neigh);
378
379 XFREE(MTYPE_PIM_NEIGHBOR, neigh);
380}
381
382struct pim_neighbor *pim_neighbor_find(struct interface *ifp,
383 struct in_addr source_addr)
384{
385 struct pim_interface *pim_ifp;
386 struct listnode *node;
387 struct pim_neighbor *neigh;
388
389 pim_ifp = ifp->info;
69719554
DS
390 if (!pim_ifp)
391 return NULL;
12e41d03
DL
392
393 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
394 if (source_addr.s_addr == neigh->source_addr.s_addr) {
395 return neigh;
396 }
397 }
398
69719554 399 return NULL;
12e41d03
DL
400}
401
99deb321
DS
402/*
403 * Find the *one* interface out
404 * this interface. If more than
405 * one return NULL
406 */
407struct pim_neighbor *
408pim_neighbor_find_if (struct interface *ifp)
409{
410 struct pim_interface *pim_ifp = ifp->info;
411
69719554 412 if (!pim_ifp || pim_ifp->pim_neighbor_list->count != 1)
99deb321
DS
413 return NULL;
414
415 return listnode_head (pim_ifp->pim_neighbor_list);
416}
417
da72c9fd 418/* rpf info associated with an upstream entry needs to be re-evaluated
419 * when an RPF neighbor comes or goes */
420static void
421pim_neighbor_rpf_update(void)
422{
423 /* XXX: for the time being piggyback on the timer used on rib changes
424 * to scan and update the rpf nexthop. This is expensive processing
425 * and we should be able to optimize neighbor changes differently than
426 * nexthop changes. */
427 sched_rpf_cache_refresh();
428}
429
12e41d03
DL
430struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
431 struct in_addr source_addr,
432 pim_hello_options hello_options,
433 uint16_t holdtime,
434 uint16_t propagation_delay,
435 uint16_t override_interval,
436 uint32_t dr_priority,
437 uint32_t generation_id,
1148de0a
DS
438 struct list *addr_list,
439 int send_hello_now)
12e41d03
DL
440{
441 struct pim_interface *pim_ifp;
442 struct pim_neighbor *neigh;
443
444 neigh = pim_neighbor_new(ifp, source_addr,
445 hello_options,
446 holdtime,
447 propagation_delay,
448 override_interval,
449 dr_priority,
450 generation_id,
451 addr_list);
452 if (!neigh) {
453 return 0;
454 }
455
456 pim_ifp = ifp->info;
457 zassert(pim_ifp);
458
459 listnode_add(pim_ifp->pim_neighbor_list, neigh);
460
818a327c
DS
461 /*
462 RFC 4601: 4.3.2. DR Election
463
464 A router's idea of the current DR on an interface can change when a
465 PIM Hello message is received, when a neighbor times out, or when a
466 router's own DR Priority changes.
467 */
468 pim_if_dr_election(neigh->interface); // new neighbor -- should not trigger dr election...
469
470 /*
471 RFC 4601: 4.3.1. Sending Hello Messages
472
473 To allow new or rebooting routers to learn of PIM neighbors quickly,
474 when a Hello message is received from a new neighbor, or a Hello
475 message with a new GenID is received from an existing neighbor, a
476 new Hello message should be sent on this interface after a
477 randomized delay between 0 and Triggered_Hello_Delay.
1148de0a
DS
478
479 This is a bit silly to do it that way. If I get a new
480 genid we need to send the hello *now* because we've
481 lined up a bunch of join/prune messages to go out the
482 interface.
818a327c 483 */
1148de0a
DS
484 if (send_hello_now)
485 pim_hello_restart_now (ifp);
486 else
487 pim_hello_restart_triggered(neigh->interface);
818a327c 488
d3dd1804
DS
489 pim_upstream_find_new_rpf();
490
e446de6a 491 pim_rp_setup ();
da72c9fd 492
493 pim_neighbor_rpf_update();
12e41d03
DL
494 return neigh;
495}
496
497static uint16_t
498find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp,
499 struct pim_neighbor *highest_neigh)
500{
501 struct pim_interface *pim_ifp;
502 struct listnode *neigh_node;
503 struct pim_neighbor *neigh;
504 uint16_t next_highest_delay_msec;
505
506 pim_ifp = ifp->info;
507 zassert(pim_ifp);
508
509 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
510
511 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
512 if (neigh == highest_neigh)
513 continue;
514 if (neigh->propagation_delay_msec > next_highest_delay_msec)
515 next_highest_delay_msec = neigh->propagation_delay_msec;
516 }
517
518 return next_highest_delay_msec;
519}
520
521static uint16_t
522find_neighbors_next_highest_override_interval_msec(struct interface *ifp,
523 struct pim_neighbor *highest_neigh)
524{
525 struct pim_interface *pim_ifp;
526 struct listnode *neigh_node;
527 struct pim_neighbor *neigh;
528 uint16_t next_highest_interval_msec;
529
530 pim_ifp = ifp->info;
531 zassert(pim_ifp);
532
533 next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
534
535 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
536 if (neigh == highest_neigh)
537 continue;
538 if (neigh->override_interval_msec > next_highest_interval_msec)
539 next_highest_interval_msec = neigh->override_interval_msec;
540 }
541
542 return next_highest_interval_msec;
543}
544
545void pim_neighbor_delete(struct interface *ifp,
546 struct pim_neighbor *neigh,
547 const char *delete_message)
548{
549 struct pim_interface *pim_ifp;
eaa54bdb 550 char src_str[INET_ADDRSTRLEN];
12e41d03
DL
551
552 pim_ifp = ifp->info;
553 zassert(pim_ifp);
554
555 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
556 zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
557 src_str, ifp->name, delete_message);
558
5a515ebe 559 THREAD_OFF(neigh->t_expire_timer);
12e41d03
DL
560
561 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
562
563 if (!PIM_OPTION_IS_SET(neigh->hello_options,
564 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
565 /* update num. of neighbors without hello option lan_delay */
566
567 --pim_ifp->pim_number_of_nonlandelay_neighbors;
568 }
569
570 if (!PIM_OPTION_IS_SET(neigh->hello_options,
571 PIM_OPTION_MASK_DR_PRIORITY)) {
572 /* update num. of neighbors without dr_pri */
573
574 --pim_ifp->pim_dr_num_nondrpri_neighbors;
575 }
576
577 zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
578 zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec);
579
580 if (pim_if_lan_delay_enabled(ifp)) {
581
582 /* will delete a neighbor with highest propagation delay? */
583 if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
584 /* then find the next highest propagation delay */
585 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
586 find_neighbors_next_highest_propagation_delay_msec(ifp, neigh);
587 }
588
589 /* will delete a neighbor with highest override interval? */
590 if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) {
591 /* then find the next highest propagation delay */
592 pim_ifp->pim_neighbors_highest_override_interval_msec =
593 find_neighbors_next_highest_override_interval_msec(ifp, neigh);
594 }
595 }
596
597 if (PIM_DEBUG_PIM_TRACE) {
598 zlog_debug("%s: deleting PIM neighbor %s on interface %s",
599 __PRETTY_FUNCTION__,
600 src_str, ifp->name);
601 }
602
603 listnode_delete(pim_ifp->pim_neighbor_list, neigh);
604
605 pim_neighbor_free(neigh);
da72c9fd 606
607 pim_neighbor_rpf_update();
12e41d03
DL
608}
609
610void pim_neighbor_delete_all(struct interface *ifp,
611 const char *delete_message)
612{
613 struct pim_interface *pim_ifp;
614 struct listnode *neigh_node;
615 struct listnode *neigh_nextnode;
616 struct pim_neighbor *neigh;
617
618 pim_ifp = ifp->info;
619 zassert(pim_ifp);
620
621 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
622 neigh_nextnode, neigh)) {
623 pim_neighbor_delete(ifp, neigh, delete_message);
624 }
625}
626
627struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
628 struct in_addr addr)
629{
630 struct listnode *node;
631 struct prefix *p;
632
633 if (!neigh->prefix_list)
634 return 0;
635
636 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
637 if (p->family == AF_INET) {
638 if (addr.s_addr == p->u.prefix4.s_addr) {
639 return p;
640 }
641 }
642 }
643
644 return 0;
645}
646
647/*
648 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
649
650 All the advertised secondary addresses in received Hello messages
651 must be checked against those previously advertised by all other
652 PIM neighbors on that interface. If there is a conflict and the
653 same secondary address was previously advertised by another
654 neighbor, then only the most recently received mapping MUST be
655 maintained, and an error message SHOULD be logged to the
656 administrator in a rate-limited manner.
657*/
658static void delete_from_neigh_addr(struct interface *ifp,
659 struct list *addr_list,
660 struct in_addr neigh_addr)
661{
662 struct listnode *addr_node;
663 struct prefix *addr;
664 struct pim_interface *pim_ifp;
665
666 pim_ifp = ifp->info;
667 zassert(pim_ifp);
668
669 zassert(addr_list);
670
671 /*
672 Scan secondary address list
673 */
674 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node,
675 addr)) {
676 struct listnode *neigh_node;
677 struct pim_neighbor *neigh;
678
679 if (addr->family != AF_INET)
680 continue;
681
682 /*
683 Scan neighbors
684 */
685 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
686 neigh)) {
687 {
688 struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
689 if (p) {
eaa54bdb
DW
690 char addr_str[INET_ADDRSTRLEN];
691 char this_neigh_str[INET_ADDRSTRLEN];
692 char other_neigh_str[INET_ADDRSTRLEN];
12e41d03
DL
693
694 pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
695 pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));
696 pim_inet4_dump("<neigh2?>", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str));
697
698 zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s",
699 addr_str, this_neigh_str, other_neigh_str, ifp->name);
700
701 listnode_delete(neigh->prefix_list, p);
702 prefix_free(p);
703 }
704 }
705
706 } /* scan neighbors */
707
708 } /* scan addr list */
709
710}
711
712void pim_neighbor_update(struct pim_neighbor *neigh,
713 pim_hello_options hello_options,
714 uint16_t holdtime,
715 uint32_t dr_priority,
716 struct list *addr_list)
717{
718 struct pim_interface *pim_ifp = neigh->interface->info;
719
720 /* Received holdtime ? */
721 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
722 pim_neighbor_timer_reset(neigh, holdtime);
723 }
724 else {
725 pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
726 }
727
728#ifdef DUMP_PREFIX_LIST
729 zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
730 __PRETTY_FUNCTION__,
731 (unsigned) neigh->prefix_list,
732 neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1,
733 (unsigned) addr_list,
734 addr_list ? (int) listcount(addr_list) : -1);
735#endif
736
737 if (neigh->prefix_list == addr_list) {
738 if (addr_list) {
739 zlog_err("%s: internal error: trying to replace same prefix list=%p",
740 __PRETTY_FUNCTION__, (void *) addr_list);
741 }
742 }
743 else {
744 /* Delete existing secondary address list */
745 delete_prefix_list(neigh);
746 }
747
748 if (addr_list) {
749 delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr);
750 }
751
752 /* Replace secondary address list */
753 neigh->prefix_list = addr_list;
754
755 update_dr_priority(neigh,
756 hello_options,
757 dr_priority);
758 /*
759 Copy flags
760 */
761 neigh->hello_options = hello_options;
762}