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