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