blob: 009f87c1725effbece6f2ee217dba8944e558795 [file] [log] [blame]
Everton Marques871dbcf2009-08-11 15:43:05 -03001/*
2 PIM for Quagga
3 Copyright (C) 2008 Everton da Silva Marques
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2 of the License, or
7 (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; see the file COPYING; if not, write to the
16 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
17 MA 02110-1301 USA
18
19 $QuaggaId: $Format:%an, %ai, %h$ $
20*/
21
22#include <zebra.h>
23
24#include "if.h"
25#include "log.h"
26#include "vty.h"
27#include "memory.h"
28#include "prefix.h"
29
30#include "pimd.h"
31#include "pim_iface.h"
32#include "pim_igmp.h"
33#include "pim_mroute.h"
34#include "pim_oil.h"
35#include "pim_str.h"
36#include "pim_pim.h"
37#include "pim_neighbor.h"
38#include "pim_ifchannel.h"
39#include "pim_rand.h"
40#include "pim_sock.h"
41
42static void pim_if_igmp_join_del_all(struct interface *ifp);
43
44void pim_if_init()
45{
46 if_init();
47}
48
49static void *if_list_clean(struct pim_interface *pim_ifp)
50{
51 if (pim_ifp->igmp_join_list) {
52 list_delete(pim_ifp->igmp_join_list);
53 }
54
55 if (pim_ifp->igmp_socket_list) {
56 list_delete(pim_ifp->igmp_socket_list);
57 }
58
59 if (pim_ifp->pim_neighbor_list) {
60 list_delete(pim_ifp->pim_neighbor_list);
61 }
62
63 if (pim_ifp->pim_ifchannel_list) {
64 list_delete(pim_ifp->pim_ifchannel_list);
65 }
66
67 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
68
69 return 0;
70}
71
72struct pim_interface *pim_if_new(struct interface *ifp, int igmp, int pim)
73{
74 struct pim_interface *pim_ifp;
75
76 zassert(ifp);
77 zassert(!ifp->info);
78
79 pim_ifp = XMALLOC(MTYPE_PIM_INTERFACE, sizeof(*pim_ifp));
80 if (!pim_ifp) {
81 zlog_err("PIM XMALLOC(%d) failure", sizeof(*pim_ifp));
82 return 0;
83 }
84
85 pim_ifp->options = 0;
86 pim_ifp->mroute_vif_index = -1;
87
Leonard Herve236b0152009-08-11 15:51:52 -030088 pim_ifp->igmp_default_robustness_variable = IGMP_DEFAULT_ROBUSTNESS_VARIABLE;
89 pim_ifp->igmp_default_query_interval = IGMP_GENERAL_QUERY_INTERVAL;
90 pim_ifp->igmp_query_max_response_time_dsec = IGMP_QUERY_MAX_RESPONSE_TIME_DSEC;
91 pim_ifp->igmp_specific_query_max_response_time_dsec = IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC;
Everton Marques871dbcf2009-08-11 15:43:05 -030092
93 /*
94 RFC 3376: 8.3. Query Response Interval
95 The number of seconds represented by the [Query Response Interval]
96 must be less than the [Query Interval].
97 */
98 zassert(pim_ifp->igmp_query_max_response_time_dsec < pim_ifp->igmp_default_query_interval);
99
100 if (pim)
101 PIM_IF_DO_PIM(pim_ifp->options);
102 if (igmp)
103 PIM_IF_DO_IGMP(pim_ifp->options);
104
105#if 0
106 /* FIXME: Should join? */
107 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp->options);
108#endif
109
110 pim_ifp->igmp_join_list = 0;
111 pim_ifp->igmp_socket_list = 0;
112 pim_ifp->pim_neighbor_list = 0;
113 pim_ifp->pim_ifchannel_list = 0;
114
115 /* list of struct igmp_sock */
116 pim_ifp->igmp_socket_list = list_new();
117 if (!pim_ifp->igmp_socket_list) {
118 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
119 __FILE__, __PRETTY_FUNCTION__);
120 return if_list_clean(pim_ifp);
121 }
122 pim_ifp->igmp_socket_list->del = (void (*)(void *)) igmp_sock_free;
123
124 /* list of struct pim_neighbor */
125 pim_ifp->pim_neighbor_list = list_new();
126 if (!pim_ifp->pim_neighbor_list) {
127 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
128 __FILE__, __PRETTY_FUNCTION__);
129 return if_list_clean(pim_ifp);
130 }
131 pim_ifp->pim_neighbor_list->del = (void (*)(void *)) pim_neighbor_free;
132
133 /* list of struct pim_ifchannel */
134 pim_ifp->pim_ifchannel_list = list_new();
135 if (!pim_ifp->pim_ifchannel_list) {
136 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
137 __FILE__, __PRETTY_FUNCTION__);
138 return if_list_clean(pim_ifp);
139 }
140 pim_ifp->pim_ifchannel_list->del = (void (*)(void *)) pim_ifchannel_free;
141
142 ifp->info = pim_ifp;
143
144 pim_sock_reset(ifp);
145
146 zassert(PIM_IF_TEST_PIM(pim_ifp->options) || PIM_IF_TEST_IGMP(pim_ifp->options));
147
148 if (PIM_MROUTE_IS_ENABLED) {
149 pim_if_add_vif(ifp);
150 }
151
152 return pim_ifp;
153}
154
155void pim_if_delete(struct interface *ifp)
156{
157 struct pim_interface *pim_ifp;
158
159 zassert(ifp);
160 pim_ifp = ifp->info;
161 zassert(pim_ifp);
162
163 if (pim_ifp->igmp_join_list) {
164 pim_if_igmp_join_del_all(ifp);
165 }
166 zassert(!pim_ifp->igmp_join_list);
167
168 zassert(pim_ifp->igmp_socket_list);
169 zassert(!listcount(pim_ifp->igmp_socket_list));
170
171 zassert(pim_ifp->pim_neighbor_list);
172 zassert(!listcount(pim_ifp->pim_neighbor_list));
173
174 zassert(pim_ifp->pim_ifchannel_list);
175 zassert(!listcount(pim_ifp->pim_ifchannel_list));
176
177 if (PIM_MROUTE_IS_ENABLED) {
178 pim_if_del_vif(ifp);
179 }
180
181 list_delete(pim_ifp->igmp_socket_list);
182 list_delete(pim_ifp->pim_neighbor_list);
183 list_delete(pim_ifp->pim_ifchannel_list);
184
185 XFREE(MTYPE_PIM_INTERFACE, pim_ifp);
186
187 ifp->info = 0;
188}
189
190void pim_if_update_could_assert(struct interface *ifp)
191{
192 struct pim_interface *pim_ifp;
193 struct listnode *node;
194 struct listnode *next_node;
195 struct pim_ifchannel *ch;
196
197 pim_ifp = ifp->info;
198 zassert(pim_ifp);
199
200 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
201 pim_ifchannel_update_could_assert(ch);
202 }
203}
204
205static void pim_if_update_my_assert_metric(struct interface *ifp)
206{
207 struct pim_interface *pim_ifp;
208 struct listnode *node;
209 struct listnode *next_node;
210 struct pim_ifchannel *ch;
211
212 pim_ifp = ifp->info;
213 zassert(pim_ifp);
214
215 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
216 pim_ifchannel_update_my_assert_metric(ch);
217 }
218}
219
220static void pim_addr_change(struct interface *ifp)
221{
222 struct pim_interface *pim_ifp;
223
224 pim_ifp = ifp->info;
225 zassert(pim_ifp);
226
227 pim_if_dr_election(ifp); /* Done TODO T30 */
228 pim_if_update_join_desired(pim_ifp); /* depends on DR */
229 pim_if_update_could_assert(ifp); /* depends on DR */
230 pim_if_update_my_assert_metric(ifp); /* depends on could_assert */
231 pim_if_update_assert_tracking_desired(ifp); /* depends on DR, join_desired */
232
233 /*
234 RFC 4601: 4.3.1. Sending Hello Messages
235
236 1) Before an interface goes down or changes primary IP address, a
237 Hello message with a zero HoldTime should be sent immediately
238 (with the old IP address if the IP address changed).
239 -- FIXME See CAVEAT C13
240
241 2) After an interface has changed its IP address, it MUST send a
242 Hello message with its new IP address.
243 -- DONE below
244
245 3) If an interface changes one of its secondary IP addresses, a
246 Hello message with an updated Address_List option and a non-zero
247 HoldTime should be sent immediately.
248 -- FIXME See TODO T31
249 */
250 pim_ifp->pim_ifstat_hello_sent = 0; /* reset hello counter */
251 if (pim_ifp->pim_sock_fd < 0)
252 return;
253 pim_hello_restart_now(ifp); /* send hello and restart timer */
254}
255
256static void on_primary_address_change(struct interface *ifp,
257 const char *caller,
258 struct in_addr old_addr,
259 struct in_addr new_addr)
260{
261 struct pim_interface *pim_ifp;
262
263 {
264 char old_str[100];
265 char new_str[100];
266 pim_inet4_dump("<old?>", old_addr, old_str, sizeof(old_str));
267 pim_inet4_dump("<new?>", new_addr, new_str, sizeof(new_str));
268 zlog_info("%s: %s: primary address changed from %s to %s on interface %s",
269 __PRETTY_FUNCTION__, caller,
270 old_str, new_str, ifp->name);
271 }
272
273 pim_ifp = ifp->info;
274
275 if (pim_ifp) {
276 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
277 pim_addr_change(ifp);
278 }
279 }
280}
281
282static void detect_primary_address_change(struct interface *ifp,
283 const char *caller)
284{
285 struct pim_interface *pim_ifp;
286 struct in_addr new_prim_addr;
287
288 pim_ifp = ifp->info;
289 if (!pim_ifp)
290 return;
291
292 new_prim_addr = pim_find_primary_addr(ifp);
293
294 if (PIM_DEBUG_ZEBRA) {
295 char new_prim_str[100];
296 char old_prim_str[100];
297 pim_inet4_dump("<new?>", new_prim_addr, new_prim_str, sizeof(new_prim_str));
298 pim_inet4_dump("<old?>", pim_ifp->primary_address, old_prim_str, sizeof(old_prim_str));
299 zlog_debug("%s: old primary addr %s, new primary addr %s on interface %s",
300 __PRETTY_FUNCTION__,
301 old_prim_str, new_prim_str, ifp->name);
302 }
303
304 if (new_prim_addr.s_addr != pim_ifp->primary_address.s_addr) {
305 struct in_addr old_addr = pim_ifp->primary_address;
306 pim_ifp->primary_address = new_prim_addr;
307
308 on_primary_address_change(ifp, caller, old_addr, new_prim_addr);
309 }
310}
311
312void pim_if_addr_add(struct connected *ifc)
313{
314 struct pim_interface *pim_ifp;
315 struct interface *ifp;
316 struct in_addr ifaddr;
317
318 zassert(ifc);
319
320 ifp = ifc->ifp;
321 zassert(ifp);
322 pim_ifp = ifp->info;
323 if (!pim_ifp)
324 return;
325
326 if (!if_is_operative(ifp))
327 return;
328
329 ifaddr = ifc->address->u.prefix4;
330
331 detect_primary_address_change(ifp, __PRETTY_FUNCTION__);
332
333 if (PIM_IF_TEST_IGMP(pim_ifp->options)) {
334 struct igmp_sock *igmp;
335
336 /* lookup IGMP socket */
337 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
338 ifaddr);
339 if (!igmp) {
340 /* if addr new, add IGMP socket */
341 pim_igmp_sock_add(pim_ifp->igmp_socket_list, ifaddr, ifp);
342 }
343 } /* igmp */
344
345 if (PIM_IF_TEST_PIM(pim_ifp->options)) {
346
347 /* Interface has a valid primary address ? */
348 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
349
350 /* Interface has a valid socket ? */
351 if (pim_ifp->pim_sock_fd < 0) {
352 if (pim_sock_add(ifp)) {
353 zlog_warn("Failure creating PIM socket for interface %s",
354 ifp->name);
355 }
356 }
357
358 }
359 } /* pim */
360
361 if (PIM_MROUTE_IS_ENABLED) {
362 /*
363 PIM or IGMP is enabled on interface, and there is at least one
364 address assigned, then try to create a vif_index.
365 */
366 if (pim_ifp->mroute_vif_index < 0) {
367 pim_if_add_vif(ifp);
368 }
369 }
370}
371
372static void pim_if_addr_del_igmp(struct connected *ifc)
373{
374 struct pim_interface *pim_ifp = ifc->ifp->info;
375 struct igmp_sock *igmp;
376 struct in_addr ifaddr;
377
378 if (ifc->address->family != AF_INET) {
379 /* non-IPv4 address */
380 return;
381 }
382
383 if (!pim_ifp) {
384 /* IGMP not enabled on interface */
385 return;
386 }
387
388 ifaddr = ifc->address->u.prefix4;
389
390 /* lookup IGMP socket */
391 igmp = pim_igmp_sock_lookup_ifaddr(pim_ifp->igmp_socket_list,
392 ifaddr);
393 if (igmp) {
394 /* if addr found, del IGMP socket */
395 igmp_sock_delete(igmp);
396 }
397}
398
399static void pim_if_addr_del_pim(struct connected *ifc)
400{
401 struct pim_interface *pim_ifp = ifc->ifp->info;
402
403 if (ifc->address->family != AF_INET) {
404 /* non-IPv4 address */
405 return;
406 }
407
408 if (!pim_ifp) {
409 /* PIM not enabled on interface */
410 return;
411 }
412
413 if (PIM_INADDR_ISNOT_ANY(pim_ifp->primary_address)) {
414 /* Interface keeps a valid primary address */
415 return;
416 }
417
418 if (pim_ifp->pim_sock_fd < 0) {
419 /* Interface does not hold a valid socket any longer */
420 return;
421 }
422
423 /*
424 pim_sock_delete() closes the socket, stops read and timer threads,
425 and kills all neighbors.
426 */
427 pim_sock_delete(ifc->ifp, "last address has been removed from interface");
428}
429
430void pim_if_addr_del(struct connected *ifc)
431{
432 struct interface *ifp;
433
434 zassert(ifc);
435 ifp = ifc->ifp;
436 zassert(ifp);
437
438 detect_primary_address_change(ifp, __PRETTY_FUNCTION__);
439
440 pim_if_addr_del_igmp(ifc);
441 pim_if_addr_del_pim(ifc);
442}
443
444void pim_if_addr_add_all(struct interface *ifp)
445{
446 struct connected *ifc;
447 struct listnode *node;
448 struct listnode *nextnode;
449
450 /* PIM/IGMP enabled ? */
451 if (!ifp->info)
452 return;
453
454 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
455 struct prefix *p = ifc->address;
456
457 if (p->family != AF_INET)
458 continue;
459
460 pim_if_addr_add(ifc);
461 }
462}
463
464void pim_if_addr_del_all(struct interface *ifp)
465{
466 struct connected *ifc;
467 struct listnode *node;
468 struct listnode *nextnode;
469
470 /* PIM/IGMP enabled ? */
471 if (!ifp->info)
472 return;
473
474 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
475 struct prefix *p = ifc->address;
476
477 if (p->family != AF_INET)
478 continue;
479
480 pim_if_addr_del(ifc);
481 }
482}
483
484void pim_if_addr_del_all_igmp(struct interface *ifp)
485{
486 struct connected *ifc;
487 struct listnode *node;
488 struct listnode *nextnode;
489
490 /* PIM/IGMP enabled ? */
491 if (!ifp->info)
492 return;
493
494 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
495 struct prefix *p = ifc->address;
496
497 if (p->family != AF_INET)
498 continue;
499
500 pim_if_addr_del_igmp(ifc);
501 }
502}
503
504void pim_if_addr_del_all_pim(struct interface *ifp)
505{
506 struct connected *ifc;
507 struct listnode *node;
508 struct listnode *nextnode;
509
510 /* PIM/IGMP enabled ? */
511 if (!ifp->info)
512 return;
513
514 for (ALL_LIST_ELEMENTS(ifp->connected, node, nextnode, ifc)) {
515 struct prefix *p = ifc->address;
516
517 if (p->family != AF_INET)
518 continue;
519
520 pim_if_addr_del_pim(ifc);
521 }
522}
523
524static struct in_addr find_first_addr(struct interface *ifp)
525{
526 struct connected *ifc;
527 struct listnode *node;
528 struct in_addr addr;
529
530 for (ALL_LIST_ELEMENTS_RO(ifp->connected, node, ifc)) {
531 struct prefix *p = ifc->address;
532
533 if (p->family != AF_INET)
534 continue;
535
536 if (PIM_INADDR_IS_ANY(p->u.prefix4)) {
537 zlog_warn("%s: null IPv4 address connected to interface %s",
538 __PRETTY_FUNCTION__, ifp->name);
539 continue;
540 }
541
542 return p->u.prefix4;
543 }
544
545 addr.s_addr = PIM_NET_INADDR_ANY;
546
547 return addr;
548}
549
550struct in_addr pim_find_primary_addr(struct interface *ifp)
551{
552 return find_first_addr(ifp);
553}
554
555/*
556 pim_if_add_vif() uses ifindex as vif_index
557
558 see also pim_if_find_vifindex_by_ifindex()
559 */
560int pim_if_add_vif(struct interface *ifp)
561{
562 struct pim_interface *pim_ifp = ifp->info;
563 struct in_addr ifaddr;
564
565 zassert(pim_ifp);
566
567 if (pim_ifp->mroute_vif_index > 0) {
568 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
569 __PRETTY_FUNCTION__,
570 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
571 return -1;
572 }
573
574 if (ifp->ifindex < 1) {
575 zlog_warn("%s: ifindex=%d < 1 on interface %s",
576 __PRETTY_FUNCTION__,
577 ifp->ifindex, ifp->name);
578 return -2;
579 }
580
581 if (ifp->ifindex >= MAXVIFS) {
582 zlog_warn("%s: ifindex=%d >= MAXVIFS=%d on interface %s",
583 __PRETTY_FUNCTION__,
584 ifp->ifindex, MAXVIFS, ifp->name);
585 return -3;
586 }
587
588 ifaddr = pim_ifp->primary_address;
589 if (PIM_INADDR_IS_ANY(ifaddr)) {
590 zlog_warn("%s: could not get address for interface %s ifindex=%d",
591 __PRETTY_FUNCTION__,
592 ifp->name, ifp->ifindex);
593 return -4;
594 }
595
596 if (pim_mroute_add_vif(ifp->ifindex, ifaddr)) {
597 /* pim_mroute_add_vif reported error */
598 return -5;
599 }
600
601 pim_ifp->mroute_vif_index = ifp->ifindex;
602
603 /*
604 Update highest vif_index
605 */
606 if (pim_ifp->mroute_vif_index > qpim_mroute_oif_highest_vif_index) {
607 qpim_mroute_oif_highest_vif_index = pim_ifp->mroute_vif_index;
608 }
609
610 return 0;
611}
612
613static int iflist_find_highest_vif_index()
614{
615 struct listnode *ifnode;
616 struct interface *ifp;
617 struct pim_interface *pim_ifp;
618 int highest_vif_index = -1;
619
620 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
621 pim_ifp = ifp->info;
622 if (!pim_ifp)
623 continue;
624
625 if (pim_ifp->mroute_vif_index > highest_vif_index) {
626 highest_vif_index = pim_ifp->mroute_vif_index;
627 }
628 }
629
630 return highest_vif_index;
631}
632
633int pim_if_del_vif(struct interface *ifp)
634{
635 struct pim_interface *pim_ifp = ifp->info;
636 int old_vif_index;
637
638 if (pim_ifp->mroute_vif_index < 1) {
639 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
640 __PRETTY_FUNCTION__,
641 pim_ifp->mroute_vif_index, ifp->name, ifp->ifindex);
642 return -1;
643 }
644
645 if (pim_mroute_del_vif(pim_ifp->mroute_vif_index)) {
646 /* pim_mroute_del_vif reported error */
647 return -2;
648 }
649
650 /*
651 Update highest vif_index
652 */
653
654 /* save old vif_index in order to compare with highest below */
655 old_vif_index = pim_ifp->mroute_vif_index;
656
657 pim_ifp->mroute_vif_index = -1;
658
659 if (old_vif_index == qpim_mroute_oif_highest_vif_index) {
660 qpim_mroute_oif_highest_vif_index = iflist_find_highest_vif_index();
661 }
662
663 return 0;
664}
665
666void pim_if_add_vif_all()
667{
668 struct listnode *ifnode;
669 struct listnode *ifnextnode;
670 struct interface *ifp;
671
672 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
673 if (!ifp->info)
674 continue;
675
676 pim_if_add_vif(ifp);
677 }
678}
679
680void pim_if_del_vif_all()
681{
682 struct listnode *ifnode;
683 struct listnode *ifnextnode;
684 struct interface *ifp;
685
686 for (ALL_LIST_ELEMENTS(iflist, ifnode, ifnextnode, ifp)) {
687 if (!ifp->info)
688 continue;
689
690 pim_if_del_vif(ifp);
691 }
692}
693
694struct interface *pim_if_find_by_vif_index(int vif_index)
695{
696 struct listnode *ifnode;
697 struct interface *ifp;
698
699 for (ALL_LIST_ELEMENTS_RO(iflist, ifnode, ifp)) {
700 if (ifp->info) {
701 struct pim_interface *pim_ifp;
702 pim_ifp = ifp->info;
703 if (vif_index == pim_ifp->mroute_vif_index)
704 return ifp;
705 }
706 }
707
708 return 0;
709}
710
711/*
712 pim_if_add_vif() uses ifindex as vif_index
713 */
714int pim_if_find_vifindex_by_ifindex(int ifindex)
715{
716 return ifindex;
717}
718
719int pim_if_lan_delay_enabled(struct interface *ifp)
720{
721 struct pim_interface *pim_ifp;
722
723 pim_ifp = ifp->info;
724 zassert(pim_ifp);
725 zassert(pim_ifp->pim_number_of_nonlandelay_neighbors >= 0);
726
727 return pim_ifp->pim_number_of_nonlandelay_neighbors == 0;
728}
729
730uint16_t pim_if_effective_propagation_delay_msec(struct interface *ifp)
731{
732 if (pim_if_lan_delay_enabled(ifp)) {
733 struct pim_interface *pim_ifp;
734 pim_ifp = ifp->info;
735 return pim_ifp->pim_neighbors_highest_propagation_delay_msec;
736 }
737 else {
738 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC;
739 }
740}
741
742uint16_t pim_if_effective_override_interval_msec(struct interface *ifp)
743{
744 if (pim_if_lan_delay_enabled(ifp)) {
745 struct pim_interface *pim_ifp;
746 pim_ifp = ifp->info;
747 return pim_ifp->pim_neighbors_highest_override_interval_msec;
748 }
749 else {
750 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC;
751 }
752}
753
754int pim_if_t_override_msec(struct interface *ifp)
755{
756 int effective_override_interval_msec;
757 int t_override_msec;
758
759 effective_override_interval_msec =
760 pim_if_effective_override_interval_msec(ifp);
761
762 t_override_msec = pim_rand_next(0, effective_override_interval_msec);
763
764 return t_override_msec;
765}
766
767uint16_t pim_if_jp_override_interval_msec(struct interface *ifp)
768{
769 return pim_if_effective_propagation_delay_msec(ifp) +
770 pim_if_effective_override_interval_msec(ifp);
771}
772
773/*
774 RFC 4601: 4.1.6. State Summarization Macros
775
776 The function NBR( I, A ) uses information gathered through PIM Hello
777 messages to map the IP address A of a directly connected PIM
778 neighbor router on interface I to the primary IP address of the same
779 router (Section 4.3.4). The primary IP address of a neighbor is the
780 address that it uses as the source of its PIM Hello messages.
781*/
782struct pim_neighbor *pim_if_find_neighbor(struct interface *ifp,
783 struct in_addr addr)
784{
785 struct listnode *neighnode;
786 struct pim_neighbor *neigh;
787 struct pim_interface *pim_ifp;
788
789 zassert(ifp);
790
791 pim_ifp = ifp->info;
792 if (!pim_ifp) {
793 zlog_warn("%s: multicast not enabled on interface %s",
794 __PRETTY_FUNCTION__,
795 ifp->name);
796 return 0;
797 }
798
799 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_neighbor_list, neighnode, neigh)) {
800
801 /* primary address ? */
802 if (neigh->source_addr.s_addr == addr.s_addr)
803 return neigh;
804
805 /* secondary address ? */
806 if (pim_neighbor_find_secondary(neigh, addr))
807 return neigh;
808 }
809
810 if (PIM_DEBUG_PIM_TRACE) {
811 char addr_str[100];
812 pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
813 zlog_debug("%s: neighbor not found for address %s on interface %s",
814 __PRETTY_FUNCTION__,
815 addr_str, ifp->name);
816 }
817
818 return 0;
819}
820
821long pim_if_t_suppressed_msec(struct interface *ifp)
822{
823 struct pim_interface *pim_ifp;
824 long t_suppressed_msec;
825
826 pim_ifp = ifp->info;
827 zassert(pim_ifp);
828
829 /* join suppression disabled ? */
830 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp->options))
831 return 0;
832
833 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
834
835 t_suppressed_msec = qpim_t_periodic * pim_rand_next(1100, 1400);
836
837 return t_suppressed_msec;
838}
839
840static void igmp_join_free(struct igmp_join *ij)
841{
842 XFREE(MTYPE_PIM_IGMP_JOIN, ij);
843}
844
845static struct igmp_join *igmp_join_find(struct list *join_list,
846 struct in_addr group_addr,
847 struct in_addr source_addr)
848{
849 struct listnode *node;
850 struct igmp_join *ij;
851
852 zassert(join_list);
853
854 for (ALL_LIST_ELEMENTS_RO(join_list, node, ij)) {
855 if ((group_addr.s_addr == ij->group_addr.s_addr) &&
856 (source_addr.s_addr == ij->source_addr.s_addr))
857 return ij;
858 }
859
860 return 0;
861}
862
863static int igmp_join_sock(const char *ifname,
864 int ifindex,
865 struct in_addr group_addr,
866 struct in_addr source_addr)
867{
868 int join_fd;
869
870 join_fd = pim_socket_raw(IPPROTO_IGMP);
871 if (join_fd < 0) {
872 return -1;
873 }
874
875 if (pim_socket_join_source(join_fd, ifindex, group_addr, source_addr, ifname)) {
876 close(join_fd);
877 return -2;
878 }
879
880 return join_fd;
881}
882
883static struct igmp_join *igmp_join_new(struct interface *ifp,
884 struct in_addr group_addr,
885 struct in_addr source_addr)
886{
887 struct pim_interface *pim_ifp;
888 struct igmp_join *ij;
889 int join_fd;
890
891 pim_ifp = ifp->info;
892 zassert(pim_ifp);
893
894 join_fd = igmp_join_sock(ifp->name, ifp->ifindex, group_addr, source_addr);
895 if (join_fd < 0) {
896 char group_str[100];
897 char source_str[100];
898 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
899 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
900 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
901 __PRETTY_FUNCTION__,
902 group_str, source_str, ifp->name);
903 return 0;
904 }
905
906 ij = XMALLOC(MTYPE_PIM_IGMP_JOIN, sizeof(*ij));
907 if (!ij) {
908 char group_str[100];
909 char source_str[100];
910 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
911 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
912 zlog_err("%s: XMALLOC(%d) failure for IGMP group %s source %s on interface %s",
913 __PRETTY_FUNCTION__,
914 sizeof(*ij), group_str, source_str, ifp->name);
915 close(join_fd);
916 return 0;
917 }
918
919 ij->sock_fd = join_fd;
920 ij->group_addr = group_addr;
921 ij->source_addr = source_addr;
922
923 listnode_add(pim_ifp->igmp_join_list, ij);
924
925 return ij;
926}
927
928int pim_if_igmp_join_add(struct interface *ifp,
929 struct in_addr group_addr,
930 struct in_addr source_addr)
931{
932 struct pim_interface *pim_ifp;
933 struct igmp_join *ij;
934
935 pim_ifp = ifp->info;
936 if (!pim_ifp) {
937 zlog_warn("%s: multicast not enabled on interface %s",
938 __PRETTY_FUNCTION__,
939 ifp->name);
940 return -1;
941 }
942
943 if (!pim_ifp->igmp_join_list) {
944 pim_ifp->igmp_join_list = list_new();
945 if (!pim_ifp->igmp_join_list) {
946 zlog_err("%s %s: failure: igmp_join_list=list_new()",
947 __FILE__, __PRETTY_FUNCTION__);
948 return -2;
949 }
950 pim_ifp->igmp_join_list->del = (void (*)(void *)) igmp_join_free;
951 }
952
953 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
954 if (ij) {
955 char group_str[100];
956 char source_str[100];
957 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
958 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
959 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
960 __PRETTY_FUNCTION__,
961 group_str, source_str, ifp->name);
962 return -3;
963 }
964
965 ij = igmp_join_new(ifp, group_addr, source_addr);
966 if (!ij) {
967 char group_str[100];
968 char source_str[100];
969 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
970 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
971 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
972 __PRETTY_FUNCTION__,
973 group_str, source_str, ifp->name);
974 return -4;
975 }
976
977 return 0;
978}
979
980
981
982int pim_if_igmp_join_del(struct interface *ifp,
983 struct in_addr group_addr,
984 struct in_addr source_addr)
985{
986 struct pim_interface *pim_ifp;
987 struct igmp_join *ij;
988
989 pim_ifp = ifp->info;
990 if (!pim_ifp) {
991 zlog_warn("%s: multicast not enabled on interface %s",
992 __PRETTY_FUNCTION__,
993 ifp->name);
994 return -1;
995 }
996
997 if (!pim_ifp->igmp_join_list) {
998 zlog_warn("%s: no IGMP join on interface %s",
999 __PRETTY_FUNCTION__,
1000 ifp->name);
1001 return -2;
1002 }
1003
1004 ij = igmp_join_find(pim_ifp->igmp_join_list, group_addr, source_addr);
1005 if (!ij) {
1006 char group_str[100];
1007 char source_str[100];
1008 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1009 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1010 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1011 __PRETTY_FUNCTION__,
1012 group_str, source_str, ifp->name);
1013 return -3;
1014 }
1015
1016 if (close(ij->sock_fd)) {
1017 int e = errno;
1018 char group_str[100];
1019 char source_str[100];
1020 pim_inet4_dump("<grp?>", group_addr, group_str, sizeof(group_str));
1021 pim_inet4_dump("<src?>", source_addr, source_str, sizeof(source_str));
1022 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1023 __PRETTY_FUNCTION__,
Everton Marquese96f0af2009-08-11 15:48:02 -03001024 ij->sock_fd, group_str, source_str, ifp->name, e, safe_strerror(e));
Everton Marques871dbcf2009-08-11 15:43:05 -03001025 /* warning only */
1026 }
1027 listnode_delete(pim_ifp->igmp_join_list, ij);
1028 igmp_join_free(ij);
1029 if (listcount(pim_ifp->igmp_join_list) < 1) {
1030 list_delete(pim_ifp->igmp_join_list);
1031 pim_ifp->igmp_join_list = 0;
1032 }
1033
1034 return 0;
1035}
1036
1037static void pim_if_igmp_join_del_all(struct interface *ifp)
1038{
1039 struct pim_interface *pim_ifp;
1040 struct listnode *node;
1041 struct listnode *nextnode;
1042 struct igmp_join *ij;
1043
1044 pim_ifp = ifp->info;
1045 if (!pim_ifp) {
1046 zlog_warn("%s: multicast not enabled on interface %s",
1047 __PRETTY_FUNCTION__,
1048 ifp->name);
1049 return;
1050 }
1051
1052 if (!pim_ifp->igmp_join_list)
1053 return;
1054
1055 for (ALL_LIST_ELEMENTS(pim_ifp->igmp_join_list, node, nextnode, ij))
1056 pim_if_igmp_join_del(ifp, ij->group_addr, ij->source_addr);
1057}
1058
1059/*
1060 RFC 4601
1061
1062 Transitions from "I am Assert Loser" State
1063
1064 Current Winner's GenID Changes or NLT Expires
1065
1066 The Neighbor Liveness Timer associated with the current winner
1067 expires or we receive a Hello message from the current winner
1068 reporting a different GenID from the one it previously reported.
1069 This indicates that the current winner's interface or router has
1070 gone down (and may have come back up), and so we must assume it no
1071 longer knows it was the winner.
1072 */
1073void pim_if_assert_on_neighbor_down(struct interface *ifp,
1074 struct in_addr neigh_addr)
1075{
1076 struct pim_interface *pim_ifp;
1077 struct listnode *node;
1078 struct listnode *next_node;
1079 struct pim_ifchannel *ch;
1080
1081 pim_ifp = ifp->info;
1082 zassert(pim_ifp);
1083
1084 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1085 /* Is (S,G,I) assert loser ? */
1086 if (ch->ifassert_state != PIM_IFASSERT_I_AM_LOSER)
1087 continue;
1088 /* Dead neighbor was winner ? */
1089 if (ch->ifassert_winner.s_addr != neigh_addr.s_addr)
1090 continue;
1091
1092 assert_action_a5(ch);
1093 }
1094}
1095
1096void pim_if_update_join_desired(struct pim_interface *pim_ifp)
1097{
1098 struct listnode *ch_node;
1099 struct pim_ifchannel *ch;
1100
1101 /* clear off flag from interface's upstreams */
1102 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1103 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch->upstream->flags);
1104 }
1105
1106 /* scan per-interface (S,G,I) state on this I interface */
1107 for (ALL_LIST_ELEMENTS_RO(pim_ifp->pim_ifchannel_list, ch_node, ch)) {
1108 struct pim_upstream *up = ch->upstream;
1109
1110 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up->flags))
1111 continue;
1112
1113 /* update join_desired for the global (S,G) state */
1114 pim_upstream_update_join_desired(up);
1115 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up->flags);
1116 }
1117}
1118
1119void pim_if_update_assert_tracking_desired(struct interface *ifp)
1120{
1121 struct pim_interface *pim_ifp;
1122 struct listnode *node;
1123 struct listnode *next_node;
1124 struct pim_ifchannel *ch;
1125
1126 pim_ifp = ifp->info;
1127 if (!pim_ifp)
1128 return;
1129
1130 for (ALL_LIST_ELEMENTS(pim_ifp->pim_ifchannel_list, node, next_node, ch)) {
1131 pim_ifchannel_update_assert_tracking_desired(ch);
1132 }
1133}