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