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.
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.
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,
30 #include "pim_iface.h"
32 #include "pim_mroute.h"
36 #include "pim_neighbor.h"
37 #include "pim_ifchannel.h"
40 #include "pim_ssmpingd.h"
42 struct interface
*pim_regiface
= NULL
;
44 static void pim_if_igmp_join_del_all(struct interface
*ifp
);
48 vrf_iflist_create(VRF_DEFAULT
);
51 static void *if_list_clean(struct pim_interface
*pim_ifp
)
53 if (pim_ifp
->igmp_join_list
) {
54 list_delete(pim_ifp
->igmp_join_list
);
57 if (pim_ifp
->igmp_socket_list
) {
58 list_delete(pim_ifp
->igmp_socket_list
);
61 if (pim_ifp
->pim_neighbor_list
) {
62 list_delete(pim_ifp
->pim_neighbor_list
);
65 if (pim_ifp
->pim_ifchannel_list
) {
66 list_delete(pim_ifp
->pim_ifchannel_list
);
69 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
74 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
76 struct pim_interface
*pim_ifp
;
81 pim_ifp
= XMALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
83 zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp
));
88 pim_ifp
->mroute_vif_index
= -1;
90 pim_ifp
->igmp_default_robustness_variable
= IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
91 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
92 pim_ifp
->igmp_query_max_response_time_dsec
= IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
93 pim_ifp
->igmp_specific_query_max_response_time_dsec
= IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
96 RFC 3376: 8.3. Query Response Interval
97 The number of seconds represented by the [Query Response Interval]
98 must be less than the [Query Interval].
100 zassert(pim_ifp
->igmp_query_max_response_time_dsec
< pim_ifp
->igmp_default_query_interval
);
103 PIM_IF_DO_PIM(pim_ifp
->options
);
105 PIM_IF_DO_IGMP(pim_ifp
->options
);
108 /* FIXME: Should join? */
109 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
112 pim_ifp
->igmp_join_list
= 0;
113 pim_ifp
->igmp_socket_list
= 0;
114 pim_ifp
->pim_neighbor_list
= 0;
115 pim_ifp
->pim_ifchannel_list
= 0;
116 pim_ifp
->pim_generation_id
= 0;
118 /* list of struct igmp_sock */
119 pim_ifp
->igmp_socket_list
= list_new();
120 if (!pim_ifp
->igmp_socket_list
) {
121 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
122 __FILE__
, __PRETTY_FUNCTION__
);
123 return if_list_clean(pim_ifp
);
125 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *)) igmp_sock_free
;
127 /* list of struct pim_neighbor */
128 pim_ifp
->pim_neighbor_list
= list_new();
129 if (!pim_ifp
->pim_neighbor_list
) {
130 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
131 __FILE__
, __PRETTY_FUNCTION__
);
132 return if_list_clean(pim_ifp
);
134 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *)) pim_neighbor_free
;
136 /* list of struct pim_ifchannel */
137 pim_ifp
->pim_ifchannel_list
= list_new();
138 if (!pim_ifp
->pim_ifchannel_list
) {
139 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
140 __FILE__
, __PRETTY_FUNCTION__
);
141 return if_list_clean(pim_ifp
);
143 pim_ifp
->pim_ifchannel_list
->del
= (void (*)(void *)) pim_ifchannel_free
;
149 if (PIM_MROUTE_IS_ENABLED
) {
156 void pim_if_delete(struct interface
*ifp
)
158 struct pim_interface
*pim_ifp
;
164 if (pim_ifp
->igmp_join_list
) {
165 pim_if_igmp_join_del_all(ifp
);
167 zassert(!pim_ifp
->igmp_join_list
);
169 zassert(pim_ifp
->igmp_socket_list
);
170 zassert(!listcount(pim_ifp
->igmp_socket_list
));
172 zassert(pim_ifp
->pim_neighbor_list
);
173 zassert(!listcount(pim_ifp
->pim_neighbor_list
));
175 zassert(pim_ifp
->pim_ifchannel_list
);
176 zassert(!listcount(pim_ifp
->pim_ifchannel_list
));
178 if (PIM_MROUTE_IS_ENABLED
) {
182 list_delete(pim_ifp
->igmp_socket_list
);
183 list_delete(pim_ifp
->pim_neighbor_list
);
184 list_delete(pim_ifp
->pim_ifchannel_list
);
186 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
191 void pim_if_update_could_assert(struct interface
*ifp
)
193 struct pim_interface
*pim_ifp
;
194 struct listnode
*node
;
195 struct listnode
*next_node
;
196 struct pim_ifchannel
*ch
;
201 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
202 pim_ifchannel_update_could_assert(ch
);
206 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
208 struct pim_interface
*pim_ifp
;
209 struct listnode
*node
;
210 struct listnode
*next_node
;
211 struct pim_ifchannel
*ch
;
216 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
217 pim_ifchannel_update_my_assert_metric(ch
);
221 static void pim_addr_change(struct interface
*ifp
)
223 struct pim_interface
*pim_ifp
;
228 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes -- 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 */
235 RFC 4601: 4.3.1. Sending Hello Messages
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
242 2) After an interface has changed its IP address, it MUST send a
243 Hello message with its new IP address.
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
251 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
252 if (pim_ifp
->pim_sock_fd
< 0)
254 pim_hello_restart_now(ifp
); /* send hello and restart timer */
257 static int detect_primary_address_change(struct interface
*ifp
,
258 int force_prim_as_any
,
261 struct pim_interface
*pim_ifp
;
262 struct in_addr new_prim_addr
;
269 if (force_prim_as_any
)
270 new_prim_addr
= qpim_inaddr_any
;
272 new_prim_addr
= pim_find_primary_addr(ifp
);
274 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
276 if (PIM_DEBUG_ZEBRA
) {
277 char new_prim_str
[100];
278 char old_prim_str
[100];
279 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
, sizeof(new_prim_str
));
280 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
, sizeof(old_prim_str
));
281 zlog_debug("%s: old=%s new=%s on interface %s: %s",
283 old_prim_str
, new_prim_str
, ifp
->name
,
284 changed
? "changed" : "unchanged");
288 pim_ifp
->primary_address
= new_prim_addr
;
290 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
294 pim_addr_change(ifp
);
300 static void detect_secondary_address_change(struct interface
*ifp
,
303 struct pim_interface
*pim_ifp
;
310 changed
= 1; /* true */
312 zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
313 __PRETTY_FUNCTION__
, ifp
->name
);
319 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
323 pim_addr_change(ifp
);
326 static void detect_address_change(struct interface
*ifp
,
327 int force_prim_as_any
,
332 prim_changed
= detect_primary_address_change(ifp
, force_prim_as_any
, caller
);
334 /* no need to detect secondary change because
335 the reaction would be the same */
339 detect_secondary_address_change(ifp
, caller
);
342 void pim_if_addr_add(struct connected
*ifc
)
344 struct pim_interface
*pim_ifp
;
345 struct interface
*ifp
;
346 struct in_addr ifaddr
;
356 if (!if_is_operative(ifp
))
359 if (PIM_DEBUG_ZEBRA
) {
361 prefix2str(ifc
->address
, buf
, BUFSIZ
);
362 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
364 ifp
->name
, ifp
->ifindex
, buf
,
365 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
366 "secondary" : "primary");
369 ifaddr
= ifc
->address
->u
.prefix4
;
371 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
373 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
374 struct igmp_sock
*igmp
;
376 /* lookup IGMP socket */
377 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
380 /* if addr new, add IGMP socket */
381 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
, ifp
);
385 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
387 /* Interface has a valid primary address ? */
388 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
390 /* Interface has a valid socket ? */
391 if (pim_ifp
->pim_sock_fd
< 0) {
392 if (pim_sock_add(ifp
)) {
393 zlog_warn("Failure creating PIM socket for interface %s",
401 if (PIM_MROUTE_IS_ENABLED
) {
403 PIM or IGMP is enabled on interface, and there is at least one
404 address assigned, then try to create a vif_index.
406 if (pim_ifp
->mroute_vif_index
< 0) {
412 static void pim_if_addr_del_igmp(struct connected
*ifc
)
414 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
415 struct igmp_sock
*igmp
;
416 struct in_addr ifaddr
;
418 if (ifc
->address
->family
!= AF_INET
) {
419 /* non-IPv4 address */
424 /* IGMP not enabled on interface */
428 ifaddr
= ifc
->address
->u
.prefix4
;
430 /* lookup IGMP socket */
431 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
434 /* if addr found, del IGMP socket */
435 igmp_sock_delete(igmp
);
439 static void pim_if_addr_del_pim(struct connected
*ifc
)
441 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
443 if (ifc
->address
->family
!= AF_INET
) {
444 /* non-IPv4 address */
449 /* PIM not enabled on interface */
453 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
454 /* Interface keeps a valid primary address */
458 if (pim_ifp
->pim_sock_fd
< 0) {
459 /* Interface does not hold a valid socket any longer */
464 pim_sock_delete() closes the socket, stops read and timer threads,
465 and kills all neighbors.
467 pim_sock_delete(ifc
->ifp
, "last address has been removed from interface");
470 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
472 struct interface
*ifp
;
478 if (PIM_DEBUG_ZEBRA
) {
480 prefix2str(ifc
->address
, buf
, BUFSIZ
);
481 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
483 ifp
->name
, ifp
->ifindex
, buf
,
484 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
485 "secondary" : "primary");
488 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
490 pim_if_addr_del_igmp(ifc
);
491 pim_if_addr_del_pim(ifc
);
494 void pim_if_addr_add_all(struct interface
*ifp
)
496 struct connected
*ifc
;
497 struct listnode
*node
;
498 struct listnode
*nextnode
;
500 /* PIM/IGMP enabled ? */
504 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
505 struct prefix
*p
= ifc
->address
;
507 if (p
->family
!= AF_INET
)
510 pim_if_addr_add(ifc
);
514 void pim_if_addr_del_all(struct interface
*ifp
)
516 struct connected
*ifc
;
517 struct listnode
*node
;
518 struct listnode
*nextnode
;
520 /* PIM/IGMP enabled ? */
524 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
525 struct prefix
*p
= ifc
->address
;
527 if (p
->family
!= AF_INET
)
530 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
534 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
536 struct connected
*ifc
;
537 struct listnode
*node
;
538 struct listnode
*nextnode
;
540 /* PIM/IGMP enabled ? */
544 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
545 struct prefix
*p
= ifc
->address
;
547 if (p
->family
!= AF_INET
)
550 pim_if_addr_del_igmp(ifc
);
554 void pim_if_addr_del_all_pim(struct interface
*ifp
)
556 struct connected
*ifc
;
557 struct listnode
*node
;
558 struct listnode
*nextnode
;
560 /* PIM/IGMP enabled ? */
564 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
565 struct prefix
*p
= ifc
->address
;
567 if (p
->family
!= AF_INET
)
570 pim_if_addr_del_pim(ifc
);
574 static struct in_addr
find_first_nonsec_addr(struct interface
*ifp
)
576 struct connected
*ifc
;
577 struct listnode
*node
;
580 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
581 struct prefix
*p
= ifc
->address
;
583 if (p
->family
!= AF_INET
)
586 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
587 zlog_warn("%s: null IPv4 address connected to interface %s",
588 __PRETTY_FUNCTION__
, ifp
->name
);
592 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
598 addr
.s_addr
= PIM_NET_INADDR_ANY
;
603 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
605 return find_first_nonsec_addr(ifp
);
608 static int pim_iface_vif_index
= 0;
611 pim_iface_next_vif_index (struct interface
*ifp
)
614 * The pimreg vif is always going to be in index 0
617 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
620 pim_iface_vif_index
++;
621 return pim_iface_vif_index
;
625 pim_if_add_vif() uses ifindex as vif_index
627 see also pim_if_find_vifindex_by_ifindex()
629 int pim_if_add_vif(struct interface
*ifp
)
631 struct pim_interface
*pim_ifp
= ifp
->info
;
632 struct in_addr ifaddr
;
633 unsigned char flags
= 0;
637 if (pim_ifp
->mroute_vif_index
> 0) {
638 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
640 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
644 if (ifp
->ifindex
< 1) {
645 zlog_warn("%s: ifindex=%d < 1 on interface %s",
647 ifp
->ifindex
, ifp
->name
);
651 ifaddr
= pim_ifp
->primary_address
;
652 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
&& PIM_INADDR_IS_ANY(ifaddr
)) {
653 zlog_warn("%s: could not get address for interface %s ifindex=%d",
655 ifp
->name
, ifp
->ifindex
);
659 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index (ifp
);
661 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
)
663 zlog_warn("%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
669 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
670 flags
= VIFF_REGISTER
;
671 #ifdef VIFF_USE_IFINDEX
673 flags
= VIFF_USE_IFINDEX
;
676 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
677 /* pim_mroute_add_vif reported error */
682 Update highest vif_index
684 if (pim_ifp
->mroute_vif_index
!= PIM_OIF_PIM_REGISTER_VIF
&&
685 pim_ifp
->mroute_vif_index
> qpim_mroute_oif_highest_vif_index
) {
686 qpim_mroute_oif_highest_vif_index
= pim_ifp
->mroute_vif_index
;
692 static int iflist_find_highest_vif_index()
694 struct listnode
*ifnode
;
695 struct interface
*ifp
;
696 struct pim_interface
*pim_ifp
;
697 int highest_vif_index
= -1;
699 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
704 if (pim_ifp
->mroute_vif_index
> highest_vif_index
) {
705 highest_vif_index
= pim_ifp
->mroute_vif_index
;
709 return highest_vif_index
;
712 int pim_if_del_vif(struct interface
*ifp
)
714 struct pim_interface
*pim_ifp
= ifp
->info
;
717 if (pim_ifp
->mroute_vif_index
< 1) {
718 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
720 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
724 if (pim_mroute_del_vif(pim_ifp
->mroute_vif_index
)) {
725 /* pim_mroute_del_vif reported error */
730 Update highest vif_index
733 /* save old vif_index in order to compare with highest below */
734 old_vif_index
= pim_ifp
->mroute_vif_index
;
736 pim_ifp
->mroute_vif_index
= -1;
738 if (old_vif_index
== qpim_mroute_oif_highest_vif_index
) {
739 qpim_mroute_oif_highest_vif_index
= iflist_find_highest_vif_index();
745 void pim_if_add_vif_all()
747 struct listnode
*ifnode
;
748 struct listnode
*ifnextnode
;
749 struct interface
*ifp
;
751 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
759 void pim_if_del_vif_all()
761 struct listnode
*ifnode
;
762 struct listnode
*ifnextnode
;
763 struct interface
*ifp
;
765 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
773 struct interface
*pim_if_find_by_vif_index(ifindex_t vif_index
)
775 struct listnode
*ifnode
;
776 struct interface
*ifp
;
779 return if_lookup_by_name_vrf ("pimreg", VRF_DEFAULT
);
781 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
783 struct pim_interface
*pim_ifp
;
786 if (vif_index
== pim_ifp
->mroute_vif_index
)
795 pim_if_add_vif() uses ifindex as vif_index
797 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex
)
799 struct pim_interface
*pim_ifp
;
800 struct interface
*ifp
;
802 ifp
= if_lookup_by_index_vrf (ifindex
, VRF_DEFAULT
);
807 return pim_ifp
->mroute_vif_index
;
810 int pim_if_lan_delay_enabled(struct interface
*ifp
)
812 struct pim_interface
*pim_ifp
;
816 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
818 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
821 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
823 if (pim_if_lan_delay_enabled(ifp
)) {
824 struct pim_interface
*pim_ifp
;
826 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
829 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
833 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
835 if (pim_if_lan_delay_enabled(ifp
)) {
836 struct pim_interface
*pim_ifp
;
838 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
841 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
845 int pim_if_t_override_msec(struct interface
*ifp
)
847 int effective_override_interval_msec
;
850 effective_override_interval_msec
=
851 pim_if_effective_override_interval_msec(ifp
);
853 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
855 return t_override_msec
;
858 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
860 return pim_if_effective_propagation_delay_msec(ifp
) +
861 pim_if_effective_override_interval_msec(ifp
);
865 RFC 4601: 4.1.6. State Summarization Macros
867 The function NBR( I, A ) uses information gathered through PIM Hello
868 messages to map the IP address A of a directly connected PIM
869 neighbor router on interface I to the primary IP address of the same
870 router (Section 4.3.4). The primary IP address of a neighbor is the
871 address that it uses as the source of its PIM Hello messages.
873 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
876 struct listnode
*neighnode
;
877 struct pim_neighbor
*neigh
;
878 struct pim_interface
*pim_ifp
;
884 zlog_warn("%s: multicast not enabled on interface %s",
890 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
, neigh
)) {
892 /* primary address ? */
893 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
896 /* secondary address ? */
897 if (pim_neighbor_find_secondary(neigh
, addr
))
901 if (PIM_DEBUG_PIM_TRACE
) {
903 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
904 zlog_debug("%s: neighbor not found for address %s on interface %s",
906 addr_str
, ifp
->name
);
912 long pim_if_t_suppressed_msec(struct interface
*ifp
)
914 struct pim_interface
*pim_ifp
;
915 long t_suppressed_msec
;
916 uint32_t ramount
= 0;
921 /* join suppression disabled ? */
922 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
925 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
926 ramount
= 1100 + (random() % (1400 - 1100 + 1));
927 t_suppressed_msec
= qpim_t_periodic
* ramount
;
929 return t_suppressed_msec
;
932 static void igmp_join_free(struct igmp_join
*ij
)
934 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
937 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
938 struct in_addr group_addr
,
939 struct in_addr source_addr
)
941 struct listnode
*node
;
942 struct igmp_join
*ij
;
946 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
947 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
) &&
948 (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
955 static int igmp_join_sock(const char *ifname
,
957 struct in_addr group_addr
,
958 struct in_addr source_addr
)
962 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
967 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
, ifname
)) {
975 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
976 struct in_addr group_addr
,
977 struct in_addr source_addr
)
979 struct pim_interface
*pim_ifp
;
980 struct igmp_join
*ij
;
986 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
, source_addr
);
989 char source_str
[100];
990 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
991 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
992 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
994 group_str
, source_str
, ifp
->name
);
998 ij
= XMALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1000 char group_str
[100];
1001 char source_str
[100];
1002 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1003 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1004 zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1005 __PRETTY_FUNCTION__
,
1006 sizeof(*ij
), group_str
, source_str
, ifp
->name
);
1011 ij
->sock_fd
= join_fd
;
1012 ij
->group_addr
= group_addr
;
1013 ij
->source_addr
= source_addr
;
1014 ij
->sock_creation
= pim_time_monotonic_sec();
1016 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1021 int pim_if_igmp_join_add(struct interface
*ifp
,
1022 struct in_addr group_addr
,
1023 struct in_addr source_addr
)
1025 struct pim_interface
*pim_ifp
;
1026 struct igmp_join
*ij
;
1028 pim_ifp
= ifp
->info
;
1030 zlog_warn("%s: multicast not enabled on interface %s",
1031 __PRETTY_FUNCTION__
,
1036 if (!pim_ifp
->igmp_join_list
) {
1037 pim_ifp
->igmp_join_list
= list_new();
1038 if (!pim_ifp
->igmp_join_list
) {
1039 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1040 __FILE__
, __PRETTY_FUNCTION__
);
1043 pim_ifp
->igmp_join_list
->del
= (void (*)(void *)) igmp_join_free
;
1046 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1048 char group_str
[100];
1049 char source_str
[100];
1050 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1051 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1052 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1053 __PRETTY_FUNCTION__
,
1054 group_str
, source_str
, ifp
->name
);
1058 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1060 char group_str
[100];
1061 char source_str
[100];
1062 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1063 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1064 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1065 __PRETTY_FUNCTION__
,
1066 group_str
, source_str
, ifp
->name
);
1070 if (PIM_DEBUG_IGMP_EVENTS
) {
1071 char group_str
[100];
1072 char source_str
[100];
1073 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1074 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1075 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1076 __PRETTY_FUNCTION__
,
1077 source_str
, group_str
, ifp
->name
);
1085 int pim_if_igmp_join_del(struct interface
*ifp
,
1086 struct in_addr group_addr
,
1087 struct in_addr source_addr
)
1089 struct pim_interface
*pim_ifp
;
1090 struct igmp_join
*ij
;
1092 pim_ifp
= ifp
->info
;
1094 zlog_warn("%s: multicast not enabled on interface %s",
1095 __PRETTY_FUNCTION__
,
1100 if (!pim_ifp
->igmp_join_list
) {
1101 zlog_warn("%s: no IGMP join on interface %s",
1102 __PRETTY_FUNCTION__
,
1107 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1109 char group_str
[100];
1110 char source_str
[100];
1111 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1112 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1113 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1114 __PRETTY_FUNCTION__
,
1115 group_str
, source_str
, ifp
->name
);
1119 if (close(ij
->sock_fd
)) {
1121 char group_str
[100];
1122 char source_str
[100];
1123 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1124 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1125 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1126 __PRETTY_FUNCTION__
,
1127 ij
->sock_fd
, group_str
, source_str
, ifp
->name
, e
, safe_strerror(e
));
1130 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1132 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1133 list_delete(pim_ifp
->igmp_join_list
);
1134 pim_ifp
->igmp_join_list
= 0;
1140 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1142 struct pim_interface
*pim_ifp
;
1143 struct listnode
*node
;
1144 struct listnode
*nextnode
;
1145 struct igmp_join
*ij
;
1147 pim_ifp
= ifp
->info
;
1149 zlog_warn("%s: multicast not enabled on interface %s",
1150 __PRETTY_FUNCTION__
,
1155 if (!pim_ifp
->igmp_join_list
)
1158 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1159 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1165 Transitions from "I am Assert Loser" State
1167 Current Winner's GenID Changes or NLT Expires
1169 The Neighbor Liveness Timer associated with the current winner
1170 expires or we receive a Hello message from the current winner
1171 reporting a different GenID from the one it previously reported.
1172 This indicates that the current winner's interface or router has
1173 gone down (and may have come back up), and so we must assume it no
1174 longer knows it was the winner.
1176 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1177 struct in_addr neigh_addr
)
1179 struct pim_interface
*pim_ifp
;
1180 struct listnode
*node
;
1181 struct listnode
*next_node
;
1182 struct pim_ifchannel
*ch
;
1184 pim_ifp
= ifp
->info
;
1187 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1188 /* Is (S,G,I) assert loser ? */
1189 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1191 /* Dead neighbor was winner ? */
1192 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1195 assert_action_a5(ch
);
1199 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1201 struct listnode
*ch_node
;
1202 struct pim_ifchannel
*ch
;
1204 /* clear off flag from interface's upstreams */
1205 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1206 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch
->upstream
->flags
);
1209 /* scan per-interface (S,G,I) state on this I interface */
1210 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1211 struct pim_upstream
*up
= ch
->upstream
;
1213 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1216 /* update join_desired for the global (S,G) state */
1217 pim_upstream_update_join_desired(up
);
1218 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1222 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1224 struct pim_interface
*pim_ifp
;
1225 struct listnode
*node
;
1226 struct listnode
*next_node
;
1227 struct pim_ifchannel
*ch
;
1229 pim_ifp
= ifp
->info
;
1233 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1234 pim_ifchannel_update_assert_tracking_desired(ch
);
1239 * PIM wants to have an interface pointer for everything it does.
1240 * The pimreg is a special interface that we have that is not
1241 * quite an inteface but a VIF is created for it.
1243 void pim_if_create_pimreg (void)
1245 if (!pim_regiface
) {
1246 pim_regiface
= if_create("pimreg", strlen("pimreg"));
1247 pim_regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1249 pim_if_new(pim_regiface
, 0, 0);