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,
19 $QuaggaId: $Format:%an, %ai, %h$ $
32 #include "pim_iface.h"
34 #include "pim_mroute.h"
38 #include "pim_neighbor.h"
39 #include "pim_ifchannel.h"
42 #include "pim_ssmpingd.h"
44 struct interface
*pim_regiface
= NULL
;
46 static void pim_if_igmp_join_del_all(struct interface
*ifp
);
50 vrf_iflist_create(VRF_DEFAULT
);
53 static void *if_list_clean(struct pim_interface
*pim_ifp
)
55 if (pim_ifp
->igmp_join_list
) {
56 list_delete(pim_ifp
->igmp_join_list
);
59 if (pim_ifp
->igmp_socket_list
) {
60 list_delete(pim_ifp
->igmp_socket_list
);
63 if (pim_ifp
->pim_neighbor_list
) {
64 list_delete(pim_ifp
->pim_neighbor_list
);
67 if (pim_ifp
->pim_ifchannel_list
) {
68 list_delete(pim_ifp
->pim_ifchannel_list
);
71 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
76 struct pim_interface
*pim_if_new(struct interface
*ifp
, int igmp
, int pim
)
78 struct pim_interface
*pim_ifp
;
83 pim_ifp
= XMALLOC(MTYPE_PIM_INTERFACE
, sizeof(*pim_ifp
));
85 zlog_err("PIM XMALLOC(%zu) failure", sizeof(*pim_ifp
));
90 pim_ifp
->mroute_vif_index
= -1;
92 pim_ifp
->igmp_default_robustness_variable
= IGMP_DEFAULT_ROBUSTNESS_VARIABLE
;
93 pim_ifp
->igmp_default_query_interval
= IGMP_GENERAL_QUERY_INTERVAL
;
94 pim_ifp
->igmp_query_max_response_time_dsec
= IGMP_QUERY_MAX_RESPONSE_TIME_DSEC
;
95 pim_ifp
->igmp_specific_query_max_response_time_dsec
= IGMP_SPECIFIC_QUERY_MAX_RESPONSE_TIME_DSEC
;
98 RFC 3376: 8.3. Query Response Interval
99 The number of seconds represented by the [Query Response Interval]
100 must be less than the [Query Interval].
102 zassert(pim_ifp
->igmp_query_max_response_time_dsec
< pim_ifp
->igmp_default_query_interval
);
105 PIM_IF_DO_PIM(pim_ifp
->options
);
107 PIM_IF_DO_IGMP(pim_ifp
->options
);
110 /* FIXME: Should join? */
111 PIM_IF_DO_IGMP_LISTEN_ALLROUTERS(pim_ifp
->options
);
114 pim_ifp
->igmp_join_list
= 0;
115 pim_ifp
->igmp_socket_list
= 0;
116 pim_ifp
->pim_neighbor_list
= 0;
117 pim_ifp
->pim_ifchannel_list
= 0;
118 pim_ifp
->pim_generation_id
= 0;
120 /* list of struct igmp_sock */
121 pim_ifp
->igmp_socket_list
= list_new();
122 if (!pim_ifp
->igmp_socket_list
) {
123 zlog_err("%s %s: failure: igmp_socket_list=list_new()",
124 __FILE__
, __PRETTY_FUNCTION__
);
125 return if_list_clean(pim_ifp
);
127 pim_ifp
->igmp_socket_list
->del
= (void (*)(void *)) igmp_sock_free
;
129 /* list of struct pim_neighbor */
130 pim_ifp
->pim_neighbor_list
= list_new();
131 if (!pim_ifp
->pim_neighbor_list
) {
132 zlog_err("%s %s: failure: pim_neighbor_list=list_new()",
133 __FILE__
, __PRETTY_FUNCTION__
);
134 return if_list_clean(pim_ifp
);
136 pim_ifp
->pim_neighbor_list
->del
= (void (*)(void *)) pim_neighbor_free
;
138 /* list of struct pim_ifchannel */
139 pim_ifp
->pim_ifchannel_list
= list_new();
140 if (!pim_ifp
->pim_ifchannel_list
) {
141 zlog_err("%s %s: failure: pim_ifchannel_list=list_new()",
142 __FILE__
, __PRETTY_FUNCTION__
);
143 return if_list_clean(pim_ifp
);
145 pim_ifp
->pim_ifchannel_list
->del
= (void (*)(void *)) pim_ifchannel_free
;
151 if (PIM_MROUTE_IS_ENABLED
) {
158 void pim_if_delete(struct interface
*ifp
)
160 struct pim_interface
*pim_ifp
;
166 if (pim_ifp
->igmp_join_list
) {
167 pim_if_igmp_join_del_all(ifp
);
169 zassert(!pim_ifp
->igmp_join_list
);
171 zassert(pim_ifp
->igmp_socket_list
);
172 zassert(!listcount(pim_ifp
->igmp_socket_list
));
174 zassert(pim_ifp
->pim_neighbor_list
);
175 zassert(!listcount(pim_ifp
->pim_neighbor_list
));
177 zassert(pim_ifp
->pim_ifchannel_list
);
178 zassert(!listcount(pim_ifp
->pim_ifchannel_list
));
180 if (PIM_MROUTE_IS_ENABLED
) {
184 list_delete(pim_ifp
->igmp_socket_list
);
185 list_delete(pim_ifp
->pim_neighbor_list
);
186 list_delete(pim_ifp
->pim_ifchannel_list
);
188 XFREE(MTYPE_PIM_INTERFACE
, pim_ifp
);
193 void pim_if_update_could_assert(struct interface
*ifp
)
195 struct pim_interface
*pim_ifp
;
196 struct listnode
*node
;
197 struct listnode
*next_node
;
198 struct pim_ifchannel
*ch
;
203 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
204 pim_ifchannel_update_could_assert(ch
);
208 static void pim_if_update_my_assert_metric(struct interface
*ifp
)
210 struct pim_interface
*pim_ifp
;
211 struct listnode
*node
;
212 struct listnode
*next_node
;
213 struct pim_ifchannel
*ch
;
218 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
219 pim_ifchannel_update_my_assert_metric(ch
);
223 static void pim_addr_change(struct interface
*ifp
)
225 struct pim_interface
*pim_ifp
;
230 pim_if_dr_election(ifp
); /* router's own DR Priority (addr) changes -- Done TODO T30 */
231 pim_if_update_join_desired(pim_ifp
); /* depends on DR */
232 pim_if_update_could_assert(ifp
); /* depends on DR */
233 pim_if_update_my_assert_metric(ifp
); /* depends on could_assert */
234 pim_if_update_assert_tracking_desired(ifp
); /* depends on DR, join_desired */
237 RFC 4601: 4.3.1. Sending Hello Messages
239 1) Before an interface goes down or changes primary IP address, a
240 Hello message with a zero HoldTime should be sent immediately
241 (with the old IP address if the IP address changed).
242 -- FIXME See CAVEAT C13
244 2) After an interface has changed its IP address, it MUST send a
245 Hello message with its new IP address.
248 3) If an interface changes one of its secondary IP addresses, a
249 Hello message with an updated Address_List option and a non-zero
250 HoldTime should be sent immediately.
251 -- FIXME See TODO T31
253 pim_ifp
->pim_ifstat_hello_sent
= 0; /* reset hello counter */
254 if (pim_ifp
->pim_sock_fd
< 0)
256 pim_hello_restart_now(ifp
); /* send hello and restart timer */
259 static int detect_primary_address_change(struct interface
*ifp
,
260 int force_prim_as_any
,
263 struct pim_interface
*pim_ifp
;
264 struct in_addr new_prim_addr
;
271 if (force_prim_as_any
)
272 new_prim_addr
= qpim_inaddr_any
;
274 new_prim_addr
= pim_find_primary_addr(ifp
);
276 changed
= new_prim_addr
.s_addr
!= pim_ifp
->primary_address
.s_addr
;
278 if (PIM_DEBUG_ZEBRA
) {
279 char new_prim_str
[100];
280 char old_prim_str
[100];
281 pim_inet4_dump("<new?>", new_prim_addr
, new_prim_str
, sizeof(new_prim_str
));
282 pim_inet4_dump("<old?>", pim_ifp
->primary_address
, old_prim_str
, sizeof(old_prim_str
));
283 zlog_debug("%s: old=%s new=%s on interface %s: %s",
285 old_prim_str
, new_prim_str
, ifp
->name
,
286 changed
? "changed" : "unchanged");
290 pim_ifp
->primary_address
= new_prim_addr
;
292 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
296 pim_addr_change(ifp
);
302 static void detect_secondary_address_change(struct interface
*ifp
,
305 struct pim_interface
*pim_ifp
;
312 changed
= 1; /* true */
314 zlog_debug("FIXME T31 C15 %s: on interface %s: acting on any addr change",
315 __PRETTY_FUNCTION__
, ifp
->name
);
321 if (!PIM_IF_TEST_PIM(pim_ifp
->options
)) {
325 pim_addr_change(ifp
);
328 static void detect_address_change(struct interface
*ifp
,
329 int force_prim_as_any
,
334 prim_changed
= detect_primary_address_change(ifp
, force_prim_as_any
, caller
);
336 /* no need to detect secondary change because
337 the reaction would be the same */
341 detect_secondary_address_change(ifp
, caller
);
344 void pim_if_addr_add(struct connected
*ifc
)
346 struct pim_interface
*pim_ifp
;
347 struct interface
*ifp
;
348 struct in_addr ifaddr
;
358 if (!if_is_operative(ifp
))
361 if (PIM_DEBUG_ZEBRA
) {
363 prefix2str(ifc
->address
, buf
, BUFSIZ
);
364 zlog_debug("%s: %s ifindex=%d connected IP address %s %s",
366 ifp
->name
, ifp
->ifindex
, buf
,
367 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
368 "secondary" : "primary");
371 ifaddr
= ifc
->address
->u
.prefix4
;
373 detect_address_change(ifp
, 0, __PRETTY_FUNCTION__
);
375 if (PIM_IF_TEST_IGMP(pim_ifp
->options
)) {
376 struct igmp_sock
*igmp
;
378 /* lookup IGMP socket */
379 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
382 /* if addr new, add IGMP socket */
383 pim_igmp_sock_add(pim_ifp
->igmp_socket_list
, ifaddr
, ifp
);
387 if (PIM_IF_TEST_PIM(pim_ifp
->options
)) {
389 /* Interface has a valid primary address ? */
390 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
392 /* Interface has a valid socket ? */
393 if (pim_ifp
->pim_sock_fd
< 0) {
394 if (pim_sock_add(ifp
)) {
395 zlog_warn("Failure creating PIM socket for interface %s",
403 if (PIM_MROUTE_IS_ENABLED
) {
405 PIM or IGMP is enabled on interface, and there is at least one
406 address assigned, then try to create a vif_index.
408 if (pim_ifp
->mroute_vif_index
< 0) {
414 static void pim_if_addr_del_igmp(struct connected
*ifc
)
416 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
417 struct igmp_sock
*igmp
;
418 struct in_addr ifaddr
;
420 if (ifc
->address
->family
!= AF_INET
) {
421 /* non-IPv4 address */
426 /* IGMP not enabled on interface */
430 ifaddr
= ifc
->address
->u
.prefix4
;
432 /* lookup IGMP socket */
433 igmp
= pim_igmp_sock_lookup_ifaddr(pim_ifp
->igmp_socket_list
,
436 /* if addr found, del IGMP socket */
437 igmp_sock_delete(igmp
);
441 static void pim_if_addr_del_pim(struct connected
*ifc
)
443 struct pim_interface
*pim_ifp
= ifc
->ifp
->info
;
445 if (ifc
->address
->family
!= AF_INET
) {
446 /* non-IPv4 address */
451 /* PIM not enabled on interface */
455 if (PIM_INADDR_ISNOT_ANY(pim_ifp
->primary_address
)) {
456 /* Interface keeps a valid primary address */
460 if (pim_ifp
->pim_sock_fd
< 0) {
461 /* Interface does not hold a valid socket any longer */
466 pim_sock_delete() closes the socket, stops read and timer threads,
467 and kills all neighbors.
469 pim_sock_delete(ifc
->ifp
, "last address has been removed from interface");
472 void pim_if_addr_del(struct connected
*ifc
, int force_prim_as_any
)
474 struct interface
*ifp
;
480 if (PIM_DEBUG_ZEBRA
) {
482 prefix2str(ifc
->address
, buf
, BUFSIZ
);
483 zlog_debug("%s: %s ifindex=%d disconnected IP address %s %s",
485 ifp
->name
, ifp
->ifindex
, buf
,
486 CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
) ?
487 "secondary" : "primary");
490 detect_address_change(ifp
, force_prim_as_any
, __PRETTY_FUNCTION__
);
492 pim_if_addr_del_igmp(ifc
);
493 pim_if_addr_del_pim(ifc
);
496 void pim_if_addr_add_all(struct interface
*ifp
)
498 struct connected
*ifc
;
499 struct listnode
*node
;
500 struct listnode
*nextnode
;
502 /* PIM/IGMP enabled ? */
506 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
507 struct prefix
*p
= ifc
->address
;
509 if (p
->family
!= AF_INET
)
512 pim_if_addr_add(ifc
);
516 void pim_if_addr_del_all(struct interface
*ifp
)
518 struct connected
*ifc
;
519 struct listnode
*node
;
520 struct listnode
*nextnode
;
522 /* PIM/IGMP enabled ? */
526 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
527 struct prefix
*p
= ifc
->address
;
529 if (p
->family
!= AF_INET
)
532 pim_if_addr_del(ifc
, 1 /* force_prim_as_any=true */);
536 void pim_if_addr_del_all_igmp(struct interface
*ifp
)
538 struct connected
*ifc
;
539 struct listnode
*node
;
540 struct listnode
*nextnode
;
542 /* PIM/IGMP enabled ? */
546 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
547 struct prefix
*p
= ifc
->address
;
549 if (p
->family
!= AF_INET
)
552 pim_if_addr_del_igmp(ifc
);
556 void pim_if_addr_del_all_pim(struct interface
*ifp
)
558 struct connected
*ifc
;
559 struct listnode
*node
;
560 struct listnode
*nextnode
;
562 /* PIM/IGMP enabled ? */
566 for (ALL_LIST_ELEMENTS(ifp
->connected
, node
, nextnode
, ifc
)) {
567 struct prefix
*p
= ifc
->address
;
569 if (p
->family
!= AF_INET
)
572 pim_if_addr_del_pim(ifc
);
576 static struct in_addr
find_first_nonsec_addr(struct interface
*ifp
)
578 struct connected
*ifc
;
579 struct listnode
*node
;
582 for (ALL_LIST_ELEMENTS_RO(ifp
->connected
, node
, ifc
)) {
583 struct prefix
*p
= ifc
->address
;
585 if (p
->family
!= AF_INET
)
588 if (PIM_INADDR_IS_ANY(p
->u
.prefix4
)) {
589 zlog_warn("%s: null IPv4 address connected to interface %s",
590 __PRETTY_FUNCTION__
, ifp
->name
);
594 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_SECONDARY
))
600 addr
.s_addr
= PIM_NET_INADDR_ANY
;
605 struct in_addr
pim_find_primary_addr(struct interface
*ifp
)
607 return find_first_nonsec_addr(ifp
);
610 static int pim_iface_vif_index
= 0;
613 pim_iface_next_vif_index (struct interface
*ifp
)
616 * The pimreg vif is always going to be in index 0
619 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
622 pim_iface_vif_index
++;
623 return pim_iface_vif_index
;
627 pim_if_add_vif() uses ifindex as vif_index
629 see also pim_if_find_vifindex_by_ifindex()
631 int pim_if_add_vif(struct interface
*ifp
)
633 struct pim_interface
*pim_ifp
= ifp
->info
;
634 struct in_addr ifaddr
;
635 unsigned char flags
= 0;
639 if (pim_ifp
->mroute_vif_index
> 0) {
640 zlog_warn("%s: vif_index=%d > 0 on interface %s ifindex=%d",
642 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
646 if (ifp
->ifindex
< 1) {
647 zlog_warn("%s: ifindex=%d < 1 on interface %s",
649 ifp
->ifindex
, ifp
->name
);
653 ifaddr
= pim_ifp
->primary_address
;
654 if (ifp
->ifindex
!= PIM_OIF_PIM_REGISTER_VIF
&& PIM_INADDR_IS_ANY(ifaddr
)) {
655 zlog_warn("%s: could not get address for interface %s ifindex=%d",
657 ifp
->name
, ifp
->ifindex
);
661 pim_ifp
->mroute_vif_index
= pim_iface_next_vif_index (ifp
);
663 if (pim_ifp
->mroute_vif_index
>= MAXVIFS
)
665 zlog_warn("%s: Attempting to configure more than MAXVIFS=%d on pim enabled interface %s",
671 if (ifp
->ifindex
== PIM_OIF_PIM_REGISTER_VIF
)
672 flags
= VIFF_REGISTER
;
673 #ifdef VIFF_USE_IFINDEX
675 flags
= VIFF_USE_IFINDEX
;
678 if (pim_mroute_add_vif(ifp
, ifaddr
, flags
)) {
679 /* pim_mroute_add_vif reported error */
684 Update highest vif_index
686 if (pim_ifp
->mroute_vif_index
!= PIM_OIF_PIM_REGISTER_VIF
&&
687 pim_ifp
->mroute_vif_index
> qpim_mroute_oif_highest_vif_index
) {
688 qpim_mroute_oif_highest_vif_index
= pim_ifp
->mroute_vif_index
;
694 static int iflist_find_highest_vif_index()
696 struct listnode
*ifnode
;
697 struct interface
*ifp
;
698 struct pim_interface
*pim_ifp
;
699 int highest_vif_index
= -1;
701 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
706 if (pim_ifp
->mroute_vif_index
> highest_vif_index
) {
707 highest_vif_index
= pim_ifp
->mroute_vif_index
;
711 return highest_vif_index
;
714 int pim_if_del_vif(struct interface
*ifp
)
716 struct pim_interface
*pim_ifp
= ifp
->info
;
719 if (pim_ifp
->mroute_vif_index
< 1) {
720 zlog_warn("%s: vif_index=%d < 1 on interface %s ifindex=%d",
722 pim_ifp
->mroute_vif_index
, ifp
->name
, ifp
->ifindex
);
726 if (pim_mroute_del_vif(pim_ifp
->mroute_vif_index
)) {
727 /* pim_mroute_del_vif reported error */
732 Update highest vif_index
735 /* save old vif_index in order to compare with highest below */
736 old_vif_index
= pim_ifp
->mroute_vif_index
;
738 pim_ifp
->mroute_vif_index
= -1;
740 if (old_vif_index
== qpim_mroute_oif_highest_vif_index
) {
741 qpim_mroute_oif_highest_vif_index
= iflist_find_highest_vif_index();
747 void pim_if_add_vif_all()
749 struct listnode
*ifnode
;
750 struct listnode
*ifnextnode
;
751 struct interface
*ifp
;
753 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
761 void pim_if_del_vif_all()
763 struct listnode
*ifnode
;
764 struct listnode
*ifnextnode
;
765 struct interface
*ifp
;
767 for (ALL_LIST_ELEMENTS (vrf_iflist (VRF_DEFAULT
), ifnode
, ifnextnode
, ifp
)) {
775 struct interface
*pim_if_find_by_vif_index(ifindex_t vif_index
)
777 struct listnode
*ifnode
;
778 struct interface
*ifp
;
781 return if_lookup_by_name_vrf ("pimreg", VRF_DEFAULT
);
783 for (ALL_LIST_ELEMENTS_RO (vrf_iflist (VRF_DEFAULT
), ifnode
, ifp
)) {
785 struct pim_interface
*pim_ifp
;
788 if (vif_index
== pim_ifp
->mroute_vif_index
)
797 pim_if_add_vif() uses ifindex as vif_index
799 int pim_if_find_vifindex_by_ifindex(ifindex_t ifindex
)
801 struct pim_interface
*pim_ifp
;
802 struct interface
*ifp
;
804 ifp
= if_lookup_by_index_vrf (ifindex
, VRF_DEFAULT
);
809 return pim_ifp
->mroute_vif_index
;
812 int pim_if_lan_delay_enabled(struct interface
*ifp
)
814 struct pim_interface
*pim_ifp
;
818 zassert(pim_ifp
->pim_number_of_nonlandelay_neighbors
>= 0);
820 return pim_ifp
->pim_number_of_nonlandelay_neighbors
== 0;
823 uint16_t pim_if_effective_propagation_delay_msec(struct interface
*ifp
)
825 if (pim_if_lan_delay_enabled(ifp
)) {
826 struct pim_interface
*pim_ifp
;
828 return pim_ifp
->pim_neighbors_highest_propagation_delay_msec
;
831 return PIM_DEFAULT_PROPAGATION_DELAY_MSEC
;
835 uint16_t pim_if_effective_override_interval_msec(struct interface
*ifp
)
837 if (pim_if_lan_delay_enabled(ifp
)) {
838 struct pim_interface
*pim_ifp
;
840 return pim_ifp
->pim_neighbors_highest_override_interval_msec
;
843 return PIM_DEFAULT_OVERRIDE_INTERVAL_MSEC
;
847 int pim_if_t_override_msec(struct interface
*ifp
)
849 int effective_override_interval_msec
;
852 effective_override_interval_msec
=
853 pim_if_effective_override_interval_msec(ifp
);
855 t_override_msec
= random() % (effective_override_interval_msec
+ 1);
857 return t_override_msec
;
860 uint16_t pim_if_jp_override_interval_msec(struct interface
*ifp
)
862 return pim_if_effective_propagation_delay_msec(ifp
) +
863 pim_if_effective_override_interval_msec(ifp
);
867 RFC 4601: 4.1.6. State Summarization Macros
869 The function NBR( I, A ) uses information gathered through PIM Hello
870 messages to map the IP address A of a directly connected PIM
871 neighbor router on interface I to the primary IP address of the same
872 router (Section 4.3.4). The primary IP address of a neighbor is the
873 address that it uses as the source of its PIM Hello messages.
875 struct pim_neighbor
*pim_if_find_neighbor(struct interface
*ifp
,
878 struct listnode
*neighnode
;
879 struct pim_neighbor
*neigh
;
880 struct pim_interface
*pim_ifp
;
886 zlog_warn("%s: multicast not enabled on interface %s",
892 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_neighbor_list
, neighnode
, neigh
)) {
894 /* primary address ? */
895 if (neigh
->source_addr
.s_addr
== addr
.s_addr
)
898 /* secondary address ? */
899 if (pim_neighbor_find_secondary(neigh
, addr
))
903 if (PIM_DEBUG_PIM_TRACE
) {
905 pim_inet4_dump("<addr?>", addr
, addr_str
, sizeof(addr_str
));
906 zlog_debug("%s: neighbor not found for address %s on interface %s",
908 addr_str
, ifp
->name
);
914 long pim_if_t_suppressed_msec(struct interface
*ifp
)
916 struct pim_interface
*pim_ifp
;
917 long t_suppressed_msec
;
918 uint32_t ramount
= 0;
923 /* join suppression disabled ? */
924 if (PIM_IF_TEST_PIM_CAN_DISABLE_JOIN_SUPRESSION(pim_ifp
->options
))
927 /* t_suppressed = t_periodic * rand(1.1, 1.4) */
928 ramount
= 1100 + (random() % (1400 - 1100 + 1));
929 t_suppressed_msec
= qpim_t_periodic
* ramount
;
931 return t_suppressed_msec
;
934 static void igmp_join_free(struct igmp_join
*ij
)
936 XFREE(MTYPE_PIM_IGMP_JOIN
, ij
);
939 static struct igmp_join
*igmp_join_find(struct list
*join_list
,
940 struct in_addr group_addr
,
941 struct in_addr source_addr
)
943 struct listnode
*node
;
944 struct igmp_join
*ij
;
948 for (ALL_LIST_ELEMENTS_RO(join_list
, node
, ij
)) {
949 if ((group_addr
.s_addr
== ij
->group_addr
.s_addr
) &&
950 (source_addr
.s_addr
== ij
->source_addr
.s_addr
))
957 static int igmp_join_sock(const char *ifname
,
959 struct in_addr group_addr
,
960 struct in_addr source_addr
)
964 join_fd
= pim_socket_raw(IPPROTO_IGMP
);
969 if (pim_socket_join_source(join_fd
, ifindex
, group_addr
, source_addr
, ifname
)) {
977 static struct igmp_join
*igmp_join_new(struct interface
*ifp
,
978 struct in_addr group_addr
,
979 struct in_addr source_addr
)
981 struct pim_interface
*pim_ifp
;
982 struct igmp_join
*ij
;
988 join_fd
= igmp_join_sock(ifp
->name
, ifp
->ifindex
, group_addr
, source_addr
);
991 char source_str
[100];
992 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
993 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
994 zlog_warn("%s: igmp_join_sock() failure for IGMP group %s source %s on interface %s",
996 group_str
, source_str
, ifp
->name
);
1000 ij
= XMALLOC(MTYPE_PIM_IGMP_JOIN
, sizeof(*ij
));
1002 char group_str
[100];
1003 char source_str
[100];
1004 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1005 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1006 zlog_err("%s: XMALLOC(%zu) failure for IGMP group %s source %s on interface %s",
1007 __PRETTY_FUNCTION__
,
1008 sizeof(*ij
), group_str
, source_str
, ifp
->name
);
1013 ij
->sock_fd
= join_fd
;
1014 ij
->group_addr
= group_addr
;
1015 ij
->source_addr
= source_addr
;
1016 ij
->sock_creation
= pim_time_monotonic_sec();
1018 listnode_add(pim_ifp
->igmp_join_list
, ij
);
1023 int pim_if_igmp_join_add(struct interface
*ifp
,
1024 struct in_addr group_addr
,
1025 struct in_addr source_addr
)
1027 struct pim_interface
*pim_ifp
;
1028 struct igmp_join
*ij
;
1030 pim_ifp
= ifp
->info
;
1032 zlog_warn("%s: multicast not enabled on interface %s",
1033 __PRETTY_FUNCTION__
,
1038 if (!pim_ifp
->igmp_join_list
) {
1039 pim_ifp
->igmp_join_list
= list_new();
1040 if (!pim_ifp
->igmp_join_list
) {
1041 zlog_err("%s %s: failure: igmp_join_list=list_new()",
1042 __FILE__
, __PRETTY_FUNCTION__
);
1045 pim_ifp
->igmp_join_list
->del
= (void (*)(void *)) igmp_join_free
;
1048 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1050 char group_str
[100];
1051 char source_str
[100];
1052 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1053 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1054 zlog_warn("%s: can't re-join existing IGMP group %s source %s on interface %s",
1055 __PRETTY_FUNCTION__
,
1056 group_str
, source_str
, ifp
->name
);
1060 ij
= igmp_join_new(ifp
, group_addr
, source_addr
);
1062 char group_str
[100];
1063 char source_str
[100];
1064 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1065 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1066 zlog_warn("%s: igmp_join_new() failure for IGMP group %s source %s on interface %s",
1067 __PRETTY_FUNCTION__
,
1068 group_str
, source_str
, ifp
->name
);
1072 if (PIM_DEBUG_IGMP_EVENTS
) {
1073 char group_str
[100];
1074 char source_str
[100];
1075 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1076 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1077 zlog_debug("%s: issued static igmp join for channel (S,G)=(%s,%s) on interface %s",
1078 __PRETTY_FUNCTION__
,
1079 source_str
, group_str
, ifp
->name
);
1087 int pim_if_igmp_join_del(struct interface
*ifp
,
1088 struct in_addr group_addr
,
1089 struct in_addr source_addr
)
1091 struct pim_interface
*pim_ifp
;
1092 struct igmp_join
*ij
;
1094 pim_ifp
= ifp
->info
;
1096 zlog_warn("%s: multicast not enabled on interface %s",
1097 __PRETTY_FUNCTION__
,
1102 if (!pim_ifp
->igmp_join_list
) {
1103 zlog_warn("%s: no IGMP join on interface %s",
1104 __PRETTY_FUNCTION__
,
1109 ij
= igmp_join_find(pim_ifp
->igmp_join_list
, group_addr
, source_addr
);
1111 char group_str
[100];
1112 char source_str
[100];
1113 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1114 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1115 zlog_warn("%s: could not find IGMP group %s source %s on interface %s",
1116 __PRETTY_FUNCTION__
,
1117 group_str
, source_str
, ifp
->name
);
1121 if (close(ij
->sock_fd
)) {
1123 char group_str
[100];
1124 char source_str
[100];
1125 pim_inet4_dump("<grp?>", group_addr
, group_str
, sizeof(group_str
));
1126 pim_inet4_dump("<src?>", source_addr
, source_str
, sizeof(source_str
));
1127 zlog_warn("%s: failure closing sock_fd=%d for IGMP group %s source %s on interface %s: errno=%d: %s",
1128 __PRETTY_FUNCTION__
,
1129 ij
->sock_fd
, group_str
, source_str
, ifp
->name
, e
, safe_strerror(e
));
1132 listnode_delete(pim_ifp
->igmp_join_list
, ij
);
1134 if (listcount(pim_ifp
->igmp_join_list
) < 1) {
1135 list_delete(pim_ifp
->igmp_join_list
);
1136 pim_ifp
->igmp_join_list
= 0;
1142 static void pim_if_igmp_join_del_all(struct interface
*ifp
)
1144 struct pim_interface
*pim_ifp
;
1145 struct listnode
*node
;
1146 struct listnode
*nextnode
;
1147 struct igmp_join
*ij
;
1149 pim_ifp
= ifp
->info
;
1151 zlog_warn("%s: multicast not enabled on interface %s",
1152 __PRETTY_FUNCTION__
,
1157 if (!pim_ifp
->igmp_join_list
)
1160 for (ALL_LIST_ELEMENTS(pim_ifp
->igmp_join_list
, node
, nextnode
, ij
))
1161 pim_if_igmp_join_del(ifp
, ij
->group_addr
, ij
->source_addr
);
1167 Transitions from "I am Assert Loser" State
1169 Current Winner's GenID Changes or NLT Expires
1171 The Neighbor Liveness Timer associated with the current winner
1172 expires or we receive a Hello message from the current winner
1173 reporting a different GenID from the one it previously reported.
1174 This indicates that the current winner's interface or router has
1175 gone down (and may have come back up), and so we must assume it no
1176 longer knows it was the winner.
1178 void pim_if_assert_on_neighbor_down(struct interface
*ifp
,
1179 struct in_addr neigh_addr
)
1181 struct pim_interface
*pim_ifp
;
1182 struct listnode
*node
;
1183 struct listnode
*next_node
;
1184 struct pim_ifchannel
*ch
;
1186 pim_ifp
= ifp
->info
;
1189 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1190 /* Is (S,G,I) assert loser ? */
1191 if (ch
->ifassert_state
!= PIM_IFASSERT_I_AM_LOSER
)
1193 /* Dead neighbor was winner ? */
1194 if (ch
->ifassert_winner
.s_addr
!= neigh_addr
.s_addr
)
1197 assert_action_a5(ch
);
1201 void pim_if_update_join_desired(struct pim_interface
*pim_ifp
)
1203 struct listnode
*ch_node
;
1204 struct pim_ifchannel
*ch
;
1206 /* clear off flag from interface's upstreams */
1207 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1208 PIM_UPSTREAM_FLAG_UNSET_DR_JOIN_DESIRED_UPDATED(ch
->upstream
->flags
);
1211 /* scan per-interface (S,G,I) state on this I interface */
1212 for (ALL_LIST_ELEMENTS_RO(pim_ifp
->pim_ifchannel_list
, ch_node
, ch
)) {
1213 struct pim_upstream
*up
= ch
->upstream
;
1215 if (PIM_UPSTREAM_FLAG_TEST_DR_JOIN_DESIRED_UPDATED(up
->flags
))
1218 /* update join_desired for the global (S,G) state */
1219 pim_upstream_update_join_desired(up
);
1220 PIM_UPSTREAM_FLAG_SET_DR_JOIN_DESIRED_UPDATED(up
->flags
);
1224 void pim_if_update_assert_tracking_desired(struct interface
*ifp
)
1226 struct pim_interface
*pim_ifp
;
1227 struct listnode
*node
;
1228 struct listnode
*next_node
;
1229 struct pim_ifchannel
*ch
;
1231 pim_ifp
= ifp
->info
;
1235 for (ALL_LIST_ELEMENTS(pim_ifp
->pim_ifchannel_list
, node
, next_node
, ch
)) {
1236 pim_ifchannel_update_assert_tracking_desired(ch
);
1241 * PIM wants to have an interface pointer for everything it does.
1242 * The pimreg is a special interface that we have that is not
1243 * quite an inteface but a VIF is created for it.
1245 void pim_if_create_pimreg (void)
1247 if (!pim_regiface
) {
1248 pim_regiface
= if_create("pimreg", strlen("pimreg"));
1249 pim_regiface
->ifindex
= PIM_OIF_PIM_REGISTER_VIF
;
1251 pim_if_new(pim_regiface
, 0, 0);