blob: 67aa9d0883aa88ee6b6751df9710c80d00589e3a [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
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
20 $QuaggaId: $Format:%an, %ai, %h$ $
21*/
22
23#include <zebra.h>
24
25#include "log.h"
26#include "prefix.h"
27#include "memory.h"
28
29#include "pimd.h"
30#include "pim_neighbor.h"
31#include "pim_time.h"
32#include "pim_str.h"
33#include "pim_iface.h"
34#include "pim_pim.h"
35#include "pim_upstream.h"
36#include "pim_ifchannel.h"
37
38static void dr_election_by_addr(struct interface *ifp)
39{
40 struct pim_interface *pim_ifp;
41 struct listnode *node;
42 struct pim_neighbor *neigh;
43
44 pim_ifp = ifp->info;
45 zassert(pim_ifp);
46
47 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
48
49 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
50 if (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr)) {
51 pim_ifp->pim_dr_addr = neigh->source_addr;
52 }
53 }
54}
55
56static void dr_election_by_pri(struct interface *ifp)
57{
58 struct pim_interface *pim_ifp;
59 struct listnode *node;
60 struct pim_neighbor *neigh;
61 uint32_t dr_pri;
62
63 pim_ifp = ifp->info;
64 zassert(pim_ifp);
65
66 pim_ifp->pim_dr_addr = pim_ifp->primary_address;
67 dr_pri = pim_ifp->pim_dr_priority;
68
69 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
70 if (
71 (neigh->dr_priority > dr_pri) ||
72 (
73 (neigh->dr_priority == dr_pri) &&
74 (ntohl(neigh->source_addr.s_addr) > ntohl(pim_ifp->pim_dr_addr.s_addr))
75 )
76 ) {
77 pim_ifp->pim_dr_addr = neigh->source_addr;
78 dr_pri = neigh->dr_priority;
79 }
80 }
81}
82
83/*
84 RFC 4601: 4.3.2. DR Election
85
86 A router's idea of the current DR on an interface can change when a
87 PIM Hello message is received, when a neighbor times out, or when a
88 router's own DR Priority changes.
89 */
90void pim_if_dr_election(struct interface *ifp)
91{
92 struct pim_interface *pim_ifp = ifp->info;
93 struct in_addr old_dr_addr;
94
95 pim_ifp->pim_dr_election_last = pim_time_monotonic_sec(); /* timestamp */
96 ++pim_ifp->pim_dr_election_count;
97
98 old_dr_addr = pim_ifp->pim_dr_addr;
99
100 if (pim_ifp->pim_dr_num_nondrpri_neighbors) {
101 dr_election_by_addr(ifp);
102 }
103 else {
104 dr_election_by_pri(ifp);
105 }
106
107 /* DR changed ? */
108 if (old_dr_addr.s_addr != pim_ifp->pim_dr_addr.s_addr) {
109 char dr_old_str[100];
110 char dr_new_str[100];
111 pim_inet4_dump("<old_dr?>", old_dr_addr, dr_old_str, sizeof(dr_old_str));
112 pim_inet4_dump("<new_dr?>", pim_ifp->pim_dr_addr, dr_new_str, sizeof(dr_new_str));
113 zlog_info("%s: DR was %s now is %s on interface %s",
114 __PRETTY_FUNCTION__,
115 dr_old_str, dr_new_str, ifp->name);
116
117 pim_if_update_join_desired(pim_ifp);
118 pim_if_update_could_assert(ifp);
119 pim_if_update_assert_tracking_desired(ifp);
120 }
121}
122
123static void update_dr_priority(struct pim_neighbor *neigh,
124 pim_hello_options hello_options,
125 uint32_t dr_priority)
126{
127 pim_hello_options will_set_pri; /* boolean */
128 pim_hello_options bit_flip; /* boolean */
129 pim_hello_options pri_change; /* boolean */
130
131 will_set_pri = PIM_OPTION_IS_SET(hello_options,
132 PIM_OPTION_MASK_DR_PRIORITY);
133
134 bit_flip =
135 (
136 will_set_pri !=
137 PIM_OPTION_IS_SET(neigh->hello_options, PIM_OPTION_MASK_DR_PRIORITY)
138 );
139
140 if (bit_flip) {
141 struct pim_interface *pim_ifp = neigh->interface->info;
142
143 /* update num. of neighbors without dr_pri */
144
145 if (will_set_pri) {
146 --pim_ifp->pim_dr_num_nondrpri_neighbors;
147 }
148 else {
149 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
150 }
151 }
152
153 pri_change =
154 (
155 bit_flip
156 ||
157 (neigh->dr_priority != dr_priority)
158 );
159
160 if (will_set_pri) {
161 neigh->dr_priority = dr_priority;
162 }
163 else {
164 neigh->dr_priority = 0; /* cosmetic unset */
165 }
166
167 if (pri_change) {
168 /*
169 RFC 4601: 4.3.2. DR Election
170
171 A router's idea of the current DR on an interface can change when a
172 PIM Hello message is received, when a neighbor times out, or when a
173 router's own DR Priority changes.
174 */
175 pim_if_dr_election(neigh->interface);
176 }
177}
178
179static int on_neighbor_timer(struct thread *t)
180{
181 struct pim_neighbor *neigh;
182 struct interface *ifp;
183 char msg[100];
184
185 zassert(t);
186 neigh = THREAD_ARG(t);
187 zassert(neigh);
188
189 ifp = neigh->interface;
190
191 if (PIM_DEBUG_PIM_TRACE) {
192 char src_str[100];
193 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
194 zlog_debug("Expired %d sec holdtime for neighbor %s on interface %s",
195 neigh->holdtime, src_str, ifp->name);
196 }
197
198 neigh->t_expire_timer = 0;
199
200 snprintf(msg, sizeof(msg), "%d-sec holdtime expired", neigh->holdtime);
201 pim_neighbor_delete(ifp, neigh, msg);
202
203 /*
204 RFC 4601: 4.3.2. DR Election
205
206 A router's idea of the current DR on an interface can change when a
207 PIM Hello message is received, when a neighbor times out, or when a
208 router's own DR Priority changes.
209 */
210 pim_if_dr_election(ifp);
211
212 return 0;
213}
214
215static void neighbor_timer_off(struct pim_neighbor *neigh)
216{
217 if (PIM_DEBUG_PIM_TRACE) {
218 if (neigh->t_expire_timer) {
219 char src_str[100];
220 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
221 zlog_debug("%s: cancelling timer for neighbor %s on %s",
222 __PRETTY_FUNCTION__,
223 src_str, neigh->interface->name);
224 }
225 }
226 THREAD_OFF(neigh->t_expire_timer);
227 zassert(!neigh->t_expire_timer);
228}
229
230void pim_neighbor_timer_reset(struct pim_neighbor *neigh, uint16_t holdtime)
231{
232 neigh->holdtime = holdtime;
233
234 neighbor_timer_off(neigh);
235
236 /*
237 0xFFFF is request for no holdtime
238 */
239 if (neigh->holdtime == 0xFFFF) {
240 return;
241 }
242
243 if (PIM_DEBUG_PIM_TRACE) {
244 char src_str[100];
245 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
246 zlog_debug("%s: starting %u sec timer for neighbor %s on %s",
247 __PRETTY_FUNCTION__,
248 neigh->holdtime, src_str, neigh->interface->name);
249 }
250
251 THREAD_TIMER_ON(master, neigh->t_expire_timer,
252 on_neighbor_timer,
253 neigh, neigh->holdtime);
254}
255
256static struct pim_neighbor *pim_neighbor_new(struct interface *ifp,
257 struct in_addr source_addr,
258 pim_hello_options hello_options,
259 uint16_t holdtime,
260 uint16_t propagation_delay,
261 uint16_t override_interval,
262 uint32_t dr_priority,
263 uint32_t generation_id,
264 struct list *addr_list)
265{
266 struct pim_interface *pim_ifp;
267 struct pim_neighbor *neigh;
268 char src_str[100];
269
270 zassert(ifp);
271 pim_ifp = ifp->info;
272 zassert(pim_ifp);
273
274 neigh = XMALLOC(MTYPE_PIM_NEIGHBOR, sizeof(*neigh));
275 if (!neigh) {
276 zlog_err("%s: PIM XMALLOC(%d) failure",
277 __PRETTY_FUNCTION__, sizeof(*neigh));
278 return 0;
279 }
280
281 neigh->creation = pim_time_monotonic_sec();
282 neigh->source_addr = source_addr;
283 neigh->hello_options = hello_options;
284 neigh->propagation_delay_msec = propagation_delay;
285 neigh->override_interval_msec = override_interval;
286 neigh->dr_priority = dr_priority;
287 neigh->generation_id = generation_id;
288 neigh->prefix_list = addr_list;
289 neigh->t_expire_timer = 0;
290 neigh->interface = ifp;
291
292 pim_neighbor_timer_reset(neigh, holdtime);
293
294 pim_inet4_dump("<src?>", source_addr, src_str, sizeof(src_str));
295
296 if (PIM_DEBUG_PIM_EVENTS) {
297 zlog_debug("%s: creating PIM neighbor %s on interface %s",
298 __PRETTY_FUNCTION__,
299 src_str, ifp->name);
300 }
301
302 zlog_info("PIM NEIGHBOR UP: neighbor %s on interface %s",
303 src_str, ifp->name);
304
305 if (neigh->propagation_delay_msec > pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
306 pim_ifp->pim_neighbors_highest_propagation_delay_msec = neigh->propagation_delay_msec;
307 }
308 if (neigh->override_interval_msec > pim_ifp->pim_neighbors_highest_override_interval_msec) {
309 pim_ifp->pim_neighbors_highest_override_interval_msec = neigh->override_interval_msec;
310 }
311
312 if (!PIM_OPTION_IS_SET(neigh->hello_options,
313 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
314 /* update num. of neighbors without hello option lan_delay */
315 ++pim_ifp->pim_number_of_nonlandelay_neighbors;
316 }
317
318 if (!PIM_OPTION_IS_SET(neigh->hello_options,
319 PIM_OPTION_MASK_DR_PRIORITY)) {
320 /* update num. of neighbors without hello option dr_pri */
321 ++pim_ifp->pim_dr_num_nondrpri_neighbors;
322 }
323
324 /*
325 RFC 4601: 4.3.2. DR Election
326
327 A router's idea of the current DR on an interface can change when a
328 PIM Hello message is received, when a neighbor times out, or when a
329 router's own DR Priority changes.
330 */
331 pim_if_dr_election(neigh->interface);
332
333 /*
334 RFC 4601: 4.3.1. Sending Hello Messages
335
336 To allow new or rebooting routers to learn of PIM neighbors quickly,
337 when a Hello message is received from a new neighbor, or a Hello
338 message with a new GenID is received from an existing neighbor, a
339 new Hello message should be sent on this interface after a
340 randomized delay between 0 and Triggered_Hello_Delay.
341 */
342 pim_hello_restart_triggered(neigh->interface);
343
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;
389 zassert(pim_ifp);
390
391 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, node, neigh)) {
392 if (source_addr.s_addr == neigh->source_addr.s_addr) {
393 return neigh;
394 }
395 }
396
397 return 0;
398}
399
400struct pim_neighbor *pim_neighbor_add(struct interface *ifp,
401 struct in_addr source_addr,
402 pim_hello_options hello_options,
403 uint16_t holdtime,
404 uint16_t propagation_delay,
405 uint16_t override_interval,
406 uint32_t dr_priority,
407 uint32_t generation_id,
408 struct list *addr_list)
409{
410 struct pim_interface *pim_ifp;
411 struct pim_neighbor *neigh;
412
413 neigh = pim_neighbor_new(ifp, source_addr,
414 hello_options,
415 holdtime,
416 propagation_delay,
417 override_interval,
418 dr_priority,
419 generation_id,
420 addr_list);
421 if (!neigh) {
422 return 0;
423 }
424
425 pim_ifp = ifp->info;
426 zassert(pim_ifp);
427
428 listnode_add(pim_ifp->pim_neighbor_list, neigh);
429
430 return neigh;
431}
432
433static uint16_t
434find_neighbors_next_highest_propagation_delay_msec(struct interface *ifp,
435 struct pim_neighbor *highest_neigh)
436{
437 struct pim_interface *pim_ifp;
438 struct listnode *neigh_node;
439 struct pim_neighbor *neigh;
440 uint16_t next_highest_delay_msec;
441
442 pim_ifp = ifp->info;
443 zassert(pim_ifp);
444
445 next_highest_delay_msec = pim_ifp->pim_propagation_delay_msec;
446
447 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
448 if (neigh == highest_neigh)
449 continue;
450 if (neigh->propagation_delay_msec > next_highest_delay_msec)
451 next_highest_delay_msec = neigh->propagation_delay_msec;
452 }
453
454 return next_highest_delay_msec;
455}
456
457static uint16_t
458find_neighbors_next_highest_override_interval_msec(struct interface *ifp,
459 struct pim_neighbor *highest_neigh)
460{
461 struct pim_interface *pim_ifp;
462 struct listnode *neigh_node;
463 struct pim_neighbor *neigh;
464 uint16_t next_highest_interval_msec;
465
466 pim_ifp = ifp->info;
467 zassert(pim_ifp);
468
469 next_highest_interval_msec = pim_ifp->pim_override_interval_msec;
470
471 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node, neigh)) {
472 if (neigh == highest_neigh)
473 continue;
474 if (neigh->override_interval_msec > next_highest_interval_msec)
475 next_highest_interval_msec = neigh->override_interval_msec;
476 }
477
478 return next_highest_interval_msec;
479}
480
481void pim_neighbor_delete(struct interface *ifp,
482 struct pim_neighbor *neigh,
483 const char *delete_message)
484{
485 struct pim_interface *pim_ifp;
486 char src_str[100];
487
488 pim_ifp = ifp->info;
489 zassert(pim_ifp);
490
491 pim_inet4_dump("<src?>", neigh->source_addr, src_str, sizeof(src_str));
492 zlog_info("PIM NEIGHBOR DOWN: neighbor %s on interface %s: %s",
493 src_str, ifp->name, delete_message);
494
495 neighbor_timer_off(neigh);
496
497 pim_if_assert_on_neighbor_down(ifp, neigh->source_addr);
498
499 if (!PIM_OPTION_IS_SET(neigh->hello_options,
500 PIM_OPTION_MASK_LAN_PRUNE_DELAY)) {
501 /* update num. of neighbors without hello option lan_delay */
502
503 --pim_ifp->pim_number_of_nonlandelay_neighbors;
504 }
505
506 if (!PIM_OPTION_IS_SET(neigh->hello_options,
507 PIM_OPTION_MASK_DR_PRIORITY)) {
508 /* update num. of neighbors without dr_pri */
509
510 --pim_ifp->pim_dr_num_nondrpri_neighbors;
511 }
512
513 zassert(neigh->propagation_delay_msec <= pim_ifp->pim_neighbors_highest_propagation_delay_msec);
514 zassert(neigh->override_interval_msec <= pim_ifp->pim_neighbors_highest_override_interval_msec);
515
516 if (pim_if_lan_delay_enabled(ifp)) {
517
518 /* will delete a neighbor with highest propagation delay? */
519 if (neigh->propagation_delay_msec == pim_ifp->pim_neighbors_highest_propagation_delay_msec) {
520 /* then find the next highest propagation delay */
521 pim_ifp->pim_neighbors_highest_propagation_delay_msec =
522 find_neighbors_next_highest_propagation_delay_msec(ifp, neigh);
523 }
524
525 /* will delete a neighbor with highest override interval? */
526 if (neigh->override_interval_msec == pim_ifp->pim_neighbors_highest_override_interval_msec) {
527 /* then find the next highest propagation delay */
528 pim_ifp->pim_neighbors_highest_override_interval_msec =
529 find_neighbors_next_highest_override_interval_msec(ifp, neigh);
530 }
531 }
532
533 if (PIM_DEBUG_PIM_TRACE) {
534 zlog_debug("%s: deleting PIM neighbor %s on interface %s",
535 __PRETTY_FUNCTION__,
536 src_str, ifp->name);
537 }
538
539 listnode_delete(pim_ifp->pim_neighbor_list, neigh);
540
541 pim_neighbor_free(neigh);
542}
543
544void pim_neighbor_delete_all(struct interface *ifp,
545 const char *delete_message)
546{
547 struct pim_interface *pim_ifp;
548 struct listnode *neigh_node;
549 struct listnode *neigh_nextnode;
550 struct pim_neighbor *neigh;
551
552 pim_ifp = ifp->info;
553 zassert(pim_ifp);
554
555 for (ALL_LIST_ELEMENTS(pim_ifp->pim_neighbor_list, neigh_node,
556 neigh_nextnode, neigh)) {
557 pim_neighbor_delete(ifp, neigh, delete_message);
558 }
559}
560
561struct prefix *pim_neighbor_find_secondary(struct pim_neighbor *neigh,
562 struct in_addr addr)
563{
564 struct listnode *node;
565 struct prefix *p;
566
567 if (!neigh->prefix_list)
568 return 0;
569
570 for (ALL_LIST_ELEMENTS_RO(neigh->prefix_list, node, p)) {
571 if (p->family == AF_INET) {
572 if (addr.s_addr == p->u.prefix4.s_addr) {
573 return p;
574 }
575 }
576 }
577
578 return 0;
579}
580
581/*
582 RFC 4601: 4.3.4. Maintaining Secondary Address Lists
583
584 All the advertised secondary addresses in received Hello messages
585 must be checked against those previously advertised by all other
586 PIM neighbors on that interface. If there is a conflict and the
587 same secondary address was previously advertised by another
588 neighbor, then only the most recently received mapping MUST be
589 maintained, and an error message SHOULD be logged to the
590 administrator in a rate-limited manner.
591*/
592static void delete_from_neigh_addr(struct interface *ifp,
593 struct list *addr_list,
594 struct in_addr neigh_addr)
595{
596 struct listnode *addr_node;
597 struct prefix *addr;
598 struct pim_interface *pim_ifp;
599
600 pim_ifp = ifp->info;
601 zassert(pim_ifp);
602
603 zassert(addr_list);
604
605 /*
606 Scan secondary address list
607 */
608 for (ALL_LIST_ELEMENTS_RO(addr_list, addr_node,
609 addr)) {
610 struct listnode *neigh_node;
611 struct pim_neighbor *neigh;
612
613 if (addr->family != AF_INET)
614 continue;
615
616 /*
617 Scan neighbors
618 */
619 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neigh_node,
620 neigh)) {
621 {
622 struct prefix *p = pim_neighbor_find_secondary(neigh, addr->u.prefix4);
623 if (p) {
624 char addr_str[100];
625 char this_neigh_str[100];
626 char other_neigh_str[100];
627
628 pim_inet4_dump("<addr?>", addr->u.prefix4, addr_str, sizeof(addr_str));
629 pim_inet4_dump("<neigh1?>", neigh_addr, this_neigh_str, sizeof(this_neigh_str));
630 pim_inet4_dump("<neigh2?>", neigh->source_addr, other_neigh_str, sizeof(other_neigh_str));
631
632 zlog_info("secondary addr %s recvd from neigh %s deleted from neigh %s on %s",
633 addr_str, this_neigh_str, other_neigh_str, ifp->name);
634
635 listnode_delete(neigh->prefix_list, p);
636 prefix_free(p);
637 }
638 }
639
640 } /* scan neighbors */
641
642 } /* scan addr list */
643
644}
645
646void pim_neighbor_update(struct pim_neighbor *neigh,
647 pim_hello_options hello_options,
648 uint16_t holdtime,
649 uint32_t dr_priority,
650 struct list *addr_list)
651{
652 struct pim_interface *pim_ifp = neigh->interface->info;
653
654 /* Received holdtime ? */
655 if (PIM_OPTION_IS_SET(hello_options, PIM_OPTION_MASK_HOLDTIME)) {
656 pim_neighbor_timer_reset(neigh, holdtime);
657 }
658 else {
659 pim_neighbor_timer_reset(neigh, PIM_IF_DEFAULT_HOLDTIME(pim_ifp));
660 }
661
662#ifdef DUMP_PREFIX_LIST
663 zlog_debug("%s: DUMP_PREFIX_LIST old_prefix_list=%x old_size=%d new_prefix_list=%x new_size=%d",
664 __PRETTY_FUNCTION__,
665 (unsigned) neigh->prefix_list,
666 neigh->prefix_list ? (int) listcount(neigh->prefix_list) : -1,
667 (unsigned) addr_list,
668 addr_list ? (int) listcount(addr_list) : -1);
669#endif
670
671 if (neigh->prefix_list == addr_list) {
672 if (addr_list) {
673 zlog_err("%s: internal error: trying to replace same prefix list=%u",
674 __PRETTY_FUNCTION__, (unsigned) addr_list);
675 }
676 }
677 else {
678 /* Delete existing secondary address list */
679 delete_prefix_list(neigh);
680 }
681
682 if (addr_list) {
683 delete_from_neigh_addr(neigh->interface, addr_list, neigh->source_addr);
684 }
685
686 /* Replace secondary address list */
687 neigh->prefix_list = addr_list;
688
689 update_dr_priority(neigh,
690 hello_options,
691 dr_priority);
692 /*
693 Copy flags
694 */
695 neigh->hello_options = hello_options;
696}